库存更新优化

This commit is contained in:
赵世界 2023-11-18 14:35:19 +08:00
parent 9c398e154f
commit b2b3def740
15 changed files with 202 additions and 120 deletions

View File

@ -0,0 +1,45 @@
<?php
namespace App\Events;
use App\Models\GoodsSku;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class BatchStockUpdateEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $goodsSkus;
public $stockWarning;
public $combinationGoodsUpdate;
/**
* Create a new event instance.
*
* @param $goodsSkuIds
* @param bool $stockWarning
* @param bool $combinationGoodsUpdate
*/
public function __construct($goodsSkuIds, bool $stockWarning = true, bool $combinationGoodsUpdate = true)
{
$this->goodsSkus = GoodsSku::query()->whereIn('id', $goodsSkuIds)->get();
$this->stockWarning = $stockWarning;
$this->combinationGoodsUpdate = $combinationGoodsUpdate;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@ -16,35 +16,28 @@ class BusinessOrdersUpdate
{ {
use Dispatchable, InteractsWithSockets, SerializesModels; use Dispatchable, InteractsWithSockets, SerializesModels;
public $businessGoodSku;
public $num; public $num;
public $businessGoods;
public $goodsSku; public $goodsSku;
public $goodsSkus; public $combinationGoodsUpdate = true;
public $combinationGoodsUpdate;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @return void
*/ */
public function __construct($item, $num) public function __construct($businessGoodSku, $num)
{ {
$this->combinationGoodsUpdate = false; $this->businessGoodSku = $businessGoodSku->toArray();
$this->businessGoods = $item->toArray();
$this->num = $num; $this->num = $num;
$this->updateStock(); $this->updateStock();
} }
private function updateStock() private function updateStock()
{ {
try { $this->goodsSku = GoodsSku::query()
$this->goodsSku = GoodsSku::query() ->where('external_sku_id', $this->businessGoodSku['external_sku_id'])
->where('external_sku_id', $this->businessGoods['external_sku_id']) ->first();
->first();
} catch (\Exception $e) {
Log::error('事件库存更新失败: ' . $e->getMessage());
return false;
}
if ($this->goodsSku) { if ($this->goodsSku) {
$this->goodsSku->stock += $this->num; $this->goodsSku->stock += $this->num;
$this->goodsSku->save(); $this->goodsSku->save();

View File

@ -2,7 +2,6 @@
namespace App\Events; namespace App\Events;
use App\Models\GoodsSku;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\PresenceChannel;
@ -14,30 +13,16 @@ use Illuminate\Queue\SerializesModels;
class StockUpdateEvent class StockUpdateEvent
{ {
use Dispatchable, InteractsWithSockets, SerializesModels; use Dispatchable, InteractsWithSockets, SerializesModels;
public $goodsSku; public $goodsSku;
public $goodsSkus;
public $isBatch;
public $combinationGoodsUpdate;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @param $data array|object * @param $goodsSku
*
* @return void
*/ */
public function __construct($data, $isBatch = 0, $combinationGoodsUpdate = false) public function __construct($goodsSku)
{ {
$this->isBatch = $isBatch; $this->goodsSku = $goodsSku;
$this->combinationGoodsUpdate = $combinationGoodsUpdate;
if (is_array($data)) {
// ids集合
$this->goodsSkus = GoodsSku::query()->whereIn('id', $data)->get();
} else {
// GoodsSku Elo模型对象
$this->goodsSku = $data;
}
} }
/** /**

View File

@ -2,7 +2,6 @@
namespace App\Http\Controllers\Goods; namespace App\Http\Controllers\Goods;
use App\Events\StockUpdateEvent;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Resources\GoodsSkuResource; use App\Http\Resources\GoodsSkuResource;
use App\Imports\CombinationGoodsImport; use App\Imports\CombinationGoodsImport;
@ -141,7 +140,6 @@ class GoodsCombinationController extends Controller
CombinationGood::query()->create(['goods_sku_id' => $sku->id, 'item_id' => $item['item_id'], 'item_num' => $item['item_num']]); CombinationGood::query()->create(['goods_sku_id' => $sku->id, 'item_id' => $item['item_id'], 'item_num' => $item['item_num']]);
} }
DB::commit(); DB::commit();
// event(new StockUpdateEvent($sku, 0, true));
} catch (\Exception $exception) { } catch (\Exception $exception) {
DB::rollBack(); DB::rollBack();
$this->res = [ $this->res = [

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Goods; namespace App\Http\Controllers\Goods;
use App\Events\BatchStockUpdateEvent;
use App\Events\StockUpdateEvent; use App\Events\StockUpdateEvent;
use App\Exports\GoodsSkusExport; use App\Exports\GoodsSkusExport;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
@ -234,7 +235,8 @@ class GoodsSkusController extends Controller
$log = new LogModel(); $log = new LogModel();
$log->batchInsert($logs); $log->batchInsert($logs);
DB::commit(); DB::commit();
event(new StockUpdateEvent(array_column($request->skus, 'id'))); // 批量更新
event(new BatchStockUpdateEvent(array_column($request->skus, 'id')));
} catch (\Exception $exception) { } catch (\Exception $exception) {
DB::rollBack(); DB::rollBack();
$this->res = [ $this->res = [

View File

@ -2,10 +2,8 @@
namespace App\Imports; namespace App\Imports;
use App\Events\StockUpdateEvent;
use App\Models\CombinationGood; use App\Models\CombinationGood;
use App\Models\GoodsSku; use App\Models\GoodsSku;
use App\Models\GoodsSkuLocation;
use App\Utils\ArrayUtils; use App\Utils\ArrayUtils;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows; use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
@ -72,7 +70,6 @@ class CombinationGoodsImport implements ToArray, SkipsEmptyRows, WithStartRow
CombinationGood::query()->create(['goods_sku_id' => $sku->id, 'item_id' => $skus[$item['item_code']]['id'], 'item_num' => $item['item_num']]); CombinationGood::query()->create(['goods_sku_id' => $sku->id, 'item_id' => $skus[$item['item_code']]['id'], 'item_num' => $item['item_num']]);
} }
DB::commit(); DB::commit();
// event(new StockUpdateEvent($sku, 0, true));
} catch (\Exception $exception) { } catch (\Exception $exception) {
DB::rollBack(); DB::rollBack();
} }

View File

@ -2,6 +2,7 @@
namespace App\Imports; namespace App\Imports;
use App\Events\BatchImportStockEvent;
use App\Jobs\SyncCostToMiaoXuan; use App\Jobs\SyncCostToMiaoXuan;
use App\Models\DailyStockRecord; use App\Models\DailyStockRecord;
use App\Models\GoodsSku; use App\Models\GoodsSku;
@ -11,7 +12,6 @@ use Exception;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows; use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToArray; use Maatwebsite\Excel\Concerns\ToArray;
use App\Utils\ArrayUtils; use App\Utils\ArrayUtils;
use App\Events\StockUpdateEvent;
class InventoryImport implements ToArray, SkipsEmptyRows class InventoryImport implements ToArray, SkipsEmptyRows
{ {
@ -98,6 +98,7 @@ class InventoryImport implements ToArray, SkipsEmptyRows
} }
} }
sleep(2); sleep(2);
event(new StockUpdateEvent($onSkuIds, 1)); // 批量更新
event(new BatchImportStockEvent($onSkuIds));
} }
} }

View File

@ -2,16 +2,15 @@
namespace App\Imports; namespace App\Imports;
use App\Events\BatchImportStockEvent;
use App\Jobs\SyncCostToMiaoXuan; use App\Jobs\SyncCostToMiaoXuan;
use App\Models\DailyStockRecord; use App\Models\DailyStockRecord;
use App\Models\GoodsSku; use App\Models\GoodsSku;
use App\Models\TodayPrice;
use App\Utils\DateTimeUtils; use App\Utils\DateTimeUtils;
use Exception; use Exception;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows; use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToArray; use Maatwebsite\Excel\Concerns\ToArray;
use App\Utils\ArrayUtils; use App\Utils\ArrayUtils;
use App\Events\StockUpdateEvent;
class NewSetImport implements ToArray, SkipsEmptyRows class NewSetImport implements ToArray, SkipsEmptyRows
{ {
@ -59,6 +58,7 @@ class NewSetImport implements ToArray, SkipsEmptyRows
$record->save(); $record->save();
} }
sleep(2); sleep(2);
event(new StockUpdateEvent($updateIds, 1)); // 批量更新
event(new BatchImportStockEvent($updateIds));
} }
} }

View File

@ -0,0 +1,50 @@
<?php
namespace App\Listeners;
use App\Events\BatchStockUpdateEvent;
use App\Jobs\BusinessGoodsSkuIncrQuantity;
use App\Models\BusinessGoodsSku;
use App\Models\Shop;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use App\Services\Business\BusinessFactory;
class BatchStockUpdateListener
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param BatchStockUpdateEvent $event
* @return void
*/
public function handle(BatchStockUpdateEvent $event)
{
$shops = Shop::query()->whereNotIn('status', [Shop::$STATUS_UNAUTHORIZED, Shop::$STATUS_STOP])->get(['id', 'plat_id']);
if (empty($shops)) {
return;
}
foreach ($shops as $shop) {
foreach ($event->goodsSkus as $goodsSku) {
$num = $goodsSku->stock;
$businessGoodsSkus = BusinessGoodsSku::query()
->select(['goods_id', 'sku_id', 'external_sku_id'])
->where('shop_id', $shop->id)
->where('is_sync', 1)
->where('external_sku_id', $goodsSku->external_sku_id)
->get();
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->batchIncrQuantity($businessGoodsSkus->toArray(), $num, false);
}
}
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\Listeners;
use App\Events\BatchStockUpdateEvent;
use App\Models\GoodsSku;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class BatchStockWarning implements ShouldQueue
{
use InteractsWithQueue;
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
public function handle(BatchStockUpdateEvent $event)
{
if (!$event->stockWarning) {
return;
}
$warningIds = $normalIds = $downIds = [];
foreach ($event->goodsSkus as $goodsSku) {
if (0 >= $goodsSku['stock']) {
$downIds[] = $goodsSku['id'];
} elseif (5 < $goodsSku['stock']) {
$normalIds[] = $goodsSku['id'];
} else {
$warningIds[] = $goodsSku['id'];
}
}
if ($warningIds) {
GoodsSku::query()->whereIn('id', $warningIds)->update(['status' => 2]);
}
if ($normalIds) {
GoodsSku::query()->whereIn('id', $normalIds)->update(['status' => 1]);
}
if ($downIds) {
GoodsSku::query()->whereIn('id', $downIds)->update(['status' => 0]);
}
}
}

View File

@ -6,7 +6,7 @@ use App\Models\CombinationGood;
use App\Models\GoodsSku; use App\Models\GoodsSku;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use App\Events\StockUpdateEvent; use App\Events\BatchStockUpdateEvent;
class CombinationGoodsStockUpdateListener class CombinationGoodsStockUpdateListener
{ {
@ -28,18 +28,18 @@ class CombinationGoodsStockUpdateListener
*/ */
public function handle($event) public function handle($event)
{ {
if ($event->combinationGoodsUpdate) { if (!$event->combinationGoodsUpdate) {
return false; return;
} }
$updateIds = $combinationGoodsIds = $combinationGoodsItemIds = []; $updateIds = $combinationGoodsIds = $combinationGoodsItemIds = [];
if ($event->goodsSku) { if (!empty($event->goodsSku)) {
if ($event->goodsSku->is_combination) { if ($event->goodsSku->is_combination) {
$combinationGoodsIds[] = $event->goodsSku->id; $combinationGoodsIds[] = $event->goodsSku->id;
} else { } else {
$combinationGoodsItemIds[] = $event->goodsSku->id; $combinationGoodsItemIds[] = $event->goodsSku->id;
} }
} }
if ($event->goodsSkus) { if (!empty($event->goodsSkus)) {
foreach ($event->goodsSkus as $sku) { foreach ($event->goodsSkus as $sku) {
if ($sku->is_combination) { if ($sku->is_combination) {
$combinationGoodsIds[] = $sku->id; $combinationGoodsIds[] = $sku->id;
@ -68,7 +68,7 @@ class CombinationGoodsStockUpdateListener
->pluck('goods_sku_id') ->pluck('goods_sku_id')
->toArray(); ->toArray();
if (empty($goodsSkuIds)) { if (empty($goodsSkuIds)) {
return false; return;
} }
foreach ($goodsSkuIds as $goodsSkuId) { foreach ($goodsSkuIds as $goodsSkuId) {
$combinationGoods = CombinationGood::query() $combinationGoods = CombinationGood::query()
@ -86,7 +86,8 @@ class CombinationGoodsStockUpdateListener
} }
if ($updateIds) { if ($updateIds) {
$updateIds = array_unique($updateIds); $updateIds = array_unique($updateIds);
event(new StockUpdateEvent($updateIds, 1, true)); // 批量更新
event(new BatchStockUpdateEvent($updateIds, false));
} }
} }
} }

View File

@ -3,7 +3,6 @@
namespace App\Listeners; namespace App\Listeners;
use App\Events\StockUpdateEvent; use App\Events\StockUpdateEvent;
use App\Jobs\BusinessGoodsSkuIncrQuantity;
use App\Models\BusinessGoodsSku; use App\Models\BusinessGoodsSku;
use App\Models\Shop; use App\Models\Shop;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
@ -35,40 +34,14 @@ class StockUpdateListener
return; return;
} }
foreach ($shops as $shop) { foreach ($shops as $shop) {
if (isset($event->goodsSku)) { $num = $event->goodsSku->stock;
$num = $event->goodsSku->stock; $businessGoodsSkus = BusinessGoodsSku::query()
$businessGoodsSkus = BusinessGoodsSku::query() ->select(['goods_id', 'sku_id', 'external_sku_id'])
->select(['goods_id', 'sku_id', 'external_sku_id']) ->where('shop_id', $shop->id)
->where('shop_id', $shop->id) ->where('is_sync', 1)
->where('is_sync', 1) ->where('external_sku_id', $event->goodsSku->external_sku_id)
->where('external_sku_id', $event->goodsSku->external_sku_id) ->get();
->get(); BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->batchIncrQuantity($businessGoodsSkus->toArray(), $num, false);
if ($event->isBatch) {
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->batchIncrQuantity($businessGoodsSkus->toArray(), $num, false);
} else {
foreach ($businessGoodsSkus as $businessGoodsSku) {
BusinessGoodsSkuIncrQuantity::dispatch($shop, $businessGoodsSku->toArray(), $num, false);
}
}
}
if (isset($event->goodsSkus)) {
foreach ($event->goodsSkus as $goodsSku) {
$num = $goodsSku->stock;
$businessGoodsSkus = BusinessGoodsSku::query()
->select(['goods_id', 'sku_id', 'external_sku_id'])
->where('shop_id', $shop->id)
->where('is_sync', 1)
->where('external_sku_id', $goodsSku->external_sku_id)
->get();
if ($event->isBatch) {
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->batchIncrQuantity($businessGoodsSkus->toArray(), $num, false);
} else {
foreach ($businessGoodsSkus as $businessGoodsSku) {
BusinessGoodsSkuIncrQuantity::dispatch($shop, $businessGoodsSku->toArray(), $num, false);
}
}
}
}
} }
} }
} }

View File

@ -22,36 +22,13 @@ class StockWarning implements ShouldQueue
public function handle($event) public function handle($event)
{ {
if (isset($event->goodsSku)) { $event->goodsSku->status = 2;
$event->goodsSku->status = 2; if (0 >= $event->goodsSku->stock) {
if (0 >= $event->goodsSku->stock) { $event->goodsSku->status = 0;
$event->goodsSku->status = 0;
}
if (5 < $event->goodsSku->stock) {
$event->goodsSku->status = 1;
}
$event->goodsSku->save();
} }
if (isset($event->goodsSkus)) { if (5 < $event->goodsSku->stock) {
$warningIds = $normalIds = $downIds = []; $event->goodsSku->status = 1;
foreach ($event->goodsSkus as $goodsSku) {
if (0 >= $goodsSku['stock']) {
$downIds[] = $goodsSku['id'];
} elseif (5 < $goodsSku['stock']) {
$normalIds[] = $goodsSku['id'];
} else {
$warningIds[] = $goodsSku['id'];
}
}
if ($warningIds) {
GoodsSku::query()->whereIn('id', $warningIds)->update(['status' => 2]);
}
if ($normalIds) {
GoodsSku::query()->whereIn('id', $normalIds)->update(['status' => 1]);
}
if ($downIds) {
GoodsSku::query()->whereIn('id', $downIds)->update(['status' => 0]);
}
} }
$event->goodsSku->save();
} }
} }

View File

@ -29,7 +29,7 @@ class UpdateBusinessGoodsStock implements ShouldQueue
* Handle the event. * Handle the event.
* *
* @param BusinessOrdersUpdate $event * @param BusinessOrdersUpdate $event
* @return void * @return false|void
*/ */
public function handle(BusinessOrdersUpdate $event) public function handle(BusinessOrdersUpdate $event)
{ {
@ -41,17 +41,19 @@ class UpdateBusinessGoodsStock implements ShouldQueue
$log->target_id = $event->goodsSku->id ?? 0; $log->target_id = $event->goodsSku->id ?? 0;
$log->target_field = 'stock'; $log->target_field = 'stock';
$log->user_id = 999; $log->user_id = 999;
$log->message = '未找到' . json_encode($event->businessGoods, 256); $log->message = '未找到' . json_encode($event->businessGoodSku, 256);
$log->save(); $log->save();
return false; return false;
} }
$builder = Shop::query()->whereNotIn('status', [Shop::$STATUS_UNAUTHORIZED, Shop::$STATUS_STOP]); $builder = Shop::query()->whereNotIn('status', [Shop::$STATUS_UNAUTHORIZED, Shop::$STATUS_STOP]);
// 非订单影响库存变更,只更新本店铺下商品 // 非订单影响库存变更,只更新本店铺下商品
if (!isset($event->businessGoods['business_order_id'])) { if (!isset($event->businessGoodSku['business_order_id'])) {
$builder->where('id', $event->businessGoods['shop_id']); $builder->where('id', $event->businessGoodSku['shop_id']);
} }
$shops = $builder->get(['id', 'plat_id']); $shops = $builder->get(['id', 'plat_id']);
if (empty($shops)) { if (empty($shops)) {
LogFile::info('可操作店铺为空'); LogFile::info('可操作店铺为空');
return false; return false;
@ -59,7 +61,7 @@ class UpdateBusinessGoodsStock implements ShouldQueue
foreach ($shops as $shop) { foreach ($shops as $shop) {
$num = $event->goodsSku->stock; $num = $event->goodsSku->stock;
$businessGoodsSkus = BusinessGoodsSku::query()->where('shop_id', $shop->id)->where('is_sync', 1)->where('external_sku_id', $event->businessGoods['external_sku_id'])->get(); $businessGoodsSkus = BusinessGoodsSku::query()->where('shop_id', $shop->id)->where('is_sync', 1)->where('external_sku_id', $event->businessGoodSku['external_sku_id'])->get();
foreach ($businessGoodsSkus as $businessGoodsSku) { foreach ($businessGoodsSkus as $businessGoodsSku) {
BusinessGoodsSkuIncrQuantity::dispatch($shop, $businessGoodsSku->toArray(), $num, false); BusinessGoodsSkuIncrQuantity::dispatch($shop, $businessGoodsSku->toArray(), $num, false);
} }

View File

@ -2,9 +2,13 @@
namespace App\Providers; namespace App\Providers;
use App\Events\BatchImportStockEvent;
use App\Events\BusinessOrdersUpdate; use App\Events\BusinessOrdersUpdate;
use App\Events\GroupSetEvent;
use App\Events\StockUpdateEvent; use App\Events\StockUpdateEvent;
use App\Events\GroupSetEvent;
use App\Events\BatchStockUpdateEvent;
use App\Listeners\BatchStockUpdateListener;
use App\Listeners\BatchStockWarning;
use App\Listeners\CreateLogisticListener; use App\Listeners\CreateLogisticListener;
use App\Listeners\GroupQueryListener; use App\Listeners\GroupQueryListener;
use App\Listeners\StockUpdateListener; use App\Listeners\StockUpdateListener;
@ -29,6 +33,11 @@ class EventServiceProvider extends ServiceProvider
StockWarning::class, StockWarning::class,
CombinationGoodsStockUpdateListener::class, CombinationGoodsStockUpdateListener::class,
], ],
BatchStockUpdateEvent::class => [
BatchStockUpdateListener::class,
BatchStockWarning::class,
CombinationGoodsStockUpdateListener::class,
],
StockUpdateEvent::class => [ StockUpdateEvent::class => [
StockUpdateListener::class, StockUpdateListener::class,
StockWarning::class, StockWarning::class,