鲜花2.0-库存成本,周数据导出功能修改+增加库存变更记录

This commit is contained in:
杨建炊 2024-08-15 17:06:30 +08:00
parent 0e78cc2d43
commit bf67357601
12 changed files with 106 additions and 70 deletions

View File

@ -10,6 +10,7 @@ use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class BatchStockUpdateEvent class BatchStockUpdateEvent
{ {

View File

@ -2,8 +2,10 @@
namespace App\Exports; namespace App\Exports;
use App\Http\Enum\TargetTypeEnum;
use App\Models\DailyStockRecord; use App\Models\DailyStockRecord;
use App\Models\Log; use App\Models\Log;
use App\Models\PurchaseRecords;
use App\Utils\ArrayUtils; use App\Utils\ArrayUtils;
use App\Utils\DateTimeUtils; use App\Utils\DateTimeUtils;
use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\FromCollection;
@ -35,14 +37,12 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
$headTitle = [ $headTitle = [
'商品编码', '商品编码',
'商品名称', '商品名称',
'商品种类', '商品品种',
'商品品牌',
'规格编码',
'规格名称', '规格名称',
]; ];
$map = [ $map = [
'cost' => ['成本', '更新前成本', '更新后成本'], 'cost' => ['当前成本', '更新前成本', "更新后成本"],
'inventory' => ['库存', '盘点', '上新'], 'inventory' => ['当前库存', '盘点数', '采购总数'],
]; ];
$headTitle = array_merge($headTitle, $map[$this->type]); $headTitle = array_merge($headTitle, $map[$this->type]);
if ('cost' === $this->type) { if ('cost' === $this->type) {
@ -70,21 +70,19 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
} }
$bodyData = []; $bodyData = [];
foreach ($data as $item) { foreach ($data as $item) {
$arr[0] = $item['goods']['goods_code']; $arr[0] = $item['external_sku_id'];
$arr[1] = $item['goods']['title']; $arr[1] = $item['name'];
$arr[2] = $item['goods']['type']['name']; $arr[2] = !empty($item['goods']['type']['name']) ? $item['goods']['type']['name'] : '';
$arr[3] = $item['goods']['brand']['name']; $arr[3] = $item['title'];
$arr[4] = $item['sku_code'];
$arr[5] = $item['title'];
if ('cost' === $this->type) { if ('cost' === $this->type) {
$arr[6] = (string)$item['cost']; $arr[4] = (string)$item['cost'];
$arr[7] = (string)$update[$item['id']]['before_update']; $arr[5] = (string)$update[$item['id']]['before_update'];
$arr[8] = (string)$update[$item['id']]['after_update']; $arr[6] = (string)$update[$item['id']]['after_update'];
} }
if ('inventory' === $this->type) { if ('inventory' === $this->type) {
$arr[6] = (string)$item['stock']; $arr[4] = (string)$item['stock'];
$arr[7] = (string)$update[$item['id']]['inventory']; $arr[5] = (string)$update[$item['id']]['inventory'];
$arr[8] = (string)$update[$item['id']]['arrived_today_num']; $arr[6] = (string)$update[$item['id']]['arrived_today_num'];
} }
$bodyData[] = $arr; $bodyData[] = $arr;
} }
@ -97,18 +95,23 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
$day = DateTimeUtils::getToday(); $day = DateTimeUtils::getToday();
$logs = Log::query() $logs = Log::query()
->select(['target_id', 'before_update', 'after_update']) ->select(['target_id', 'before_update', 'after_update'])
->where('target_type', 'goods_sku') ->where('target_type', TargetTypeEnum::PURCHASE)
->where('target_field', 'cost') ->where('target_field', 'stock')
->where('created_at', '>', $day) ->where('created_at', '>', $day)
->orderBy('id', 'asc')
->get(); ->get();
$update = []; $update = [];
foreach ($logs as $log) { foreach ($logs as $log) {
if ($log['before_update'] !== $log['after_update'] || (int)$log['after_update']) { if (!isset($update[$log['target_id']])) {
if (!isset($update[$log['target_id']])) { $beforeData = json_decode($log['before_update'], true);
$update[$log['target_id']]['before_update'] = $log['before_update']; if (!empty($beforeData['cost'])) {
$update[$log['target_id']]['before_update'] = $beforeData['cost'];
} }
$update[$log['target_id']]['after_update'] = $log['after_update'];
}
$afterData = json_decode($log['after_update'], true);
if (!empty($afterData['cost']) && $afterData['cost'] != $beforeData['cost']) {
$update[$log['target_id']]['after_update'] = $afterData['cost'];
} }
} }

View File

@ -33,9 +33,8 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
{ {
$headTitle = [ $headTitle = [
'商品名称', '商品名称',
'品类', '品种',
'规格', '规格名称',
'品牌',
'商品编码', '商品编码',
'成本', '成本',
'销售数量', '销售数量',
@ -51,8 +50,7 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
->with([ ->with([
'goods:id,title', 'goods:id,title',
'goodsType:id,name', 'goodsType:id,name',
'goodsSku:id,title', 'goodsSku:id,title,name'
'goodsBrand:id,name',
]) ])
->where('date', '>=', $this->startDate) ->where('date', '>=', $this->startDate)
->where('date', '<=', $this->endDate) ->where('date', '<=', $this->endDate)
@ -66,10 +64,9 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
$number = $item->total_goods_number - $item->total_cancel_number; $number = $item->total_goods_number - $item->total_cancel_number;
if (!isset($arr[$item->external_sku_id])) { if (!isset($arr[$item->external_sku_id])) {
$arr[$item->external_sku_id] = [ $arr[$item->external_sku_id] = [
'goodsTitle' => $item->goods->title, 'goodsTitle' => !empty($item->goodsSku) ? $item->goodsSku->name:'',
'goodsTypeName' => $item->goodsType->name, 'goodsTypeName' => !empty($item->goodsType) ? $item->goodsType->name : "",
'goodsSkuTitle' => $item->goodsSku->title, 'goodsSkuTitle' => !empty($item->goodsSku) ? $item->goodsSku->title : "",
'goodsBrandName' => $item->goodsBrand->name,
'external_sku_id' => $item->external_sku_id, 'external_sku_id' => $item->external_sku_id,
'cost' => [], 'cost' => [],
'number' => [], 'number' => [],
@ -97,7 +94,6 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
$item['goodsTitle'], $item['goodsTitle'],
$item['goodsTypeName'], $item['goodsTypeName'],
$item['goodsSkuTitle'], $item['goodsSkuTitle'],
$item['goodsBrandName'],
$item['external_sku_id'], $item['external_sku_id'],
$cost, $cost,
array_sum($item['number']), array_sum($item['number']),

View File

@ -193,11 +193,8 @@ class GoodsCombinationController extends Controller
public function goodsSkus(Request $request, $title) public function goodsSkus(Request $request, $title)
{ {
$goodsIds = Goods::query()
->where('title', 'like', '%' . $title . '%')
->pluck('id');
$skus = GoodsSku::query() $skus = GoodsSku::query()
->whereIn('goods_id', $goodsIds) ->where('title', 'like', '%' . $title . '%')
->where('is_combination', 0) ->where('is_combination', 0)
->with('goods:id,title') ->with('goods:id,title')
->get(['id', 'title', 'goods_id']); ->get(['id', 'title', 'goods_id']);

View File

@ -84,12 +84,10 @@ class DailyStockRecordController extends Controller
*/ */
public function inventoryBatchStore(Request $request) public function inventoryBatchStore(Request $request)
{ {
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'inventoryOrders' => 'required|array', 'inventoryOrders' => 'required|array',
'inventoryOrders.*.external_sku_id' => 'required|string', 'inventoryOrders.*.external_sku_id' => 'required|string',
'inventoryOrders.*.inventory' => 'required|integer', 'inventoryOrders.*.inventory' => 'required|integer',
]); ]);
if ($validator->fails()) { if ($validator->fails()) {
//校验失败返回异常 //校验失败返回异常

View File

@ -158,7 +158,7 @@ class LossRecordController extends Controller
return response($content, $this->res['httpCode']); return response($content, $this->res['httpCode']);
} }
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray(); $goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
$updateIds = []; $allUpdateIds = [];
$batchNumber = GeneratorUtils::generateBatchNumber(); $batchNumber = GeneratorUtils::generateBatchNumber();
$today = DateTimeUtils::getToday(); $today = DateTimeUtils::getToday();
//开始保存数据 //开始保存数据
@ -178,10 +178,10 @@ class LossRecordController extends Controller
$lossRecords->save(); $lossRecords->save();
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ['num' => 0 - $v['num'], "cost" => $v['cost']]); $updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ['num' => 0 - $v['num'], "cost" => $v['cost']]);
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
} }
event(new BatchStockUpdateEvent($updateIds)); event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
return response($this->res, $this->res['httpCode']); return response($this->res, $this->res['httpCode']);
} }

View File

@ -99,7 +99,7 @@ class PurchaseRecordController extends Controller
} }
$purchaseRecords->save(); $purchaseRecords->save();
$updateIds = GoodSkuService::computeSkuStock($goodsSku->toArray(), $allParams,TargetTypeEnum::PURCHASE); $updateIds = GoodSkuService::computeSkuStock($goodsSku->toArray(), $allParams, TargetTypeEnum::PURCHASE);
event(new BatchStockUpdateEvent($updateIds)); event(new BatchStockUpdateEvent($updateIds));
} else { } else {
$this->res = [ $this->res = [
@ -180,7 +180,7 @@ class PurchaseRecordController extends Controller
return response($content, $this->res['httpCode']); return response($content, $this->res['httpCode']);
} }
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray(); $goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
$updateIds = []; $allUpdateIds = [];
$expireDay = DeveloperConfigService::getDefaultExpireDay(); $expireDay = DeveloperConfigService::getDefaultExpireDay();
$today = DateTimeUtils::getToday(); $today = DateTimeUtils::getToday();
$batchNumber = GeneratorUtils::generateBatchNumber(); $batchNumber = GeneratorUtils::generateBatchNumber();
@ -201,11 +201,12 @@ class PurchaseRecordController extends Controller
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString(); $purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
$purchaseRecords->save(); $purchaseRecords->save();
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, $v,TargetTypeEnum::PURCHASE); $updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, $v, TargetTypeEnum::PURCHASE);
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
} }
//如果是組合商品会触发重算逻辑 //如果是組合商品会触发重算逻辑
event(new BatchStockUpdateEvent($updateIds)); event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
return response($this->res, $this->res['httpCode']); return response($this->res, $this->res['httpCode']);
} }

