NewOrderCountingRecordService.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <?php
  2. namespace App\Services;
  3. use App\Logistic;
  4. use App\Order;
  5. use App\OrderCountingRecord;
  6. use App\Warehouse;
  7. use Carbon\Carbon;
  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. return Cache::remember($key, 60, function () use ($start, $end, $unit, $ownerIds) {
  15. $orders = $this->get($start, $end, $unit, $ownerIds);
  16. $dataList = collect();
  17. $orders->groupBy('date_target')->each(function ($items) use (&$dataList, $unit) {
  18. $counter = $items->reduce(function ($sum, $item) {
  19. return $sum + $item->amount;
  20. }, 0);
  21. $date_target = $items[0]->date_target;
  22. $dataList->push([
  23. 'counter' => $counter,
  24. 'date_target' => $date_target,
  25. ]);
  26. });
  27. return $dataList->sortBy("date_target");
  28. });
  29. }
  30. public function logisticsCountingRecords($start, $end, $ownerIds)
  31. {
  32. $key = 'logisticsCountingRecords_' . $start . '_' . $end . '_' . json_encode($ownerIds);
  33. return Cache::remember($key, 600, function () use ($start, $end, $ownerIds) {
  34. $dataList = collect();
  35. $resultOrders = $this->get($start, $end, '日', $ownerIds);
  36. $resultOrders->groupBy('logistic_id')->each(function ($item) use (&$dataList) {
  37. $counter = $item->reduce(function ($sum, $item) {
  38. return $sum + $item->amount;
  39. }, 0);
  40. $dataList->push([
  41. 'value' => $counter,
  42. 'logistic_id' => $item[0]->logistic_id,
  43. ]);
  44. });
  45. $map = [];
  46. $logistics = Logistic::query()->whereIn('id', data_get($dataList, '*.logistic_id'))->get();
  47. $logistics->each(function ($logistic) use (&$map) {
  48. $map[$logistic->id] = $logistic;
  49. });
  50. return $dataList->map(function (&$item) use ($map) {
  51. $logistic = $map[$item['logistic_id']] ?? '';
  52. $item['name'] = $logistic->name ?? '';
  53. return $item;
  54. });
  55. });
  56. }
  57. public function warehouseCountingRecords($start, $end, $ownerIds)
  58. {
  59. $key = 'warehouseCountingRecords_' . $start . '_' . $end . '_' . json_encode($ownerIds);
  60. return Cache::remember($key, 600, function () use ($start, $end, $ownerIds) {
  61. $dataList = collect();
  62. $resultOrders = $this->get($start, $end, '日', $ownerIds);
  63. $resultOrders->groupBy('warehouse_id')->each(function ($item) use (&$dataList) {
  64. $counter = $item->reduce(function ($sum, $item) {
  65. return $sum + $item->amount;
  66. }, 0);
  67. $dataList->push([
  68. 'value' => $counter,
  69. 'warehouse_id' => $item[0]->warehouse_id,
  70. ]);
  71. });
  72. $map = [];
  73. $logistics = Warehouse::query()->whereIn('id', data_get($dataList, '*.warehouse_id'))->get();
  74. $logistics->each(function ($warehouse) use (&$map) {
  75. $map[$warehouse->id] = $warehouse;
  76. });
  77. return $dataList->map(function (&$item) use ($map) {
  78. $warehouse = $map[$item['warehouse_id']] ?? '';
  79. $item['code'] = $warehouse->name ?? '';
  80. switch ($item['code']) {
  81. case 'WH01':
  82. $item['name'] = '松江一仓';
  83. break;
  84. case 'WH02':
  85. $item['name'] = '松江二仓';
  86. break;
  87. case 'WH03':
  88. $item['name'] = '嘉定一仓';
  89. break;
  90. default:
  91. $item['name'] = '仓库为空';
  92. break;
  93. }
  94. return $item;
  95. });
  96. });
  97. }
  98. public function get($start, $end, $unit, $ownerIds)
  99. {
  100. $queryCondition = $this->transfersToCondition($start, $end, $unit, $ownerIds);
  101. return $this->getOrderCountingRecords($queryCondition);
  102. }
  103. public function getFromCache($queryCondition)
  104. {
  105. $lackingCondition = [];
  106. $orderCountingRecords_FromCache = collect();
  107. $lackingCondition['unit'] = $queryCondition['unit'];
  108. foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
  109. foreach ($ownerIds as $ownerId) {
  110. $key = 'order_counting_records_' . $dateStr . '_' . $ownerId . '_' . $queryCondition['unit'];
  111. $items = cache()->get($key);
  112. if (empty($items)) {
  113. if (empty($lackingCondition['data'][$dateStr])) {
  114. $lackingCondition['data'][$dateStr] = [];
  115. }
  116. $lackingCondition['data'][$dateStr][] = $ownerId;
  117. } else {
  118. foreach ($items as $item) {
  119. $orderCountingRecords_FromCache->push($item);
  120. }
  121. }
  122. }
  123. }
  124. return [$orderCountingRecords_FromCache, $lackingCondition];
  125. }
  126. public function dataFromMiddleTable($queryCondition)
  127. {
  128. $result = [];
  129. $orderSqlBuilder = OrderCountingRecord::query();
  130. $unit = $queryCondition['unit'];
  131. foreach ($queryCondition['data'] as $date => $owners) {
  132. $orderSqlBuilder->orWhere(function ($query) use ($owners, $date, $unit) {
  133. $query->whereIn('owner_id', $owners)->where('date_target', $date)->where('counting_unit', $unit);
  134. });
  135. }
  136. $dataFromMiddleTable = $orderSqlBuilder->get();
  137. $this->insertIntoCache($dataFromMiddleTable, $unit);
  138. $queryCondition = $this->unQueryCondition($dataFromMiddleTable, $queryCondition);
  139. $orderCountingRecords_fromSelfTable = $dataFromMiddleTable;
  140. $lackingCondition = $queryCondition;
  141. return [$orderCountingRecords_fromSelfTable, $lackingCondition];
  142. }
  143. public function getOrderCountingRecords($queryCondition)
  144. {
  145. list($orderCountingRecords_fromCache, $lackingCondition)
  146. = $this->getFromCache($queryCondition);
  147. if (empty($lackingCondition['data'])) {
  148. return $orderCountingRecords_fromCache;
  149. }
  150. list($orderCountingRecords_fromSelfTable, $lackingCondition)
  151. = $this->dataFromMiddleTable($lackingCondition);
  152. if (empty($lackingCondition['data'])) {
  153. return $orderCountingRecords_fromCache->concat($orderCountingRecords_fromSelfTable);
  154. }
  155. list($orderCountingRecords_combinedByLower, $lackingCondition)
  156. = $this->getByLowerUnit($lackingCondition);
  157. if (!empty($lackingCondition)) {
  158. $orderCountingRecords_FromOrder = $this->dataFromOrder($lackingCondition);
  159. }
  160. return $orderCountingRecords_FromOrder ?? collect()
  161. ->concat($orderCountingRecords_fromCache)
  162. ->concat($orderCountingRecords_fromSelfTable)
  163. ->concat($orderCountingRecords_combinedByLower ?? collect());
  164. }
  165. public function getByLowerUnit($queryCondition)
  166. {
  167. switch ($queryCondition['unit']) {
  168. case '年':
  169. $lowUnit = '月';
  170. $conditionClone = ['unit' => $lowUnit, 'data' => []];
  171. foreach ($queryCondition['data'] as $date => $ownerIds) {
  172. $startAt = $date;
  173. $endAt = Carbon::parse($date)->endOfYear()->toDateString();
  174. $items = $this->transfersToCondition(
  175. $startAt, $endAt, $lowUnit, $ownerIds
  176. )['data'];
  177. foreach ($items as $dateStr => $item) {
  178. if (empty($conditionClone['data'][$dateStr])) $conditionClone['data'][$dateStr] = $dateStr;
  179. $conditionClone['data'][$dateStr] = ($item);
  180. }
  181. }
  182. $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
  183. $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'year');
  184. break;
  185. case '月':
  186. $lowUnit = '日';
  187. $conditionClone = ['unit' => $lowUnit, 'data' => []];
  188. foreach ($queryCondition['data'] as $date => $ownerIds) {
  189. $startAt = $date;
  190. $endAt = Carbon::parse($date)->endOfMonth()->toDateString();
  191. $items = $this->transfersToCondition(
  192. $startAt, $endAt, $lowUnit, $ownerIds
  193. )['data'];
  194. foreach ($items as $dateStr => $item) {
  195. if (empty($conditionClone['data'][$dateStr])) $conditionClone['data'][$dateStr] = $dateStr;
  196. $conditionClone['data'][$dateStr] = ($item);
  197. }
  198. }
  199. $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
  200. $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'month');
  201. break;
  202. case '日':
  203. return [[], $queryCondition];
  204. default:
  205. }
  206. return [$orderCountingRecords_combinedByLower, []];
  207. }
  208. public function transfersToCondition($start, $end, $unit, $ownerIds)
  209. {
  210. $condition = [
  211. 'data' => [],
  212. 'unit' => $unit,];
  213. $startAt = Carbon::parse($start);
  214. $dates = [];
  215. switch ($unit) {
  216. case '年':
  217. $dates = collect($startAt->yearsUntil($end, 1)->toArray())
  218. ->map(function (Carbon $date) {
  219. return $date->firstOfYear();
  220. });
  221. break;
  222. case '月':
  223. $dates = collect($startAt->monthsUntil($end, 1)->toArray())
  224. ->map(function (Carbon $date) {
  225. return $date->firstOfMonth();
  226. });
  227. break;
  228. case '日':
  229. $dates = collect($startAt->daysUntil($end, 1)->toArray())
  230. ->map(function (Carbon $date) {
  231. return $date->startOfDay();
  232. });
  233. break;
  234. default:
  235. }
  236. foreach ($dates as $day) {
  237. $condition['data'][$day->toDateString()] = $ownerIds;
  238. }
  239. return $condition;
  240. }
  241. public function dataFromOrder($queryCondition)
  242. {
  243. $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");
  244. foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
  245. $orderSqlBuilder->orWhere(function ($query) use ($ownerIds, $dateStr) {
  246. $query->whereIn('owner_id', $ownerIds)->where('created_at', '>', $dateStr)->where('created_at', '<', Carbon::parse($dateStr)->addDay()->toDateString())->where('wms_status', '订单完成');
  247. });
  248. }
  249. $dataFromOrder = $orderSqlBuilder->groupBy(['owner_id', 'warehouse_id', 'shop_id', 'logistic_id', 'date_target'])->get();
  250. $dataFromMiddleTable = $this->ordersToOrderCountingRecords($dataFromOrder, $queryCondition['unit']);
  251. $this->setDefultData($dataFromMiddleTable, $queryCondition);
  252. $this->insertIntoMiddleTable($dataFromMiddleTable);
  253. $this->insertIntoCache($dataFromMiddleTable, $queryCondition['unit']);
  254. return $dataFromMiddleTable;
  255. }
  256. public function insertIntoMiddleTable($data)
  257. {
  258. $data->filter(function ($item) {
  259. return $this->isNotCurrentDate($item->date_target);
  260. })->chunk(1000)->each(function ($item) {
  261. OrderCountingRecord::query()->insert($item->toArray());
  262. });
  263. }
  264. public function insertIntoCache($collect, $unit)
  265. {
  266. $map = [];
  267. $collect->each(function ($order) use ($unit, &$map) {
  268. $key = "order_counting_records_{$order->date_target}_{$order->owner_id}_{$unit}";
  269. if (empty($map[$key])) $map[$key] = [];
  270. $map[$key][] = $order;
  271. });
  272. foreach ($map as $key => $orders) {
  273. $ttl = 3600 * 24;
  274. if (!$this->isNotCurrentDate($orders[0]['date_target'])) {
  275. $ttl = 70;
  276. }
  277. Cache::put($key, collect($orders), $ttl);
  278. }
  279. }
  280. public function isNotCurrentDate($dateStr): bool
  281. {
  282. return $dateStr != Carbon::now()->format('Y-m-d')
  283. && $dateStr != Carbon::now()->year . '-' . Carbon::now()->month;
  284. }
  285. public function unQueryCondition($dataFromMiddleTable, $unQueryCondition)
  286. {
  287. $map = [];
  288. $dataFromMiddleTable->each(function ($item) use (&$map) {
  289. $key = 'owner_id=' . $item->owner_id . ' date_target' . $item->date_target;
  290. $map[$key] = true;
  291. });
  292. foreach ($unQueryCondition['data'] as $dateStr => $ownerIds) {
  293. foreach ($ownerIds as $key => $ownerId) {
  294. $key1 = 'owner_id=' . $ownerId . ' date_target' . $dateStr;
  295. if (isset($map[$key1])) {
  296. //中间表查找到数据
  297. unset($unQueryCondition['data'][$dateStr][$key]);
  298. }
  299. }
  300. if (empty($unQueryCondition['data'][$dateStr])) {
  301. unset($unQueryCondition['data'][$dateStr]);
  302. }
  303. }
  304. return $unQueryCondition;
  305. }
  306. public function ordersToOrderCountingRecords($dataFromOrder, $unit)
  307. {
  308. $dataFromMiddleTable = collect();
  309. //当日当周当月当年的数据不能插入到中间表
  310. $dateTime = Carbon::now()->toDateTimeString();
  311. foreach ($dataFromOrder as $order) {
  312. $carbon = Carbon::parse($order->date_target);
  313. $year = $carbon->year;
  314. $week = $carbon->week;
  315. $month = $carbon->month;
  316. $dataFromMiddleTable->push(new OrderCountingRecord([
  317. 'owner_id' => $order->owner_id,
  318. 'shop_id' => $order->shop_id,
  319. 'warehouse_id' => $order->warehouse_id,
  320. 'logistic_id' => $order->logistic_id,
  321. 'date_target' => $order->date_target,
  322. 'counting_unit' => $unit,
  323. 'amount' => $order->amounts,
  324. 'week' => $year . '-' . $week,
  325. 'month' => $year . '-' . $month,
  326. 'year' => $year . '',
  327. 'created_at' => $dateTime,
  328. 'updated_at' => $dateTime,
  329. ]));
  330. }
  331. return $dataFromMiddleTable;
  332. }
  333. public function count($orderCountingRecords_days, $unit)
  334. {
  335. $isEnd = false;
  336. $result = collect();
  337. $item = null;
  338. $amount = 0;
  339. foreach ($orderCountingRecords_days as $itemToCount) {
  340. if ($itemToCount instanceof OrderCountingRecord) {
  341. if (!$isEnd) {
  342. $isEnd = true;
  343. $item = clone($itemToCount);
  344. }
  345. $amount += $itemToCount->amount;
  346. } else {
  347. $result = $result->concat($this->count($itemToCount, $unit));
  348. }
  349. }
  350. if ($isEnd) {
  351. switch ($unit) {
  352. case "日":
  353. $item['date_target'] = Carbon::parse($item['date_target'])->firstOfMonth()->toDateString();
  354. break;
  355. case "月":
  356. $item['date_target'] = Carbon::parse($item['date_target'])->firstOfYear()->toDateString();
  357. break;
  358. }
  359. $item['amount'] = $amount;
  360. $item['counting_unit'] = $unit;
  361. return $result->push($item);
  362. }
  363. return $result;
  364. }
  365. public function turnGradingUpToLow($orderCountingRecords_days, $unit, $grading)
  366. {
  367. $orderCountingRecords_days = $orderCountingRecords_days->groupBy(['owner_id', 'shop_id', 'warehouse_id', 'logistic_id', $grading]);
  368. return $this->count($orderCountingRecords_days, $unit);
  369. }
  370. public function setDefultData($dataFromMiddleTable, $queryCondition)
  371. {
  372. $map = [];
  373. foreach ($dataFromMiddleTable as $data) {
  374. if (empty($map[$data->date_target . '-' . $data->owner_id])) $map[$data->date_target . '-' . $data->owner_id] = true;
  375. }
  376. foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
  377. foreach ($ownerIds as $ownerId) {
  378. if (empty($map[$dateStr . '-' . $ownerId]) && Carbon::parse($dateStr)->isBefore(Carbon::now())) {
  379. $carbon = Carbon::parse($dateStr);
  380. $year = $carbon->year;
  381. $week = $carbon->week;
  382. $month = $carbon->month;
  383. $dataFromMiddleTable->push(new OrderCountingRecord([
  384. 'owner_id' => $ownerId,
  385. 'shop_id' => null,
  386. 'warehouse_id' => null,
  387. 'logistic_id' => null,
  388. 'date_target' => $dateStr,
  389. 'counting_unit' => $queryCondition['unit'],
  390. 'amount' => 0,
  391. 'week' => $year . '-' . $week,
  392. 'month' => $year . '-' . $month,
  393. 'year' => $year . '',
  394. 'created_at' => $carbon->toDateString(),
  395. 'updated_at' => $carbon->toDateString(),
  396. ]));
  397. }
  398. }
  399. }
  400. }
  401. }