Compare commits
229 Commits
develop
...
hotfix/yjc
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c69014a12 | |||
| 0cd78ff136 | |||
| 2019a88fb9 | |||
| e850b3d336 | |||
| 968e5137a8 | |||
| fef0f10ade | |||
| 95b2182558 | |||
| 2eca516eb5 | |||
| c662130a13 | |||
| f88ae50f45 | |||
| 647adeefbe | |||
| c44ad62315 | |||
| 5673e6c19c | |||
| 36f9624754 | |||
| f70965aec1 | |||
| ff27d20316 | |||
| acd48764fa | |||
| c1016e8382 | |||
| 12bfcb0241 | |||
| 0b72923c4e | |||
| 855da74a9a | |||
| 43a1c491c1 | |||
| fbd286f80a | |||
| 582c1d5022 | |||
| 4263702e3f | |||
| fd00fec068 | |||
| 481042ac22 | |||
| 52424dc3cd | |||
| baa5c435b5 | |||
| fd26bc2568 | |||
| 1b06e308c8 | |||
| 96efa40eeb | |||
| 8840d1a719 | |||
| 114f4fb477 | |||
| 94ccd1e01c | |||
| d355d30583 | |||
| d1b2d06c6b | |||
| 5b73d0641e | |||
| cc24e05e1a | |||
| a72e1dd052 | |||
| 56bca0063a | |||
| 8164f21ab9 | |||
| deea4ea47e | |||
| b8a7b9372f | |||
| 5a58e4f144 | |||
| f13039fe9b | |||
| 3f776c8d58 | |||
| 81ac07c395 | |||
| 43b9c9516b | |||
| 92eba2d461 | |||
| cf8eeb5560 | |||
| 34aae9e275 | |||
| 088d7dd306 | |||
| a89d0d78cd | |||
| b6855614d3 | |||
| 9628d56779 | |||
| 05d1ad7ae7 | |||
| 964ac2af6a | |||
| 10b606e18a | |||
| 8724b7ef24 | |||
| 4ecc66eb32 | |||
| 08270f5a4a | |||
| ffe74fd672 | |||
| 86ba51dc6f | |||
| 1b2481a6be | |||
| 6c4ac570da | |||
| 118cc6c749 | |||
| bf1d627e9d | |||
| 4b2e57a8a0 | |||
| b8cc587c63 | |||
| b68f0f7ed0 | |||
| d2fded39f2 | |||
| 274ed2f1c1 | |||
| 82bfc36ab5 | |||
| ca20c9020e | |||
| 8f156fa71b | |||
| 3475baedd6 | |||
| c027c7ef0a | |||
| d347d2436c | |||
| 837b92e06a | |||
| d6fadaae1e | |||
| 51e8f3a9fb | |||
| efcde2d5df | |||
| fbc2eeb42c | |||
| 13021d439a | |||
| 0f4d91e939 | |||
| d9f73a8675 | |||
| 1bbb0c4c63 | |||
| 072e995b70 | |||
| 2c965ed7b2 | |||
| 1bff0bf7e8 | |||
| 46f32294b8 | |||
| f946d6c65b | |||
| 4327e6805d | |||
| 9db90e62c2 | |||
| 8b3066b210 | |||
| 914f59d6c9 | |||
| 47f8d4dab4 | |||
| f2b52e5c88 | |||
| bec14778a3 | |||
| 2283bfcc0c | |||
| 55f1d1f133 | |||
| 0947542239 | |||
| 985d4c8b59 | |||
| c60786f798 | |||
| 67dd4ea4fb | |||
| a5e82074a8 | |||
| 9229309500 | |||
| 625acfa290 | |||
| 2ca2352ba0 | |||
| 24757518fc | |||
| a9e542f89b | |||
| 495253e791 | |||
| c017753fe6 | |||
| a8290bd5d0 | |||
| ffc78c9dc3 | |||
| 74b42969b7 | |||
| c48c4da83d | |||
| 8af2f75854 | |||
| 86554e20d5 | |||
| ae5cc03c17 | |||
| 44163c5c5c | |||
| 2e96bc6cdd | |||
| 67ed7dbe6b | |||
| 7bcecbe435 | |||
| e76f78dd8c | |||
| c95efcdc15 | |||
| ab3b8b47f3 | |||
| dd482189f9 | |||
| 02cd13c6f7 | |||
| 0e2e982eb2 | |||
| 68168a0936 | |||
| a5dacc8a81 | |||
| 3f1f724cdd | |||
| c62829b1ad | |||
| f9c0662282 | |||
| 1b6bd4ffc4 | |||
| 53ac852284 | |||
| 3410958449 | |||
| fcd6735028 | |||
| a9d04bdf18 | |||
| cb56e5a227 | |||
| 7fb90a77f9 | |||
| a43d8b0c81 | |||
| ea65bcee66 | |||
| 20ae896e0c | |||
| fb52234ee5 | |||
| 50229d464e | |||
| d0d10604d5 | |||
| d8f181a033 | |||
| 10428c0673 | |||
| 7ad3581a9d | |||
| 863f78f73f | |||
| 984132bfff | |||
| 374787b57c | |||
| 43977aea63 | |||
| cb9261853a | |||
| 2c974cfbc0 | |||
| fe7a4e5c33 | |||
| 16b93f1619 | |||
| 6e8ca109fc | |||
| 0477d04bbd | |||
| 70442ebbac | |||
| f54cf6a4a8 | |||
| f858221f24 | |||
| 2468a9c751 | |||
| 825748480c | |||
| 89a2df396e | |||
| 0273ea5255 | |||
| a70945dc33 | |||
| 2ac84ea838 | |||
| c57304bad2 | |||
| 5214fa853c | |||
| 465b93e035 | |||
| 496aa21138 | |||
| 267e5ab5cd | |||
| 25f805496d | |||
| bf67357601 | |||
| 0e78cc2d43 | |||
| 2a36638d75 | |||
| 9e50b007eb | |||
| 05b5cd400a | |||
| dda4b5eb2a | |||
| 6261fa78b8 | |||
| 235388bbaa | |||
| 8a76862c0b | |||
| 45ab63dc6d | |||
| 3399bce4db | |||
| b16e95800d | |||
| f0b4b4637a | |||
| e2eb40185f | |||
| 6b20a06619 | |||
| 23b9f168a0 | |||
| 8eb24162ed | |||
| 7369891fbf | |||
| 887573a81f | |||
| e0fce64e18 | |||
| ea56daa372 | |||
| 9c559f3bdd | |||
| 32edad5d4b | |||
| 616232460e | |||
| 3fbba03d78 | |||
| 7e33e1f3f7 | |||
| 3313c4a713 | |||
| cfc9870314 | |||
| de8ecd514e | |||
| cccebe685f | |||
| 489a0050c4 | |||
| cca19547d2 | |||
| 0bdd35f15b | |||
| 5734c08ba4 | |||
| 7e3a5fed04 | |||
| 45882b4a72 | |||
| fdaa818c28 | |||
| dd6f9427c7 | |||
| f9bc1fc65a | |||
| 86ac32d29f | |||
| dba30f1168 | |||
| 618979614a | |||
| ab03594786 | |||
| 91e4e5342e | |||
| f9220ef396 | |||
| fa41ac4047 | |||
| 6841435ea0 | |||
| 3b61176cda | |||
| 3ac66d6d63 | |||
| 9d96dc07ec | |||
| f1d31ac865 | |||
| 3b2f7cec04 |
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
84
app/Console/Commands/CheckSkuQualityPeriod.php
Normal file
84
app/Console/Commands/CheckSkuQualityPeriod.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?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()->subDays(4)->startOfDay()->toDateTimeString();//目前检查范围是5天
|
||||||
|
|
||||||
|
//查询未处理过的快过期的异常订单
|
||||||
|
$purchaseRecords = DB::table('purchase_records as a')
|
||||||
|
->select("a.created_at","a.date", "a.num", "b.title","b.name", "b.stock", "a.id", "b.id as sku_id", "b.external_sku_id")
|
||||||
|
->leftJoin('goods_skus as b', 'a.external_sku_id', '=', 'b.external_sku_id')
|
||||||
|
->where("a.check_status", "=", 0)
|
||||||
|
->whereBetween('a.expire_time', [$startTime, $endTime])->get();
|
||||||
|
Log::info('采购临期记录', [$purchaseRecords]);
|
||||||
|
|
||||||
|
if ($purchaseRecords->isNotEmpty()) {
|
||||||
|
$messageService = new MessageService();
|
||||||
|
$updateIds = [];
|
||||||
|
foreach ($purchaseRecords as $v) {
|
||||||
|
// 单独采购单后续总和小于库存表示该sku没有卖完
|
||||||
|
$totalPurchaseNum = PurchaseRecords::query()->where('created_at', '>', $v->created_at)
|
||||||
|
->where('external_sku_id', "=", $v->external_sku_id)
|
||||||
|
->where("status", 1)->sum('num');
|
||||||
|
if ($totalPurchaseNum < $v->stock) {
|
||||||
|
$messageService->skuQualityPeriodNoticeMessage((array)$v);
|
||||||
|
}else{
|
||||||
|
//
|
||||||
|
$updateIds[] = $v->id;
|
||||||
|
}
|
||||||
|
//更新下状态
|
||||||
|
}
|
||||||
|
if(!empty($updateIds)){
|
||||||
|
PurchaseRecords::query()->whereIn('id', $updateIds)->update([
|
||||||
|
"check_status" => 1
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('任务完成:check-CheckSkuQualityPeriod',[$updateIds]);
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use App\Models\DailyStockRecord;
|
use App\Models\DailyStockRecord;
|
||||||
use App\Models\GoodsSku;
|
use App\Models\GoodsSku;
|
||||||
@ -41,19 +42,20 @@ class Inventory extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
DB::beginTransaction();
|
|
||||||
try {
|
$log = new Log();
|
||||||
$log = new Log();
|
$log->module = 'goods';
|
||||||
$log->module = 'goods';
|
$log->action = 'PATCH';
|
||||||
$log->action = 'PATCH';
|
$log->target_type = 'goods_sku';
|
||||||
$log->target_type = 'goods_sku';
|
$log->target_id = 0;
|
||||||
$log->target_id = 0;
|
$log->target_field = 'timingInventory';
|
||||||
$log->target_field = 'timingInventory';
|
$log->user_id = 999;
|
||||||
$log->user_id = 999;
|
// 数据库存储过程,7点定时执行
|
||||||
// 数据库存储过程,7点定时执行
|
$data = [];
|
||||||
$data = [];
|
$date = date('Y-m-d');
|
||||||
$date = date('Y-m-d');
|
GoodsSku::query()->chunk(500, static function ($skus) use (&$data, $date, $log) {
|
||||||
GoodsSku::query()->chunk(500, static function ($skus) use (&$data, $date) {
|
DB::beginTransaction();
|
||||||
|
try {
|
||||||
foreach ($skus as $sku) {
|
foreach ($skus as $sku) {
|
||||||
$data[] = [
|
$data[] = [
|
||||||
'sku_id' => $sku->id,
|
'sku_id' => $sku->id,
|
||||||
@ -64,15 +66,16 @@ class Inventory extends Command
|
|||||||
'two_days_ago_num' => $sku->two_days_ago_num + $sku->yesterday_num,
|
'two_days_ago_num' => $sku->two_days_ago_num + $sku->yesterday_num,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
//$record = new DailyStockRecord();
|
||||||
$record = new DailyStockRecord();
|
//$record->batchInsert($data);
|
||||||
$record->batchInsert($data);
|
DB::commit();
|
||||||
DB::commit();
|
$log->message = '7点数据更新成功';
|
||||||
$log->message = '7点数据更新成功';
|
} catch (\Exception $exception) {
|
||||||
} catch (\Exception $exception) {
|
$log->message = '7点数据更新失败' . $exception->getMessage();
|
||||||
$log->message = '7点数据更新失败' . $exception->getMessage();
|
DB::rollBack();
|
||||||
DB::rollBack();
|
}
|
||||||
}
|
|
||||||
|
});
|
||||||
$log->save();
|
$log->save();
|
||||||
$this->info($log->message);
|
$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\Services\Business\BusinessFactory;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class KttOrderQuery extends Command
|
class KttOrderQuery extends Command
|
||||||
{
|
{
|
||||||
|
|||||||
67
app/Console/Commands/KttOrderSyncStatus.php
Normal file
67
app/Console/Commands/KttOrderSyncStatus.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Http\Enum\BusinessOrderShippingStatus;
|
||||||
|
use App\Models\BusinessOrder;
|
||||||
|
use App\Models\Shop;
|
||||||
|
use App\Services\Business\BusinessFactory;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class KttOrderSyncStatus extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'ktt:order_sync_status {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
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$ids = $this->argument('ids');
|
||||||
|
if (!empty($ids)) {
|
||||||
|
$ids = explode(",", $ids);
|
||||||
|
}
|
||||||
|
$startTime = Carbon::now()->subDays(15)->getPreciseTimestamp(3);
|
||||||
|
BusinessOrder::query()->when($ids, function ($query) use ($ids) {
|
||||||
|
$query->whereIn('id',$ids);
|
||||||
|
})
|
||||||
|
->where('confirm_at', '>=', $startTime)
|
||||||
|
->where('shipping_status', BusinessOrderShippingStatus::UNSHIP)
|
||||||
|
->where('cancel_status', 0)
|
||||||
|
->chunk(200, function ($orders) {
|
||||||
|
foreach ($orders as $order) {
|
||||||
|
$shop = Shop::query()->find($order['shop_id']);
|
||||||
|
if (!empty($shop)) {
|
||||||
|
BusinessFactory::init()->make($shop->plat_id)->setShop($shop)->queryStatusAndSync($order);
|
||||||
|
usleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
|
use App\Console\Commands\CheckPrice;
|
||||||
|
use App\Console\Commands\CheckSkuQualityPeriod;
|
||||||
use App\Console\Commands\DailySalesReport;
|
use App\Console\Commands\DailySalesReport;
|
||||||
|
use App\Console\Commands\DailyStockRecordReport;
|
||||||
use App\Console\Commands\GoodsSkuDailyReport;
|
use App\Console\Commands\GoodsSkuDailyReport;
|
||||||
use App\Console\Commands\Inventory;
|
use App\Console\Commands\Inventory;
|
||||||
|
use App\Console\Commands\KttOrderAfterSaleQuery;
|
||||||
|
use App\Console\Commands\KttOrderSyncStatus;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
use App\Console\Commands\KttOrderQuery;
|
use App\Console\Commands\KttOrderQuery;
|
||||||
@ -45,6 +50,18 @@ class Kernel extends ConsoleKernel
|
|||||||
$schedule->command(DailySalesReport::class, ['S7'])->dailyAt('09:30');
|
$schedule->command(DailySalesReport::class, ['S7'])->dailyAt('09:30');
|
||||||
|
|
||||||
$schedule->command(DeleteKttQuery::class)->daily();
|
$schedule->command(DeleteKttQuery::class)->daily();
|
||||||
|
//新增价格校验
|
||||||
|
$schedule->command(CheckPrice::class)->everyFifteenMinutes();
|
||||||
|
//保质期
|
||||||
|
$schedule->command(CheckSkuQualityPeriod::class)->dailyAt('11:00');
|
||||||
|
//快团团售后单拉取
|
||||||
|
$schedule->command(KttOrderAfterSaleQuery::class)->everyFifteenMinutes();
|
||||||
|
//同步售卖信息和报损相关数据
|
||||||
|
$schedule->command(DailyStockRecordReport::class)->dailyAt('03:30');
|
||||||
|
|
||||||
|
//新增快团团订单状态同步
|
||||||
|
$schedule->command(KttOrderSyncStatus::class)->everyTenMinutes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use Illuminate\Broadcasting\PrivateChannel;
|
|||||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class BatchStockUpdateEvent
|
class BatchStockUpdateEvent
|
||||||
{
|
{
|
||||||
|
|||||||
@ -21,6 +21,8 @@ class BusinessOrdersUpdate
|
|||||||
public $businessGoodSku;
|
public $businessGoodSku;
|
||||||
public $num;
|
public $num;
|
||||||
public $goodsSku;
|
public $goodsSku;
|
||||||
|
public $type = "BusinessOrdersUpdate";
|
||||||
|
|
||||||
public $combinationGoodsUpdate = true;
|
public $combinationGoodsUpdate = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,39 +32,50 @@ class BusinessOrdersUpdate
|
|||||||
*/
|
*/
|
||||||
public function __construct($businessGoodSku, $num)
|
public function __construct($businessGoodSku, $num)
|
||||||
{
|
{
|
||||||
$this->businessGoodSku = $businessGoodSku->toArray();
|
try {
|
||||||
$this->num = $num;
|
$this->businessGoodSku = $businessGoodSku->toArray();
|
||||||
$this->updateStock();
|
$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()
|
private function updateStock()
|
||||||
{
|
{
|
||||||
$this->goodsSku = GoodsSku::query()
|
$this->goodsSku = GoodsSku::query()
|
||||||
->where('external_sku_id', $this->businessGoodSku['external_sku_id'])
|
->where('external_sku_id', $this->businessGoodSku['external_sku_id'])
|
||||||
->first();
|
->first();
|
||||||
if (is_null($this->goodsSku)) {
|
if (is_null($this->goodsSku)) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
$oldStock = $this->goodsSku->stock;
|
||||||
$stock = $this->goodsSku->stock + $this->num;
|
$stock = $this->goodsSku->stock + $this->num;
|
||||||
|
$saleStock = $this->goodsSku->sale_stock + $this->num;
|
||||||
if (0 >= $stock) {
|
$saleStock = ($saleStock > 0) ? $saleStock : 0;
|
||||||
$this->goodsSku->status = GoodsSku::$STATUS_DOWN;
|
$updateParam = ["stock" => $stock, "sale_stock" => $saleStock];
|
||||||
|
if (0 >= $saleStock) {
|
||||||
|
$updateParam['status'] = GoodsSku::$STATUS_DOWN;
|
||||||
} else {
|
} else {
|
||||||
$this->goodsSku->status = GoodsSku::$STATUS_ON_SALE;
|
$updateParam['status'] = GoodsSku::$STATUS_ON_SALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 今日到货 + 1T 大于20,且当前剩余库存小于4时 直接下架
|
Log::info("sku 业务订单库存更:{$this->goodsSku->id},num:{$this->num}", [$updateParam, (array)$this->goodsSku]);
|
||||||
$arrivedTodayNum = DailyStockRecord::query()
|
//乐观锁更新
|
||||||
->where('day', DateTimeUtils::getToday())
|
return GoodsSku::query()->where('external_sku_id', $this->businessGoodSku['external_sku_id'])->
|
||||||
->where('sku_id', $this->goodsSku->id)
|
where("stock", "=", $oldStock)->update($updateParam);
|
||||||
->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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
40
app/Events/CancelLogisticEvent.php
Normal file
40
app/Events/CancelLogisticEvent.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PresenceChannel;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CancelLogisticEvent
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
public $shopId;
|
||||||
|
public $orderSn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($shopId, $orderSn)
|
||||||
|
{
|
||||||
|
$this->shopId = $shopId;
|
||||||
|
$this->orderSn = $orderSn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the channels the event should broadcast on.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Broadcasting\Channel|array
|
||||||
|
*/
|
||||||
|
public function broadcastOn()
|
||||||
|
{
|
||||||
|
return new PrivateChannel('channel-name');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -33,22 +33,14 @@ class StockUpdateEvent
|
|||||||
|
|
||||||
private function checkStatusAndStock($goodsSku)
|
private function checkStatusAndStock($goodsSku)
|
||||||
{
|
{
|
||||||
$stock = $goodsSku->stock;
|
//新版上下架和真实库存无关
|
||||||
if (0 >= $goodsSku->stock) {
|
if (0 >= $goodsSku->sale_stock) {
|
||||||
$status = GoodsSku::$STATUS_DOWN;
|
$status = GoodsSku::$STATUS_DOWN;
|
||||||
} else {
|
} else {
|
||||||
$status = GoodsSku::$STATUS_ON_SALE;
|
$status = GoodsSku::$STATUS_ON_SALE;
|
||||||
}
|
}
|
||||||
$arrivedTodayNum = DailyStockRecord::query()
|
|
||||||
->where('day', DateTimeUtils::getToday())
|
|
||||||
->where('sku_id', $goodsSku->id)
|
|
||||||
->value('arrived_today_num');
|
|
||||||
if (20 < $arrivedTodayNum + $goodsSku->yesterday_num && 4 > $goodsSku->stock) {
|
|
||||||
$status = GoodsSku::$STATUS_DOWN;
|
|
||||||
$stock = 0;
|
|
||||||
}
|
|
||||||
$goodsSku->status = $status;
|
$goodsSku->status = $status;
|
||||||
$goodsSku->stock = $stock;
|
|
||||||
$goodsSku->save();
|
$goodsSku->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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;
|
namespace App\Exports;
|
||||||
|
|
||||||
|
use App\Http\Enum\TargetTypeEnum;
|
||||||
use App\Models\DailyStockRecord;
|
use App\Models\DailyStockRecord;
|
||||||
|
use App\Models\Goods;
|
||||||
use App\Models\Log;
|
use App\Models\Log;
|
||||||
|
use App\Models\PurchaseRecords;
|
||||||
use App\Utils\ArrayUtils;
|
use App\Utils\ArrayUtils;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||||
@ -35,56 +38,72 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
|
|||||||
$headTitle = [
|
$headTitle = [
|
||||||
'商品编码',
|
'商品编码',
|
||||||
'商品名称',
|
'商品名称',
|
||||||
'商品种类',
|
'在售库存',
|
||||||
'商品品牌',
|
"剩余库存",
|
||||||
'规格编码',
|
'创建时间',
|
||||||
'规格名称',
|
|
||||||
];
|
];
|
||||||
$map = [
|
$map = [
|
||||||
'cost' => ['成本', '更新前成本', '更新后成本'],
|
'cost' => ['当前成本', '更新前成本', "更新后成本"],
|
||||||
'inventory' => ['库存', '盘点', '上新'],
|
'inventory' => ['当前库存', '盘点数', '采购总数'],
|
||||||
];
|
];
|
||||||
$headTitle = array_merge($headTitle, $map[$this->type]);
|
$headTitle = array_merge($headTitle, $map[$this->type] ?? []);
|
||||||
if ('cost' === $this->type) {
|
if ('cost' === $this->type) {
|
||||||
$update = $this->getChangeCostLogs();
|
$update = $this->getChangeCostLogs();
|
||||||
}
|
}
|
||||||
if ('inventory' === $this->type) {
|
if ('inventory' === $this->type) {
|
||||||
$update = $this->getInventoryRecord();
|
$update = $this->getInventoryRecord();
|
||||||
}
|
}
|
||||||
$ids = array_keys($update);
|
if ($this->type === "goods_sku" || $this->type === "goods_combination") {
|
||||||
if (empty($ids)) {
|
$builder = GoodsSku::query();
|
||||||
return [$headTitle];
|
if (request()->get('type_id')) {
|
||||||
}
|
$goodsIds = Goods::query()->filter()->pluck('id')->toArray();
|
||||||
$model = GoodsSku::query()
|
$builder->whereIn('goods_id', $goodsIds);
|
||||||
->when($ids, function ($query, $ids) {
|
}
|
||||||
return $query->whereIn('id', $ids);
|
if (request()->get('goods_title')) {
|
||||||
})
|
$builder->where('name', 'like', '%' . request()->get('goods_title') . '%');
|
||||||
->with(['goods' => function ($query) {
|
}
|
||||||
$query->with(['type:id,name', 'brand:id,name'])
|
if ($this->type === "goods_combination") {
|
||||||
->orderBy('type_id')
|
$builder->where('is_combination', 1);
|
||||||
->orderBy('brand_id');
|
} else {
|
||||||
}]);
|
$builder->where('is_combination', 0);
|
||||||
$data = $model->get()->toArray();
|
}
|
||||||
if (empty($data)) {
|
$data = $builder->filter()->orderByDesc('id')->get()->toArray();
|
||||||
return [$headTitle];
|
} 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 = [];
|
$bodyData = [];
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
$arr[0] = $item['goods']['goods_code'];
|
$arr[0] = $item['external_sku_id'];
|
||||||
$arr[1] = $item['goods']['title'];
|
$arr[1] = $item['name'];
|
||||||
$arr[2] = $item['goods']['type']['name'];
|
$arr[2] = $item['sale_stock'] ?? '0';
|
||||||
$arr[3] = $item['goods']['brand']['name'];
|
$arr[3] = $item['stock'] ?? '0';
|
||||||
$arr[4] = $item['sku_code'];
|
$arr[4] = $item['created_at'];
|
||||||
$arr[5] = $item['title'];
|
|
||||||
if ('cost' === $this->type) {
|
if ('cost' === $this->type) {
|
||||||
$arr[6] = (string)$item['cost'];
|
$arr[5] = (string)$item['cost'];
|
||||||
$arr[7] = (string)$update[$item['id']]['before_update'];
|
$arr[6] = (string)$update[$item['id']]['before_update'];
|
||||||
$arr[8] = (string)$update[$item['id']]['after_update'];
|
$arr[7] = (string)$update[$item['id']]['after_update'];
|
||||||
}
|
}
|
||||||
if ('inventory' === $this->type) {
|
if ('inventory' === $this->type) {
|
||||||
$arr[6] = (string)$item['stock'];
|
$arr[5] = (string)$item['stock'];
|
||||||
$arr[7] = (string)$update[$item['id']]['inventory'];
|
$arr[6] = (string)$update[$item['id']]['inventory'];
|
||||||
$arr[8] = (string)$update[$item['id']]['arrived_today_num'];
|
$arr[7] = (string)$update[$item['id']]['arrived_today_num'];
|
||||||
}
|
}
|
||||||
$bodyData[] = $arr;
|
$bodyData[] = $arr;
|
||||||
}
|
}
|
||||||
@ -97,18 +116,23 @@ class GoodsSkusExport implements FromCollection, ShouldAutoSize
|
|||||||
$day = DateTimeUtils::getToday();
|
$day = DateTimeUtils::getToday();
|
||||||
$logs = Log::query()
|
$logs = Log::query()
|
||||||
->select(['target_id', 'before_update', 'after_update'])
|
->select(['target_id', 'before_update', 'after_update'])
|
||||||
->where('target_type', 'goods_sku')
|
->where('target_type', TargetTypeEnum::PURCHASE)
|
||||||
->where('target_field', 'cost')
|
->where('target_field', 'stock')
|
||||||
->where('created_at', '>', $day)
|
->where('created_at', '>', $day)
|
||||||
->orderBy('id', 'asc')
|
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$update = [];
|
$update = [];
|
||||||
foreach ($logs as $log) {
|
foreach ($logs as $log) {
|
||||||
if ($log['before_update'] !== $log['after_update'] || (int)$log['after_update']) {
|
if (!isset($update[$log['target_id']])) {
|
||||||
if (!isset($update[$log['target_id']])) {
|
$beforeData = json_decode($log['before_update'], true);
|
||||||
$update[$log['target_id']]['before_update'] = $log['before_update'];
|
if (!empty($beforeData['cost'])) {
|
||||||
|
$update[$log['target_id']]['before_update'] = $beforeData['cost'];
|
||||||
}
|
}
|
||||||
$update[$log['target_id']]['after_update'] = $log['after_update'];
|
|
||||||
|
}
|
||||||
|
$afterData = json_decode($log['after_update'], true);
|
||||||
|
if (!empty($afterData['cost']) && $afterData['cost'] != $beforeData['cost']) {
|
||||||
|
$update[$log['target_id']]['after_update'] = $afterData['cost'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,9 +33,8 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
|||||||
{
|
{
|
||||||
$headTitle = [
|
$headTitle = [
|
||||||
'商品名称',
|
'商品名称',
|
||||||
'品类',
|
'品种',
|
||||||
'规格',
|
'规格名称',
|
||||||
'品牌',
|
|
||||||
'商品编码',
|
'商品编码',
|
||||||
'成本',
|
'成本',
|
||||||
'销售数量',
|
'销售数量',
|
||||||
@ -51,8 +50,7 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
|||||||
->with([
|
->with([
|
||||||
'goods:id,title',
|
'goods:id,title',
|
||||||
'goodsType:id,name',
|
'goodsType:id,name',
|
||||||
'goodsSku:id,title',
|
'goodsSku:id,title,name'
|
||||||
'goodsBrand:id,name',
|
|
||||||
])
|
])
|
||||||
->where('date', '>=', $this->startDate)
|
->where('date', '>=', $this->startDate)
|
||||||
->where('date', '<=', $this->endDate)
|
->where('date', '<=', $this->endDate)
|
||||||
@ -66,10 +64,9 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
|||||||
$number = $item->total_goods_number - $item->total_cancel_number;
|
$number = $item->total_goods_number - $item->total_cancel_number;
|
||||||
if (!isset($arr[$item->external_sku_id])) {
|
if (!isset($arr[$item->external_sku_id])) {
|
||||||
$arr[$item->external_sku_id] = [
|
$arr[$item->external_sku_id] = [
|
||||||
'goodsTitle' => $item->goods->title,
|
'goodsTitle' => !empty($item->goodsSku) ? $item->goodsSku->name:'',
|
||||||
'goodsTypeName' => $item->goodsType->name,
|
'goodsTypeName' => !empty($item->goodsType) ? $item->goodsType->name : "",
|
||||||
'goodsSkuTitle' => $item->goodsSku->title,
|
'goodsSkuTitle' => !empty($item->goodsSku) ? $item->goodsSku->title : "",
|
||||||
'goodsBrandName' => $item->goodsBrand->name,
|
|
||||||
'external_sku_id' => $item->external_sku_id,
|
'external_sku_id' => $item->external_sku_id,
|
||||||
'cost' => [],
|
'cost' => [],
|
||||||
'number' => [],
|
'number' => [],
|
||||||
@ -97,7 +94,6 @@ class WeekDataExport implements FromCollection, ShouldAutoSize
|
|||||||
$item['goodsTitle'],
|
$item['goodsTitle'],
|
||||||
$item['goodsTypeName'],
|
$item['goodsTypeName'],
|
||||||
$item['goodsSkuTitle'],
|
$item['goodsSkuTitle'],
|
||||||
$item['goodsBrandName'],
|
|
||||||
$item['external_sku_id'],
|
$item['external_sku_id'],
|
||||||
$cost,
|
$cost,
|
||||||
array_sum($item['number']),
|
array_sum($item['number']),
|
||||||
|
|||||||
@ -10,6 +10,9 @@ class BusinessOrderFilter extends Filters
|
|||||||
{
|
{
|
||||||
protected function ids($value)
|
protected function ids($value)
|
||||||
{
|
{
|
||||||
|
if(is_string($value)){
|
||||||
|
$value = explode(",", $value);
|
||||||
|
}
|
||||||
return $this->builder->whereIn('id', $value);
|
return $this->builder->whereIn('id', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Filters;
|
namespace App\Filters;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class GoodsSkuFilter extends Filters
|
class GoodsSkuFilter extends Filters
|
||||||
{
|
{
|
||||||
protected function skuTitle($value)
|
protected function skuTitle($value)
|
||||||
@ -28,4 +30,46 @@ class GoodsSkuFilter extends Filters
|
|||||||
{
|
{
|
||||||
return $this->builder->where('is_combination', $value);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function minStock($value)
|
||||||
|
{
|
||||||
|
return $this->builder->where('stock',">=", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function maxStock($value)
|
||||||
|
{
|
||||||
|
return $this->builder->where('stock',"<=", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function minSaleStock($value)
|
||||||
|
{
|
||||||
|
return $this->builder->where('sale_stock',">=", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function maxSaleStock($value)
|
||||||
|
{
|
||||||
|
return $this->builder->where('sale_stock',"<=", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function neqSaleStock($value)
|
||||||
|
{
|
||||||
|
return $this->builder->where('sale_stock',"!=", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function neqStock($value)
|
||||||
|
{
|
||||||
|
return $this->builder->where('stock',"!=", $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -93,7 +93,8 @@ class BusinessGoodsSkusController extends Controller
|
|||||||
if (empty($sku)) {
|
if (empty($sku)) {
|
||||||
$this->setValidatorFailResponse('未找到对应的商品,请核实后再次同步或删除此平台商品');
|
$this->setValidatorFailResponse('未找到对应的商品,请核实后再次同步或删除此平台商品');
|
||||||
} else {
|
} else {
|
||||||
event(new BusinessOrdersUpdate($businessGoodsSku, 0));
|
$shop = $businessGoodsSku->shop;
|
||||||
|
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->incrQuantity($businessGoodsSku, $sku->sale_stock, false);
|
||||||
$this->res['message'] = '库存同步请求发送成功,具体结果查看日志';
|
$this->res['message'] = '库存同步请求发送成功,具体结果查看日志';
|
||||||
}
|
}
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
|
|||||||
@ -2,18 +2,21 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Business;
|
namespace App\Http\Controllers\Business;
|
||||||
|
|
||||||
|
use App\Exports\BusinessOrderExport;
|
||||||
use App\Exports\OrderBlankExport;
|
use App\Exports\OrderBlankExport;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\BusinessOrder;
|
use App\Models\BusinessOrder;
|
||||||
use App\Models\BusinessOrderItem;
|
use App\Models\BusinessOrderItem;
|
||||||
use App\Models\GoodsSku;
|
use App\Models\GoodsSku;
|
||||||
use App\Models\Shop;
|
use App\Models\Shop;
|
||||||
use App\Services\Ship\WayBillService;
|
use App\Models\Waybill;
|
||||||
|
use App\Services\WayBill\JingDong\WayBillService;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Resources\BusinessOrderResource;
|
use App\Http\Resources\BusinessOrderResource;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Maatwebsite\Excel\Facades\Excel;
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
|
|
||||||
class BusinessOrderController extends Controller
|
class BusinessOrderController extends Controller
|
||||||
@ -26,15 +29,41 @@ class BusinessOrderController extends Controller
|
|||||||
$builder = BusinessOrder::query()
|
$builder = BusinessOrder::query()
|
||||||
->with([
|
->with([
|
||||||
'shop:id,name',
|
'shop:id,name',
|
||||||
'items:id,business_order_id,goods_name,goods_number,external_sku_id'
|
'items:id,business_order_id,goods_name,goods_number,external_sku_id',
|
||||||
|
"waybill"
|
||||||
])
|
])
|
||||||
->whereIn('shop_id', $shopIds)
|
->whereIn('shop_id', $shopIds)
|
||||||
->filter();
|
->filter();
|
||||||
$externalSkuIds = $request->get('external_sku_ids');
|
$externalSkuIds = $request->get('external_sku_ids');
|
||||||
|
$externalSkuId = $request->get('external_sku_id');
|
||||||
|
if (!empty($externalSkuId)) {
|
||||||
|
$externalSkuIds = $externalSkuId;
|
||||||
|
}
|
||||||
if ($externalSkuIds) {
|
if ($externalSkuIds) {
|
||||||
|
if (is_string($externalSkuIds)) {
|
||||||
|
$externalSkuIds = explode(",", $externalSkuIds);
|
||||||
|
}
|
||||||
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
|
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
|
||||||
$builder->whereIn('id', $ids);
|
$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')
|
$businessOrders = $builder->orderByDesc('confirm_at')
|
||||||
->paginate($request->get('per_page'));
|
->paginate($request->get('per_page'));
|
||||||
|
|
||||||
@ -158,24 +187,25 @@ class BusinessOrderController extends Controller
|
|||||||
->whereIn('shop_id', $shopIds)
|
->whereIn('shop_id', $shopIds)
|
||||||
->filter();
|
->filter();
|
||||||
$externalSkuIds = $request->get('external_sku_ids');
|
$externalSkuIds = $request->get('external_sku_ids');
|
||||||
|
|
||||||
if ($externalSkuIds) {
|
if ($externalSkuIds) {
|
||||||
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
|
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
|
||||||
$builder->whereIn('id', $ids);
|
$builder->whereIn('id', $ids);
|
||||||
}
|
}
|
||||||
if ($ids = $request->input('ids')) {
|
if ($ids = $request->input('ids')) {
|
||||||
|
if (is_string($ids)) {
|
||||||
|
$ids = explode(",", $ids);
|
||||||
|
}
|
||||||
$builder->whereIn('id', $ids);
|
$builder->whereIn('id', $ids);
|
||||||
}
|
}
|
||||||
$businessOrders = $builder->get();
|
$businessOrders = $builder->get();
|
||||||
|
|
||||||
$waybill = new WayBillService();
|
$waybill = new WayBillService();
|
||||||
$waybill->setOrders($businessOrders);
|
$waybill->setOrders($businessOrders);
|
||||||
$contents = $waybill->getContents();
|
$contents = $waybill->getWayBillContents();
|
||||||
// 待打印数据
|
|
||||||
[$documents, $orderIds] = $waybill->getDocumentsAndOrderIds($contents);
|
|
||||||
|
|
||||||
return response([
|
return response([
|
||||||
'documents' => $this->combinationPrintDocuments($documents),
|
'data' => $contents
|
||||||
'order_ids' => implode(',', $orderIds),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,9 +262,11 @@ class BusinessOrderController extends Controller
|
|||||||
$orderIds = $request->input('order_ids');
|
$orderIds = $request->input('order_ids');
|
||||||
$orderIds = explode(',', $orderIds);
|
$orderIds = explode(',', $orderIds);
|
||||||
BusinessOrder::query()
|
BusinessOrder::query()
|
||||||
->where('id', $orderIds)
|
->whereIn('id', $orderIds)
|
||||||
->increment('print_status');
|
->update(['print_status' => 1]);
|
||||||
|
Waybill::query()
|
||||||
|
->where('order_id', $orderIds)
|
||||||
|
->update(['status' => Waybill::$STATUS_PRINT_SUCCESS]);
|
||||||
return response(['message' => 'success']);
|
return response(['message' => 'success']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
app/Http/Controllers/Business/WaybillController.php
Normal file
74
app/Http/Controllers/Business/WaybillController.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Business;
|
||||||
|
|
||||||
|
use App\Events\BusinessOrderCancelEvent;
|
||||||
|
use App\Events\CancelLogisticEvent;
|
||||||
|
use App\Exports\BusinessOrderExport;
|
||||||
|
use App\Exports\OrderBlankExport;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\BusinessOrder;
|
||||||
|
use App\Models\BusinessOrderItem;
|
||||||
|
use App\Models\GoodsSku;
|
||||||
|
use App\Models\Shop;
|
||||||
|
use App\Models\Waybill;
|
||||||
|
use App\Services\Business\BusinessFactory;
|
||||||
|
use App\Services\WayBill\JingDong\JingDongService;
|
||||||
|
use App\Services\WayBill\JingDong\WayBillService;
|
||||||
|
use App\Utils\DateTimeUtils;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Http\Resources\BusinessOrderResource;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
|
|
||||||
|
class WaybillController extends Controller
|
||||||
|
{
|
||||||
|
public function queryTrace(Request $request)
|
||||||
|
{
|
||||||
|
$params = $request->validate([
|
||||||
|
'order_id' => 'required',
|
||||||
|
], [
|
||||||
|
'order_id.required' => '订单id',
|
||||||
|
]);
|
||||||
|
$waybill = Waybill::query()->where("order_id", $params['order_id'])->firstOrFail();
|
||||||
|
$jingDongService = new JingDongService();
|
||||||
|
return $jingDongService->queryTrace($waybill);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel(Request $request)
|
||||||
|
{
|
||||||
|
$params = $request->validate([
|
||||||
|
'order_id' => 'required',
|
||||||
|
], [
|
||||||
|
'order_id.required' => '订单id',
|
||||||
|
]);
|
||||||
|
$waybill = Waybill::query()->where("order_id", $params['order_id'])->firstOrFail();
|
||||||
|
if (empty($waybill->waybill_code)) {
|
||||||
|
throw new \Exception("无快递单号可取消");
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
//取消快团团物流
|
||||||
|
$shop = Shop::query()->findOrFail($waybill->shop_id);
|
||||||
|
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
|
||||||
|
$client->cancelLogistic($waybill->order_sn, $waybill->waybill_code);
|
||||||
|
//取消京东物流
|
||||||
|
$jingDongService = new JingDongService();
|
||||||
|
$jingDongService->cancelOrder($waybill);
|
||||||
|
}catch(\Exception $exception) {
|
||||||
|
Log::error("取消快团团或者京东物流异常", ["error" => $exception->getMessage()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$waybill->waybill_code = '';
|
||||||
|
$waybill->encryptedData = '';
|
||||||
|
$waybill->status = Waybill::$STATUS_INIT;
|
||||||
|
$waybill->cancel = 1;
|
||||||
|
$waybill->save();
|
||||||
|
BusinessOrder::query()->where("id", $params['order_id'])->update(['print_status' => 0]);
|
||||||
|
|
||||||
|
return response(['message' => 'success']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -47,4 +47,23 @@ class Controller extends BaseController
|
|||||||
|
|
||||||
return $this->log->add($targetId, $targetField);
|
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;
|
namespace App\Http\Controllers\DataCenter;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Enum\StaticTypeEnum;
|
||||||
use App\Http\Resources\DailySalesReportResource;
|
use App\Http\Resources\DailySalesReportResource;
|
||||||
|
use App\Models\BusinessOrderItem;
|
||||||
use App\Models\DailySalesReport;
|
use App\Models\DailySalesReport;
|
||||||
|
use App\Models\GoodsSku;
|
||||||
|
use App\Services\Statistic\SaleDataService;
|
||||||
use App\Utils\FormatUtils;
|
use App\Utils\FormatUtils;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
class DataCenterController extends Controller
|
class DataCenterController extends Controller
|
||||||
{
|
{
|
||||||
@ -37,4 +44,89 @@ class DataCenterController extends Controller
|
|||||||
|
|
||||||
return DailySalesReportResource::collection($dailySalesReports);
|
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\Imports\CombinationGoodsImport;
|
||||||
use App\Models\BusinessOrderItem;
|
use App\Models\BusinessOrderItem;
|
||||||
use App\Models\CombinationGood;
|
use App\Models\CombinationGood;
|
||||||
|
use App\Models\DeveloperConfig;
|
||||||
use App\Models\Goods;
|
use App\Models\Goods;
|
||||||
use App\Models\GoodsSku;
|
use App\Models\GoodsSku;
|
||||||
|
use App\Utils\GeneratorUtils;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Maatwebsite\Excel\Facades\Excel;
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
@ -20,43 +24,82 @@ class GoodsCombinationController extends Controller
|
|||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
// ToDo
|
// ToDo
|
||||||
// 可通过子商品查找主商品
|
$sortField = $request->input('sort_field', 'id');//stock sale_stock order_goods_num
|
||||||
$skus = GoodsSku::query()
|
$sortValue = $request->input('sort_value', 'desc');
|
||||||
->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'));
|
|
||||||
$fields = implode(',', [
|
$fields = implode(',', [
|
||||||
'shop_id',
|
'shop_id',
|
||||||
'external_sku_id',
|
'external_sku_id',
|
||||||
'sum(goods_number) as number',
|
'SUM(goods_number) - SUM(already_cancel_number) as number',
|
||||||
'sum(already_cancel_number) as cancel_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) {
|
foreach ($skus as &$item) {
|
||||||
$items = [];
|
$items = [];
|
||||||
$lastInventoryTime = date('Y-m-d 07:00:00');
|
if (isset($externals[$item['id']])) {
|
||||||
$orderDetail = BusinessOrderItem::query()
|
$item['order_detail'] = $externals[$item['id']];
|
||||||
->select(DB::raw($fields))
|
$item['order_goods_num'] = $ids[$item['id']];
|
||||||
->with(['shop:id,name'])
|
} else {
|
||||||
->where('external_sku_id', $item['external_sku_id'])
|
$item['order_detail'] = [];
|
||||||
->when($lastInventoryTime, function ($query) use ($lastInventoryTime) {
|
$item['order_goods_num'] = 0;
|
||||||
$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'));
|
|
||||||
}
|
}
|
||||||
$item['order_goods_num'] = $addOrderGoodsNum - $reduceOrderGoodsNum;
|
|
||||||
$item['order_detail'] = $orderDetail;
|
|
||||||
$number = BusinessOrderItem::query()
|
$number = BusinessOrderItem::query()
|
||||||
->where('external_sku_id', $item['external_sku_id'])
|
->where('external_sku_id', $item['external_sku_id'])
|
||||||
->sum('goods_number');
|
->sum('goods_number');
|
||||||
@ -65,6 +108,9 @@ class GoodsCombinationController extends Controller
|
|||||||
->sum('already_cancel_number');
|
->sum('already_cancel_number');
|
||||||
$item['total_orders_num'] = $number - $cancelNumber;
|
$item['total_orders_num'] = $number - $cancelNumber;
|
||||||
foreach ($item['combinationGoods'] as $combinationItem) {
|
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[] = [
|
$items[] = [
|
||||||
'cost' => 0,
|
'cost' => 0,
|
||||||
'external_sku_id' => $combinationItem['goodsSkuItem']['external_sku_id'],
|
'external_sku_id' => $combinationItem['goodsSkuItem']['external_sku_id'],
|
||||||
@ -75,9 +121,10 @@ class GoodsCombinationController extends Controller
|
|||||||
'reference_price' => $combinationItem['goodsSkuItem']['reference_price'],
|
'reference_price' => $combinationItem['goodsSkuItem']['reference_price'],
|
||||||
'status' => $combinationItem['goodsSkuItem']['status'],
|
'status' => $combinationItem['goodsSkuItem']['status'],
|
||||||
'stock' => $combinationItem['goodsSkuItem']['stock'],
|
'stock' => $combinationItem['goodsSkuItem']['stock'],
|
||||||
'thumb_url' => $combinationItem['goodsSkuItem']['goods']['img_url'],
|
'sale_stock' => $combinationItem['goodsSkuItem']['sale_stock'],
|
||||||
'img_url' => $combinationItem['goodsSkuItem']['goods']['img_url'],
|
'thumb_url' => null,
|
||||||
'title' => $combinationItem['goodsSkuItem']['goods']['title'] . $combinationItem['goodsSkuItem']['title'],
|
'img_url' => null,//图片暂时去掉
|
||||||
|
'title' => $title,
|
||||||
'updated_at' => $combinationItem['goodsSkuItem']['updated_at'],
|
'updated_at' => $combinationItem['goodsSkuItem']['updated_at'],
|
||||||
'yesterday_num' => $combinationItem['goodsSkuItem']['yesterday_num'],
|
'yesterday_num' => $combinationItem['goodsSkuItem']['yesterday_num'],
|
||||||
'order_goods_num' => '请在商品列表查看',
|
'order_goods_num' => '请在商品列表查看',
|
||||||
@ -88,15 +135,18 @@ class GoodsCombinationController extends Controller
|
|||||||
$item['children'] = $items;
|
$item['children'] = $items;
|
||||||
unset($item['combinationGoods']);
|
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)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$validator = Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
'title' => 'required',
|
'title' => 'required',
|
||||||
'external_sku_id' => 'required',
|
'external_sku_id' => 'sometimes',
|
||||||
'combination_goods.*' => 'required',
|
'combination_goods.*' => 'required',
|
||||||
'combination_goods.*.item_id' => 'required',
|
'combination_goods.*.item_id' => 'required',
|
||||||
'combination_goods.*.item_num' => 'required|gt:0',
|
'combination_goods.*.item_num' => 'required|gt:0',
|
||||||
@ -106,20 +156,33 @@ class GoodsCombinationController extends Controller
|
|||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
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) && $hasCodeSku->id != $request->input('id',0)) {
|
||||||
|
throw new \Exception("该组合商品编码已存在");
|
||||||
|
}
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
$combinationGoods = $request->input('combination_goods');
|
$combinationGoods = $request->input('combination_goods');
|
||||||
$itemIds = array_column($combinationGoods, 'item_id');
|
$itemIds = array_column($combinationGoods, 'item_id');
|
||||||
$skus = GoodsSku::query()
|
$skus = GoodsSku::query()
|
||||||
->whereIn('id', $itemIds)
|
->whereIn('id', $itemIds)
|
||||||
->pluck('stock', 'id')
|
->get()
|
||||||
|
->pluck(null, 'id')
|
||||||
->toArray();
|
->toArray();
|
||||||
$stock = [];
|
$stock = [];
|
||||||
|
$saleStock = [];
|
||||||
foreach ($combinationGoods as $item) {
|
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);
|
$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')) {
|
if ($id = $request->input('id')) {
|
||||||
$sku = GoodsSku::query()->findOrFail($id);
|
$sku = GoodsSku::query()->findOrFail($id);
|
||||||
} else {
|
} else {
|
||||||
@ -127,11 +190,15 @@ class GoodsCombinationController extends Controller
|
|||||||
$sku->goods_id = 0;
|
$sku->goods_id = 0;
|
||||||
$sku->is_combination = 1;
|
$sku->is_combination = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$sku->status = $status;
|
$sku->status = $status;
|
||||||
$sku->title = $request->input('title');
|
$sku->title = $request->input('title');
|
||||||
$sku->sku_code = $request->input('external_sku_id');
|
$sku->name = $request->input('title');
|
||||||
$sku->external_sku_id = $request->input('external_sku_id');
|
$sku->sku_code = $externalSkuId;
|
||||||
|
$sku->external_sku_id = $externalSkuId;
|
||||||
$sku->stock = $stock;
|
$sku->stock = $stock;
|
||||||
|
$sku->sale_stock = $saleStock;
|
||||||
$sku->save();
|
$sku->save();
|
||||||
CombinationGood::query()
|
CombinationGood::query()
|
||||||
->where('goods_sku_id', $sku->id)
|
->where('goods_sku_id', $sku->id)
|
||||||
@ -180,16 +247,17 @@ class GoodsCombinationController extends Controller
|
|||||||
|
|
||||||
public function goodsSkus(Request $request, $title)
|
public function goodsSkus(Request $request, $title)
|
||||||
{
|
{
|
||||||
$goodsIds = Goods::query()
|
|
||||||
->where('title', 'like', '%' . $title . '%')
|
|
||||||
->pluck('id');
|
|
||||||
$skus = GoodsSku::query()
|
$skus = GoodsSku::query()
|
||||||
->whereIn('goods_id', $goodsIds)
|
->where('name', 'like', '%' . $title . '%')
|
||||||
->where('is_combination', 0)
|
->where('is_combination', 0)
|
||||||
->with('goods:id,title')
|
->with('goods:id,title')
|
||||||
->get(['id', 'title', 'goods_id']);
|
->get(['id', 'title', 'goods_id', "name"]);
|
||||||
foreach ($skus as &$sku) {
|
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);
|
return GoodsSkuResource::collection($skus);
|
||||||
|
|||||||
@ -5,10 +5,13 @@ namespace App\Http\Controllers\Goods;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\GoodsSkuRequest;
|
use App\Http\Requests\GoodsSkuRequest;
|
||||||
use App\Http\Resources\GoodsResource;
|
use App\Http\Resources\GoodsResource;
|
||||||
|
use App\Models\GoodsType;
|
||||||
use App\Models\Log as LogModel;
|
use App\Models\Log as LogModel;
|
||||||
|
use App\Services\Good\GoodService;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use App\Models\Goods;
|
use App\Models\Goods;
|
||||||
use App\Http\Requests\GoodsRequest;
|
use App\Http\Requests\GoodsRequest;
|
||||||
@ -42,28 +45,23 @@ class GoodsController extends Controller
|
|||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
if (!empty($request->goods_id)) {
|
$goodService = new GoodService();
|
||||||
$goods = Goods::query()->find($request->goods_id);
|
$goods = $goodService->saveDefaultGoodsByGoodType($request->type_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();
|
|
||||||
}
|
|
||||||
$goodsSkus = [];
|
$goodsSkus = [];
|
||||||
|
|
||||||
foreach ($request->skus as $item) {
|
foreach ($request->skus as $item) {
|
||||||
$item['goods_id'] = $goods->id;
|
$item['goods_id'] = $goods->id;
|
||||||
$item['stock'] = $item['num'];
|
$item['stock'] = $item['num'] ?? 0;
|
||||||
$item['reference_price'] = $item['cost'] * 1.5;
|
$item['reference_price'] = $item['cost'] * 1.5;
|
||||||
$item['external_sku_id'] = $goods->goods_code . '_' . $item['sku_code'];
|
$item['sku_code'] = !empty($item['external_sku_id']) ? $item['external_sku_id'] : $goodService->getRandomCode();
|
||||||
$item['name'] = $goods->title . $item['title'];
|
$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;
|
$goodsSkus[] = $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
$collection = $goods->skus()->createMany($goodsSkus)->toArray();
|
$collection = $goods->skus()->createMany($goodsSkus)->toArray();
|
||||||
$this->setAfterUpdateForLog($collection);
|
$this->setAfterUpdateForLog($collection);
|
||||||
$this->addLog(0, 'add');
|
$this->addLog(0, 'add');
|
||||||
@ -89,13 +87,14 @@ class GoodsController extends Controller
|
|||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function download()
|
public function download()
|
||||||
{
|
{
|
||||||
$file = resource_path('templates/goods_skus_import.xlsx');
|
$file = resource_path('templates/sale_stock_import.xlsx');
|
||||||
$headers = [
|
$headers = [
|
||||||
'Content-Type: application/xlsx',
|
'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\GoodsSkusExport;
|
||||||
use App\Exports\WeekDataExport;
|
use App\Exports\WeekDataExport;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Enum\ExcelKeyEnum;
|
||||||
use App\Http\Requests\GoodsRequest;
|
use App\Http\Requests\GoodsRequest;
|
||||||
use App\Http\Requests\GoodsSkuRequest;
|
use App\Http\Requests\GoodsSkuRequest;
|
||||||
use App\Imports\InventoryImport;
|
use App\Imports\InventoryImport;
|
||||||
use App\Imports\NewSetImport;
|
use App\Imports\NewSetImport;
|
||||||
|
use App\Imports\SaleStockImport;
|
||||||
use App\Models\BusinessOrderItem;
|
use App\Models\BusinessOrderItem;
|
||||||
use App\Models\DailySalesReport;
|
use App\Models\DailySalesReport;
|
||||||
use App\Models\DeveloperConfig;
|
use App\Models\DeveloperConfig;
|
||||||
use App\Models\Goods;
|
use App\Models\Goods;
|
||||||
use App\Models\Log;
|
use App\Models\Log;
|
||||||
use App\Models\Log as LogModel;
|
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\ArrayUtils;
|
||||||
use App\Utils\DateTimeUtils;
|
use App\Utils\DateTimeUtils;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@ -44,6 +50,86 @@ class GoodsSkusController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$ids = [];
|
||||||
|
$externals = $this->buildExternals($ids);
|
||||||
|
$builder = GoodsSku::query();
|
||||||
|
$this->preparQueryGoodsSkus($request, $builder);
|
||||||
|
$day = DateTimeUtils::getToday();
|
||||||
|
|
||||||
|
$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);
|
||||||
|
}])
|
||||||
|
->where('is_combination', 0);
|
||||||
|
$sum = null;
|
||||||
|
if ($request->get('goods_title')) {
|
||||||
|
$sumData = (clone $goodsSkusBuilder)->select('id',"stock")->get();
|
||||||
|
$sum['goods_number'] = 0;
|
||||||
|
$sum['stock']=0;
|
||||||
|
if (!empty($sumData)) {
|
||||||
|
foreach ($sumData as $item) {
|
||||||
|
$sum['goods_number'] += $ids[$item['id']] ?? 0;
|
||||||
|
$sum['stock'] += $item['stock'] ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sum['real_stock'] = ($sum['stock'] ?? 0) + $sum['goods_number'];
|
||||||
|
}
|
||||||
|
if ($sortField == "order_goods_num") {
|
||||||
|
$finalIds = [];
|
||||||
|
asort($ids);
|
||||||
|
foreach ($ids as $id => $number) {
|
||||||
|
$finalIds[] = $id;
|
||||||
|
}
|
||||||
|
if (empty($finalIds)) {
|
||||||
|
$goodsSkusBuilder->orderBy("id", $sortValue);
|
||||||
|
} else {
|
||||||
|
$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 = !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']] ?? 0;
|
||||||
|
} else {
|
||||||
|
$sku['order_detail'] = [];
|
||||||
|
$sku['order_goods_num'] = 0;
|
||||||
|
}
|
||||||
|
$sku['inventory_time'] = $lastInventoryTime;
|
||||||
|
if ('销售' === $rolesName[0]) {
|
||||||
|
$sku['cost'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($sku['yesterday_num'])) {
|
||||||
|
$sku['sale_ratio'] = round($sku['stock'] / $sku['yesterday_num'], 2) * 100;
|
||||||
|
} else {
|
||||||
|
$sku['sale_ratio'] = 0;
|
||||||
|
}
|
||||||
|
$sku['yesterday_num'] = bcadd($sku['stock'], $sku['order_goods_num']);
|
||||||
|
|
||||||
|
}
|
||||||
|
$data = [
|
||||||
|
"manage" => ["is_admin" => in_array($rolesName[0], ["运营", "超级管理员", "管理员", "系统管理员", "店铺运营"]) ? 1 : 0],
|
||||||
|
"sum" => $sum
|
||||||
|
];
|
||||||
|
return GoodsSkuResource::collection($goodsSkus)->additional($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildExternals(&$ids)
|
||||||
{
|
{
|
||||||
$fields = implode(',', [
|
$fields = implode(',', [
|
||||||
'shop_id',
|
'shop_id',
|
||||||
@ -60,7 +146,8 @@ class GoodsSkusController extends Controller
|
|||||||
->select(DB::raw($fields))
|
->select(DB::raw($fields))
|
||||||
->with([
|
->with([
|
||||||
'shop:id,name',
|
'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('created_at', '>', $orderRestTime)
|
||||||
->where('external_sku_id', '<>', '')
|
->where('external_sku_id', '<>', '')
|
||||||
@ -68,70 +155,33 @@ class GoodsSkusController extends Controller
|
|||||||
->orderByDesc('number')
|
->orderByDesc('number')
|
||||||
->get()
|
->get()
|
||||||
->toArray();
|
->toArray();
|
||||||
$ids = $externals = [];
|
$externals = [];
|
||||||
foreach ($businessOrderItems as $businessOrderItem) {
|
foreach ($businessOrderItems as $businessOrderItem) {
|
||||||
if (is_null($businessOrderItem['goods_sku'])) {
|
if (is_null($businessOrderItem['goods_sku'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$id = $businessOrderItem['goods_sku']['id'];
|
$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'];
|
||||||
|
$businessOrderItem['goods_number'] = ((int)$businessOrderItem['number']) * $combinationGoods['item_num'];
|
||||||
|
$externals[$combinationGoods['item_id']][] = $businessOrderItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (isset($ids[$id])) {
|
if (isset($ids[$id])) {
|
||||||
$ids[$id] += (int)$businessOrderItem['number'];
|
$ids[$id] += (int)$businessOrderItem['number'];
|
||||||
} else {
|
} else {
|
||||||
$ids[$id] = (int)$businessOrderItem['number'];
|
$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']);
|
|
||||||
}])
|
|
||||||
->with(['daily' => function ($query) use ($day) {
|
|
||||||
$query->where('day', $day);
|
|
||||||
}])
|
|
||||||
->whereIn('id', $finalIds)
|
|
||||||
->orderByRaw("FIELD(id, {$idField})")
|
|
||||||
->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'));
|
|
||||||
} else {
|
|
||||||
$sku['order_detail'] = [];
|
|
||||||
$sku['order_goods_num'] = 0;
|
|
||||||
}
|
|
||||||
$sku['order_goods_num'] -= $sku['daily']['reissue_num'];
|
|
||||||
$sku['inventory_time'] = $lastInventoryTime;
|
|
||||||
if ('销售' === $rolesName[0]) {
|
|
||||||
$sku['cost'] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GoodsSkuResource::collection($goodsSkus);
|
return $externals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function preparQueryGoodsSkus(Request $request, &$builder)
|
private function preparQueryGoodsSkus(Request $request, &$builder)
|
||||||
{
|
{
|
||||||
if ($request->get('keyword_type') && $request->get('keyword_value')) {
|
if ($request->get('keyword_type') && $request->get('keyword_value')) {
|
||||||
@ -189,22 +239,14 @@ class GoodsSkusController extends Controller
|
|||||||
$sku = GoodsSku::query()->find($id);
|
$sku = GoodsSku::query()->find($id);
|
||||||
$this->setBeforeUpdateForLog($sku->toArray());
|
$this->setBeforeUpdateForLog($sku->toArray());
|
||||||
$skuInfo = $request->sku;
|
$skuInfo = $request->sku;
|
||||||
$skuInfo['external_sku_id'] = $request->goods['goods_code'] . '_' . $request->sku['sku_code'];
|
$goodService = new GoodService();
|
||||||
$skuInfo['name'] = $request->goods['title'] . $request->sku['title'];
|
$goods = $goodService->saveDefaultGoodsByGoodType($request->goods['type_id']);
|
||||||
|
$skuInfo['goods_id'] = $goods->id;
|
||||||
|
$skuInfo['name'] = $goodService->getSkuName($request->goods['type_id'], $skuInfo);
|
||||||
$sku->update($skuInfo);
|
$sku->update($skuInfo);
|
||||||
$this->setAfterUpdateForLog($sku->toArray());
|
$this->setAfterUpdateForLog($sku->toArray());
|
||||||
$this->addLog($id, 'update');
|
$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();
|
DB::commit();
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
@ -221,7 +263,7 @@ class GoodsSkusController extends Controller
|
|||||||
public function batchUpdate(Request $request)
|
public function batchUpdate(Request $request)
|
||||||
{
|
{
|
||||||
$appendRules = [
|
$appendRules = [
|
||||||
'updateType' => ['required', 'string', Rule::in(['newest', 'inventory', 'stock'])],
|
'updateType' => ['required', 'string', Rule::in(['newest', 'inventory', 'stock', "saleStock"])],
|
||||||
'skus' => ['required', 'array'],
|
'skus' => ['required', 'array'],
|
||||||
'skus.*.id' => [
|
'skus.*.id' => [
|
||||||
'required',
|
'required',
|
||||||
@ -240,6 +282,62 @@ class GoodsSkusController extends Controller
|
|||||||
return $this->$function($request);
|
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();
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
DB::rollBack();
|
||||||
|
$this->res = [
|
||||||
|
'httpCode' => 400,
|
||||||
|
'errorCode' => 400500,
|
||||||
|
'errorMessage' => $exception->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!empty($updateIds)) {
|
||||||
|
event(new BatchStockUpdateEvent($updateIds));
|
||||||
|
}
|
||||||
|
return response($this->res, $this->res['httpCode']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上新
|
* 上新
|
||||||
*
|
*
|
||||||
@ -297,7 +395,7 @@ class GoodsSkusController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 库存盘点
|
* 库存盘点 准备废弃中
|
||||||
*
|
*
|
||||||
* @param $request
|
* @param $request
|
||||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
|
||||||
@ -377,6 +475,7 @@ class GoodsSkusController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -472,7 +571,7 @@ class GoodsSkusController extends Controller
|
|||||||
$validator = Validator::make($request->all(), $rules);
|
$validator = Validator::make($request->all(), $rules);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||||
goto end;
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
$updateField = \request('updateField');
|
$updateField = \request('updateField');
|
||||||
$sku = GoodsSku::query()->find($id);
|
$sku = GoodsSku::query()->find($id);
|
||||||
@ -494,10 +593,11 @@ class GoodsSkusController extends Controller
|
|||||||
$changeNum = $sku->reserve - $request->reserve;
|
$changeNum = $sku->reserve - $request->reserve;
|
||||||
if (0 > $changeNum + $sku->stock) {
|
if (0 > $changeNum + $sku->stock) {
|
||||||
$this->setValidatorFailResponse('预留量超过库存数量');
|
$this->setValidatorFailResponse('预留量超过库存数量');
|
||||||
goto end;
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
$sku->stock += $changeNum;
|
$sku->stock += $changeNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sku->$updateField = $request->$updateField;
|
$sku->$updateField = $request->$updateField;
|
||||||
$sku->save();
|
$sku->save();
|
||||||
$this->setAfterUpdateForLog($sku->$updateField);
|
$this->setAfterUpdateForLog($sku->$updateField);
|
||||||
@ -551,6 +651,7 @@ class GoodsSkusController extends Controller
|
|||||||
$endDate = Carbon::now()->subWeek()->endOfWeek()->toDateString();
|
$endDate = Carbon::now()->subWeek()->endOfWeek()->toDateString();
|
||||||
return Excel::download(new WeekDataExport($startDate, $endDate), $startDate . '~' . $endDate . '.xlsx');
|
return Excel::download(new WeekDataExport($startDate, $endDate), $startDate . '~' . $endDate . '.xlsx');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Excel::download(new GoodsSkusExport($type), $type . '.xlsx');
|
return Excel::download(new GoodsSkusExport($type), $type . '.xlsx');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,4 +760,25 @@ class GoodsSkusController extends Controller
|
|||||||
|
|
||||||
return $data;
|
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\Http\Resources\GoodsTypeResource;
|
||||||
use App\Models\GoodsType;
|
use App\Models\GoodsType;
|
||||||
use App\Models\Log as LogModel;
|
use App\Models\Log as LogModel;
|
||||||
|
use App\Utils\FormatUtils;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@ -23,7 +24,11 @@ class GoodsTypesController extends Controller
|
|||||||
|
|
||||||
public function index(Request $request)
|
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);
|
return GoodsTypeResource::collection($goodsTypes);
|
||||||
}
|
}
|
||||||
@ -31,27 +36,34 @@ class GoodsTypesController extends Controller
|
|||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$validator = Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
'names' => 'required|array',
|
'name' => 'required|string|max:191',
|
||||||
'names.*' => 'required|string|max:191|unique:goods_types,name',
|
'parent_id' => 'sometimes',
|
||||||
|
'show' => 'sometimes|integer',
|
||||||
]);
|
]);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
$goodsTypes = [];
|
$level = 1;
|
||||||
foreach ($request->names as $name) {
|
if ($request->parent_id) {
|
||||||
$goodsTypes[] = ['name' => $name];
|
$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();
|
$goodsType = new GoodsType();
|
||||||
if (!$goodsType->batchInsert($goodsTypes)) {
|
$goodsType->parent_id = $request->parent_id ?? 0;
|
||||||
$this->res = [
|
$goodsType->show = $request->show ?? 1;
|
||||||
'httpCode' => 500,
|
$goodsType->name = $request->name;
|
||||||
'errorCode' => 500500,
|
$goodsType->level = $level;
|
||||||
'errorMessage' => '批量添加失败',
|
$goodsType->save();
|
||||||
];
|
|
||||||
}
|
$this->setAfterUpdateForLog($request->all());
|
||||||
$this->setAfterUpdateForLog($goodsTypes);
|
|
||||||
$this->addLog(0, 'add');
|
$this->addLog(0, 'add');
|
||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
@ -65,12 +77,9 @@ class GoodsTypesController extends Controller
|
|||||||
public function update($id, Request $request)
|
public function update($id, Request $request)
|
||||||
{
|
{
|
||||||
$validator = Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
'name' => [
|
'name' => 'sometimes|string|max:191',
|
||||||
'required',
|
'parent_id' => 'sometimes',
|
||||||
'string',
|
'show' => 'sometimes|integer',
|
||||||
'max:191',
|
|
||||||
Rule::unique('goods_types')->ignore($id),
|
|
||||||
]
|
|
||||||
]);
|
]);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||||
@ -79,7 +88,18 @@ class GoodsTypesController extends Controller
|
|||||||
}
|
}
|
||||||
$goodsType = GoodsType::query()->find($id);
|
$goodsType = GoodsType::query()->find($id);
|
||||||
$this->setBeforeUpdateForLog($goodsType->name);
|
$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();
|
$goodsType->save();
|
||||||
$this->setAfterUpdateForLog($goodsType->name);
|
$this->setAfterUpdateForLog($goodsType->name);
|
||||||
$this->addLog($id, 'name');
|
$this->addLog($id, 'name');
|
||||||
@ -95,4 +115,11 @@ class GoodsTypesController extends Controller
|
|||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
app/Http/Controllers/Message/WebsiteMessageController.php
Normal file
88
app/Http/Controllers/Message/WebsiteMessageController.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batchRead(Request $request)
|
||||||
|
{
|
||||||
|
$params = $request->validate([
|
||||||
|
'ids' => 'required|array'
|
||||||
|
], [
|
||||||
|
'ids.required' => '需要操作的ids'
|
||||||
|
]);
|
||||||
|
WebsiteMessages::query()->whereIn('id', $params['ids'])->update(['status' => 1]);
|
||||||
|
return $this->success();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Models\Log as LogModel;
|
use App\Models\Log as LogModel;
|
||||||
use App\Utils\ArrayUtils;
|
use App\Utils\ArrayUtils;
|
||||||
use App\Utils\FormatUtils;
|
use App\Utils\FormatUtils;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Spatie\Permission\Models\Permission;
|
use Spatie\Permission\Models\Permission;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|||||||
67
app/Http/Controllers/Shop/ShopSendsController.php
Normal file
67
app/Http/Controllers/Shop/ShopSendsController.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Shop;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\BusinessGoodsSku;
|
||||||
|
use App\Models\DeveloperConfig;
|
||||||
|
use App\Models\GoodsSku;
|
||||||
|
use App\Models\Shop;
|
||||||
|
use App\Http\Resources\ShopsResource;
|
||||||
|
use App\Models\ShopSender;
|
||||||
|
use App\Models\ShopShip;
|
||||||
|
use App\Services\Business\KuaiTuanTuan\FaceSheet;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use App\Services\Business\BusinessFactory;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use App\Models\BusinessOrderItem;
|
||||||
|
|
||||||
|
class ShopSendsController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$shopSender = ShopSender::query()->filter()->paginate($request->get('per_page'));
|
||||||
|
|
||||||
|
return JsonResource::collection($shopSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$params = $request->validate([
|
||||||
|
'id' => 'sometimes',
|
||||||
|
'shop_id' => 'required|int',
|
||||||
|
'province' => 'required',
|
||||||
|
'city' => 'required',
|
||||||
|
'district' => 'required',
|
||||||
|
'detail' => 'required',
|
||||||
|
'name' => 'required',
|
||||||
|
'mobile' => 'required',
|
||||||
|
'sort' => 'sometimes',
|
||||||
|
'wp_code' => 'sometimes',
|
||||||
|
], [
|
||||||
|
'shop_id.required' => '请选择店铺',
|
||||||
|
'province.required' => '请选择省份',
|
||||||
|
'city.required' => '请选择城市',
|
||||||
|
'district.required' => '请选择地区',
|
||||||
|
'detail.required' => '请填写详细地址',
|
||||||
|
]);
|
||||||
|
$params['wp_code'] = $params['wp_code'] ?? 'JD';
|
||||||
|
$params['country'] = $params['country'] ?? '中国';
|
||||||
|
if (empty($params['id'])) {
|
||||||
|
$shopSender = new ShopSender();
|
||||||
|
$shopSender->fill($params);
|
||||||
|
$shopSender->save();
|
||||||
|
} else {
|
||||||
|
ShopSender::query()->where('id', $params['id'])->update($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response($this->res, $this->res['httpCode']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@ use App\Models\ShopShip;
|
|||||||
use App\Services\Business\KuaiTuanTuan\FaceSheet;
|
use App\Services\Business\KuaiTuanTuan\FaceSheet;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use App\Services\Business\BusinessFactory;
|
use App\Services\Business\BusinessFactory;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@ -52,13 +53,16 @@ class ShopsController extends Controller
|
|||||||
$validator = Validator::make($request->all(), [
|
$validator = Validator::make($request->all(), [
|
||||||
'name' => 'required|string|max:191|unique:shops,name',
|
'name' => 'required|string|max:191|unique:shops,name',
|
||||||
'plat_id' => 'required|integer',
|
'plat_id' => 'required|integer',
|
||||||
'ratio' => 'required',
|
'ratio' => 'sometimes',
|
||||||
]);
|
]);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
$this->setValidatorFailResponse($validator->getMessageBag()->getMessages());
|
||||||
|
|
||||||
return response($this->res, $this->res['httpCode']);
|
return response($this->res, $this->res['httpCode']);
|
||||||
}
|
}
|
||||||
|
if(empty($request->ratio)){
|
||||||
|
$request->ratio = "*1";
|
||||||
|
}
|
||||||
$operator = substr($request->ratio, 0, 1);
|
$operator = substr($request->ratio, 0, 1);
|
||||||
if (!in_array($operator, ['+', '-', '*', '/'])) {
|
if (!in_array($operator, ['+', '-', '*', '/'])) {
|
||||||
$this->res->errorMessage = '运算符号仅允许+,-,*,/';
|
$this->res->errorMessage = '运算符号仅允许+,-,*,/';
|
||||||
@ -128,6 +132,7 @@ class ShopsController extends Controller
|
|||||||
$business->bindGoods($request->get('data'));
|
$business->bindGoods($request->get('data'));
|
||||||
}
|
}
|
||||||
if ('orders' === $request->get('type')) {
|
if ('orders' === $request->get('type')) {
|
||||||
|
Log::info('秒选order',[$request->get('data')]);
|
||||||
$business->saveOrders($request->get('data'));
|
$business->saveOrders($request->get('data'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,10 +208,11 @@ class ShopsController extends Controller
|
|||||||
} else {
|
} else {
|
||||||
$shops = $builder->where('id', $shopId)->get();
|
$shops = $builder->where('id', $shopId)->get();
|
||||||
}
|
}
|
||||||
|
//同步三方的是在售库存
|
||||||
$skus = GoodsSku::query()
|
$skus = GoodsSku::query()
|
||||||
->where('updated_at', '>', date('Y-m-d 07:01:00'))
|
->where('updated_at', '>', date('Y-m-d 07:01:00'))
|
||||||
->whereNotNull('external_sku_id')
|
->whereNotNull('external_sku_id')
|
||||||
->pluck('stock', 'external_sku_id')
|
->pluck('sale_stock', 'external_sku_id')
|
||||||
->toArray();
|
->toArray();
|
||||||
foreach ($shops as $shop) {
|
foreach ($shops as $shop) {
|
||||||
$business = BusinessFactory::init()->make($shop->plat_id);
|
$business = BusinessFactory::init()->make($shop->plat_id);
|
||||||
@ -220,6 +226,7 @@ class ShopsController extends Controller
|
|||||||
->get()
|
->get()
|
||||||
->toArray();
|
->toArray();
|
||||||
$business->batchIncrQuantity($businessGoodsSkus, $stock, false);
|
$business->batchIncrQuantity($businessGoodsSkus, $stock, false);
|
||||||
|
usleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
141
app/Http/Controllers/Supplier/DailyStockRecordController.php
Normal file
141
app/Http/Controllers/Supplier/DailyStockRecordController.php
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<?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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$start = $request->get("start_time");
|
||||||
|
$end = $request->get("end_time");
|
||||||
|
$dailyStockRecord = $build->when($start, function ($query) use ($start) {
|
||||||
|
$query->where("created_at", ">=", $start);
|
||||||
|
})->when($end, function ($query) use ($end) {
|
||||||
|
$query->where("created_at", "<=", $end);
|
||||||
|
})->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']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
320
app/Http/Controllers/Supplier/PurchaseRecordController.php
Normal file
320
app/Http/Controllers/Supplier/PurchaseRecordController.php
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
<?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->date_start_time) && !empty($request->date_end_time)) {
|
||||||
|
$dateStart = Carbon::parse($request->date_start_time)->toDateString();
|
||||||
|
$dateEnd = Carbon::parse($request->date_end_time)->subDay()->toDateString();
|
||||||
|
$builder->whereBetween('date', [$dateStart, $dateEnd]);
|
||||||
|
}
|
||||||
|
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']);
|
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] ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Http/Enum/BusinessOrderShippingStatus.php
Normal file
17
app/Http/Enum/BusinessOrderShippingStatus.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Enum;
|
||||||
|
|
||||||
|
|
||||||
|
class BusinessOrderShippingStatus
|
||||||
|
{
|
||||||
|
const UNSHIP = 0;
|
||||||
|
const SHIPPED = 1;//已发货
|
||||||
|
const SHIPPING = 2;//部分发货
|
||||||
|
const RECEIVED = 3;//已收货
|
||||||
|
|
||||||
|
const SHIPPED_MAP = [
|
||||||
|
self::SHIPPED, self::SHIPPING, self::RECEIVED,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
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)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
|
//目前permission仅菜单权限和接口权限耦合 这里先放开
|
||||||
|
$permissions = $request->user()->getPermissionsViaRoles()->toArray();
|
||||||
|
return $next($request);
|
||||||
// 获取当前路由名称
|
// 获取当前路由名称
|
||||||
$currentRouteName = Route::currentRouteName();
|
$currentRouteName = Route::currentRouteName();
|
||||||
// 引入当前守卫的权限文件
|
// 引入当前守卫的权限文件
|
||||||
|
|||||||
@ -25,11 +25,7 @@ class GoodsRequest extends FormRequest
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => ['sometimes', 'required', 'integer', 'exists:goods,id'],
|
|
||||||
'title' => ['required', 'string', 'max:191'],
|
|
||||||
'type_id' => ['required', 'integer', 'exists:goods_types,id'],
|
'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'],
|
'id' => ['sometimes', 'required', 'integer', 'exists:goods_skus,id'],
|
||||||
'goods_id' => ['sometimes', 'required', 'integer', 'exists:goods,id'],
|
'goods_id' => ['sometimes', 'required', 'integer', 'exists:goods,id'],
|
||||||
'title' => ['sometimes', 'required', 'string', 'max:191'],
|
'title' => ['sometimes', 'required', 'string', 'max:191'],
|
||||||
'sku_code' => ['sometimes', 'required', 'distinct', 'alpha_dash', 'max:32'],
|
|
||||||
'status' => ['sometimes', 'required', 'integer', Rule::in([0, 1, 2])],
|
'status' => ['sometimes', 'required', 'integer', Rule::in([0, 1, 2])],
|
||||||
'num' => ['sometimes', 'required', 'integer'],
|
'num' => ['sometimes', 'required', 'integer'],
|
||||||
'cost' => ['sometimes', 'required', 'numeric'],
|
'cost' => ['sometimes', 'required', 'numeric'],
|
||||||
|
'attribute' => ['sometimes', 'required', 'string'],
|
||||||
'reference_price' => [
|
'reference_price' => [
|
||||||
'sometimes',
|
'sometimes',
|
||||||
'numeric',
|
'numeric',
|
||||||
|
|||||||
@ -9,11 +9,21 @@ class BusinessOrderResource extends JsonResource
|
|||||||
/**
|
/**
|
||||||
* Transform the resource into an array.
|
* Transform the resource into an array.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function toArray($request)
|
public function toArray($request)
|
||||||
{
|
{
|
||||||
return parent::toArray($request);
|
$data = parent::toArray($request);
|
||||||
|
$data['confirm_at'] = date('Y-m-d H:i:s', $data['confirm_at'] / 1000);
|
||||||
|
$map = ['未发货', '已发货', '部分发货', "已收货", '' => ''];
|
||||||
|
$data['shipping_status'] = $map[$data['shipping_status']] ?? '';
|
||||||
|
$map = ['帮忙团订单', '自卖团订单', '' => ''];
|
||||||
|
$data['is_supplier'] = $map[$data['is_supplier']] ?? '';
|
||||||
|
$map = ['未取消', '已取消', '' => ''];
|
||||||
|
$data['cancel_status'] = $map[$data['cancel_status']] ?? '';
|
||||||
|
$map = ['未发起售后 ', '退款中', '退款成功', '待处理', '拒绝退款', '待(顾客)退货', '待(团长)确认退货', '撤销', '撤销', '(系统)关闭' => ''];
|
||||||
|
$data['after_sales_status'] = $map[$data['after_sales_status']] ?? '';
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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['name']}库存可能需要补货,当前实际库存{$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['name']}编码{$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\Models\GoodsSku;
|
||||||
use App\Utils\ArrayUtils;
|
use App\Utils\ArrayUtils;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||||
use Maatwebsite\Excel\Concerns\ToArray;
|
use Maatwebsite\Excel\Concerns\ToArray;
|
||||||
use Maatwebsite\Excel\Concerns\WithStartRow;
|
use Maatwebsite\Excel\Concerns\WithStartRow;
|
||||||
@ -50,18 +51,23 @@ class CombinationGoodsImport implements ToArray, SkipsEmptyRows, WithStartRow
|
|||||||
$itemCodes = array_column($info['item'], 'item_code');
|
$itemCodes = array_column($info['item'], 'item_code');
|
||||||
$skus = GoodsSku::query()
|
$skus = GoodsSku::query()
|
||||||
->whereIn('external_sku_id', $itemCodes)
|
->whereIn('external_sku_id', $itemCodes)
|
||||||
->get(['id', 'external_sku_id', 'stock'])
|
->get(['id', 'external_sku_id', 'stock', "sale_stock"])
|
||||||
->toArray();
|
->toArray();
|
||||||
$skus = ArrayUtils::index($skus, 'external_sku_id');
|
$skus = ArrayUtils::index($skus, 'external_sku_id');
|
||||||
$stock = [];
|
$stock = [];
|
||||||
|
$saleStock = [];
|
||||||
foreach ($info['item'] as $item) {
|
foreach ($info['item'] as $item) {
|
||||||
$stock[] = (int)($skus[$item['item_code']]['stock'] / $item['item_num']);
|
$stock[] = (int)($skus[$item['item_code']]['stock'] / $item['item_num']);
|
||||||
|
$saleStock[] = (int)($skus[$item['item_code']]['sale_stock'] / $item['item_num']);
|
||||||
|
|
||||||
}
|
}
|
||||||
$stock = min($stock);
|
$stock = min($stock);
|
||||||
$status = $stock ? (5 < $stock ? 1 : 2) : 0;
|
$saleStock = min($saleStock);
|
||||||
|
$status = $saleStock ? (5 < $saleStock ? 1 : 2) : 0;
|
||||||
$sku = GoodsSku::query()->updateOrCreate(
|
$sku = GoodsSku::query()->updateOrCreate(
|
||||||
['external_sku_id' => $info['external_sku_id'], 'is_combination' => 1],
|
['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()
|
CombinationGood::query()
|
||||||
->where('goods_sku_id', $sku->id)
|
->where('goods_sku_id', $sku->id)
|
||||||
|
|||||||
@ -2,16 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Imports;
|
namespace App\Imports;
|
||||||
|
|
||||||
use App\Events\BatchStockUpdateEvent;
|
|
||||||
use App\Jobs\SyncCostToMiaoXuan;
|
|
||||||
use App\Models\DailyStockRecord;
|
|
||||||
use App\Models\GoodsSku;
|
use App\Models\GoodsSku;
|
||||||
use App\Models\TodayPrice;
|
use App\Services\GoodSku\GoodSkuService;
|
||||||
use App\Utils\DateTimeUtils;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
|
||||||
use Maatwebsite\Excel\Concerns\ToArray;
|
use Maatwebsite\Excel\Concerns\ToArray;
|
||||||
use App\Utils\ArrayUtils;
|
|
||||||
|
|
||||||
class InventoryImport implements ToArray, SkipsEmptyRows
|
class InventoryImport implements ToArray, SkipsEmptyRows
|
||||||
{
|
{
|
||||||
@ -20,85 +16,30 @@ class InventoryImport implements ToArray, SkipsEmptyRows
|
|||||||
*/
|
*/
|
||||||
public function array(array $collection)
|
public function array(array $collection)
|
||||||
{
|
{
|
||||||
$header = $collection[0];
|
if (!empty($collection)) {
|
||||||
unset($collection[0]);
|
unset($collection[0]);
|
||||||
$externalSkuId = [];
|
$externalSkuIds = [];
|
||||||
foreach ($collection as &$row) {
|
$inventoryKeyByExternalSkuIdMap = [];
|
||||||
$row = array_map(static function ($v) {
|
foreach ($collection as &$row) {
|
||||||
return trim($v);
|
$row = array_map(static function ($v) {
|
||||||
}, $row);
|
return trim($v);
|
||||||
$externalSkuId[] = $row[0];
|
}, $row);
|
||||||
}
|
$inventoryKeyByExternalSkuIdMap[$row[0]] = $row[2];
|
||||||
unset($row);
|
$externalSkuIds[] = $row[0];
|
||||||
$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;
|
|
||||||
}
|
}
|
||||||
$goodsSku = $hasGoodsSkus[$row[0]];
|
unset($row);
|
||||||
if ('下架' === $goodsSku['status']) {
|
//新版盘点excel字段 编码 商品名称 盘点数
|
||||||
GoodsSku::query()->where('id', $goodsSku['id'])->update([
|
$goodsSkus = GoodsSku::query()->with("combinationGoods")->whereIn('external_sku_id', $externalSkuIds)
|
||||||
'stock' => $row[2] + $row[3],
|
->get()->toArray();
|
||||||
'cost' => $row[4],
|
$goodsSkus = collect($goodsSkus)->map(function ($v) use ($inventoryKeyByExternalSkuIdMap) {
|
||||||
'status' => 1,
|
if (isset($inventoryKeyByExternalSkuIdMap[$v['external_sku_id']])) {
|
||||||
]);
|
$v['inventory'] = $inventoryKeyByExternalSkuIdMap[$v['external_sku_id']];
|
||||||
} else {
|
return $v;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
})->toArray();
|
||||||
$todayPrice[] = [
|
Log::info("goodsSkus",$goodsSkus);
|
||||||
'day' => $day,
|
$goodSkuService = new GoodSkuService();
|
||||||
'external_sku_id' => $goodsSku['external_sku_id'],
|
$goodSkuService->inventory($goodsSkus);
|
||||||
'shop_price' => json_encode($shopPrice, 256)
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
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 = Carbon::now()->toDateTimeString();
|
||||||
|
}
|
||||||
|
$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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
app/Imports/SaleStockImport.php
Normal file
84
app/Imports/SaleStockImport.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?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();
|
||||||
|
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new Exception($exception->getMessage());
|
||||||
|
}
|
||||||
|
if (!empty($updateIds)) {
|
||||||
|
event(new BatchStockUpdateEvent($updateIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,8 @@ use App\Models\Shop;
|
|||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use App\Services\Business\BusinessFactory;
|
use App\Services\Business\BusinessFactory;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class BatchStockUpdateListener implements ShouldQueue
|
class BatchStockUpdateListener implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -35,18 +37,23 @@ class BatchStockUpdateListener implements ShouldQueue
|
|||||||
if (empty($shops)) {
|
if (empty($shops)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($shops as $shop) {
|
try {
|
||||||
foreach ($event->goodsSkus as $goodsSku) {
|
foreach ($shops as $shop) {
|
||||||
$num = $goodsSku->stock;
|
foreach ($event->goodsSkus as $goodsSku) {
|
||||||
$businessGoodsSkus = BusinessGoodsSku::query()
|
//后续同步三方使用在售库存
|
||||||
->select(['goods_id', 'sku_id', 'external_sku_id'])
|
$num = $goodsSku->sale_stock;
|
||||||
->where('shop_id', $shop->id)
|
$businessGoodsSkus = BusinessGoodsSku::query()
|
||||||
->where('is_sync', 1)
|
->select(['goods_id', 'sku_id', 'external_sku_id'])
|
||||||
->where('external_sku_id', $goodsSku->external_sku_id)
|
->where('shop_id', $shop->id)
|
||||||
->get();
|
->where('is_sync', 1)
|
||||||
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->batchIncrQuantity($businessGoodsSkus->toArray(), $num, false);
|
->where('external_sku_id', $goodsSku->external_sku_id)
|
||||||
usleep(140);
|
->get();
|
||||||
|
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->batchIncrQuantity($businessGoodsSkus->toArray(), $num, false);
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Log::error("同步三方库存出现异常", [$exception->getMessage()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
app/Listeners/BusinessOrderUpdateListener.php
Normal file
72
app/Listeners/BusinessOrderUpdateListener.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?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)) {
|
||||||
|
//查询库存是否满足告警规则
|
||||||
|
//查找昨日统计的库存数据
|
||||||
|
$record = DailyStockRecord::query()->where('sku_id', $event->goodsSku->id)->where("inventory", '>', 0)->orderByDesc('day')->first();
|
||||||
|
Log::info("库存告警record", [$record]);
|
||||||
|
$inventory = $record->inventory ?? 0;
|
||||||
|
$expireTime = Carbon::now()->addMinutes(30)->toDateTimeString();
|
||||||
|
$proportion = Cache::remember(CacheKeyEnum::STOCK_RULE_PROPORTION, $expireTime, function () {
|
||||||
|
$developerConfig = DeveloperConfig::query()->where("key", "=", DevConfigKeyEnum::STOCK_RULE_PROPORTION)->first();
|
||||||
|
return $developerConfig['value'] ?? DevConfigKeyEnum::DEFAULT_STOCK_RULE_PROPORTION;
|
||||||
|
});
|
||||||
|
//库存比例小于最近盘点多少告警 一天也只是告警一次
|
||||||
|
if ($inventory > 10 && $inventory * $proportion > $event->goodsSku->stock) {
|
||||||
|
$messageService = new MessageService();
|
||||||
|
$messageService->createLowerStockNoticeMessage($inventory, $event->goodsSku->toArray());
|
||||||
|
//更新库存状态
|
||||||
|
GoodsSku::query()->where("id", "=", $event->goodsSku->id)->update([
|
||||||
|
"status" => SkuStatusEnum::NOTICE
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
Log::error("库存告警发生异常", ["error" => $exception->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
|
use App\Events\CancelLogisticEvent;
|
||||||
use App\Events\CreateLogisticEvent;
|
use App\Events\CreateLogisticEvent;
|
||||||
use App\Models\Shop;
|
use App\Models\Shop;
|
||||||
use App\Models\Waybill;
|
use App\Models\Waybill;
|
||||||
@ -11,9 +12,6 @@ use Illuminate\Queue\InteractsWithQueue;
|
|||||||
|
|
||||||
class CancelLogisticListener implements ShouldQueue
|
class CancelLogisticListener implements ShouldQueue
|
||||||
{
|
{
|
||||||
public $connection = 'redis';
|
|
||||||
|
|
||||||
public $queue = 'listeners';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the event listener.
|
* Create the event listener.
|
||||||
@ -31,7 +29,7 @@ class CancelLogisticListener implements ShouldQueue
|
|||||||
* @param CreateLogisticEvent $event
|
* @param CreateLogisticEvent $event
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle(CreateLogisticEvent $event)
|
public function handle(CancelLogisticEvent $event)
|
||||||
{
|
{
|
||||||
$waybillNo = Waybill::query()
|
$waybillNo = Waybill::query()
|
||||||
->where('shop_id', $event->shopId)
|
->where('shop_id', $event->shopId)
|
||||||
|
|||||||
@ -9,6 +9,8 @@ use App\Utils\DateTimeUtils;
|
|||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use App\Events\BatchStockUpdateEvent;
|
use App\Events\BatchStockUpdateEvent;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class CombinationGoodsStockUpdateListener implements ShouldQueue
|
class CombinationGoodsStockUpdateListener implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -53,20 +55,32 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 减子商品库存
|
$updateIds = [];
|
||||||
|
//拉取三分订单时可能出现组合订单的情况 需要同步扣减库存
|
||||||
if ($combinationGoodsIds) {
|
if ($combinationGoodsIds) {
|
||||||
$combinationGoods = CombinationGood::query()
|
$combinationGoods = CombinationGood::query()
|
||||||
->with('goodsSku:id,stock')
|
->with('goodsSku:id,stock')
|
||||||
->whereIn('goods_sku_id', $combinationGoodsIds)
|
->whereIn('goods_sku_id', $combinationGoodsIds)
|
||||||
->get();
|
->get();
|
||||||
|
$num = !empty($event->num) ? $event->num : -1;
|
||||||
foreach ($combinationGoods as $item) {
|
foreach ($combinationGoods as $item) {
|
||||||
$goodsSku = GoodsSku::query()->find($item['item_id']);
|
DB::transaction(function () use ($item, &$updateIds, $num) {
|
||||||
$stock = $goodsSku->stock - $item['item_num'];
|
$goodsSku = GoodsSku::query()->find($item['item_id']);
|
||||||
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock);
|
$stock = $goodsSku->stock + $item['item_num'] * $num;
|
||||||
$goodsSku->status = $status;
|
//新增逻辑 在线库存同步扣减
|
||||||
$goodsSku->stock = $stock;
|
$saleStock = max($goodsSku->sale_stock + $item['item_num'] * $num, 0);
|
||||||
$goodsSku->save();
|
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock, $saleStock);
|
||||||
$updateIds[] = $goodsSku->id;
|
$goodsSku->status = $status;
|
||||||
|
$goodsSku->stock = $stock;
|
||||||
|
$goodsSku->sale_stock = $saleStock;
|
||||||
|
$goodsSku->save();
|
||||||
|
Log::info("sku 业务订单库存更:{$goodsSku->id},num:{$num}", [$stock, $saleStock]);
|
||||||
|
$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 +90,30 @@ class CombinationGoodsStockUpdateListener implements ShouldQueue
|
|||||||
->pluck('goods_sku_id');
|
->pluck('goods_sku_id');
|
||||||
foreach ($goodsSkuIds as $goodsSkuId) {
|
foreach ($goodsSkuIds as $goodsSkuId) {
|
||||||
$combinationGoods = CombinationGood::query()
|
$combinationGoods = CombinationGood::query()
|
||||||
->with('goodsSkuItem:id,stock')
|
->with('goodsSkuItem:id,stock,sale_stock')
|
||||||
->where('goods_sku_id', $goodsSkuId)
|
->where('goods_sku_id', $goodsSkuId)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$stock = [];
|
$stock = [];
|
||||||
|
$saleStock = [];
|
||||||
foreach ($combinationGoods as $goods) {
|
foreach ($combinationGoods as $goods) {
|
||||||
$stock[] = (int)($goods['goodsSkuItem']['stock'] / $goods['item_num']);
|
$stock[] = (int)($goods['goodsSkuItem']['stock'] / $goods['item_num']);
|
||||||
|
$saleStock[] = (int)($goods['goodsSkuItem']['sale_stock'] / $goods['item_num']);
|
||||||
}
|
}
|
||||||
|
//库存和在线可售库存都是通过子商品维护的
|
||||||
$stock = min($stock);
|
$stock = min($stock);
|
||||||
|
$saleStock = min($saleStock);
|
||||||
$goodsSku = GoodsSku::query()->find($goodsSkuId);
|
$goodsSku = GoodsSku::query()->find($goodsSkuId);
|
||||||
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock);
|
//新增在线可售逻辑判断 前置已经完成逻辑扣减或者增加
|
||||||
|
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock, $saleStock);
|
||||||
$goodsSku->status = $status;
|
$goodsSku->status = $status;
|
||||||
$goodsSku->stock = $stock;
|
$goodsSku->stock = $stock;
|
||||||
|
$goodsSku->sale_stock = $saleStock;
|
||||||
$goodsSku->save();
|
$goodsSku->save();
|
||||||
$updateIds[] = $goodsSkuId;
|
$updateIds[] = $goodsSkuId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($updateIds) {
|
if ($updateIds) {
|
||||||
$updateIds = array_unique($updateIds);
|
$updateIds = array_unique($updateIds);
|
||||||
// 批量更新
|
// 批量更新
|
||||||
@ -99,21 +121,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;
|
$status = GoodsSku::$STATUS_DOWN;
|
||||||
} else {
|
} else {
|
||||||
$status = GoodsSku::$STATUS_ON_SALE;
|
$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];
|
return [$status, $stock];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\CreateLogisticEvent;
|
use App\Events\CreateLogisticEvent;
|
||||||
|
use App\Models\BusinessOrder;
|
||||||
use App\Models\Shop;
|
use App\Models\Shop;
|
||||||
use App\Services\Business\BusinessFactory;
|
use App\Services\Business\BusinessFactory;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@ -10,10 +11,6 @@ use Illuminate\Queue\InteractsWithQueue;
|
|||||||
|
|
||||||
class CreateLogisticListener implements ShouldQueue
|
class CreateLogisticListener implements ShouldQueue
|
||||||
{
|
{
|
||||||
public $connection = 'redis';
|
|
||||||
|
|
||||||
public $queue = 'listeners';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the event listener.
|
* Create the event listener.
|
||||||
*
|
*
|
||||||
@ -27,12 +24,12 @@ class CreateLogisticListener implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Handle the event.
|
* Handle the event.
|
||||||
*
|
*
|
||||||
* @param CreateLogisticEvent $event
|
* @param CreateLogisticEvent $event
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle(CreateLogisticEvent $event)
|
public function handle(CreateLogisticEvent $event)
|
||||||
{
|
{
|
||||||
$shop = Shop::query()->findOrFail($event->shopId);
|
$shop = Shop::query()->findOrFail($event->shopId);;
|
||||||
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
|
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
|
||||||
$client->createLogistic($event->orderSn, $event->waybillNo);
|
$client->createLogistic($event->orderSn, $event->waybillNo);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class StockUpdateListener implements ShouldQueue
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($shops as $shop) {
|
foreach ($shops as $shop) {
|
||||||
$num = $event->goodsSku->stock;
|
$num = $event->goodsSku->sale_stock;
|
||||||
$businessGoodsSkus = BusinessGoodsSku::query()
|
$businessGoodsSkus = BusinessGoodsSku::query()
|
||||||
->select(['goods_id', 'sku_id', 'external_sku_id'])
|
->select(['goods_id', 'sku_id', 'external_sku_id'])
|
||||||
->where('shop_id', $shop->id)
|
->where('shop_id', $shop->id)
|
||||||
|
|||||||
@ -60,7 +60,7 @@ class UpdateBusinessGoodsStock implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($shops as $shop) {
|
foreach ($shops as $shop) {
|
||||||
$num = $event->goodsSku->stock;
|
$num = $event->goodsSku->sale_stock;
|
||||||
$businessGoodsSkus = BusinessGoodsSku::query()
|
$businessGoodsSkus = BusinessGoodsSku::query()
|
||||||
->where('shop_id', $shop->id)
|
->where('shop_id', $shop->id)
|
||||||
->where('is_sync', 1)
|
->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');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,6 +23,8 @@ class BusinessOrder extends Model
|
|||||||
'print_status',
|
'print_status',
|
||||||
'ids',
|
'ids',
|
||||||
'pno',
|
'pno',
|
||||||
|
'order_sn',
|
||||||
|
'id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
@ -62,36 +64,6 @@ class BusinessOrder extends Model
|
|||||||
'order_sn',
|
'order_sn',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getConfirmAtAttribute($value)
|
|
||||||
{
|
|
||||||
return date('Y-m-d H:i:s', $value / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getShippingStatusAttribute($value)
|
|
||||||
{
|
|
||||||
$map = ['未发货', '已发货', '部分发货', '' => ''];
|
|
||||||
|
|
||||||
return $map[$value];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIsSupplierAttribute($value)
|
|
||||||
{
|
|
||||||
$map = ['帮忙团订单', '自卖团订单', '' => ''];
|
|
||||||
|
|
||||||
return $map[$value];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCancelStatusAttribute($value)
|
|
||||||
{
|
|
||||||
$map = ['未取消', '已取消', '' => ''];
|
|
||||||
|
|
||||||
return $map[$value];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAfterSalesStatusAttribute($value)
|
|
||||||
{
|
|
||||||
return empty($value) ? '未售后' : '有售后';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function items()
|
public function items()
|
||||||
{
|
{
|
||||||
@ -102,4 +74,9 @@ class BusinessOrder extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Shop::class, 'shop_id', 'id');
|
return $this->belongsTo(Shop::class, 'shop_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function waybill()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Waybill::class, 'id', 'order_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\traits\Filter;
|
||||||
|
|
||||||
class DailyStockRecord extends Model
|
class DailyStockRecord extends Model
|
||||||
{
|
{
|
||||||
|
use Filter;
|
||||||
|
|
||||||
protected $hidden = ['created_at', 'updated_at'];
|
protected $hidden = ['created_at', 'updated_at'];
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public $fieldSearchable = [
|
||||||
|
'day',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function goodsSku()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(GoodsSku::class, 'sku_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,14 @@ class GoodsSku extends Model
|
|||||||
'exclude_ids',
|
'exclude_ids',
|
||||||
'external_sku_id',
|
'external_sku_id',
|
||||||
'is_combination',
|
'is_combination',
|
||||||
|
"create_time_start",
|
||||||
|
"create_time_end",
|
||||||
|
'min_stock',
|
||||||
|
'max_stock',
|
||||||
|
'min_sale_stock',
|
||||||
|
'max_sale_stock',
|
||||||
|
"neq_stock",
|
||||||
|
"neq_sale_stock",
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
@ -33,10 +41,10 @@ class GoodsSku extends Model
|
|||||||
'external_sku_id',
|
'external_sku_id',
|
||||||
'is_combination',
|
'is_combination',
|
||||||
'name',
|
'name',
|
||||||
|
'sale_stock',
|
||||||
|
'attribute'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = ['created_at'];
|
|
||||||
|
|
||||||
public static $STATUS_ON_SALE = 1;
|
public static $STATUS_ON_SALE = 1;
|
||||||
public static $STATUS_DOWN = 0;
|
public static $STATUS_DOWN = 0;
|
||||||
|
|
||||||
@ -63,10 +71,17 @@ class GoodsSku extends Model
|
|||||||
|
|
||||||
public function getThumbUrlAttribute($value)
|
public function getThumbUrlAttribute($value)
|
||||||
{
|
{
|
||||||
|
|
||||||
return json_decode($value, true);
|
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;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class GoodsType extends Model
|
class GoodsType extends Model
|
||||||
{
|
{
|
||||||
|
use SoftDeletes;
|
||||||
/**
|
/**
|
||||||
* 数组中的属性会被隐藏。
|
* 数组中的属性会被隐藏。
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $hidden = ['deleted_at'];
|
protected $hidden = ['deleted_at'];
|
||||||
|
|
||||||
|
public function parentType()
|
||||||
|
{
|
||||||
|
return $this->hasOne(GoodsType::class, 'id', 'parent_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,6 +72,9 @@ class Log extends Model
|
|||||||
'kuaituantuan' => '快团团',
|
'kuaituantuan' => '快团团',
|
||||||
'miaoxuan' => '妙选',
|
'miaoxuan' => '妙选',
|
||||||
'goods' => '商品',
|
'goods' => '商品',
|
||||||
|
"sku_stock_purchase" => "入库采购",
|
||||||
|
"sku_stock_loss" => "报损记录",
|
||||||
|
"sku_stock_inventory" => "盘点记录",
|
||||||
];
|
];
|
||||||
|
|
||||||
return $map[$value] ?? $value;
|
return $map[$value] ?? $value;
|
||||||
@ -89,6 +92,7 @@ class Log extends Model
|
|||||||
'set' => '设置',
|
'set' => '设置',
|
||||||
'cost' => '成本',
|
'cost' => '成本',
|
||||||
'stock' => '库存',
|
'stock' => '库存',
|
||||||
|
'sale_stock' => '在售库存',
|
||||||
'inventory' => '库存盘点',
|
'inventory' => '库存盘点',
|
||||||
'reserve' => '预留量 ',
|
'reserve' => '预留量 ',
|
||||||
'timingInventory' => '7点盘点',
|
'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');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,16 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\traits\Filter;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class ShopSender extends Model
|
class ShopSender extends Model
|
||||||
{
|
{
|
||||||
|
use Filter;
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
//查询字段
|
||||||
|
public $fieldSearchable = [
|
||||||
|
'shop_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';
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
@ -11,6 +12,7 @@ class User extends Authenticatable
|
|||||||
{
|
{
|
||||||
use Notifiable;
|
use Notifiable;
|
||||||
use HasRoles;
|
use HasRoles;
|
||||||
|
use SoftDeletes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
|
|||||||
@ -10,4 +10,9 @@ class Waybill extends Model
|
|||||||
|
|
||||||
public static $BUSINESS_EXPRESS_CODE = 247;
|
public static $BUSINESS_EXPRESS_CODE = 247;
|
||||||
public static $AIR_FREIGHT_CODE = 266;
|
public static $AIR_FREIGHT_CODE = 266;
|
||||||
|
|
||||||
|
public static $STATUS_INIT = 0;
|
||||||
|
public static $STATUS_CREATE_WAYBILL_CODE = 1;
|
||||||
|
public static $STATUS_CREATE_WAYBILL_ENCRYPTED_DATA = 2;
|
||||||
|
public static $STATUS_PRINT_SUCCESS = 3;
|
||||||
}
|
}
|
||||||
|
|||||||
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';
|
||||||
|
}
|
||||||
@ -3,10 +3,12 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Events\BusinessOrdersUpdate;
|
use App\Events\BusinessOrdersUpdate;
|
||||||
|
use App\Events\CancelLogisticEvent;
|
||||||
use App\Events\StockUpdateEvent;
|
use App\Events\StockUpdateEvent;
|
||||||
use App\Events\GroupSetEvent;
|
use App\Events\GroupSetEvent;
|
||||||
use App\Events\BatchStockUpdateEvent;
|
use App\Events\BatchStockUpdateEvent;
|
||||||
use App\Listeners\BatchStockUpdateListener;
|
use App\Listeners\BatchStockUpdateListener;
|
||||||
|
use App\Listeners\BusinessOrderUpdateListener;
|
||||||
use App\Listeners\CreateLogisticListener;
|
use App\Listeners\CreateLogisticListener;
|
||||||
use App\Listeners\GroupQueryListener;
|
use App\Listeners\GroupQueryListener;
|
||||||
use App\Listeners\StockUpdateListener;
|
use App\Listeners\StockUpdateListener;
|
||||||
@ -27,7 +29,7 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
protected $listen = [
|
protected $listen = [
|
||||||
BusinessOrdersUpdate::class => [
|
BusinessOrdersUpdate::class => [
|
||||||
UpdateBusinessGoodsStock::class,
|
UpdateBusinessGoodsStock::class,
|
||||||
CombinationGoodsStockUpdateListener::class,
|
CombinationGoodsStockUpdateListener::class
|
||||||
],
|
],
|
||||||
BatchStockUpdateEvent::class => [
|
BatchStockUpdateEvent::class => [
|
||||||
BatchStockUpdateListener::class,
|
BatchStockUpdateListener::class,
|
||||||
@ -46,6 +48,9 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
CreateLogisticEvent::class => [
|
CreateLogisticEvent::class => [
|
||||||
CreateLogisticListener::class
|
CreateLogisticListener::class
|
||||||
],
|
],
|
||||||
|
CancelLogisticEvent::class => [
|
||||||
|
CancelLogisticListener::class
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -4,6 +4,7 @@ namespace App\Services\Business;
|
|||||||
|
|
||||||
use App\Events\BusinessOrderCancelEvent;
|
use App\Events\BusinessOrderCancelEvent;
|
||||||
use App\Events\BusinessOrdersUpdate;
|
use App\Events\BusinessOrdersUpdate;
|
||||||
|
use App\Events\CancelLogisticEvent;
|
||||||
use App\Models\BusinessGoodsSku;
|
use App\Models\BusinessGoodsSku;
|
||||||
use App\Models\BusinessOrder;
|
use App\Models\BusinessOrder;
|
||||||
use App\Models\BusinessOrderItem;
|
use App\Models\BusinessOrderItem;
|
||||||
@ -38,6 +39,10 @@ abstract class BusinessClient
|
|||||||
|
|
||||||
abstract public function downloadOrdersAndSave($beginTime, $endTime, $downloadType = 'default', $page = 1);
|
abstract public function downloadOrdersAndSave($beginTime, $endTime, $downloadType = 'default', $page = 1);
|
||||||
|
|
||||||
|
abstract public function downloadAfterSaleOrdersAndSave($beginTime, $endTime, $page = 1);
|
||||||
|
|
||||||
|
abstract public function queryStatusAndSync($order);
|
||||||
|
|
||||||
public function saveOrders($orders)
|
public function saveOrders($orders)
|
||||||
{
|
{
|
||||||
$shopId = $this->getShop()->id;
|
$shopId = $this->getShop()->id;
|
||||||
@ -51,7 +56,7 @@ abstract class BusinessClient
|
|||||||
$orderRecord->update($order);
|
$orderRecord->update($order);
|
||||||
}
|
}
|
||||||
if (!empty($order['cancel_status'])) {
|
if (!empty($order['cancel_status'])) {
|
||||||
event(new BusinessOrderCancelEvent($shopId, $order['order_sn']));
|
event(new CancelLogisticEvent($shopId, $order['order_sn']));
|
||||||
}
|
}
|
||||||
$goodsSkuNum = 0;
|
$goodsSkuNum = 0;
|
||||||
foreach ($order['sub_order_list'] as $item) {
|
foreach ($order['sub_order_list'] as $item) {
|
||||||
@ -92,6 +97,7 @@ abstract class BusinessClient
|
|||||||
}
|
}
|
||||||
$orderItem->update($item);
|
$orderItem->update($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增量更新库存
|
// 增量更新库存
|
||||||
if ($num && $item['external_sku_id']) {
|
if ($num && $item['external_sku_id']) {
|
||||||
event(new BusinessOrdersUpdate($orderItem, $num));
|
event(new BusinessOrdersUpdate($orderItem, $num));
|
||||||
@ -149,14 +155,14 @@ abstract class BusinessClient
|
|||||||
'headers' => ['Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8'],
|
'headers' => ['Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8'],
|
||||||
'form_params' => $params
|
'form_params' => $params
|
||||||
];
|
];
|
||||||
$res = (new Client())->request($method, $url, $headers);
|
$res = (new Client(['verify'=>false]))->request($method, $url, $headers);
|
||||||
$size = $res->getBody()->getSize();
|
$size = $res->getBody()->getSize();
|
||||||
$res = json_decode($res->getBody()->getContents(), true);
|
$res = json_decode($res->getBody()->getContents(), true);
|
||||||
$paramsJson = json_encode($params, 256);
|
$paramsJson = json_encode($params, 256);
|
||||||
if (strlen($paramsJson) > 1024) {
|
if (strlen($paramsJson) > 1024) {
|
||||||
$paramsJson = '';
|
$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","pdd.ktt.order.get"], true)) {
|
||||||
$log = new Log();
|
$log = new Log();
|
||||||
$log->module = 'plat';
|
$log->module = 'plat';
|
||||||
$log->action = $method;
|
$log->action = $method;
|
||||||
@ -171,7 +177,7 @@ abstract class BusinessClient
|
|||||||
}
|
}
|
||||||
$log->save();
|
$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('快团团请求: ' . $paramsJson);
|
||||||
LogFile::info('快团团返回: ' . json_encode($res, 256));
|
LogFile::info('快团团返回: ' . json_encode($res, 256));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,9 @@ namespace App\Services\Business\KuaiTuanTuan;
|
|||||||
|
|
||||||
use App\Events\BusinessOrdersUpdate;
|
use App\Events\BusinessOrdersUpdate;
|
||||||
use App\Models\BusinessGoodsSku;
|
use App\Models\BusinessGoodsSku;
|
||||||
|
use App\Models\GoodsSku;
|
||||||
|
use App\Services\Business\BusinessFactory;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class Goods
|
class Goods
|
||||||
{
|
{
|
||||||
@ -43,7 +46,14 @@ class Goods
|
|||||||
if (empty($businessGoodSku->id)) {
|
if (empty($businessGoodSku->id)) {
|
||||||
$businessGoodSku->save();
|
$businessGoodSku->save();
|
||||||
if (!empty($businessGoodSku->external_sku_id)) {
|
if (!empty($businessGoodSku->external_sku_id)) {
|
||||||
event(new BusinessOrdersUpdate($businessGoodSku, 0));
|
$shop = $businessGoodSku->shop;
|
||||||
|
$sku = GoodsSku::query()
|
||||||
|
->where('external_sku_id', $businessGoodSku->external_sku_id)
|
||||||
|
->first();
|
||||||
|
Log::info("商品下载新增sku",[$businessGoodSku]);
|
||||||
|
if(!empty($sku)){
|
||||||
|
BusinessFactory::init()->make($shop['plat_id'])->setShopWithId($shop['id'])->incrQuantity($businessGoodSku, $sku->sale_stock, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$businessGoodSku->update($data);
|
$businessGoodSku->update($data);
|
||||||
|
|||||||
@ -2,13 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Services\Business\KuaiTuanTuan;
|
namespace App\Services\Business\KuaiTuanTuan;
|
||||||
|
|
||||||
|
use App\Events\BusinessOrdersUpdate;
|
||||||
|
use App\Models\BusinessAfterSaleOrder;
|
||||||
use App\Models\BusinessGoodsSku;
|
use App\Models\BusinessGoodsSku;
|
||||||
|
use App\Models\BusinessOrderItem;
|
||||||
use App\Models\GoodsSku;
|
use App\Models\GoodsSku;
|
||||||
use App\Models\GroupGoods;
|
use App\Models\GroupGoods;
|
||||||
use App\Models\Shop;
|
use App\Models\Shop;
|
||||||
use App\Models\ShopShip;
|
use App\Models\ShopShip;
|
||||||
use App\Services\Business\BusinessClient;
|
use App\Services\Business\BusinessClient;
|
||||||
use App\Models\Groups as GroupsModel;
|
use App\Models\Groups as GroupsModel;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class KuaiTuanTuan extends BusinessClient
|
class KuaiTuanTuan extends BusinessClient
|
||||||
@ -123,6 +127,104 @@ 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 queryStatusAndSync($order)
|
||||||
|
{
|
||||||
|
[$type, $appendParams] = Order::getOrderInfo($order->order_sn);
|
||||||
|
$responseName = 'ktt_order_get_response';
|
||||||
|
$res = $this->doRequest($type, $appendParams);
|
||||||
|
if (!isset($res[$responseName]['order_info'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$queryOrder = $res[$responseName]['order_info'];
|
||||||
|
$needUpdate = false;
|
||||||
|
if ($order->shipping_status != $queryOrder['shipping_status']) {
|
||||||
|
$order->shipping_status = $queryOrder['shipping_status'];
|
||||||
|
$needUpdate = true;
|
||||||
|
}
|
||||||
|
if ($order->cancel_status != $queryOrder['cancel_status']) {
|
||||||
|
$order->cancel_status = $queryOrder['cancel_status'];
|
||||||
|
$needUpdate = true;
|
||||||
|
}
|
||||||
|
if ($order->after_sales_status != $queryOrder['after_sales_status']) {
|
||||||
|
//售后状态更新
|
||||||
|
$order->after_sales_status = $queryOrder['after_sales_status'];
|
||||||
|
$needUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($needUpdate) {
|
||||||
|
$goodsSkuNum = 0;
|
||||||
|
foreach ($queryOrder['sub_order_list'] as $item) {
|
||||||
|
$orderItem = BusinessOrderItem::firstOrNew(['shop_id' => $order->shop_id, 'business_order_id' => $order->id, 'goods_id' => $item['goods_id'], 'sku_id' => $item['sku_id']], $item);
|
||||||
|
if ($item['external_sku_id']) {
|
||||||
|
$goodsSku = GoodsSku::query()
|
||||||
|
->with('combinationGoods')
|
||||||
|
->where('external_sku_id', $item['external_sku_id'])
|
||||||
|
->first('external_sku_id');
|
||||||
|
$combinationNum = $goodsSku ? ($goodsSku->combinationGoods->count() ?: 1) : 1;
|
||||||
|
$goodsSkuNum += $combinationNum;
|
||||||
|
} else {
|
||||||
|
$goodsSkuNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($orderItem->id)) {
|
||||||
|
$orderItem->update($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$order->goods_sku_num = $goodsSkuNum;
|
||||||
|
$order->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getOrderInfo($orderSn)
|
public function getOrderInfo($orderSn)
|
||||||
{
|
{
|
||||||
[$type, $appendParams] = Order::getOrderInfo($orderSn);
|
[$type, $appendParams] = Order::getOrderInfo($orderSn);
|
||||||
@ -163,6 +265,7 @@ class KuaiTuanTuan extends BusinessClient
|
|||||||
$publicParams = array_merge($publicParams, $appendParams);
|
$publicParams = array_merge($publicParams, $appendParams);
|
||||||
$publicParams['sign'] = $this->getSign($publicParams);
|
$publicParams['sign'] = $this->getSign($publicParams);
|
||||||
$res = $this->formDataPostRequest($url, $publicParams);
|
$res = $this->formDataPostRequest($url, $publicParams);
|
||||||
|
Log::info("快团团请求", ["param" => $publicParams, "res" => $res]);
|
||||||
if (isset($res['error_response'])) {
|
if (isset($res['error_response'])) {
|
||||||
// "error_msg":"业务服务错误","sub_msg":"该店铺下不存在该商品","sub_code":"11","error_code":50001
|
// "error_msg":"业务服务错误","sub_msg":"该店铺下不存在该商品","sub_code":"11","error_code":50001
|
||||||
// "error_msg":"业务服务错误","sub_msg":"该SKU在快团团中设置的库存为无限库存,不支持修改库存","sub_code":"13","error_code":50001
|
// "error_msg":"业务服务错误","sub_msg":"该SKU在快团团中设置的库存为无限库存,不支持修改库存","sub_code":"13","error_code":50001
|
||||||
@ -271,7 +374,6 @@ class KuaiTuanTuan extends BusinessClient
|
|||||||
public function createLogistic($orderSn, $waybillNo)
|
public function createLogistic($orderSn, $waybillNo)
|
||||||
{
|
{
|
||||||
[$type, $appendParams] = Order::createOrderLogistic($orderSn, $waybillNo);
|
[$type, $appendParams] = Order::createOrderLogistic($orderSn, $waybillNo);
|
||||||
|
|
||||||
return $this->doRequest($type, $appendParams);
|
return $this->doRequest($type, $appendParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -92,5 +92,21 @@ class Order
|
|||||||
|
|
||||||
return [$type, $appendParams];
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
namespace App\Services\Business\MiaoXuan;
|
namespace App\Services\Business\MiaoXuan;
|
||||||
|
|
||||||
use App\Models\BusinessGoodsSku;
|
use App\Models\BusinessGoodsSku;
|
||||||
|
use App\Models\BusinessOrderItem;
|
||||||
|
use App\Models\GoodsSku;
|
||||||
use App\Services\Business\BusinessClient;
|
use App\Services\Business\BusinessClient;
|
||||||
|
|
||||||
class MiaoXuan extends BusinessClient
|
class MiaoXuan extends BusinessClient
|
||||||
@ -33,6 +35,54 @@ class MiaoXuan extends BusinessClient
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function downloadAfterSaleOrdersAndSave($beginTime, $endTime, $page = 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queryStatusAndSync($order)
|
||||||
|
{
|
||||||
|
$appendParams = ["order_sn" => $order->order_sn, "type" => "erpQuery"];
|
||||||
|
$url = 'http://shop.chutang66.com/miaoxuan/queryOrder';
|
||||||
|
$queryOrder = $this->formDataPostRequest($url, $appendParams);
|
||||||
|
$needUpdate = false;
|
||||||
|
if ($order->shipping_status != $queryOrder['shipping_status']) {
|
||||||
|
$order->shipping_status = $queryOrder['shipping_status'];
|
||||||
|
$needUpdate = true;
|
||||||
|
}
|
||||||
|
if ($order->cancel_status != $queryOrder['cancel_status']) {
|
||||||
|
$order->cancel_status = $queryOrder['cancel_status'];
|
||||||
|
$needUpdate = true;
|
||||||
|
}
|
||||||
|
if ($order->after_sales_status!= $queryOrder['after_sales_status']) {
|
||||||
|
//售后状态更新
|
||||||
|
$order->after_sales_status = $queryOrder['after_sales_status'];
|
||||||
|
$needUpdate = true;
|
||||||
|
}
|
||||||
|
if ($needUpdate) {
|
||||||
|
$goodsSkuNum = 0;
|
||||||
|
foreach ($queryOrder['sub_order_list'] as $item) {
|
||||||
|
$orderItem = BusinessOrderItem::firstOrNew(['shop_id' => $order->shop_id, 'business_order_id' => $order->id, 'goods_id' => $item['goods_id'], 'sku_id' => $item['sku_id']], $item);
|
||||||
|
if ($item['external_sku_id']) {
|
||||||
|
$goodsSku = GoodsSku::query()
|
||||||
|
->with('combinationGoods')
|
||||||
|
->where('external_sku_id', $item['external_sku_id'])
|
||||||
|
->first('external_sku_id');
|
||||||
|
$combinationNum = $goodsSku ? ($goodsSku->combinationGoods->count() ?: 1) : 1;
|
||||||
|
$goodsSkuNum += $combinationNum;
|
||||||
|
} else {
|
||||||
|
$goodsSkuNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($orderItem->id)) {
|
||||||
|
$orderItem->update($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$order->goods_sku_num = $goodsSkuNum;
|
||||||
|
$order->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function batchIncrQuantity($businessGoodsSkus, $num, $incremental)
|
public function batchIncrQuantity($businessGoodsSkus, $num, $incremental)
|
||||||
{
|
{
|
||||||
$batchAppendParams = [];
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
226
app/Services/GoodSku/GoodSkuService.php
Normal file
226
app/Services/GoodSku/GoodSkuService.php
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\GoodSku;
|
||||||
|
|
||||||
|
use App\Events\BatchStockUpdateEvent;
|
||||||
|
use App\Http\Enum\BusinessOrderShippingStatus;
|
||||||
|
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;
|
||||||
|
use phpDocumentor\Reflection\Types\Collection;
|
||||||
|
|
||||||
|
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")->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();
|
||||||
|
$skuIds = collect($skusWithCombinationGoods)->pluck("id")->toArray();
|
||||||
|
//关联的组合数据
|
||||||
|
$combinationGoods = CombinationGood::query()->with("goodsSku:id,external_sku_id")->whereIn('item_id', $skuIds)->get()->toArray();
|
||||||
|
$externalSkuIds = collect($combinationGoods)->pluck("goods_sku.external_sku_id")->merge(collect($externalSkuIds))->toArray();
|
||||||
|
Log::info("需要查询的externalSkuIds",[$externalSkuIds]);
|
||||||
|
//默认只查15天内未发货的数据
|
||||||
|
$startTime = Carbon::now()->subDays(15)->toDateTimeString();
|
||||||
|
$unshippedDataCollect = BusinessOrderItem::query()
|
||||||
|
->with([
|
||||||
|
'shop:id,name',
|
||||||
|
'goodsSku:id,external_sku_id,is_combination',
|
||||||
|
'goodsSku.combinationGoods:id,goods_sku_id,item_id,item_num'
|
||||||
|
])
|
||||||
|
->leftJoin("business_orders as b", "business_order_id", "=", "b.id")
|
||||||
|
->select("external_sku_id", DB::raw("SUM(goods_number) - SUM(already_cancel_number) as number"))
|
||||||
|
->whereIn("external_sku_id", $externalSkuIds)
|
||||||
|
->where("b.shipping_status", "=", BusinessOrderShippingStatus::UNSHIP)
|
||||||
|
->where("b.after_sales_status", "!=", 2)
|
||||||
|
->where("business_order_items.created_at", ">=", $startTime)->where("business_order_items.cancel_status", "=", 0)
|
||||||
|
->groupBy('external_sku_id')->get()->toArray();
|
||||||
|
|
||||||
|
Log::info("盘点未发货数据",[$unshippedDataCollect]);
|
||||||
|
$ids = [];
|
||||||
|
//重组订单
|
||||||
|
foreach ($unshippedDataCollect as $businessOrderItem) {
|
||||||
|
if (is_null($businessOrderItem['goods_sku'])) {
|
||||||
|
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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($ids[$id])) {
|
||||||
|
$ids[$id] += (int)$businessOrderItem['number'];
|
||||||
|
} else {
|
||||||
|
$ids[$id] = (int)$businessOrderItem['number'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return collect($skusWithCombinationGoods)->map(function ($v) use ($ids) {
|
||||||
|
$v['real_stock'] = $v['inventory'] ?? null;
|
||||||
|
if (!empty($ids[$v['id']]) && isset($v['inventory'])) {
|
||||||
|
$v['real_stock'] = $v['inventory'] - $ids[$v['id']];
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
244
app/Services/WayBill/JingDong/JingDongService.php
Normal file
244
app/Services/WayBill/JingDong/JingDongService.php
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\WayBill\JingDong;
|
||||||
|
|
||||||
|
use App\Enum\Pickup\ConsignType;
|
||||||
|
use App\Models\BusinessOrder;
|
||||||
|
use App\Models\OrderItem;
|
||||||
|
use App\Models\Pickup;
|
||||||
|
use App\Models\Waybill;
|
||||||
|
use App\Services\Pickup\Exceptions\KdNiaoException;
|
||||||
|
use App\Utils\Env\EnvUtils;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Lop\LopOpensdkPhp\Filters\ErrorResponseFilter;
|
||||||
|
use Lop\LopOpensdkPhp\Filters\IsvFilter;
|
||||||
|
use Lop\LopOpensdkPhp\Options;
|
||||||
|
use Lop\LopOpensdkPhp\Support\DefaultClient;
|
||||||
|
use Lop\LopOpensdkPhp\Support\GenericRequest;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class JingDongService
|
||||||
|
{
|
||||||
|
public $baseUrl;
|
||||||
|
public $appKey;
|
||||||
|
public $appSecret;
|
||||||
|
public $accessToken;
|
||||||
|
public $customerCode;
|
||||||
|
public static $CANCEL_TYPE = [
|
||||||
|
1 => '预约信息有误',
|
||||||
|
2 => '快递员无法取件',
|
||||||
|
3 => '上门太慢',
|
||||||
|
4 => '运费太贵',
|
||||||
|
7 => '联系不上快递员',
|
||||||
|
8 => '快递员要求取消',
|
||||||
|
11 => '其他(如疫情管控,无法寄 件)',
|
||||||
|
9 => '预约信息有误',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->baseUrl = "https://api.jdl.com";
|
||||||
|
$this->appKey = "5ee218f6619e438db8755ee560c3eaa7";
|
||||||
|
$this->appSecret = "7ffb176f75014ebbb37061f051024bf3";
|
||||||
|
$this->accessToken = "4e411a1d178147cdb58b5579a0df378d";//每年都会过期 https://oauth.jdl.com/oauth/authorize?client_id=YOUR_APP_KEY&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code
|
||||||
|
//生产环境域名:https://oauth.jdl.com 预发环境域名:https://uat-oauth.jdl.com
|
||||||
|
$this->domain = "FreshMedicineDelivery";//对接方案的编码 生鲜快递
|
||||||
|
$this->customerCode = "028K4188368";//月结编码
|
||||||
|
/*if (!EnvUtils::checkIsProduce()) {
|
||||||
|
//沙箱环境
|
||||||
|
$this->baseUrl = "https://test-api.jdl.com";
|
||||||
|
$this->appKey = "62d07644754843cc882fca7c01476c4f";
|
||||||
|
$this->appSecret = "0c2c8b6b7c10481ea639f6daa09ac02e";
|
||||||
|
$this->accessToken = "78c246c0ab564e67add6296a9eaf04a1";;//每年都会过期 https://oauth.jdl.com/oauth/authorize?client_id=YOUR_APP_KEY&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code
|
||||||
|
$this->customerCode = "27K1234912";//月结编码
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function request($body, $path)
|
||||||
|
{
|
||||||
|
// 生产环境: https://api.jdl.com
|
||||||
|
$client = new DefaultClient($this->baseUrl);
|
||||||
|
// 系统参数,应用的app_ley和app_secret,可从【控制台-应用管理-概览】中查看;access_token是用户授权时获取的令牌,用户授权相关说明请查看https://cloud.jdl.com/#/devSupport/53392
|
||||||
|
$isvFilter = new IsvFilter($this->appKey, $this->appSecret, $this->accessToken);
|
||||||
|
$errorResponseFilter = new ErrorResponseFilter();
|
||||||
|
|
||||||
|
$request = new GenericRequest();
|
||||||
|
$request->setDomain($this->domain);//对接方案的编码,应用订购对接方案后可在订阅记录查看
|
||||||
|
$request->setPath($path);//api的path,可在API文档查看
|
||||||
|
$request->setMethod("POST");//只支持POST
|
||||||
|
// 序列化后的JSON字符串
|
||||||
|
$request->setBody(json_encode([$body]));
|
||||||
|
|
||||||
|
// 为请求添加ISV模式过滤器,自动根据算法计算开放平台鉴权及签名信息
|
||||||
|
$request->addFilter($isvFilter);
|
||||||
|
// 为请求添加错误响应解析过滤器,如果不添加需要手动解析错误响应
|
||||||
|
$request->addFilter($errorResponseFilter);
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
|
||||||
|
$options->setAlgorithm(Options::MD5_SALT);
|
||||||
|
Log::info("京东请求body:{$path}", [$body]);
|
||||||
|
$response = $client->execute($request, $options);
|
||||||
|
$response = json_decode($response->getBody(), true);
|
||||||
|
Log::info("京东返回请求response", [$response]);
|
||||||
|
if (!isset($response['code']) || ($response['code'] != 0 && $response['code'] != 1 && $response['code'] != 1000)) {
|
||||||
|
throw new \Exception($response['message'] ?? "code异常");
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function buildCargoes($extend)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"quantity" => $extend["quantity"] ?? 1,
|
||||||
|
"goodsName" => "鲜花",
|
||||||
|
"volume" => ($extend['volume'] ?? 0) > 0 ? $extend['volume'] : 100,
|
||||||
|
"weight" => $extend['weight'] ?? 1,
|
||||||
|
"packageQty" => 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildContact($params)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'senderName' => $params['name'] ?? '',
|
||||||
|
'senderPhone' => $params['mobile'] ?? '',
|
||||||
|
'senderAddress' => substr($params['province_name'] . $params['city_name'] . $params['area_name'] . $params['address_detail'], 0, 350),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createOrder(Waybill $pickup)
|
||||||
|
{
|
||||||
|
$path = "/freshmedicinedelivery/delivery/create/order/v1";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"orderId" => $pickupData['order_sn'],
|
||||||
|
"senderContactRequest" => [
|
||||||
|
'senderName' => $pickupData['sender_name'] ?? '',
|
||||||
|
'senderPhone' => $pickupData['sender_mobile'] ?? '',
|
||||||
|
'senderAddress' => substr($pickupData['sender_province'] . $pickupData['sender_city']
|
||||||
|
. $pickupData['sender_district'] . $pickupData['sender_detail'], 0, 350)
|
||||||
|
],
|
||||||
|
"customerCode" => $this->customerCode,
|
||||||
|
"remark" => $pickup['note'] ?? '',
|
||||||
|
"salePlatform" => '0030001',//其他平台
|
||||||
|
"cargoesRequest" => $this->buildCargoes($pickup),
|
||||||
|
"receiverContactRequest" => [
|
||||||
|
'receiverName' => $pickupData['recipient_name'] ?? '',
|
||||||
|
'receiverPhone' => $pickupData['recipient_mobile'] ?? '',
|
||||||
|
'receiverAddress' => substr($pickupData['recipient_province'] . $pickupData['recipient_city'] . $pickupData['recipient_district'] . $pickupData['recipient_detail'], 0, 350)
|
||||||
|
],
|
||||||
|
"channelOrderId" => $pickupData['order_sn'],
|
||||||
|
"promiseTimeType" => 26,//22:医药冷链 26:冷链专送,29医药专送
|
||||||
|
"goodsType" => 7,//1:普通,2:生鲜常温,5:鲜活,6:控温,7:冷藏,8:冷冻,9:深冷;21:医药冷藏,23:医药控温,24:医药常温,25:医药冷冻,27:医药深冷
|
||||||
|
//"pickUpStartTime" => Carbon::today()->startOfDay()->addDays(2)->addHours(19)->toDateTimeString(),
|
||||||
|
//"pickUpEndTime" => Carbon::today()->startOfDay()->addDays(2)->addHours(21)->toDateTimeString(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
return $response['data'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function cancelOrder(Waybill $pickup)
|
||||||
|
{
|
||||||
|
$path = "/freshmedicinedelivery/delivery/cancel/waybill/v1";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"waybillNo" => $pickupData['waybill_code'],
|
||||||
|
"customerCode" => $this->customerCode,
|
||||||
|
"interceptReason" => "订单信息有误",
|
||||||
|
];
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
|
||||||
|
return $response['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pullData(Waybill $pickup)
|
||||||
|
{
|
||||||
|
//云打印
|
||||||
|
$this->domain = "jdcloudprint";
|
||||||
|
$path = "/PullDataService/pullData";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"cpCode" => "JD",
|
||||||
|
"wayBillInfos" => [[
|
||||||
|
'orderNo' => $pickupData['order_sn'],
|
||||||
|
'jdWayBillCode' => $pickupData['waybill_code'],
|
||||||
|
]],
|
||||||
|
"parameters" => ["ewCustomerCode" => $this->customerCode],
|
||||||
|
"objectId" => $pickupData['object_id'],
|
||||||
|
];
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
|
||||||
|
return $response['prePrintDatas'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function queryOrder(Waybill $pickup)
|
||||||
|
{
|
||||||
|
$path = "/ecap/v1/orders/details/query";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"waybillCode" => $pickupData['ship_sn'] ?? '',
|
||||||
|
"orderCode" => $pickupData['out_order_sn'] ?? "",
|
||||||
|
"customerCode" => $this->customerCode,
|
||||||
|
"orderOrigin" => 2,
|
||||||
|
];
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
|
||||||
|
return $response['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subscribe(Waybill $pickup)
|
||||||
|
{
|
||||||
|
$path = "/jd/tracking/subscribe";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"referenceNumber" => $pickupData['ship_sn'] ?? '',
|
||||||
|
"referenceType" => 20000,
|
||||||
|
"customerCode" => $this->customerCode,
|
||||||
|
];
|
||||||
|
$this->domain = "Tracking_JD";//对接方案的编码
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
|
||||||
|
return $response['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queryFee(Waybill $pickup)
|
||||||
|
{
|
||||||
|
$path = "/ecap/v1/orders/actualfee/query";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"waybillCode" => $pickupData['ship_sn'] ?? '',
|
||||||
|
"orderCode" => $pickupData['out_order_sn'] ?? "",
|
||||||
|
"customerCode" => $this->customerCode,
|
||||||
|
"orderOrigin" => 2,
|
||||||
|
];
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
|
||||||
|
return $response['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queryTrace(Waybill $pickup)
|
||||||
|
{
|
||||||
|
$path = "/freshmedicinedelivery/delivery/query/waybill/gis/v1";
|
||||||
|
$pickupData = $pickup->toArray();
|
||||||
|
$body = [
|
||||||
|
"waybillNo" => $pickupData['waybill_code'] ?? '',
|
||||||
|
"customerCode" => $this->customerCode,
|
||||||
|
];
|
||||||
|
$response = $this->request($body, $path);
|
||||||
|
|
||||||
|
return $response['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
281
app/Services/WayBill/JingDong/WayBillService.php
Normal file
281
app/Services/WayBill/JingDong/WayBillService.php
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\WayBill\JingDong;
|
||||||
|
|
||||||
|
use App\Events\CreateLogisticEvent;
|
||||||
|
use App\Http\Enum\BusinessOrderShippingStatus;
|
||||||
|
use App\Models\BusinessOrder;
|
||||||
|
use App\Models\GoodsSku;
|
||||||
|
use App\Models\ShopSender;
|
||||||
|
use App\Models\ShopShip;
|
||||||
|
use App\Models\Waybill;
|
||||||
|
use App\Services\Business\KuaiTuanTuan\FaceSheet;
|
||||||
|
|
||||||
|
class WayBillService
|
||||||
|
{
|
||||||
|
public $orders;
|
||||||
|
public $objectId;
|
||||||
|
public $adminUser;
|
||||||
|
// 标准模板
|
||||||
|
public $templateUrl = 'https://template-content.jd.com/template-oss?tempCode=jdkd76x130';
|
||||||
|
// 时效类型
|
||||||
|
public $timedDeliveryCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新版京东打印-下单
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getWayBillContents()
|
||||||
|
{
|
||||||
|
// 已下单过的订单不再下单
|
||||||
|
$contents = [];
|
||||||
|
$this->adminUser = auth('api')->user();
|
||||||
|
$jingDongService = new JingDongService();
|
||||||
|
foreach ($this->orders as $shopId => $order) {
|
||||||
|
// 订单取消的情况暂不处理
|
||||||
|
$shopSend = $this->getShopSend($shopId);
|
||||||
|
foreach ($order as $item) {
|
||||||
|
[$sender, $orderInfo, $senderConfig] = $this->prepareRequest($item, $shopSend);
|
||||||
|
$waybill = $this->saveWayBill($item, $shopSend, $senderConfig);
|
||||||
|
if (empty($waybill->waybill_code)) {
|
||||||
|
$resp = $jingDongService->createOrder($waybill);
|
||||||
|
if (isset($resp['waybillNo'])) {
|
||||||
|
$waybill->status = Waybill::$STATUS_CREATE_WAYBILL_CODE;
|
||||||
|
$waybill->waybill_code = $resp['waybillNo'];
|
||||||
|
$waybill->save();
|
||||||
|
//物流发货
|
||||||
|
event(new CreateLogisticEvent($waybill->shop_id, $waybill->order_sn, $waybill->waybill_code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//返回面单待打印数据
|
||||||
|
if (empty($waybill->encryptedData)) {
|
||||||
|
// 延时0.5秒 防止订单查询不到
|
||||||
|
usleep(0.5 * 1000000);
|
||||||
|
$resp = $jingDongService->pullData($waybill);
|
||||||
|
if (!empty($resp[0]['perPrintData'])) {
|
||||||
|
$waybill->status = Waybill::$STATUS_CREATE_WAYBILL_ENCRYPTED_DATA;
|
||||||
|
$waybill->templateUrl = $this->templateUrl;
|
||||||
|
$waybill->encryptedData = $resp[0]['perPrintData'];
|
||||||
|
$waybill->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$contents[$item['id']] = $waybill;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDocumentsAndOrderIds($contents)
|
||||||
|
{
|
||||||
|
// 打印单,根据商品排序
|
||||||
|
$items = [];
|
||||||
|
foreach ($contents as $docId => $content) {
|
||||||
|
foreach ($content['items'] as $item) {
|
||||||
|
if ($item['is_single']) {
|
||||||
|
$items[$item['external_sku_id']][] = $docId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ksort($items);
|
||||||
|
$documents = $orderIds = $hasIds = [];
|
||||||
|
foreach ($items as $docIds) {
|
||||||
|
$docIds = array_unique($docIds);
|
||||||
|
$docIds = array_diff($docIds, $hasIds);
|
||||||
|
$hasIds = array_merge($hasIds, $docIds);
|
||||||
|
foreach ($docIds as $docId) {
|
||||||
|
$orderIds[] = $contents[$docId]['order_id'];
|
||||||
|
$documents[] = $contents[$docId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$documents, $orderIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveWayBill($order, $shopShip, $senderConfig)
|
||||||
|
{
|
||||||
|
$waybill = Waybill::query()->firstOrNew(
|
||||||
|
['order_sn' => $order['order_sn']]
|
||||||
|
);
|
||||||
|
|
||||||
|
$waybill->shop_id = $order['shop_id'];
|
||||||
|
$waybill->object_id = $this->objectId;
|
||||||
|
|
||||||
|
$waybill->sender_country = $senderConfig['country'];
|
||||||
|
$waybill->sender_province = $senderConfig['province'];
|
||||||
|
$waybill->sender_city = $senderConfig['city'];
|
||||||
|
$waybill->sender_district = $senderConfig['district'];
|
||||||
|
$waybill->sender_detail = $senderConfig['detail'];
|
||||||
|
$waybill->sender_name = $senderConfig['name'];
|
||||||
|
$waybill->sender_mobile = (int)$senderConfig['mobile'];
|
||||||
|
|
||||||
|
$waybill->recipient_province = $order['recipient_province'];
|
||||||
|
$waybill->recipient_city = $order['recipient_city'];
|
||||||
|
$waybill->recipient_district = $order['recipient_district'];
|
||||||
|
$waybill->recipient_detail = $order['recipient_detail'];
|
||||||
|
$waybill->recipient_name = $order['recipient_name'];
|
||||||
|
$waybill->recipient_mobile = $order['recipient_mobile'];
|
||||||
|
|
||||||
|
$waybill->user_id = $this->adminUser->id ?? 0;
|
||||||
|
$waybill->wp_code = $senderConfig['wp_code'];
|
||||||
|
$waybill->order_sn = $order['order_sn'];
|
||||||
|
$waybill->order_id = $order['id'];
|
||||||
|
$waybill->participate_no = $order['participate_no'];
|
||||||
|
$waybill->note = $order['note'];
|
||||||
|
$waybill->items = json_encode($order['items'], 256);
|
||||||
|
$waybill->save();
|
||||||
|
return $waybill;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTimedDelivery($order)
|
||||||
|
{
|
||||||
|
$this->timedDeliveryCode = Waybill::$BUSINESS_EXPRESS_CODE;
|
||||||
|
$address = [
|
||||||
|
'辽宁省' => [],
|
||||||
|
'吉林省' => [],
|
||||||
|
'黑龙江省' => [],
|
||||||
|
'甘肃省' => [],
|
||||||
|
'海南省' => [],
|
||||||
|
'宁夏回族自治区' => [
|
||||||
|
'银川市', '石嘴山市', '吴忠市', '固原市'
|
||||||
|
],
|
||||||
|
'青海省' => [
|
||||||
|
'西宁市', '海东市', '海北藏族自治州', '黄南藏族自治州', '海南藏族自治州', '玉树藏族自治州'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
if (isset($address[$order['recipient_province']])) {
|
||||||
|
if (empty($address[$order['recipient_province']])) {
|
||||||
|
$this->timedDeliveryCode = Waybill::$AIR_FREIGHT_CODE;
|
||||||
|
}
|
||||||
|
if ($address[$order['recipient_province']] && in_array($order['recipient_city'], $address[$order['recipient_province']], true)) {
|
||||||
|
$this->timedDeliveryCode = Waybill::$AIR_FREIGHT_CODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareRequest($order, $shopSend)
|
||||||
|
{
|
||||||
|
$this->setObjectId();
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
foreach ($order['items'] as $item) {
|
||||||
|
$items[] = [
|
||||||
|
'name' => $item['name'],
|
||||||
|
'count' => $item['count'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($shopSend)) {
|
||||||
|
abort(404, '发货人信息未匹配');
|
||||||
|
}
|
||||||
|
$senderConfig = $shopSend;
|
||||||
|
$sender = [
|
||||||
|
'address' => [
|
||||||
|
'city' => $senderConfig['city'],
|
||||||
|
'country' => $senderConfig['country'],
|
||||||
|
'detail' => $senderConfig['detail'],
|
||||||
|
'district' => $senderConfig['district'],
|
||||||
|
'province' => $senderConfig['province'],
|
||||||
|
],
|
||||||
|
'name' => $senderConfig['name'],
|
||||||
|
'mobile' => $senderConfig['mobile'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$orderInfo = [
|
||||||
|
'object_id' => $this->objectId,
|
||||||
|
'order_info' => [
|
||||||
|
'order_channels_type' => 'PDD',
|
||||||
|
'trade_order_list' => [$order['order_sn']],
|
||||||
|
],
|
||||||
|
'package_info' => [
|
||||||
|
'items' => $items,
|
||||||
|
],
|
||||||
|
'recipient' => [
|
||||||
|
'address' => [
|
||||||
|
'city' => $order['recipient_city'],
|
||||||
|
'detail' => $order['recipient_detail'],
|
||||||
|
'district' => $order['recipient_district'],
|
||||||
|
'province' => $order['recipient_province'],
|
||||||
|
],
|
||||||
|
'name' => $order['recipient_name'],
|
||||||
|
'mobile' => $order['recipient_mobile'],
|
||||||
|
],
|
||||||
|
'template_url' => $this->templateUrl,
|
||||||
|
];
|
||||||
|
|
||||||
|
return [$sender, $orderInfo, $senderConfig];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setObjectId()
|
||||||
|
{
|
||||||
|
$this->objectId = date('YmdHis') . str_pad(mt_rand(1, 9999999), 7, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOrders($orders)
|
||||||
|
{
|
||||||
|
$orders = $orders->toArray();
|
||||||
|
// 订单拆分组合
|
||||||
|
foreach ($orders as $order) {
|
||||||
|
if ($order['shipping_status'] != BusinessOrderShippingStatus::UNSHIP) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($order['cancel_status'] == 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$info = [
|
||||||
|
'id' => $order['id'],
|
||||||
|
'shop_id' => $order['shop_id'],
|
||||||
|
'order_sn' => $order['order_sn'],
|
||||||
|
'recipient_province' => $order['receiver_address_province'],
|
||||||
|
'recipient_city' => $order['receiver_address_city'],
|
||||||
|
'recipient_district' => $order['receiver_address_district'],
|
||||||
|
'recipient_detail' => $order['receiver_address_detail'],
|
||||||
|
'recipient_name' => $order['receiver_name'],
|
||||||
|
'recipient_mobile' => $order['receiver_mobile'],
|
||||||
|
'participate_no' => $order['is_supplier'] ? $order['participate_no'] : $order['supply_participate_no'],
|
||||||
|
'note' => $order['business_note'] ? $order['business_note'] . ',' . $order['buyer_memo'] : $order['buyer_memo'],
|
||||||
|
'items' => []
|
||||||
|
];
|
||||||
|
$note = "";
|
||||||
|
foreach ($order['items'] as $item) {
|
||||||
|
$count = $item['goods_number'] - $item['already_cancel_number'];
|
||||||
|
$info['items'][] = [
|
||||||
|
'is_single' => true,
|
||||||
|
'should_print' => true,
|
||||||
|
'name' => $item['goods_name'],
|
||||||
|
'count' => $count,
|
||||||
|
'external_sku_id' => $item['external_sku_id'],
|
||||||
|
];
|
||||||
|
$note .= $item['goods_name'] . " " . $count . "件,";
|
||||||
|
}
|
||||||
|
$note .= "[备注:" . $info['note'] . "]";
|
||||||
|
$info['note'] = $note;
|
||||||
|
$this->orders[$order['shop_id']][] = $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getShopSend($shopId)
|
||||||
|
{
|
||||||
|
return ShopSender::query()
|
||||||
|
->where('status', 1)->orderBy('sort')
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getShopShip($shopId)
|
||||||
|
{
|
||||||
|
return ShopShip::query()
|
||||||
|
->select(['id', 'shop_id', 'access_token', 'owner_id'])
|
||||||
|
->where('shop_id', $shopId)
|
||||||
|
->with([
|
||||||
|
'senders' => function ($query) {
|
||||||
|
$query->where('status', 1)->orderBy('sort');
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Utils;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class DateTimeUtils
|
class DateTimeUtils
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -42,4 +44,28 @@ class DateTimeUtils
|
|||||||
|
|
||||||
return (int)ceil($time);
|
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/framework": "^6.20.26",
|
||||||
"laravel/tinker": "^2.5",
|
"laravel/tinker": "^2.5",
|
||||||
"maatwebsite/excel": "^3.1",
|
"maatwebsite/excel": "^3.1",
|
||||||
|
"predis/predis": "^2.2",
|
||||||
"spatie/laravel-permission": "*"
|
"spatie/laravel-permission": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
@ -38,7 +39,8 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\": "app/"
|
"App\\": "app/",
|
||||||
|
"Lop\\LopOpensdkPhp\\" : "extend/lop-opensdk-php/src/"
|
||||||
},
|
},
|
||||||
"classmap": [
|
"classmap": [
|
||||||
"database/seeds",
|
"database/seeds",
|
||||||
|
|||||||
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",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "037b06c1b26399725a1d9c0687402942",
|
"content-hash": "964631bbee47f895975146a783331c50",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aliyuncs/oss-sdk-php",
|
"name": "aliyuncs/oss-sdk-php",
|
||||||
@ -2587,6 +2587,73 @@
|
|||||||
],
|
],
|
||||||
"time": "2022-07-30T15:51:26+00:00"
|
"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",
|
"name": "psr/container",
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
|
|||||||
@ -52,6 +52,7 @@ return [
|
|||||||
'path' => storage_path('logs/laravel.log'),
|
'path' => storage_path('logs/laravel.log'),
|
||||||
'level' => 'debug',
|
'level' => 'debug',
|
||||||
'days' => 14,
|
'days' => 14,
|
||||||
|
"permission" => 0777
|
||||||
],
|
],
|
||||||
|
|
||||||
'slack' => [
|
'slack' => [
|
||||||
|
|||||||
@ -61,7 +61,8 @@ class CreateBusinessOrdersTable extends Migration
|
|||||||
// 索引
|
// 索引
|
||||||
$table->unique(['shop_id', 'order_sn']);
|
$table->unique(['shop_id', 'order_sn']);
|
||||||
$table->index(['shop_id', 'participate_no']);
|
$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');
|
||||||
|
}
|
||||||
|
}
|
||||||
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