|
|
@@ -0,0 +1,439 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+
|
|
|
+namespace App\Services;
|
|
|
+
|
|
|
+
|
|
|
+use App\Logistic;
|
|
|
+use App\Order;
|
|
|
+use App\OrderCountingRecord;
|
|
|
+use App\Warehouse;
|
|
|
+use Carbon\Carbon;
|
|
|
+use Illuminate\Support\Facades\Cache;
|
|
|
+
|
|
|
+class NewOrderCountingRecordService
|
|
|
+{
|
|
|
+ public function orderCountingRecords($start, $end, $unit, $ownerIds)
|
|
|
+ {
|
|
|
+ $orders = $this->get($start, $end, $unit, $ownerIds);
|
|
|
+ $dataList = collect();
|
|
|
+ $orders->groupBy('date_target')->sortKeys()->each(function ($items) use (&$dataList, $unit) {
|
|
|
+ $counter = $items->reduce(function ($sum, $item) {
|
|
|
+ return $sum + $item->amount;
|
|
|
+ }, 0);
|
|
|
+ $date_target = $items[0]->date_target;
|
|
|
+ $dataList->push([
|
|
|
+ 'counter' => $counter,
|
|
|
+ 'date_target' => $date_target,
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ return $dataList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function logisticsCountingRecords($start, $end, $ownerIds)
|
|
|
+ {
|
|
|
+ $key = 'logisticsCountingRecords_' . $start . '_' . $end . '_' . json_encode($ownerIds);
|
|
|
+ return Cache::remember($key, 600, function () use ($start, $end, $ownerIds) {
|
|
|
+ $dataList = collect();
|
|
|
+ $resultOrders = $this->get($start, $end, '日', $ownerIds);
|
|
|
+ $resultOrders->groupBy('logistic_id')->each(function ($item) use (&$dataList) {
|
|
|
+ $counter = $item->reduce(function ($sum, $item) {
|
|
|
+ return $sum + $item->amount;
|
|
|
+ }, 0);
|
|
|
+ $dataList->push([
|
|
|
+ 'value' => $counter,
|
|
|
+ 'logistic_id' => $item[0]->logistic_id,
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ $map = [];
|
|
|
+ $logistics = Logistic::query()->whereIn('id', data_get($dataList, '*.logistic_id'))->get();
|
|
|
+ $logistics->each(function ($logistic) use (&$map) {
|
|
|
+ $map[$logistic->id] = $logistic;
|
|
|
+ });
|
|
|
+ return $dataList->map(function (&$item) use ($map) {
|
|
|
+ $logistic = $map[$item['logistic_id']] ?? '';
|
|
|
+ $item['name'] = $logistic->name ?? '';
|
|
|
+ return $item;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public function warehouseCountingRecords($start, $end, $ownerIds)
|
|
|
+ {
|
|
|
+ $key = 'warehouseCountingRecords_' . $start . '_' . $end . '_' . json_encode($ownerIds);
|
|
|
+ return Cache::remember($key, 600, function () use ($start, $end, $ownerIds) {
|
|
|
+ $dataList = collect();
|
|
|
+ $resultOrders = $this->get($start, $end, '日', $ownerIds);
|
|
|
+ $resultOrders->groupBy('warehouse_id')->each(function ($item) use (&$dataList) {
|
|
|
+ $counter = $item->reduce(function ($sum, $item) {
|
|
|
+ return $sum + $item->amount;
|
|
|
+ }, 0);
|
|
|
+ $dataList->push([
|
|
|
+ 'value' => $counter,
|
|
|
+ 'warehouse_id' => $item[0]->warehouse_id,
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ $map = [];
|
|
|
+ $logistics = Warehouse::query()->whereIn('id', data_get($dataList, '*.warehouse_id'))->get();
|
|
|
+ $logistics->each(function ($warehouse) use (&$map) {
|
|
|
+ $map[$warehouse->id] = $warehouse;
|
|
|
+ });
|
|
|
+ return $dataList->map(function (&$item) use ($map) {
|
|
|
+ $warehouse = $map[$item['warehouse_id']] ?? '';
|
|
|
+ $item['code'] = $warehouse->name ?? '';
|
|
|
+ switch ($item['code']) {
|
|
|
+ case 'WH01':
|
|
|
+ $item['name'] = '松江一仓';
|
|
|
+ break;
|
|
|
+ case 'WH02':
|
|
|
+ $item['name'] = '松江二仓';
|
|
|
+ break;
|
|
|
+ case 'WH03':
|
|
|
+ $item['name'] = '嘉定一仓';
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ $item['name'] = '仓库为空';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return $item;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public function get($start, $end, $unit, $ownerIds)
|
|
|
+ {
|
|
|
+ $queryCondition = $this->transfersToCondition($start, $end, $unit, $ownerIds);
|
|
|
+ return $this->getOrderCountingRecords($queryCondition);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getFromCache($queryCondition)
|
|
|
+ {
|
|
|
+ $lackingCondition = [];
|
|
|
+ $orderCountingRecords_FromCache = collect();
|
|
|
+ $lackingCondition['unit'] = $queryCondition['unit'];
|
|
|
+ foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
|
|
|
+ foreach ($ownerIds as $ownerId) {
|
|
|
+ $key = 'order_counting_records_' . $dateStr . '_' . $ownerId . '_' . $queryCondition['unit'];
|
|
|
+ $items = cache()->get($key);
|
|
|
+ if (empty($items)) {
|
|
|
+ if (empty($lackingCondition['data'][$dateStr])) {
|
|
|
+ $lackingCondition['data'][$dateStr] = [];
|
|
|
+ }
|
|
|
+ $lackingCondition['data'][$dateStr][] = $ownerId;
|
|
|
+ } else {
|
|
|
+ foreach ($items as $item) {
|
|
|
+ $orderCountingRecords_FromCache->push($item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return [$orderCountingRecords_FromCache, $lackingCondition];
|
|
|
+ }
|
|
|
+
|
|
|
+ public function dataFromMiddleTable($queryCondition)
|
|
|
+ {
|
|
|
+ $result = [];
|
|
|
+ $orderSqlBuilder = OrderCountingRecord::query();
|
|
|
+ $unit = $queryCondition['unit'];
|
|
|
+ foreach ($queryCondition['data'] as $date => $owners) {
|
|
|
+ $orderSqlBuilder->orWhere(function ($query) use ($owners, $date, $unit) {
|
|
|
+ $query->whereIn('owner_id', $owners)->where('date_target', $date)->where('counting_unit', $unit);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ $dataFromMiddleTable = $orderSqlBuilder->get();
|
|
|
+ $this->insertIntoCache($dataFromMiddleTable, $unit);
|
|
|
+ $queryCondition = $this->unQueryCondition($dataFromMiddleTable, $queryCondition);
|
|
|
+ $orderCountingRecords_fromSelfTable = $dataFromMiddleTable;
|
|
|
+ $lackingCondition = $queryCondition;
|
|
|
+ return [$orderCountingRecords_fromSelfTable, $lackingCondition];
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getOrderCountingRecords($queryCondition)
|
|
|
+ {
|
|
|
+
|
|
|
+ list($orderCountingRecords_fromCache, $lackingCondition)
|
|
|
+ = $this->getFromCache($queryCondition);
|
|
|
+ if (empty($lackingCondition['data'])) {
|
|
|
+ return $orderCountingRecords_fromCache;
|
|
|
+ }
|
|
|
+
|
|
|
+ list($orderCountingRecords_fromSelfTable, $lackingCondition)
|
|
|
+ = $this->dataFromMiddleTable($lackingCondition);
|
|
|
+ if (empty($lackingCondition['data'])) {
|
|
|
+ return $orderCountingRecords_fromCache->concat($orderCountingRecords_fromSelfTable);
|
|
|
+ }
|
|
|
+ list($orderCountingRecords_combinedByLower, $lackingCondition)
|
|
|
+ = $this->getByLowerUnit($lackingCondition);
|
|
|
+
|
|
|
+ if (!empty($lackingCondition)) {
|
|
|
+ $orderCountingRecords_FromOrder = $this->dataFromOrder($lackingCondition);
|
|
|
+ }
|
|
|
+ $result = collect();
|
|
|
+ if (isset($orderCountingRecords_FromOrder) && !$orderCountingRecords_FromOrder->isEmpty()) {
|
|
|
+ $result = $result->concat($orderCountingRecords_FromOrder);
|
|
|
+ }
|
|
|
+ if (!$orderCountingRecords_fromCache->isEmpty()) {
|
|
|
+ $result = $result->concat($orderCountingRecords_fromCache);
|
|
|
+ }
|
|
|
+ if (!$orderCountingRecords_fromSelfTable->isEmpty()) {
|
|
|
+ $result = $result->concat($orderCountingRecords_fromSelfTable);
|
|
|
+ }
|
|
|
+ if (count($orderCountingRecords_combinedByLower) != 0) {
|
|
|
+ $result = $result->concat($orderCountingRecords_combinedByLower);
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public function getByLowerUnit($queryCondition)
|
|
|
+ {
|
|
|
+ switch ($queryCondition['unit']) {
|
|
|
+ case '年':
|
|
|
+ $lowUnit = '月';
|
|
|
+ $conditionClone = ['unit' => $lowUnit, 'data' => []];
|
|
|
+ foreach ($queryCondition['data'] as $date => $ownerIds) {
|
|
|
+ $startAt = $date;
|
|
|
+ $endAt = Carbon::parse($date)->endOfYear()->toDateString();
|
|
|
+ $items = $this->transfersToCondition(
|
|
|
+ $startAt, $endAt, $lowUnit, $ownerIds
|
|
|
+ )['data'];
|
|
|
+ foreach ($items as $dateStr => $item) {
|
|
|
+ if (empty($conditionClone['data'][$dateStr])) $conditionClone['data'][$dateStr] = $dateStr;
|
|
|
+ $conditionClone['data'][$dateStr] = ($item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
|
|
|
+ $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'year');
|
|
|
+ break;
|
|
|
+ case '月':
|
|
|
+ $lowUnit = '日';
|
|
|
+ $conditionClone = ['unit' => $lowUnit, 'data' => []];
|
|
|
+ foreach ($queryCondition['data'] as $date => $ownerIds) {
|
|
|
+ $startAt = $date;
|
|
|
+ $endAt = Carbon::parse($date)->endOfMonth()->toDateString();
|
|
|
+ $items = $this->transfersToCondition(
|
|
|
+ $startAt, $endAt, $lowUnit, $ownerIds
|
|
|
+ )['data'];
|
|
|
+ foreach ($items as $dateStr => $item) {
|
|
|
+ if (empty($conditionClone['data'][$dateStr])) $conditionClone['data'][$dateStr] = $dateStr;
|
|
|
+ $conditionClone['data'][$dateStr] = ($item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
|
|
|
+ $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'month');
|
|
|
+ break;
|
|
|
+ case '日':
|
|
|
+ return [[], $queryCondition];
|
|
|
+ default:
|
|
|
+ }
|
|
|
+ return [$orderCountingRecords_combinedByLower, []];
|
|
|
+ }
|
|
|
+
|
|
|
+ public function transfersToCondition($start, $end, $unit, $ownerIds)
|
|
|
+ {
|
|
|
+ $condition = [
|
|
|
+ 'data' => [],
|
|
|
+ 'unit' => $unit,];
|
|
|
+ $startAt = Carbon::parse($start);
|
|
|
+ $dates = [];
|
|
|
+ switch ($unit) {
|
|
|
+ case '年':
|
|
|
+ $dates = collect($startAt->yearsUntil($end, 1)->toArray())
|
|
|
+ ->map(function (Carbon $date) {
|
|
|
+ return $date->firstOfYear();
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case '月':
|
|
|
+ $dates = collect($startAt->monthsUntil($end, 1)->toArray())
|
|
|
+ ->map(function (Carbon $date) {
|
|
|
+ return $date->firstOfMonth();
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ case '日':
|
|
|
+ $dates = collect($startAt->daysUntil($end, 1)->toArray())
|
|
|
+ ->map(function (Carbon $date) {
|
|
|
+ return $date->startOfDay();
|
|
|
+ });
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($dates as $day) {
|
|
|
+ $condition['data'][$day->toDateString()] = $ownerIds;
|
|
|
+ }
|
|
|
+ return $condition;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function dataFromOrder($queryCondition)
|
|
|
+ {
|
|
|
+ $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");
|
|
|
+ foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
|
|
|
+ $orderSqlBuilder->orWhere(function ($query) use ($ownerIds, $dateStr) {
|
|
|
+ $query->whereIn('owner_id', $ownerIds)->where('created_at', '>', $dateStr)->where('created_at', '<', Carbon::parse($dateStr)->addDay()->toDateString())->where('wms_status', '订单完成');
|
|
|
+ });
|
|
|
+ }
|
|
|
+ $dataFromOrder = $orderSqlBuilder->groupBy(['owner_id', 'warehouse_id', 'shop_id', 'logistic_id', 'date_target'])->get();
|
|
|
+ $dataFromMiddleTable = $this->ordersToOrderCountingRecords($dataFromOrder, $queryCondition['unit']);
|
|
|
+ $this->setDefultData($dataFromMiddleTable, $queryCondition);
|
|
|
+ $this->insertIntoMiddleTable($dataFromMiddleTable);
|
|
|
+ $this->insertIntoCache($dataFromMiddleTable, $queryCondition['unit']);
|
|
|
+ return $dataFromMiddleTable;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function insertIntoMiddleTable($data)
|
|
|
+ {
|
|
|
+ $data->filter(function ($item) {
|
|
|
+ return $this->isNotCurrentDate($item->date_target);
|
|
|
+ })->chunk(1000)->each(function ($item) {
|
|
|
+ OrderCountingRecord::query()->insert($item->toArray());
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public function insertIntoCache($collect, $unit)
|
|
|
+ {
|
|
|
+ $map = [];
|
|
|
+ $collect->each(function ($order) use ($unit, &$map) {
|
|
|
+ $key = "order_counting_records_{$order->date_target}_{$order->owner_id}_{$unit}";
|
|
|
+ if (empty($map[$key])) $map[$key] = [];
|
|
|
+ $map[$key][] = $order;
|
|
|
+ });
|
|
|
+
|
|
|
+ foreach ($map as $key => $orders) {
|
|
|
+ $ttl = 3600 * 24;
|
|
|
+ if (!$this->isNotCurrentDate($orders[0]['date_target'])) {
|
|
|
+ $ttl = 70;
|
|
|
+ }
|
|
|
+ Cache::put($key, collect($orders), $ttl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function isNotCurrentDate($dateStr): bool
|
|
|
+ {
|
|
|
+ return $dateStr != Carbon::now()->format('Y-m-d')
|
|
|
+ && $dateStr != Carbon::now()->year . '-' . Carbon::now()->month;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public function unQueryCondition($dataFromMiddleTable, $unQueryCondition)
|
|
|
+ {
|
|
|
+ $map = [];
|
|
|
+ $dataFromMiddleTable->each(function ($item) use (&$map) {
|
|
|
+ $key = 'owner_id=' . $item->owner_id . ' date_target' . $item->date_target;
|
|
|
+ $map[$key] = true;
|
|
|
+ });
|
|
|
+ foreach ($unQueryCondition['data'] as $dateStr => $ownerIds) {
|
|
|
+ foreach ($ownerIds as $key => $ownerId) {
|
|
|
+ $key1 = 'owner_id=' . $ownerId . ' date_target' . $dateStr;
|
|
|
+ if (isset($map[$key1])) {
|
|
|
+ //中间表查找到数据
|
|
|
+ unset($unQueryCondition['data'][$dateStr][$key]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (empty($unQueryCondition['data'][$dateStr])) {
|
|
|
+ unset($unQueryCondition['data'][$dateStr]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $unQueryCondition;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public function ordersToOrderCountingRecords($dataFromOrder, $unit)
|
|
|
+ {
|
|
|
+ $dataFromMiddleTable = collect();
|
|
|
+ //当日当周当月当年的数据不能插入到中间表
|
|
|
+ $dateTime = Carbon::now()->toDateTimeString();
|
|
|
+ foreach ($dataFromOrder as $order) {
|
|
|
+ $carbon = Carbon::parse($order->date_target);
|
|
|
+ $year = $carbon->year;
|
|
|
+ $week = $carbon->week;
|
|
|
+ $month = $carbon->month;
|
|
|
+ $dataFromMiddleTable->push(new OrderCountingRecord([
|
|
|
+ 'owner_id' => $order->owner_id,
|
|
|
+ 'shop_id' => $order->shop_id,
|
|
|
+ 'warehouse_id' => $order->warehouse_id,
|
|
|
+ 'logistic_id' => $order->logistic_id,
|
|
|
+ 'date_target' => $order->date_target,
|
|
|
+ 'counting_unit' => $unit,
|
|
|
+ 'amount' => $order->amounts,
|
|
|
+ 'week' => $year . '-' . $week,
|
|
|
+ 'month' => $year . '-' . $month,
|
|
|
+ 'year' => $year . '',
|
|
|
+ 'created_at' => $dateTime,
|
|
|
+ 'updated_at' => $dateTime,
|
|
|
+ ]));
|
|
|
+ }
|
|
|
+ return $dataFromMiddleTable;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function count($orderCountingRecords_days, $unit)
|
|
|
+ {
|
|
|
+ $isEnd = false;
|
|
|
+ $result = collect();
|
|
|
+ $item = null;
|
|
|
+ $amount = 0;
|
|
|
+ foreach ($orderCountingRecords_days as $itemToCount) {
|
|
|
+ if ($itemToCount instanceof OrderCountingRecord) {
|
|
|
+ if (!$isEnd) {
|
|
|
+ $isEnd = true;
|
|
|
+ $item = clone($itemToCount);
|
|
|
+ }
|
|
|
+ $amount += $itemToCount->amount;
|
|
|
+ } else {
|
|
|
+ $result = $result->concat($this->count($itemToCount, $unit));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($isEnd) {
|
|
|
+ switch ($unit) {
|
|
|
+ case "日":
|
|
|
+ $item['date_target'] = Carbon::parse($item['date_target'])->firstOfMonth()->toDateString();
|
|
|
+ break;
|
|
|
+ case "月":
|
|
|
+ $item['date_target'] = Carbon::parse($item['date_target'])->firstOfYear()->toDateString();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ $item['amount'] = $amount;
|
|
|
+ $item['counting_unit'] = $unit;
|
|
|
+ return $result->push($item);
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function turnGradingUpToLow($orderCountingRecords_days, $unit, $grading)
|
|
|
+ {
|
|
|
+ $orderCountingRecords_days = $orderCountingRecords_days->groupBy(['owner_id', 'shop_id', 'warehouse_id', 'logistic_id', $grading]);
|
|
|
+ return $this->count($orderCountingRecords_days, $unit);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setDefultData($dataFromMiddleTable, $queryCondition)
|
|
|
+ {
|
|
|
+ $map = [];
|
|
|
+ foreach ($dataFromMiddleTable as $data) {
|
|
|
+ if (empty($map[$data->date_target . '-' . $data->owner_id])) $map[$data->date_target . '-' . $data->owner_id] = true;
|
|
|
+ }
|
|
|
+ foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
|
|
|
+ foreach ($ownerIds as $ownerId) {
|
|
|
+ if (empty($map[$dateStr . '-' . $ownerId]) && Carbon::parse($dateStr)->isBefore(Carbon::now())) {
|
|
|
+ $carbon = Carbon::parse($dateStr);
|
|
|
+ $year = $carbon->year;
|
|
|
+ $week = $carbon->week;
|
|
|
+ $month = $carbon->month;
|
|
|
+ $dataFromMiddleTable->push(new OrderCountingRecord([
|
|
|
+ 'owner_id' => $ownerId,
|
|
|
+ 'shop_id' => null,
|
|
|
+ 'warehouse_id' => null,
|
|
|
+ 'logistic_id' => null,
|
|
|
+ 'date_target' => $dateStr,
|
|
|
+ 'counting_unit' => $queryCondition['unit'],
|
|
|
+ 'amount' => 0,
|
|
|
+ 'week' => $year . '-' . $week,
|
|
|
+ 'month' => $year . '-' . $month,
|
|
|
+ 'year' => $year . '',
|
|
|
+ 'created_at' => $carbon->toDateString(),
|
|
|
+ 'updated_at' => $carbon->toDateString(),
|
|
|
+ ]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|