鲜花2.0-报失单导入和价格告警
This commit is contained in:
parent
3b61176cda
commit
6841435ea0
@ -41,9 +41,9 @@ class CheckPrice extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
//定时任务每天只查询昨天当天数据 触发节点每日凌晨
|
//定时任务每15min执行一次 只会查询15min内的订单数据
|
||||||
$yesterdayStartTime = Carbon::yesterday()->startOfDay()->toDateTimeString();
|
$startTime = Carbon::now()->subMinutes(15)->toDateTimeString();
|
||||||
$yesterdayEndTime = Carbon::yesterday()->endOfDay()->toDateTimeString();
|
$endTime = Carbon::now()->toDateTimeString();
|
||||||
|
|
||||||
//查询价格异常订单
|
//查询价格异常订单
|
||||||
$results = DB::table('business_order_items as a')
|
$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')
|
, 'b.cost','a.created_at','a.business_order_id')
|
||||||
->leftJoin('goods_skus as b', 'a.external_sku_id', '=', 'b.external_sku_id')
|
->leftJoin('goods_skus as b', 'a.external_sku_id', '=', 'b.external_sku_id')
|
||||||
->leftJoin('goods as c', 'b.goods_id', '=', 'c.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')
|
->havingRaw('goods_price < cost')
|
||||||
->get();
|
->get();
|
||||||
if($results->isNotEmpty()){
|
if($results->isNotEmpty()){
|
||||||
Log::info($yesterdayStartTime.'异常订单',$results->toArray());
|
Log::info($startTime.'异常订单',$results->toArray());
|
||||||
$messageService = new MessageService();
|
$messageService = new MessageService();
|
||||||
foreach ($results as $v){
|
foreach ($results as $v){
|
||||||
$messageService->createPriceExceptionMessage($v->business_order_id,
|
$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;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Console\Commands\CheckPrice;
|
use App\Console\Commands\CheckPrice;
|
||||||
|
use App\Console\Commands\CheckSkuQualityPeriod;
|
||||||
use App\Console\Commands\DailySalesReport;
|
use App\Console\Commands\DailySalesReport;
|
||||||
use App\Console\Commands\GoodsSkuDailyReport;
|
use App\Console\Commands\GoodsSkuDailyReport;
|
||||||
use App\Console\Commands\Inventory;
|
use App\Console\Commands\Inventory;
|
||||||
@ -47,7 +48,9 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$schedule->command(DeleteKttQuery::class)->daily();
|
$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 $businessGoodSku;
|
||||||
public $num;
|
public $num;
|
||||||
public $goodsSku;
|
public $goodsSku;
|
||||||
|
public $type = "BusinessOrdersUpdate";
|
||||||
|
|
||||||
public $combinationGoodsUpdate = true;
|
public $combinationGoodsUpdate = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +55,7 @@ class BusinessOrdersUpdate
|
|||||||
|
|
||||||
$this->goodsSku->sale_stock = $saleStock;
|
$this->goodsSku->sale_stock = $saleStock;
|
||||||
$this->goodsSku->stock = $stock;
|
$this->goodsSku->stock = $stock;
|
||||||
Log::info("sku 业务订单库存更新",(array)$this->goodsSku);
|
Log::info("sku 业务订单库存更新", (array)$this->goodsSku);
|
||||||
$this->goodsSku->save();
|
$this->goodsSku->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,23 +34,13 @@ class StockUpdateEvent
|
|||||||
private function checkStatusAndStock($goodsSku)
|
private function checkStatusAndStock($goodsSku)
|
||||||
{
|
{
|
||||||
//新版上下架和真实库存无关
|
//新版上下架和真实库存无关
|
||||||
$stock = $goodsSku->sale_stock;
|
|
||||||
if (0 >= $goodsSku->sale_stock) {
|
if (0 >= $goodsSku->sale_stock) {
|
||||||
$status = GoodsSku::$STATUS_DOWN;
|
$status = GoodsSku::$STATUS_DOWN;
|
||||||
} else {
|
} else {
|
||||||
$status = GoodsSku::$STATUS_ON_SALE;
|
$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->status = $status;
|
||||||
$goodsSku->stock = $stock;
|
|
||||||
$goodsSku->save();
|
$goodsSku->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -273,8 +273,7 @@ class GoodsSkusController extends Controller
|
|||||||
$log = new LogModel();
|
$log = new LogModel();
|
||||||
$log->batchInsert($logs);
|
$log->batchInsert($logs);
|
||||||
DB::commit();
|
DB::commit();
|
||||||
// 批量更新
|
|
||||||
event(new BatchStockUpdateEvent(array_column($request->skus, 'id')));
|
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
$this->res = [
|
$this->res = [
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use App\Imports\LossImport;
|
|||||||
use App\Imports\NewSetImport;
|
use App\Imports\NewSetImport;
|
||||||
use App\Imports\PurchaseImport;
|
use App\Imports\PurchaseImport;
|
||||||
use App\Models\BusinessOrderItem;
|
use App\Models\BusinessOrderItem;
|
||||||
|
use App\Models\CombinationGood;
|
||||||
use App\Models\DailySalesReport;
|
use App\Models\DailySalesReport;
|
||||||
use App\Models\DeveloperConfig;
|
use App\Models\DeveloperConfig;
|
||||||
use App\Models\Goods;
|
use App\Models\Goods;
|
||||||
@ -22,6 +23,8 @@ use App\Models\Log;
|
|||||||
use App\Models\Log as LogModel;
|
use App\Models\Log as LogModel;
|
||||||
use App\Models\LossRecords;
|
use App\Models\LossRecords;
|
||||||
use App\Models\PurchaseRecords;
|
use App\Models\PurchaseRecords;
|
||||||
|
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||||
|
use App\Services\GoodSku\GoodSkuService;
|
||||||
use App\Utils\ArrayUtils;
|
use App\Utils\ArrayUtils;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@ -161,6 +164,7 @@ class WareHouseSkusController extends Controller
|
|||||||
}
|
}
|
||||||
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
|
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
|
||||||
$updateIds = [];
|
$updateIds = [];
|
||||||
|
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||||
//开始保存数据
|
//开始保存数据
|
||||||
foreach ($purchaseOrders as $v) {
|
foreach ($purchaseOrders as $v) {
|
||||||
$goodsSkuItem = $goodsSkuMap[$v['external_sku_id']];
|
$goodsSkuItem = $goodsSkuMap[$v['external_sku_id']];
|
||||||
@ -173,20 +177,13 @@ class WareHouseSkusController extends Controller
|
|||||||
$purchaseRecords->buyer_name = $v['buyer_name'] ?? '';
|
$purchaseRecords->buyer_name = $v['buyer_name'] ?? '';
|
||||||
$purchaseRecords->supplier_name = $v['supplier_name'] ?? '';
|
$purchaseRecords->supplier_name = $v['supplier_name'] ?? '';
|
||||||
$purchaseRecords->supplier_id = $v['supplier_id'] ?? 0;
|
$purchaseRecords->supplier_id = $v['supplier_id'] ?? 0;
|
||||||
|
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||||
$purchaseRecords->save();
|
$purchaseRecords->save();
|
||||||
|
|
||||||
//更新库存
|
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem,$v);
|
||||||
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'];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//如果是組合商品後續會處理组合商品库存的拆分
|
//如果是組合商品会触发重算逻辑
|
||||||
event(new BatchStockUpdateEvent($updateIds));
|
event(new BatchStockUpdateEvent($updateIds));
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
@ -254,17 +251,10 @@ class WareHouseSkusController extends Controller
|
|||||||
$lossRecords->reason = $v['reason'] ?? '';
|
$lossRecords->reason = $v['reason'] ?? '';
|
||||||
$lossRecords->save();
|
$lossRecords->save();
|
||||||
|
|
||||||
//更新库存
|
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem,['num'=>0-$v['num'],"cost"=>$v['cost']]);
|
||||||
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'];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//如果是組合商品後續會處理组合商品库存的拆分
|
|
||||||
event(new BatchStockUpdateEvent($updateIds));
|
event(new BatchStockUpdateEvent($updateIds));
|
||||||
return response($this->res, $this->res['httpCode']);
|
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;
|
namespace App\Http\Service;
|
||||||
|
|
||||||
|
use App\Http\Enum\Message\MessageTypeEnum;
|
||||||
use App\Models\WebsiteMessages;
|
use App\Models\WebsiteMessages;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class MessageService
|
class MessageService
|
||||||
{
|
{
|
||||||
public function createPriceExceptionMessage(string $businessOrderId
|
//值为角色ids
|
||||||
,string $productName,string $skuName,string $goodsPrice,string $cost){
|
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['title'] = "订单价格异常告警";
|
||||||
$arr['role_id'] = 9;
|
$arr['role_id'] = $v;
|
||||||
$arr['content'] = Carbon::yesterday()->format('Y-m-d')."订单号:{$businessOrderId}-商品{$productName}
|
$arr['unique_key'] = $date."-".$businessOrderId;
|
||||||
|
$arr['type'] = MessageTypeEnum::PRICE_EXCEPTION_NOTICE;
|
||||||
|
$arr['content'] = $date . "订单号:{$businessOrderId}-商品{$productName}
|
||||||
规格{$skuName}价格有异常,当前售价{$goodsPrice}/支,当前成本价{$cost}/支";
|
规格{$skuName}价格有异常,当前售价{$goodsPrice}/支,当前成本价{$cost}/支";
|
||||||
$arr['created_at'] = Carbon::now()->toDateTimeString();
|
$this->saveWebsiteMessages($arr);
|
||||||
$arr['updated_at'] = Carbon::now()->toDateTimeString();
|
|
||||||
return WebsiteMessages::insert($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\GoodsSku;
|
||||||
use App\Models\LossRecords;
|
use App\Models\LossRecords;
|
||||||
use App\Models\PurchaseRecords;
|
use App\Models\PurchaseRecords;
|
||||||
|
use App\Services\GoodSku\GoodSkuService;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -54,15 +55,7 @@ class LossImport implements ToArray, SkipsEmptyRows
|
|||||||
$lossRecords->reason = $row[5] ?? '';
|
$lossRecords->reason = $row[5] ?? '';
|
||||||
$lossRecords->save();
|
$lossRecords->save();
|
||||||
|
|
||||||
//更新库存
|
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => 0 - $row[2], 'cost' => $row[3]]);
|
||||||
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'];
|
|
||||||
}
|
}
|
||||||
Log::info("报损导入内容:", $collection);
|
Log::info("报损导入内容:", $collection);
|
||||||
// 批量更新
|
// 批量更新
|
||||||
|
|||||||
@ -7,7 +7,10 @@ use App\Jobs\SyncCostToMiaoXuan;
|
|||||||
use App\Models\DailyStockRecord;
|
use App\Models\DailyStockRecord;
|
||||||
use App\Models\GoodsSku;
|
use App\Models\GoodsSku;
|
||||||
use App\Models\PurchaseRecords;
|
use App\Models\PurchaseRecords;
|
||||||
|
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||||
|
use App\Services\GoodSku\GoodSkuService;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||||
@ -36,6 +39,7 @@ class PurchaseImport implements ToArray, SkipsEmptyRows
|
|||||||
->get(['id', 'status', 'external_sku_id', 'stock'])
|
->get(['id', 'status', 'external_sku_id', 'stock'])
|
||||||
->toArray();
|
->toArray();
|
||||||
$hasGoodsSkus = ArrayUtils::index($hasGoodsSkus, 'external_sku_id');
|
$hasGoodsSkus = ArrayUtils::index($hasGoodsSkus, 'external_sku_id');
|
||||||
|
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||||
//excel字段排序 編碼 商品名稱 导购數量 成本价 采购人名称 供应商名称
|
//excel字段排序 編碼 商品名稱 导购數量 成本价 采购人名称 供应商名称
|
||||||
foreach ($collection as $row) {
|
foreach ($collection as $row) {
|
||||||
if (!isset($hasGoodsSkus[$row[0]])) {
|
if (!isset($hasGoodsSkus[$row[0]])) {
|
||||||
@ -51,17 +55,10 @@ class PurchaseImport implements ToArray, SkipsEmptyRows
|
|||||||
$purchaseRecords->cost = $row[3];
|
$purchaseRecords->cost = $row[3];
|
||||||
$purchaseRecords->buyer_name = $row[4] ?? '';
|
$purchaseRecords->buyer_name = $row[4] ?? '';
|
||||||
$purchaseRecords->supplier_name = $row[5] ?? '';
|
$purchaseRecords->supplier_name = $row[5] ?? '';
|
||||||
|
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||||
$purchaseRecords->save();
|
$purchaseRecords->save();
|
||||||
|
|
||||||
//更新库存
|
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem,["num"=>$row[2],'cost'=>$row[3]]);
|
||||||
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'];
|
|
||||||
}
|
}
|
||||||
Log::info("采购导入内容:",$collection);
|
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()
|
$combinationGoods = CombinationGood::query()
|
||||||
->with('goodsSku:id,stock')
|
->with('goodsSku:id,stock')
|
||||||
->whereIn('goods_sku_id', $combinationGoodsIds)
|
->whereIn('goods_sku_id', $combinationGoodsIds)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use App\Events\StockUpdateEvent;
|
|||||||
use App\Events\GroupSetEvent;
|
use App\Events\GroupSetEvent;
|
||||||
use App\Events\BatchStockUpdateEvent;
|
use App\Events\BatchStockUpdateEvent;
|
||||||
use App\Listeners\BatchStockUpdateListener;
|
use App\Listeners\BatchStockUpdateListener;
|
||||||
|
use App\Listeners\BusinessOrderUpdateListener;
|
||||||
use App\Listeners\CreateLogisticListener;
|
use App\Listeners\CreateLogisticListener;
|
||||||
use App\Listeners\GroupQueryListener;
|
use App\Listeners\GroupQueryListener;
|
||||||
use App\Listeners\StockUpdateListener;
|
use App\Listeners\StockUpdateListener;
|
||||||
@ -28,6 +29,7 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
BusinessOrdersUpdate::class => [
|
BusinessOrdersUpdate::class => [
|
||||||
UpdateBusinessGoodsStock::class,
|
UpdateBusinessGoodsStock::class,
|
||||||
CombinationGoodsStockUpdateListener::class,
|
CombinationGoodsStockUpdateListener::class,
|
||||||
|
BusinessOrderUpdateListener::class
|
||||||
],
|
],
|
||||||
BatchStockUpdateEvent::class => [
|
BatchStockUpdateEvent::class => [
|
||||||
BatchStockUpdateListener::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;
|
namespace App\Services\GoodSku;
|
||||||
|
|
||||||
use App\Events\BatchStockUpdateEvent;
|
use App\Events\BatchStockUpdateEvent;
|
||||||
use App\Events\CreateLogisticEvent;
|
use App\Models\CombinationGood;
|
||||||
use App\Models\BusinessOrderItem;
|
|
||||||
use App\Models\DailyStockRecord;
|
use App\Models\DailyStockRecord;
|
||||||
use App\Models\GoodsSku;
|
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 App\Utils\DateTimeUtils;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class GoodSkuService
|
class GoodSkuService
|
||||||
{
|
{
|
||||||
@ -43,7 +36,7 @@ class GoodSkuService
|
|||||||
$record->save();
|
$record->save();
|
||||||
//查询sku当前未发货的数量 目前数据看着有问题暂不操作
|
//查询sku当前未发货的数量 目前数据看着有问题暂不操作
|
||||||
|
|
||||||
//库存修改
|
//库存修改 盘点是直接覆盖所以这里加个锁
|
||||||
GoodsSku::query()->where('id', $sku['id'])->lockForUpdate()->update([
|
GoodsSku::query()->where('id', $sku['id'])->lockForUpdate()->update([
|
||||||
'stock' => $requestSkusMap[$sku['external_sku_id']]['inventory']
|
'stock' => $requestSkusMap[$sku['external_sku_id']]['inventory']
|
||||||
]);
|
]);
|
||||||
@ -51,7 +44,32 @@ class GoodSkuService
|
|||||||
}
|
}
|
||||||
// 批量更新
|
// 批量更新
|
||||||
event(new BatchStockUpdateEvent($updateIds));
|
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->unsignedDecimal('cost')->default(0)->comment('成本');
|
||||||
$table->string('buyer_name')->nullable()->comment('采购人');
|
$table->string('buyer_name')->nullable()->comment('采购人');
|
||||||
$table->string('status')->default(0)->comment('盘点完近似状态 0未完成1已售卖完成');
|
$table->string('status')->default(0)->comment('盘点完近似状态 0未完成1已售卖完成');
|
||||||
|
$table->string('expire_time')->nullable()->comment('保质期时间');
|
||||||
$table->string('supplier_name')->nullable()->comment('供应商名称');
|
$table->string('supplier_name')->nullable()->comment('供应商名称');
|
||||||
$table->Integer('supplier_id')->nullable()->comment('供应商id');
|
$table->Integer('supplier_id')->nullable()->comment('供应商id');
|
||||||
// 索引
|
// 索引
|
||||||
$table->index('sku_id');
|
$table->index('sku_id');
|
||||||
$table->index('external_sku_id');
|
$table->index('external_sku_id');
|
||||||
|
$table->index('status');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,12 +17,15 @@ class CreateWebsiteMessagesTable extends Migration
|
|||||||
$table->bigIncrements('id');
|
$table->bigIncrements('id');
|
||||||
$table->string('title')->comment('消息内容标题');
|
$table->string('title')->comment('消息内容标题');
|
||||||
$table->string('content')->comment('消息内容');
|
$table->string('content')->comment('消息内容');
|
||||||
|
$table->string('type')->comment('消息类型');
|
||||||
|
$table->string('unique_key')->comment('类型下唯一的key避免重复写入');
|
||||||
$table->string('role_id')->nullable()->comment('角色名称');
|
$table->string('role_id')->nullable()->comment('角色名称');
|
||||||
$table->Integer('uid')->nullable()->comment('用户id 存在非0值表示当前uid可见');
|
$table->Integer('uid')->nullable()->comment('用户id 存在非0值表示当前uid可见');
|
||||||
$table->tinyInteger('status')->default(0)->comment('消息状态 0未读 1已读');
|
$table->tinyInteger('status')->default(0)->comment('消息状态 0未读 1已读');
|
||||||
$table->string('extend')->nullable()->comment('拓展字段 后续拓展用');
|
$table->string('extend')->nullable()->comment('拓展字段 后续拓展用');
|
||||||
|
|
||||||
$table->index(["role_id","uid"]);
|
$table->index(["role_id","uid"]);
|
||||||
|
$table->unique(["type","unique_key"]);
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user