mirror of
https://gitee.com/hzchunfen/erp.git
synced 2025-12-01 06:30:49 +00:00
!240 鲜花2.0迭代
Merge pull request !240 from 杨建炊/fix-release-1.0.0/yjc-migrate
This commit is contained in:
commit
1bff0bf7e8
66
app/Console/Commands/CheckPrice.php
Normal file
66
app/Console/Commands/CheckPrice.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Http\Service\MessageService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
class CheckPrice extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'check:price';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '检查价格异常';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//定时任务每15min执行一次 只会查询15min内的订单数据
|
||||
$startTime = Carbon::now()->subMinutes(15)->toDateTimeString();
|
||||
$endTime = Carbon::now()->toDateTimeString();
|
||||
|
||||
//查询价格异常订单
|
||||
$results = DB::table('business_order_items as a')
|
||||
->select('b.name as cn_name', 'b.title as title', DB::raw('ROUND(a.goods_price / 100,2) AS goods_price')
|
||||
, 'b.cost','a.created_at','a.business_order_id')
|
||||
->leftJoin('goods_skus as b', 'a.external_sku_id', '=', 'b.external_sku_id')
|
||||
->whereBetween('a.created_at', [$startTime,$endTime])
|
||||
->whereRaw('a.goods_price / 100 < cost')
|
||||
->get();
|
||||
if($results->isNotEmpty()){
|
||||
Log::info($startTime.'异常订单',$results->toArray());
|
||||
$messageService = new MessageService();
|
||||
foreach ($results as $v){
|
||||
$messageService->createPriceExceptionMessage($v->business_order_id,
|
||||
$v->cn_name,$v->title,$v->goods_price,$v->cost);
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('任务完成:check-CheckPrice');
|
||||
}
|
||||
}
|
||||
80
app/Console/Commands/CheckSkuQualityPeriod.php
Normal file
80
app/Console/Commands/CheckSkuQualityPeriod.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?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", "b.id as sku_id", "b.external_sku_id")
|
||||
->leftJoin('goods_skus as b', 'a.sku_id', '=', 'b.id')
|
||||
->where("a.check_status", "=", 0)
|
||||
->whereBetween('a.expire_time', [$startTime, $endTime])->get();
|
||||
Log::info('purchaseRecords', (array)$purchaseRecords);
|
||||
if ($purchaseRecords->isNotEmpty()) {
|
||||
$messageService = new MessageService();
|
||||
$updateIds = [];
|
||||
foreach ($purchaseRecords as $v) {
|
||||
// 单独采购单后续总和小于库存表示该sku没有卖完
|
||||
$totalPurchaseNum = PurchaseRecords::query()->where('date', '>=', $v->date)
|
||||
->where('external_sku_id', "=", $v->external_sku_id)
|
||||
->where("status", 1)->sum('num');
|
||||
if ($totalPurchaseNum < $v->stock) {
|
||||
$messageService->skuQualityPeriodNoticeMessage((array)$v);
|
||||
}
|
||||
$updateIds[] = $v->id;
|
||||
//更新下状态
|
||||
|
||||
}
|
||||
PurchaseRecords::query()->whereIn('id', $updateIds)->update([
|
||||
"check_status" => 1
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
Log::info('任务完成:check-CheckSkuQualityPeriod');
|
||||
}
|
||||
}
|
||||
101
app/Console/Commands/DailyStockRecordReport.php
Normal file
101
app/Console/Commands/DailyStockRecordReport.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\DailyReport;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\LossRecords;
|
||||
use App\Models\PurchaseRecords;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DailyStockRecordReport extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'daily:report:stock_record {date?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '每日商品库存记录';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$date = $this->argument('date');
|
||||
if (is_null($date)) {
|
||||
$date = Carbon::yesterday()->format('Y-m-d');
|
||||
}
|
||||
$startDateTime = Carbon::parse($date)->startOfDay()->toDateTimeString();
|
||||
$endDateTime = Carbon::parse($date)->endOfDay()->toDateTimeString();
|
||||
//统计订单数量
|
||||
$orderItems = BusinessOrderItem::query()
|
||||
->leftJoin("business_orders as b", "business_order_id", "=", "b.id")
|
||||
->select("business_order_items.external_sku_id"
|
||||
, DB::raw("sum(goods_number-already_cancel_number) as goods_total")
|
||||
, DB::raw("ROUND(sum(goods_amount) / 100,2) as order_total_amount"))
|
||||
->where('b.confirm_at', '>=', Carbon::parse($startDateTime)->getPreciseTimestamp(3))
|
||||
->where('b.confirm_at', '<=', Carbon::parse($endDateTime)->getPreciseTimestamp(3))
|
||||
->where("business_order_items.cancel_status", "=", 0)
|
||||
->groupBy('external_sku_id')->get()->pluck(null, "external_sku_id")->toArray();
|
||||
|
||||
//统计采购单数量
|
||||
$purchaseRecords = PurchaseRecords::query()
|
||||
->select(DB::raw("sum(num) as arrived_today_num"), "external_sku_id")
|
||||
->whereBetween("check_time", [$startDateTime, $endDateTime])
|
||||
->where("status",1)
|
||||
->groupBy("external_sku_id")->get()->pluck(null, "external_sku_id")->toArray();
|
||||
//统计报损数量
|
||||
$lossRecords = LossRecords::query()
|
||||
->select(DB::raw("sum(num) as loss_num"), "external_sku_id")
|
||||
->whereBetween("created_at", [$startDateTime, $endDateTime])
|
||||
->groupBy("external_sku_id")->get()->pluck(null, "external_sku_id")->toArray();
|
||||
Log::info("{$date}每日库存记录", ["orderItems" => $orderItems
|
||||
, "purchaseRecords" => $purchaseRecords, "lossRecords" => $lossRecords]);
|
||||
$needUpdateExternalSkuIds = array_merge(array_keys($orderItems), array_keys($purchaseRecords), array_keys($lossRecords));
|
||||
//开始更新数据
|
||||
if (!empty($needUpdateExternalSkuIds)) {
|
||||
$needUpdateSkuIdsMap = GoodsSku::query()->whereIn("external_sku_id", $needUpdateExternalSkuIds)->pluck("external_sku_id", 'id')->toArray();
|
||||
|
||||
collect($needUpdateSkuIdsMap)->each(function ($externalSkuId,$skuId) use ($date, $orderItems, $purchaseRecords, $lossRecords) {
|
||||
$record = DailyStockRecord::query()->firstOrNew([
|
||||
'sku_id' => $skuId,
|
||||
'day' => $date,
|
||||
]);
|
||||
$record->arrived_today_num = !empty($purchaseRecords[$externalSkuId]["arrived_today_num"])
|
||||
? $purchaseRecords[$externalSkuId]["arrived_today_num"] : 0;
|
||||
$record->loss_num = !empty($lossRecords[$externalSkuId]["loss_num"])
|
||||
? $lossRecords[$externalSkuId]["loss_num"] : 0;
|
||||
$record->order_goods_num = !empty($orderItems[$externalSkuId]["goods_total"])
|
||||
? $orderItems[$externalSkuId]["goods_total"] : 0;
|
||||
$record->order_total_amount = !empty($orderItems[$externalSkuId]["order_total_amount"])
|
||||
? $orderItems[$externalSkuId]["order_total_amount"] : 0;
|
||||
$record->save();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
54
app/Console/Commands/InitSaleStock.php
Normal file
54
app/Console/Commands/InitSaleStock.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Http\Service\MessageService;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Services\Business\MiaoXuan\Goods;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
class InitSaleStock extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'init:sale_stock {ids?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '初始化在售库存';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$ids = $this->argument('ids');
|
||||
if(!empty($ids)){
|
||||
$ids = explode(',',$ids);
|
||||
}
|
||||
GoodsSku::query()->where("stock",'>',0)->when($ids,function($query)use($ids){
|
||||
$query->whereIn('id',$ids);
|
||||
})->update(['sale_stock' => DB::raw('stock')]);
|
||||
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
@ -41,19 +42,20 @@ class Inventory extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$log = new Log();
|
||||
$log->module = 'goods';
|
||||
$log->action = 'PATCH';
|
||||
$log->target_type = 'goods_sku';
|
||||
$log->target_id = 0;
|
||||
$log->target_field = 'timingInventory';
|
||||
$log->user_id = 999;
|
||||
// 数据库存储过程,7点定时执行
|
||||
$data = [];
|
||||
$date = date('Y-m-d');
|
||||
GoodsSku::query()->chunk(500, static function ($skus) use (&$data, $date) {
|
||||
|
||||
$log = new Log();
|
||||
$log->module = 'goods';
|
||||
$log->action = 'PATCH';
|
||||
$log->target_type = 'goods_sku';
|
||||
$log->target_id = 0;
|
||||
$log->target_field = 'timingInventory';
|
||||
$log->user_id = 999;
|
||||
// 数据库存储过程,7点定时执行
|
||||
$data = [];
|
||||
$date = date('Y-m-d');
|
||||
GoodsSku::query()->chunk(500, static function ($skus) use (&$data, $date, $log) {
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
foreach ($skus as $sku) {
|
||||
$data[] = [
|
||||
'sku_id' => $sku->id,
|
||||
@ -64,15 +66,16 @@ class Inventory extends Command
|
||||
'two_days_ago_num' => $sku->two_days_ago_num + $sku->yesterday_num,
|
||||
]);
|
||||
}
|
||||
});
|
||||
$record = new DailyStockRecord();
|
||||
$record->batchInsert($data);
|
||||
DB::commit();
|
||||
$log->message = '7点数据更新成功';
|
||||
} catch (\Exception $exception) {
|
||||
$log->message = '7点数据更新失败' . $exception->getMessage();
|
||||
DB::rollBack();
|
||||
}
|
||||
$record = new DailyStockRecord();
|
||||
$record->batchInsert($data);
|
||||
DB::commit();
|
||||
$log->message = '7点数据更新成功';
|
||||
} catch (\Exception $exception) {
|
||||
$log->message = '7点数据更新失败' . $exception->getMessage();
|
||||
DB::rollBack();
|
||||
}
|
||||
|
||||
});
|
||||
$log->save();
|
||||
$this->info($log->message);
|
||||
}
|
||||
|
||||
53
app/Console/Commands/KttOrderAfterSaleQuery.php
Normal file
53
app/Console/Commands/KttOrderAfterSaleQuery.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Shop;
|
||||
use App\Services\Business\BusinessFactory;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class KttOrderAfterSaleQuery extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ktt:after_sale_order_query';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '快团团根据成交时间拉取快团团增量售后单';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$shops = Shop::query()->where('plat_id', Shop::$PLAT_KTT)->where('status', Shop::$STATUS_AUTHORIZED)->get();
|
||||
$endTime = DateTimeUtils::getMicroTime();
|
||||
$beginTime = $endTime - (15 * 60 * 1000)-1000;//售后单每15min查询一次 多查询一秒
|
||||
foreach ($shops as $shop) {
|
||||
BusinessFactory::init()->make($shop->plat_id)->setShop($shop)->downloadAfterSaleOrdersAndSave($beginTime, $endTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ use App\Models\Shop;
|
||||
use App\Services\Business\BusinessFactory;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class KttOrderQuery extends Command
|
||||
{
|
||||
|
||||
@ -2,9 +2,12 @@
|
||||
|
||||
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;
|
||||
use App\Console\Commands\KttOrderAfterSaleQuery;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use App\Console\Commands\KttOrderQuery;
|
||||
@ -45,6 +48,15 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->command(DailySalesReport::class, ['S7'])->dailyAt('09:30');
|
||||
|
||||
$schedule->command(DeleteKttQuery::class)->daily();
|
||||
//新增价格校验
|
||||
$schedule->command(CheckPrice::class)->everyFifteenMinutes();
|
||||
//保质期
|
||||
$schedule->command(CheckSkuQualityPeriod::class)->dailyAt('05:30');
|
||||
//快团团售后单拉取
|
||||
$schedule->command(KttOrderAfterSaleQuery::class)->everyFifteenMinutes();
|
||||
//同步售卖信息和报损相关数据
|
||||
$schedule->command(GoodsSkuDailyReport::class)->dailyAt('03:30');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -10,6 +10,7 @@ use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BatchStockUpdateEvent
|
||||
{
|
||||
|
||||
@ -21,6 +21,8 @@ class BusinessOrdersUpdate
|
||||
public $businessGoodSku;
|
||||
public $num;
|
||||
public $goodsSku;
|
||||
public $type = "BusinessOrdersUpdate";
|
||||
|
||||
public $combinationGoodsUpdate = true;
|
||||
|
||||
/**
|
||||
@ -30,39 +32,50 @@ class BusinessOrdersUpdate
|
||||
*/
|
||||
public function __construct($businessGoodSku, $num)
|
||||
{
|
||||
$this->businessGoodSku = $businessGoodSku->toArray();
|
||||
$this->num = $num;
|
||||
$this->updateStock();
|
||||
try {
|
||||
$this->businessGoodSku = $businessGoodSku->toArray();
|
||||
$this->num = $num;
|
||||
$updateResult = false;
|
||||
//暂时设定重试3次
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
if ($this->updateStock()) {
|
||||
$updateResult = true;
|
||||
break;
|
||||
}
|
||||
usleep(140);
|
||||
}
|
||||
if (!$updateResult) {
|
||||
Log::error("sku 业务更新失败", (array)$this->businessGoodSku);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
Log::error("sku 业务更新发生异常", ["error" => $exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function updateStock()
|
||||
{
|
||||
$this->goodsSku = GoodsSku::query()
|
||||
->where('external_sku_id', $this->businessGoodSku['external_sku_id'])
|
||||
->first();
|
||||
if (is_null($this->goodsSku)) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
$oldStock = $this->goodsSku->stock;
|
||||
$stock = $this->goodsSku->stock + $this->num;
|
||||
|
||||
if (0 >= $stock) {
|
||||
$this->goodsSku->status = GoodsSku::$STATUS_DOWN;
|
||||
$saleStock = $this->goodsSku->sale_stock + $this->num;
|
||||
$saleStock = ($saleStock > 0) ? $saleStock : 0;
|
||||
$updateParam = ["stock" => $stock, "sale_stock" => $saleStock];
|
||||
if (0 >= $saleStock) {
|
||||
$updateParam['status'] = GoodsSku::$STATUS_DOWN;
|
||||
} else {
|
||||
$this->goodsSku->status = GoodsSku::$STATUS_ON_SALE;
|
||||
$updateParam['status'] = GoodsSku::$STATUS_ON_SALE;
|
||||
}
|
||||
|
||||
// 今日到货 + 1T 大于20,且当前剩余库存小于4时 直接下架
|
||||
$arrivedTodayNum = DailyStockRecord::query()
|
||||
->where('day', DateTimeUtils::getToday())
|
||||
->where('sku_id', $this->goodsSku->id)
|
||||
->value('arrived_today_num');
|
||||
if (20 < $arrivedTodayNum + $this->goodsSku->yesterday_num && 4 > $stock) {
|
||||
$this->goodsSku->status = GoodsSku::$STATUS_DOWN;
|
||||
$stock = 0;
|
||||
}
|
||||
|
||||
$this->goodsSku->stock = $stock;
|
||||
$this->goodsSku->save();
|
||||
Log::info("sku 业务订单库存更:{$this->goodsSku->id}", $updateParam);
|
||||
//乐观锁更新
|
||||
return GoodsSku::query()->where('external_sku_id', $this->businessGoodSku['external_sku_id'])->
|
||||
where("stock", "=", $oldStock)->update($updateParam);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -33,22 +33,14 @@ class StockUpdateEvent
|
||||
|
||||
private function checkStatusAndStock($goodsSku)
|
||||
{
|
||||
$stock = $goodsSku->stock;
|
||||
if (0 >= $goodsSku->stock) {
|
||||
//新版上下架和真实库存无关
|
||||
if (0 >= $goodsSku->sale_stock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
} else {
|
||||
$status = GoodsSku::$STATUS_ON_SALE;
|
||||
}
|
||||
$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();
|
||||
}
|
||||
|
||||
|
||||
63
app/Exports/BusinessAfterOrderExport.php
Normal file
63
app/Exports/BusinessAfterOrderExport.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Http\Enum\AfterSaleOrderStatusEnum;
|
||||
use App\Models\DailyReport;
|
||||
use App\Models\Shop;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class BusinessAfterOrderExport implements FromCollection, ShouldAutoSize
|
||||
{
|
||||
private $data;
|
||||
|
||||
public function __construct($orders)
|
||||
{
|
||||
$this->data = $this->createData($orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function collection()
|
||||
{
|
||||
return new Collection($this->data);
|
||||
}
|
||||
|
||||
|
||||
private function createData($orders)
|
||||
{
|
||||
$headTitle = [
|
||||
'父订单编号',
|
||||
'店铺名称',
|
||||
'退款金额',
|
||||
'用户申请退运费金额',
|
||||
'退款原因',
|
||||
'描述',
|
||||
'申请类型',
|
||||
'售后单状态',
|
||||
'售后单创建时间',
|
||||
'图片链接',
|
||||
];
|
||||
$bodyData = [];
|
||||
foreach ($orders as $order) {
|
||||
$bodyData[] = [
|
||||
$order['order_sn'],
|
||||
$order['shop']['name'],
|
||||
bcdiv($order['refund_amount'], 100, 2),
|
||||
bcdiv($order['refund_shipping_amount'], 100, 2),
|
||||
$order['reason'],
|
||||
$order['description'],
|
||||
empty($order['apply_type']) ? "仅退款" : "退货退款",
|
||||
AfterSaleOrderStatusEnum::getData($order['after_sales_status']),
|
||||
$order['after_sale_created_at'],
|
||||
implode(",", $order['image_list'])
|
||||
];
|
||||
}
|
||||
|
||||
return [$headTitle, $bodyData];
|
||||
}
|
||||
}
|
||||
68
app/Exports/BusinessOrderExport.php
Normal file
68
app/Exports/BusinessOrderExport.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\DailyReport;
|
||||
use App\Models\Shop;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Illuminate\Support\Collection;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class BusinessOrderExport implements FromCollection, ShouldAutoSize
|
||||
{
|
||||
private $data;
|
||||
|
||||
public function __construct($orders)
|
||||
{
|
||||
$this->data = $this->createData($orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function collection()
|
||||
{
|
||||
return new Collection($this->data);
|
||||
}
|
||||
|
||||
|
||||
private function createData($orders)
|
||||
{
|
||||
$headTitle = [
|
||||
'订单id/编号',
|
||||
'商品信息|个数',
|
||||
'店铺名称',
|
||||
'跟团号',
|
||||
'收件人',
|
||||
'收件地址',
|
||||
'下单时间',
|
||||
'发货状态',
|
||||
'订单状态',
|
||||
'售后状态',
|
||||
];
|
||||
$bodyData = [];
|
||||
foreach ($orders as $order) {
|
||||
$productInfo = "";
|
||||
foreach ($order['items'] as $item) {
|
||||
$productInfo .= $item['goods_name']. "|" . $item['goods_number'] . ",";
|
||||
}
|
||||
rtrim($productInfo, ",");
|
||||
$bodyData[] = [
|
||||
$order['id'] . "/" . $order['order_sn'],
|
||||
$productInfo,
|
||||
$order['shop']['name'],
|
||||
$order['is_supplier'].":".$order['participate_no'],
|
||||
$order['receiver_name'],
|
||||
$order['receiver_address_province']." ". $order['receiver_address_city']." ".$order['receiver_address_district']." ".$order['receiver_address_detail'],
|
||||
$order['confirm_at'],
|
||||
$order['shipping_status'],
|
||||
$order['cancel_status'],
|
||||
$order['after_sales_status']
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
return [$headTitle, $bodyData];
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,11 @@
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Http\Enum\TargetTypeEnum;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\Goods;
|
||||
use App\Models\Log;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Utils\ArrayUtils;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
@ -35,56 +38,70 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
|
||||
$headTitle = [
|
||||
'商品编码',
|
||||
'商品名称',
|
||||
'商品种类',
|
||||
'商品品牌',
|
||||
'规格编码',
|
||||
'规格名称',
|
||||
'可售库存',
|
||||
'创建时间',
|
||||
];
|
||||
$map = [
|
||||
'cost' => ['成本', '更新前成本', '更新后成本'],
|
||||
'inventory' => ['库存', '盘点', '上新'],
|
||||
'cost' => ['当前成本', '更新前成本', "更新后成本"],
|
||||
'inventory' => ['当前库存', '盘点数', '采购总数'],
|
||||
];
|
||||
$headTitle = array_merge($headTitle, $map[$this->type]);
|
||||
$headTitle = array_merge($headTitle, $map[$this->type] ?? []);
|
||||
if ('cost' === $this->type) {
|
||||
$update = $this->getChangeCostLogs();
|
||||
}
|
||||
if ('inventory' === $this->type) {
|
||||
$update = $this->getInventoryRecord();
|
||||
}
|
||||
$ids = array_keys($update);
|
||||
if (empty($ids)) {
|
||||
return [$headTitle];
|
||||
}
|
||||
$model = GoodsSku::query()
|
||||
->when($ids, function ($query, $ids) {
|
||||
return $query->whereIn('id', $ids);
|
||||
})
|
||||
->with(['goods' => function ($query) {
|
||||
$query->with(['type:id,name', 'brand:id,name'])
|
||||
->orderBy('type_id')
|
||||
->orderBy('brand_id');
|
||||
}]);
|
||||
$data = $model->get()->toArray();
|
||||
if (empty($data)) {
|
||||
return [$headTitle];
|
||||
if ($this->type === "goods_sku" || $this->type === "goods_combination") {
|
||||
$builder = GoodsSku::query();
|
||||
if (request()->get('type_id')) {
|
||||
$goodsIds = Goods::query()->filter()->pluck('id')->toArray();
|
||||
$builder->whereIn('goods_id', $goodsIds);
|
||||
}
|
||||
if (request()->get('goods_title')) {
|
||||
$builder->where('name', 'like', '%' . request()->get('goods_title') . '%');
|
||||
}
|
||||
if ($this->type === "goods_combination") {
|
||||
$builder->where('is_combination', 1);
|
||||
} else {
|
||||
$builder->where('is_combination', 0);
|
||||
}
|
||||
$data = $builder->filter()->orderByDesc('id')->get()->toArray();
|
||||
} else {
|
||||
$ids = array_keys($update);
|
||||
if (empty($ids)) {
|
||||
return [$headTitle];
|
||||
}
|
||||
$model = GoodsSku::query()
|
||||
->when($ids, function ($query, $ids) {
|
||||
return $query->whereIn('id', $ids);
|
||||
})
|
||||
->with(['goods' => function ($query) {
|
||||
$query->with(['type:id,name', 'brand:id,name'])
|
||||
->orderBy('type_id')
|
||||
->orderBy('brand_id');
|
||||
}]);
|
||||
$data = $model->get()->toArray();
|
||||
if (empty($data)) {
|
||||
return [$headTitle];
|
||||
}
|
||||
}
|
||||
|
||||
$bodyData = [];
|
||||
foreach ($data as $item) {
|
||||
$arr[0] = $item['goods']['goods_code'];
|
||||
$arr[1] = $item['goods']['title'];
|
||||
$arr[2] = $item['goods']['type']['name'];
|
||||
$arr[3] = $item['goods']['brand']['name'];
|
||||
$arr[4] = $item['sku_code'];
|
||||
$arr[5] = $item['title'];
|
||||
$arr[0] = $item['external_sku_id'];
|
||||
$arr[1] = $item['name'];
|
||||
$arr[2] = $item['sale_stock'] ?? 0;
|
||||
$arr[3] = $item['created_at'];
|
||||
if ('cost' === $this->type) {
|
||||
$arr[6] = (string)$item['cost'];
|
||||
$arr[7] = (string)$update[$item['id']]['before_update'];
|
||||
$arr[8] = (string)$update[$item['id']]['after_update'];
|
||||
$arr[4] = (string)$item['cost'];
|
||||
$arr[5] = (string)$update[$item['id']]['before_update'];
|
||||
$arr[6] = (string)$update[$item['id']]['after_update'];
|
||||
}
|
||||
if ('inventory' === $this->type) {
|
||||
$arr[6] = (string)$item['stock'];
|
||||
$arr[7] = (string)$update[$item['id']]['inventory'];
|
||||
$arr[8] = (string)$update[$item['id']]['arrived_today_num'];
|
||||
$arr[4] = (string)$item['stock'];
|
||||
$arr[5] = (string)$update[$item['id']]['inventory'];
|
||||
$arr[6] = (string)$update[$item['id']]['arrived_today_num'];
|
||||
}
|
||||
$bodyData[] = $arr;
|
||||
}
|
||||
@ -97,18 +114,23 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
|
||||
$day = DateTimeUtils::getToday();
|
||||
$logs = Log::query()
|
||||
->select(['target_id', 'before_update', 'after_update'])
|
||||
->where('target_type', 'goods_sku')
|
||||
->where('target_field', 'cost')
|
||||
->where('target_type', TargetTypeEnum::PURCHASE)
|
||||
->where('target_field', 'stock')
|
||||
->where('created_at', '>', $day)
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
|
||||
$update = [];
|
||||
foreach ($logs as $log) {
|
||||
if ($log['before_update'] !== $log['after_update'] || (int)$log['after_update']) {
|
||||
if (!isset($update[$log['target_id']])) {
|
||||
$update[$log['target_id']]['before_update'] = $log['before_update'];
|
||||
if (!isset($update[$log['target_id']])) {
|
||||
$beforeData = json_decode($log['before_update'], true);
|
||||
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'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,9 +33,8 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
||||
{
|
||||
$headTitle = [
|
||||
'商品名称',
|
||||
'品类',
|
||||
'规格',
|
||||
'品牌',
|
||||
'品种',
|
||||
'规格名称',
|
||||
'商品编码',
|
||||
'成本',
|
||||
'销售数量',
|
||||
@ -51,8 +50,7 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
||||
->with([
|
||||
'goods:id,title',
|
||||
'goodsType:id,name',
|
||||
'goodsSku:id,title',
|
||||
'goodsBrand:id,name',
|
||||
'goodsSku:id,title,name'
|
||||
])
|
||||
->where('date', '>=', $this->startDate)
|
||||
->where('date', '<=', $this->endDate)
|
||||
@ -66,10 +64,9 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
||||
$number = $item->total_goods_number - $item->total_cancel_number;
|
||||
if (!isset($arr[$item->external_sku_id])) {
|
||||
$arr[$item->external_sku_id] = [
|
||||
'goodsTitle' => $item->goods->title,
|
||||
'goodsTypeName' => $item->goodsType->name,
|
||||
'goodsSkuTitle' => $item->goodsSku->title,
|
||||
'goodsBrandName' => $item->goodsBrand->name,
|
||||
'goodsTitle' => !empty($item->goodsSku) ? $item->goodsSku->name:'',
|
||||
'goodsTypeName' => !empty($item->goodsType) ? $item->goodsType->name : "",
|
||||
'goodsSkuTitle' => !empty($item->goodsSku) ? $item->goodsSku->title : "",
|
||||
'external_sku_id' => $item->external_sku_id,
|
||||
'cost' => [],
|
||||
'number' => [],
|
||||
@ -97,7 +94,6 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
||||
$item['goodsTitle'],
|
||||
$item['goodsTypeName'],
|
||||
$item['goodsSkuTitle'],
|
||||
$item['goodsBrandName'],
|
||||
$item['external_sku_id'],
|
||||
$cost,
|
||||
array_sum($item['number']),
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class GoodsSkuFilter extends Filters
|
||||
{
|
||||
protected function skuTitle($value)
|
||||
@ -28,4 +30,16 @@ class GoodsSkuFilter extends Filters
|
||||
{
|
||||
return $this->builder->where('is_combination', $value);
|
||||
}
|
||||
|
||||
protected function createTimeStart($value)
|
||||
{
|
||||
|
||||
return $this->builder->where('created_at', ">=", $value);
|
||||
}
|
||||
|
||||
protected function createTimeEnd($value)
|
||||
{
|
||||
$end = Carbon::parse($value)->endOfDay()->toDateTimeString();
|
||||
return $this->builder->where('created_at', "<=", $end);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Business;
|
||||
|
||||
use App\Exports\BusinessAfterOrderExport;
|
||||
use App\Exports\BusinessOrderExport;
|
||||
use App\Exports\OrderBlankExport;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\BusinessAfterSaleOrder;
|
||||
use App\Models\BusinessOrder;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Shop;
|
||||
use App\Services\Ship\WayBillService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Resources\BusinessOrderResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class BusinessAfterSaleOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$shopIds = Shop::query()
|
||||
->where('plat_id', Shop::$PLAT_KTT)
|
||||
->pluck('id');
|
||||
$builder = BusinessAfterSaleOrder::query()
|
||||
->with(["shop:id,name"])
|
||||
->whereIn('shop_id', $shopIds)
|
||||
->filter();
|
||||
if (!empty($request->created_at_start) & !empty($request->created_at_end)) {
|
||||
$builder = $builder->whereBetween("after_sale_created_at"
|
||||
, [$request->created_at_start, $request->created_at_end]);
|
||||
}
|
||||
|
||||
if ($request->get("is_export")) {
|
||||
$params = $request->validate([
|
||||
'created_at_start' => 'required',
|
||||
'created_at_end' => 'required',
|
||||
], [
|
||||
'created_at_start.required' => '请输入开始确认时间',
|
||||
'created_at_end.required' => '请输入结束确认时间',
|
||||
]);
|
||||
$startDate = Carbon::parse($params['created_at_start']);
|
||||
$endDate = Carbon::parse($params['created_at_end']);
|
||||
|
||||
if ($endDate->gt($startDate->copy()->addMonth())) {
|
||||
throw new \Exception("导出时间超出一个月");
|
||||
}
|
||||
|
||||
return Excel::download(new BusinessAfterOrderExport($builder->get()->toArray())
|
||||
, $startDate . '~' . $endDate . "售后订单数据" . '.xlsx');
|
||||
}
|
||||
$businessOrders = $builder->orderByDesc('after_sale_created_at')
|
||||
->paginate($request->get('per_page'));
|
||||
$businessOrders->getCollection()->map(function ($v) {
|
||||
$v->refund_amount = bcdiv($v->refund_amount,100,2);
|
||||
$v->refund_shipping_amount = bcdiv($v->refund_shipping_amount,100,2);
|
||||
});
|
||||
|
||||
return JsonResource::collection($businessOrders);
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Business;
|
||||
|
||||
use App\Exports\BusinessOrderExport;
|
||||
use App\Exports\OrderBlankExport;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\BusinessOrder;
|
||||
@ -35,6 +36,24 @@ class BusinessOrderController extends Controller
|
||||
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
|
||||
$builder->whereIn('id', $ids);
|
||||
}
|
||||
|
||||
if($request->get("is_export")){
|
||||
$params = $request->validate([
|
||||
'confirm_at_start' => 'required',
|
||||
'confirm_at_end' => 'required',
|
||||
], [
|
||||
'confirm_at_start.required' => '请输入开始确认时间',
|
||||
'confirm_at_end.required' => '请输入结束确认时间',
|
||||
]);
|
||||
$startDate = Carbon::parse($params['confirm_at_start']);
|
||||
$endDate = Carbon::parse($params['confirm_at_end']);
|
||||
|
||||
if ($endDate->gt($startDate->copy()->addMonth())) {
|
||||
throw new \Exception("导出时间超出一个月");
|
||||
}
|
||||
|
||||
return Excel::download(new BusinessOrderExport($builder->get()->toArray()), $startDate . '~' . $endDate."订单数据" . '.xlsx');
|
||||
}
|
||||
$businessOrders = $builder->orderByDesc('confirm_at')
|
||||
->paginate($request->get('per_page'));
|
||||
|
||||
|
||||
@ -47,4 +47,23 @@ class Controller extends BaseController
|
||||
|
||||
return $this->log->add($targetId, $targetField);
|
||||
}
|
||||
|
||||
public function success($data, $msg = "")
|
||||
{
|
||||
return [
|
||||
"success" => true,
|
||||
"msg" => $msg,
|
||||
"data" => $data
|
||||
];
|
||||
}
|
||||
|
||||
public function error($errorCode, $msg = "")
|
||||
{
|
||||
return [
|
||||
"success" => false,
|
||||
"msg" => $msg,
|
||||
"errorCode" => $errorCode,
|
||||
"data" => []
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,10 +3,17 @@
|
||||
namespace App\Http\Controllers\DataCenter;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Enum\StaticTypeEnum;
|
||||
use App\Http\Resources\DailySalesReportResource;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\DailySalesReport;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Services\Statistic\SaleDataService;
|
||||
use App\Utils\FormatUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class DataCenterController extends Controller
|
||||
{
|
||||
@ -37,4 +44,89 @@ class DataCenterController extends Controller
|
||||
|
||||
return DailySalesReportResource::collection($dailySalesReports);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销售报表
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function saleStatistics(Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'type' => 'required|integer', //1表示今日
|
||||
'start_day' => 'sometimes|date_format:Y-m-d',
|
||||
'end_day' => 'sometimes|date_format:Y-m-d',
|
||||
'start_time' => 'sometimes|date_format:Y-m-d H:i:s',
|
||||
'end_time' => 'sometimes|date_format:Y-m-d H:i:s'
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
return $this->success(SaleDataService::saleStatistics($request));
|
||||
}
|
||||
|
||||
/**
|
||||
* spu 维度的数据统计
|
||||
* @param Request $request
|
||||
* @return array|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|mixed
|
||||
*/
|
||||
public function spuSaleStatistics(Request $request)
|
||||
{
|
||||
//进行校验验证
|
||||
$validator = Validator::make($request->all(), [
|
||||
'type' => 'required|integer', //1表示今日
|
||||
'start_day' => 'sometimes|date_format:Y-m-d',
|
||||
'end_day' => 'sometimes|date_format:Y-m-d',
|
||||
'start_time' => 'sometimes|date_format:Y-m-d H:i:s',
|
||||
'end_time' => 'sometimes|date_format:Y-m-d H:i:s'
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
return $this->success(SaleDataService::spuSaleStatistics($request));
|
||||
}
|
||||
|
||||
public function gmvStatistics(Request $request)
|
||||
{
|
||||
//进行校验验证
|
||||
$validator = Validator::make($request->all(), [
|
||||
'type' => 'required|integer', //1表示今日
|
||||
'start_day' => 'required_unless:type,1|date_format:Y-m-d',
|
||||
'end_day' => 'required_unless:type,1|date_format:Y-m-d',
|
||||
"interval" => 'sometimes|integer|max:120|min:1',
|
||||
'start_time' => 'sometimes|date_format:Y-m-d H:i:s',
|
||||
'end_time' => 'sometimes|date_format:Y-m-d H:i:s',
|
||||
'sku_id' => 'sometimes|integer'
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
return $this->success(SaleDataService::gmvStatistics($request));
|
||||
}
|
||||
|
||||
public function lossRecordStatistics(Request $request)
|
||||
{
|
||||
//进行校验验证
|
||||
$validator = Validator::make($request->all(), [
|
||||
'start_time' => 'sometimes|date_format:Y-m-d H:i:s',
|
||||
'end_time' => 'sometimes|date_format:Y-m-d H:i:s',
|
||||
'sku_id' => 'sometimes|integer',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
return $this->success(SaleDataService::lossRecordStatistics($request));
|
||||
}
|
||||
}
|
||||
@ -7,10 +7,14 @@ use App\Http\Resources\GoodsSkuResource;
|
||||
use App\Imports\CombinationGoodsImport;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\CombinationGood;
|
||||
use App\Models\DeveloperConfig;
|
||||
use App\Models\Goods;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Utils\GeneratorUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
@ -20,43 +24,82 @@ class GoodsCombinationController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
// ToDo
|
||||
// 可通过子商品查找主商品
|
||||
$skus = GoodsSku::query()
|
||||
->with([
|
||||
'combinationGoods:id,goods_sku_id,item_id,item_num',
|
||||
'combinationGoods.goodsSkuItem:id,goods_id,title,stock,external_sku_id,updated_at,yesterday_num,reference_price,status',
|
||||
'combinationGoods.goodsSkuItem.goods:id,title,img_url',
|
||||
])
|
||||
->where('is_combination', 1)
|
||||
->filter()
|
||||
->orderBy('stock', 'desc')
|
||||
->paginate($request->get('per_page'));
|
||||
$sortField = $request->input('sort_field', 'id');//stock sale_stock order_goods_num
|
||||
$sortValue = $request->input('sort_value', 'desc');
|
||||
$fields = implode(',', [
|
||||
'shop_id',
|
||||
'external_sku_id',
|
||||
'sum(goods_number) as number',
|
||||
'sum(already_cancel_number) as cancel_number',
|
||||
'SUM(goods_number) - SUM(already_cancel_number) as number',
|
||||
]);
|
||||
$orderRestTime = DeveloperConfig::query()
|
||||
->where('key', DeveloperConfig::$ORDER_RESET_TIME)
|
||||
->value('value');
|
||||
if (is_null($orderRestTime)) {
|
||||
$orderRestTime = date('Y-m-d 07:00:00');
|
||||
}
|
||||
|
||||
$businessOrderItems = BusinessOrderItem::query()
|
||||
->select(DB::raw($fields))
|
||||
->with([
|
||||
'shop:id,name',
|
||||
'goodsSku:id,external_sku_id,is_combination',
|
||||
'goodsSku.combinationGoods:id,goods_sku_id,item_id,item_num'
|
||||
])
|
||||
->where('created_at', '>', $orderRestTime)
|
||||
->where('external_sku_id', '<>', '')
|
||||
->groupBy(['shop_id', 'external_sku_id'])
|
||||
->orderByDesc('number')
|
||||
->get()
|
||||
->toArray();
|
||||
$ids = $externals = [];
|
||||
foreach ($businessOrderItems as $businessOrderItem) {
|
||||
if (is_null($businessOrderItem['goods_sku'])) {
|
||||
continue;
|
||||
}
|
||||
$id = $businessOrderItem['goods_sku']['id'];
|
||||
if (isset($ids[$id])) {
|
||||
$ids[$id] += (int)$businessOrderItem['number'];
|
||||
} else {
|
||||
$ids[$id] = (int)$businessOrderItem['number'];
|
||||
}
|
||||
|
||||
$externals[$id][] = $businessOrderItem;
|
||||
}
|
||||
arsort($ids);
|
||||
|
||||
// 可通过子商品查找主商品
|
||||
$goodsSkusBuilder = GoodsSku::query()
|
||||
->with([
|
||||
'combinationGoods:id,goods_sku_id,item_id,item_num',
|
||||
'combinationGoods.goodsSkuItem:id,name,goods_id,title,stock,sale_stock,external_sku_id,updated_at,yesterday_num,reference_price,status',
|
||||
'combinationGoods.goodsSkuItem.goods:id,title,img_url',
|
||||
])
|
||||
->where('is_combination', 1)
|
||||
->filter();
|
||||
if ($sortField == "order_goods_num") {
|
||||
$finalIds = [];
|
||||
asort($ids);
|
||||
foreach ($ids as $id => $number) {
|
||||
$finalIds[] = $id;
|
||||
}
|
||||
|
||||
$idField = implode(',', $finalIds);
|
||||
$goodsSkusBuilder->orderByRaw("FIELD(id,{$idField}) {$sortValue}");
|
||||
} else {
|
||||
$goodsSkusBuilder->orderBy($sortField, $sortValue);
|
||||
}
|
||||
$skus = $goodsSkusBuilder
|
||||
->paginate($request->get('per_page'));
|
||||
foreach ($skus as &$item) {
|
||||
$items = [];
|
||||
$lastInventoryTime = date('Y-m-d 07:00:00');
|
||||
$orderDetail = BusinessOrderItem::query()
|
||||
->select(DB::raw($fields))
|
||||
->with(['shop:id,name'])
|
||||
->where('external_sku_id', $item['external_sku_id'])
|
||||
->when($lastInventoryTime, function ($query) use ($lastInventoryTime) {
|
||||
$query->where('created_at', '>', $lastInventoryTime);
|
||||
})
|
||||
->groupBy(['shop_id', 'external_sku_id'])
|
||||
->get()
|
||||
->toArray();
|
||||
$addOrderGoodsNum = $reduceOrderGoodsNum = 0;
|
||||
if ($orderDetail) {
|
||||
$addOrderGoodsNum = array_sum(array_column($orderDetail, 'number'));
|
||||
$reduceOrderGoodsNum = array_sum(array_column($orderDetail, 'cancel_number'));
|
||||
if (isset($externals[$item['id']])) {
|
||||
$item['order_detail'] = $externals[$item['id']];
|
||||
$item['order_goods_num'] = $ids[$item['id']];
|
||||
} else {
|
||||
$item['order_detail'] = [];
|
||||
$item['order_goods_num'] = 0;
|
||||
}
|
||||
$item['order_goods_num'] = $addOrderGoodsNum - $reduceOrderGoodsNum;
|
||||
$item['order_detail'] = $orderDetail;
|
||||
|
||||
$number = BusinessOrderItem::query()
|
||||
->where('external_sku_id', $item['external_sku_id'])
|
||||
->sum('goods_number');
|
||||
@ -65,6 +108,9 @@ class GoodsCombinationController extends Controller
|
||||
->sum('already_cancel_number');
|
||||
$item['total_orders_num'] = $number - $cancelNumber;
|
||||
foreach ($item['combinationGoods'] as $combinationItem) {
|
||||
$title = !empty($combinationItem['goodsSkuItem']['name']) ? $combinationItem['goodsSkuItem']['name'] :
|
||||
(!empty($combinationItem['goodsSkuItem']['goods']) ? $combinationItem['goodsSkuItem']['goods']['title']
|
||||
. " " . $combinationItem['goodsSkuItem']['title'] : $combinationItem['goodsSkuItem']['title']);
|
||||
$items[] = [
|
||||
'cost' => 0,
|
||||
'external_sku_id' => $combinationItem['goodsSkuItem']['external_sku_id'],
|
||||
@ -75,9 +121,10 @@ class GoodsCombinationController extends Controller
|
||||
'reference_price' => $combinationItem['goodsSkuItem']['reference_price'],
|
||||
'status' => $combinationItem['goodsSkuItem']['status'],
|
||||
'stock' => $combinationItem['goodsSkuItem']['stock'],
|
||||
'thumb_url' => $combinationItem['goodsSkuItem']['goods']['img_url'],
|
||||
'img_url' => $combinationItem['goodsSkuItem']['goods']['img_url'],
|
||||
'title' => $combinationItem['goodsSkuItem']['goods']['title'] . $combinationItem['goodsSkuItem']['title'],
|
||||
'sale_stock' => $combinationItem['goodsSkuItem']['sale_stock'],
|
||||
'thumb_url' => null,
|
||||
'img_url' => null,//图片暂时去掉
|
||||
'title' => $title,
|
||||
'updated_at' => $combinationItem['goodsSkuItem']['updated_at'],
|
||||
'yesterday_num' => $combinationItem['goodsSkuItem']['yesterday_num'],
|
||||
'order_goods_num' => '请在商品列表查看',
|
||||
@ -88,15 +135,18 @@ class GoodsCombinationController extends Controller
|
||||
$item['children'] = $items;
|
||||
unset($item['combinationGoods']);
|
||||
}
|
||||
$rolesName = $request->user()->getRoleNames()->toArray();
|
||||
$data = ["manage" => ["is_admin" => in_array($rolesName[0]
|
||||
, ["运营", "超级管理员", "管理员", "系统管理员", "店铺运营"]) ? 1 : 0]];
|
||||
|
||||
return GoodsSkuResource::collection($skus);
|
||||
return GoodsSkuResource::collection($skus)->additional($data);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'title' => 'required',
|
||||
'external_sku_id' => 'required',
|
||||
'external_sku_id' => 'sometimes',
|
||||
'combination_goods.*' => 'required',
|
||||
'combination_goods.*.item_id' => 'required',
|
||||
'combination_goods.*.item_num' => 'required|gt:0',
|
||||
@ -106,20 +156,33 @@ class GoodsCombinationController extends Controller
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$externalSkuId = $request->input('external_sku_id') ??
|
||||
GeneratorUtils::generateCombinationGoodNumber($request->combination_goods);
|
||||
$hasCodeSku = GoodsSku::query()->where("external_sku_id", $externalSkuId)->first();
|
||||
if (!empty($hasCodeSku)) {
|
||||
throw new \Exception("该组合商品编码已存在");
|
||||
}
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$combinationGoods = $request->input('combination_goods');
|
||||
$itemIds = array_column($combinationGoods, 'item_id');
|
||||
$skus = GoodsSku::query()
|
||||
->whereIn('id', $itemIds)
|
||||
->pluck('stock', 'id')
|
||||
->get()
|
||||
->pluck(null, 'id')
|
||||
->toArray();
|
||||
$stock = [];
|
||||
$saleStock = [];
|
||||
foreach ($combinationGoods as $item) {
|
||||
$stock[] = (int)($skus[$item['item_id']] / $item['item_num']);
|
||||
if (!empty($skus[$item['item_id']])) {
|
||||
$stock[] = (int)($skus[$item['item_id']]['stock'] / $item['item_num']);
|
||||
$saleStock[] = (int)($skus[$item['item_id']]['sale_stock'] / $item['item_num']);
|
||||
}
|
||||
}
|
||||
$stock = min($stock);
|
||||
$status = $stock ? (5 < $stock ? 1 : 2) : 0;
|
||||
$saleStock = min($saleStock);
|
||||
|
||||
$status = $saleStock ? (5 < $saleStock ? 1 : 2) : 0;
|
||||
if ($id = $request->input('id')) {
|
||||
$sku = GoodsSku::query()->findOrFail($id);
|
||||
} else {
|
||||
@ -127,11 +190,15 @@ class GoodsCombinationController extends Controller
|
||||
$sku->goods_id = 0;
|
||||
$sku->is_combination = 1;
|
||||
}
|
||||
|
||||
|
||||
$sku->status = $status;
|
||||
$sku->title = $request->input('title');
|
||||
$sku->sku_code = $request->input('external_sku_id');
|
||||
$sku->external_sku_id = $request->input('external_sku_id');
|
||||
$sku->name = $request->input('title');
|
||||
$sku->sku_code = $externalSkuId;
|
||||
$sku->external_sku_id = $externalSkuId;
|
||||
$sku->stock = $stock;
|
||||
$sku->sale_stock = $saleStock;
|
||||
$sku->save();
|
||||
CombinationGood::query()
|
||||
->where('goods_sku_id', $sku->id)
|
||||
@ -180,16 +247,17 @@ class GoodsCombinationController extends Controller
|
||||
|
||||
public function goodsSkus(Request $request, $title)
|
||||
{
|
||||
$goodsIds = Goods::query()
|
||||
->where('title', 'like', '%' . $title . '%')
|
||||
->pluck('id');
|
||||
$skus = GoodsSku::query()
|
||||
->whereIn('goods_id', $goodsIds)
|
||||
->where('name', 'like', '%' . $title . '%')
|
||||
->where('is_combination', 0)
|
||||
->with('goods:id,title')
|
||||
->get(['id', 'title', 'goods_id']);
|
||||
->get(['id', 'title', 'goods_id', "name"]);
|
||||
foreach ($skus as &$sku) {
|
||||
$sku['title'] = $sku['goods']['title'] . $sku['title'];
|
||||
if (!empty($sku['name'])) {
|
||||
$sku['title'] = $sku['name'];
|
||||
} else {
|
||||
$sku['title'] = ($sku['goods']['title'] ?? "") . $sku['title'];
|
||||
}
|
||||
}
|
||||
|
||||
return GoodsSkuResource::collection($skus);
|
||||
|
||||
@ -5,10 +5,13 @@ namespace App\Http\Controllers\Goods;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\GoodsSkuRequest;
|
||||
use App\Http\Resources\GoodsResource;
|
||||
use App\Models\GoodsType;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Services\Good\GoodService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Models\Goods;
|
||||
use App\Http\Requests\GoodsRequest;
|
||||
@ -42,28 +45,23 @@ class GoodsController extends Controller
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
if (!empty($request->goods_id)) {
|
||||
$goods = Goods::query()->find($request->goods_id);
|
||||
} else {
|
||||
$goods = new Goods();
|
||||
$goods->title = $request->title;
|
||||
$goods->img_url = $request->img_url;
|
||||
$goods->type_id = $request->type_id;
|
||||
$goods->brand_id = $request->brand_id;
|
||||
$goods->goods_code = $request->goods_code;
|
||||
$goods->save();
|
||||
}
|
||||
$goodService = new GoodService();
|
||||
$goods = $goodService->saveDefaultGoodsByGoodType($request->type_id);
|
||||
$goodsSkus = [];
|
||||
|
||||
foreach ($request->skus as $item) {
|
||||
$item['goods_id'] = $goods->id;
|
||||
$item['stock'] = $item['num'];
|
||||
$item['stock'] = $item['num'] ?? 0;
|
||||
$item['reference_price'] = $item['cost'] * 1.5;
|
||||
$item['external_sku_id'] = $goods->goods_code . '_' . $item['sku_code'];
|
||||
$item['name'] = $goods->title . $item['title'];
|
||||
$item['sku_code'] = !empty($item['external_sku_id']) ? $item['external_sku_id'] : $goodService->getRandomCode();
|
||||
$item['external_sku_id'] = !empty($item['external_sku_id']) ? $item['external_sku_id'] : ($goods->goods_code . '_' . $item['sku_code']);
|
||||
$item['name'] = $goodService->getSkuName($request->type_id,$item);
|
||||
$goodsSkus[] = $item;
|
||||
}
|
||||
|
||||
$collection = $goods->skus()->createMany($goodsSkus)->toArray();
|
||||
$this->setAfterUpdateForLog($collection);
|
||||
$this->addLog(0, 'add');
|
||||
@ -89,13 +87,14 @@ class GoodsController extends Controller
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
public function download()
|
||||
{
|
||||
$file = resource_path('templates/goods_skus_import.xlsx');
|
||||
$file = resource_path('templates/sale_stock_import.xlsx');
|
||||
$headers = [
|
||||
'Content-Type: application/xlsx',
|
||||
];
|
||||
|
||||
return response()->download($file, 'goods_skus_import.xlsx', $headers);
|
||||
return response()->download($file, 'sale_stock_import.xlsx', $headers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,16 +7,22 @@ use App\Events\StockUpdateEvent;
|
||||
use App\Exports\GoodsSkusExport;
|
||||
use App\Exports\WeekDataExport;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Enum\ExcelKeyEnum;
|
||||
use App\Http\Requests\GoodsRequest;
|
||||
use App\Http\Requests\GoodsSkuRequest;
|
||||
use App\Imports\InventoryImport;
|
||||
use App\Imports\NewSetImport;
|
||||
use App\Imports\SaleStockImport;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\DailySalesReport;
|
||||
use App\Models\DeveloperConfig;
|
||||
use App\Models\Goods;
|
||||
use App\Models\Log;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||
use App\Services\Good\GoodService;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Services\Ship\WayBillService;
|
||||
use App\Utils\ArrayUtils;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
@ -60,7 +66,8 @@ class GoodsSkusController extends Controller
|
||||
->select(DB::raw($fields))
|
||||
->with([
|
||||
'shop:id,name',
|
||||
'goodsSku:id,external_sku_id'
|
||||
'goodsSku:id,external_sku_id,is_combination',
|
||||
'goodsSku.combinationGoods:id,goods_sku_id,item_id,item_num'
|
||||
])
|
||||
->where('created_at', '>', $orderRestTime)
|
||||
->where('external_sku_id', '<>', '')
|
||||
@ -74,62 +81,76 @@ class GoodsSkusController extends Controller
|
||||
continue;
|
||||
}
|
||||
$id = $businessOrderItem['goods_sku']['id'];
|
||||
if ($businessOrderItem['goods_sku']['is_combination']) {
|
||||
foreach ($businessOrderItem['goods_sku']['combination_goods'] ?? [] as $combinationGoods) {
|
||||
$ids[$combinationGoods['item_id']] = $ids[$combinationGoods['item_id']] ?? 0
|
||||
+ ((int)$businessOrderItem['number']) * $combinationGoods['item_num'];
|
||||
$externals[$combinationGoods['item_id']][] = $businessOrderItem;
|
||||
}
|
||||
}
|
||||
if (isset($ids[$id])) {
|
||||
$ids[$id] += (int)$businessOrderItem['number'];
|
||||
} else {
|
||||
$ids[$id] = (int)$businessOrderItem['number'];
|
||||
}
|
||||
|
||||
$externals[$businessOrderItem['external_sku_id']][] = $businessOrderItem;
|
||||
$externals[$id][] = $businessOrderItem;
|
||||
}
|
||||
arsort($ids);
|
||||
|
||||
|
||||
$builder = GoodsSku::query();
|
||||
$this->preparQueryGoodsSkus($request, $builder);
|
||||
$day = DateTimeUtils::getToday();
|
||||
$goodsSkus = (clone $builder)->filter()
|
||||
->where('is_combination', 0)
|
||||
->orderByDesc('stock')
|
||||
->pluck('stock', 'id')
|
||||
->toArray();
|
||||
$finalIds = [];
|
||||
foreach ($ids as $id => $number) {
|
||||
if (isset($goodsSkus[$id])) {
|
||||
$finalIds[] = $id;
|
||||
unset($goodsSkus[$id]);
|
||||
}
|
||||
}
|
||||
$finalIds = array_merge($finalIds, array_keys($goodsSkus));
|
||||
$idField = implode(',', $finalIds);
|
||||
|
||||
$goodsSkus = (clone $builder)->with(['goods' => function ($query) {
|
||||
$query->with(['type:id,name', 'brand:id,name']);
|
||||
$sortField = $request->input('sort_field', 'id');//stock sale_stock order_goods_num
|
||||
$sortValue = $request->input('sort_value', 'desc');
|
||||
$goodsSkusBuilder = (clone $builder)->filter()->with(['goods' => function ($query) {
|
||||
$query->with(['type' => function ($query) {
|
||||
$query->with("parentType:id,name")->select(["id", "name", "parent_id"]);
|
||||
}]);
|
||||
}])
|
||||
->with(['daily' => function ($query) use ($day) {
|
||||
$query->where('day', $day);
|
||||
}])
|
||||
->whereIn('id', $finalIds)
|
||||
->orderByRaw("FIELD(id, {$idField})")
|
||||
->paginate($request->get('per_page'));
|
||||
->where('is_combination', 0);
|
||||
if ($sortField == "order_goods_num") {
|
||||
$finalIds = [];
|
||||
asort($ids);
|
||||
foreach ($ids as $id => $number) {
|
||||
$finalIds[] = $id;
|
||||
}
|
||||
|
||||
$idField = implode(',', $finalIds);
|
||||
$goodsSkusBuilder->orderByRaw("FIELD(id,{$idField}) {$sortValue}");
|
||||
} else {
|
||||
$goodsSkusBuilder->orderBy($sortField, $sortValue);
|
||||
}
|
||||
|
||||
$goodsSkus = $goodsSkusBuilder->paginate($request->get('per_page'));
|
||||
$rolesName = $request->user()->getRoleNames()->toArray();
|
||||
foreach ($goodsSkus as &$sku) {
|
||||
$lastInventoryTime = $sku['daily']['inventory_time'] ?: date('Y-m-d 07:00:00');
|
||||
if (isset($externals[$sku['external_sku_id']])) {
|
||||
$sku['order_detail'] = $externals[$sku['external_sku_id']];
|
||||
$sku['order_goods_num'] = array_sum(array_column($externals[$sku['external_sku_id']], 'number'));
|
||||
$lastInventoryTime = !empty($sku['daily']['inventory_time']) ? $sku['daily']['inventory_time'] : date('Y-m-d 07:00:00');
|
||||
if (isset($externals[$sku['id']])) {
|
||||
$sku['order_detail'] = $externals[$sku['id']];
|
||||
$sku['order_goods_num'] = $ids[$sku['id']];
|
||||
} else {
|
||||
$sku['order_detail'] = [];
|
||||
$sku['order_goods_num'] = 0;
|
||||
}
|
||||
$sku['order_goods_num'] -= $sku['daily']['reissue_num'];
|
||||
$sku['order_goods_num'] -= $sku['daily']['reissue_num'] ?? 0;
|
||||
$sku['inventory_time'] = $lastInventoryTime;
|
||||
if ('销售' === $rolesName[0]) {
|
||||
$sku['cost'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return GoodsSkuResource::collection($goodsSkus);
|
||||
if (!empty($sku['yesterday_num'])) {
|
||||
$sku['sale_ratio'] = round($sku['stock'] / $sku['yesterday_num'], 2) * 100;
|
||||
} else {
|
||||
$sku['sale_ratio'] = 0;
|
||||
}
|
||||
}
|
||||
$data = ["manage" => ["is_admin" => in_array($rolesName[0], ["运营", "超级管理员", "管理员", "系统管理员", "店铺运营"]) ? 1 : 0]];
|
||||
return GoodsSkuResource::collection($goodsSkus)->additional($data);
|
||||
}
|
||||
|
||||
private function preparQueryGoodsSkus(Request $request, &$builder)
|
||||
@ -189,22 +210,14 @@ class GoodsSkusController extends Controller
|
||||
$sku = GoodsSku::query()->find($id);
|
||||
$this->setBeforeUpdateForLog($sku->toArray());
|
||||
$skuInfo = $request->sku;
|
||||
$skuInfo['external_sku_id'] = $request->goods['goods_code'] . '_' . $request->sku['sku_code'];
|
||||
$skuInfo['name'] = $request->goods['title'] . $request->sku['title'];
|
||||
$goodService = new GoodService();
|
||||
$goods = $goodService->saveDefaultGoodsByGoodType($request->goods['type_id']);
|
||||
$skuInfo['goods_id'] = $goods->id;
|
||||
$skuInfo['name'] = $goodService->getSkuName($request->goods['type_id'], $skuInfo);
|
||||
$sku->update($skuInfo);
|
||||
$this->setAfterUpdateForLog($sku->toArray());
|
||||
$this->addLog($id, 'update');
|
||||
// 商品更新
|
||||
$goods = Goods::query()->find($sku->goods_id);
|
||||
$this->log = new LogModel([
|
||||
'module' => 'goods',
|
||||
'action' => $request->getMethod(),
|
||||
'target_type' => 'goods',
|
||||
]);
|
||||
$this->setBeforeUpdateForLog($goods->toArray());
|
||||
$goods->update($request->goods);
|
||||
$this->setAfterUpdateForLog($goods->toArray());
|
||||
$this->addLog($sku->goods_id, 'update');
|
||||
|
||||
DB::commit();
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
@ -221,7 +234,7 @@ class GoodsSkusController extends Controller
|
||||
public function batchUpdate(Request $request)
|
||||
{
|
||||
$appendRules = [
|
||||
'updateType' => ['required', 'string', Rule::in(['newest', 'inventory', 'stock'])],
|
||||
'updateType' => ['required', 'string', Rule::in(['newest', 'inventory', 'stock', "saleStock"])],
|
||||
'skus' => ['required', 'array'],
|
||||
'skus.*.id' => [
|
||||
'required',
|
||||
@ -240,6 +253,63 @@ class GoodsSkusController extends Controller
|
||||
return $this->$function($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新版本运营管理 主要修改在线库存和成本价(修订) 看看是否需要单独提供修改
|
||||
*
|
||||
* @param $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
private function saleStock($request)
|
||||
{
|
||||
$updateIds = [];
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$logs = [];
|
||||
foreach ($request->skus as $sku) {
|
||||
if ($sku['sale_stock'] < 0) {
|
||||
throw new \Exception("商品id{$sku['id']}在售库存数不能小于0");
|
||||
}
|
||||
$costLog = [
|
||||
'module' => 'goods',
|
||||
'action' => $request->getMethod(),
|
||||
'target_type' => 'goods_sku',
|
||||
'target_id' => $sku['id'],
|
||||
'user_id' => $request->user()->id
|
||||
];
|
||||
// 成本
|
||||
$goodsSku = GoodsSku::query()->where('id', $sku['id'])->first(['id', 'cost', 'sale_stock']);
|
||||
$costLog['target_field'] = 'sale_stock';
|
||||
$costLog['before_update'] = $goodsSku->sale_stock;
|
||||
$goodsSku->sale_stock = $sku['sale_stock'];
|
||||
if (0 >= $goodsSku->sale_stock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
} else {
|
||||
$status = GoodsSku::$STATUS_ON_SALE;
|
||||
}
|
||||
$goodsSku->status = $status;
|
||||
$goodsSku->save();
|
||||
$costLog['after_update'] = $goodsSku->sale_stock;
|
||||
$logs[] = $costLog;
|
||||
$updateIds[] = $sku['id'];
|
||||
}
|
||||
$log = new LogModel();
|
||||
$log->batchInsert($logs);
|
||||
DB::commit();
|
||||
if (!empty($updateIds)) {
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'errorCode' => 400500,
|
||||
'errorMessage' => $exception->getMessage(),
|
||||
];
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上新
|
||||
*
|
||||
@ -297,7 +367,7 @@ class GoodsSkusController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* 库存盘点
|
||||
* 库存盘点 准备废弃中
|
||||
*
|
||||
* @param $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
@ -377,6 +447,7 @@ class GoodsSkusController extends Controller
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -472,7 +543,7 @@ class GoodsSkusController extends Controller
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
goto end;
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$updateField = \request('updateField');
|
||||
$sku = GoodsSku::query()->find($id);
|
||||
@ -494,10 +565,11 @@ class GoodsSkusController extends Controller
|
||||
$changeNum = $sku->reserve - $request->reserve;
|
||||
if (0 > $changeNum + $sku->stock) {
|
||||
$this->setValidatorFailResponse('预留量超过库存数量');
|
||||
goto end;
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$sku->stock += $changeNum;
|
||||
}
|
||||
|
||||
$sku->$updateField = $request->$updateField;
|
||||
$sku->save();
|
||||
$this->setAfterUpdateForLog($sku->$updateField);
|
||||
@ -551,6 +623,7 @@ class GoodsSkusController extends Controller
|
||||
$endDate = Carbon::now()->subWeek()->endOfWeek()->toDateString();
|
||||
return Excel::download(new WeekDataExport($startDate, $endDate), $startDate . '~' . $endDate . '.xlsx');
|
||||
}
|
||||
|
||||
return Excel::download(new GoodsSkusExport($type), $type . '.xlsx');
|
||||
}
|
||||
|
||||
@ -659,4 +732,25 @@ class GoodsSkusController extends Controller
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function saleStockImport(Request $request)
|
||||
{
|
||||
if (!$request->hasFile(ExcelKeyEnum::SALE_STOCK_FILE)) {
|
||||
$this->res = [
|
||||
'httpCode' => 404,
|
||||
'errorCode' => 404404,
|
||||
'errorMessage' => 'not found inventory file',
|
||||
];
|
||||
}
|
||||
try {
|
||||
$import = new SaleStockImport();
|
||||
$path = $request->file(ExcelKeyEnum::SALE_STOCK_FILE);
|
||||
Excel::import($import, $path);
|
||||
$this->addLog(0, 'import', ExcelKeyEnum::SALE_STOCK_FILE);
|
||||
} catch (ValidationException $exception) {
|
||||
$this->setValidatorFailResponse($exception->validator->getMessageBag()->getMessages());
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\GoodsTypeResource;
|
||||
use App\Models\GoodsType;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Utils\FormatUtils;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -23,7 +24,11 @@ class GoodsTypesController extends Controller
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$goodsTypes = GoodsType::query()->paginate($request->get('per_page'));
|
||||
$build = GoodsType::query();
|
||||
if(!empty($request->level)){
|
||||
$build->where("level","=",$request->level);
|
||||
}
|
||||
$goodsTypes = $build->paginate($request->get('per_page'));
|
||||
|
||||
return GoodsTypeResource::collection($goodsTypes);
|
||||
}
|
||||
@ -31,27 +36,34 @@ class GoodsTypesController extends Controller
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'names' => 'required|array',
|
||||
'names.*' => 'required|string|max:191|unique:goods_types,name',
|
||||
'name' => 'required|string|max:191',
|
||||
'parent_id' => 'sometimes',
|
||||
'show' => 'sometimes|integer',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$goodsTypes = [];
|
||||
foreach ($request->names as $name) {
|
||||
$goodsTypes[] = ['name' => $name];
|
||||
$level = 1;
|
||||
if ($request->parent_id) {
|
||||
$parentGoodsType = GoodsType::query()->where("id", "=", $request->parent_id)->get()->toArray();
|
||||
$level = $parentGoodsType['level'] ?? 1 + 1;
|
||||
$existTypeName = GoodsType::query()->where("parent_id", "=", $request->parent_id)
|
||||
->where("name",$request->name)->first();
|
||||
if($existTypeName){
|
||||
throw new \Exception("当前品类下该名称已存在");
|
||||
}
|
||||
}
|
||||
|
||||
$goodsType = new GoodsType();
|
||||
if (!$goodsType->batchInsert($goodsTypes)) {
|
||||
$this->res = [
|
||||
'httpCode' => 500,
|
||||
'errorCode' => 500500,
|
||||
'errorMessage' => '批量添加失败',
|
||||
];
|
||||
}
|
||||
$this->setAfterUpdateForLog($goodsTypes);
|
||||
$goodsType->parent_id = $request->parent_id ?? 0;
|
||||
$goodsType->show = $request->show ?? 1;
|
||||
$goodsType->name = $request->name;
|
||||
$goodsType->level = $level;
|
||||
$goodsType->save();
|
||||
|
||||
$this->setAfterUpdateForLog($request->all());
|
||||
$this->addLog(0, 'add');
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
@ -65,12 +77,9 @@ class GoodsTypesController extends Controller
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:191',
|
||||
Rule::unique('goods_types')->ignore($id),
|
||||
]
|
||||
'name' => 'sometimes|string|max:191',
|
||||
'parent_id' => 'sometimes',
|
||||
'show' => 'sometimes|integer',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
@ -79,7 +88,18 @@ class GoodsTypesController extends Controller
|
||||
}
|
||||
$goodsType = GoodsType::query()->find($id);
|
||||
$this->setBeforeUpdateForLog($goodsType->name);
|
||||
$goodsType->name = request('name');
|
||||
$level= 1;
|
||||
if ($request->parent_id) {
|
||||
$parentGoodsType = GoodsType::query()->where("id", "=", $request->parent_id)->get()->toArray();
|
||||
$level = $parentGoodsType['level'] ?? 1 + 1;
|
||||
}
|
||||
|
||||
$goodsType->parent_id = $request->parent_id ?? 0;
|
||||
$goodsType->show = $request->show ?? 1;
|
||||
if($request->name){
|
||||
$goodsType->name = $request->name;
|
||||
}
|
||||
$goodsType->level = $level;
|
||||
$goodsType->save();
|
||||
$this->setAfterUpdateForLog($goodsType->name);
|
||||
$this->addLog($id, 'name');
|
||||
@ -95,4 +115,11 @@ class GoodsTypesController extends Controller
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
public function tree(Request $request)
|
||||
{
|
||||
$goodsTypes = GoodsType::query()->get()->toArray();
|
||||
$menus = FormatUtils::formatTreeData($goodsTypes, $request->parent_id??0);
|
||||
return $this->success($menus);
|
||||
}
|
||||
}
|
||||
|
||||
77
app/Http/Controllers/Message/WebsiteMessageController.php
Normal file
77
app/Http/Controllers/Message/WebsiteMessageController.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Message;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Enum\Goods\SkuStatusEnum;
|
||||
use App\Http\Enum\Message\MessageTypeEnum;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\WebsiteMessages;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class WebsiteMessageController extends Controller
|
||||
{
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$roleIds = collect($request->user()->roles)->pluck('id')->toArray() ?? [];
|
||||
$status = $request->input('status') ?? 0;
|
||||
$websiteMessage = WebsiteMessages::query()->where('status', '=', $status);
|
||||
|
||||
if (!empty($roleIds)) {
|
||||
$websiteMessagePage = $websiteMessage->whereIn('role_id', $roleIds)
|
||||
->paginate($request->get('per_page'));
|
||||
return JsonResource::collection($websiteMessagePage);
|
||||
}
|
||||
|
||||
return JsonResource::collection([]);
|
||||
}
|
||||
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'status' => ['required', 'integer', 'in:0,1']
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
//更新站內信狀態
|
||||
$websiteMessages = WebsiteMessages::query()->find($id);
|
||||
if (empty($websiteMessages)) {
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'errorCode' => 400404,
|
||||
'errorMessage' => "站内信数据不存在",
|
||||
];
|
||||
|
||||
return response($this->res, "400");
|
||||
}
|
||||
$websiteMessages->status = $request->status;
|
||||
Log::info("管理員更新站內信", (array)$request->user());
|
||||
$websiteMessages->save();
|
||||
|
||||
if ($request->status == 1) {
|
||||
//标记已读触发
|
||||
$this->hook($websiteMessages);
|
||||
}
|
||||
|
||||
return $websiteMessages;
|
||||
}
|
||||
|
||||
public function hook($websiteMessages)
|
||||
{
|
||||
if ($websiteMessages->type == MessageTypeEnum::LOW_STOCK_NOTICE) {
|
||||
$keyArray = explode("-", $websiteMessages->unique_key);//时间Ymd-对应id-角色id
|
||||
$skuId = $keyArray[1] ?? 0;
|
||||
if (!empty($skuId)) {
|
||||
//变更回上架状态
|
||||
GoodsSku::query()->where("id", "=", $skuId)->update(["status" => SkuStatusEnum::UP]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Utils\ArrayUtils;
|
||||
use App\Utils\FormatUtils;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
@ -52,13 +52,16 @@ class ShopsController extends Controller
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|string|max:191|unique:shops,name',
|
||||
'plat_id' => 'required|integer',
|
||||
'ratio' => 'required',
|
||||
'ratio' => 'sometimes',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
if(empty($request->ratio)){
|
||||
$request->ratio = "*1";
|
||||
}
|
||||
$operator = substr($request->ratio, 0, 1);
|
||||
if (!in_array($operator, ['+', '-', '*', '/'])) {
|
||||
$this->res->errorMessage = '运算符号仅允许+,-,*,/';
|
||||
@ -203,10 +206,11 @@ class ShopsController extends Controller
|
||||
} else {
|
||||
$shops = $builder->where('id', $shopId)->get();
|
||||
}
|
||||
//同步三方的是在售库存
|
||||
$skus = GoodsSku::query()
|
||||
->where('updated_at', '>', date('Y-m-d 07:01:00'))
|
||||
->whereNotNull('external_sku_id')
|
||||
->pluck('stock', 'external_sku_id')
|
||||
->pluck('sale_stock', 'external_sku_id')
|
||||
->toArray();
|
||||
foreach ($shops as $shop) {
|
||||
$business = BusinessFactory::init()->make($shop->plat_id);
|
||||
|
||||
135
app/Http/Controllers/Supplier/DailyStockRecordController.php
Normal file
135
app/Http/Controllers/Supplier/DailyStockRecordController.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Supplier;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Enum\ExcelKeyEnum;
|
||||
use App\Imports\InventoryImport;
|
||||
use App\Imports\LossImport;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class DailyStockRecordController extends Controller
|
||||
{
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->log = new LogModel([
|
||||
'module' => 'supplier',
|
||||
'action' => $request->getMethod(),
|
||||
'target_type' => 'dailyStockRecord',
|
||||
]);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$build = DailyStockRecord::query()->whereNotNull("inventory_time")->filter()->with("goodsSku:id,name,title,external_sku_id");
|
||||
if (!empty($request->title)) {
|
||||
$build->whereHas('goodsSku', function ($query) use ($request) {
|
||||
$query->where('name', 'like', '%' . $request->title . '%');
|
||||
});
|
||||
}
|
||||
if (!empty($request->get('external_sku_id'))) {
|
||||
$build->whereHas('goodsSku', function ($query) use ($request) {
|
||||
$query->where('external_sku_id', '=', $request->external_sku_id);
|
||||
});
|
||||
}
|
||||
$dailyStockRecord = $build->orderByDesc("id")->paginate($request->get('per_page'));
|
||||
return JsonResource::collection($dailyStockRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'external_sku_id' => 'required|string',
|
||||
'inventory' => 'required|integer',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$goodsSku = GoodsSku::query()->with("combinationGoods")->where('external_sku_id', "=", $request->external_sku_id)->first();
|
||||
if (empty($goodsSku)) {
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'message' => '查询不到sku信息',
|
||||
'errorCode' => "ERP001",
|
||||
'errorMessage' => '查询不到sku信息',
|
||||
];
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$goodsSkuWithInventory = array_merge($goodsSku->toArray(),["inventory"=>$request->inventory]);
|
||||
//同批量逻辑操作
|
||||
$goodSkuService = new GoodSkuService();
|
||||
$goodSkuService->inventory([$goodsSkuWithInventory]);
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function inventoryBatchStore(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'inventoryOrders' => 'required|array',
|
||||
'inventoryOrders.*.external_sku_id' => 'required|string',
|
||||
'inventoryOrders.*.inventory' => 'required|integer',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$inventoryKeyByExternalSkuIdMap = collect($request->inventoryOrders)->pluck(null,"external_sku_id")->toArray();
|
||||
$goodsSkus = GoodsSku::query()->with("combinationGoods")->whereIn('external_sku_id', array_keys($inventoryKeyByExternalSkuIdMap))
|
||||
->get()->toArray();
|
||||
$goodsSkus = collect($goodsSkus)->map(function ($v) use ($inventoryKeyByExternalSkuIdMap) {
|
||||
if (!empty($inventoryKeyByExternalSkuIdMap[$v['external_sku_id']])) {
|
||||
$v['inventory'] = $inventoryKeyByExternalSkuIdMap[$v['external_sku_id']]['inventory'];
|
||||
return $v;
|
||||
}
|
||||
})->toArray();
|
||||
Log::info("goodsSkus",$goodsSkus);
|
||||
$goodSkuService = new GoodSkuService();
|
||||
$goodSkuService->inventory($goodsSkus);
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
public function inventoryImport(Request $request)
|
||||
{
|
||||
if (!$request->hasFile('inventoryFile')) {
|
||||
$this->res = [
|
||||
'httpCode' => 404,
|
||||
'errorCode' => 404404,
|
||||
'errorMessage' => 'not found inventory file',
|
||||
];
|
||||
}
|
||||
try {
|
||||
$import = new InventoryImport();
|
||||
$path = $request->file('inventoryFile');
|
||||
Excel::import($import, $path);
|
||||
$this->addLog(0, 'import', 'inventory');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->setValidatorFailResponse($exception->validator->getMessageBag()->getMessages());
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
231
app/Http/Controllers/Supplier/LossRecordController.php
Normal file
231
app/Http/Controllers/Supplier/LossRecordController.php
Normal file
@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Supplier;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Enum\ExcelKeyEnum;
|
||||
use App\Imports\LossImport;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\Goods;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Log;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Models\LossRecords;
|
||||
use App\Models\Suppliers;
|
||||
use App\Models\User;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use App\Utils\GeneratorUtils;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class LossRecordController extends Controller
|
||||
{
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->log = new LogModel([
|
||||
'module' => 'supplier',
|
||||
'action' => $request->getMethod(),
|
||||
'target_type' => 'loss_record',
|
||||
]);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$builder = LossRecords::query()->filter()->with("goodsSku:name,external_sku_id,title");
|
||||
if (!empty($request->start_time) && !empty($request->end_time)) {
|
||||
$builder->whereBetween('created_at', [$request->start_time, $request->end_time]);
|
||||
}
|
||||
if (!empty($request->title)) {
|
||||
$builder->whereHas('goodsSku', function ($query) use ($request) {
|
||||
$query->where('name', 'like', '%' . $request->title . '%');
|
||||
});
|
||||
}
|
||||
$dailyStockRecord = $builder->orderByDesc("id")->paginate($request->get('per_page'));
|
||||
return JsonResource::collection($dailyStockRecord);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'external_sku_id' => 'required|string',
|
||||
'num' => 'required|integer',
|
||||
'reason' => 'sometimes|string',
|
||||
'buyer_name' => 'sometimes|string'
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$goodsSku = GoodsSku::query()->where('external_sku_id', "=", $request->external_sku_id)->first();
|
||||
if (!empty($goodsSku)) {
|
||||
$buyerUserId = User::query()->where("name", $allParams['buyer_name'] ?? '')
|
||||
->pluck("id")->first();
|
||||
$today = DateTimeUtils::getToday();
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
//保存記錄
|
||||
$lossRecords = new LossRecords();
|
||||
$lossRecords->batch_number = GeneratorUtils::generateBatchNumber();
|
||||
$lossRecords->external_sku_id = $allParams['external_sku_id'];
|
||||
$lossRecords->num = $allParams['num'];
|
||||
$lossRecords->cost = $allParams['cost'];
|
||||
$lossRecords->date = $allParams['date'] ?? $today;
|
||||
$lossRecords->buyer_user_id = $allParams['buyer_user_id'] ?? ($buyerUserId ?? 0);
|
||||
$lossRecords->buyer_name = $allParams['buyer_name'] ?? '';
|
||||
$lossRecords->reason = $allParams['reason'] ?? '';
|
||||
$lossRecords->phenomenon = $v['phenomenon'] ?? '';
|
||||
$lossRecords->save();
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSku->toArray()
|
||||
, ['num' => 0 - $allParams['num'], "cost" => $allParams['cost'], "user_id" => $request->user()->id]);
|
||||
DB::commit();
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'message' => '查询不到sku信息',
|
||||
'errorCode' => "ERP001",
|
||||
'errorMessage' => '查询不到sku信息',
|
||||
];
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'reason' => 'sometimes|string',
|
||||
'buyer_name' => 'sometimes|string',
|
||||
'buyer_user_id' => 'sometimes|integer'
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$lossRecords = LossRecords::query()->find($id);
|
||||
if (!empty($lossRecords)) {
|
||||
//更新記錄
|
||||
$lossRecords->buyer_name = $allParams['buyer_name'] ?? '';
|
||||
$lossRecords->buyer_user_id = $allParams['buyer_user_id'] ?? 0;
|
||||
$lossRecords->reason = $allParams['reason'] ?? '';
|
||||
$lossRecords->phenomenon = $allParams['phenomenon'] ?? '';
|
||||
$lossRecords->save();
|
||||
} else {
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'message' => '查询不到sku信息',
|
||||
'errorCode' => "ERP001",
|
||||
'errorMessage' => '查询不到sku信息',
|
||||
];
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
public function lossBatchStore(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'lossOrders' => 'required|array',
|
||||
'lossOrders.*.external_sku_id' => 'required|string',
|
||||
'lossOrders.*.num' => 'required|integer',
|
||||
'lossOrders.*.reason' => 'sometimes|string',
|
||||
'lossOrders.*.buyer_name' => 'sometimes|string',//采购商
|
||||
'lossOrders.*.phenomenon' => 'sometimes|string',
|
||||
'lossOrders.*.date' => 'sometimes|date_format:Y-m-d'
|
||||
]);
|
||||
//参数校验
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$lossOrders = $request->input('lossOrders') ?? [];
|
||||
$externalSkuIds = collect($lossOrders)->pluck("external_sku_id")->toArray();
|
||||
$goodsSku = GoodsSku::query()->whereIn('external_sku_id', $externalSkuIds)->get();
|
||||
if ($goodsSku->pluck("external_sku_id")->diff($externalSkuIds)->isNotEmpty()) {
|
||||
$content = implode(',', $goodsSku->pluck("external_sku_id")->diff($externalSkuIds)->toArray());
|
||||
$content .= "以上sku编码数据库中不存在";
|
||||
return response($content, $this->res['httpCode']);
|
||||
}
|
||||
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
|
||||
$allUpdateIds = [];
|
||||
$batchNumber = GeneratorUtils::generateBatchNumber();
|
||||
$today = DateTimeUtils::getToday();
|
||||
//开始保存数据
|
||||
foreach ($lossOrders as $v) {
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$goodsSkuItem = $goodsSkuMap[$v['external_sku_id']];
|
||||
//保存記錄
|
||||
$lossRecords = new LossRecords();
|
||||
$lossRecords->batch_number = $batchNumber;
|
||||
$lossRecords->external_sku_id = $v['external_sku_id'];
|
||||
$lossRecords->num = $v['num'];
|
||||
$lossRecords->cost = $v['cost'];
|
||||
$lossRecords->date = $v['date'] ?? $today;
|
||||
$lossRecords->buyer_user_id = $v['buyer_user_id'] ?? 0;
|
||||
$lossRecords->buyer_name = $v['buyer_name'] ?? '';
|
||||
$lossRecords->reason = $v['reason'] ?? '';
|
||||
$lossRecords->phenomenon = $v['phenomenon'] ?? '';
|
||||
$lossRecords->save();
|
||||
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem
|
||||
, ['num' => 0 - $v['num'], "cost" => $v['cost'], "user_id" => $request->user()->id]);
|
||||
DB::commit();
|
||||
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
}
|
||||
}
|
||||
|
||||
event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 报损单单后台批量导入
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|void
|
||||
*/
|
||||
public function lossImport(Request $request)
|
||||
{
|
||||
if (!$request->hasFile(ExcelKeyEnum::LOSS_KEY)) {
|
||||
$this->res = [
|
||||
'httpCode' => 404,
|
||||
'errorCode' => 404404,
|
||||
'errorMessage' => 'not found loss file',
|
||||
];
|
||||
}
|
||||
try {
|
||||
$import = new LossImport();
|
||||
$path = $request->file(ExcelKeyEnum::LOSS_KEY);
|
||||
Excel::import($import, $path);
|
||||
$this->addLog(0, 'import', ExcelKeyEnum::LOSS_KEY);
|
||||
} catch (ValidationException $exception) {
|
||||
$this->setValidatorFailResponse($exception->validator->getMessageBag()->getMessages());
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
}
|
||||
315
app/Http/Controllers/Supplier/PurchaseRecordController.php
Normal file
315
app/Http/Controllers/Supplier/PurchaseRecordController.php
Normal file
@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Supplier;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Enum\ExcelKeyEnum;
|
||||
use App\Http\Enum\Purchase\PurchaseConfigEnum;
|
||||
use App\Http\Enum\Purchase\PurchaseStatusEnum;
|
||||
use App\Http\Enum\TargetTypeEnum;
|
||||
use App\Http\Resources\GoodsSkuResource;
|
||||
use App\Http\Resources\RolesResource;
|
||||
use App\Imports\PurchaseImport;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Log;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Models\Suppliers;
|
||||
use App\Models\User;
|
||||
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use App\Utils\GeneratorUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class PurchaseRecordController extends Controller
|
||||
{
|
||||
public $isAutoCheck = 0;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->log = new LogModel([
|
||||
'module' => 'supplier',
|
||||
'action' => $request->getMethod(),
|
||||
'target_type' => 'purchase_record',
|
||||
]);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$builder = PurchaseRecords::query()->filter()->with("goodsSku:id,name,external_sku_id,title");
|
||||
if (!empty($request->start_time) && !empty($request->end_time)) {
|
||||
$builder->whereBetween('created_at', [$request->start_time, $request->end_time]);
|
||||
}
|
||||
if (!empty($request->title)) {
|
||||
$builder->whereHas('goodsSku', function ($query) use ($request) {
|
||||
$query->where('name', 'like', '%' . $request->title . '%');
|
||||
});
|
||||
}
|
||||
$dailyStockRecord = $builder->orderByDesc("id")->paginate($request->get('per_page'));
|
||||
return JsonResource::collection($dailyStockRecord);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'external_sku_id' => 'required|string',
|
||||
'num' => 'required|integer',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$goodsSku = GoodsSku::query()->where('external_sku_id', "=", $request->external_sku_id)->first();
|
||||
if (!empty($goodsSku)) {
|
||||
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||
$today = DateTimeUtils::getToday();
|
||||
if (empty($allParams['buyer_user_id'])) {
|
||||
$buyerUserId = User::query()->where("name", $allParams['buyer_name'] ?? '')
|
||||
->pluck("id")->first();
|
||||
}
|
||||
if (empty($allParams['supplier_id'])) {
|
||||
$supplierId = Suppliers::query()->where("supplier_name", $allParams['supplier_name'] ?? '')
|
||||
->pluck("id")->first();
|
||||
}
|
||||
|
||||
//保存記錄
|
||||
$purchaseRecords = new PurchaseRecords();
|
||||
$purchaseRecords->external_sku_id = $allParams['external_sku_id'];
|
||||
$purchaseRecords->batch_number = GeneratorUtils::generateBatchNumber();
|
||||
$purchaseRecords->num = $allParams['num'];
|
||||
$purchaseRecords->cost = $allParams['cost'];
|
||||
$purchaseRecords->date = $today;
|
||||
$purchaseRecords->buyer_user_id = $allParams['buyer_user_id'] ?? ($buyerUserId ?? 0);
|
||||
$purchaseRecords->buyer_name = $allParams['buyer_name'] ?? '';
|
||||
$purchaseRecords->supplier_name = $allParams['supplier_name'] ?? '';
|
||||
$purchaseRecords->supplier_id = $allParams['supplier_id'] ?? ($supplierId ?? 0);
|
||||
if (!empty($allParams['expire_time'])) {
|
||||
$purchaseRecords->expire_time = Carbon::parse($allParams['expire_time'])->toDateTimeString();
|
||||
} else {
|
||||
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||
}
|
||||
$purchaseRecords->save();
|
||||
if (PurchaseConfigEnum::IS_AUTO_CHECK) {
|
||||
$allParams['user_id'] = $request->user()->id;
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSku->toArray(), $allParams, TargetTypeEnum::PURCHASE);
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
}
|
||||
} else {
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'message' => '查询不到sku信息',
|
||||
'errorCode' => "ERP001",
|
||||
'errorMessage' => '查询不到sku信息',
|
||||
];
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'buyer_name' => 'sometimes|string',
|
||||
'supplier_name' => 'sometimes|string',
|
||||
"expire_time" => 'sometimes|string'
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$goodsSku = GoodsSku::query()->where('id', "=", $id)->get();
|
||||
if (!empty($goodsSku)) {
|
||||
//可以修改的記錄
|
||||
$purchaseRecords = PurchaseRecords::query()->find($id);
|
||||
$purchaseRecords->buyer_user_id = $allParams['buyer_user_id'] ?? 0;
|
||||
$purchaseRecords->buyer_name = $allParams['buyer_name'] ?? '';
|
||||
$purchaseRecords->supplier_name = $allParams['supplier_name'] ?? '';
|
||||
$purchaseRecords->supplier_id = $allParams['supplier_id'] ?? 0;
|
||||
if ($purchaseRecords->status == PurchaseStatusEnum::WAIT_CHECK) {
|
||||
$purchaseRecords->cost = $allParams['cost'] ?? 0;
|
||||
$purchaseRecords->num = $allParams['num'] ?? 0;
|
||||
}
|
||||
if (!empty($allParams['expire_time'])) {
|
||||
$purchaseRecords->expire_time = Carbon::parse($allParams['expire_time'])->toDateTimeString();
|
||||
}
|
||||
if (!empty($allParams['date'])) {
|
||||
$purchaseRecords->date = Carbon::parse($allParams['date'])->toDateString();
|
||||
}
|
||||
if (!empty($allParams['arrived_time'])) {
|
||||
$purchaseRecords->arrived_time = Carbon::parse($allParams['arrived_time'])->toDateTimeString();
|
||||
}
|
||||
|
||||
$purchaseRecords->save();
|
||||
|
||||
} else {
|
||||
$this->res = [
|
||||
'httpCode' => 400,
|
||||
'message' => '查询不到sku信息',
|
||||
'errorCode' => "ERP001",
|
||||
'errorMessage' => '查询不到sku信息',
|
||||
];
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 采购单后台批量存储
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|void
|
||||
*/
|
||||
public function purchaseBatchStore(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'purchaseOrders' => 'required|array',
|
||||
'purchaseOrders.*.external_sku_id' => 'required|string',
|
||||
'purchaseOrders.*.num' => 'required|integer',
|
||||
'purchaseOrders.*.cost' => 'required',]);
|
||||
//参数校验
|
||||
if ($validator->fails()) {
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
$purchaseOrders = $request->input('purchaseOrders') ?? [];
|
||||
$externalSkuIds = collect($purchaseOrders)->pluck("external_sku_id")->toArray();
|
||||
$goodsSku = GoodsSku::query()->whereIn('external_sku_id', $externalSkuIds)->get();
|
||||
if (collect($externalSkuIds)->diff($goodsSku->pluck("external_sku_id"))->isNotEmpty()) {
|
||||
$content = implode(',', collect($externalSkuIds)->diff($goodsSku->pluck("external_sku_id"))->toArray());
|
||||
$content .= "以上sku编码数据库中不存在";
|
||||
return response($content, 400);
|
||||
}
|
||||
$goodsSkuMap = $goodsSku->pluck(null, 'external_sku_id')->toArray();
|
||||
$allUpdateIds = [];
|
||||
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||
$today = DateTimeUtils::getToday();
|
||||
$batchNumber = GeneratorUtils::generateBatchNumber();
|
||||
//开始保存数据
|
||||
foreach ($purchaseOrders as $v) {
|
||||
$goodsSkuItem = $goodsSkuMap[$v['external_sku_id']];
|
||||
//保存記錄
|
||||
$purchaseRecords = new PurchaseRecords();
|
||||
$purchaseRecords->batch_number = $batchNumber;
|
||||
$purchaseRecords->external_sku_id = $v['external_sku_id'];
|
||||
$purchaseRecords->num = $v['num'];
|
||||
$purchaseRecords->cost = $v['cost'];
|
||||
$purchaseRecords->date = $v['date'] ?? $today;
|
||||
$purchaseRecords->buyer_user_id = $v['buyer_user_id'] ?? 0;
|
||||
$purchaseRecords->buyer_name = $v['buyer_name'] ?? '';
|
||||
$purchaseRecords->supplier_name = $v['supplier_name'] ?? '';
|
||||
$purchaseRecords->supplier_id = $v['supplier_id'] ?? 0;
|
||||
$purchaseRecords->arrived_time = $v['arrived_time'] ?? Carbon::now()->toDateTimeString();
|
||||
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||
$purchaseRecords->save();
|
||||
if (PurchaseConfigEnum::IS_AUTO_CHECK) {
|
||||
$v['user_id'] = $request->user()->id;
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, $v, TargetTypeEnum::PURCHASE);
|
||||
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
|
||||
}
|
||||
|
||||
}
|
||||
if (PurchaseConfigEnum::IS_AUTO_CHECK) {
|
||||
//如果是組合商品会触发重算逻辑
|
||||
event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 报损单后台批量存储
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|void
|
||||
*/
|
||||
public function purchaseImport(Request $request)
|
||||
{
|
||||
if (!$request->hasFile(ExcelKeyEnum::PURCHASE_KEY)) {
|
||||
$this->res = [
|
||||
'httpCode' => 404,
|
||||
'errorCode' => 404404,
|
||||
'errorMessage' => 'not found purchase file',
|
||||
];
|
||||
}
|
||||
try {
|
||||
$import = new PurchaseImport();
|
||||
$path = $request->file(ExcelKeyEnum::PURCHASE_KEY);
|
||||
Excel::import($import, $path);
|
||||
$this->addLog(0, 'import', ExcelKeyEnum::PURCHASE_KEY);
|
||||
} catch (ValidationException $exception) {
|
||||
$this->setValidatorFailResponse($exception->validator->getMessageBag()->getMessages());
|
||||
}
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 报损单后台批量存储
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|void
|
||||
*/
|
||||
public function purchaseBatchCheck(Request $request)
|
||||
{
|
||||
$params = $request->validate([
|
||||
'purchaseOrders' => 'required|array',
|
||||
'purchaseOrders.*.id' => 'required|integer',
|
||||
'purchaseOrders.*.status' => 'required|in:1,2',
|
||||
'purchaseOrders.*.num' => 'sometimes|integer',
|
||||
]);
|
||||
$allUpdateIds = [];
|
||||
$now = Carbon::now()->toDateTimeString();
|
||||
foreach ($params['purchaseOrders'] as $v) {
|
||||
$purchaseRecordBuilder = PurchaseRecords::query()->with("goodsSku")->where("id", $v['id'])->first();
|
||||
if (empty($purchaseRecordBuilder)) {
|
||||
continue;
|
||||
}
|
||||
$purchaseRecords = $purchaseRecordBuilder->toArray();
|
||||
if (empty($purchaseRecords['goods_sku'])) {
|
||||
continue;
|
||||
}
|
||||
if ($purchaseRecords['status'] == $v['status']) {
|
||||
continue;
|
||||
}
|
||||
if (!empty($v['num'])) {
|
||||
$purchaseRecordBuilder->num = $v['num'];
|
||||
$purchaseRecords['num'] = $v['num'];
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
if (PurchaseStatusEnum::CHECK_SUCCESS == $v['status']) {
|
||||
$updateIds = GoodSkuService::computeSkuStock($purchaseRecords['goods_sku'], $purchaseRecords, TargetTypeEnum::PURCHASE);
|
||||
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
|
||||
}
|
||||
$purchaseRecordBuilder->status = $v['status'];
|
||||
$purchaseRecordBuilder->check_time = $now;
|
||||
$purchaseRecordBuilder->save();
|
||||
DB::commit();
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
\Illuminate\Support\Facades\Log::error("质检审核事务异常", ["error" => $exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
if (!empty($allUpdateIds)) {
|
||||
event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
|
||||
}
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
109
app/Http/Controllers/Supplier/SuppliersController.php
Normal file
109
app/Http/Controllers/Supplier/SuppliersController.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Supplier;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Log;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Models\Suppliers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class SuppliersController extends Controller
|
||||
{
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->log = new LogModel([
|
||||
'module' => 'supplier',
|
||||
'action' => $request->getMethod(),
|
||||
'target_type' => 'supplier',
|
||||
]);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$suppliers = Suppliers::query()->paginate($request->get('per_page'));
|
||||
return JsonResource::collection($suppliers);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'supplier_name' => 'required|string',
|
||||
'company_name' => 'required|string',
|
||||
'address' => 'sometimes|string',
|
||||
'link_tel' => 'sometimes|string',
|
||||
'payment_account' => 'sometimes|string',
|
||||
'supply_type' => 'sometimes|string',
|
||||
'agent_id' => 'sometimes|integer',
|
||||
'agent_name' => 'sometimes|string',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
//保存数据
|
||||
$suppliers = new Suppliers();
|
||||
$suppliers->supplier_name = $request->supplier_name;
|
||||
$suppliers->company_name = $request->company_name ?? '';
|
||||
$suppliers->link_tel = $request->link_tel ?? '';
|
||||
$suppliers->address = $request->address ?? '';
|
||||
$suppliers->payment_account = $request->payment_account ?? '';
|
||||
$suppliers->supply_type = $request->supply_type ?? '';
|
||||
$suppliers->agent_id = $request->agent_id ?? 0;
|
||||
$suppliers->agent_name = $request->agent_name ?? '';
|
||||
$suppliers->save();
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
|
||||
public function update($id, Request $request)
|
||||
{
|
||||
//获取所有参数
|
||||
$allParams = $request->all();
|
||||
//进行校验验证
|
||||
$validator = Validator::make($allParams, [
|
||||
'supplier_name' => 'required|string',
|
||||
'company_name' => 'required|string',
|
||||
'address' => 'sometimes|string',
|
||||
'link_tel' => 'sometimes|string',
|
||||
'payment_account' => 'sometimes|string',
|
||||
'supply_type' => 'sometimes|string',
|
||||
'agent_id' => 'sometimes|integer',
|
||||
'agent_name' => 'sometimes|string',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
//校验失败返回异常
|
||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
//保存数据
|
||||
$suppliers = Suppliers::query()->find($id);
|
||||
$suppliers->supplier_name = $request->supplier_name;
|
||||
$suppliers->company_name = $request->company_name ?? '';
|
||||
$suppliers->link_tel = $request->link_tel ?? '';
|
||||
$suppliers->address = $request->address ?? '';
|
||||
$suppliers->payment_account = $request->payment_account ?? '';
|
||||
$suppliers->supply_type = $request->supply_type ?? '';
|
||||
$suppliers->agent_id = $request->agent_id ?? 0;
|
||||
$suppliers->agent_name = $request->agent_name ?? '';
|
||||
$suppliers->save();
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$goodsType = Suppliers::query()->find($id);
|
||||
$goodsType->delete();
|
||||
$this->addLog($id, 'status');
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
}
|
||||
@ -101,4 +101,9 @@ class UsersController extends Controller
|
||||
|
||||
return response($this->res, $this->res['httpCode']);
|
||||
}
|
||||
|
||||
public function userRoles(Request $request)
|
||||
{
|
||||
return $request->user()->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
34
app/Http/Enum/AfterSaleOrderStatusEnum.php
Normal file
34
app/Http/Enum/AfterSaleOrderStatusEnum.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class AfterSaleOrderStatusEnum
|
||||
{
|
||||
const WAIT = 0;
|
||||
const REFUNDING = 1;
|
||||
const REFUNDED_SUCCESS = 2;
|
||||
const WAIT_HANDLE = 3;
|
||||
const REFUND_REFUSE = 4;
|
||||
const WAIT_RETURN_GOOD = 6;
|
||||
const WAIT_CONFIRM_RETURN_GOOD = 7;
|
||||
const USER_CANCEL = 8;
|
||||
const CLOSE = 9;
|
||||
|
||||
const MAP = [
|
||||
self::WAIT => "未发起售后",
|
||||
self::REFUNDING => "退款中",
|
||||
self::REFUNDED_SUCCESS => "退款成功",
|
||||
self::WAIT_HANDLE => "待处理",
|
||||
self::REFUND_REFUSE => "拒绝退款",
|
||||
self::WAIT_RETURN_GOOD => "待退货",
|
||||
self::WAIT_CONFIRM_RETURN_GOOD => "待团长确认退货",
|
||||
self::USER_CANCEL => "用户取消",
|
||||
self::CLOSE => "系统已关闭",
|
||||
];
|
||||
|
||||
public static function getData($key)
|
||||
{
|
||||
return self::MAP[$key] ?? '';
|
||||
}
|
||||
}
|
||||
16
app/Http/Enum/CacheKeyEnum.php
Normal file
16
app/Http/Enum/CacheKeyEnum.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class CacheKeyEnum
|
||||
{
|
||||
|
||||
const STOCK_RULE_PROPORTION = "stock_rule_proportion";
|
||||
|
||||
const DEFAULT_EXPIRE_DAY = "default_expire_day";
|
||||
|
||||
const SPU_STATISTIC_BY_DATE = "spu_statistic_by_date";
|
||||
|
||||
const SKU_ADMIN_ROLE_IDS = "sku_admin_role_ids";
|
||||
}
|
||||
21
app/Http/Enum/DevConfigKeyEnum.php
Normal file
21
app/Http/Enum/DevConfigKeyEnum.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?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;
|
||||
|
||||
const SKU_ADMIN_ROLE_IDS = "sku_admin_role_ids";
|
||||
|
||||
const DEFAULT_SKU_ADMIN_ROLE_IDS = "1,2";
|
||||
|
||||
}
|
||||
14
app/Http/Enum/ExcelKeyEnum.php
Normal file
14
app/Http/Enum/ExcelKeyEnum.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class ExcelKeyEnum
|
||||
{
|
||||
const PURCHASE_KEY = "purchaseFile";
|
||||
|
||||
const LOSS_KEY = "lossFile";
|
||||
|
||||
const SALE_STOCK_FILE = "saleStockFile";
|
||||
|
||||
}
|
||||
15
app/Http/Enum/Goods/SkuStatusEnum.php
Normal file
15
app/Http/Enum/Goods/SkuStatusEnum.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum\Goods;
|
||||
|
||||
|
||||
class SkuStatusEnum
|
||||
{
|
||||
const DOWN = 0;
|
||||
|
||||
const UP = 1;
|
||||
|
||||
const NOTICE = 2;
|
||||
|
||||
|
||||
}
|
||||
21
app/Http/Enum/Message/MessageTypeEnum.php
Normal file
21
app/Http/Enum/Message/MessageTypeEnum.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?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";
|
||||
|
||||
const DEFAULT_ROLE_IDS = [11];
|
||||
|
||||
const MESSAGE_ALL_TYPE = [
|
||||
self::LOW_STOCK_NOTICE,
|
||||
self::PRICE_EXCEPTION_NOTICE,
|
||||
self::QUALITY_PERIOD_EXPIRE_NOTICE
|
||||
];
|
||||
}
|
||||
11
app/Http/Enum/Purchase/PurchaseConfigEnum.php
Normal file
11
app/Http/Enum/Purchase/PurchaseConfigEnum.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum\Purchase;
|
||||
|
||||
|
||||
class PurchaseConfigEnum
|
||||
{
|
||||
|
||||
const IS_AUTO_CHECK = 0;
|
||||
|
||||
}
|
||||
11
app/Http/Enum/Purchase/PurchaseStatusEnum.php
Normal file
11
app/Http/Enum/Purchase/PurchaseStatusEnum.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum\Purchase;
|
||||
|
||||
|
||||
class PurchaseStatusEnum
|
||||
{
|
||||
const WAIT_CHECK = 0;
|
||||
const CHECK_SUCCESS = 1;
|
||||
const CHECK_FAILED = 2;
|
||||
}
|
||||
11
app/Http/Enum/StaticTypeEnum.php
Normal file
11
app/Http/Enum/StaticTypeEnum.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class StaticTypeEnum
|
||||
{
|
||||
|
||||
const TODAY = 1;
|
||||
|
||||
}
|
||||
15
app/Http/Enum/TargetTypeEnum.php
Normal file
15
app/Http/Enum/TargetTypeEnum.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Enum;
|
||||
|
||||
|
||||
class TargetTypeEnum
|
||||
{
|
||||
|
||||
const PURCHASE = "sku_stock_purchase";
|
||||
|
||||
const LOSS = "sku_stock_loss";
|
||||
|
||||
const INVENTORY = "sku_stock_inventory";
|
||||
|
||||
}
|
||||
@ -16,6 +16,9 @@ class CheckPermissions
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
//目前permission仅菜单权限和接口权限耦合 这里先放开
|
||||
$permissions = $request->user()->getPermissionsViaRoles()->toArray();
|
||||
return $next($request);
|
||||
// 获取当前路由名称
|
||||
$currentRouteName = Route::currentRouteName();
|
||||
// 引入当前守卫的权限文件
|
||||
|
||||
@ -25,11 +25,7 @@ class GoodsRequest extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'id' => ['sometimes', 'required', 'integer', 'exists:goods,id'],
|
||||
'title' => ['required', 'string', 'max:191'],
|
||||
'type_id' => ['required', 'integer', 'exists:goods_types,id'],
|
||||
'brand_id' => ['integer', 'exists:goods_brands,id'],
|
||||
'goods_code' => ['required', 'alpha_dash', 'max:32', Rule::unique('goods')->ignore(request('goods_id'))],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -28,10 +28,10 @@ class GoodsSkuRequest extends FormRequest
|
||||
'id' => ['sometimes', 'required', 'integer', 'exists:goods_skus,id'],
|
||||
'goods_id' => ['sometimes', 'required', 'integer', 'exists:goods,id'],
|
||||
'title' => ['sometimes', 'required', 'string', 'max:191'],
|
||||
'sku_code' => ['sometimes', 'required', 'distinct', 'alpha_dash', 'max:32'],
|
||||
'status' => ['sometimes', 'required', 'integer', Rule::in([0, 1, 2])],
|
||||
'num' => ['sometimes', 'required', 'integer'],
|
||||
'cost' => ['sometimes', 'required', 'numeric'],
|
||||
'attribute' => ['sometimes', 'required', 'string'],
|
||||
'reference_price' => [
|
||||
'sometimes',
|
||||
'numeric',
|
||||
|
||||
121
app/Http/Service/MessageService.php
Normal file
121
app/Http/Service/MessageService.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Service;
|
||||
|
||||
use App\Http\Enum\Message\MessageTypeEnum;
|
||||
use App\Models\DeveloperConfig;
|
||||
use App\Models\WebsiteMessages;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class MessageService
|
||||
{
|
||||
public $roleIdsMapKeyByNoticeType = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$DeveloperConfig = DeveloperConfig::query()->whereIn("key", MessageTypeEnum::MESSAGE_ALL_TYPE)
|
||||
->pluck("value", "key")->toArray();
|
||||
$this->roleIdsMapKeyByNoticeType = [
|
||||
MessageTypeEnum::PRICE_EXCEPTION_NOTICE => !empty($DeveloperConfig[MessageTypeEnum::PRICE_EXCEPTION_NOTICE])
|
||||
? explode(",", $DeveloperConfig[MessageTypeEnum::PRICE_EXCEPTION_NOTICE]) : MessageTypeEnum::DEFAULT_ROLE_IDS,
|
||||
MessageTypeEnum::LOW_STOCK_NOTICE => !empty($DeveloperConfig[MessageTypeEnum::LOW_STOCK_NOTICE])
|
||||
? explode(",", $DeveloperConfig[MessageTypeEnum::LOW_STOCK_NOTICE]) : MessageTypeEnum::DEFAULT_ROLE_IDS,
|
||||
MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE => !empty($DeveloperConfig[MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE])
|
||||
? explode(",", $DeveloperConfig[MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE]) : MessageTypeEnum::DEFAULT_ROLE_IDS
|
||||
];
|
||||
}
|
||||
|
||||
//值为角色ids
|
||||
|
||||
|
||||
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('Ymd');
|
||||
foreach ($roleIds as $v) {
|
||||
$arr['title'] = "订单价格异常告警";
|
||||
$arr['role_id'] = $v;
|
||||
$arr['unique_key'] = $date . "-" . $businessOrderId . "-" . $v;
|
||||
$arr['type'] = MessageTypeEnum::PRICE_EXCEPTION_NOTICE;
|
||||
$arr['content'] = $date . "订单号:{$businessOrderId}-商品{$productName}
|
||||
规格{$skuName}价格有异常,当前售价{$goodsPrice}/支,当前成本价{$cost}/支";
|
||||
$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('Ymd');
|
||||
foreach ($roleIds as $v) {
|
||||
$arr['title'] = "商品库存不足告警";
|
||||
$arr['role_id'] = $v;
|
||||
$arr['unique_key'] = $date . "-" . $goodsSku['id'] . "-" . $v;
|
||||
$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('Ymd');
|
||||
foreach ($roleIds as $v) {
|
||||
$arr['title'] = "商品保质期告警";
|
||||
$arr['role_id'] = $v;
|
||||
$arr['unique_key'] = $date . "-" . $goodsSku['id'] . "-" . $v;//这个场景下实际是采购单的id
|
||||
$arr['type'] = MessageTypeEnum::QUALITY_PERIOD_EXPIRE_NOTICE;
|
||||
$arr['content'] = $date . "规格{$goodsSku['title']}编码{$goodsSku['external_sku_id']},即将过期,目前实际库存{$goodsSku['stock']},当时采购数量为{$goodsSku['num']},录入采购时间为{$goodsSku['created_at']}";
|
||||
|
||||
$this->saveWebsiteMessages($arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function saveWebsiteMessages($arr)
|
||||
{
|
||||
$hasMessage = WebsiteMessages::query()->where("type", "=", $arr['type'])
|
||||
->where("unique_key", "=", $arr['unique_key'])->first();
|
||||
if (!empty($hasMessage)) {
|
||||
//已经写入过了
|
||||
return true;
|
||||
}
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ use App\Models\CombinationGood;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Utils\ArrayUtils;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||
use Maatwebsite\Excel\Concerns\ToArray;
|
||||
use Maatwebsite\Excel\Concerns\WithStartRow;
|
||||
@ -50,18 +51,23 @@ class CombinationGoodsImport implements ToArray, SkipsEmptyRows, WithStartRow
|
||||
$itemCodes = array_column($info['item'], 'item_code');
|
||||
$skus = GoodsSku::query()
|
||||
->whereIn('external_sku_id', $itemCodes)
|
||||
->get(['id', 'external_sku_id', 'stock'])
|
||||
->get(['id', 'external_sku_id', 'stock', "sale_stock"])
|
||||
->toArray();
|
||||
$skus = ArrayUtils::index($skus, 'external_sku_id');
|
||||
$stock = [];
|
||||
$saleStock = [];
|
||||
foreach ($info['item'] as $item) {
|
||||
$stock[] = (int)($skus[$item['item_code']]['stock'] / $item['item_num']);
|
||||
$saleStock[] = (int)($skus[$item['item_code']]['sale_stock'] / $item['item_num']);
|
||||
|
||||
}
|
||||
$stock = min($stock);
|
||||
$status = $stock ? (5 < $stock ? 1 : 2) : 0;
|
||||
$saleStock = min($saleStock);
|
||||
$status = $saleStock ? (5 < $saleStock ? 1 : 2) : 0;
|
||||
$sku = GoodsSku::query()->updateOrCreate(
|
||||
['external_sku_id' => $info['external_sku_id'], 'is_combination' => 1],
|
||||
['title' => $info['title'], 'goods_id' => 0, 'sku_code' => $info['external_sku_id'], 'stock' => $stock, 'status' => $status]
|
||||
['title' => $info['title'],'name' => $info['title'], 'goods_id' => 0, 'sku_code' => $info['external_sku_id']
|
||||
, 'stock' => $stock, "sale_stock" => $saleStock, 'status' => $status]
|
||||
);
|
||||
CombinationGood::query()
|
||||
->where('goods_sku_id', $sku->id)
|
||||
|
||||
@ -2,16 +2,12 @@
|
||||
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Jobs\SyncCostToMiaoXuan;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\TodayPrice;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||
use Maatwebsite\Excel\Concerns\ToArray;
|
||||
use App\Utils\ArrayUtils;
|
||||
|
||||
class InventoryImport implements ToArray, SkipsEmptyRows
|
||||
{
|
||||
@ -20,85 +16,30 @@ class InventoryImport implements ToArray, SkipsEmptyRows
|
||||
*/
|
||||
public function array(array $collection)
|
||||
{
|
||||
$header = $collection[0];
|
||||
unset($collection[0]);
|
||||
$externalSkuId = [];
|
||||
foreach ($collection as &$row) {
|
||||
$row = array_map(static function ($v) {
|
||||
return trim($v);
|
||||
}, $row);
|
||||
$externalSkuId[] = $row[0];
|
||||
}
|
||||
unset($row);
|
||||
$updateIds = $todayPrice = [];
|
||||
$day = DateTimeUtils::getToday();
|
||||
$dateTime = date('Y-m-d H:i:s');
|
||||
$hasGoodsSkus = GoodsSku::query()
|
||||
->whereIn('external_sku_id', $externalSkuId)
|
||||
->get(['id', 'status', 'external_sku_id'])
|
||||
->toArray();
|
||||
$hasGoodsSkus = ArrayUtils::index($hasGoodsSkus, 'external_sku_id');
|
||||
foreach ($collection as $row) {
|
||||
if (!isset($hasGoodsSkus[$row[0]])) {
|
||||
continue;
|
||||
if (!empty($collection)) {
|
||||
unset($collection[0]);
|
||||
$externalSkuIds = [];
|
||||
$inventoryKeyByExternalSkuIdMap = [];
|
||||
foreach ($collection as &$row) {
|
||||
$row = array_map(static function ($v) {
|
||||
return trim($v);
|
||||
}, $row);
|
||||
$inventoryKeyByExternalSkuIdMap[$row[0]] = $row[2];
|
||||
$externalSkuIds[] = $row[0];
|
||||
}
|
||||
$goodsSku = $hasGoodsSkus[$row[0]];
|
||||
if ('下架' === $goodsSku['status']) {
|
||||
GoodsSku::query()->where('id', $goodsSku['id'])->update([
|
||||
'stock' => $row[2] + $row[3],
|
||||
'cost' => $row[4],
|
||||
'status' => 1,
|
||||
]);
|
||||
} else {
|
||||
GoodsSku::query()->where('id', $goodsSku['id'])->update([
|
||||
'stock' => $row[2] + $row[3],
|
||||
'cost' => $row[4],
|
||||
]);
|
||||
}
|
||||
SyncCostToMiaoXuan::dispatch($row[0], $row[4]);
|
||||
$updateIds[] = $goodsSku['id'];
|
||||
DailyStockRecord::query()->where('sku_id', $goodsSku['id'])->where('day', $day)->update([
|
||||
'arrived_today_num' => $row[3],
|
||||
'inventory' => $row[2],
|
||||
'inventory_time' => $dateTime
|
||||
]);
|
||||
$shopPrice = [];
|
||||
foreach ($row as $i => $v) {
|
||||
if ($i > 4) {
|
||||
$shopPrice[$header[$i]] = $v;
|
||||
unset($row);
|
||||
//新版盘点excel字段 编码 商品名称 盘点数
|
||||
$goodsSkus = GoodsSku::query()->with("combinationGoods")->whereIn('external_sku_id', $externalSkuIds)
|
||||
->get()->toArray();
|
||||
$goodsSkus = collect($goodsSkus)->map(function ($v) use ($inventoryKeyByExternalSkuIdMap) {
|
||||
if (!empty($inventoryKeyByExternalSkuIdMap[$v['external_sku_id']])) {
|
||||
$v['inventory'] = $inventoryKeyByExternalSkuIdMap[$v['external_sku_id']];
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
$todayPrice[] = [
|
||||
'day' => $day,
|
||||
'external_sku_id' => $goodsSku['external_sku_id'],
|
||||
'shop_price' => json_encode($shopPrice, 256)
|
||||
];
|
||||
})->toArray();
|
||||
Log::info("goodsSkus",$goodsSkus);
|
||||
$goodSkuService = new GoodSkuService();
|
||||
$goodSkuService->inventory($goodsSkus);
|
||||
}
|
||||
if ($todayPrice) {
|
||||
TodayPrice::query()->delete();
|
||||
$model = new TodayPrice();
|
||||
$model->batchInsert($todayPrice);
|
||||
}
|
||||
sleep(2);
|
||||
$onSkuIds = GoodsSku::query()
|
||||
->where('is_combination', 0)
|
||||
->where('status', '>', 0)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
$downSkuIds = array_diff($onSkuIds, $updateIds);
|
||||
if ($downSkuIds) {
|
||||
$goodsSkus = GoodsSku::query()->whereIn('id', $downSkuIds)
|
||||
->get(['id', 'yesterday_num', 'stock'])
|
||||
->toArray();
|
||||
foreach ($goodsSkus as $goodsSku) {
|
||||
GoodsSku::query()->where('id', $goodsSku['id'])->update([
|
||||
'yesterday_num' => $goodsSku['yesterday_num'] - $goodsSku['stock'],
|
||||
'stock' => 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
sleep(2);
|
||||
// 批量更新
|
||||
event(new BatchStockUpdateEvent($onSkuIds));
|
||||
}
|
||||
}
|
||||
|
||||
91
app/Imports/LossImport.php
Normal file
91
app/Imports/LossImport.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Jobs\SyncCostToMiaoXuan;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\LossRecords;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Models\User;
|
||||
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use App\Utils\GeneratorUtils;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||
use Maatwebsite\Excel\Concerns\ToArray;
|
||||
use App\Utils\ArrayUtils;
|
||||
|
||||
class LossImport implements ToArray, SkipsEmptyRows
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function array(array $collection)
|
||||
{
|
||||
if (!empty($collection)) {
|
||||
unset($collection[0]);
|
||||
$externalSkuIds = [];
|
||||
$buyerNames = [];
|
||||
foreach ($collection as &$row) {
|
||||
$row = array_map(static function ($v) {
|
||||
return trim($v);
|
||||
}, $row);
|
||||
$externalSkuIds[] = $row[0];
|
||||
$buyerNames[] = $row[4];
|
||||
}
|
||||
unset($row);
|
||||
$allUpdateIds = [];
|
||||
$hasGoodsSkus = GoodsSku::query()
|
||||
->whereIn('external_sku_id', $externalSkuIds)
|
||||
->get(['id', 'status', 'external_sku_id', 'stock', "sale_stock", "cost", "is_combination"])
|
||||
->toArray();
|
||||
$hasGoodsSkus = ArrayUtils::index($hasGoodsSkus, 'external_sku_id');
|
||||
$buyerUserIdKeyByNameMap = User::query()->whereIn("name", $buyerNames)->get()
|
||||
->pluck("id", "name")->toArray();
|
||||
$today = DateTimeUtils::getToday();
|
||||
$batchNumber = GeneratorUtils::generateBatchNumber("import");
|
||||
//excel字段排序 編碼 商品名稱 报损數量 成本价 采购人名称 报损现象 报损原因 报损日期
|
||||
foreach ($collection as $row) {
|
||||
if (!isset($hasGoodsSkus[$row[0]])) {
|
||||
continue;
|
||||
}
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
//执行库存操作
|
||||
$goodsSkuItem = $hasGoodsSkus[$row[0]];
|
||||
//保存記錄
|
||||
$lossRecords = new LossRecords();
|
||||
$lossRecords->batch_number = $batchNumber;
|
||||
$lossRecords->external_sku_id = $row[0];
|
||||
$lossRecords->num = $row[2];
|
||||
$lossRecords->cost = $row[3];
|
||||
$lossRecords->buyer_user_id = $buyerUserIdKeyByNameMap[$row[4]] ?? 0;
|
||||
$lossRecords->buyer_name = $row[4] ?? '';
|
||||
$lossRecords->phenomenon = $row[5] ?? '';
|
||||
$lossRecords->reason = $row[6] ?? '';
|
||||
$lossRecords->date = $today;
|
||||
if (!empty($row[7])) {
|
||||
$lossRecords->date = DateTimeUtils::excelUploadDateToString($row[7], $today);
|
||||
}
|
||||
$lossRecords->save();
|
||||
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => 0 - $row[2], 'cost' => $row[3]]);
|
||||
DB::commit();
|
||||
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
}
|
||||
}
|
||||
Log::info("报损导入内容:", $collection);
|
||||
// 批量更新
|
||||
event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
100
app/Imports/PurchaseImport.php
Normal file
100
app/Imports/PurchaseImport.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Http\Enum\Purchase\PurchaseConfigEnum;
|
||||
use App\Http\Enum\TargetTypeEnum;
|
||||
use App\Jobs\SyncCostToMiaoXuan;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\PurchaseRecords;
|
||||
use App\Models\Suppliers;
|
||||
use App\Models\User;
|
||||
use App\Services\DeveloperConfig\DeveloperConfigService;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use App\Utils\GeneratorUtils;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||
use Maatwebsite\Excel\Concerns\ToArray;
|
||||
use App\Utils\ArrayUtils;
|
||||
|
||||
class PurchaseImport implements ToArray, SkipsEmptyRows
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function array(array $collection)
|
||||
{
|
||||
if (!empty($collection)) {
|
||||
unset($collection[0]);
|
||||
$externalSkuIds = [];
|
||||
$supplierNames = [];
|
||||
$buyerNames = [];
|
||||
foreach ($collection as &$row) {
|
||||
$row = array_map(static function ($v) {
|
||||
return trim($v);
|
||||
}, $row);
|
||||
$externalSkuIds[] = $row[0];
|
||||
$buyerNames[] = $row[4];
|
||||
$supplierNames[] = $row[5];
|
||||
}
|
||||
unset($row);
|
||||
$allUpdateIds = [];
|
||||
$hasGoodsSkus = GoodsSku::query()
|
||||
->whereIn('external_sku_id', $externalSkuIds)
|
||||
->get(['id', 'status', 'external_sku_id', 'stock', "sale_stock", "cost", "is_combination"])
|
||||
->toArray();
|
||||
$hasGoodsSkus = ArrayUtils::index($hasGoodsSkus, 'external_sku_id');
|
||||
//获取供货商
|
||||
$supplierIdKeyByNameMap = Suppliers::query()->whereIn("supplier_name", $supplierNames)->get()
|
||||
->pluck("id", "supplier_name")->toArray();
|
||||
$buyerUserIdKeyByNameMap = User::query()->whereIn("name", $buyerNames)->get()
|
||||
->pluck("id", "name")->toArray();
|
||||
$expireDay = DeveloperConfigService::getDefaultExpireDay();
|
||||
$today = DateTimeUtils::getToday();
|
||||
$batch_number = GeneratorUtils::generateBatchNumber("import");
|
||||
//excel字段排序 編碼 商品名稱 导购數量 成本价 采购人名称 供应商名称 采购日期
|
||||
foreach ($collection as $row) {
|
||||
if (!isset($hasGoodsSkus[$row[0]])) {
|
||||
continue;
|
||||
}
|
||||
//执行库存操作
|
||||
$goodsSkuItem = $hasGoodsSkus[$row[0]];
|
||||
//保存記錄
|
||||
$purchaseRecords = new PurchaseRecords();
|
||||
$purchaseRecords->external_sku_id = $row[0];
|
||||
$purchaseRecords->batch_number = $batch_number;
|
||||
$purchaseRecords->num = $row[2];
|
||||
$purchaseRecords->cost = $row[3];
|
||||
$purchaseRecords->date = $today;
|
||||
if (!empty($row[6])) {
|
||||
$purchaseRecords->date = DateTimeUtils::excelUploadDateToString($row[6], $today);
|
||||
}
|
||||
if (!empty($row[7])) {
|
||||
$purchaseRecords->arrived_time = DateTimeUtils::excelUploadDateToString($row[7], $today,"Y-m-d H:i:s");
|
||||
}else{
|
||||
$purchaseRecords->arrived_time = $today;
|
||||
}
|
||||
$purchaseRecords->buyer_user_id = $buyerUserIdKeyByNameMap[$row[4]] ?? 0;
|
||||
$purchaseRecords->buyer_name = $row[4] ?? '';
|
||||
$purchaseRecords->supplier_name = $row[5] ?? '';
|
||||
$purchaseRecords->supplier_id = $supplierIdKeyByNameMap[$row[5]] ?? 0;
|
||||
$purchaseRecords->expire_time = Carbon::now()->addDays($expireDay)->toDateTimeString();
|
||||
$purchaseRecords->save();
|
||||
if (PurchaseConfigEnum::IS_AUTO_CHECK) {
|
||||
$updateIds = GoodSkuService::computeSkuStock($goodsSkuItem, ["num" => $row[2], 'cost' => $row[3]], TargetTypeEnum::PURCHASE);
|
||||
$allUpdateIds = array_merge($allUpdateIds, $updateIds);
|
||||
}
|
||||
}
|
||||
Log::info("采购导入内容:", $collection);
|
||||
if (PurchaseConfigEnum::IS_AUTO_CHECK) {
|
||||
// 批量更新
|
||||
event(new BatchStockUpdateEvent(collect($allUpdateIds)->unique()->toArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
app/Imports/SaleStockImport.php
Normal file
83
app/Imports/SaleStockImport.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Services\GoodSku\GoodSkuService;
|
||||
use Exception;
|
||||
use App\Models\Log as LogModel;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||
use Maatwebsite\Excel\Concerns\ToArray;
|
||||
|
||||
class SaleStockImport implements ToArray, SkipsEmptyRows
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function array(array $collection)
|
||||
{
|
||||
if (!empty($collection)) {
|
||||
unset($collection[0]);
|
||||
$externalSkuIds = [];
|
||||
$inventoryKeyByExternalSkuIdMap = [];
|
||||
foreach ($collection as &$row) {
|
||||
$row = array_map(static function ($v) {
|
||||
return trim($v);
|
||||
}, $row);
|
||||
if ($row[2] < 0) {
|
||||
throw new Exception("商品编码{$row[0]}在售库存数不能小于0");
|
||||
}
|
||||
$inventoryKeyByExternalSkuIdMap[$row[0]] = $row[2];
|
||||
$externalSkuIds[] = $row[0];
|
||||
}
|
||||
unset($row);
|
||||
//新版盘点excel字段 编码 在售库存值 商品名称
|
||||
$updateIds = [];
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$logs = [];
|
||||
foreach ($externalSkuIds as $externalSkuId) {
|
||||
// 成本
|
||||
$goodsSku = GoodsSku::query()->where('external_sku_id', $externalSkuId)->first(['id', 'cost', 'sale_stock']);
|
||||
Log::info("SKU", [$goodsSku]);
|
||||
if (empty($goodsSku)) {
|
||||
continue;
|
||||
}
|
||||
$costLog = [
|
||||
'module' => 'goods',
|
||||
'action' => "SaleStockImport",
|
||||
'target_type' => 'goods_sku',
|
||||
'target_id' => $goodsSku['id'],
|
||||
'user_id' => Auth::id() ?? 999
|
||||
];
|
||||
$costLog['target_field'] = 'sale_stock';
|
||||
$costLog['before_update'] = $goodsSku->sale_stock;
|
||||
$goodsSku->sale_stock = $inventoryKeyByExternalSkuIdMap[$externalSkuId] ?? 0;
|
||||
if (0 >= $goodsSku->sale_stock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
} else {
|
||||
$status = GoodsSku::$STATUS_ON_SALE;
|
||||
}
|
||||
$goodsSku->status = $status;
|
||||
$goodsSku->save();
|
||||
$costLog['after_update'] = $goodsSku->sale_stock;
|
||||
$logs[] = $costLog;
|
||||
$updateIds[] = $goodsSku['id'];
|
||||
}
|
||||
$log = new LogModel();
|
||||
$log->batchInsert($logs);
|
||||
DB::commit();
|
||||
if (!empty($updateIds)) {
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
throw new Exception($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,8 @@ use App\Models\Shop;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use App\Services\Business\BusinessFactory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BatchStockUpdateListener implements ShouldQueue
|
||||
{
|
||||
@ -35,18 +37,23 @@ class BatchStockUpdateListener implements ShouldQueue
|
||||
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);
|
||||
usleep(140);
|
||||
try {
|
||||
foreach ($shops as $shop) {
|
||||
foreach ($event->goodsSkus as $goodsSku) {
|
||||
//后续同步三方使用在售库存
|
||||
$num = $goodsSku->sale_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);
|
||||
usleep(140);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
Log::error("同步三方库存出现异常", [$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
70
app/Listeners/BusinessOrderUpdateListener.php
Normal file
70
app/Listeners/BusinessOrderUpdateListener.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?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\Enum\Goods\SkuStatusEnum;
|
||||
use App\Http\Service\MessageService;
|
||||
use App\Models\BusinessGoodsSku;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\DeveloperConfig;
|
||||
use App\Models\GoodsSku;
|
||||
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;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
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)
|
||||
{
|
||||
try {
|
||||
if (!empty($event->goodsSku)) {
|
||||
//查询库存是否满足告警规则
|
||||
//查找昨日统计的库存数据
|
||||
$inventory = $event->goodsSku['yesterday_num'] ?? 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());
|
||||
//更新库存状态
|
||||
GoodsSku::query()->where("id", "=", $event->goodsSku->id)->update([
|
||||
"status" => SkuStatusEnum::NOTICE
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
Log::error("库存告警发生异常", ["error" => $exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,8 @@ use App\Utils\DateTimeUtils;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CombinationGoodsStockUpdateListener implements ShouldQueue
|
||||
{
|
||||
@ -53,20 +55,31 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
|
||||
}
|
||||
}
|
||||
}
|
||||
// 减子商品库存
|
||||
$updateIds = [];
|
||||
//拉取三分订单时可能出现组合订单的情况 需要同步扣减库存
|
||||
if ($combinationGoodsIds) {
|
||||
$combinationGoods = CombinationGood::query()
|
||||
->with('goodsSku:id,stock')
|
||||
->whereIn('goods_sku_id', $combinationGoodsIds)
|
||||
->get();
|
||||
$num = !empty($event->num) ? $event->num : -1;
|
||||
foreach ($combinationGoods as $item) {
|
||||
$goodsSku = GoodsSku::query()->find($item['item_id']);
|
||||
$stock = $goodsSku->stock - $item['item_num'];
|
||||
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock);
|
||||
$goodsSku->status = $status;
|
||||
$goodsSku->stock = $stock;
|
||||
$goodsSku->save();
|
||||
$updateIds[] = $goodsSku->id;
|
||||
DB::transaction(function () use ($item, &$updateIds, $num) {
|
||||
$goodsSku = GoodsSku::query()->lockForUpdate()->find($item['item_id']);
|
||||
$stock = $goodsSku->stock + $item['item_num'] * $num;
|
||||
//新增逻辑 在线库存同步扣减
|
||||
$saleStock = max($goodsSku->sale_stock + $item['item_num'] * $num, 0);
|
||||
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock, $saleStock);
|
||||
$goodsSku->status = $status;
|
||||
$goodsSku->stock = $stock;
|
||||
$goodsSku->sale_stock = $saleStock;
|
||||
$goodsSku->save();
|
||||
$mainGoodsSku = GoodsSku::query()->find($item['goods_sku_id']);
|
||||
$mainGoodsSku->stock = min($mainGoodsSku->stock,(int)($stock / $item['item_num']));
|
||||
$mainGoodsSku->sale_stock = min($mainGoodsSku->sale_stock,(int)($saleStock / $item['item_num']));
|
||||
$mainGoodsSku->save();
|
||||
$updateIds[] = $goodsSku->id;
|
||||
});
|
||||
}
|
||||
}
|
||||
// 计算主商品库存
|
||||
@ -76,22 +89,30 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
|
||||
->pluck('goods_sku_id');
|
||||
foreach ($goodsSkuIds as $goodsSkuId) {
|
||||
$combinationGoods = CombinationGood::query()
|
||||
->with('goodsSkuItem:id,stock')
|
||||
->with('goodsSkuItem:id,stock,sale_stock')
|
||||
->where('goods_sku_id', $goodsSkuId)
|
||||
->get();
|
||||
|
||||
$stock = [];
|
||||
$saleStock = [];
|
||||
foreach ($combinationGoods as $goods) {
|
||||
$stock[] = (int)($goods['goodsSkuItem']['stock'] / $goods['item_num']);
|
||||
$saleStock[] = (int)($goods['goodsSkuItem']['sale_stock'] / $goods['item_num']);
|
||||
}
|
||||
//库存和在线可售库存都是通过子商品维护的
|
||||
$stock = min($stock);
|
||||
$saleStock = min($saleStock);
|
||||
$goodsSku = GoodsSku::query()->find($goodsSkuId);
|
||||
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock);
|
||||
//新增在线可售逻辑判断 前置已经完成逻辑扣减或者增加
|
||||
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock, $saleStock);
|
||||
$goodsSku->status = $status;
|
||||
$goodsSku->stock = $stock;
|
||||
$goodsSku->sale_stock = $saleStock;
|
||||
$goodsSku->save();
|
||||
$updateIds[] = $goodsSkuId;
|
||||
}
|
||||
}
|
||||
|
||||
if ($updateIds) {
|
||||
$updateIds = array_unique($updateIds);
|
||||
// 批量更新
|
||||
@ -99,21 +120,14 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
|
||||
}
|
||||
}
|
||||
|
||||
private function checkStatusAndStock($goodsSku, $stock)
|
||||
private function checkStatusAndStock($goodsSku, $stock, $saleStock)
|
||||
{
|
||||
if (0 >= $stock) {
|
||||
//下线库存判断以在线可售库存为准
|
||||
if (0 >= $saleStock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
} else {
|
||||
$status = GoodsSku::$STATUS_ON_SALE;
|
||||
}
|
||||
$arrivedTodayNum = DailyStockRecord::query()
|
||||
->where('day', DateTimeUtils::getToday())
|
||||
->where('sku_id', $goodsSku->id)
|
||||
->value('arrived_today_num');
|
||||
if (20 < $arrivedTodayNum + $goodsSku->yesterday_num && 4 > $stock) {
|
||||
$status = GoodsSku::$STATUS_DOWN;
|
||||
$stock = 0;
|
||||
}
|
||||
|
||||
return [$status, $stock];
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ class StockUpdateListener implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
foreach ($shops as $shop) {
|
||||
$num = $event->goodsSku->stock;
|
||||
$num = $event->goodsSku->sale_stock;
|
||||
$businessGoodsSkus = BusinessGoodsSku::query()
|
||||
->select(['goods_id', 'sku_id', 'external_sku_id'])
|
||||
->where('shop_id', $shop->id)
|
||||
|
||||
@ -60,7 +60,7 @@ class UpdateBusinessGoodsStock implements ShouldQueue
|
||||
}
|
||||
|
||||
foreach ($shops as $shop) {
|
||||
$num = $event->goodsSku->stock;
|
||||
$num = $event->goodsSku->sale_stock;
|
||||
$businessGoodsSkus = BusinessGoodsSku::query()
|
||||
->where('shop_id', $shop->id)
|
||||
->where('is_sync', 1)
|
||||
|
||||
37
app/Models/BusinessAfterSaleOrder.php
Normal file
37
app/Models/BusinessAfterSaleOrder.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\traits\Filter;
|
||||
|
||||
class BusinessAfterSaleOrder extends Model
|
||||
{
|
||||
use Filter;
|
||||
|
||||
protected $table = 'business_after_sale_orders';
|
||||
|
||||
protected $fillable = [
|
||||
'after_sales_biz_sn',
|
||||
];
|
||||
|
||||
public $fieldSearchable = [
|
||||
'after_sales_status',
|
||||
"shop_id",
|
||||
"order_sn",
|
||||
"after_sales_biz_sn"
|
||||
];
|
||||
|
||||
public function getImageListAttribute($value)
|
||||
{
|
||||
return !empty($value) ? json_decode($value, true) : $value;
|
||||
}
|
||||
|
||||
public function getSubExtensionsAttribute($value)
|
||||
{
|
||||
return !empty($value) ? json_decode($value, true) : $value;
|
||||
}
|
||||
public function shop()
|
||||
{
|
||||
return $this->belongsTo(Shop::class, 'shop_id', 'id');
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,23 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\traits\Filter;
|
||||
|
||||
class DailyStockRecord extends Model
|
||||
{
|
||||
use Filter;
|
||||
|
||||
protected $hidden = ['created_at', 'updated_at'];
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public $fieldSearchable = [
|
||||
'day',
|
||||
];
|
||||
|
||||
public function goodsSku()
|
||||
{
|
||||
return $this->belongsTo(GoodsSku::class, 'sku_id', 'id');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,6 +15,8 @@ class GoodsSku extends Model
|
||||
'exclude_ids',
|
||||
'external_sku_id',
|
||||
'is_combination',
|
||||
"create_time_start",
|
||||
"create_time_end"
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
@ -33,10 +35,10 @@ class GoodsSku extends Model
|
||||
'external_sku_id',
|
||||
'is_combination',
|
||||
'name',
|
||||
'sale_stock',
|
||||
'attribute'
|
||||
];
|
||||
|
||||
protected $hidden = ['created_at'];
|
||||
|
||||
public static $STATUS_ON_SALE = 1;
|
||||
public static $STATUS_DOWN = 0;
|
||||
|
||||
@ -63,10 +65,17 @@ class GoodsSku extends Model
|
||||
|
||||
public function getThumbUrlAttribute($value)
|
||||
{
|
||||
|
||||
return json_decode($value, true);
|
||||
}
|
||||
|
||||
public function getNameAttribute($value)
|
||||
{
|
||||
if(empty($value)){
|
||||
return $this->attributes['title']??'';
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 此规格从属于一个商品
|
||||
*/
|
||||
|
||||
@ -2,12 +2,20 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class GoodsType extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
/**
|
||||
* 数组中的属性会被隐藏。
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
public function parentType()
|
||||
{
|
||||
return $this->hasOne(GoodsType::class, 'id', 'parent_id');
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +72,9 @@ class Log extends Model
|
||||
'kuaituantuan' => '快团团',
|
||||
'miaoxuan' => '妙选',
|
||||
'goods' => '商品',
|
||||
"sku_stock_purchase" => "入库采购",
|
||||
"sku_stock_loss" => "报损记录",
|
||||
"sku_stock_inventory" => "盘点记录",
|
||||
];
|
||||
|
||||
return $map[$value] ?? $value;
|
||||
@ -89,6 +92,7 @@ class Log extends Model
|
||||
'set' => '设置',
|
||||
'cost' => '成本',
|
||||
'stock' => '库存',
|
||||
'sale_stock' => '在售库存',
|
||||
'inventory' => '库存盘点',
|
||||
'reserve' => '预留量 ',
|
||||
'timingInventory' => '7点盘点',
|
||||
|
||||
23
app/Models/LossRecords.php
Normal file
23
app/Models/LossRecords.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\traits\Filter;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class LossRecords extends Model
|
||||
{
|
||||
|
||||
use Filter;
|
||||
|
||||
protected $table = 'loss_records';
|
||||
protected $guarded = [];
|
||||
public $fieldSearchable = [
|
||||
'external_sku_id',
|
||||
];
|
||||
|
||||
public function goodsSku()
|
||||
{
|
||||
return $this->belongsTo(GoodsSku::class, 'external_sku_id', 'external_sku_id');
|
||||
}
|
||||
}
|
||||
24
app/Models/PurchaseRecords.php
Normal file
24
app/Models/PurchaseRecords.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\traits\Filter;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PurchaseRecords extends Model
|
||||
{
|
||||
|
||||
use Filter;
|
||||
|
||||
protected $table = 'purchase_records';
|
||||
protected $guarded = [];
|
||||
public $fieldSearchable = [
|
||||
'external_sku_id',
|
||||
'status'
|
||||
];
|
||||
|
||||
public function goodsSku()
|
||||
{
|
||||
return $this->belongsTo(GoodsSku::class, 'external_sku_id', 'external_sku_id');
|
||||
}
|
||||
}
|
||||
11
app/Models/Suppliers.php
Normal file
11
app/Models/Suppliers.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Suppliers extends Model
|
||||
{
|
||||
//
|
||||
protected $table = 'suppliers';
|
||||
}
|
||||
11
app/Models/WebsiteMessages.php
Normal file
11
app/Models/WebsiteMessages.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WebsiteMessages extends Model
|
||||
{
|
||||
//
|
||||
protected $table = 'website_messages';
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -38,6 +38,8 @@ abstract class BusinessClient
|
||||
|
||||
abstract public function downloadOrdersAndSave($beginTime, $endTime, $downloadType = 'default', $page = 1);
|
||||
|
||||
abstract public function downloadAfterSaleOrdersAndSave($beginTime, $endTime, $page = 1);
|
||||
|
||||
public function saveOrders($orders)
|
||||
{
|
||||
$shopId = $this->getShop()->id;
|
||||
@ -92,6 +94,7 @@ abstract class BusinessClient
|
||||
}
|
||||
$orderItem->update($item);
|
||||
}
|
||||
|
||||
// 增量更新库存
|
||||
if ($num && $item['external_sku_id']) {
|
||||
event(new BusinessOrdersUpdate($orderItem, $num));
|
||||
@ -156,7 +159,7 @@ abstract class BusinessClient
|
||||
if (strlen($paramsJson) > 1024) {
|
||||
$paramsJson = '';
|
||||
}
|
||||
if (!in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list'], true)) {
|
||||
if (!in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list',"pdd.ktt.after.sales.increment.list"], true)) {
|
||||
$log = new Log();
|
||||
$log->module = 'plat';
|
||||
$log->action = $method;
|
||||
@ -171,7 +174,7 @@ abstract class BusinessClient
|
||||
}
|
||||
$log->save();
|
||||
}
|
||||
if (in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list'], true)) {
|
||||
if (in_array($params['type'], ['pdd.ktt.increment.order.query', 'pdd.ktt.order.list',"pdd.ktt.after.sales.increment.list"], true)) {
|
||||
LogFile::info('快团团请求: ' . $paramsJson);
|
||||
LogFile::info('快团团返回: ' . json_encode($res, 256));
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services\Business\KuaiTuanTuan;
|
||||
|
||||
use App\Models\BusinessAfterSaleOrder;
|
||||
use App\Models\BusinessGoodsSku;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\GroupGoods;
|
||||
@ -9,6 +10,7 @@ use App\Models\Shop;
|
||||
use App\Models\ShopShip;
|
||||
use App\Services\Business\BusinessClient;
|
||||
use App\Models\Groups as GroupsModel;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class KuaiTuanTuan extends BusinessClient
|
||||
@ -123,6 +125,56 @@ class KuaiTuanTuan extends BusinessClient
|
||||
}
|
||||
}
|
||||
|
||||
public function downloadAfterSaleOrdersAndSave($beginTime, $endTime, $page = 1)
|
||||
{
|
||||
[$type, $appendParams] = Order::downloadIncrementAfterSaleOrders($beginTime, $endTime, $page);
|
||||
$responseName = 'ktt_after_sales_incermet_list_response';
|
||||
$res = $this->doRequest($type, $appendParams);
|
||||
if (!isset($res[$responseName])) {
|
||||
return;
|
||||
}
|
||||
$this->saveAfterSaleOrdersServer($res[$responseName]['list']);
|
||||
if ($res[$responseName]['has_next'] == false) {
|
||||
return;
|
||||
}
|
||||
$pageNum = ceil($res[$responseName]['total_count'] / $appendParams['page_size']);
|
||||
if ($pageNum > $page && 30 >= $page) {
|
||||
$this->downloadAfterSaleOrdersAndSave($beginTime, $endTime, $page + 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function saveAfterSaleOrdersServer($orders)
|
||||
{
|
||||
$shopId = $this->getShop()->id;
|
||||
$now = Carbon::now()->toDateTimeString();
|
||||
foreach ($orders as $k => $v) {
|
||||
$model = BusinessAfterSaleOrder::query()->where("shop_id", "=", $shopId)
|
||||
->where("after_sales_biz_sn", "=", $v['after_sales_biz_sn'])->first();
|
||||
if (empty($model)) {
|
||||
$model = new BusinessAfterSaleOrder();
|
||||
} else {
|
||||
$model->updated_at = $now;
|
||||
}
|
||||
$model->shop_id = $shopId;
|
||||
$model->refund_amount = $v['apply_extension']['refund_amount'];
|
||||
$model->refund_shipping_amount = $v['apply_extension']['refund_shipping_amount'];
|
||||
$model->description = $v['apply_extension']['description'] ?? '';
|
||||
$model->reason = $v['apply_extension']['reason'] ?? '';
|
||||
$model->sub_extensions = isset($v['apply_extension']['sub_extensions']) ? json_encode($v['apply_extension']['sub_extensions']) : null;
|
||||
$model->return_goods_extension = isset($v['return_goods_extension']) ? json_encode($v['return_goods_extension']) : null;
|
||||
$model->image_list = isset($v['apply_extension']['image_list']) ? json_encode($v['apply_extension']['image_list']) : null;
|
||||
$model->apply_type = $v['apply_type'];
|
||||
$model->order_sn = $v['order_sn'];
|
||||
$model->after_sales_biz_sn = $v['after_sales_biz_sn'];
|
||||
$model->after_sales_status = $v['after_sales_status'];
|
||||
$model->after_sale_created_at = !empty($v['created_at']) ? Carbon::createFromTimestamp($v['created_at'] / 1000)->toDateTimeString() : "";
|
||||
$model->after_sale_updated_at = !empty($v['updated_at']) ? Carbon::createFromTimestamp($v['created_at'] / 1000)->toDateTimeString() : "";
|
||||
$model->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function getOrderInfo($orderSn)
|
||||
{
|
||||
[$type, $appendParams] = Order::getOrderInfo($orderSn);
|
||||
@ -163,6 +215,7 @@ class KuaiTuanTuan extends BusinessClient
|
||||
$publicParams = array_merge($publicParams, $appendParams);
|
||||
$publicParams['sign'] = $this->getSign($publicParams);
|
||||
$res = $this->formDataPostRequest($url, $publicParams);
|
||||
Log::info("快团团请求", ["param" => $publicParams, "res" => $res]);
|
||||
if (isset($res['error_response'])) {
|
||||
// "error_msg":"业务服务错误","sub_msg":"该店铺下不存在该商品","sub_code":"11","error_code":50001
|
||||
// "error_msg":"业务服务错误","sub_msg":"该SKU在快团团中设置的库存为无限库存,不支持修改库存","sub_code":"13","error_code":50001
|
||||
|
||||
@ -92,5 +92,21 @@ class Order
|
||||
|
||||
return [$type, $appendParams];
|
||||
}
|
||||
|
||||
/**
|
||||
* 快团团增量查售后单订单
|
||||
*/
|
||||
public static function downloadIncrementAfterSaleOrders($beginTime, $endTime, $page = 1)
|
||||
{
|
||||
$type = 'pdd.ktt.after.sales.increment.list';
|
||||
$appendParams = [
|
||||
'start_updated_at' => $beginTime, // 更新起始时间
|
||||
'end_updated_at' => $endTime, // 更新结束时间
|
||||
'page_number' => $page, // 页码
|
||||
'page_size' => 100, // 数量
|
||||
];
|
||||
|
||||
return [$type, $appendParams];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,10 @@ class MiaoXuan extends BusinessClient
|
||||
{
|
||||
}
|
||||
|
||||
public function downloadAfterSaleOrdersAndSave($beginTime, $endTime, $page = 1){
|
||||
|
||||
}
|
||||
|
||||
public function batchIncrQuantity($businessGoodsSkus, $num, $incremental)
|
||||
{
|
||||
$batchAppendParams = [];
|
||||
|
||||
35
app/Services/DeveloperConfig/DeveloperConfigService.php
Normal file
35
app/Services/DeveloperConfig/DeveloperConfigService.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?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;
|
||||
});
|
||||
}
|
||||
|
||||
public static function getSkuAdminRoleIds()
|
||||
{
|
||||
$expireTime = Carbon::now()->addHour();
|
||||
return Cache::remember(CacheKeyEnum::SKU_ADMIN_ROLE_IDS, $expireTime, function () {
|
||||
$developerConfig = DeveloperConfig::query()->where("key",
|
||||
"=", DevConfigKeyEnum::SKU_ADMIN_ROLE_IDS)->first();
|
||||
$roleIdsStr = $developerConfig['value'] ?? DevConfigKeyEnum::DEFAULT_SKU_ADMIN_ROLE_IDS;
|
||||
return explode(",", $roleIdsStr) ?? [];
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
106
app/Services/Good/GoodService.php
Normal file
106
app/Services/Good/GoodService.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Good;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\CombinationGood;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\Goods;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\GoodsType;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Predis\Command\Redis\SUBSCRIBE;
|
||||
|
||||
class GoodService
|
||||
{
|
||||
public function saveDefaultGoodsByGoodType($typeId)
|
||||
{
|
||||
$goodsType = GoodsType::query()->with("parentType")->where('id', "=", $typeId)
|
||||
->first()->toArray();
|
||||
$params['type_id'] = $typeId;
|
||||
$parentName = "";
|
||||
$params['goods_code'] = static::getChCode($goodsType['id']);
|
||||
if (!empty($goodsType['parent_type']['id'])) {
|
||||
$params['goods_code'] .= "Z". static::getChCode($goodsType['parent_type']['id']);
|
||||
$parentName = $goodsType['parent_type']['name'] ?? '';
|
||||
}
|
||||
$saveData = $params;
|
||||
$saveData['title'] = $goodsType['name'] . " " .$parentName;
|
||||
return Goods::query()->firstOrCreate($params, $saveData);
|
||||
}
|
||||
|
||||
public function getTypeFormatName($typeId)
|
||||
{
|
||||
$goodsType = GoodsType::query()->with("parentType")->where('id', "=", $typeId)
|
||||
->first()->toArray();
|
||||
$parentName = "";
|
||||
if (!empty($goodsType['parent_type']['name'])) {
|
||||
$parentName = $goodsType['parent_type']['name'] ?? '';
|
||||
}
|
||||
return $goodsType['name'] . " " .$parentName;
|
||||
}
|
||||
|
||||
public function getSkuName($typeId,$sku)
|
||||
{
|
||||
$goodsType = GoodsType::query()->with("parentType")->where('id', "=", $typeId)
|
||||
->first()->toArray();
|
||||
$skuName = $goodsType['name'];
|
||||
if(!empty($sku['attribute'])){
|
||||
$skuName.=" ".$sku['attribute'];
|
||||
}
|
||||
if (!empty($goodsType['parent_type']['name'])) {
|
||||
$skuName.= " ".$goodsType['parent_type']['name'] ?? '';
|
||||
}
|
||||
return $skuName." ".$sku['title'];
|
||||
}
|
||||
|
||||
public function getRandomCode()
|
||||
{
|
||||
$time = time();
|
||||
return substr($time, -7) . static::randomString(3);
|
||||
}
|
||||
|
||||
public static function randomString($len = 32)
|
||||
{
|
||||
$chars = [
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
|
||||
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
|
||||
"w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
|
||||
"S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
|
||||
"3", "4", "5", "6", "7", "8", "9"
|
||||
];
|
||||
|
||||
// 将数组打乱
|
||||
shuffle($chars);
|
||||
|
||||
$charsLen = count($chars) - 1;
|
||||
$output = "";
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$output .= $chars[mt_rand(0, $charsLen)];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取非z的字符串
|
||||
* @param $intValue
|
||||
* @return string
|
||||
*/
|
||||
public function getChCode($intValue)
|
||||
{
|
||||
$ch = range('A', 'Y');
|
||||
$result = '';
|
||||
while ($intValue) {
|
||||
$result = $ch[$intValue % 25] . $result;
|
||||
$intValue = intval($intValue / 25);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
193
app/Services/GoodSku/GoodSkuService.php
Normal file
193
app/Services/GoodSku/GoodSkuService.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\GoodSku;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Http\Enum\TargetTypeEnum;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\CombinationGood;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\Log as LogModel;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use App\Utils\GeneratorUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class GoodSkuService
|
||||
{
|
||||
/**
|
||||
* $skusWithCombinationGoods 除了携带组合商品的字段 还拼接了盘点的具体库存值inventory
|
||||
* @param array $skusWithCombinationGoods
|
||||
* @return void
|
||||
*/
|
||||
public function inventory(array $skusWithCombinationGoods)
|
||||
{
|
||||
$skusWithCombinationGoods = $this->handleSkusWithCombinationGoods($skusWithCombinationGoods);
|
||||
//传进来的sku可能包含组合商品 所以这里需要事先计算好数据
|
||||
$inventoryKeyBySkuIdMap = collect($skusWithCombinationGoods)->where('is_combination', "=", 0)
|
||||
->pluck("real_stock", "id")->filter()->toArray();
|
||||
|
||||
Log::info("库存原始操作map", $inventoryKeyBySkuIdMap);
|
||||
//计算组合商品
|
||||
foreach ($skusWithCombinationGoods as $sku) {
|
||||
if (!empty($sku['is_combination'])) {
|
||||
foreach ($sku['combination_goods'] as $combinationGoods) {
|
||||
if (!isset($inventoryKeyBySkuIdMap[$combinationGoods["item_id"]])) {
|
||||
//没有盘点到的sku需要在原先的sku库存
|
||||
$inventoryKeyBySkuIdMap[$combinationGoods["item_id"]] = 0;
|
||||
}
|
||||
|
||||
$inventoryKeyBySkuIdMap[$combinationGoods["item_id"]] += $combinationGoods['item_num'] * $sku['real_stock'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$today = DateTimeUtils::getToday();
|
||||
$dateTime = date('Y-m-d H:i:s');
|
||||
$updateIds = [];
|
||||
Log::info("库存盘点前完整信息", $skusWithCombinationGoods);
|
||||
Log::info("需要操作的库存数据", $inventoryKeyBySkuIdMap);
|
||||
$batchNumber = GeneratorUtils::generateBatchNumber("import");
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
foreach ($skusWithCombinationGoods as $sku) {
|
||||
// 更新每日数据
|
||||
DailyStockRecord::query()->updateOrCreate([
|
||||
'sku_id' => $sku['id'],
|
||||
'day' => $today,
|
||||
], [
|
||||
"inventory" => $sku['inventory'],
|
||||
"inventory_time" => $dateTime,
|
||||
"batch_number" => $batchNumber
|
||||
]);
|
||||
}
|
||||
$costLogs = [];
|
||||
//更新库存并记录数据
|
||||
foreach ($inventoryKeyBySkuIdMap as $skuId => $realStock) {
|
||||
//库存修改 盘点是直接覆盖
|
||||
$skuData = GoodsSku::query()->where('id', $skuId)->first();
|
||||
if (!empty($skuData)) {
|
||||
$costLogs[] = static::addStockLog($skuData
|
||||
, TargetTypeEnum::INVENTORY, ['stock' => $realStock]);
|
||||
$skuData->stock = $realStock;
|
||||
$skuData->save();
|
||||
$updateIds[] = $skuId;
|
||||
}
|
||||
|
||||
}
|
||||
$log = new LogModel();
|
||||
$log->batchInsert($costLogs);
|
||||
DB::commit();
|
||||
} catch (\Exception $exception) {
|
||||
DB::rollBack();
|
||||
Log::error("库存盘点异常", ["error" => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
// 批量更新
|
||||
event(new BatchStockUpdateEvent($updateIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 库存盘点 需要扣减未发货未取消的订单数据
|
||||
* 目前只查询了7日内的数据
|
||||
* @param array $skusWithCombinationGoods
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function handleSkusWithCombinationGoods(array $skusWithCombinationGoods)
|
||||
{
|
||||
//查询sku当前未发货的数量 需要扣减
|
||||
$externalSkuIds = collect($skusWithCombinationGoods)->pluck("external_sku_id")->toArray();
|
||||
//默认只查15天内未发货的数据
|
||||
$startTime = Carbon::now()->subDays(15)->startOfDay()->toDateTimeString();
|
||||
$unshippedDataCollect = BusinessOrderItem::query()
|
||||
->leftJoin("business_orders as b", "business_order_id", "=", "b.id")
|
||||
->select("external_sku_id", DB::raw("sum(goods_number) as goods_total"), DB::raw("sum(already_cancel_number) as cancel_total"))
|
||||
->whereIn("external_sku_id", $externalSkuIds)->where("b.shipping_status", "=", 0)
|
||||
->where("business_order_items.created_at", ">=", $startTime)->where("business_order_items.cancel_status", "=", 0)
|
||||
->groupBy('external_sku_id')->get()->toArray();
|
||||
$unshippedData = collect($unshippedDataCollect)->pluck(null, "external_sku_id")->toArray();
|
||||
Log::info("15日内未发货数据", $unshippedData);
|
||||
return collect($skusWithCombinationGoods)->map(function ($v) use ($unshippedData) {
|
||||
$v['real_stock'] = $v['inventory'] ?? null;
|
||||
if (!empty($unshippedData[$v['external_sku_id']]) && isset($v['inventory'])) {
|
||||
$v['real_stock'] = $v['inventory'] - $unshippedData[$v['external_sku_id']]['goods_total']
|
||||
+ $unshippedData[$v['external_sku_id']]['cancel_total'];
|
||||
|
||||
}
|
||||
return $v;
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
|
||||
public static function computeSkuStock(array $goodsSkuItem, array $changeData, $targetType = TargetTypeEnum::LOSS)
|
||||
{
|
||||
$updateIds = [];
|
||||
$updateParams = [];
|
||||
//添加系统日志
|
||||
$costLogs = [];
|
||||
// 成本
|
||||
if (empty($goodsSkuItem['is_combination'])) {
|
||||
$updateParam = [
|
||||
'stock' => $goodsSkuItem['stock'] + $changeData['num'],
|
||||
'sale_stock' => max($goodsSkuItem['sale_stock'] + $changeData['num'], 0),
|
||||
];
|
||||
|
||||
if ($targetType == TargetTypeEnum::PURCHASE) {
|
||||
$updateParam['cost'] = $changeData['cost'];
|
||||
}
|
||||
if ($updateParam['sale_stock'] <= 0) {
|
||||
$updateParam['status'] = GoodsSku::$STATUS_DOWN;
|
||||
}
|
||||
GoodsSku::query()->where('external_sku_id', "=", $goodsSkuItem['external_sku_id'])
|
||||
->update($updateParam);
|
||||
$updateIds[] = $goodsSkuItem['id'];
|
||||
$updateParams[] = $updateParam;
|
||||
$costLogs[] = static::addStockLog($goodsSkuItem, $targetType, $updateParam);
|
||||
|
||||
} else {
|
||||
$combinationGood = CombinationGood::query()->with('goodsSkuItem:id,stock,sale_stock')
|
||||
->where('goods_sku_id', $goodsSkuItem['id'])->get();
|
||||
|
||||
foreach ($combinationGood as $item) {
|
||||
$updateParam = [
|
||||
'stock' => $item['goodsSkuItem']['stock'] + $changeData['num'] * $item['item_num'],
|
||||
'sale_stock' => max($item['goodsSkuItem']['sale_stock'] + $changeData['num'] * $item['item_num'], 0),
|
||||
];
|
||||
if ($updateParam['sale_stock'] <= 0) {
|
||||
$updateParam['status'] = GoodsSku::$STATUS_DOWN;
|
||||
}
|
||||
GoodsSku::query()->where('id', $item['goodsSkuItem']['id'])->update($updateParam);
|
||||
|
||||
$updateIds[] = $item['goodsSkuItem']['id'];
|
||||
$updateParams[] = $updateParam;
|
||||
$costLogs[] = static::addStockLog($item['goodsSkuItem'], $targetType, $updateParam);
|
||||
}
|
||||
}
|
||||
$log = new LogModel();
|
||||
$log->batchInsert($costLogs);
|
||||
Log::info("本次请求更新参数", $updateParams);
|
||||
return $updateIds;
|
||||
}
|
||||
|
||||
public static function addStockLog($goodsSkuItem, $targetType = TargetTypeEnum::LOSS, $updateParam)
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$costLog = [
|
||||
'module' => 'goods',
|
||||
'action' => "POST",
|
||||
'target_type' => $targetType,
|
||||
'target_id' => $goodsSkuItem['id'] ?? 0,
|
||||
'user_id' => $userId ?? 999,
|
||||
"target_field" => "stock"
|
||||
];
|
||||
$costLog['before_update'] = json_encode($goodsSkuItem);
|
||||
$costLog['after_update'] = json_encode($updateParam);
|
||||
|
||||
return $costLog;
|
||||
}
|
||||
|
||||
}
|
||||
410
app/Services/Statistic/SaleDataService.php
Normal file
410
app/Services/Statistic/SaleDataService.php
Normal file
@ -0,0 +1,410 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Statistic;
|
||||
|
||||
use App\Events\BatchStockUpdateEvent;
|
||||
use App\Http\Enum\CacheKeyEnum;
|
||||
use App\Http\Enum\StaticTypeEnum;
|
||||
use App\Models\BusinessOrderItem;
|
||||
use App\Models\CombinationGood;
|
||||
use App\Models\DailyStockRecord;
|
||||
use App\Models\GoodsSku;
|
||||
use App\Models\LossRecords;
|
||||
use App\Utils\DateTimeUtils;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class SaleDataService
|
||||
{
|
||||
/**
|
||||
* sku维度的统计数据
|
||||
*/
|
||||
public static function saleStatistics(Request $request)
|
||||
{
|
||||
if (StaticTypeEnum::TODAY == $request->type) {
|
||||
//实时统计 sku维度
|
||||
return static::skuSaleStatisticsByToday($request);
|
||||
} else {
|
||||
//历史数据查询
|
||||
return static::skuSaleStatisticsByHistory($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sku维度 今日实时统计
|
||||
*/
|
||||
public static function skuSaleStatisticsByToday(Request $request)
|
||||
{
|
||||
[$startTime, $endTime] = static::getTimeRange($request);
|
||||
$build = BusinessOrderItem::query();
|
||||
if (!empty($request->sku_id)) {
|
||||
$externalSkuId = GoodsSku::query()->where("id", "=", $request->sku_id)
|
||||
->pluck("external_sku_id")->first();
|
||||
if (!empty($externalSkuId)) {
|
||||
$build->where("external_sku_id", "=", $externalSkuId);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
$orderItems = $build
|
||||
->leftJoin("business_orders as b", "business_order_id", "=", "b.id")
|
||||
->select("business_order_items.external_sku_id"
|
||||
, DB::raw("sum(CASE WHEN b.shipping_status>0 THEN goods_number-already_cancel_number ELSE 0 END) as shipping_num")
|
||||
, DB::raw("sum(CASE WHEN b.shipping_status=0 THEN goods_number-already_cancel_number ELSE 0 END) as unshipping_num")
|
||||
, DB::raw("sum(goods_number-already_cancel_number) as goods_total")
|
||||
, DB::raw("ROUND(sum(goods_amount) / 100,2) as goods_total_amount"))
|
||||
->whereBetween("business_order_items.created_at", [$startTime, $endTime])
|
||||
->where("external_sku_id", "!=", "")
|
||||
->where("business_order_items.cancel_status", "=", 0)
|
||||
->groupBy('external_sku_id')
|
||||
->orderBy("goods_total", "DESC")
|
||||
->paginate($request->get('per_page'));
|
||||
|
||||
if (!empty($orderItems->items())) {
|
||||
$externalSkuIds = collect($orderItems->items())->pluck("external_sku_id")->toArray();
|
||||
$goodsSkus = GoodsSku::query()->whereIn("external_sku_id", $externalSkuIds)
|
||||
->select("id", "title", "name", "stock", "sale_stock", "status", "external_sku_id")->get()
|
||||
->pluck(null, "id")->toArray();
|
||||
return static::addSaleDataToGoodsSku($goodsSkus, $orderItems);
|
||||
}
|
||||
return $orderItems;
|
||||
}
|
||||
|
||||
public static function skuSaleStatisticsByHistory(Request $request)
|
||||
{
|
||||
[$startTime, $endTime] = static::getTimeRange($request);
|
||||
$build = DailyStockRecord::query();
|
||||
if (!empty($request->sku_id)) {
|
||||
$build->where("sku_id", "=", $request->sku_id);
|
||||
}
|
||||
$dailyRecord = $build->select("sku_id", DB::raw("sum(order_goods_num) as goods_total")
|
||||
, DB::raw("sum(order_total_amount) as goods_total_amount"))
|
||||
->whereBetween("created_at", [$startTime, $endTime])
|
||||
->groupBy("sku_id")
|
||||
->having(DB::raw("sum(order_goods_num)"), ">", 0)
|
||||
->orderBy("goods_total", "DESC")
|
||||
->paginate($request->get('per_page'));
|
||||
$skuIds = collect($dailyRecord->items())->pluck('sku_id')->toArray();
|
||||
$goodsSkusMapKeyBySkuId = GoodsSku::query()->select("id", "title", "name", "stock", "sale_stock"
|
||||
, "status", "external_sku_id")->whereIn("id", $skuIds)
|
||||
->get()->pluck(null, "id")->toArray();
|
||||
$dailyRecord->getCollection()->map(function ($v) use ($goodsSkusMapKeyBySkuId) {
|
||||
if (!empty($goodsSkusMapKeyBySkuId[$v['sku_id']])) {
|
||||
foreach ($goodsSkusMapKeyBySkuId[$v['sku_id']] as $key => $val) {
|
||||
$v->$key = $val;
|
||||
}
|
||||
} else {
|
||||
//出现异常的skuid
|
||||
$v->title = "未知商品";
|
||||
$v->name = "未知商品";
|
||||
$v->stock = 0;
|
||||
$v->sale_stock = 0;
|
||||
$v->status = "下架";
|
||||
$v->id = 0;
|
||||
}
|
||||
});
|
||||
return $dailyRecord;
|
||||
}
|
||||
|
||||
public static function addSaleDataToGoodsSku($goodsSku, $orderItems)
|
||||
{
|
||||
$skuIds = collect($goodsSku)->pluck("id")->toArray();
|
||||
//查询8天内-昨天的数据
|
||||
$startTime = Carbon::now()->subDays(8)->startOfDay()->toDateTimeString();
|
||||
$endTime = Carbon::yesterday()->endOfDay()->toDateTimeString();
|
||||
$dailyRecord = DailyStockRecord::query()->whereIn("sku_id", $skuIds)
|
||||
->whereBetween("day", [$startTime, $endTime])
|
||||
->get()->toArray();
|
||||
$dailyRecordGroupBySkuId = collect($dailyRecord)->groupBy("sku_id")->toArray();
|
||||
Log::info("dailyRecordGroupBySkuId", $dailyRecordGroupBySkuId);
|
||||
$combineGoodsSkus = collect($goodsSku)->map(function ($v) use ($dailyRecordGroupBySkuId, $orderItems) {
|
||||
$v['yesterday_avg_num'] = round(collect($dailyRecordGroupBySkuId[$v['id']] ?? [])->sortByDesc("day")
|
||||
->take(1)->avg("order_goods_num") ?? 0, 2);
|
||||
$v['three_day_avg_num'] = round(collect($dailyRecordGroupBySkuId[$v['id']] ?? [])->sortByDesc("day")
|
||||
->take(3)->avg("order_goods_num") ?? 0, 2);
|
||||
$v['seven_day_avg_num'] = round(collect($dailyRecordGroupBySkuId[$v['id']] ?? [])->sortByDesc("day")
|
||||
->take(7)->avg("order_goods_num") ?? 0, 2);
|
||||
return $v;
|
||||
})->pluck(null, "external_sku_id")->toArray();
|
||||
Log::info("combineGoodsSkus", $combineGoodsSkus);
|
||||
$orderItems->getCollection()->map(function ($v) use ($combineGoodsSkus) {
|
||||
if (!empty($combineGoodsSkus[$v['external_sku_id']])) {
|
||||
foreach ($combineGoodsSkus[$v['external_sku_id']] as $key => $val) {
|
||||
$v->$key = $val;
|
||||
}
|
||||
} else {
|
||||
//出现异常售卖的编码
|
||||
$v->title = "未知商品";
|
||||
$v->name = "未知商品";
|
||||
$v->stock = 0;
|
||||
$v->sale_stock = 0;
|
||||
$v->status = "下架";
|
||||
$v->yesterday_avg_num = 0;
|
||||
$v->three_day_avg_num = 0;
|
||||
$v->id = 0;
|
||||
$v->seven_day_avg_num = 0;
|
||||
}
|
||||
});
|
||||
return $orderItems;
|
||||
}
|
||||
|
||||
public static function spuSaleStatistics(Request $request)
|
||||
{
|
||||
//spu 基本就是全统计了
|
||||
if (StaticTypeEnum::TODAY == $request->type) {
|
||||
return static::spuSaleStatisticsByToday($request);
|
||||
} else {
|
||||
//统计历史数据 这里走缓存
|
||||
return static::spuSaleStatisticsByHistoryCache($request);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getTimeRange(Request $request)
|
||||
{
|
||||
if (!empty($request->input("start_time")) && !empty($request->input("start_time"))) {
|
||||
$startTime = Carbon::parse($request->input("start_time"))->toDateTimeString();
|
||||
$endTime = Carbon::parse($request->input("end_time"))->toDateTimeString();
|
||||
} else {
|
||||
$startTime = Carbon::parse($request->input("start_day"))->toDateTimeString();
|
||||
$endTime = Carbon::parse($request->input("end_day"))->endOfDay()->toDateTimeString();
|
||||
}
|
||||
return [$startTime, $endTime];
|
||||
}
|
||||
|
||||
public static function spuSaleStatisticsByToday(Request $request)
|
||||
{
|
||||
[$startTime, $endTime] = static::getTimeRange($request);
|
||||
//实时统计 sku维度
|
||||
$orderItems = BusinessOrderItem::query()
|
||||
->leftJoin("business_orders as b", "business_order_id", "=", "b.id")
|
||||
->select("business_order_items.external_sku_id"
|
||||
, DB::raw("sum(CASE WHEN b.shipping_status>0 THEN goods_number-already_cancel_number ELSE 0 END) as shipping_num")
|
||||
, DB::raw("sum(CASE WHEN b.shipping_status=0 THEN goods_number-already_cancel_number ELSE 0 END) as unshipping_num")
|
||||
, DB::raw("sum(goods_number-already_cancel_number) as goods_total")
|
||||
, DB::raw("ROUND(sum(goods_amount) / 100,2) as goods_total_amount"))
|
||||
->where('b.confirm_at', '>=', Carbon::parse($startTime)->getPreciseTimestamp(3))
|
||||
->where('b.confirm_at', '<=', Carbon::parse($endTime)->getPreciseTimestamp(3))
|
||||
->where("external_sku_id", "!=", "")
|
||||
->where("business_order_items.cancel_status", "=", 0)
|
||||
->groupBy('external_sku_id')->get()->toArray();
|
||||
|
||||
$externalSkuIds = collect($orderItems)->pluck("external_sku_id")->toArray();
|
||||
$goodsSkus = GoodsSku::query()
|
||||
->with([
|
||||
'combinationGoods:id,goods_sku_id,item_id,item_num',
|
||||
'combinationGoods.goodsSkuItem:id,name,goods_id,title,stock,sale_stock,external_sku_id,updated_at,yesterday_num,reference_price,status',
|
||||
])
|
||||
->whereIn("external_sku_id", $externalSkuIds)->get()->pluck(null, "external_sku_id")
|
||||
->toArray();
|
||||
$skus = [];
|
||||
//组合商品
|
||||
foreach ($orderItems as $orderItem) {
|
||||
$sku = $goodsSkus[$orderItem['external_sku_id']] ?? [];
|
||||
if (!empty($sku['is_combination'])) {
|
||||
foreach ($sku['combination_goods'] as $combinationGood) {
|
||||
$skuItem = $goodsSkus[$combinationGood['goods_sku_item']['external_sku_id']] ?? [];
|
||||
$skuItem['shipping_num'] = $skuItem['shipping_num'] ?? 0 + $orderItem['shipping_num'] * $combinationGood['item_num'];
|
||||
$skuItem['unshipping_num'] = $skuItem['unshipping_num'] ?? 0 + $orderItem['unshipping_num'] * $combinationGood['item_num'];
|
||||
$skuItem['goods_total'] = $skuItem['goods_total'] ?? 0 + $orderItem['goods_total'] * $combinationGood['item_num'];
|
||||
$skuItem['goods_total_amount'] = $skuItem['goods_total_amount'] ?? 0 + $orderItem['goods_total_amount'] * $combinationGood['item_num'];
|
||||
$skus[$combinationGood['goods_sku_item']['external_sku_id']] = $skuItem;
|
||||
}
|
||||
} else {
|
||||
$skuItem = $skus[$orderItem['external_sku_id']] ?? [];
|
||||
$skuItem['shipping_num'] = $skuItem['shipping_num'] ?? 0 + $orderItem['shipping_num'];
|
||||
$skuItem['unshipping_num'] = $skuItem['unshipping_num'] ?? 0 + $orderItem['unshipping_num'];
|
||||
$skuItem['goods_total'] = $skuItem['goods_total'] ?? 0 + $orderItem['goods_total'];
|
||||
$skuItem['goods_total_amount'] = $skuItem['goods_total_amount'] ?? 0 + $orderItem['goods_total_amount'];
|
||||
$skus[$orderItem['external_sku_id']] = $skuItem;
|
||||
}
|
||||
}
|
||||
$goodsSkuWithTypes = GoodsSku::query()
|
||||
->Join("goods", "goods_id", "=", "goods.id")
|
||||
->Join("goods_types", "goods.type_id", "=", "goods_types.id")
|
||||
->whereIn("external_sku_id", array_keys($skus))
|
||||
->select("goods_skus.id", "goods_types.id as type_id", "goods_types.name", "external_sku_id", "stock", "sale_stock")
|
||||
->get()->toArray();
|
||||
|
||||
return collect($goodsSkuWithTypes)->map(function ($v) use ($skus) {
|
||||
if (!empty($skus[$v['external_sku_id']])) {
|
||||
return array_merge($v, $skus[$v['external_sku_id']]);
|
||||
}
|
||||
})->filter()->values()->groupBy('type_id')->map(function ($v, $key) {
|
||||
return [
|
||||
"type_id" => $key,
|
||||
"type_name" => $v[0]['name'] ?? '',
|
||||
"stock" => $v->sum("stock"),
|
||||
"sale_stock" => $v->sum("sale_stock"),
|
||||
"shipping_num" => $v->sum("shipping_num"),
|
||||
"unshipping_num" => $v->sum("unshipping_num"),
|
||||
"goods_total" => $v->sum("goods_total"),
|
||||
"goods_total_amount" => $v->sum("goods_total_amount"),
|
||||
];
|
||||
})->sortByDesc('goods_total')->values()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过历史报表统计spu数据-缓存
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public
|
||||
static function spuSaleStatisticsByHistoryCache(Request $request)
|
||||
{
|
||||
[$startTime, $endTime] = static::getTimeRange($request);
|
||||
$cacheKey = CacheKeyEnum::SPU_STATISTIC_BY_DATE . $request->input("start_day") . "_" . $request->input("end_day");
|
||||
$expireTime = Carbon::now()->addHour();
|
||||
return Cache::remember($cacheKey, $expireTime, function () use ($startTime, $endTime) {
|
||||
return static::spuSaleStatisticsByHistory($startTime, $endTime);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过历史报表统计spu数据
|
||||
* @param $startTime
|
||||
* @param $endTime
|
||||
* @return array
|
||||
*/
|
||||
public static function spuSaleStatisticsByHistory($startTime, $endTime)
|
||||
{
|
||||
$dailyAllRecord = DailyStockRecord::query()
|
||||
->select("sku_id", DB::raw("sum(order_goods_num) as goods_total")
|
||||
, DB::raw("sum(order_total_amount) as goods_total_amount"))
|
||||
->whereBetween("day", [$startTime, $endTime])
|
||||
->groupBy("sku_id")
|
||||
->having(DB::raw("sum(order_goods_num)"), ">", 0)
|
||||
->get()->toArray();
|
||||
$skuIds = collect($dailyAllRecord)->pluck('sku_id')->toArray();
|
||||
$goodsSkus = GoodsSku::query()
|
||||
->with([
|
||||
'combinationGoods:id,goods_sku_id,item_id,item_num'
|
||||
])
|
||||
->whereIn("id", $skuIds)->get()->pluck(null, "id")
|
||||
->toArray();
|
||||
$skus = [];
|
||||
//组合商品需要分散到sku维度进行统计
|
||||
foreach ($dailyAllRecord as $skuRecord) {
|
||||
$sku = $goodsSkus[$skuRecord['sku_id']] ?? [];
|
||||
if (!empty($sku['is_combination'])) {
|
||||
foreach ($sku['combination_goods'] as $combinationGood) {
|
||||
$skuItem = $goodsSkus[$combinationGood['item_id']] ?? [];
|
||||
$skuItem['goods_total'] = $skuItem['goods_total'] ?? 0 + $skuRecord['goods_total'] * $combinationGood['item_num'];
|
||||
$skuItem['goods_total_amount'] = $skuItem['goods_total_amount'] ?? 0 + $skuRecord['goods_total_amount'] * $combinationGood['item_num'];
|
||||
$skus[$combinationGood['item_id']] = $skuItem;
|
||||
}
|
||||
} else {
|
||||
$skuItem = $skus[$skuRecord['sku_id']] ?? [];
|
||||
$skuItem['goods_total'] = $skuItem['goods_total'] ?? 0 + $skuRecord['goods_total'];
|
||||
$skuItem['goods_total_amount'] = $skuItem['goods_total_amount'] ?? 0 + $skuRecord['goods_total_amount'];
|
||||
$skus[$skuRecord['sku_id']] = $skuItem;
|
||||
}
|
||||
}
|
||||
$goodsSkuWithTypes = GoodsSku::query()
|
||||
->Join("goods", "goods_id", "=", "goods.id")
|
||||
->Join("goods_types", "goods.type_id", "=", "goods_types.id")
|
||||
->select("goods_skus.id", "goods_types.id as type_id", "goods_types.name", "external_sku_id", "stock", "sale_stock")
|
||||
->whereIn("goods_skus.id", array_keys($skus))
|
||||
->get()->toArray();
|
||||
|
||||
return collect($goodsSkuWithTypes)->map(function ($v) use ($skus) {
|
||||
if (!empty($skus[$v['id']])) {
|
||||
return array_merge($v, $skus[$v['id']]);
|
||||
}
|
||||
})->filter()->values()->groupBy('type_id')->map(function ($v, $key) {
|
||||
return [
|
||||
"type_id" => $key,
|
||||
"type_name" => $v[0]['name'] ?? '',
|
||||
"stock" => $v->sum("stock"),
|
||||
"sale_stock" => $v->sum("sale_stock"),
|
||||
"goods_total" => $v->sum("goods_total"),
|
||||
"goods_total_amount" => $v->sum("goods_total_amount"),
|
||||
];
|
||||
})->sortByDesc('goods_total')->values()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* gmv 统计
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public static function gmvStatistics(Request $request)
|
||||
{
|
||||
if (StaticTypeEnum::TODAY == $request->type) {
|
||||
[$startTime, $endTime] = static::getTimeRange($request);
|
||||
$build = BusinessOrderItem::query();
|
||||
if (!empty($request->sku_id)) {
|
||||
$externalSkuId = GoodsSku::query()->where("id", "=", $request->sku_id)
|
||||
->pluck("external_sku_id")->first();
|
||||
if (!empty($externalSkuId)) {
|
||||
$build->where("external_sku_id", "=", $externalSkuId);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
$orderItems = $build->select("business_order_items.external_sku_id"
|
||||
, "goods_number", "already_cancel_number", "goods_amount", "created_at")
|
||||
->whereBetween("business_order_items.created_at", [$startTime, $endTime])
|
||||
->where("business_order_items.cancel_status", "=", 0)
|
||||
->get()->toArray();
|
||||
$interval = $request->input("interval", 30);
|
||||
return collect($orderItems)->groupBy(function ($v) use ($startTime, $interval) {
|
||||
$diff = Carbon::parse($v['created_at'])->diffInMinutes(Carbon::parse($startTime));
|
||||
return (int)floor($diff / $interval);
|
||||
})->map(function ($v, $key) use ($startTime, $interval) {
|
||||
return [
|
||||
"sort_key" => $key,
|
||||
"interval" => $interval,
|
||||
"time_start" => Carbon::parse($startTime)->addMinutes($key * $interval)->toTimeString(),
|
||||
"time_end" => Carbon::parse($startTime)->addMinutes(($key + 1) * $interval)->toTimeString(),
|
||||
"goods_total" => $v->sum("goods_number") - $v->sum("already_cancel_number"),
|
||||
"goods_total_amount" => round($v->sum("goods_amount") / 100, 2),
|
||||
];
|
||||
})->sort()->values()->toArray();
|
||||
} else {
|
||||
//gmv 统计历史数据
|
||||
[$startTime, $endTime] = static::getTimeRange($request);
|
||||
$build = DailyStockRecord::query();
|
||||
if (!empty($request->sku_id)) {
|
||||
$build->where("sku_id", "=", $request->sku_id);
|
||||
}
|
||||
return $build->select("day", DB::raw("sum(order_total_amount) as goods_total_amount")
|
||||
, DB::raw("sum(order_goods_num) as goods_total"))
|
||||
->whereBetween("day", [$startTime, $endTime])
|
||||
->groupBy("day")->orderBy("day")
|
||||
->get()->toArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 报损统计
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public static function lossRecordStatistics(Request $request)
|
||||
{
|
||||
$startTime = Carbon::parse($request->input("start_time"))->toDateTimeString();
|
||||
$endTime = Carbon::parse($request->input("end_time"))->toDateTimeString();
|
||||
$build = LossRecords::query();
|
||||
if (!empty($request->sku_id)) {
|
||||
$externalSkuId = GoodsSku::query()->where("id", "=", $request->sku_id)
|
||||
->pluck("external_sku_id")->first();
|
||||
if (!empty($externalSkuId)) {
|
||||
$build->where("external_sku_id", "=", $externalSkuId);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return $build->select("date", DB::raw("sum(num) as total_num")
|
||||
, DB::raw("sum(num*cost) as total_loss_amount"))
|
||||
->whereBetween("date", [$startTime, $endTime])
|
||||
->groupBy("date")->orderBy("date")
|
||||
->get()->toArray();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DateTimeUtils
|
||||
{
|
||||
/**
|
||||
@ -42,4 +44,28 @@ class DateTimeUtils
|
||||
|
||||
return (int)ceil($time);
|
||||
}
|
||||
|
||||
|
||||
public static function validateDate($date, $format = 'Y-m-d')
|
||||
{
|
||||
$d = \DateTime::createFromFormat($format, $date);
|
||||
return $d && $d->format($format) === $date;
|
||||
}
|
||||
|
||||
public static function excelUploadDateToString($excelData, $defaultTime, $format = "Y-m-d")
|
||||
{
|
||||
|
||||
try {
|
||||
$time = ($excelData - 25569) * 24 * 3600;
|
||||
if ($format == "Y-m-d H:i:s") {
|
||||
$time = $time - 8 * 3600;
|
||||
}
|
||||
return date($format, $time);
|
||||
} catch (\Exception $exception) {
|
||||
Log::error("时间转化出错", [$exception->getMessage()]);
|
||||
}
|
||||
return $defaultTime;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
44
app/Utils/GeneratorUtils.php
Normal file
44
app/Utils/GeneratorUtils.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use App\Utils\NumberUtils;
|
||||
use Yeepay\Yop\Sdk\Utils\Http\HttpUtils;
|
||||
|
||||
class GeneratorUtils
|
||||
{
|
||||
|
||||
public static function generateBatchNumber($type = "add")
|
||||
{
|
||||
$code = "A";//批量添加
|
||||
if ($type != 1) {
|
||||
$code = "I";//导入
|
||||
}
|
||||
return $code.date("YmdHis") . rand(1000, 10000);
|
||||
}
|
||||
|
||||
public static function generateCombinationGoodNumber($goods)
|
||||
{
|
||||
$code = "";
|
||||
foreach ($goods as $v){
|
||||
$code.=static::getChCode($v['item_id'])."Z".static::getChCode($v['item_num'])."Z";
|
||||
}
|
||||
rtrim($code,"Z");
|
||||
return $code;
|
||||
}
|
||||
/**
|
||||
* 获取非z的字符串
|
||||
* @param $intValue
|
||||
* @return string
|
||||
*/
|
||||
public static function getChCode($intValue)
|
||||
{
|
||||
$ch = range('A', 'Y');
|
||||
$result = '';
|
||||
while ($intValue) {
|
||||
$result = $ch[$intValue % 25] . $result;
|
||||
$intValue = intval($intValue / 25);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
41
app/Utils/RedisLockUtils.php
Normal file
41
app/Utils/RedisLockUtils.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use App\Exceptions\ServiceException;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class RedisLockUtils
|
||||
{
|
||||
private static $prefix = 'lock';
|
||||
|
||||
public static function getKey($keyType, $extend = '')
|
||||
{
|
||||
return collect([
|
||||
self::$prefix,
|
||||
$keyType,
|
||||
$extend
|
||||
])->filter()->implode(':');
|
||||
}
|
||||
|
||||
public static function getLock($lockKey, $expireSeconds = 1, $throwException = false)
|
||||
{
|
||||
$lock = Redis::setnx($lockKey, 1);
|
||||
if (!$lock) {
|
||||
if ($throwException) {
|
||||
throw new ServiceException('操作频繁');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Redis::expire($lockKey, $expireSeconds);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function deleteLock($lockKey)
|
||||
{
|
||||
return Redis::del($lockKey);
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@
|
||||
"laravel/framework": "^6.20.26",
|
||||
"laravel/tinker": "^2.5",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"predis/predis": "^2.2",
|
||||
"spatie/laravel-permission": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
69
composer.lock
generated
69
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "037b06c1b26399725a1d9c0687402942",
|
||||
"content-hash": "964631bbee47f895975146a783331c50",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aliyuncs/oss-sdk-php",
|
||||
@ -2587,6 +2587,73 @@
|
||||
],
|
||||
"time": "2022-07-30T15:51:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "predis/predis",
|
||||
"version": "v2.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/predis/predis.git",
|
||||
"reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1",
|
||||
"reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.3",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^8.0 || ~9.4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Predis\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Till Krüss",
|
||||
"homepage": "https://till.im",
|
||||
"role": "Maintainer"
|
||||
}
|
||||
],
|
||||
"description": "A flexible and feature-complete Redis client for PHP.",
|
||||
"homepage": "http://github.com/predis/predis",
|
||||
"keywords": [
|
||||
"nosql",
|
||||
"predis",
|
||||
"redis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/predis/predis/issues",
|
||||
"source": "https://github.com/predis/predis/tree/v2.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/tillkruss",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-13T16:42:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.1.1",
|
||||
|
||||
@ -52,6 +52,7 @@ return [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => 'debug',
|
||||
'days' => 14,
|
||||
"permission" => 0777
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
|
||||
@ -61,7 +61,8 @@ class CreateBusinessOrdersTable extends Migration
|
||||
// 索引
|
||||
$table->unique(['shop_id', 'order_sn']);
|
||||
$table->index(['shop_id', 'participate_no']);
|
||||
$table->index(['shop_id', 'confirm_at', 'after_sales_status', 'cancel_status', 'is_supplier']);
|
||||
$table->index(['shop_id', 'confirm_at', 'after_sales_status', 'cancel_status', 'is_supplier']
|
||||
,"shop_id_confirm_at_composite_index");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePurchaseRecordsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('purchase_records', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('external_sku_id',60)->comment('唯一sku标识');
|
||||
$table->string('batch_number',60)->nullable()->comment('批次号');
|
||||
$table->date('date')->nullable()->comment('日期');;
|
||||
$table->Integer('num')->default(0)->comment('采购数量');
|
||||
$table->unsignedDecimal('cost')->default(0)->comment('成本');
|
||||
$table->Integer('buyer_user_id')->default(0)->comment('购买人用户id');;
|
||||
$table->string('buyer_name')->nullable()->comment('采购人');
|
||||
$table->Integer('check_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('external_sku_id');
|
||||
$table->index('created_at');
|
||||
$table->index('batch_number');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('purchase_records');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateLossRecordsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('loss_records', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('external_sku_id',60)->comment('唯一sku标识');
|
||||
$table->string('batch_number',60)->nullable()->comment('批次号');
|
||||
$table->date('date')->nullable()->comment('日期');
|
||||
$table->Integer('num')->default(0)->comment('报损数量');
|
||||
$table->unsignedDecimal('cost')->default(0)->comment('成本');
|
||||
$table->Integer('buyer_user_id')->default(0)->comment('购买人用户id');;
|
||||
$table->string('buyer_name')->nullable()->comment('采购人');
|
||||
$table->string('reason')->nullable()->comment('报损原因');
|
||||
$table->string('phenomenon')->nullable()->comment('报损现象');
|
||||
|
||||
// 索引
|
||||
$table->index('external_sku_id');
|
||||
$table->index('created_at');
|
||||
$table->index('batch_number');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('loss_records');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateWebsiteMessagesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('website_messages', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('title')->comment('消息内容标题');
|
||||
$table->string('content')->comment('消息内容');
|
||||
$table->string('type',60)->comment('消息类型');
|
||||
$table->string('unique_key',100)->comment('类型下唯一的key避免重复写入');
|
||||
$table->Integer('role_id')->nullable()->comment('角色id');
|
||||
$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();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('website_messages');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSuppliersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('suppliers', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('supplier_name',100)->comment('供应商名称');
|
||||
$table->string('company_name',100)->nullable()->comment('公司名称');
|
||||
$table->string('address')->nullable()->comment('地址');
|
||||
$table->string('link_tel',100)->nullable()->comment('联系方式');
|
||||
$table->string('payment_account',100)->nullable()->comment('支付方式');
|
||||
$table->string('supply_type')->nullable()->comment('供应类型');
|
||||
$table->string('agent_name')->nullable()->comment('开发维护人');
|
||||
$table->Integer('agent_id')->nullable()->comment('开发维护人id');
|
||||
|
||||
$table->index('supplier_name');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('suppliers');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddSaleStockAndQualityPeriodToGoodsSkusTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasColumns('goods_skus', ['sale_stock', 'quality_period'])) {
|
||||
return;
|
||||
}
|
||||
Schema::table('goods_skus', function (Blueprint $table) {
|
||||
//
|
||||
$table->integer('sale_stock')->default(0)->comment("在售库存数");
|
||||
$table->integer('quality_period')->nullable()->comment("保质期时间,单位天");
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('goods_skus', function (Blueprint $table) {
|
||||
//
|
||||
$table->dropColumn('sale_stock');
|
||||
$table->dropColumn('quality_period');
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddOrderTotalAmountToDailyStockRecord extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasColumns('daily_stock_records', ['order_total_amount',"batch_number"])) {
|
||||
return;
|
||||
}
|
||||
Schema::table('daily_stock_records', function (Blueprint $table) {
|
||||
$table->decimal('order_total_amount')->default(0)->comment('订单总金额');
|
||||
$table->string('batch_number',60)->nullable()->comment('批次号');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if (Schema::hasColumns('daily_stock_records', ['order_total_amount',"batch_number"])) {
|
||||
return;
|
||||
}
|
||||
Schema::table('daily_stock_records', function (Blueprint $table) {
|
||||
//
|
||||
$table->dropColumn('order_total_amount');
|
||||
$table->dropColumn('batch_number');
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateBusinessAfterSaleOrders extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('business_after_sale_orders', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('after_sales_biz_sn',100)->comment('售后单编号');
|
||||
$table->string('order_sn',100)->comment('父单编号');
|
||||
$table->integer('shop_id')->comment('门店id');
|
||||
$table->integer('after_sales_status')->default(0)->comment('售后单状态
|
||||
0-未发起售后 1-退款中 2-退款成功 3-待处理 4-拒绝退款 6-待(顾客)退货 7-待(团长)确认退货 8-(顾客)撤销 9-(系统)关闭');
|
||||
$table->bigInteger('refund_amount')->default(0)->comment('退款金额');
|
||||
$table->bigInteger('refund_shipping_amount')->default(0)->comment('用户申请退运费金额');
|
||||
$table->string('description')->nullable()->comment('描述');
|
||||
$table->string('reason')->nullable()->comment('原因');
|
||||
$table->text('sub_extensions')->nullable()->comment('子单信息');
|
||||
$table->text('image_list')->nullable()->comment('图片列表');
|
||||
$table->text('return_goods_extension')->nullable()->comment('退款物流信息');
|
||||
$table->integer('apply_type')->default(0)->comment('售后单类型 0-仅退款 1-退货退款');
|
||||
$table->dateTime('after_sale_created_at')->nullable()->comment('售后单三方创建时间');
|
||||
$table->dateTime('after_sale_updated_at')->nullable()->comment('售后单三方更新时间');
|
||||
|
||||
$table->unique(["shop_id",'order_sn'],"unique_shop_id_order_sn");
|
||||
$table->index('order_sn');
|
||||
$table->index(['after_sales_biz_sn',"apply_type"],"index_biz_sn_apply_type");
|
||||
$table->index('after_sale_created_at');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('business_after_sale_orders');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddFieldsToGoodsTypes extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasColumns('goods_types', ['parent_id', 'show',"level"])) {
|
||||
return;
|
||||
}
|
||||
Schema::table('goods_types', function (Blueprint $table) {
|
||||
$table->integer('parent_id')->default(0)->comment('父id');
|
||||
$table->integer('show')->default(1)->comment('是否显示 0隐藏 1显示');
|
||||
$table->integer('level')->default(1)->comment('层级 目前仅记录使用 默认1');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('goods_types', function (Blueprint $table) {
|
||||
//
|
||||
$table->dropColumn('parent_id');
|
||||
$table->dropColumn('show');
|
||||
$table->dropColumn('level');
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class RemoveIndexToGoodsTypes extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
|
||||
Schema::table('goods_types', function (Blueprint $table) {
|
||||
$table->dropUnique('goods_types_name_unique');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('goods_types', function (Blueprint $table) {
|
||||
//
|
||||
$table->unique('name');
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAttributeToGoodsSkus extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasColumn('goods_skus', "attribute")) {
|
||||
return;
|
||||
}
|
||||
Schema::table('goods_skus', function (Blueprint $table) {
|
||||
|
||||
$table->string('attribute',100)->default("")->comment('属性名称');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
Schema::table('goods_skus', function (Blueprint $table) {
|
||||
$table->dropColumn("attribute");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddFieldToPurchaseRecordsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasColumns('purchase_records', ["arrived_time", "status","check_time"])) {
|
||||
return;
|
||||
}
|
||||
Schema::table('purchase_records', function (Blueprint $table) {
|
||||
$table->dateTime('arrived_time')->nullable()->comment('到货时间');
|
||||
$table->integer('status')->default(0)->comment('采购单状态 0待审核 1已审核 2审核失败');
|
||||
$table->dateTime('check_time')->nullable()->comment('审核时间');;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('purchase_records', function (Blueprint $table) {
|
||||
//
|
||||
$table->dropColumn('arrived_time');
|
||||
$table->dropColumn('status');
|
||||
$table->dropColumn('check_time');
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews -Indexes
|
||||
</IfModule>
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Handle Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
</IfModule>
|
||||
1
public/dist/css/107.fd5b2517.css
vendored
Normal file
1
public/dist/css/107.fd5b2517.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.searchBox[data-v-41a7827f]{display:flex;align-items:center;flex-wrap:wrap;white-space:nowrap}.searchBox .row[data-v-41a7827f]{font-size:14px;margin-bottom:20px;margin-right:15px;display:flex;align-items:center}.searchBox .time[data-v-41a7827f]{margin-left:20px;color:#999;font-size:12px}.opaBox[data-v-41a7827f]{margin-bottom:15px}
|
||||
1
public/dist/css/147.610fa777.css
vendored
Normal file
1
public/dist/css/147.610fa777.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.searchBox[data-v-6c4b71cd]{display:flex;align-items:center;flex-wrap:wrap;white-space:nowrap}.searchBox .row[data-v-6c4b71cd]{font-size:14px;margin-bottom:20px;margin-right:15px;display:flex;align-items:center}.imgBox .img[data-v-6c4b71cd]{width:55px;height:55px;border-radius:4px;margin:3px}
|
||||
1
public/dist/css/149.9f84b84a.css
vendored
1
public/dist/css/149.9f84b84a.css
vendored
@ -1 +0,0 @@
|
||||
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.aside-show[data-v-c25279e8]{transition:all .3s;opacity:0;width:0!important}.aside-hide[data-v-c25279e8]{transition:all .3s;opacity:1;width:200px!important}.el-container[data-v-c25279e8]{height:100vh}.el-aside[data-v-c25279e8]{background-color:#d3dce6;color:#333;overflow-x:hidden}.el-aside[data-v-c25279e8]::-webkit-scrollbar{width:8px}.el-aside[data-v-c25279e8]::-webkit-scrollbar-thumb{background-color:hsla(220,4%,58%,.3);border-radius:20px}.el-main[data-v-c25279e8]{background-color:#f0f2f5;color:#333;padding:0 0!important}.el-main[data-v-c25279e8]::-webkit-scrollbar{width:10px}.el-main[data-v-c25279e8]::-webkit-scrollbar-thumb{background-color:hsla(220,4%,58%,.3)}.box-card[data-v-c25279e8]{min-height:calc(100vh - 120px);margin:10px}.conent[data-v-c25279e8]{width:100%;min-height:calc(100vh - 200px);position:relative}.add[data-v-c25279e8]{cursor:pointer;font-size:25px;color:#606266}.head[data-v-c25279e8]{padding:10px;background-color:#fff;border-bottom:1px solid #f6f6f6;box-shadow:0 1px 4px rgba(0,21,41,.08)}.head ul[data-v-c25279e8]{display:flex;justify-content:space-between}.head ul li[data-v-c25279e8]{display:flex;align-items:center}.head ul li .right[data-v-c25279e8]{margin-left:20px}.head ul li .token[data-v-c25279e8]{cursor:pointer}.el-aside[data-v-c25279e8]{background:#282c34;box-shadow:2px 0 6px rgba(0,21,41,.35)}[data-v-c25279e8] .el-menu{border:none}.el-menu-item[data-v-c25279e8]:hover{outline:0!important;background:#5470c6!important;border-radius:5px!important}.el-menu-item.is-active[data-v-c25279e8]{color:#fff!important;background:#5470c6!important;border-radius:5px!important}.el-menu-item-group__title[data-v-c25279e8]{padding:0 0!important}
|
||||
1
public/dist/css/197.e8b8bfee.css
vendored
Normal file
1
public/dist/css/197.e8b8bfee.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.searchBox[data-v-825b4586]{display:flex;align-items:center;flex-wrap:wrap;white-space:nowrap;.row[data-v-825b4586]{font-size:14px;margin-bottom:20px;margin-right:15px;display:flex;align-items:center}}.opaBox[data-v-825b4586]{margin-bottom:15px}.btn[data-v-825b4586]{float:right}.commodityimg[data-v-825b4586]{width:59px;height:59px;background:hsla(0,0%,89%,.39);opacity:1;display:block;margin-right:12px}.Img[data-v-825b4586]{width:100%;height:100%}[data-v-825b4586] .flex .cell{display:flex;align-items:center}[data-v-825b4586] .btn11{padding:0;width:14px;height:14px}[data-v-825b4586] .btn11 img{width:100%;height:100%}.page[data-v-825b4586]{margin-top:20px}
|
||||
1
public/dist/css/199.fc892afb.css
vendored
Normal file
1
public/dist/css/199.fc892afb.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.searchBox[data-v-42163996]{display:flex;align-items:center;flex-wrap:wrap;white-space:nowrap}.searchBox .row[data-v-42163996]{font-size:14px;margin-bottom:20px;margin-right:15px;display:flex;align-items:center}.searchBox .time[data-v-42163996]{margin-left:20px;color:#999;font-size:12px}.echartBox[data-v-42163996]{width:100%;height:480px}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user