View File

@ -6,8 +6,10 @@ namespace App\Http\Enum;
class TargetTypeEnum class TargetTypeEnum
{ {
const PURCHASE = "purchase"; const PURCHASE = "sku_stock_purchase";
const LOSS = "loss"; const LOSS = "sku_stock_loss";
const INVENTORY = "sku_stock_inventory";
} }

View File

@ -38,7 +38,7 @@ class LossImport implements ToArray, SkipsEmptyRows
$buyerNames[] = $row[4]; $buyerNames[] = $row[4];
} }
unset($row); unset($row);
$updateIds = []; $allUpdateIds = [];
$hasGoodsSkus = GoodsSku::query() $hasGoodsSkus = GoodsSku::query()
->whereIn('external_sku_id', $externalSkuIds) ->whereIn('external_sku_id', $externalSkuIds)
->get(['id', 'status', 'external_sku_id', 'stock', "sale_stock", "cost", "is_combination"]) ->get(['id', 'status', 'external_sku_id', 'stock', "sale_stock", "cost", "is_combination"])
@ -71,11 +71,12 @@ class LossImport implements ToArray, SkipsEmptyRows
} }
$lossRecords->save(); $lossRecords->save();
$updateIds += GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => 0 - $row[2], 'cost' => $row[3]]); $updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => 0 - $row[2], 'cost' => $row[3]]);
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
} }
Log::info("报损导入内容:", $collection); Log::info("报损导入内容:", $collection);
// 批量更新 // 批量更新
event(new BatchStockUpdateEvent(collect($updateIds)->unique()->toArray())); event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
} }

