erp/app/Services/GoodSku/GoodSkuService.php

227 lines
9.4 KiB
PHP
Raw Permalink Normal View History

2024-07-26 17:48:07 +08:00
<?php
namespace App\Services\GoodSku;
use App\Events\BatchStockUpdateEvent;
2024-11-29 17:18:48 +08:00
use App\Http\Enum\BusinessOrderShippingStatus;
2024-08-15 11:23:29 +08:00
use App\Http\Enum\TargetTypeEnum;
use App\Models\BusinessOrderItem;
use App\Models\CombinationGood;
2024-07-26 17:48:07 +08:00
use App\Models\DailyStockRecord;
use App\Models\GoodsSku;
use App\Models\Log as LogModel;
2024-07-26 17:48:07 +08:00
use App\Utils\DateTimeUtils;
2024-08-13 18:17:03 +08:00
use App\Utils\GeneratorUtils;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
2024-11-29 17:18:48 +08:00
use phpDocumentor\Reflection\Types\Collection;
2024-07-26 17:48:07 +08:00
class GoodSkuService
{
2024-07-30 15:30:32 +08:00
/**
* $skusWithCombinationGoods 除了携带组合商品的字段 还拼接了盘点的具体库存值inventory
* @param array $skusWithCombinationGoods
* @return void
*/
public function inventory(array $skusWithCombinationGoods)
2024-07-26 17:48:07 +08:00
{
$skusWithCombinationGoods = $this->handleSkusWithCombinationGoods($skusWithCombinationGoods);
2024-11-08 16:04:31 +08:00
//传进来的sku可能包含组合商品 所以这里需要事先计算好数据
2024-07-30 15:30:32 +08:00
$inventoryKeyBySkuIdMap = collect($skusWithCombinationGoods)->where('is_combination', "=", 0)
2024-11-08 16:04:31 +08:00
->pluck("real_stock", "id")->toArray();
2024-08-13 18:17:03 +08:00
Log::info("库存原始操作map", $inventoryKeyBySkuIdMap);
2024-07-30 15:30:32 +08:00
//计算组合商品
foreach ($skusWithCombinationGoods as $sku) {
if (!empty($sku['is_combination'])) {
foreach ($sku['combination_goods'] as $combinationGoods) {
if (!isset($inventoryKeyBySkuIdMap[$combinationGoods["item_id"]])) {
2024-07-30 15:30:32 +08:00
//没有盘点到的sku需要在原先的sku库存
2024-08-14 17:02:31 +08:00
$inventoryKeyBySkuIdMap[$combinationGoods["item_id"]] = 0;
2024-07-30 15:30:32 +08:00
}
2024-08-13 18:17:03 +08:00
$inventoryKeyBySkuIdMap[$combinationGoods["item_id"]] += $combinationGoods['item_num'] * $sku['real_stock'];
}
}
}
2024-07-26 17:48:07 +08:00
$today = DateTimeUtils::getToday();
$dateTime = date('Y-m-d H:i:s');
$updateIds = [];
2024-07-30 15:30:32 +08:00
Log::info("库存盘点前完整信息", $skusWithCombinationGoods);
Log::info("需要操作的库存数据", $inventoryKeyBySkuIdMap);
2024-08-13 18:17:03 +08:00
$batchNumber = GeneratorUtils::generateBatchNumber("import");
2024-08-13 18:17:03 +08:00
DB::beginTransaction();
try {
foreach ($skusWithCombinationGoods as $sku) {
// 更新每日数据
2024-08-13 18:17:03 +08:00
DailyStockRecord::query()->updateOrCreate([
'sku_id' => $sku['id'],
'day' => $today,
], [
"inventory" => $sku['inventory'],
"inventory_time" => $dateTime,
"batch_number" => $batchNumber
]);
}
$costLogs = [];
//更新库存并记录数据
2024-08-13 18:17:03 +08:00
foreach ($inventoryKeyBySkuIdMap as $skuId => $realStock) {
//库存修改 盘点是直接覆盖
$skuData = GoodsSku::query()->where('id', $skuId)->first();
if (!empty($skuData)) {
$costLogs[] = static::addStockLog($skuData
, TargetTypeEnum::INVENTORY, ['stock' => $realStock]);
$skuData->stock = $realStock;
$skuData->save();
$updateIds[] = $skuId;
}
2024-08-13 18:17:03 +08:00
}
$log = new LogModel();
$log->batchInsert($costLogs);
2024-08-14 17:02:31 +08:00
DB::commit();
2024-08-13 18:17:03 +08:00
} catch (\Exception $exception) {
DB::rollBack();
2024-08-14 17:02:31 +08:00
Log::error("库存盘点异常", ["error" => $exception->getMessage()]);
2024-07-26 17:48:07 +08:00
}
2024-08-13 18:17:03 +08:00
2024-07-26 17:48:07 +08:00
// 批量更新
event(new BatchStockUpdateEvent($updateIds));
}
2024-07-26 17:48:07 +08:00
/**
* 库存盘点 需要扣减未发货未取消的订单数据
* 目前只查询了7日内的数据
* @param array $skusWithCombinationGoods
* @return \Illuminate\Support\Collection
*/
2024-08-13 18:17:03 +08:00
public function handleSkusWithCombinationGoods(array $skusWithCombinationGoods)
{
//查询sku当前未发货的数量 需要扣减
2024-11-29 17:18:48 +08:00
$externalSkuIds = collect($skusWithCombinationGoods)->pluck("external_sku_id")->toArray();
$skuIds = collect($skusWithCombinationGoods)->pluck("id")->toArray();
//关联的组合数据
2024-12-03 13:52:22 +08:00
$combinationGoods = CombinationGood::query()->with("goodsSku:id,external_sku_id")->whereIn('item_id', $skuIds)->get()->toArray();
2024-11-29 17:18:48 +08:00
$externalSkuIds = collect($combinationGoods)->pluck("goods_sku.external_sku_id")->merge(collect($externalSkuIds))->toArray();
2024-12-03 13:52:22 +08:00
Log::info("需要查询的externalSkuIds",[$externalSkuIds]);
//默认只查15天内未发货的数据
2024-12-03 13:52:22 +08:00
$startTime = Carbon::now()->subDays(15)->toDateTimeString();
$unshippedDataCollect = BusinessOrderItem::query()
2024-11-29 17:18:48 +08:00
->with([
'shop:id,name',
'goodsSku:id,external_sku_id,is_combination',
'goodsSku.combinationGoods:id,goods_sku_id,item_id,item_num'
])
->leftJoin("business_orders as b", "business_order_id", "=", "b.id")
2024-11-29 17:18:48 +08:00
->select("external_sku_id", DB::raw("SUM(goods_number) - SUM(already_cancel_number) as number"))
->whereIn("external_sku_id", $externalSkuIds)
->where("b.shipping_status", "=", BusinessOrderShippingStatus::UNSHIP)
2024-12-05 19:03:56 +08:00
->where("b.after_sales_status", "!=", 2)
2024-12-04 13:49:28 +08:00
->where("business_order_items.created_at", ">=", $startTime)->where("business_order_items.cancel_status", "=", 0)
->groupBy('external_sku_id')->get()->toArray();
2024-12-02 17:24:01 +08:00
2024-12-03 13:52:22 +08:00
Log::info("盘点未发货数据",[$unshippedDataCollect]);
2024-12-11 11:12:24 +08:00
$ids = [];
2024-11-29 17:18:48 +08:00
//重组订单
foreach ($unshippedDataCollect as $businessOrderItem) {
if (is_null($businessOrderItem['goods_sku'])) {
continue;
}
$id = $businessOrderItem['goods_sku']['id'];
if ($businessOrderItem['goods_sku']['is_combination']) {
foreach ($businessOrderItem['goods_sku']['combination_goods'] ?? [] as $combinationGoods) {
$ids[$combinationGoods['item_id']] = ($ids[$combinationGoods['item_id']] ?? 0)
+ ((int)$businessOrderItem['number']) * $combinationGoods['item_num'];
}
}
if (isset($ids[$id])) {
$ids[$id] += (int)$businessOrderItem['number'];
} else {
$ids[$id] = (int)$businessOrderItem['number'];
}
}
2024-08-07 16:23:04 +08:00
2024-11-29 17:18:48 +08:00
return collect($skusWithCombinationGoods)->map(function ($v) use ($ids) {
$v['real_stock'] = $v['inventory'] ?? null;
if (!empty($ids[$v['id']]) && isset($v['inventory'])) {
$v['real_stock'] = $v['inventory'] - $ids[$v['id']];
}
return $v;
})->toArray();
}
public static function computeSkuStock(array $goodsSkuItem, array $changeData, $targetType = TargetTypeEnum::LOSS)
{
$updateIds = [];
$updateParams = [];
//添加系统日志
$costLogs = [];
// 成本
if (empty($goodsSkuItem['is_combination'])) {
$updateParam = [
'stock' => $goodsSkuItem['stock'] + $changeData['num'],
2024-10-29 16:33:30 +08:00
'sale_stock' => max($goodsSkuItem['sale_stock'] + $changeData['num'], 0),
];
2024-10-22 17:31:30 +08:00
2024-08-15 11:23:29 +08:00
if ($targetType == TargetTypeEnum::PURCHASE) {
$updateParam['cost'] = $changeData['cost'];
2024-08-15 11:23:29 +08:00
}
2024-10-29 16:33:30 +08:00
if ($updateParam['sale_stock'] <= 0) {
$updateParam['status'] = GoodsSku::$STATUS_DOWN;
}
2024-08-13 18:17:03 +08:00
GoodsSku::query()->where('external_sku_id', "=", $goodsSkuItem['external_sku_id'])
->update($updateParam);
$updateIds[] = $goodsSkuItem['id'];
$updateParams[] = $updateParam;
$costLogs[] = static::addStockLog($goodsSkuItem, $targetType, $updateParam);
} else {
$combinationGood = CombinationGood::query()->with('goodsSkuItem:id,stock,sale_stock')
->where('goods_sku_id', $goodsSkuItem['id'])->get();
foreach ($combinationGood as $item) {
$updateParam = [
'stock' => $item['goodsSkuItem']['stock'] + $changeData['num'] * $item['item_num'],
2024-10-29 16:33:30 +08:00
'sale_stock' => max($item['goodsSkuItem']['sale_stock'] + $changeData['num'] * $item['item_num'], 0),
];
2024-10-29 16:33:30 +08:00
if ($updateParam['sale_stock'] <= 0) {
$updateParam['status'] = GoodsSku::$STATUS_DOWN;
}
GoodsSku::query()->where('id', $item['goodsSkuItem']['id'])->update($updateParam);
$updateIds[] = $item['goodsSkuItem']['id'];
$updateParams[] = $updateParam;
$costLogs[] = static::addStockLog($item['goodsSkuItem'], $targetType, $updateParam);
}
}
$log = new LogModel();
$log->batchInsert($costLogs);
Log::info("本次请求更新参数", $updateParams);
return $updateIds;
2024-07-26 17:48:07 +08:00
}
public static function addStockLog($goodsSkuItem, $targetType = TargetTypeEnum::LOSS, $updateParam)
{
2024-10-29 16:33:30 +08:00
$userId = Auth::id();
$costLog = [
2024-08-24 14:23:06 +08:00
'module' => 'goods',
'action' => "POST",
'target_type' => $targetType,
'target_id' => $goodsSkuItem['id'] ?? 0,
'user_id' => $userId ?? 999,
"target_field" => "stock"
];
$costLog['before_update'] = json_encode($goodsSkuItem);
$costLog['after_update'] = json_encode($updateParam);
return $costLog;
}
2024-07-26 17:48:07 +08:00
}