mirror of
https://gitee.com/hzchunfen/erp.git
synced 2025-11-30 22:20:45 +00:00
鲜花2.0-报失单导入和价格告警
This commit is contained in:
parent
3b61176cda
commit
6841435ea0
@ -41,9 +41,9 @@ class CheckPrice extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//定时任务每天只查询昨天当天数据 触发节点每日凌晨
|
||||
$yesterdayStartTime = Carbon::yesterday()->startOfDay()->toDateTimeString();
|
||||
$yesterdayEndTime = Carbon::yesterday()->endOfDay()->toDateTimeString();
|
||||
//定时任务每15min执行一次 只会查询15min内的订单数据
|
||||
$startTime = Carbon::now()->subMinutes(15)->toDateTimeString();
|
||||
$endTime = Carbon::now()->toDateTimeString();
|
||||
|
||||
//查询价格异常订单
|
||||
$results = DB::table('business_order_items as a')
|
||||
@ -51,11 +51,11 @@ class CheckPrice extends Command
|
||||
, 'b.cost','a.created_at','a.business_order_id')
|
||||
->leftJoin('goods_skus as b', 'a.external_sku_id', '=', 'b.external_sku_id')
|
||||
->leftJoin('goods as c', 'b.goods_id', '=', 'c.id')
|
||||
->whereBetween('a.created_at', [$yesterdayStartTime,$yesterdayEndTime])
|
||||
->whereBetween('a.created_at', [$startTime,$endTime])
|
||||
->havingRaw('goods_price < cost')
|
||||
->get();
|
||||
if($results->isNotEmpty()){
|
||||
Log::info($yesterdayStartTime.'异常订单',$results->toArray());
|
||||
Log::info($startTime.'异常订单',$results->toArray());
|
||||
$messageService = new MessageService();
|
||||
foreach ($results as $v){
|
||||
$messageService->createPriceExceptionMessage($v->business_order_id,
|
||||
|
||||
75
app/Console/Commands/CheckSkuQualityPeriod.php
Normal file
75
app/Console/Commands/CheckSkuQualityPeriod.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Http\Service\MessageService;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\PurchaseRecords;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CheckSkuQualityPeriod extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:sku_quality_period';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '检查sku保质期';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//定时任务每天执行一次
|
||||
$endTime = Carbon::now()->endOfDay()->toDateTimeString();
|
||||
$startTime = Carbon::now()->startOfDay()->toDateTimeString();//目前检查范围是1天
|
||||
|
||||
//查询未处理过的快过期的异常订单
|
||||
$purchaseRecords = DB::table('purchase_records as a')
|
||||
->select("a.created_at", "a.num", "b.title", "b.stock", "a.id", "a.sku_id", "b.external_sku_id")
|
||||
->leftJoin('goods_skus as b', 'a.sku_id', '=', 'b.id')
|
||||
->where("a.status", "=", 0)
|
||||
->whereBetween('a.expire_time', [$startTime, $endTime])->get();
|
||||
if ($purchaseRecords->isNotEmpty()) {
|
||||
$messageService = new MessageService();
|
||||
foreach ($purchaseRecords as $v) {
|
||||
// 单独采购单后续总和小于库存表示该sku没有卖完
|
||||
$totalPurchaseNum = PurchaseRecords::query()->where('id', '>=', $v->id)
|
||||
->where('sku_id',"=",$v->sku_id)->sum('num');
|
||||
if ($totalPurchaseNum < $v->stock) {
|
||||
Log::info("触发通知{$totalPurchaseNum}:",(array)$v);
|
||||
$messageService->skuQualityPeriodNoticeMessage((array)$v);
|
||||
}
|
||||
//更新下状态
|
||||
PurchaseRecords::query()->update([
|
||||
"status" => 1
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('任务完成:check-CheckSkuQualityPeriod');
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Commands\CheckPrice;
|
||||
use App\Console\Commands\CheckSkuQualityPeriod;
|
||||
use App\Console\Commands\DailySalesReport;
|
||||
use App\Console\Commands\GoodsSkuDailyReport;
|
||||
use App\Console\Commands\Inventory;
|
||||
@ -47,7 +48,9 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->command(DeleteKttQuery::class)->daily();
|
||||
//新增价格校验
|
||||
$schedule->command(CheckPrice::class)->dailyAt('07:00');
|
||||
$schedule->command(CheckPrice::class)->everyFifteenMinutes();
|
||||
$schedule->command(CheckSkuQualityPeriod::class)->dailyAt('05:30');;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -21,6 +21,8 @@ class BusinessOrdersUpdate
|
||||
public $businessGoodSku;
|
||||
public $num;
|
||||
public $goodsSku;
|
||||
public $type = "BusinessOrdersUpdate";
|
||||
|
||||
public $combinationGoodsUpdate = true;
|
||||
|
||||
/**
|
||||
@ -53,7 +55,7 @@ class BusinessOrdersUpdate
|
||||
|
||||
$this->goodsSku->sale_stock = $saleStock;
|
||||
$this->goodsSku->stock = $stock;
|
||||
Log::info("sku 业务订单库存更新",(array)$this->goodsSku);
|
||||
Log::info("sku 业务订单库存更新", (array)$this->goodsSku);
|
||||
$this->goodsSku->save();
|
||||
}
|
||||
|
||||
|
||||
@ -34,23 +34,13 @@ class StockUpdateEvent
|
||||
private function checkStatusAndStock($goodsSku)
|
||||
{
|
||||
//新版上下架和真实库存无关
|
||||
$stock = $goodsSku->sale_stock;
|
||||
if (0 >= $goodsSku->sale_stock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
} else {
|
||||
$status = GoodsSku::$STATUS_ON_SALE;
|
||||
}
|
||||
//TODO 待确认逻辑
|
||||
$arrivedTodayNum = DailyStockRecord::query()
|
||||
->where('day', DateTimeUtils::getToday())
|
||||
->where('sku_id', $goodsSku->id)
|
||||
->value('arrived_today_num');
|
||||
if (20 < $arrivedTodayNum + $goodsSku->yesterday_num && 4 > $goodsSku->stock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
$stock = 0;
|
||||
}
|
||||
|
||||
$goodsSku->status = $status;
|
||||
$goodsSku->stock = $stock;
|
||||
$goodsSku->save();
|
||||
}
|
||||
|
||||
|
||||
@ -273,8 +273,7 @@ class GoodsSkusController extends Controller
|
||||
$log = new LogModel();
|
||||
$log->batchInsert($logs);
|
||||
DB::commit();
|
||||
// 批量更新
|
||||
event(new BatchStockUpdateEvent(array_column($request->skus, 'id')));
|
||||
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
$this->res = [
|
||||
|
||||
@ -15,6 +15,7 @@ use App\Imports\LossImport;
|
||||
use App\Imports\NewSetImport;
|
||||
use App\Imports\PurchaseImport;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\CombinationGood;
|
||||
use App\Models\DailySalesReport;
|
||||
use App\Models\DeveloperConfig;
|
||||
use App\Models\Goods;
|
||||
@ -22,6 +23,8 @@ use App\Models\Log;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Models\LossRecords;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\ArrayUtils;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
@ -161,6 +164,7 @@ class WareHouseSkusController extends Controller
|
||||
}
|
||||
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
|
||||
$updateIds = [];
|
||||
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||
//开始保存数据
|
||||
foreach ($purchaseOrders as $v) {
|
||||
$goodsSkuItem = $goodsSkuMap[$v['external_sku_id']];
|
||||
@ -173,20 +177,13 @@ class WareHouseSkusController extends Controller
|
||||
$purchaseRecords->buyer_name = $v['buyer_name'] ?? '';
|
||||
$purchaseRecords->supplier_name = $v['supplier_name'] ?? '';
|
||||
$purchaseRecords->supplier_id = $v['supplier_id'] ?? 0;
|
||||
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||
$purchaseRecords->save();
|
||||
|
||||
//更新库存
|
||||
GoodsSku::query()->where('external_sku_id', $v['external_sku_id'])->update([
|
||||
'stock' => $goodsSkuItem['stock'] + $v['num'],
|
||||
'sale_stock' => $goodsSkuItem['sale_stock'] + $v['num'],
|
||||
'cost' => number_format(($goodsSkuItem['stock']*$goodsSkuItem['cost']+$v['cost']*$v['num'])
|
||||
/($goodsSkuItem['stock'] + $v['num']),2),
|
||||
'status' => 1,
|
||||
]);
|
||||
$updateIds[] = $goodsSkuItem['id'];
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem,$v);
|
||||
|
||||
}
|
||||
//如果是組合商品後續會處理组合商品库存的拆分
|
||||
//如果是組合商品会触发重算逻辑
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
@ -254,17 +251,10 @@ class WareHouseSkusController extends Controller
|
||||
$lossRecords->reason = $v['reason'] ?? '';
|
||||
$lossRecords->save();
|
||||
|
||||
//更新库存
|
||||
GoodsSku::query()->where('external_sku_id', $v['external_sku_id'])->update([
|
||||
'stock' => $goodsSkuItem['stock'] - $v['num'],
|
||||
'sale_stock' => $goodsSkuItem['sale_stock'] - $v['num'],
|
||||
'cost' => number_format(($goodsSkuItem['stock']*$goodsSkuItem['cost']-$v['cost']*$v['num'])
|
||||
/($goodsSkuItem['stock'] - $v['num']),2),
|
||||
]);
|
||||
$updateIds[] = $goodsSkuItem['id'];
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem,['num'=>0-$v['num'],"cost"=>$v['cost']]);
|
||||
|
||||
}
|
||||
//如果是組合商品後續會處理组合商品库存的拆分
|
||||
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
12
app/Http/Enum/CacheKeyEnum.php
Normal file
12
app/Http/Enum/CacheKeyEnum.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class CacheKeyEnum
|
||||
{
|
||||
|
||||
const STOCK_RULE_PROPORTION = "stock_rule_proportion";
|
||||
|
||||
const DEFAULT_EXPIRE_DAY = "default_expire_day";
|
||||
}
|
||||
17
app/Http/Enum/DevConfigKeyEnum.php
Normal file
17
app/Http/Enum/DevConfigKeyEnum.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class DevConfigKeyEnum
|
||||
{
|
||||
|
||||
const STOCK_RULE_PROPORTION = "stock_rule_proportion";
|
||||
|
||||
const DEFAULT_STOCK_RULE_PROPORTION = 0.2;
|
||||
|
||||
const SKU_EXPIRE_DAY = "sku_expire_day";
|
||||
|
||||
const DEFAULT_EXPIRE_DAY = 3;
|
||||
|
||||
}
|
||||
13
app/Http/Enum/Message/MessageTypeEnum.php
Normal file
13
app/Http/Enum/Message/MessageTypeEnum.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum\Message;
|
||||
|
||||
|
||||
class MessageTypeEnum
|
||||
{
|
||||
CONST PRICE_EXCEPTION_NOTICE = "price_exception_notice";
|
||||
|
||||
const LOW_STOCK_NOTICE = "low_stock_notice";
|
||||
|
||||
const QUALITY_PERIOD_EXPIRE_NOTICE = "quality_period_expire_notice";
|
||||
}
|
||||
@ -2,20 +2,102 @@
|
||||
|
||||
namespace App\Http\Service;
|
||||
|
||||
use App\Http\Enum\Message\MessageTypeEnum;
|
||||
use App\Models\WebsiteMessages;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class MessageService
|
||||
{
|
||||
public function createPriceExceptionMessage(string $businessOrderId
|
||||
,string $productName,string $skuName,string $goodsPrice,string $cost){
|
||||
//值为角色ids
|
||||
public $roleIdsMapKeyByNoticeType = [
|
||||
MessageTypeEnum::PRICE_EXCEPTION_NOTICE => [9],
|
||||
MessageTypeEnum::LOW_STOCK_NOTICE => [9],
|
||||
MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE => [9]
|
||||
];
|
||||
|
||||
public function createPriceExceptionMessage(string $businessOrderId, string $productName, string $skuName
|
||||
, string $goodsPrice, string $cost)
|
||||
{
|
||||
$roleIds = $this->roleIdsMapKeyByNoticeType[MessageTypeEnum::PRICE_EXCEPTION_NOTICE] ?? [];
|
||||
if (empty($roleIds)) {
|
||||
Log::error("消息配置异常", $this->roleIdsMapKeyByNoticeType);
|
||||
}
|
||||
$date = Carbon::now()->format('Y-m-d');
|
||||
foreach ($roleIds as $v) {
|
||||
$arr['title'] = "订单价格异常告警";
|
||||
$arr['role_id'] = 9;
|
||||
$arr['content'] = Carbon::yesterday()->format('Y-m-d')."订单号:{$businessOrderId}-商品{$productName}
|
||||
$arr['role_id'] = $v;
|
||||
$arr['unique_key'] = $date."-".$businessOrderId;
|
||||
$arr['type'] = MessageTypeEnum::PRICE_EXCEPTION_NOTICE;
|
||||
$arr['content'] = $date . "订单号:{$businessOrderId}-商品{$productName}
|
||||
规格{$skuName}价格有异常,当前售价{$goodsPrice}/支,当前成本价{$cost}/支";
|
||||
$arr['created_at'] = Carbon::now()->toDateTimeString();
|
||||
$arr['updated_at'] = Carbon::now()->toDateTimeString();
|
||||
return WebsiteMessages::insert($arr);
|
||||
$this->saveWebsiteMessages($arr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 低库存告警
|
||||
* @param $inventory
|
||||
* @param $goodsSku
|
||||
* @return void
|
||||
*/
|
||||
public function createLowerStockNoticeMessage($inventory,$goodsSku)
|
||||
{
|
||||
$roleIds = $this->roleIdsMapKeyByNoticeType[MessageTypeEnum::LOW_STOCK_NOTICE] ?? [];
|
||||
if (empty($roleIds)) {
|
||||
Log::error("消息配置异常", $this->roleIdsMapKeyByNoticeType);
|
||||
}
|
||||
$date = Carbon::now()->format('Y-m-d');
|
||||
foreach ($roleIds as $v) {
|
||||
$arr['title'] = "订单库存不足告警";
|
||||
$arr['role_id'] = $v;
|
||||
$arr['unique_key'] = $date."-".$goodsSku['id'];
|
||||
$arr['type'] = MessageTypeEnum::LOW_STOCK_NOTICE;
|
||||
$arr['content'] = $date . "规格{$goodsSku['title']}库存可能需要补货,当前实际库存{$goodsSku['stock']},上次库存盘点数{$inventory}";
|
||||
$this->saveWebsiteMessages($arr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保質期告警
|
||||
* @param $goodsSku
|
||||
* @return void
|
||||
*/
|
||||
public function skuQualityPeriodNoticeMessage($goodsSku)
|
||||
{
|
||||
$roleIds = $this->roleIdsMapKeyByNoticeType[MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE] ?? [];
|
||||
if (empty($roleIds)) {
|
||||
Log::error("消息配置异常", $this->roleIdsMapKeyByNoticeType);
|
||||
}
|
||||
$date = Carbon::now()->format('Y-m-d');
|
||||
foreach ($roleIds as $v) {
|
||||
$arr['title'] = "订单库存不足告警";
|
||||
$arr['role_id'] = $v;
|
||||
$arr['unique_key'] = $date."-".$goodsSku['id'];//这个场景下实际是采购单的id
|
||||
$arr['type'] = MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE;
|
||||
$arr['content'] = $date . "规格{$goodsSku['title']},即将过期,实际库存{$goodsSku['stock']}
|
||||
,当时采购数量为{$goodsSku['num']},录入采购时间为{$goodsSku['created_at']}";
|
||||
|
||||
$this->saveWebsiteMessages($arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function saveWebsiteMessages($arr)
|
||||
{
|
||||
$websiteMessages = new WebsiteMessages();
|
||||
$websiteMessages->title = $arr['title'];
|
||||
$websiteMessages->type = $arr['type'];
|
||||
$websiteMessages->role_id = $arr['role_id'];
|
||||
$websiteMessages->content = $arr['content'];
|
||||
$websiteMessages->unique_key = $arr['unique_key'];
|
||||
if (!empty($arr['uid'])) {
|
||||
$websiteMessages->uid = $arr['uid'];
|
||||
}
|
||||
Log::info("站内消息保存",(array)$arr);
|
||||
return $websiteMessages->save($arr);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\LossRecords;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@ -54,15 +55,7 @@ class LossImport implements ToArray, SkipsEmptyRows
|
||||
$lossRecords->reason = $row[5] ?? '';
|
||||
$lossRecords->save();
|
||||
|
||||
//更新库存
|
||||
GoodsSku::query()->where('external_sku_id', $row[0])->update([
|
||||
'stock' => $goodsSkuItem['stock'] - $row[2],
|
||||
'sale_stock' => $goodsSkuItem['sale_stock'] - $row[2],
|
||||
'cost' => number_format(($goodsSkuItem['stock'] * $goodsSkuItem['cost'] - $row[3] * $row[2])
|
||||
/ ($goodsSkuItem['stock'] - $row[2]), 2),
|
||||
'status' => 1,
|
||||
]);
|
||||
$updateIds[] = $hasGoodsSkus['id'];
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => 0 - $row[2], 'cost' => $row[3]]);
|
||||
}
|
||||
Log::info("报损导入内容:", $collection);
|
||||
// 批量更新
|
||||
|
||||
@ -7,7 +7,10 @@ use App\Jobs\SyncCostToMiaoXuan;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||
@ -36,6 +39,7 @@ class PurchaseImport implements ToArray, SkipsEmptyRows
|
||||
->get(['id', 'status', 'external_sku_id', 'stock'])
|
||||
->toArray();
|
||||
$hasGoodsSkus = ArrayUtils::index($hasGoodsSkus, 'external_sku_id');
|
||||
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||
//excel字段排序 編碼 商品名稱 导购數量 成本价 采购人名称 供应商名称
|
||||
foreach ($collection as $row) {
|
||||
if (!isset($hasGoodsSkus[$row[0]])) {
|
||||
@ -51,17 +55,10 @@ class PurchaseImport implements ToArray, SkipsEmptyRows
|
||||
$purchaseRecords->cost = $row[3];
|
||||
$purchaseRecords->buyer_name = $row[4] ?? '';
|
||||
$purchaseRecords->supplier_name = $row[5] ?? '';
|
||||
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||
$purchaseRecords->save();
|
||||
|
||||
//更新库存
|
||||
GoodsSku::query()->where('external_sku_id', $row[0])->update([
|
||||
'stock' => $goodsSkuItem['stock'] + $row[2],
|
||||
'sale_stock' => $goodsSkuItem['sale_stock'] + $row[2],
|
||||
'cost' => number_format(($goodsSkuItem['stock']*$goodsSkuItem['cost']+$row[3]*$row[2])
|
||||
/($goodsSkuItem['stock'] + $row[2]),2),
|
||||
'status' => 1,
|
||||
]);
|
||||
$updateIds[] = $hasGoodsSkus['id'];
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem,["num"=>$row[2],'cost'=>$row[3]]);
|
||||
}
|
||||
Log::info("采购导入内容:",$collection);
|
||||
// 批量更新
|
||||
|
||||
60
app/Listeners/BusinessOrderUpdateListener.php
Normal file
60
app/Listeners/BusinessOrderUpdateListener.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Events\BusinessOrdersUpdate;
|
||||
use App\Http\Enum\CacheKeyEnum;
|
||||
use App\Http\Enum\DevConfigKeyEnum;
|
||||
use App\Http\Service\MessageService;
|
||||
use App\Models\BusinessGoodsSku;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\DeveloperConfig;
|
||||
use App\Models\Shop;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use App\Services\Business\BusinessFactory;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class BusinessOrderUpdateListener implements ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue;
|
||||
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param BusinessOrdersUpdate $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(BusinessOrdersUpdate $event)
|
||||
{
|
||||
//查询库存是否满足告警规则
|
||||
$skuId = $event->goodsSku->id;
|
||||
$nowTime = Carbon::now()->toDateTimeString();
|
||||
//查找最后一次盘点数据
|
||||
$dailyStockRecord = DailyStockRecord::query()->where("sku_id", '=', $skuId)->
|
||||
where("inventory_time", '<', $nowTime)->orderByDesc('inventory_time')->first();
|
||||
$inventory = $dailyStockRecord['inventory'] ?? 0;
|
||||
$expireTime = Carbon::now()->addMinutes(30)->toDateTimeString();
|
||||
$proportion = Cache::remember(CacheKeyEnum::STOCK_RULE_PROPORTION, $expireTime, function () {
|
||||
$developerConfig = DeveloperConfig::query()->where("key", "=", DevConfigKeyEnum::STOCK_RULE_PROPORTION)->first();
|
||||
return $developerConfig['value'] ?? DevConfigKeyEnum::DEFAULT_STOCK_RULE_PROPORTION;
|
||||
});
|
||||
//库存比例小于最近盘点多少告警 一天也只是告警一次
|
||||
if ($inventory > 10 && $inventory * $proportion > $event->goodsSku->stock) {
|
||||
$messageService = new MessageService();
|
||||
$messageService->createLowerStockNoticeMessage($inventory,$event->goodsSku->toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,8 +54,9 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
|
||||
}
|
||||
}
|
||||
}
|
||||
// 减子商品库存
|
||||
if ($combinationGoodsIds) {
|
||||
|
||||
// 减子商品库存 这咯做了调整 其他批量更新不需要同步扣减库存
|
||||
if ($combinationGoodsIds&&!empty($event->type)) {
|
||||
$combinationGoods = CombinationGood::query()
|
||||
->with('goodsSku:id,stock')
|
||||
->whereIn('goods_sku_id', $combinationGoodsIds)
|
||||
|
||||
@ -7,6 +7,7 @@ use App\Events\StockUpdateEvent;
|
||||
use App\Events\GroupSetEvent;
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Listeners\BatchStockUpdateListener;
|
||||
use App\Listeners\BusinessOrderUpdateListener;
|
||||
use App\Listeners\CreateLogisticListener;
|
||||
use App\Listeners\GroupQueryListener;
|
||||
use App\Listeners\StockUpdateListener;
|
||||
@ -28,6 +29,7 @@ class EventServiceProvider extends ServiceProvider
|
||||
BusinessOrdersUpdate::class => [
|
||||
UpdateBusinessGoodsStock::class,
|
||||
CombinationGoodsStockUpdateListener::class,
|
||||
BusinessOrderUpdateListener::class
|
||||
],
|
||||
BatchStockUpdateEvent::class => [
|
||||
BatchStockUpdateListener::class,
|
||||
|
||||
24
app/Services/DeveloperConfig/DeveloperConfigService.php
Normal file
24
app/Services/DeveloperConfig/DeveloperConfigService.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\DeveloperConfig;
|
||||
|
||||
use App\Http\Enum\CacheKeyEnum;
|
||||
use App\Http\Enum\DevConfigKeyEnum;
|
||||
use App\Models\DeveloperConfig;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class DeveloperConfigService
|
||||
{
|
||||
|
||||
public static function getDefaultExpireDay()
|
||||
{
|
||||
$expireTime = Carbon::now()->addHour();
|
||||
return Cache::remember(CacheKeyEnum::DEFAULT_EXPIRE_DAY, $expireTime, function () {
|
||||
$developerConfig = DeveloperConfig::query()->where("key",
|
||||
"=", DevConfigKeyEnum::SKU_EXPIRE_DAY)->first();
|
||||
return $developerConfig['value'] ?? DevConfigKeyEnum::DEFAULT_EXPIRE_DAY;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,17 +3,10 @@
|
||||
namespace App\Services\GoodSku;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Events\CreateLogisticEvent;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\CombinationGood;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Models\ShopShip;
|
||||
use App\Models\Waybill;
|
||||
use App\Services\Business\KuaiTuanTuan\FaceSheet;
|
||||
use App\Utils\ArrayUtils;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class GoodSkuService
|
||||
{
|
||||
@ -43,7 +36,7 @@ class GoodSkuService
|
||||
$record->save();
|
||||
//查询sku当前未发货的数量 目前数据看着有问题暂不操作
|
||||
|
||||
//库存修改
|
||||
//库存修改 盘点是直接覆盖所以这里加个锁
|
||||
GoodsSku::query()->where('id', $sku['id'])->lockForUpdate()->update([
|
||||
'stock' => $requestSkusMap[$sku['external_sku_id']]['inventory']
|
||||
]);
|
||||
@ -51,7 +44,32 @@ class GoodSkuService
|
||||
}
|
||||
// 批量更新
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
}
|
||||
|
||||
public static function computeSkuStock(array $goodsSkuItem, array $v): array
|
||||
{
|
||||
$updateIds = [];
|
||||
if (!empty($v['is_combination'])) {
|
||||
GoodsSku::query()->where('external_sku_id', $v['external_sku_id'])->update([
|
||||
'stock' => $goodsSkuItem['stock'] + $v['num'],
|
||||
'sale_stock' => $goodsSkuItem['sale_stock'] + $v['num'],
|
||||
'cost' => number_format(($goodsSkuItem['stock'] * $goodsSkuItem['cost'] + $v['cost'] * $v['num'])
|
||||
/ ($goodsSkuItem['stock'] + $v['num']), 2),
|
||||
]);
|
||||
$updateIds[] = $goodsSkuItem['id'];
|
||||
} else {
|
||||
//组合商品 这里需要重新获取 减少更新丢失概率 后续考虑库存管理用redis
|
||||
$combinationGood = CombinationGood::query()->with('goodsSkuItem:id,stock,sale_stock')
|
||||
->where('goods_sku_id', $goodsSkuItem['id'])->get();
|
||||
foreach ($combinationGood as $item) {
|
||||
GoodsSku::query()->where('id', $item['goodsSkuItem']['id'])->update([
|
||||
'stock' => $item['goodsSkuItem']['stock'] + $v['num'] * $item['item_num'],
|
||||
'sale_stock' => $item['goodsSkuItem']['sale_stock'] + $v['num'] * $item['item_num'],
|
||||
]);
|
||||
$updateIds[] = $item['goodsSkuItem']['id'];
|
||||
}
|
||||
}
|
||||
return $updateIds;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -21,11 +21,13 @@ class CreatePurchaseRecordsTable extends Migration
|
||||
$table->unsignedDecimal('cost')->default(0)->comment('成本');
|
||||
$table->string('buyer_name')->nullable()->comment('采购人');
|
||||
$table->string('status')->default(0)->comment('盘点完近似状态 0未完成1已售卖完成');
|
||||
$table->string('expire_time')->nullable()->comment('保质期时间');
|
||||
$table->string('supplier_name')->nullable()->comment('供应商名称');
|
||||
$table->Integer('supplier_id')->nullable()->comment('供应商id');
|
||||
// 索引
|
||||
$table->index('sku_id');
|
||||
$table->index('external_sku_id');
|
||||
$table->index('status');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
@ -17,12 +17,15 @@ class CreateWebsiteMessagesTable extends Migration
|
||||
$table->bigIncrements('id');
|
||||
$table->string('title')->comment('消息内容标题');
|
||||
$table->string('content')->comment('消息内容');
|
||||
$table->string('type')->comment('消息类型');
|
||||
$table->string('unique_key')->comment('类型下唯一的key避免重复写入');
|
||||
$table->string('role_id')->nullable()->comment('角色名称');
|
||||
$table->Integer('uid')->nullable()->comment('用户id 存在非0值表示当前uid可见');
|
||||
$table->tinyInteger('status')->default(0)->comment('消息状态 0未读 1已读');
|
||||
$table->string('extend')->nullable()->comment('拓展字段 后续拓展用');
|
||||
|
||||
$table->index(["role_id","uid"]);
|
||||
$table->unique(["type","unique_key"]);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user