OrderCountingRecordService.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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 DateTime;
  9. use Illuminate\Database\Eloquent\Builder;
  10. use Illuminate\Database\Eloquent\Collection;
  11. use Illuminate\Support\Facades\Auth;
  12. use Illuminate\Support\Facades\Cache;
  13. use App\User;
  14. use Illuminate\Support\Str;
  15. class OrderCountingRecordService
  16. {
  17. /** @var $ownerService OwnerService */
  18. private $ownerService = null;
  19. function __construct()
  20. {
  21. $this->ownerService = app(OwnerService::class);
  22. }
  23. /**
  24. * @param $start
  25. * @param $end
  26. * @param null $ownerIds ;
  27. * @param string $unit
  28. * @param $user
  29. * @return mixed
  30. */
  31. public function get($start, $end, $ownerIds = null, $unit = '日', $user)
  32. {
  33. $resultByCache = $this->getByCache($start, $end, $ownerIds, $unit, $user);
  34. if (!($resultByCache['unExistingOrders'])) return $resultByCache['resultOrders'];
  35. $resultByOrderCountingRecords = $this->getByDatabase($resultByCache['unExistingOrders'], $unit);
  36. $this->createByDatabase($resultByOrderCountingRecords['unExistingOrders'], $unit);
  37. $this->getByDatabase($resultByCache['unExistingOrders'], $unit);
  38. $resultByCache = $this->getByCache($start, $end, $ownerIds, $unit, $user);
  39. return $resultByCache['resultOrders'];
  40. }
  41. public function orderCountingRecords($start, $end, $ownerIds = null, $unit = '日', $user = null)
  42. {
  43. $key = 'orderCountingRecords_' . $start . '_' . $end . '_' . $unit . '_' . Auth::user()->id;
  44. return Cache::remember($key, 60, function () use ($start, $end, $unit, $ownerIds, $user) {
  45. $orders = $this->get($start, $end, null, $unit, null);
  46. $dataList = collect();
  47. $orders->groupBy('date_target')->each(function ($items) use (&$dataList, $unit) {
  48. $counter = $items->reduce(function ($sum, $item) {
  49. return $sum + $item->amount;
  50. }, 0);
  51. $date_target = $items[0]->date_target;
  52. if ($unit == '周') {
  53. $date_target = (new DateTime())->setISODate(Str::of($date_target)->explode('-')[0], Str::of($date_target)->explode('-')[1])->format('yy-m-d');
  54. }
  55. $dataList->push([
  56. 'counter' => $counter,
  57. 'date_target' => $date_target,
  58. ]);
  59. });
  60. return $dataList->sortBy("date_target");
  61. });
  62. }
  63. /**
  64. * @param $start
  65. * @param $end
  66. * @param null $ownerIds
  67. * @param null $user
  68. * @return \Illuminate\Support\Collection|\Tightenco\Collect\Support\Collection
  69. */
  70. public function logisticsCountingRecords($start, $end, $ownerIds = null, $user = null)
  71. {
  72. $key = 'logisticsCountingRecords_' . $start . '_' . $end . '_' . Auth::user()->id;
  73. return Cache::remember($key, 600, function () use ($start, $end, $ownerIds, $user) {
  74. $dataList = collect();
  75. $resultOrders = $this->get($start, $end, $ownerIds, '日', $user);
  76. $resultOrders->groupBy('logistic_id')->each(function ($item) use (&$dataList) {
  77. $counter = $item->reduce(function ($sum, $item) {
  78. return $sum + $item->amount;
  79. }, 0);
  80. $dataList->push([
  81. 'value' => $counter,
  82. 'logistic_id' => $item[0]->logistic_id,
  83. ]);
  84. });
  85. $map = [];
  86. $logistics = Logistic::query()->whereIn('id', data_get($dataList, '*.logistic_id'))->get();
  87. $logistics->each(function ($logistic) use (&$map) {
  88. $map[$logistic->id] = $logistic;
  89. });
  90. return $dataList->map(function (&$item) use ($map) {
  91. $logistic = $map[$item['logistic_id']] ?? '';
  92. $item['name'] = $logistic->name ?? '';
  93. return $item;
  94. });
  95. });
  96. }
  97. public function warehouseCountingRecords($start, $end, $ownerIds = null, $user = null)
  98. {
  99. $key = 'warehouseCountingRecords_' . $start . '_' . $end . '_' . Auth::user()->id;
  100. return Cache::remember($key, 600, function () use ($start, $end, $ownerIds, $user) {
  101. $dataList = collect();
  102. $resultOrders = $this->get($start, $end, $ownerIds, '日', $user);
  103. $resultOrders->groupBy('warehouse_id')->each(function ($item) use (&$dataList) {
  104. $counter = $item->reduce(function ($sum, $item) {
  105. return $sum + $item->amount;
  106. }, 0);
  107. $dataList->push([
  108. 'value' => $counter,
  109. 'warehouse_id' => $item[0]->warehouse_id,
  110. ]);
  111. });
  112. $map = [];
  113. $logistics = Warehouse::query()->whereIn('id', data_get($dataList, '*.warehouse_id'))->get();
  114. $logistics->each(function ($warehouse) use (&$map) {
  115. $map[$warehouse->id] = $warehouse;
  116. });
  117. return $dataList->map(function (&$item) use ($map) {
  118. $warehouse = $map[$item['warehouse_id']] ?? '';
  119. $item['code'] = $warehouse->name ?? '';
  120. switch ($item['code']) {
  121. case 'WH01':
  122. $item['name'] = '松江一仓';
  123. break;
  124. case 'WH02':
  125. $item['name'] = '松江二仓';
  126. break;
  127. case 'WH03':
  128. $item['name'] = '嘉定一仓';
  129. break;
  130. default:
  131. $item['name'] = '仓库为空';
  132. break;
  133. }
  134. return $item;
  135. });
  136. });
  137. }
  138. /**
  139. * @param $start
  140. * @param $end
  141. * @param null $ownerIds
  142. * @param string $unit
  143. * @param $user
  144. * @return array
  145. */
  146. public function getByCache($start, $end, $ownerIds = null, $unit = '日', $user)
  147. {// Order[] results, Array [$date=>[$ownerIds]]
  148. $countingOwnerIds = $this->getCountingOwnerIds($ownerIds, $user);
  149. $resultOrders = collect();
  150. $unExistingOrders = [];
  151. $dateArray = $this->periodDateToArray($start, $end, $unit);
  152. foreach ($dateArray as $dateStr) {
  153. foreach ($countingOwnerIds as $ownerId) {
  154. $key = "order_counting_records_{$dateStr}_{$ownerId}_{$unit}";
  155. $orders = Cache::get($key);
  156. if ($orders) {
  157. $orders->each(function ($item) use (&$resultOrders) {
  158. $resultOrders->push($item);
  159. });
  160. continue;
  161. }
  162. $unExistingOrders[$dateStr][] = $ownerId;
  163. }
  164. }
  165. return ['resultOrders' => $resultOrders, 'unExistingOrders' => $unExistingOrders];
  166. }
  167. public function getByDatabase($targetOwnerIdsUnderDates, $unit = '日')
  168. {// Order[] results, Array [$date=>[$ownerIds]]
  169. $orderSqlBuilder = OrderCountingRecord::query();
  170. foreach ($targetOwnerIdsUnderDates as $date => $owners) {
  171. $orderSqlBuilder->orWhere(function ($query) use ($owners, $date, $unit) {
  172. $query->whereIn('owner_id', $owners)->where('date_target', $date)->where('counting_unit', $unit);
  173. });
  174. }
  175. $resultOrders = $orderSqlBuilder->get();
  176. $resultOrders->groupBy(['date_target', 'owner_id'])->each(function ($item, $dateStr) use ($unit) {
  177. $item->each(function ($item, $owner_id) use ($dateStr, $unit) {
  178. $key = "order_counting_records_{$dateStr}_{$owner_id}_{$unit}";
  179. $ttl = 3600 * 24;
  180. if (!$this->isNotCurrentDate($dateStr)) {
  181. $ttl = 70;
  182. }
  183. Cache::put($key, $item, $ttl);
  184. });
  185. });
  186. $map = [];
  187. $resultOrders->each(function ($item) use (&$map) {
  188. $key = 'owner_id=' . $item->owner_id . ' date_target' . $item->date_target;
  189. $map[$key] = true;
  190. });
  191. foreach ($targetOwnerIdsUnderDates as $dateStr => $ownerIds) {
  192. foreach ($ownerIds as $key => $ownerId) {
  193. $key1 = 'owner_id=' . $ownerId . ' date_target' . $dateStr;
  194. if (isset($map[$key1]) && $this->isNotCurrentDate($dateStr)) {
  195. //中间表查找到数据,并且时间不是当前日期
  196. unset($targetOwnerIdsUnderDates[$dateStr][$key]);
  197. }
  198. }
  199. }
  200. return ['resultOrders' => $resultOrders, 'unExistingOrders' => $targetOwnerIdsUnderDates];
  201. }
  202. public function createByDatabase($targetOwnerIdsUnderDates, $unit = '日')
  203. {// Order[] results]
  204. switch ($unit) {
  205. case '日':
  206. $resultOrders = $this->getCreateByDatabaseUnitDay($targetOwnerIdsUnderDates);
  207. break;
  208. case'周':
  209. $resultOrders = $this->getCreateByDatabaseUnitWeek($targetOwnerIdsUnderDates);
  210. break;
  211. case'月':
  212. $resultOrders = $this->getCreateByDatabaseUnitMonth($targetOwnerIdsUnderDates);
  213. break;
  214. default:
  215. $resultOrders = collect();
  216. break;
  217. }
  218. $result = collect();
  219. $isHasCurrentDate = false;
  220. $currentDate = null;
  221. foreach ($targetOwnerIdsUnderDates as $dateStr => $ownerIds) {
  222. if ($this->isNotCurrentDate($dateStr)) {
  223. foreach ($ownerIds as $ownerId) {
  224. if ($resultOrders->where('date_target', $dateStr)->where('owner_id', $ownerId)->count() == 0) {
  225. $result->push([
  226. 'owner_id' => $ownerId,
  227. 'shop_id' => null,
  228. 'warehouse_id' => null,
  229. 'logistic_id' => null,
  230. 'date_target' => $dateStr,
  231. 'counting_unit' => $unit,
  232. 'amount' => 0,
  233. ]);
  234. }
  235. }
  236. } else {
  237. //查询范围包含当天
  238. $isHasCurrentDate = true;
  239. $currentDate = $dateStr;
  240. }
  241. }
  242. $resultOrders->each(function ($order) use (&$result, $unit) {
  243. $orderCountingRecord = new OrderCountingRecord([
  244. 'owner_id' => $order->owner_id,
  245. 'shop_id' => $order->shop_id,
  246. 'warehouse_id' => $order->warehouse_id,
  247. 'logistic_id' => $order->logistic_id,
  248. 'date_target' => $order->date_target,
  249. 'counting_unit' => $unit,
  250. 'amount' => $order->amounts,
  251. ]);
  252. $result->push($orderCountingRecord);
  253. });
  254. $this->insertDataToMiddle($isHasCurrentDate, $currentDate, $unit, $result);
  255. return ['resultOrders' => $result];
  256. }
  257. public function periodDateToArray($start, $end, $unit = '日')
  258. {
  259. $dataArray = [];
  260. switch ($unit) {
  261. case '日';
  262. foreach (Carbon::parse($start)->daysUntil($end, 1)->toArray() as $item) {
  263. $dataArray[] = $item->toDateString();
  264. }
  265. break;
  266. case '周';
  267. foreach (Carbon::parse($start)->weeksUntil($end, 1)->toArray() as $item) {
  268. $dataArray[] = $item->year . '-' . $item->week . '';
  269. }
  270. break;
  271. case '月';
  272. foreach (Carbon::parse($start)->monthsUntil($end, 1)->toArray() as $item) {
  273. $dataArray[] = $item->year . '-' . $item->format('m') . '';
  274. }
  275. break;
  276. case '年';
  277. foreach (Carbon::parse($start)->yearsUntil($end, 1)->toArray() as $item) {
  278. $dataArray[] = $item->year . '-' . $item->month . '';
  279. }
  280. break;
  281. default:
  282. break;
  283. }
  284. return $dataArray;
  285. }
  286. /**
  287. * @param $ownerIds
  288. * @return array
  289. */
  290. public function getCountingOwnerIds($ownerIds = null, $user): array
  291. {
  292. if ($user == null) {
  293. $user = auth()->user();
  294. }
  295. /** @var UserService $userService */
  296. $userService = app('UserService');
  297. $permittingOwnerIds = $userService->getPermittingOwnerIds($user);
  298. if (!$ownerIds) {
  299. return $permittingOwnerIds;
  300. }
  301. return Cache::remember(
  302. 'PermittingOwnerIds' . '_' . auth()->user()->id . '_' . implode('_', $ownerIds),
  303. 600, function () use ($ownerIds, $permittingOwnerIds) {
  304. /** @var User $user */
  305. return array_intersect($ownerIds, $permittingOwnerIds);
  306. });
  307. }
  308. /**
  309. * @param $targetOwnerIdsUnderDates
  310. * @return Builder[]|Collection
  311. */
  312. private function getCreateByDatabaseUnitDay($targetOwnerIdsUnderDates)
  313. {
  314. $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");
  315. foreach ($targetOwnerIdsUnderDates as $dateStr => $ownerIds) {
  316. $orderSqlBuilder->orWhere(function ($query) use ($ownerIds, $dateStr) {
  317. $query->whereIn('owner_id', $ownerIds)->where('created_at', '>', $dateStr)->where('created_at', '<', Carbon::parse($dateStr)->addDay()->toDateString())->where('wms_status', '订单完成');
  318. });
  319. }
  320. return $orderSqlBuilder->groupBy(['owner_id', 'warehouse_id', 'shop_id', 'logistic_id', 'date_target'])->get();
  321. }
  322. private function getCreateByDatabaseUnitWeek($targetOwnerIdsUnderDates)
  323. {
  324. $orderSqlBuilder = Order::query()->selectRaw("owner_id,warehouse_id,shop_id,logistic_id,count(1) as amounts ,DATE_FORMAT(created_at,'%x-%v') as date_target");
  325. foreach ($targetOwnerIdsUnderDates as $dateStr => $ownerIds) {
  326. $orderSqlBuilder->orWhere(function ($query) use ($ownerIds, $dateStr) {
  327. $dateStr = (new DateTime())->setISODate(Str::of($dateStr)->explode('-')[0], Str::of($dateStr)->explode('-')[1])->format('yy-m-d');
  328. $query->whereIn('owner_id', $ownerIds)->where('created_at', '>', $dateStr)->where('created_at', '<=', Carbon::parse($dateStr)->addWeek()->toDateString())->where('wms_status', '订单完成');
  329. });
  330. }
  331. return $orderSqlBuilder->groupBy(['owner_id', 'warehouse_id', 'shop_id', 'logistic_id', 'date_target'])->get();
  332. }
  333. private function getCreateByDatabaseUnitMonth($targetOwnerIdsUnderDates)
  334. {
  335. $orderSqlBuilder = Order::query()->selectRaw("owner_id,warehouse_id,shop_id,logistic_id,count(1) as amounts ,DATE_FORMAT(created_at,'%Y-%m') as date_target");
  336. foreach ($targetOwnerIdsUnderDates as $dateStr => $ownerIds) {
  337. $orderSqlBuilder->orWhere(function ($query) use ($ownerIds, $dateStr) {
  338. $year = Str::of($dateStr)->explode('-')[0];
  339. $month = Str::of($dateStr)->explode('-')[1];
  340. $dateStr = $year . '-' . $month . '-01';
  341. $query->whereIn('owner_id', $ownerIds)->where('created_at', '>', $dateStr)->where('created_at', '<', Carbon::parse($dateStr)->addMonth()->toDateString())->where('wms_status', '订单完成');
  342. });
  343. }
  344. return $orderSqlBuilder->groupBy(['owner_id', 'warehouse_id', 'shop_id', 'logistic_id', 'date_target'])->get();
  345. }
  346. /**
  347. * @param $dateStr
  348. * @return bool
  349. */
  350. public function isNotCurrentDate($dateStr): bool
  351. {
  352. return $dateStr != Carbon::now()->format('Y-m-d')
  353. && $dateStr != Carbon::now()->year . '-' . Carbon::now()->week
  354. && $dateStr != Carbon::now()->year . '-' . Carbon::now()->month;
  355. }
  356. protected function insertDataToMiddle($isHasCurrentDate, $currentDate, $unit, $result)
  357. {
  358. $orderCountingRecordsClock = cache()->get('orderCountingRecordsClock');
  359. switch ($orderCountingRecordsClock) {
  360. case true:
  361. case null:
  362. $this->setClockAndDeleteCurrentDateAndInsert($isHasCurrentDate, $currentDate, $unit, $result);
  363. break;
  364. default:
  365. break;
  366. }
  367. }
  368. protected function deleteMiddleWhereCurrentDate($isHasCurrentDate, $currentDate, $unit)
  369. {
  370. if ($isHasCurrentDate) {
  371. //删除OrderCountingRecord表中与当前日期相关的数据,之后的批量插入重新插入这部分数据
  372. OrderCountingRecord::query()->where('date_target', $currentDate)->where('counting_unit', $unit)->delete();
  373. }
  374. }
  375. protected function setClockAndDeleteCurrentDateAndInsert($isHasCurrentDate, $currentDate, $unit, $result)
  376. {
  377. cache()->put('orderCountingRecordsClock', false, 10);
  378. $this->deleteMiddleWhereCurrentDate($isHasCurrentDate, $currentDate, $unit);
  379. $result->chunk(1000)->each(function ($item) {
  380. OrderCountingRecord::query()->insert($item->toArray());
  381. });
  382. cache()->put('orderCountingRecordsClock', true, 10);
  383. }
  384. }