diff --git a/app/Console/Commands/DailyStockRecordReport.php b/app/Console/Commands/DailyStockRecordReport.php new file mode 100644 index 0000000..8550978 --- /dev/null +++ b/app/Console/Commands/DailyStockRecordReport.php @@ -0,0 +1,92 @@ +format('Y-m-d'); + $startDateTime = Carbon::parse($date)->startOfDay()->toDateTimeString(); + $endDateTime = Carbon::parse($date)->endOfDay()->toDateTimeString(); + //统计订单数量 + $orderItems = BusinessOrderItem::query() + ->leftJoin("business_orders as b", "business_order_id", "=", "b.id") + ->select("business_order_items.external_sku_id" + , DB::raw("sum(goods_number-already_cancel_number) as goods_total")) + ->whereBetween("business_order_items.created_at", [$startDateTime, $endDateTime]) + ->where("business_order_items.cancel_status", "=", 0) + ->groupBy('external_sku_id')->get()->pluck(null, "external_sku_id")->toArray(); + + //统计采购单数量 + $purchaseRecords = PurchaseRecords::query() + ->select(DB::raw("sum(num) as arrived_today_num"), "external_sku_id") + ->whereBetween("created_at", [$startDateTime, $endDateTime]) + ->groupBy("external_sku_id")->get()->pluck(null, "external_sku_id")->toArray(); + //统计报损数量 + $lossRecords = LossRecords::query() + ->select(DB::raw("sum(num) as loss_num"), "external_sku_id") + ->whereBetween("created_at", [$startDateTime, $endDateTime]) + ->groupBy("external_sku_id")->get()->pluck(null, "external_sku_id")->toArray(); + Log::info("{$date}每日库存记录", ["orderItems" => $orderItems + , "purchaseRecords" => $purchaseRecords, "lossRecords" => $lossRecords]); + $needUpdateExternalSkuIds = array_merge(array_keys($orderItems), array_keys($purchaseRecords), array_keys($lossRecords)); + //开始更新数据 + if (!empty($needUpdateExternalSkuIds)) { + $needUpdateSkuIdsMap = GoodsSku::query()->whereIn("external_sku_id", $needUpdateExternalSkuIds)->pluck("external_sku_id", 'id')->toArray(); + collect($needUpdateSkuIdsMap)->each(function ($externalSkuId,$skuId) use ($date, $orderItems, $purchaseRecords, $lossRecords) { + $record = DailyStockRecord::query()->firstOrNew([ + 'sku_id' => $skuId, + 'day' => $date, + ]); + $record->arrived_today_num = !empty($purchaseRecords[$externalSkuId]["arrived_today_num"]) + ? $purchaseRecords[$externalSkuId]["arrived_today_num"] : 0; + $record->loss_num = !empty($lossRecords[$externalSkuId]["loss_num"]) + ? $lossRecords[$externalSkuId]["loss_num"] : 0; + $record->order_goods_num = !empty($orderItems[$externalSkuId]["goods_total"]) + ? $orderItems[$externalSkuId]["goods_total"] : 0; + $record->save(); + }); + } + } +} diff --git a/app/Http/Controllers/DataCenter/DataCenterController.php b/app/Http/Controllers/DataCenter/DataCenterController.php index b31250a..9a0936b 100644 --- a/app/Http/Controllers/DataCenter/DataCenterController.php +++ b/app/Http/Controllers/DataCenter/DataCenterController.php @@ -3,10 +3,16 @@ namespace App\Http\Controllers\DataCenter; use App\Http\Controllers\Controller; +use App\Http\Enum\StaticTypeEnum; use App\Http\Resources\DailySalesReportResource; +use App\Models\BusinessOrderItem; use App\Models\DailySalesReport; +use App\Models\GoodsSku; use App\Utils\FormatUtils; +use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Validator; class DataCenterController extends Controller { @@ -37,4 +43,48 @@ class DataCenterController extends Controller return DailySalesReportResource::collection($dailySalesReports); } + + /** + * 销售报表 + * @param Request $request + * @return void + */ + public function skuSalesReport(Request $request) + { + //获取所有参数 + $allParams = $request->all(); + //进行校验验证 + $validator = Validator::make($allParams, [ + 'type' => 'required|integer', //1表示今日 + 'start_day' => 'sometimes|string', + 'end_day' => 'sometimes|string', + 'title' => 'sometimes|string' + ]); + + if ($validator->fails()) { + //校验失败返回异常 + $this->setValidatorFailResponse($validator->getMessageBag()->getMessages()); + return response($this->res, $this->res['httpCode']); + } + if (StaticTypeEnum::TODAY == $allParams->type) { + //实时统计 + $orderItems = BusinessOrderItem::query() + ->leftJoin("business_orders as b", "business_order_id", "=", "b.id") + ->select("business_order_items.external_sku_id" + , DB::raw("sum(CASE WHEN b.shipping_status>0 THEN goods_number-already_cancel_number ELSE 0 END) as shipping_num") + , DB::raw("sum(CASE WHEN b.shipping_status=0 THEN goods_number-already_cancel_number ELSE 0 END) as unshipping_num") + , DB::raw("sum(goods_number-already_cancel_number) as goods_total")) + ->where("business_order_items.created_at", ">",Carbon::now()->startOfDay()->toDateTimeString()) + ->where("business_order_items.cancel_status", "=", 0) + ->groupBy('external_sku_id') + ->orderBy("goods_total","DESC") + ->paginate($request->get('per_page')); + return $orderItems; + } else { + $startTime = Carbon::parse($request->input("start_day"))->toDateTimeString(); + $endTime = Carbon::parse($request->input("end_day"))->endOfDay()->toDateTimeString(); + } + + + } } \ No newline at end of file diff --git a/app/Http/Controllers/Supplier/DailyStockRecordController.php b/app/Http/Controllers/Supplier/DailyStockRecordController.php index 4588929..773d0a9 100644 --- a/app/Http/Controllers/Supplier/DailyStockRecordController.php +++ b/app/Http/Controllers/Supplier/DailyStockRecordController.php @@ -63,7 +63,7 @@ class DailyStockRecordController extends Controller $goodsSku = GoodsSku::query()->with("combinationGoods")->where('external_sku_id', "=", $request->external_sku_id)->first(); if (empty($goodsSku)) { $this->res = [ - 'httpCode' => 200, + 'httpCode' => 400, 'message' => '查询不到sku信息', 'errorCode' => "ERP001", 'errorMessage' => '查询不到sku信息', diff --git a/app/Http/Controllers/Supplier/LossRecordController.php b/app/Http/Controllers/Supplier/LossRecordController.php index be54a64..5aa57ca 100644 --- a/app/Http/Controllers/Supplier/LossRecordController.php +++ b/app/Http/Controllers/Supplier/LossRecordController.php @@ -69,7 +69,7 @@ class LossRecordController extends Controller event(new BatchStockUpdateEvent($updateIds)); } else { $this->res = [ - 'httpCode' => 200, + 'httpCode' => 400, 'message' => '查询不到sku信息', 'errorCode' => "ERP001", 'errorMessage' => '查询不到sku信息', @@ -94,17 +94,15 @@ class LossRecordController extends Controller $this->setValidatorFailResponse($validator->getMessageBag()->getMessages()); return response($this->res, $this->res['httpCode']); } - $goodsSku = GoodsSku::query()->where('id', "=", $id)->get(); - if (!empty($goodsSku)) { + $lossRecords = LossRecords::query()->find($id); + if (!empty($lossRecords)) { //更新記錄 - $lossRecords = new LossRecords(); $lossRecords->buyer_name = $allParams['buyer_name'] ?? ''; $lossRecords->reason = $allParams['reason'] ?? ''; $lossRecords->save(); - } else { $this->res = [ - 'httpCode' => 200, + 'httpCode' => 400, 'message' => '查询不到sku信息', 'errorCode' => "ERP001", 'errorMessage' => '查询不到sku信息', diff --git a/app/Http/Controllers/Supplier/PurchaseRecordController.php b/app/Http/Controllers/Supplier/PurchaseRecordController.php index 5acd821..f088a49 100644 --- a/app/Http/Controllers/Supplier/PurchaseRecordController.php +++ b/app/Http/Controllers/Supplier/PurchaseRecordController.php @@ -75,7 +75,7 @@ class PurchaseRecordController extends Controller event(new BatchStockUpdateEvent($updateIds)); } else { $this->res = [ - 'httpCode' => 200, + 'httpCode' => 400, 'message' => '查询不到sku信息', 'errorCode' => "ERP001", 'errorMessage' => '查询不到sku信息', @@ -116,7 +116,7 @@ class PurchaseRecordController extends Controller } else { $this->res = [ - 'httpCode' => 200, + 'httpCode' => 400, 'message' => '查询不到sku信息', 'errorCode' => "ERP001", 'errorMessage' => '查询不到sku信息', diff --git a/app/Http/Enum/StaticTypeEnum.php b/app/Http/Enum/StaticTypeEnum.php new file mode 100644 index 0000000..0065a89 --- /dev/null +++ b/app/Http/Enum/StaticTypeEnum.php @@ -0,0 +1,11 @@ +handleSkusWithCombinationGoods($skusWithCombinationGoods); //传进来的sku可能包含组合商品 所以这里需要事先计算好数据 $inventoryKeyBySkuIdMap = collect($skusWithCombinationGoods)->where('is_combination', "=", 0) - ->pluck("inventory", "sku_id")->toArray(); + ->pluck("inventory", "id")->toArray(); //计算组合商品 foreach ($skusWithCombinationGoods as $sku) { if (!empty($sku['is_combination'])) { @@ -28,7 +32,7 @@ class GoodSkuService if (empty($inventoryKeyBySkuIdMap[$combinationGoods["item_id"]])) { //没有盘点到的sku需要在原先的sku库存 $inventoryKeyBySkuIdMap[$combinationGoods["item_id"]] = GoodsSku::query() - ->where('id', $combinationGoods["item_id"])->pluck('stock')->first()??0; + ->where('id', $combinationGoods["item_id"])->pluck('stock')->first() ?? 0; } $inventoryKeyBySkuIdMap[$combinationGoods["item_id"]] += $combinationGoods['item_num'] * $sku['inventory']; @@ -50,7 +54,6 @@ class GoodSkuService $record->inventory = $totalInventory; $record->inventory_time = $dateTime; $record->save(); - //查询sku当前未发货的数量 目前数据看着有问题暂不操作 //库存修改 盘点是直接覆盖 GoodsSku::query()->where('id', $skuId)->update([ @@ -62,7 +65,36 @@ class GoodSkuService event(new BatchStockUpdateEvent($updateIds)); } - public static function computeSkuStock(array $goodsSkuItem, array $v): array + /** + * 库存盘点 需要扣减未发货未取消的订单数据 + * 目前只查询了7日内的数据 + * @param array $skusWithCombinationGoods + * @return \Illuminate\Support\Collection + */ + public function handleSkusWithCombinationGoods(array $skusWithCombinationGoods){ + //查询sku当前未发货的数量 需要扣减 + $externalSkuIds = collect($skusWithCombinationGoods)->pluck("external_sku_id")->toArray(); + //默认只查7天内未发货的数据 + $startTime = Carbon::now()->subDays(7)->startOfDay()->toDateTimeString(); + $unshippedDataCollect = BusinessOrderItem::query() + ->leftJoin("business_orders as b", "business_order_id", "=", "b.id") + ->select("external_sku_id", DB::raw("sum(goods_number) as goods_total"), DB::raw("sum(already_cancel_number) as cancel_total")) + ->whereIn("external_sku_id", $externalSkuIds)->where("b.shipping_status", "=", 0) + ->where("business_order_items.created_at", ">=", $startTime)->where("business_order_items.cancel_status", "=", 0) + ->groupBy('external_sku_id')->get()->toArray(); + $unshippedData = collect($unshippedDataCollect)->pluck(null,"external_sku_id")->toArray(); + Log::info("7日内未发货数据", $unshippedData); + return collect($skusWithCombinationGoods)->map(function ($v) use ($unshippedData) { + if (!empty($unshippedData[$v['external_sku_id']])) { + $v['inventory'] = $v['inventory'] - $unshippedData[$v['external_sku_id']]['goods_total'] + + $unshippedData[$v['external_sku_id']]['cancel_total']; + } + return $v; + })->toArray(); + } + + + public static function computeSkuStock(array $goodsSkuItem, array $v) { $updateIds = []; Log::info("库存更新前完整商品信息", $goodsSkuItem); diff --git a/routes/api.php b/routes/api.php index 5a0d95d..751c3d5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -85,6 +85,10 @@ Route::middleware(['auth:api', 'check.permissions'])->group(function () { Route::resource('supplier/loss_record', 'Supplier\LossRecordController',['only' => ['index', 'store','update']]); //仓库管理-盘点 Route::resource('supplier/daily_stock_record', 'Supplier\DailyStockRecordController',['only' => ['index', 'store']]); + + // 数据中心 销售报表 + Route::get('data_center/sku_sales_report', [DataCenterController::class, 'skuSalesReport'])->name('sku_sales_report.index'); + }); Route::get('stock/goods_skus', [GoodsSkusController::class, 'stockNum'])->middleware('auth:api'); Route::get('goods/filter/{title}', [GoodsCombinationController::class, 'goodsSkus'])->middleware('auth:api'); diff --git a/tests/Feature/BusinessOrderUpdateTest.php b/tests/Feature/BusinessOrderUpdateTest.php index 6c71a5e..b446dd7 100644 --- a/tests/Feature/BusinessOrderUpdateTest.php +++ b/tests/Feature/BusinessOrderUpdateTest.php @@ -4,6 +4,8 @@ use App\Models\BusinessGoodsSku; use App\Models\BusinessOrderItem; use App\Models\GoodsSku; +use App\Services\Business\BusinessFactory; +use App\Utils\DateTimeUtils; use Illuminate\Support\Facades\Log; use Tests\TestCase; @@ -18,7 +20,12 @@ class BusinessOrderUpdateTest extends TestCase */ public function testBasicTest() { - +// $shop = new \App\Models\Shop(); +// $shop->id=19; +// $shop->access_token="7e00e77428cf45348cb1ca190dc769670377bd0c"; +// $endTime = DateTimeUtils::getMicroTime(); +// $beginTime = $endTime - 63000; +// BusinessFactory::init()->make("快团团")->setShop($shop)->downloadOrdersAndSave($beginTime, $endTime, 'increment'); } }