feat: master 覆盖

This commit is contained in:
赵世界 2024-03-13 17:17:47 +08:00
commit 9c5a962c70
166 changed files with 7501 additions and 10128 deletions

View File

@ -0,0 +1,127 @@
<?php
namespace App\Console\Commands;
use App\Models\BusinessOrderItem;
use App\Models\DailyReport;
use App\Models\GoodsSku;
use Carbon\Carbon;
use Illuminate\Console\Command;
class GoodsSkuDailyReport extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'daily:report:goods_sku {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()
->select(['shop_id', 'already_cancel_number', 'external_sku_id', 'goods_amount', 'goods_cost_price', 'goods_number', 'goods_price'])
->where('external_sku_id', '<>', '')
->where('created_at', '>=', $startDateTime)
->where('created_at', '<=', $endDateTime)
->get();
if ($orderItems->isEmpty()) {
return;
}
$externalSkuIds = array_unique(array_column($orderItems->toArray(), 'external_sku_id'));
$goodsSkus = GoodsSku::query()
->select(['id', 'goods_id', 'cost', 'external_sku_id'])
->with([
'goods:id,type_id,brand_id'
])
->where('is_combination', 0)
->whereIn('external_sku_id', $externalSkuIds)
->get()
->pluck(null, 'external_sku_id')
->toArray();
if (empty($goodsSkus)) {
return;
}
$data = [];
foreach ($orderItems as $orderItem) {
if (!isset($goodsSkus[$orderItem->external_sku_id])) {
continue;
}
if (!isset($data[$orderItem->external_sku_id])) {
$data[$orderItem->external_sku_id] = [
'goods_id' => $goodsSkus[$orderItem->external_sku_id]['goods']['id'],
'type_id' => $goodsSkus[$orderItem->external_sku_id]['goods']['type_id'],
'brand_id' => $goodsSkus[$orderItem->external_sku_id]['goods']['brand_id'],
'goods_sku_id' => $goodsSkus[$orderItem->external_sku_id]['id'],
'cost' => $goodsSkus[$orderItem->external_sku_id]['cost'],
'total_goods_price' => 0,
'total_goods_cost_price' => 0,
'total_goods_amount' => 0,
'total_goods_number' => 0,
'total_cancel_number' => 0,
'shop_data' => [],
];
}
$data[$orderItem->external_sku_id]['total_goods_price'] += $orderItem->goods_price;
$data[$orderItem->external_sku_id]['total_goods_cost_price'] += $orderItem->goods_cost_price;
$data[$orderItem->external_sku_id]['total_goods_amount'] += $orderItem->goods_amount;
$data[$orderItem->external_sku_id]['total_goods_number'] += $orderItem->goods_number;
$data[$orderItem->external_sku_id]['total_cancel_number'] += $orderItem->already_cancel_number;
if (!isset($data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id])) {
$data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id] = [
'total_goods_price' => 0,
'total_goods_cost_price' => 0,
'total_goods_amount' => 0,
'total_goods_number' => 0,
'total_cancel_number' => 0,
];
}
$data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id]['total_goods_price'] += $orderItem->goods_price;
$data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id]['total_goods_cost_price'] += $orderItem->goods_cost_price;
$data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id]['total_goods_amount'] += $orderItem->goods_amount;
$data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id]['total_goods_number'] += $orderItem->goods_number;
$data[$orderItem->external_sku_id]['shop_data'][$orderItem->shop_id]['total_cancel_number'] += $orderItem->already_cancel_number;
}
foreach ($data as $externalSkuId => $datum) {
DailyReport::query()->firstOrCreate([
'date' => $date,
'external_sku_id' => $externalSkuId
], $datum);
}
}
}

View File

@ -2,8 +2,10 @@
namespace App\Console\Commands;
use App\Events\CreateLogisticEvent;
use App\Events\StockUpdateEvent;
use App\Exports\DiffTodayPriceGoodsExport;
use App\Jobs\SyncCostToMiaoXuan;
use App\Models\BusinessGoodsSku;
use App\Models\BusinessOrder;
use App\Models\GoodsSku;

View File

@ -2,6 +2,7 @@
namespace App\Console;
use App\Console\Commands\GoodsSkuDailyReport;
use App\Console\Commands\Inventory;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -29,6 +30,7 @@ class Kernel extends ConsoleKernel
{
// 服务器/etc/crontab添加cron入口
// * * * * * cd /home/wwwroot/erp.chutang66.com && php artisan schedule:run >> /dev/null 2>&1
$schedule->command(GoodsSkuDailyReport::class)->dailyAt('06:00');
$schedule->command(Inventory::class)->dailyAt('07:00');
$schedule->command(KttOrderQuery::class)->everyMinute();
$schedule->command(DeleteKttQuery::class)->daily();

View File

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

View File

@ -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 BusinessOrderCancelEvent
{
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');
}
}

View File