View File

@ -42,7 +42,7 @@ class PurchaseImport implements ToArray, SkipsEmptyRows
$supplierNames[] = $row[5]; $supplierNames[] = $row[5];
} }
unset($row); unset($row);
$updateIds = []; $allUpdateIds = [];
$hasGoodsSkus = GoodsSku::query() $hasGoodsSkus = GoodsSku::query()
->whereIn('external_sku_id', $externalSkuIds) ->whereIn('external_sku_id', $externalSkuIds)
->get(['id', 'status', 'external_sku_id', 'stock', "sale_stock", "cost", "is_combination"]) ->get(['id', 'status', 'external_sku_id', 'stock', "sale_stock", "cost", "is_combination"])
@ -80,11 +80,13 @@ class PurchaseImport implements ToArray, SkipsEmptyRows
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString(); $purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
$purchaseRecords->save(); $purchaseRecords->save();
$updateIds += GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => $row[2], 'cost' => $row[3]], TargetTypeEnum::PURCHASE); $updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => $row[2], 'cost' => $row[3]], TargetTypeEnum::PURCHASE);
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
} }
Log::info("采购导入内容:", $collection); Log::info("采购导入内容:", $collection);
Log::info("allUpdateIds:", $allUpdateIds);
// 批量更新 // 批量更新
event(new BatchStockUpdateEvent(collect($updateIds)->unique()->toArray())); event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
} }
} }
} }

