NewOrderCountingRecordService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. <?php
  2. namespace App\Services;
  3. use App\Order;
  4. use App\OrderCountingRecord;
  5. use App\User;
  6. use Carbon\Carbon;
  7. use Illuminate\Support\Collection;
  8. use Illuminate\Support\Facades\Cache;
  9. class NewOrderCountingRecordService
  10. {
  11. public function orderCountingRecords($start, $end, $unit, $ownerIds)
  12. {
  13. $key = 'orderCountingRecords_' . $start . '_' . $end . '_' . $unit . '_' . json_encode($ownerIds);
  14. $queryCondition = $this->transfersToCondition($start, $end, $unit, $ownerIds);
  15. return cache()->remember($key, 600, function () use ($queryCondition) {
  16. return $this->getOrderCountingRecords($queryCondition);
  17. });
  18. }
  19. public function getFromCache($queryCondition)
  20. {
  21. $lackingCondition = [];
  22. $orderCountingRecords_FromCache = collect();
  23. $lackingCondition['unit'] = $queryCondition['unit'];
  24. foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
  25. foreach ($ownerIds as $ownerId) {
  26. $key = 'order_counting_records_' . $dateStr . '_' . $ownerId . '_' . $queryCondition['unit'];
  27. $items = cache()->get($key);
  28. if (empty($items)) {
  29. if (empty($lackingCondition['data'][$dateStr])) {
  30. $lackingCondition['data'][$dateStr] = [];
  31. }
  32. $lackingCondition['data'][$dateStr][] = $ownerId;
  33. } else {
  34. foreach ($items as $item) {
  35. $orderCountingRecords_FromCache->push($item);
  36. }
  37. }
  38. }
  39. }
  40. return [$orderCountingRecords_FromCache, $lackingCondition];
  41. }
  42. public function dataFromMiddleTable($queryCondition)
  43. {
  44. $result = [];
  45. $orderSqlBuilder = OrderCountingRecord::query();
  46. $unit = $queryCondition['unit'];
  47. foreach ($queryCondition['data'] as $date => $owners) {
  48. $orderSqlBuilder->orWhere(function ($query) use ($owners, $date, $unit) {
  49. $query->whereIn('owner_id', $owners)->where('date_target', $date)->where('counting_unit', $unit);
  50. });
  51. }
  52. $dataFromMiddleTable = $orderSqlBuilder->get();
  53. $this->insertIntoCache($dataFromMiddleTable, $unit);
  54. $queryCondition = $this->unQueryCondition($dataFromMiddleTable, $queryCondition);
  55. $orderCountingRecords_fromSelfTable = $dataFromMiddleTable;
  56. $lackingCondition = $queryCondition;
  57. return [$orderCountingRecords_fromSelfTable, $lackingCondition];
  58. }
  59. public function getOrderCountingRecords($queryCondition)
  60. {
  61. list($orderCountingRecords_fromCache, $lackingCondition)
  62. = $this->getFromCache($queryCondition);
  63. if (empty($lackingCondition['data'])) {
  64. return $orderCountingRecords_fromCache;
  65. }
  66. list($orderCountingRecords_fromSelfTable, $lackingCondition)
  67. = $this->dataFromMiddleTable($lackingCondition);
  68. if (empty($lackingCondition['data'])) {
  69. return $orderCountingRecords_fromCache->concat($orderCountingRecords_fromSelfTable);
  70. }
  71. if ($queryCondition['unit'] != '日') {
  72. list($orderCountingRecords_combinedByLower, $lackingCondition)
  73. = $this->getByLowerUnit($lackingCondition);
  74. }
  75. if (!empty($lackingCondition)) {
  76. $orderCountingRecords_FromOrder = $this->dataFromOrder($lackingCondition);
  77. }
  78. return $orderCountingRecords_FromOrder ?? collect()
  79. ->concat($orderCountingRecords_fromCache)
  80. ->concat($orderCountingRecords_fromSelfTable)
  81. ->concat($orderCountingRecords_combinedByLower ?? collect());
  82. }
  83. public function getByLowerUnit($queryCondition)
  84. {
  85. switch ($queryCondition['unit']) {
  86. case '年':
  87. break;
  88. case '月':
  89. $lowUnit = '周';
  90. $conditionClone = ['unit' => $lowUnit, 'data' => []];
  91. foreach ($queryCondition['data'] as $date => $ownerIds) {
  92. $startAt = $date;
  93. $endAt = Carbon::parse($date)->endOfMonth()->toDateString();
  94. $items = $this->transfersToCondition(
  95. $startAt, $endAt, $lowUnit, $ownerIds
  96. )['data'];
  97. foreach ($items as $dateStr => $item) {
  98. if (empty($conditionClone['data'][$dateStr])) $conditionClone['data'][$dateStr] = $dateStr;
  99. $conditionClone['data'][$dateStr] = ($item);
  100. }
  101. }
  102. $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
  103. $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'month');
  104. break;
  105. case '周':
  106. $lowUnit = '日';
  107. $conditionClone = ['unit' => $lowUnit, 'data' => []];
  108. foreach ($queryCondition['data'] as $date => $ownerIds) {
  109. $startAt = $date;
  110. $endAt = Carbon::parse($date)->endOfWeek()->toDateString();
  111. $items = $this->transfersToCondition(
  112. $startAt, $endAt, $lowUnit, $ownerIds
  113. )['data'];
  114. foreach ($items as $dateStr => $item) {
  115. if (empty($conditionClone['data'][$dateStr])) $conditionClone['data'][$dateStr] = $dateStr;
  116. $conditionClone['data'][$dateStr] = ($item);
  117. }
  118. }
  119. $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
  120. $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'week');
  121. break;
  122. case '日':
  123. return [[], $queryCondition];
  124. default:
  125. }
  126. return [$orderCountingRecords_combinedByLower, []];
  127. }
  128. public function transfersToCondition($start, $end, $unit, $ownerIds)
  129. {
  130. $condition = [
  131. 'data' => [],
  132. 'unit' => $unit,];
  133. $startAt = Carbon::parse($start);
  134. $dates = [];
  135. switch ($unit) {
  136. case '年':
  137. $dates = collect($startAt->yearsUntil($end, 1)->toArray())
  138. ->map(function (Carbon $date) {
  139. return $date->firstOfYear();
  140. });
  141. break;
  142. case '月':
  143. $dates = collect($startAt->monthsUntil($end, 1)->toArray())
  144. ->map(function (Carbon $date) {
  145. return $date->firstOfMonth();
  146. });
  147. break;
  148. case '周':
  149. $dates = collect($startAt->weeksUntil($end, 1)->toArray())
  150. ->map(function (Carbon $date) {
  151. return $date->startOfWeek();
  152. });
  153. break;
  154. case '日':
  155. $dates = collect($startAt->daysUntil($end, 1)->toArray())
  156. ->map(function (Carbon $date) {
  157. return $date->startOfDay();
  158. });
  159. break;
  160. default:
  161. }
  162. foreach ($dates as $day) {
  163. $condition['data'][$day->toDateString()] = $ownerIds;
  164. }
  165. return $condition;
  166. }
  167. public function dataFromOrder($queryCondition)
  168. {
  169. $orderSqlBuilder = Order::query()->selectRaw("owner_id,warehouse_id,shop_id,logistic_id,count(1) as amounts ,DATE_FORMAT(created_at,'%Y-%m-%d') as date_target");
  170. foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
  171. $orderSqlBuilder->orWhere(function ($query) use ($ownerIds, $dateStr) {
  172. $query->whereIn('owner_id', $ownerIds)->where('created_at', '>', $dateStr)->where('created_at', '<', Carbon::parse($dateStr)->addDay()->toDateString())->where('wms_status', '订单完成');
  173. });
  174. }
  175. $dataFromOrder = $orderSqlBuilder->groupBy(['owner_id', 'warehouse_id', 'shop_id', 'logistic_id', 'date_target'])->get();
  176. $dataFromMiddleTable = $this->ordersToOrderCountingRecords($dataFromOrder, $queryCondition['unit']);
  177. $this->setDefultData($dataFromMiddleTable, $queryCondition);
  178. $this->insertIntoMiddleTable($dataFromMiddleTable);
  179. $this->insertIntoCache($dataFromMiddleTable, $queryCondition['unit']);
  180. return $dataFromMiddleTable;
  181. }
  182. public function insertIntoMiddleTable($data)
  183. {
  184. $data->filter(function ($item) {
  185. return $this->isNotCurrentDate($item->date_target);
  186. })->chunk(1000)->each(function ($item) {
  187. OrderCountingRecord::query()->insert($item->toArray());
  188. });
  189. }
  190. public function insertIntoCache($collect, $unit)
  191. {
  192. $map = [];
  193. $collect->each(function ($order) use ($unit, &$map) {
  194. $key = "order_counting_records_{$order->date_target}_{$order->owner_id}_{$unit}";
  195. if (empty($map[$key])) $map[$key] = [];
  196. $map[$key][] = $order;
  197. });
  198. foreach ($map as $key => $orders) {
  199. $ttl = 3600 * 24;
  200. if (!$this->isNotCurrentDate($orders[0]['date_target'])) {
  201. $ttl = 70;
  202. }
  203. Cache::put($key, collect($orders), $ttl);
  204. }
  205. }
  206. public function isNotCurrentDate($dateStr): bool
  207. {
  208. return $dateStr != Carbon::now()->format('Y-m-d')
  209. && $dateStr != Carbon::now()->year . '-' . Carbon::now()->week
  210. && $dateStr != Carbon::now()->year . '-' . Carbon::now()->month;
  211. }
  212. public function unQueryCondition($dataFromMiddleTable, $unQueryCondition)
  213. {
  214. $map = [];
  215. $dataFromMiddleTable->each(function ($item) use (&$map) {
  216. $key = 'owner_id=' . $item->owner_id . ' date_target' . $item->date_target;
  217. $map[$key] = true;
  218. });
  219. foreach ($unQueryCondition['data'] as $dateStr => $ownerIds) {
  220. foreach ($ownerIds as $key => $ownerId) {
  221. $key1 = 'owner_id=' . $ownerId . ' date_target' . $dateStr;
  222. if (isset($map[$key1])) {
  223. //中间表查找到数据
  224. unset($unQueryCondition['data'][$dateStr][$key]);
  225. }
  226. }
  227. }
  228. return $unQueryCondition;
  229. }
  230. public function ordersToOrderCountingRecords($dataFromOrder, $unit)
  231. {
  232. $dataFromMiddleTable = collect();
  233. //当日当周当月当年的数据不能插入到中间表
  234. $dateTime = Carbon::now()->toDateTimeString();
  235. foreach ($dataFromOrder as $order) {
  236. $carbon = Carbon::parse($order->date_target);
  237. $year = $carbon->year;
  238. $week = $carbon->week;
  239. $month = $carbon->month;
  240. $dataFromMiddleTable->push(new OrderCountingRecord([
  241. 'owner_id' => $order->owner_id,
  242. 'shop_id' => $order->shop_id,
  243. 'warehouse_id' => $order->warehouse_id,
  244. 'logistic_id' => $order->logistic_id,
  245. 'date_target' => $order->date_target,
  246. 'counting_unit' => $unit,
  247. 'amount' => $order->amounts,
  248. 'week' => $year . '-' . $week,
  249. 'month' => $year . '-' . $month,
  250. 'year' => $year . '',
  251. 'created_at' => $dateTime,
  252. 'updated_at' => $dateTime,
  253. ]));
  254. }
  255. return $dataFromMiddleTable;
  256. }
  257. public function count($orderCountingRecords_days, $unit)
  258. {
  259. $isEnd = false;
  260. $result = collect();
  261. $item = null;
  262. $amount = 0;
  263. foreach ($orderCountingRecords_days as $itemToCount) {
  264. if ($itemToCount instanceof OrderCountingRecord) {
  265. if (!$isEnd) {
  266. $isEnd = true;
  267. $item = clone($itemToCount);
  268. }
  269. $amount += $itemToCount->amount;
  270. } else {
  271. $result = $result->concat($this->count($itemToCount, $unit));
  272. }
  273. }
  274. if ($isEnd) {
  275. switch ($unit) {
  276. case "日":
  277. $item['date_target'] = Carbon::parse($item['date_target'])->startOfWeek()->toDateString();
  278. break;
  279. case "周":
  280. $item['date_target'] = Carbon::parse($item['date_target'])->firstOfMonth()->toDateString();
  281. break;
  282. case "月":
  283. $item['date_target'] = Carbon::parse($item['date_target'])->firstOfYear()->toDateString();
  284. break;
  285. }
  286. $item['amount'] = $amount;
  287. $item['counting_unit'] = $unit;
  288. return $result->push($item);
  289. }
  290. return $result;
  291. }
  292. public function turnGradingUpToLow($orderCountingRecords_days, $unit, $grading)
  293. {
  294. $orderCountingRecords_days = $orderCountingRecords_days->groupBy(['owner_id', 'shop_id', 'warehouse_id', 'logistic_id', $grading]);
  295. return $this->count($orderCountingRecords_days, $unit);
  296. }
  297. public function setDefultData($dataFromMiddleTable, $queryCondition)
  298. {
  299. $map = [];
  300. foreach ($dataFromMiddleTable as $data) {
  301. if (empty($map[$data->date_target . '-' . $data->owner_id])) $map[$data->date_target . '-' . $data->owner_id] = true;
  302. }
  303. foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
  304. foreach ($ownerIds as $ownerId) {
  305. if (empty($map[$dateStr . '-' . $ownerId]) && Carbon::parse($dateStr)->isBefore(Carbon::now())) {
  306. $carbon = Carbon::parse($dateStr);
  307. $year = $carbon->year;
  308. $week = $carbon->week;
  309. $month = $carbon->month;
  310. $dataFromMiddleTable->push(new OrderCountingRecord([
  311. 'owner_id' => $ownerId,
  312. 'shop_id' => null,
  313. 'warehouse_id' => null,
  314. 'logistic_id' => null,
  315. 'date_target' => $dateStr,
  316. 'counting_unit' => $queryCondition['unit'],
  317. 'amount' => 0,
  318. 'week' => $year . '-' . $week,
  319. 'month' => $year . '-' . $month,
  320. 'year' => $year . '',
  321. 'created_at' => $carbon->toDateString(),
  322. 'updated_at' => $carbon->toDateString(),
  323. ]));
  324. }
  325. }
  326. }
  327. }
  328. }