@ -2,7 +2,9 @@
namespace App\Events;
use App\Models\DailyStockRecord;
use App\Models\GoodsSku;
use App\Utils\DateTimeUtils;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
@ -16,39 +18,51 @@ class BusinessOrdersUpdate
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $businessGoodSku;
public $num;
public $businessGoods;
public $goodsSku;
public $goodsSkus;
public $combinationGoodsUpdate;
public $combinationGoodsUpdate = true;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($item, $num)
public function __construct($businessGoodSku, $num)
{
$this->combinationGoodsUpdate = false;
$this->businessGoods = $item->toArray();
$this->businessGoodSku = $businessGoodSku->toArray();
$this->num = $num;
$this->updateStock();
}
private function updateStock()
{
try {
$this->goodsSku = GoodsSku::query()
->where('external_sku_id', $this->businessGoods['external_sku_id'])
->first();
} catch (\Exception $e) {
Log::error('事件库存更新失败: ' . $e->getMessage());
$this->goodsSku = GoodsSku::query()
->where('external_sku_id', $this->businessGoodSku['external_sku_id'])
->first();
if (is_null($this->goodsSku)) {
return false;
}
if ($this->goodsSku) {
$this->goodsSku->stock += $this->num;
$this->goodsSku->save();
$stock = $this->goodsSku->stock + $this->num;
if (0 >= $stock) {
$this->goodsSku->status = GoodsSku::$STATUS_DOWN;
} else {
$this->goodsSku->status = GoodsSku::$STATUS_ON_SALE;
}
// 今日到货 + 1T 大于20,且当前剩余库存小于4时 直接下架
$arrivedTodayNum = DailyStockRecord::query()
->where('day', DateTimeUtils::getToday())
->where('sku_id', $this->goodsSku->id)
->value('arrived_today_num');
if (20 < $arrivedTodayNum + $this->goodsSku->yesterday_num && 4 > $stock) {
$this->goodsSku->status = GoodsSku::$STATUS_DOWN;
$stock = 0;
}
$this->goodsSku->stock = $stock;
$this->goodsSku->save();
}
/**

View File

@ -0,0 +1,42 @@
<?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 CreateLogisticEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $shopId;
public $orderSn;
public $waybillNo;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($shopId, $orderSn, $waybillNo)
{
$this->shopId = $shopId;
$this->orderSn = $orderSn;
$this->waybillNo = $waybillNo;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@ -2,7 +2,9 @@
namespace App\Events;
use App\Models\DailyStockRecord;
use App\Models\GoodsSku;
use App\Utils\DateTimeUtils;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
@ -16,28 +18,38 @@ class StockUpdateEvent
use Dispatchable, InteractsWithSockets, SerializesModels;
public $goodsSku;
public $goodsSkus;
public $isBatch;
public $combinationGoodsUpdate;
public $combinationGoodsUpdate = true;
/**
* Create a new event instance.
*
* @param $data array|object
*
* @return void
* @param $goodsSku
*/
public function __construct($data, $isBatch = 0, $combinationGoodsUpdate = false)
public function __construct($goodsSku)
{
$this->isBatch = $isBatch;
$this->combinationGoodsUpdate = $combinationGoodsUpdate;
if (is_array($data)) {
// ids集合
$this->goodsSkus = GoodsSku::query()->whereIn('id', $data)->get();
$this->goodsSku = $goodsSku;
$this->checkStatusAndStock($goodsSku);
}
private function checkStatusAndStock($goodsSku)
{
$stock = $goodsSku->stock;
if (0 >= $goodsSku->stock) {
$status = GoodsSku::$STATUS_DOWN;
} else {
// GoodsSku Elo模型对象
$this->goodsSku = $data;
$status = GoodsSku::$STATUS_ON_SALE;
}
$arrivedTodayNum = DailyStockRecord::query()
->where('day', DateTimeUtils::getToday())
->where('sku_id', $goodsSku->id)
->value('arrived_today_num');
if (20 < $arrivedTodayNum + $goodsSku->yesterday_num && 4 > $goodsSku->stock) {
$status = GoodsSku::$STATUS_DOWN;
$stock = 0;
}
$goodsSku->status = $status;
$goodsSku->stock = $stock;
$goodsSku->save();
}
/**

View File

@ -0,0 +1,111 @@
<?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;
class WeekDataExport implements FromCollection, ShouldAutoSize
{
private $startDate;
private $endDate;
private $data;
public function __construct($startDate, $endDate)
{
$this->startDate = $startDate;
$this->endDate = $endDate;
$this->data = $this->createData();
}
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return new Collection($this->data);
}
private function createData()
{
$headTitle = [
'商品名称',
'品类',
'规格',
'品牌',
'商品编码',
'成本',
'销售数量',
];
$shops = Shop::query()
->whereNotIn('id', [7, 9, 10, 11, 17, 18])
->orderBy('id')
->pluck('name', 'id')
->toArray();
$headTitle = array_merge($headTitle, array_values($shops));
$dailyReports = DailyReport::query()
->with([
'goods:id,title',
'goodsType:id,name',
'goodsSku:id,title',
'goodsBrand:id,name',
])
->where('date', '>=', $this->startDate)
->where('date', '<=', $this->endDate)
->get();
if ($dailyReports->isEmpty()) {
return [$headTitle];
}
$arr = [];
foreach ($dailyReports as $item) {
$number = $item->total_goods_number - $item->total_cancel_number;
if (!isset($arr[$item->external_sku_id])) {
$arr[$item->external_sku_id] = [
'goodsTitle' => $item->goods->title,
'goodsTypeName' => $item->goodsType->name,
'goodsSkuTitle' => $item->goodsSku->title,
'goodsBrandName' => $item->goodsBrand->name,
'external_sku_id' => $item->external_sku_id,
'cost' => [],
'number' => [],
'shops' => []
];
}
$arr[$item->external_sku_id]['cost'][] = $item->cost;
$arr[$item->external_sku_id]['number'][] = $number;
foreach ($item->shop_data as $shopId => $shopData) {
$number = $shopData['total_goods_number'] - $shopData['total_cancel_number'];
if (!isset($arr[$item->external_sku_id]['shops'][$shopId])) {
$arr[$item->external_sku_id]['shops'][$shopId] = 0;
}
$arr[$item->external_sku_id]['shops'][$shopId] += $number;
}
}
$bodyData = [];
foreach ($arr as $item) {
$cost = array_sum($item['cost']) / count($item['cost']);
$shopData = [];
foreach ($shops as $shopId => $shopName) {
$shopData[] = $item['shops'][$shopId] ?? 0;
}
$data = [
$item['goodsTitle'],
$item['goodsTypeName'],
$item['goodsSkuTitle'],
$item['goodsBrandName'],
$item['external_sku_id'],
$cost,
array_sum($item['number']),
];
$bodyData[] = array_merge($data, $shopData);
}
return [$headTitle, $bodyData];
}
}

View File

@ -4,6 +4,7 @@ namespace App\Filters;
use App\Models\BusinessOrderItem;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
class BusinessOrderFilter extends Filters
{
@ -22,6 +23,14 @@ class BusinessOrderFilter extends Filters
return $this->builder->where('supply_participate_no', trim($value));
}
protected function pno($value)
{
return $this->builder->where(function (Builder $builder) use ($value) {
$builder->where('participate_no', $value)
->orWhere('supply_participate_no', $value);
});
}
protected function shopId($value)
{
return $this->builder->where('shop_id', $value);

View File

@ -203,7 +203,7 @@ class BusinessOrderController extends Controller
];
$data = [];
foreach ($documents as &$document) {
$documentData['data']['list'][0]['text'] = '[跟团号: ' . $document['participate_no'] . '] ';
$documentData['data']['list'][0]['text'] = $document['participate_no'] ? '[跟团号: ' . $document['participate_no'] . '] ' : '';
$documentID = $document['documentID'];
$count = 0;
foreach ($document['items'] as $item) {

View File

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

View File

@ -2,19 +2,23 @@
namespace App\Http\Controllers\Goods;
use App\Events\BatchStockUpdateEvent;
use App\Events\StockUpdateEvent;
use App\Exports\GoodsSkusExport;
use App\Exports\WeekDataExport;
use App\Http\Controllers\Controller;
use App\Http\Requests\GoodsRequest;
use App\Http\Requests\GoodsSkuRequest;
use App\Imports\InventoryImport;
use App\Imports\NewSetImport;
use App\Models\BusinessOrderItem;
use App\Models\DeveloperConfig;
use App\Models\Goods;
use App\Models\Log;
use App\Models\Log as LogModel;
use App\Utils\ArrayUtils;
use App\Utils\DateTimeUtils;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Models\GoodsSku;
use App\Http\Resources\GoodsSkuResource;
@ -40,46 +44,84 @@ class GoodsSkusController extends Controller
public function index(Request $request)
{
$builder = GoodsSku::query();
$this->preparQueryGoodsSkus($request, $builder);
$day = DateTimeUtils::getToday();
$goodsSkus = $builder->filter()
->with(['goods' => function ($query) {
$query->with(['type:id,name', 'brand:id,name']);
}])
->with(['daily' => function ($query) use ($day) {
$query->where('day', $day);
}])
->where('is_combination', 0)
->orderBy('stock', 'desc')
->paginate($request->get('per_page'));
$fields = implode(',', [
'shop_id',
'external_sku_id',
'sum(goods_number) as number',
'sum(already_cancel_number) as cancel_number',
'SUM(goods_number) - SUM(already_cancel_number) as number',
]);
$orderRestTime = DeveloperConfig::query()
->where('key', DeveloperConfig::$ORDER_RESET_TIME)
->value('value');
if (is_null($orderRestTime)) {
$orderRestTime = date('Y-m-d 07:00:00');
}
$businessOrderItems = BusinessOrderItem::query()
->select(DB::raw($fields))
->with([
'shop:id,name',
'goodsSku:id,external_sku_id'
])
->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[$businessOrderItem['external_sku_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'];
$orderDetail = BusinessOrderItem::query()
->select(DB::raw($fields))
->with(['shop:id,name'])
->where('external_sku_id', $sku['external_sku_id'])
->when($lastInventoryTime, function ($query) use ($lastInventoryTime) {
$query->where('created_at', '>', $lastInventoryTime);
})
->groupBy(['shop_id', 'external_sku_id'])
->get()
->toArray();
$addOrderGoodsNum = $reduceOrderGoodsNum = 0;
if ($orderDetail) {
$addOrderGoodsNum = array_sum(array_column($orderDetail, 'number'));
$reduceOrderGoodsNum = array_sum(array_column($orderDetail, 'cancel_number'));
$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['inventory_time'] = $lastInventoryTime;
$sku['order_goods_num'] = $addOrderGoodsNum - $reduceOrderGoodsNum;
$sku['order_detail'] = $orderDetail;
if ('销售' === $rolesName[0]) {
$sku['cost'] = 0;
}
@ -234,7 +276,8 @@ class GoodsSkusController extends Controller
$log = new LogModel();
$log->batchInsert($logs);
DB::commit();
event(new StockUpdateEvent(array_column($request->skus, 'id')));
// 批量更新
event(new BatchStockUpdateEvent(array_column($request->skus, 'id')));
} catch (\Exception $exception) {
DB::rollBack();
$this->res = [
@ -482,6 +525,11 @@ class GoodsSkusController extends Controller
{
$type = $request->get('exportType');
ob_end_clean();
if ('week_data' === $type) {
$startDate = Carbon::now()->subWeek()->startOfWeek()->toDateString();
$endDate = Carbon::now()->subWeek()->endOfWeek()->toDateString();
return Excel::download(new WeekDataExport($startDate, $endDate), $startDate . '~' . $endDate . '.xlsx');
}
return Excel::download(new GoodsSkusExport($type), $type . '.xlsx');
}
@ -541,6 +589,11 @@ class GoodsSkusController extends Controller
$roseNum += $stock;
continue;
}
// 多头玫瑰
if (false !== strpos($externalSkuId, 'D')) {
$roseNum += $stock;
continue;
}
// 草花剔除A开头
if (false !== strpos($externalSkuId, 'A')) {
continue;
@ -549,10 +602,14 @@ class GoodsSkusController extends Controller
if (false !== strpos($externalSkuId, 'Z')) {
continue;
}
// 剔除N开头年宵花
if (false !== strpos($externalSkuId, 'N')) {
// 剔除测试CS
if (false !== strpos($externalSkuId, 'CS')) {
continue;
}
// 剔除N开头年宵花
// if (false !== strpos($externalSkuId, 'N')) {
// continue;
// }
$otherNum += $stock;
}

View File

@ -14,18 +14,25 @@ class ShipController extends Controller
{
public function index(Request $request)
{
$shopShips = ShopShip::query()
->select(['id', 'type', 'shop_id', 'expires_at', 'owner_id', 'owner_name'])
->with('shop:id,name')
$shops = Shop::query()
->select(['id', 'name', 'plat_id'])
->with('ship')
// ->where('plat_id', 1)
->get();
$time = date('Y-m-d H:i:s');
foreach ($shopShips as $shopShip) {
if ($shopShip->expires_at && $time >= $shopShip->expires_at) {
ShopShip::query()->where('shop_id', $shopShip->shop_id)->update(['status' => Shop::$STATUS_UNAUTHORIZED]);
foreach ($shops as $shop) {
$faceSheet = new FaceSheet();
$shop->authUrl = $faceSheet->getAuthUrl($shop->id, $shop->plat_id);
$shop->status = 0;
if ($shop->ship) {
$shop->status = $shop->ship->getOriginal('status');
if ($shop->ship->expires_at && $time >= $shop->ship->expires_at) {
ShopShip::query()->where('shop_id', $shop->id)->update(['status' => Shop::$STATUS_UNAUTHORIZED]);
}
}
}
return ShopsResource::collection($shopShips);
return ShopsResource::collection($shops);
}
public function getSenders(Request $request)
@ -49,6 +56,7 @@ class ShipController extends Controller
$sender->mobile = $item['mobile'];
$sender->sort = $item['sort'];
$sender->status = $item['status'];
$sender->timed_delivery_code = $item['timed_delivery_code'];
$sender->save();
}

View File

@ -4,6 +4,7 @@ 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;
@ -247,4 +248,15 @@ class ShopsController extends Controller
}
}
}
public function orderReset(Request $request)
{
DeveloperConfig::query()->updateOrCreate([
'key' => DeveloperConfig::$ORDER_RESET_TIME,
], [
'value' => date('Y-m-d H:i:s')
]);
return response($this->res, $this->res['httpCode']);
}
}

View File

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

View File

@ -2,6 +2,8 @@
namespace App\Imports;
use App\Events\BatchStockUpdateEvent;
use App\Jobs\SyncCostToMiaoXuan;
use App\Models\DailyStockRecord;
use App\Models\GoodsSku;
use App\Models\TodayPrice;
@ -10,7 +12,6 @@ use Exception;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToArray;
use App\Utils\ArrayUtils;
use App\Events\StockUpdateEvent;
class InventoryImport implements ToArray, SkipsEmptyRows
{
@ -54,6 +55,7 @@ class InventoryImport implements ToArray, SkipsEmptyRows
'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],
@ -96,6 +98,7 @@ class InventoryImport implements ToArray, SkipsEmptyRows
}
}
sleep(2);
event(new StockUpdateEvent($onSkuIds, 1));
// 批量更新
event(new BatchStockUpdateEvent($onSkuIds));
}
}

View File

@ -2,15 +2,15 @@
namespace App\Imports;
use App\Events\BatchStockUpdateEvent;
use App\Jobs\SyncCostToMiaoXuan;
use App\Models\DailyStockRecord;
use App\Models\GoodsSku;
use App\Models\TodayPrice;
use App\Utils\DateTimeUtils;
use Exception;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToArray;
use App\Utils\ArrayUtils;
use App\Events\StockUpdateEvent;
class NewSetImport implements ToArray, SkipsEmptyRows
{
@ -50,13 +50,17 @@ class NewSetImport implements ToArray, SkipsEmptyRows
'stock' => $row[2] + $goodsSku['stock'],
]);
}
SyncCostToMiaoXuan::dispatch($row[0], $row[3]);
$updateIds[] = $goodsSku['id'];
// 今日到货
$record = DailyStockRecord::query()->where('sku_id', $goodsSku['id'])->where('day', $day)->first(['id', 'arrived_today_num']);
$record = DailyStockRecord::query()
->where('sku_id', $goodsSku['id'])
->where('day', $day)->first(['id', 'arrived_today_num']);
$record->arrived_today_num += $row[2];
$record->save();
}
sleep(2);
event(new StockUpdateEvent($updateIds, 1));
// 批量更新
event(new BatchStockUpdateEvent($updateIds));
}
}

View File

@ -14,7 +14,7 @@ class BusinessGoodsSkuIncrQuantity implements ShouldQueue
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $shop;
public $businessGoods;
public $businessGoodsSku;
public $num;
public $isIncremental = true;
@ -23,10 +23,10 @@ class BusinessGoodsSkuIncrQuantity implements ShouldQueue
*
* @return void
*/
public function __construct($shop, $businessGoods, $num, $isIncremental)
public function __construct($shop, $businessGoodsSku, $num, $isIncremental)
{
$this->shop = $shop;
$this->businessGoods = $businessGoods;
$this->businessGoodsSku = $businessGoodsSku;
$this->num = $num;
$this->isIncremental = $isIncremental;
}
@ -38,8 +38,8 @@ class BusinessGoodsSkuIncrQuantity implements ShouldQueue
*/
public function handle()
{
if ($this->businessGoods) {
BusinessFactory::init()->make($this->shop['plat_id'])->setShopWithId($this->shop['id'])->incrQuantity($this->businessGoods, $this->num, $this->isIncremental);
if ($this->businessGoodsSku) {
BusinessFactory::init()->make($this->shop['plat_id'])->setShopWithId($this->shop['id'])->incrQuantity($this->businessGoodsSku, $this->num, $this->isIncremental);
}
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Jobs;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SyncCostToMiaoXuan implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $externalSkuId;
public $cost;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($externalSkuId, $cost)
{
$this->externalSkuId = $externalSkuId;
$this->cost = $cost;
}
/**
* Execute the job.
*
* @return void
* @throws GuzzleException
*/
public function handle()
{
$url = 'http://shop.chutang66.com/miaoxuan/cost';
$method = 'PUT';
$headers = [
'headers' => ['Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8'],
'form_params' => [
'external_sku_id' => $this->externalSkuId,
'cost' => $this->cost,
]
];
(new Client())->request($method, $url, $headers);
}
}

View File

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

View File

@ -0,0 +1,47 @@
<?php
namespace App\Listeners;
use App\Events\CreateLogisticEvent;
use App\Models\Shop;
use App\Models\Waybill;
use App\Services\Business\BusinessFactory;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class CancelLogisticListener implements ShouldQueue
{
public $connection = 'redis';
public $queue = 'listeners';
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param CreateLogisticEvent $event
* @return void
*/
public function handle(CreateLogisticEvent $event)
{
$waybillNo = Waybill::query()
->where('shop_id', $event->shopId)
->where('order_sn', $event->orderSn)
->value('waybill_code');
if (empty($waybillNo)) {
return;
}
$shop = Shop::query()->findOrFail($event->shopId);
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
$client->cancelLogistic($event->orderSn, $event->waybillNo);
}
}

View File

@ -3,10 +3,12 @@
namespace App\Listeners;
use App\Models\CombinationGood;
use App\Models\DailyStockRecord;
use App\Models\GoodsSku;
use App\Utils\DateTimeUtils;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use App\Events\StockUpdateEvent;
use App\Events\BatchStockUpdateEvent;
class CombinationGoodsStockUpdateListener
{
@ -28,18 +30,19 @@ class CombinationGoodsStockUpdateListener
*/
public function handle($event)
{
if ($event->combinationGoodsUpdate) {
if (!$event->combinationGoodsUpdate) {
return false;
}
$updateIds = $combinationGoodsIds = $combinationGoodsItemIds = [];
if ($event->goodsSku) {
if (!empty($event->goodsSku)) {
if ($event->goodsSku->is_combination) {
$combinationGoodsIds[] = $event->goodsSku->id;
} else {
$combinationGoodsItemIds[] = $event->goodsSku->id;
}
}
if ($event->goodsSkus) {
if (!empty($event->goodsSkus)) {
foreach ($event->goodsSkus as $sku) {
if ($sku->is_combination) {
$combinationGoodsIds[] = $sku->id;
@ -55,21 +58,20 @@ class CombinationGoodsStockUpdateListener
->whereIn('goods_sku_id', $combinationGoodsIds)
->get();
foreach ($combinationGoods as $item) {
$sku = GoodsSku::query()->find($item['item_id']);
$sku->stock -= $item['item_num'];
$sku->save();
$updateIds[] = $sku->id;
$goodsSku = GoodsSku::query()->find($item['item_id']);
$stock = $goodsSku->stock - $item['item_num'];
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock);
$goodsSku->status = $status;
$goodsSku->stock = $stock;
$goodsSku->save();
$updateIds[] = $goodsSku->id;
}
}
// 计算主商品库存
if ($combinationGoodsItemIds) {
$goodsSkuIds = CombinationGood::query()
->whereIn('item_id', $combinationGoodsItemIds)
->pluck('goods_sku_id')
->toArray();
if (empty($goodsSkuIds)) {
return false;
}
->pluck('goods_sku_id');
foreach ($goodsSkuIds as $goodsSkuId) {
$combinationGoods = CombinationGood::query()
->with('goodsSkuItem:id,stock')
@ -80,13 +82,37 @@ class CombinationGoodsStockUpdateListener
$stock[] = (int)($goods['goodsSkuItem']['stock'] / $goods['item_num']);
}
$stock = min($stock);
GoodsSku::query()->where('id', $goodsSkuId)->update(['stock' => $stock]);
$goodsSku = GoodsSku::query()->find($goodsSkuId);
[$status, $stock] = $this->checkStatusAndStock($goodsSku, $stock);
$goodsSku->status = $status;
$goodsSku->stock = $stock;
$goodsSku->save();
$updateIds[] = $goodsSkuId;
}
}
if ($updateIds) {
$updateIds = array_unique($updateIds);
event(new StockUpdateEvent($updateIds, 1, true));
// 批量更新
event(new BatchStockUpdateEvent($updateIds, false));
}
}
private function checkStatusAndStock($goodsSku, $stock)
{
if (0 >= $stock) {
$status = GoodsSku::$STATUS_DOWN;
} else {
$status = GoodsSku::$STATUS_ON_SALE;
}
$arrivedTodayNum = DailyStockRecord::query()
->where('day', DateTimeUtils::getToday())
->where('sku_id', $goodsSku->id)
->value('arrived_today_num');
if (20 < $arrivedTodayNum + $goodsSku->yesterday_num && 4 > $stock) {
$status = GoodsSku::$STATUS_DOWN;
$stock = 0;
}
return [$status, $stock];
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Listeners;
use App\Events\CreateLogisticEvent;
use App\Models\Shop;
use App\Services\Business\BusinessFactory;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class CreateLogisticListener implements ShouldQueue
{
public $connection = 'redis';
public $queue = 'listeners';
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param CreateLogisticEvent $event
* @return void
*/
public function handle(CreateLogisticEvent $event)
{
$shop = Shop::query()->findOrFail($event->shopId);
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
$client->createLogistic($event->orderSn, $event->waybillNo);
}
}

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ class BusinessOrder extends Model
'goods_sku_num',
'print_status',
'ids',
'pno',
];
protected $fillable = [

View File

@ -44,4 +44,9 @@ class BusinessOrderItem extends Model
{
return $this->hasOne(GoodsSkuLocation::class, 'external_sku_id', 'external_sku_id');
}
public function goodsSku()
{
return $this->hasOne(GoodsSku::class, 'external_sku_id', 'external_sku_id');
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class DailyReport extends Model
{
protected $guarded = [];
protected $casts = [
'shop_data' => 'array',
];
public function goods()
{
return $this->hasOne(Goods::class, 'id', 'goods_id');
}
public function goodsBrand()
{
return $this->belongsTo(GoodsBrand::class, 'brand_id', 'id');
}
public function goodsType()
{
return $this->belongsTo(GoodsType::class, 'type_id', 'id');
}
public function goodsSku()
{
return $this->hasOne(GoodsSku::class, 'id', 'goods_sku_id');
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class DeveloperConfig extends Model
{
protected $guarded = [];
public static $ORDER_RESET_TIME = 'order_reset_time';
}

View File

@ -36,6 +36,9 @@ class GoodsSku extends Model
protected $hidden = ['created_at'];
public static $STATUS_ON_SALE = 1;
public static $STATUS_DOWN = 0;
/**
* 获取状态
*

View File

@ -3,14 +3,19 @@
namespace App\Providers;
use App\Events\BusinessOrdersUpdate;
use App\Events\GroupSetEvent;
use App\Events\StockUpdateEvent;
use App\Events\GroupSetEvent;
use App\Events\BatchStockUpdateEvent;
use App\Listeners\BatchStockUpdateListener;
use App\Listeners\CreateLogisticListener;
use App\Listeners\GroupQueryListener;
use App\Listeners\StockUpdateListener;
use App\Listeners\StockWarning;
use App\Listeners\CombinationGoodsStockUpdateListener;
use App\Listeners\UpdateBusinessGoodsStock;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use App\Events\BusinessOrderCancelEvent;
use App\Listeners\CancelLogisticListener;
use App\Events\CreateLogisticEvent;
class EventServiceProvider extends ServiceProvider
{
@ -22,17 +27,25 @@ class EventServiceProvider extends ServiceProvider
protected $listen = [
BusinessOrdersUpdate::class => [
UpdateBusinessGoodsStock::class,
StockWarning::class,
CombinationGoodsStockUpdateListener::class,
],
BatchStockUpdateEvent::class => [
BatchStockUpdateListener::class,
CombinationGoodsStockUpdateListener::class,
],
StockUpdateEvent::class => [
StockUpdateListener::class,
StockWarning::class,
CombinationGoodsStockUpdateListener::class,
],
GroupSetEvent::class => [
GroupQueryListener::class,
],
BusinessOrderCancelEvent::class => [
CancelLogisticListener::class
],
CreateLogisticEvent::class => [
CreateLogisticListener::class
],
];
/**

View File

@ -2,6 +2,7 @@
namespace App\Services\Business;
use App\Events\BusinessOrderCancelEvent;
use App\Events\BusinessOrdersUpdate;
use App\Models\BusinessGoodsSku;
use App\Models\BusinessOrder;
@ -29,6 +30,10 @@ abstract class BusinessClient
abstract public function bindGoods($goods);
abstract public function createLogistic($orderSn, $waybillNo);
abstract public function cancelLogistic($orderSn, $waybillNo);
abstract public function incrQuantity($businessGoodsSku, $num, $incremental);
abstract public function downloadOrdersAndSave($beginTime, $endTime, $downloadType = 'default', $page = 1);
@ -45,6 +50,9 @@ abstract class BusinessClient
} else {
$orderRecord->update($order);
}
if (!empty($order['cancel_status'])) {
event(new BusinessOrderCancelEvent($shopId, $order['order_sn']));
}
$goodsSkuNum = 0;
foreach ($order['sub_order_list'] as $item) {
$item['shop_id'] = $shopId;

View File

@ -15,6 +15,10 @@ class BusinessFactory
$this->platList['妙选'] = MiaoXuan::class;
}
/**
* @param $platName
* @return BusinessClient
*/
public function make($platName)
{
return new $this->platList[$platName];

View File

@ -262,4 +262,25 @@ class KuaiTuanTuan extends BusinessClient
return $this->doRequest($type, $appendParams);
}
public function createLogistic($orderSn, $waybillNo)
{
[$type, $appendParams] = Order::createOrderLogistic($orderSn, $waybillNo);
return $this->doRequest($type, $appendParams);
}
public function cancelLogistic($orderSn, $waybillNo)
{
[$type, $appendParams] = Order::deleteOrderLogistic($orderSn, $waybillNo);
return $this->doRequest($type, $appendParams);
}
public function getLogisticsCompanies()
{
[$type, $appendParams] = Order::getLogisticsCompanies();
return $this->doRequest($type, $appendParams);
}
}

View File

@ -57,5 +57,40 @@ class Order
return [$type, $appendParams];
}
public static function getLogisticsCompanies()
{
$type = 'pdd.logistics.companies.get';
return [$type, []];
}
public static function createOrderLogistic($orderSn, $waybillNo, $logisticsId = 44, $logisticsName = '顺丰快递')
{
// 不支持拆单发货
$type = 'pdd.ktt.order.logistic.create';
$appendParams = [
'logisticsId' => $logisticsId,
'logisticsName' => $logisticsName,
'orderSn' => $orderSn,
// 'subOrderSnList' => [], 发货子单号列表,无子单号视为整单发货
'waybillNo' => $waybillNo,
];
return [$type, $appendParams];
}
public static function deleteOrderLogistic($orderSn, $waybillNo)
{
$type = 'pdd.ktt.order.logistic.delete';
$appendParams = [
'orderSn' => $orderSn,
// 'subOrderSnList' => [], 发货子单号列表,无子单号视为整单发货
'waybillNo' => $waybillNo,
];
return [$type, $appendParams];
}
}

View File

@ -47,4 +47,14 @@ class MiaoXuan extends BusinessClient
{
// TODO: Implement downloadGoods() method.
}
public function createLogistic($orderSn, $waybillNo)
{
// TODO: Implement createLogistic() method.
}
public function cancelLogistic($orderSn, $waybillNo)
{
// TODO: Implement cancelLogistic() method.
}
}

View File

@ -2,6 +2,7 @@
namespace App\Services\Ship;
use App\Events\CreateLogisticEvent;
use App\Models\GoodsSku;
use App\Models\ShopShip;
use App\Models\Waybill;
@ -29,18 +30,15 @@ class WayBillService
$contents = [];
foreach ($this->orders as $shopId => $order) {
// 订单取消的情况暂不处理
$shopShip = $this->getShopShip($shopId);
$faceSheet = new FaceSheet();
$faceSheet->setShop($shopShip);
foreach ($order as $item) {
$packageInfoItems = $this->getPackageInfoItems($item);
$this->getTimedDelivery($item);
$faceSheet = new FaceSheet();
$shopShip = $this->getShopShip($shopId);
$faceSheet->setShop($shopShip);
[$sender, $orderInfo, $wpCode] = $this->prepareRequest($item, $shopShip, $packageInfoItems);
$waybill = $this->saveWayBill($item, $shopShip);
[$sender, $orderInfo, $senderConfig] = $this->prepareRequest($item, $shopShip);
$waybill = $this->saveWayBill($item, $shopShip, $senderConfig);
if (empty($waybill->id)) {
$resp = $faceSheet->getWayBill($sender, $orderInfo, $wpCode);
$resp = $faceSheet->getWayBill($sender, $orderInfo, $senderConfig['wp_code']);
if (isset($resp['pdd_waybill_get_response'])) {
$data = $resp['pdd_waybill_get_response']['modules'][0];
$printData = json_decode($data['print_data'], true);
@ -67,6 +65,7 @@ class WayBillService
'participate_no' => $waybill->participate_no,
'note' => $waybill->note,
];
event(new CreateLogisticEvent($shopShip->shop_id, $waybill->order_sn, $data['waybill_code']));
}
} else {
$contents[$waybill->id] = [
@ -117,14 +116,13 @@ class WayBillService
return [$documents, $orderIds];
}
private function saveWayBill($order, $shop)
private function saveWayBill($order, $shopShip, $senderConfig)
{
$senderConfig = $shop->senders[0];
$waybill = Waybill::query()->firstOrNew(
['order_sn' => $order['order_sn']]
);
$waybill->shop_id = $shop->shop_id;
$waybill->shop_id = $shopShip->shop_id;
$waybill->object_id = $this->objectId;
$waybill->sender_country = $senderConfig['country'];
@ -142,19 +140,18 @@ class WayBillService
$waybill->recipient_name = $order['recipient_name'];
$waybill->recipient_mobile = $order['recipient_mobile'];
$waybill->user_id = $shop->owner_id;
$waybill->user_id = $shopShip->owner_id;
$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->code = $this->timedDeliveryCode;
return $waybill;
}
private function getTimedDelivery($orderItem)
private function getTimedDelivery($order)
{
$this->timedDeliveryCode = Waybill::$BUSINESS_EXPRESS_CODE;
$address = [
@ -170,18 +167,22 @@ class WayBillService
'西宁市', '海东市', '海北藏族自治州', '黄南藏族自治州', '海南藏族自治州', '玉树藏族自治州'
],
];
if (isset($address[$orderItem['recipient_province']])) {
if (empty($address[$orderItem['recipient_province']])) {
if (isset($address[$order['recipient_province']])) {
if (empty($address[$order['recipient_province']])) {
$this->timedDeliveryCode = Waybill::$AIR_FREIGHT_CODE;
}
if ($address[$orderItem['recipient_province']] && in_array($orderItem['recipient_city'], $address[$orderItem['recipient_province']], true)) {
if ($address[$order['recipient_province']] && in_array($order['recipient_city'], $address[$order['recipient_province']], true)) {
$this->timedDeliveryCode = Waybill::$AIR_FREIGHT_CODE;
}
}
}
private function getPackageInfoItems($order)
private function prepareRequest($order, $shopShip)
{
$this->getTimedDelivery($order);
$this->setObjectId();
$items = [];
foreach ($order['items'] as $item) {
if ($item['should_print']) {
@ -197,12 +198,17 @@ class WayBillService
}
}
return $items;
}
$senderConfig = [];
foreach ($shopShip->senders as $sender) {
if ($sender['timed_delivery_code'] === $this->timedDeliveryCode) {
$senderConfig = $sender;
break;
}
}
private function prepareRequest($order, $shopShip, $packageInfoItems)
{
$senderConfig = $shopShip->senders[0];
if (empty($senderConfig)) {
abort(404, '发货人信息未匹配');
}
$sender = [
'address' => [
'city' => $senderConfig['city'],
@ -215,8 +221,6 @@ class WayBillService
'mobile' => $senderConfig['mobile'],
];
$this->setObjectId();
$orderInfo = [
'logistics_services' => [
'TIMED-DELIVERY' => [
@ -229,7 +233,7 @@ class WayBillService
'trade_order_list' => [$order['order_sn']],
],
'package_info' => [
'items' => $packageInfoItems,
'items' => $items,
],
'recipient' => [
'address' => [
@ -245,7 +249,7 @@ class WayBillService
'user_id' => $shopShip->owner_id,
];
return [$sender, $orderInfo, $senderConfig['wp_code']];
return [$sender, $orderInfo, $senderConfig];
}
public function setObjectId()
@ -339,15 +343,12 @@ class WayBillService
private function getShopShip($shopId)
{
$type = $this->timedDeliveryCode === Waybill::$AIR_FREIGHT_CODE ? 'air' : 'normal';
return ShopShip::query()
->select(['id', 'shop_id', 'access_token', 'owner_id'])
->where('shop_id', $shopId)
->where('type', $type)
->with([
'senders' => function ($query) {
$query->orderBy('sort')->first();
$query->where('status', 1)->orderBy('sort');
}
])
->first();

View File

@ -13,7 +13,7 @@ return [
|
*/
'name' => env('APP_NAME', 'CFen Erp'),
'name' => env('APP_NAME', 'chunfen_erp'),
/*
|--------------------------------------------------------------------------

View File

@ -131,7 +131,7 @@ return [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'database' => env('REDIS_DB', '10'),
],
'cache' => [
@ -139,7 +139,7 @@ return [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
'database' => env('REDIS_CACHE_DB', '11'),
],
],

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTimedDeliveryCodeToShopSendersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasColumns('shop_senders', ['timed_delivery_code'])) {
return;
}
Schema::table('shop_senders', function (Blueprint $table) {
$table->integer('timed_delivery_code')->default(247)->comment('地址类型: 247-电商标快,266-空运');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('shop_senders', function (Blueprint $table) {
$table->dropColumn(['timed_delivery_code']);
});
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateDeveloperConfigsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasTable('developer_configs')) {
return;
}
Schema::create('developer_configs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('key')->comment('配置项名称');
$table->string('value')->comment('配置项值');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('developer_configs');
}
}

View File

@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateDailyReportsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('daily_reports', function (Blueprint $table) {
$table->bigIncrements('id');
$table->date('date');
$table->unsignedInteger('goods_id');
$table->unsignedInteger('type_id');
$table->unsignedInteger('brand_id');
$table->unsignedInteger('goods_sku_id');
$table->string('external_sku_id', 64);
$table->unsignedInteger('total_goods_price')->default(0);
$table->unsignedInteger('total_goods_cost_price')->default(0);
$table->unsignedInteger('total_goods_amount')->default(0);
$table->unsignedInteger('total_goods_number')->default(0);
$table->unsignedInteger('total_cancel_number')->default(0);
$table->unsignedDecimal('cost')->default(0);
$table->text('shop_data');
$table->timestamps();
$table->index(['date', 'external_sku_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('week_reports');
}
}

View File

@ -1 +1 @@
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.table[data-v-14b6ebcc]{margin-top:20px;position:relative}.btn[data-v-14b6ebcc]{float:right}[data-v-14b6ebcc] .cell{display:flex;align-items:center}.commodityimg[data-v-14b6ebcc]{width:59px;height:59px;background:hsla(0,0%,89%,.39);opacity:1;display:block;margin-right:12px}.Img[data-v-14b6ebcc]{width:100%;height:100%}.confirmbtn[data-v-14b6ebcc]{width:114px;height:44px;border-radius:3px;margin-top:21px;margin-bottom:8px}.import-right[data-v-14b6ebcc]{margin-top:30px}.import-right a[data-v-14b6ebcc]{text-decoration:none;color:#000}[data-v-14b6ebcc] .btn11{padding:0;width:14px;height:14px}[data-v-14b6ebcc] .btn11 img{width:100%;height:100%}.page[data-v-14b6ebcc]{margin-top:20px}
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.table[data-v-10d7f5ca]{margin-top:20px;position:relative}.btn[data-v-10d7f5ca]{float:right}[data-v-10d7f5ca] .cell{display:flex;align-items:center}.commodityimg[data-v-10d7f5ca]{width:59px;height:59px;background:hsla(0,0%,89%,.39);opacity:1;display:block;margin-right:12px}.Img[data-v-10d7f5ca]{width:100%;height:100%}.confirmbtn[data-v-10d7f5ca]{width:114px;height:44px;border-radius:3px;margin-top:21px;margin-bottom:8px}.import-right[data-v-10d7f5ca]{margin-top:30px}.import-right a[data-v-10d7f5ca]{text-decoration:none;color:#000}[data-v-10d7f5ca] .btn11{padding:0;width:14px;height:14px}[data-v-10d7f5ca] .btn11 img{width:100%;height:100%}.page[data-v-10d7f5ca]{margin-top:20px}

View File

@ -1 +1 @@
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.block[data-v-6626bfcd]{margin-top:20px}
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.block[data-v-2a09710c]{margin-top:20px}

View File

@ -1 +1 @@
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}a[data-v-e84f6478]{text-decoration:none;color:#fff}.block[data-v-e84f6478]{margin-top:20px}
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}a[data-v-446dc800]{text-decoration:none;color:#fff}.block[data-v-446dc800]{margin-top:20px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>erp</title><script defer="defer" src="js/chunk-vendors.9dd0c7db.js"></script><script defer="defer" src="js/app.65f96f26.js"></script><link href="css/chunk-vendors.4e2d36cb.css" rel="stylesheet"><link href="css/app.487f8f5a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but erp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>erp</title><script defer="defer" src="js/chunk-vendors.04652b46.js"></script><script defer="defer" src="js/app.c0ecb7b8.js"></script><link href="css/chunk-vendors.77489a8d.css" rel="stylesheet"><link href="css/app.487f8f5a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but erp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
public/dist/js/156.783ddb27.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/156.783ddb27.js.map vendored Normal file

File diff suppressed because one or more lines are too long

4
public/dist/js/238.f0fe850b.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/238.f0fe850b.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
public/dist/js/262.86188f20.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/262.86188f20.js.map vendored Normal file

File diff suppressed because one or more lines are too long

4
public/dist/js/300.651c8b8a.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/300.651c8b8a.js.map vendored Normal file

File diff suppressed because one or more lines are too long

4
public/dist/js/348.a9ecce61.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/348.a9ecce61.js.map vendored Normal file

File diff suppressed because one or more lines are too long

4
public/dist/js/361.5f4eb665.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/361.5f4eb665.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
public/dist/js/43.18f7062c.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/43.18f7062c.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
public/dist/js/507.36b2cf9e.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/507.36b2cf9e.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
public/dist/js/523.e5886175.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/dist/js/523.e5886175.js.map vendored Normal file

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More