View File

@ -103,6 +103,7 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
$updateIds[] = $goodsSkuId; $updateIds[] = $goodsSkuId;
} }
} }
if ($updateIds) { if ($updateIds) {
$updateIds = array_unique($updateIds); $updateIds = array_unique($updateIds);
// 批量更新 // 批量更新

View File

@ -8,6 +8,7 @@ use App\Models\BusinessOrderItem;
use App\Models\CombinationGood; use App\Models\CombinationGood;
use App\Models\DailyStockRecord; use App\Models\DailyStockRecord;
use App\Models\GoodsSku; use App\Models\GoodsSku;
use App\Models\Log as LogModel;
use App\Utils\DateTimeUtils; use App\Utils\DateTimeUtils;
use App\Utils\GeneratorUtils; use App\Utils\GeneratorUtils;
use Carbon\Carbon; use Carbon\Carbon;
@ -52,7 +53,7 @@ class GoodSkuService
DB::beginTransaction(); DB::beginTransaction();
try { try {
foreach ($skusWithCombinationGoods as $sku) { foreach ($skusWithCombinationGoods as $sku) {
// 更新 // 更新每日数据
DailyStockRecord::query()->updateOrCreate([ DailyStockRecord::query()->updateOrCreate([
'sku_id' => $sku['id'], 'sku_id' => $sku['id'],
'day' => $today, 'day' => $today,
@ -62,19 +63,26 @@ class GoodSkuService
"batch_number" => $batchNumber "batch_number" => $batchNumber
]); ]);
} }
$costLogs = [];
//更新库存并记录数据
foreach ($inventoryKeyBySkuIdMap as $skuId => $realStock) { foreach ($inventoryKeyBySkuIdMap as $skuId => $realStock) {
//库存修改 盘点是直接覆盖 //库存修改 盘点是直接覆盖
GoodsSku::query()->where('id', $skuId)->update([ $skuData = GoodsSku::query()->where('id', $skuId)->first();
'stock' => $realStock if(!empty($skuData)){
]); $costLogs[] = static::addStockLog($skuData, []
$updateIds[] = $skuId; , TargetTypeEnum::INVENTORY, ['stock' => $realStock]);
$skuData->stock = $realStock;
$skuData->save();
$updateIds[] = $skuId;
}
} }
$log = new LogModel();
$log->batchInsert($costLogs);
DB::commit(); DB::commit();
} catch (\Exception $exception) { } catch (\Exception $exception) {
DB::rollBack(); DB::rollBack();
Log::error("库存盘点异常", ["error" => $exception->getMessage()]); Log::error("库存盘点异常", ["error" => $exception->getMessage()]);
} }
// 批量更新 // 批量更新
@ -113,39 +121,65 @@ class GoodSkuService
} }
public static function computeSkuStock(array $goodsSkuItem, array $v, $targetType = TargetTypeEnum::LOSS) public static function computeSkuStock(array $goodsSkuItem, array $changeData, $targetType = TargetTypeEnum::LOSS)
{ {
$updateIds = []; $updateIds = [];
Log::info("库存更新前完整商品信息", $goodsSkuItem); Log::info("库存更新前完整商品信息", $goodsSkuItem);
Log::info("库存更新前完整请求信息", $v); Log::info("库存更新前完整请求信息", $changeData);
$updateParams = []; $updateParams = [];
//添加系统日志
$costLogs = [];
// 成本
if (empty($goodsSkuItem['is_combination'])) { if (empty($goodsSkuItem['is_combination'])) {
$updateParam = [ $updateParam = [
'stock' => $goodsSkuItem['stock'] + $v['num'], 'stock' => $goodsSkuItem['stock'] + $changeData['num'],
'sale_stock' => $goodsSkuItem['sale_stock'] + $v['num'], 'sale_stock' => $goodsSkuItem['sale_stock'] + $changeData['num'],
]; ];
if ($targetType == TargetTypeEnum::PURCHASE) { if ($targetType == TargetTypeEnum::PURCHASE) {
$updateParam['cost'] = $v['cost']; $updateParam['cost'] = $changeData['cost'];
} }
GoodsSku::query()->where('external_sku_id', "=", $goodsSkuItem['external_sku_id']) GoodsSku::query()->where('external_sku_id', "=", $goodsSkuItem['external_sku_id'])
->update($updateParam); ->update($updateParam);
$updateIds[] = $goodsSkuItem['id']; $updateIds[] = $goodsSkuItem['id'];
$updateParams[] = $updateParam; $updateParams[] = $updateParam;
$costLogs[] = static::addStockLog($goodsSkuItem, $changeData, $targetType, $updateParam);
} else { } else {
$combinationGood = CombinationGood::query()->with('goodsSkuItem:id,stock,sale_stock') $combinationGood = CombinationGood::query()->with('goodsSkuItem:id,stock,sale_stock')
->where('goods_sku_id', $goodsSkuItem['id'])->get(); ->where('goods_sku_id', $goodsSkuItem['id'])->get();
foreach ($combinationGood as $item) { foreach ($combinationGood as $item) {
$updateParam = [ $updateParam = [
'stock' => $item['goodsSkuItem']['stock'] + $v['num'] * $item['item_num'], 'stock' => $item['goodsSkuItem']['stock'] + $changeData['num'] * $item['item_num'],
'sale_stock' => $item['goodsSkuItem']['sale_stock'] + $v['num'] * $item['item_num'], 'sale_stock' => $item['goodsSkuItem']['sale_stock'] + $changeData['num'] * $item['item_num'],
]; ];
GoodsSku::query()->where('id', $item['goodsSkuItem']['id'])->update($updateParam); GoodsSku::query()->where('id', $item['goodsSkuItem']['id'])->update($updateParam);
$updateIds[] = $item['goodsSkuItem']['id']; $updateIds[] = $item['goodsSkuItem']['id'];
$updateParams[] = $updateParam; $updateParams[] = $updateParam;
$costLogs[] = static::addStockLog($item['goodsSkuItem'], $changeData, $targetType, $updateParam);
} }
} }
$log = new LogModel();
$log->batchInsert($costLogs);
Log::info("本次请求更新参数", $updateParams); Log::info("本次请求更新参数", $updateParams);
return $updateIds; return $updateIds;
} }
public static function addStockLog($goodsSkuItem, $changeData, $targetType = TargetTypeEnum::LOSS, $updateParam)
{
$costLog = [
'module' => 'goodSkus',
'action' => "POST",
'target_type' => $targetType,
'target_id' => $goodsSkuItem['id'] ?? 0,
'user_id' => $changeData['user_id'] ?? 999,
"target_field" => "stock"
];
$costLog['before_update'] = json_encode($goodsSkuItem);
$costLog['after_update'] = json_encode($updateParam);
return $costLog;
}
} }