6
0
Fork 0

Merge branch 'develop'

release
李静 2022-02-17 14:48:36 +08:00
commit 8dd8b903e0
47 changed files with 991 additions and 174 deletions

View File

@ -23,10 +23,3 @@ COPY ./docker/php/php.ini "$PHP_INI_DIR/"
COPY --from=composer:2.1 /usr/bin/composer /usr/bin/composer
ARG PGID
ENV PGID ${PGID:-1000}
ARG PUID
ENV PUID ${PUID:-1000}
RUN groupmod -g ${PGID} www-data && \
usermod -u ${PUID} www-data

View File

@ -32,7 +32,7 @@ class CalculatePurchaseAmountOfCurrentPeriod
}
return Cache::remember($this->prefix($startAt).':'.$dealer->user_id, 3600, function () use ($dealer, $startAt) {
return $this->calculatePurchaseAmount->handle($dealer, $startAt);
return bcdiv($this->calculatePurchaseAmount->handle($dealer, $startAt), '1', 2);
});
}

View File

@ -10,6 +10,7 @@ use App\Admin\Actions\Show\DealerOrderRemark;
use App\Admin\Repositories\DealerOrder;
use App\Enums\DealerOrderStatus;
use App\Models\DealerChannelSubsidyLog;
use App\Models\DealerOrder as DealerOrderModel;
use App\Models\DealerOrderProduct;
use Dcat\Admin\Admin;
use Dcat\Admin\Form;
@ -48,6 +49,12 @@ class DealerOrderController extends AdminController
$grid->column('total_amount')->prepend('¥');
$statusTexts = DealerOrderStatus::texts();
$grid->column('pay_way')->using(DealerOrderModel::$payWayText)->label([
'wallet'=>'warning',
'offline'=>'danger',
'none'=>'#b3b9bf',
]);
$grid->column('order_status')->display(function ($v) {
return $this->order_status;
})->using($statusTexts)->dot([
@ -63,7 +70,7 @@ class DealerOrderController extends AdminController
// $grid->column('pay_info');
// $grid->column('pay_image');
// $grid->column('pay_time');
// $grid->column('paied_time');
$grid->column('paied_time');
// $grid->column('shipping_time');
// $grid->column('shippinged_time');
$grid->column('created_at')->sortable();
@ -96,6 +103,8 @@ class DealerOrderController extends AdminController
$filter->equal('user.phone')->width(3);
$filter->equal('consignor.phone')->width(3);
$filter->equal('sn')->width(3);
$filter->between('created_at')->dateTime()->width(5);
$filter->between('paied_time')->dateTime()->width(5);
// $filter->equal('id');
});
});

View File

@ -43,7 +43,11 @@ class DealerWalletToBankLogController extends AdminController
0=>'primary',
1=>'success',
2=>'danger',
]);
])->filter(Grid\Column\Filter\In::make([
DealerWalletToBankLogModel::STATUS_PENDING=>'待处理',
DealerWalletToBankLogModel::STATUS_AGREE=>'同意',
DealerWalletToBankLogModel::STATUS_REFUSE=>'拒绝',
]));
$grid->column('remarks');
$grid->column('created_at')->sortable();
// $grid->column('updated_at')
@ -58,11 +62,11 @@ class DealerWalletToBankLogController extends AdminController
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->equal('status')->select([
DealerWalletToBankLogModel::STATUS_PENDING=>'待处理',
DealerWalletToBankLogModel::STATUS_AGREE=>'已同意',
DealerWalletToBankLogModel::STATUS_REFUSE=>'已拒绝',
])->width(3);
// $filter->equal('status')->select([
// DealerWalletToBankLogModel::STATUS_PENDING=>'待处理',
// DealerWalletToBankLogModel::STATUS_AGREE=>'已同意',
// DealerWalletToBankLogModel::STATUS_REFUSE=>'已拒绝',
// ])->width(3);
$filter->equal('user.phone')->width(3);
$filter->between('created_at')->dateTime()->width(7);
});
@ -100,45 +104,45 @@ class DealerWalletToBankLogController extends AdminController
$show->divider('收款信息-银行');
$show->field('bank_user_name', '银行-收款人')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['bank']['user_name']??'';
return $payInfo['bank']['user_name'] ?? '';
});
$show->field('bank_bank_name', '银行-名称')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['bank']['bank_name']??'';
return $payInfo['bank']['bank_name'] ?? '';
});
$show->field('bank_bank_number', '银行-卡号')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['bank']['bank_number']??'';
return $payInfo['bank']['bank_number'] ?? '';
});
$show->field('bank_bank_description', '银行-开户行')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['bank']['bank_description']??'';
return $payInfo['bank']['bank_description'] ?? '';
});
$show->divider('收款信息-支付宝');
$show->field('alipay_user_name', '支付宝-真实名称')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['alipay']['user_name']??'';
return $payInfo['alipay']['user_name'] ?? '';
});
$show->field('alipay_ali_name', '支付宝-账户')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['alipay']['ali_name']??'';
return $payInfo['alipay']['ali_name'] ?? '';
});
$show->field('alipay_image', '支付宝-收款码')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['alipay']['image']??'';
return $payInfo['alipay']['image'] ?? '';
})->image();
$show->divider('收款信息-微信');
$show->field('wechat_user_name', '微信-真实名称')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['wechat']['user_name']??'';
return $payInfo['wechat']['user_name'] ?? '';
});
$show->field('wechat_wechat_name', '微信-ID')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['wechat']['wechat_name']??'';
return $payInfo['wechat']['wechat_name'] ?? '';
});
$show->field('wechat_image', '微信-收款码')->as(function () {
$payInfo = $this->getPayInfo();
return $payInfo['wechat']['image']??'';
return $payInfo['wechat']['image'] ?? '';
})->image();
$show->field('created_at');

View File

@ -51,7 +51,7 @@ class DealerProductLvlRule extends Form implements LazyRenderable
$_rule = DealerProductLvlRuleModel::find($rule['id']);
$_rule['lvl'] = $rule['lvl'];
$_rule['sale_price'] = $rule['sale_price'];
$_rule['min_order_amount'] = $rule['min_order_amount'];
// $_rule['min_order_amount'] = $rule['min_order_amount'];
$lvlRules[] = $_rule;
}
}
@ -88,7 +88,7 @@ class DealerProductLvlRule extends Form implements LazyRenderable
6 => '一级经销商',
]);
$form->currency('sale_price', '等级进货单价')->symbol('¥');
$form->currency('min_order_amount', '等级单次最低进货价')->symbol('¥');
// $form->currency('min_order_amount', '等级单次最低进货价')->symbol('¥');
});
}

View File

@ -43,9 +43,15 @@ class Dealer extends Form
$this->currency('withdraw_fee_rate', '提现费率')->symbol('%');
$this->number('withdraw_days', '提现间隔');
$this->currency('upgrade_amount_'.DealerLvl::Contracted->value, '签约门槛')->symbol('¥');
$this->currency('upgrade_amount_'.DealerLvl::Special->value, '特邀门槛')->symbol('¥');
$this->currency('upgrade_amount_'.DealerLvl::Gold->value, '金牌门槛')->symbol('¥');
$this->currency('upgrade_amount_'.DealerLvl::Gold->value, '金牌升级门槛')->symbol('¥');
$this->currency('upgrade_amount_'.DealerLvl::Special->value, '特邀升级门槛')->symbol('¥');
$this->currency('upgrade_amount_'.DealerLvl::Contracted->value, '签约升级门槛')->symbol('¥');
$this->currency('min_order_amount_'.DealerLvl::Gold->value, '金牌单次进货最低金额')->symbol('¥');
$this->currency('min_order_amount_'.DealerLvl::Special->value, '特邀单次进货最低金额')->symbol('¥');
$this->currency('min_order_amount_'.DealerLvl::Contracted->value, '签约单次进货最低金额')->symbol('¥');
$this->currency('min_order_amount_'.DealerLvl::Secondary->value, '二级签约单次进货最低金额')->symbol('¥');
$this->currency('min_order_amount_'.DealerLvl::Top->value, '一级签约单次进货最低金额')->symbol('¥');
$this->number('order_auto_allocate_times', '订单自动分配时间(分)')->min(1);
@ -139,6 +145,13 @@ class Dealer extends Form
'upgrade_amount_'.DealerLvl::Contracted->value => $dealerSettings['upgrade_amount_'.DealerLvl::Contracted->value] ?? '',
'upgrade_amount_'.DealerLvl::Special->value => $dealerSettings['upgrade_amount_'.DealerLvl::Special->value] ?? '',
'upgrade_amount_'.DealerLvl::Gold->value => $dealerSettings['upgrade_amount_'.DealerLvl::Gold->value] ?? '',
'min_order_amount_'.DealerLvl::Gold->value => $dealerSettings['min_order_amount_'.DealerLvl::Gold->value] ?? '',
'min_order_amount_'.DealerLvl::Special->value => $dealerSettings['min_order_amount_'.DealerLvl::Special->value] ?? '',
'min_order_amount_'.DealerLvl::Contracted->value => $dealerSettings['min_order_amount_'.DealerLvl::Contracted->value] ?? '',
'min_order_amount_'.DealerLvl::Secondary->value => $dealerSettings['min_order_amount_'.DealerLvl::Secondary->value] ?? '',
'min_order_amount_'.DealerLvl::Top->value => $dealerSettings['min_order_amount_'.DealerLvl::Top->value] ?? '',
'bank'=>$dealerSettings['bank'] ?? [],
'alipay'=>$dealerSettings['alipay'] ?? [],
'wechat' =>$dealerSettings['wechat'] ?? [],

View File

@ -393,6 +393,10 @@ class OrderProcessCommand extends Command
$ranking = 0;
foreach ($dealers as $dealer) {
if (! in_array($dealer->lvl, [DealerLvl::Secondary, DealerLvl::Top])) {
continue;
}
// 如果当前经销商等级没有对应的管理津贴分配规则,则忽略
if (is_null($rule = $rules->get($dealer->lvl->value))) {
continue;
@ -400,6 +404,27 @@ class OrderProcessCommand extends Command
// 同等级管理津贴最多给三次
if ($last === null || $dealer->lvl->value > $last->lvl->value) {
if ($ranking < 3 && $dealer->lvl === DealerLvl::Top) {
if ($secondarySubsidyRule = $rules->get(DealerLvl::Secondary->value)) {
$key = 'price_'.(1 + $ranking).'st';
$secondarySubsidy = $secondarySubsidyRule->{$key};
if (bccomp($secondarySubsidy, '0') === 1) {
$logs[] = [
'user_id' => $dealer->user_id,
'order_id' => $product->order_id,
'product_id' => $product->product_id,
'lvl' => $dealer->lvl,
'sales_volume' => $product->qty,
'total_amount' => bcmul($product->qty, $secondarySubsidy, 2),
'created_at' => $tz,
'updated_at' => $tz,
];
}
}
}
$ranking = 1;
} elseif ($ranking < 3 && $dealer->lvl->value === $last->lvl->value) {
$ranking++;

View File

@ -34,15 +34,27 @@ class OrderSettleCommand extends Command
public function handle()
{
while (true) {
$page = 0;
Order::where(
'completed_at',
'<=',
now()->subDays(app_settings('distribution.settle_days', 7))
)->where([
'status' => Order::STATUS_COMPLETED,
'is_settlable' => false,
'is_settle' => false,
])->chunkById(200, function ($orders) {
foreach ($orders as $order) {
$order->update([
'is_settlable' => true,
]);
}
});
// 只查询可结算的订单,并且没有处理中的售后单
// 检查订单是否有未执行的分销任务
Order::whereDoesntHave('afterSales', function ($query) {
return $query->processing();
})->whereDoesntHave('distributionPreIncomeJobs', function ($query) {
return $query->pending();
})->settlable()->chunkById(200, function ($orders) use (&$page) {
})->settlable()->chunkById(200, function ($orders) {
$orders->load(['user', 'afterSales']);
foreach ($orders as $order) {
@ -58,17 +70,9 @@ class OrderSettleCommand extends Command
report($e);
}
}
$page++;
});
if ($page === 0) {
sleep(60);
} elseif ($page === 1) {
sleep(30);
} else {
sleep(15);
}
sleep(60);
}
}

View File

@ -18,9 +18,12 @@ class DealerOrderFilter extends ModelFilter
case 'wait_paid'://待收款
$this->onlyPaid();
break;
case 'wait_shippinged'://待收
case 'wait_shipping'://待发
$this->onlyShipping();
break;
case 'wait_shippinged'://待收货
$this->onlyShippinged();
break;
case 'completed'://已完成
$this->onlyCompleted();
break;

View File

@ -4,12 +4,50 @@ namespace App\Endpoint\Api\Http\Controllers\Account;
use App\Endpoint\Api\Http\Controllers\Controller;
use App\Exceptions\BizException;
use App\Models\SmsCode;
use App\Models\Wallet;
use App\Services\SmsCodeService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
class WalletPasswordController extends Controller
{
/**
* 设置钱包密码
*
* @param Request $request
* @param SmsCodeService $smsCodeService
* @return void
*/
public function update(Request $request, SmsCodeService $smsCodeService)
{
$input = $request->validate([
'verify_code' => ['bail', 'required'],
'password' => ['bail', 'required', 'regex:/^\d{6}$/i'],
], [
'password.regex' => '安全密码 是6位数字',
], [
'verify_code' => '验证码',
'password' => '安全密码',
]);
$user = $request->user();
$smsCodeService->validate(
$user->phone,
SmsCode::TYPE_SET_WALLET_PASSWORD,
$input['verify_code']
);
Wallet::updateOrCreate([
'user_id'=> $user->id,
], [
'password' => $input['password'],
]);
return response()->noContent();
}
/**
* 设置安全密码
*

View File

@ -6,6 +6,7 @@ use App\Endpoint\Api\Http\Controllers\Controller;
use App\Endpoint\Api\Http\Resources\Dealer\OrderResource;
use App\Endpoint\Api\Http\Resources\Dealer\OrderSimpleResource;
use App\Exceptions\BizException;
use App\Exceptions\PayPasswordIncorrectException;
use App\Helpers\Paginator as PaginatorHelper;
use App\Models\DealerOrder;
use App\Models\DealerProduct;
@ -57,7 +58,84 @@ class OrderController extends Controller
$product = DealerProduct::online()->findOrFail($input['product_id']);
try {
DB::beginTransaction();
$order = $orderService->createOrder($request->user(), $product, $input['num'], $input['shipping_address_id']);
$order = $orderService->quickCreateOrder($request->user(), $product, $input['num'], $input['shipping_address_id']);
DB::commit();
} catch (BizException $e) {
DB::rollBack();
throw $e;
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('下单失败,请稍后再试');
}
return OrderResource::make($order);
}
/**
* 确认订单
*
* @param Request $request
* @param OrderService $orderService
*/
public function checkOrder(Request $request, OrderService $orderService)
{
$input = $request->validate([
'shopping_cart' => ['bail', 'required', 'array'],
], [], [
'shopping_cart'=>'购物车商品',
]);
$user = $request->user();
$shoppingCartItems = $user->dealerShoppingCartItems()->findMany($input['shopping_cart']);
$shoppingCartItems->load('product');
$totalQty = $shoppingCartItems->sum('quantity');
$data = [];
foreach ($shoppingCartItems as $item) {
$data[] = [
'id' => $item->id,
'name' => $item->name,
'cover' => $item->cover,
'sell_price' => $item->sell_price,
'dealer_price' => $orderService->getSalePrice($user, $item->product, $totalQty),
'quantity' => $item->quantity,
];
}
return response()->json(['data'=>$data]);
}
/**
* 新下单接口
*/
public function newStore(Request $request, OrderService $orderService)
{
$isQuick = $request->filled('product');
$rules = $isQuick ? [
'product.id' => ['bail', 'required', 'int'],
'product.quantity' => ['bail', 'required', 'int', 'min:1'],
'shipping_address_id' => ['bail', 'required', 'int'],
] : [
'shopping_cart' => ['bail', 'required', 'array'],
'shipping_address_id' => ['bail', 'required', 'int'],
];
$input = $request->validate($rules, [], [
'product.id' => '商品',
'product.quantity' => '数量',
'shopping_cart' => '购物车商品',
'shipping_address_id' => '收货地址',
]);
try {
DB::beginTransaction();
if ($isQuick) {
$product = DealerProduct::online()->findOrFail($input['product']['id']);
$order = $orderService->quickCreateOrder($request->user(), $product, $input['product']['quantity'], $input['shipping_address_id']);
} else {
$order = $orderService->cartCreateOrder($request->user(), $input['shopping_cart'], $input['shipping_address_id']);
}
DB::commit();
} catch (BizException $e) {
DB::rollBack();
@ -138,8 +216,33 @@ class OrderController extends Controller
$input = $request->validate([
'pay_image' => ['bail', 'string'],
'pay_way' => ['bail', 'string'],
'pay_password' => ['bail', 'string'],
], [], [
'pay_image' => '打款凭证',
'pay_way' => '支付方式',
'pay_password' => '支付密码',
]);
$orderService->payOrder($order, $input['pay_image'] ?? null);
$payWay = $input['pay_way'] ?? 'offline';
if ($payWay == DealerOrder::PAY_WAY_WALLET) {
//验证支付密码
if (! $request->user()->wallet?->verifyPassword($input['pay_password'] ?? '')) {
throw new PayPasswordIncorrectException();
}
}
try {
DB::beginTransaction();
$orderService->payOrder($order, $input['pay_way'] ?? 'offline', $input['pay_image'] ?? null);
DB::commit();
} catch (BizException $th) {
DB::rollBack();
throw $th;
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('操作失败,请刷新后再试');
}
return response()->noContent();
}
@ -166,7 +269,40 @@ class OrderController extends Controller
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$e = new BizException('当前可发货库存不足');
}
throw $e;
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('操作失败,请刷新后再试');
}
return response()->noContent();
}
/**
* 确认发货
*
* @param [type] $id
* @param Request $request
* @param OrderService $orderService
* @return void
*/
public function shippingOrder($id, Request $request, OrderService $orderService)
{
$order = DealerOrder::findOrFail($id);
$userId = $request->user()->id;
//不是发货人
if (!$order->isConsignor($userId)) {
throw new BizException('订单未找到');
}
try {
DB::beginTransaction();
$orderService->shippingOrder($order);//确认发货
DB::commit();
} catch (QueryException $e) {
DB::rollBack();
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$e = new BizException('当前可发货库存不足');
}
throw $e;
} catch (Throwable $th) {
DB::rollBack();

View File

@ -0,0 +1,101 @@
<?php
namespace App\Endpoint\Api\Http\Controllers\Dealer;
use App\Endpoint\Api\Http\Controllers\Controller;
use App\Models\DealerProduct;
use App\Services\Dealer\OrderService;
use Illuminate\Http\Request;
class ShoppingCartItemController extends Controller
{
/**
* 购物车商品列表
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request, OrderService $orderService)
{
$user = $request->user();
$items = $user->dealerShoppingCartItems()->latest('id')->get();
$items->load('product');
$totalQty = $items->sum('quantity');
$data = [];
foreach ($items as $item) {
$data[] = [
'id'=>$item->id,
'name' =>$item->name,
'cover'=>$item->cover,
'sell_price'=>$item->sell_price,
'dealer_price' =>$orderService->getSalePrice($user, $item->product, $totalQty),
'quantity'=>$item->quantity,
];
}
return response()->json(['data'=>$data]);
}
/**
* 加入购物车
*/
public function store(Request $request)
{
$input = $request->validate([
'product_id' => ['bail', 'required', 'int'],
'quantity' => ['bail', 'required', 'int', 'min:1'],
]);
$product = DealerProduct::online()->findOrFail($input['product_id']);
$shoppingCartItem = $request->user()->dealerShoppingCartItems()->firstOrCreate([
'product_id' => $product->id,
], [
'name' => $product->name,
'cover' => $product->cover,
'sell_price' => $product->price,
'quantity' => $input['quantity'],
]);
if (!$shoppingCartItem->wasRecentlyCreated) {
$shoppingCartItem->increment('quantity', $input['quantity']);
}
return response()->noContent();
}
/**
* 购物车变动
*/
public function update($id, Request $request)
{
$input = $request->validate([
'quantity' => ['bail', 'required', 'int', 'min:1'],
]);
$shoppingCartItem = $request->user()->dealerShoppingCartItems()->findOrFail($id);
$product = DealerProduct::online()->findOrFail($shoppingCartItem->product_id);
$shoppingCartItem->update(array_merge($input, [
'name' => $product->name,
'cover' => $product->cover,
'sell_price' => $product->price,
]));
return response()->noContent();
}
/**
* 移出购物车
*/
public function delete(Request $request)
{
$input = $request->validate([
'ids' => ['bail', 'required', 'array'],
]);
$request->user()->dealerShoppingCartItems()->whereIn('id', $input['ids'])->delete();
return response()->noContent();
}
}

View File

@ -2,6 +2,7 @@
namespace App\Endpoint\Api\Http\Controllers\Dealer;
use App\Actions\Dealer\CalculatePurchaseAmountOfCurrentPeriod;
use App\Endpoint\Api\Http\Controllers\Controller;
use App\Endpoint\Api\Http\Resources\Dealer\DealerResource;
use App\Endpoint\Api\Http\Resources\Dealer\UserInfoResource;
@ -13,17 +14,24 @@ class UserController extends Controller
* 个人信息
*
* @param \Illuminate\Http\Request $request
* @param \App\Actions\Dealer\CalculatePurchaseAmountOfCurrentPeriod $calculatePurchaseAmountOfCurrentPeriod
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request)
{
public function show(
Request $request,
CalculatePurchaseAmountOfCurrentPeriod $calculatePurchaseAmountOfCurrentPeriod
) {
$user = $request->user();
$dealer = DealerResource::make($user->dealer)->toArray($request);
$dealer['current_purchase_amount'] = $calculatePurchaseAmountOfCurrentPeriod->handle($user->dealer);
return response()->json([
'phone' => $user->phone,
'dealer'=> $user->dealer ? DealerResource::make($user->dealer) : [],
'dealer'=> $dealer,
'dealer_wallet' => $user->dealerWallet?->balance,
'user_info' => UserInfoResource::make($user->userInfo),
'has_password' => (bool) $user->wallet?->password,
]);
}

View File

@ -8,6 +8,7 @@ use App\Endpoint\Api\Http\Resources\Dealer\UserProductResource;
use App\Exceptions\BizException;
use App\Helpers\Paginator;
use App\Models\DealerUserProductLog;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
@ -73,9 +74,15 @@ class UserProductController extends Controller
'product_id'=> $input['product_id'],
'type' => DealerUserProductLog::TYPE_OFFLINE_OUT,
'qty'=>$input['num'],
'remark'=>$input['remark']??null,
'remark'=>$input['remark'] ?? null,
]);
DB::commit();
} catch (QueryException $e) {
DB::rollBack();
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$e = new BizException('库存不足');
}
throw $e;
} catch (Throwable $th) {
DB::rollBack();
report($th);
@ -83,4 +90,53 @@ class UserProductController extends Controller
}
return response()->noContent();
}
/**
* 撤销线下去库存
*
*/
public function revokeQtyLog(DealerUserProductLog $log, Request $request)
{
//判断是否是自己的日志
if ($log->user_id != $request->user()->id) {
throw new BizException('日志未找到');
}
//是否可以撤销
if (!$log->canRevoke()) {
throw new BizException('该日志无法撤销');
}
$product = $request->user()->dealerProducts()
->where('product_id', $log->product_id)
->first();
if (!$product) {
throw new BizException('您还没有该商品');
}
try {
DB::beginTransaction();
$product->increment('stock', $log->qty);
$revokeLog = DealerUserProductLog::create([
'user_id'=> $request->user()->id,
'product_id'=> $log->product_id,
'type' => DealerUserProductLog::TYPE_REVOKE_IN,
'qty' => $log->qty,
'remark'=> '撤销回滚',
]);
$log->update([
'revoke_id' => $revokeLog->id,
]);
DB::commit();
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('系统繁忙,请稍后再试');
}
return response()->noContent();
}
}

View File

@ -136,7 +136,7 @@ class OrderController extends Controller
DB::transaction(function () use ($id, $user) {
$order = $user->orders()->lockForUpdate()->findOrFail($id);
(new OrderService())->confirm($order);
(new OrderService())->confirm($order, true);
});
return response()->noContent();

View File

@ -2,9 +2,12 @@
namespace App\Endpoint\Api\Http\Controllers;
use App\Endpoint\Api\Http\Requests\StoreSmsCodeRequest;
use App\Exceptions\BizException;
use App\Models\SmsCode;
use App\Rules\PhoneNumber;
use App\Services\SmsCodeService;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;
use Throwable;
class SmsCodeController extends Controller
@ -12,22 +15,36 @@ class SmsCodeController extends Controller
/**
* 发送短信验证码
*
* @param \App\Endpoint\Api\Http\Requests\StoreSmsCodeRequest $request
* @param \Illuminate\Http\Request $request
* @param \App\Services\SmsCodeService $smsCodeService
* @return \Illuminate\Http\Response
*
* @throws \App\Exceptions\BizException
*/
public function store(
StoreSmsCodeRequest $request,
Request $request,
SmsCodeService $smsCodeService,
) {
$type = (int) $request->input('type');
if (in_array($type, [SmsCode::TYPE_SET_WALLET_PASSWORD])) {
if (is_null($user = $request->user())) {
throw new AuthenticationException('请先登录', ['api']);
}
$phone = $user->phone;
} else {
$request->validate([
'phone' => ['bail', 'required', new PhoneNumber()],
]);
$phone = $request->input('phone');
}
$code = app()->isProduction() ? mt_rand(100000, 999999) : '666666';
try {
$smsCodeService->send(
$request->input('phone'),
$request->input('type'),
app()->isProduction() ? mt_rand(100000, 999999) : '666666',
);
$smsCodeService->send($phone, $type, $code);
} catch (BizException $e) {
throw $e;
} catch (Throwable $e) {

View File

@ -1,32 +0,0 @@
<?php
namespace App\Endpoint\Api\Http\Requests;
use App\Rules\PhoneNumber;
use Illuminate\Foundation\Http\FormRequest;
class StoreSmsCodeRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'phone' => ['bail', 'required', new PhoneNumber()],
'type' => ['bail', 'required', 'int'],
];
}
}

View File

@ -18,11 +18,11 @@ class DealerResource extends JsonResource
'lvl' => $this->lvl,
'lvl_name'=> $this->lvl_text,
'is_sale' => $this->is_sale,
'guanli_values'=> $this->calculate_total_amount, //预计管理津贴
'guanli_values'=> bcdiv($this->calculate_total_amount, '1', 2), //预计管理津贴
'team_sales_value' => $this->team_sales_value, // 团队业绩
'pay_info'=>$this->pay_info ?: null,
'can_withdraw'=> $this->canWithdraw(),
'total_purchase_amount'=> $this->total_purchase_amount, // 总进货业绩
'total_purchase_amount'=> bcdiv($this->total_purchase_amount, '1', 2), // 总进货业绩
];
}
}

View File

@ -21,6 +21,7 @@ class OrderResource extends JsonResource
'total_amount' => $this->total_amount,
'created_at' => $this->created_at->toDateTimeString(),
'status' => $this->status,
'pay_way' => $this->pay_way ?? '',
'pay_info' => $this->getConsignorPayInfo(),
'pay_image'=> $this->pay_image,
'is_consignor' => $request->user()->id == $this->consignor_id, //是否发货人身份

View File

@ -17,7 +17,7 @@ class ProductLvlRuleResource extends JsonResource
return [
'lvl' => $this->lvl,
'sale_price' => $this->sale_price,
'min_order_amount' => $this->min_order_amount,
'min_order_amount' => app_settings('dealer.min_order_amount_'.$this->lvl, 0),
];
}
}

View File

@ -16,10 +16,16 @@ class UserProductLogResource extends JsonResource
public function toArray($request)
{
return [
'id' => $this->id,
'product_name'=> $this->product?->name,
'remark' => $this->remark,
'qty' => ($this->type == DealerUserProductLog::TYPE_ORDER_IN ? '+' : '-').$this->qty.$this->product?->unit,
'qty' => (in_array($this->type, [
DealerUserProductLog::TYPE_ORDER_IN,
DealerUserProductLog::TYPE_ADMIN_IN,
DealerUserProductLog::TYPE_REVOKE_IN,
]) ? '+' : '-').$this->qty.$this->product?->unit,
'created_at' => $this->created_at->toDateTimeString(),
'can_revoke' => $this->canRevoke(),
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Endpoint\Api\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class OrderProductSimpleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'sku_id' => $this->sku_id,
'name' => $this->name,
'cover' => $this->cover,
'specs' => array_values((array) $this->specs),
'sell_price' => $this->sell_price_format,
'vip_price' => $this->vip_price_format,
'total_amount' => $this->total_amount,
'quantity' => $this->quantity,
'is_gift' => $this->isGift(),
];
}
}

View File

@ -14,6 +14,12 @@ class OrderResource extends JsonResource
*/
public function toArray($request)
{
if ($this->resource->relationLoaded('products')) {
foreach ($this->resource->products as $product) {
$product->setRelation('order', $this->resource);
}
}
return [
'id' => $this->id,
'sn' => $this->sn,

View File

@ -21,7 +21,7 @@ class OrderResourceCollection extends ResourceCollection
'total_amount' => $item->total_amount_format,
'status' => $item->order_status,
'created_date' => $item->created_at->toDateString(),
'products' => OrderProductResource::collection($item->whenLoaded('products')),
'products' => OrderProductSimpleResource::collection($item->whenLoaded('products')),
'expires_at' => $item->expires_at,
];
})->toArray();

View File

@ -92,6 +92,7 @@ Route::group([
// 修改密码
Route::post('change-password', ChangePasswordController::class);
//安全密码
Route::put('wallet-password', [WalletPasswordController::class, 'update']);
Route::post('wallet-password/reset', [WalletPasswordController::class, 'reset']);//重置或设置安全密码
//我的账户
@ -236,13 +237,22 @@ Route::group([
Route::get('user-products/{product}', [Dealer\UserProductController::class, 'show']);
Route::get('user-products-logs', [Dealer\UserProductController::class, 'logs']);
Route::post('user-products/offline-out', [Dealer\UserProductController::class, 'offlineOutQty']);
Route::post('user-products/offline-out-revoke/{log}', [Dealer\UserProductController::class, 'revokeQtyLog']);
//购物车
Route::apiResource('shopping-cart-items', Dealer\ShoppingCartItemController::class)->only(
['index', 'store', 'update']
);
Route::delete('shopping-cart-items', [Dealer\ShoppingCartItemController::class, 'delete']);
Route::get('orders-check', [Dealer\OrderController::class, 'checkOrder']);
//计算商品下单价格
Route::get('orders/total-amount', [Dealer\OrderController::class, 'totalAmount']);
//订单列表
Route::get('orders', [Dealer\OrderController::class, 'index']);
//下单
Route::post('orders', [Dealer\OrderController::class, 'store']);
Route::post('orders-new', [Dealer\OrderController::class, 'newStore']);
//订单详情
Route::get('orders/{order}', [Dealer\OrderController::class, 'show']);
@ -250,8 +260,10 @@ Route::group([
Route::post('orders/{order}/confirm', [Dealer\OrderController::class, 'confirmOrder']);
//确认打款
Route::post('orders/{order}/pay', [Dealer\OrderController::class, 'payOrder']);
//确认收款
//确认收款+发货
Route::post('orders/{order}/paid', [Dealer\OrderController::class, 'paidOrder']);
//确认发货
Route::post('orders/{order}/shipping', [Dealer\OrderController::class, 'shippingOrder']);
//确认收货
Route::post('orders/{order}/shippinged', [Dealer\OrderController::class, 'shippingedOrder']);
//取消订单

View File

@ -9,4 +9,6 @@ enum DealerWalletAction: int {
case ChannelSubsidyIn = 4;
case WithdrawBank = 5;
case WithdrawFiled = 6;
case OrderPaid = 7;
case OrderIncome = 8;
}

View File

@ -14,6 +14,9 @@ class DealerOrder extends Model
use Filterable;
use HasDateTimeFormatter;
public const PAY_WAY_WALLET = 'wallet'; // 余额
public const PAY_WAY_OFFLINE = 'offline'; // 线下支付
protected $attributes = [
'status' => DealerOrderStatus::Pending,
'settle_state' => DealerOrderSettleState::Pending,
@ -40,6 +43,7 @@ class DealerOrder extends Model
'consignee_telephone',
'consignee_zone',
'consignee_address',
'pay_way',
'pay_time',
'paied_time',
'shipping_time',
@ -48,6 +52,11 @@ class DealerOrder extends Model
'remark',
];
public static $payWayText = [
self::PAY_WAY_WALLET => '余额支付',
self::PAY_WAY_OFFLINE => '线下打款',
];
/**
* 仅获取待结算的已付款订单
*/
@ -79,7 +88,7 @@ class DealerOrder extends Model
}
/**
* 待收款+待发货
* 待收款
*/
public function scopeOnlyPaid($query)
{
@ -87,9 +96,17 @@ class DealerOrder extends Model
}
/**
* 已发货/待收
* 待发
*/
public function scopeOnlyShipping($query)
{
return $query->where('status', DealerOrderStatus::Paid);
}
/**
* 已发货/待收货
*/
public function scopeOnlyShippinged($query)
{
// return $query->whereIn('status', [
// DealerOrderStatus::Confirming, DealerOrderStatus::Paid, DealerOrderStatus::Shipped,

View File

@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class DealerShoppingCartItem extends Model
{
use HasFactory;
protected $fillable = [
'product_id',
'user_id',
'name',
'cover',
'sell_price',
'quantity',
];
public function product()
{
return $this->belongsTo(DealerProduct::class, 'product_id');
}
}

View File

@ -18,6 +18,7 @@ class DealerUserProductLog extends Model
public const TYPE_OFFLINE_OUT = 3;//线下去库存
public const TYPE_ADMIN_IN = 4;//后台添加库存
public const TYPE_ADMIN_OUT = 5;//后台扣减库存
public const TYPE_REVOKE_IN = 9;//撤销线下去库存
protected $fillable = [
'user_id',
@ -25,10 +26,16 @@ class DealerUserProductLog extends Model
'type',
'qty',
'remark',
'revoke_id',
];
public function product()
{
return $this->belongsTo(DealerProduct::class, 'product_id');
}
public function canRevoke()
{
return ($this->type == static::TYPE_OFFLINE_OUT) && ($this->revoke_id == 0);
}
}

View File

@ -44,6 +44,7 @@ class Order extends Model
'is_settle' => false,
'is_change' => false,
'status' => self::STATUS_PENDING,
'is_settlable' => false,
];
/**
@ -56,6 +57,7 @@ class Order extends Model
'status' => 'int',
'is_settle' => 'bool',
'is_change' => 'bool',
'is_settlable' => 'bool',
];
/**
@ -88,6 +90,7 @@ class Order extends Model
'is_change',
'is_settle',
'sales_value',
'is_settlable',
];
public static $payWayText = [
@ -123,7 +126,7 @@ class Order extends Model
public function scopeSettlable($query)
{
return $query->where('status', static::STATUS_COMPLETED)
->where('completed_at', '<=', now()->subDays(app_settings('distribution.settle_days', 7)))
->where('is_settlable', true)
->where('is_settle', false);
}
@ -302,19 +305,6 @@ class Order extends Model
return $this->status === static::STATUS_CANCELLED;
}
/**
* 将订单标记为已完成
*
* @return void
*/
public function markAsCompleted()
{
$this->update([
'status' => static::STATUS_COMPLETED,
'completed_at' => now(),
]);
}
/**
* 获取订单券优惠金额
*

View File

@ -81,6 +81,15 @@ class OrderProduct extends Model
return $this->belongsTo(ProductSku::class, 'sku_id');
}
/**
* 此订单商品所属的SKU
*
*/
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
}
/**
* 确认此订单商品是否是赠品
*
@ -100,11 +109,15 @@ class OrderProduct extends Model
{
$res = false;
//老判断,有过期时间,且未到过期时间,未发起过售后
if ($this->order->is_settlable) {
return false;
}
// 老判断,有过期时间,且未到过期时间,未发起过售后
// $oldJudge = !is_null($this->after_expire_at) && $this->after_expire_at > now() && $this->after_sale_state == 0;
//新判断, 有发货单,在售后时间范围内, 当前无售后;
if ($this->packages()->where('is_failed', false)->count() >0) {
if ($this->packages()->where('is_failed', false)->count() > 0) {
if ((is_null($this->after_expire_at) || $this->after_expire_at > now()) && $this->after_sale_state == 0) {
$res = true;
}
@ -121,9 +134,11 @@ class OrderProduct extends Model
public function getHasAfterSaleAttribute(): bool
{
$res = false;
if ($this->afterSales()->count() > 0) {
$res =true;
$res = true;
}
return $res;
}

View File

@ -2,10 +2,12 @@
namespace App\Models;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Model;
class QuotaLog extends Model
{
use HasDateTimeFormatter;
/**
* @var array
*/

View File

@ -14,6 +14,7 @@ class SmsCode extends Model
public const TYPE_REGISTER = 1;
public const TYPE_RESET_PASSWORD = 2;
public const TYPE_SET_WALLET_PASSWORD = 3;
/**
* @var array
@ -51,6 +52,7 @@ class SmsCode extends Model
public static $allowedTypes = [
self::TYPE_REGISTER,
self::TYPE_RESET_PASSWORD,
self::TYPE_SET_WALLET_PASSWORD,
];
/**

View File

@ -104,6 +104,15 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac
return $this->hasMany(ShoppingCartItem::class);
}
/**
* 属于此用户的批零购物车商品
*
*/
public function dealerShoppingCartItems()
{
return $this->hasMany(DealerShoppingCartItem::class);
}
/**
* 属于此用户的收货地址
*/

View File

@ -4,9 +4,11 @@ namespace App\Services\Dealer;
use App\Enums\DealerLvl;
use App\Enums\DealerOrderStatus;
use App\Enums\DealerWalletAction;
use App\Exceptions\BizException;
use App\Models\DealerOrder;
use App\Models\DealerOrderAllocateLog;
use App\Models\DealerOrderProduct;
use App\Models\DealerProduct;
use App\Models\DealerUserProductLog;
use App\Models\ShippingAddress;
@ -17,13 +19,13 @@ use Illuminate\Database\QueryException;
class OrderService
{
/**
* 计算订单价格
* 获取单个商品实际价格
*
* @param User $user
* @param DealerProduct $product
* @param integer $number
* @return string
*/
public function totalAmount(User $user, DealerProduct $product, int $number = 0)
public function getSalePrice(User $user, DealerProduct $product, int $number = 0)
{
//获取等级规则,判断当前用户等级是否配置等级价格
$salePrice = $product->price;
@ -44,13 +46,23 @@ class OrderService
break;
}
}
// dd($salePrice, $number);
return bcmul($salePrice, $number, 2);
return $salePrice;
}
/**
* 创建订单
* 计算订单价格
*
* @param DealerProduct $product
* @param integer $number
* @return string
*/
public function totalAmount(User $user, DealerProduct $product, int $number = 0, ?int $allNumber = null)
{
return bcmul($this->getSalePrice($user, $product, $allNumber ?? $number), $number, 2);
}
/**
* 快捷创建订单(单个商品下单)
*
* @param User $user
* @param DealerProduct $product
@ -58,16 +70,109 @@ class OrderService
* @param integer $shippingAddressId
* @return DealerOrder $order
*/
public function createOrder(User $user, DealerProduct $product, int $number = 0, int $shippingAddressId)
public function quickCreateOrder(User $user, DealerProduct $product, int $number = 0, int $shippingAddressId)
{
//判断是否满足当前等级最低补货价
$totalAmount = $this->totalAmount($user, $product, $number);
foreach ($product->lvlRules as $rule) {
if ($user->dealer && $rule->lvl == $user->dealer->lvl->value && $totalAmount < $rule->min_order_amount) {
throw new BizException('当前单次补货价格不能低于'.$rule->min_order_amount.'元');
}
// foreach ($product->lvlRules as $rule) {
// $min_order_amount = app_settings('min_order_amount'.$rule->lvl);
// if ($user->dealer && $rule->lvl == $user->dealer->lvl->value && $totalAmount < $min_order_amount) {
// throw new BizException('当前单次补货价格不能低于'.$min_order_amount.'元');
// }
// }
$order = $this->createOrder($user, $totalAmount, $shippingAddressId);
//保存订单商品-----一个订单对应一个商品
$order->products()->create([
'order_id' => $order->id,
'product_id'=> $product->id,
'name'=> $product->name,
'subtitle'=> $product->subtitle,
'cover'=> $product->cover,
'price' => $product->price,
'sale_price'=> bcdiv($totalAmount, $number, 2),
'qty'=> $number,
]);
if (!$order->consignor) {//如果订单分配给公司,则直接确认
$this->confirmOrder($order);
}
return $order;
}
/**
* 购物车创建订单
*
* @param User $user
* @param [type] $cartIds
* @param integer $shippingAddressId
* @return DealerOrder $order
*/
public function cartCreateOrder(User $user, $cartIds, int $shippingAddressId)
{
//获取购物车商品
$shoppingCartItems = $user->dealerShoppingCartItems()->findMany($cartIds);
if ($shoppingCartItems->count() !== count($cartIds)) {
throw new BizException('购物车商品已丢失');
}
$shoppingCartItems->load('product');
$totalQty = $shoppingCartItems->sum('quantity');
$totalAmount = 0;
$orderProducts = [];
foreach ($shoppingCartItems as $item) {
if (!$item->product->isOnline()) {
throw new BizException('购物车商品已失效');
}
//计算订单价格
$totalAmount += $this->totalAmount($user, $item->product, $item->quantity, $totalQty);
//组装订单商品
$orderProducts[] = [
'product_id' => $item->product_id,
'name'=> $item->name,
'subtitle' => $item->product->subtitle,
'cover' => $item->cover,
'price' => $item->sell_price,
'sale_price' => $this->getSalePrice($user, $item->product, $totalQty),
'qty' => $item->quantity,
];
}
$order = $this->createOrder($user, $totalAmount, $shippingAddressId);
DealerOrderProduct::insert(array_map(function ($product) use ($order) {
return array_merge($product, [
'order_id'=>$order->id,
'created_at'=> $order->created_at,
'updated_at'=> $order->updated_at,
]);
}, $orderProducts));
//清除购物车对应商品
$user->dealerShoppingCartItems()->whereIn('id', $cartIds)->delete();
if (!$order->consignor) {//如果订单分配给公司,则直接确认
$this->confirmOrder($order);
}
return $order;
}
/**
* 创建订单
*
* @param User $user
* @param [type] $totalAmount
* @param integer $shippingAddressId
* @return DealerOrder $order
*/
protected function createOrder(User $user, $totalAmount, int $shippingAddressId)
{
//判断是否满足当前等级最低补货价
$min_order_amount = app_settings('dealer.min_order_amount_'.$user->dealer?->lvl->value, 0);
if ($user->dealer && $totalAmount < $min_order_amount) {
throw new BizException('当前单次补货价格不能低于'.$min_order_amount.'元');
}
//找到发货人
$consignor = $this->getConsignor($user, $totalAmount);
@ -96,22 +201,6 @@ class OrderService
}
} while (true);
//保存订单商品-----一个订单对应一个商品
$order->products()->create([
'order_id' => $order->id,
'product_id'=> $product->id,
'name'=> $product->name,
'subtitle'=> $product->subtitle,
'cover'=> $product->cover,
'price' => $product->price,
'sale_price'=> bcdiv($totalAmount, $number, 2),
'qty'=> $number,
]);
if (!$order->consignor) {//如果订单分配给公司,则直接确认
$this->confirmOrder($order);
}
return $order;
}
@ -136,17 +225,41 @@ class OrderService
*
* @return void
*/
public function payOrder(DealerOrder $order, ?string $payImage)
public function payOrder(DealerOrder $order, string $payWay, ?string $payImage)
{
if (empty($payWay)) {
throw new BizException('请选择付款方式');
}
if (!$order->isPendinged()) {
throw new BizException('订单状态异常,请刷新后再试');
}
$order->update([
'status' => DealerOrderStatus::Confirming,
'pay_image' => $payImage,
'pay_info' => $order->getConsignorPayInfo() ?? null,
'pay_time' => now(),
]);
switch ($payWay) {
case DealerOrder::PAY_WAY_WALLET:
/** 付款以及完成确认收款动作 **/
$walletService = new WalletService();
//付款
$walletService->changeBalance($order->user, 0 - $order->total_amount, DealerWalletAction::OrderPaid, '订单:'.$order->sn, $order);
$order->update([
'status'=>DealerOrderStatus::Confirming,
'pay_time' => now(),
'pay_way' => DealerOrder::PAY_WAY_WALLET,
]);
//收款
if ($order->consignor) {
$walletService->changeBalance($order->consignor, $order->total_amount, DealerWalletAction::OrderIncome, '订单:'.$order->sn, $order);
}
$this->paidOrder($order);
break;
case DealerOrder::PAY_WAY_OFFLINE:
$order->update([
'status' => DealerOrderStatus::Confirming,
'pay_image' => $payImage,
'pay_info' => $order->getConsignorPayInfo() ?? null,
'pay_time' => now(),
'pay_way' => DealerOrder::PAY_WAY_OFFLINE,
]);
break;
}
}
/**

View File

@ -819,14 +819,19 @@ class OrderService
* 确认订单
*
* @param \App\Models\Order $order
* @param bool $isSettlable
* @return void
*/
public function confirm(Order $order)
public function confirm(Order $order, $isSettlable = false)
{
if (! $order->isShipped()) {
throw new BizException('订单包裹未发完');
}
if ($isSettlable && $order->afterSales()->processing()->count() > 0) {
throw new BizException('订单商品售后中,不能完成此订单');
}
$orderPackageService = new OrderPackageService();
$order->loadMissing('packages');
@ -839,7 +844,11 @@ class OrderService
$orderPackageService->checkPackage($package, true);
}
$order->markAsCompleted();
$order->update([
'is_settlable' => $isSettlable,
'status' => Order::STATUS_COMPLETED,
'completed_at' => now(),
]);
}
/**

View File

@ -9,11 +9,6 @@ use Illuminate\Support\Arr;
class SettingService
{
/**
* @var array
*/
protected $items = [];
/**
* @var integer
*/
@ -40,19 +35,17 @@ class SettingService
$_key = $this->getSettingKey($key);
if (! array_key_exists($_key, $this->items)) {
try {
$this->items[$_key] = $this->cache->remember($this->cacheKey($_key), $this->ttl, function () use ($_key) {
$settings = Setting::where('key', $_key)->firstOrFail();
try {
$settings[$_key] = $this->cache->remember($this->cacheKey($_key), $this->ttl, function () use ($_key) {
$setting = Setting::where('key', $_key)->firstOrFail();
return $settings->value;
});
} catch (ModelNotFoundException $e) {
return $default;
}
return $setting->value;
});
} catch (ModelNotFoundException $e) {
return $default;
}
return Arr::get($this->items, $key, $default);
return Arr::get($settings, $key, $default);
}
/**
@ -110,7 +103,6 @@ class SettingService
public function cleanCache(string $key): void
{
$_key = $this->getSettingKey($key);
unset($this->items[$_key]);
$this->cache->forget($this->cacheKey($_key));
}

View File

@ -43,10 +43,23 @@ class SmsCodeService
throw new BizException(__('Invalid verification code type'));
}
if ($type === SmsCode::TYPE_REGISTER) {
if (User::where('phone', $phone)->exists()) {
throw new BizException(__('The phone number is already registered'));
}
$user = User::where('phone', $phone)->first();
switch ($type) {
case SmsCode::TYPE_REGISTER:
if ($user) {
throw new BizException(__('The phone number is already registered'));
}
break;
case SmsCode::TYPE_RESET_PASSWORD:
case SmsCode::TYPE_SET_WALLET_PASSWORD:
if ($user === null) {
throw new BizException('手机号未注册');
}
break;
}
if (! $this->cache->add("sms_lock_{$type}_{$phone}", 1, $decaySeconds)) {
@ -58,6 +71,7 @@ class SmsCodeService
'code' => $code,
'type' => $type,
'expires_at' => now()->addSeconds($this->expires),
'user_id' => $user->id,
]);
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPayWayToDealerOrdersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('dealer_orders', function (Blueprint $table) {
//
$table->string('pay_way')->nullable()->comment('1线下打款,2余额');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('dealer_orders', function (Blueprint $table) {
//
$table->dropColumn('pay_way');
});
}
}

View File

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateDealerShoppingCartItemsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('dealer_shopping_cart_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->comment('用户ID');
$table->unsignedBigInteger('product_id')->comment('商品ID');
$table->string('name')->comment('商品名称');
$table->string('cover')->nullable()->comment('封面图');
$table->unsignedDecimal('sell_price', 10, 2)->default(0.00)->comment('销售价格:元');
$table->unsignedDecimal('dealer_price', 10, 2)->default(0.00)->comment('经销商价格:元');
$table->unsignedInteger('quantity')->default(0)->comment('购买数量');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('dealer_shopping_cart_items');
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddHasRevokeToDealerUserProductLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('dealer_user_product_logs', function (Blueprint $table) {
//
$table->unsignedBigInteger('revoke_id')->default(0)->comment('撤销关联ID');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('dealer_user_product_logs', function (Blueprint $table) {
//
$table->dropColumn('revoke_id');
});
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsSettlableToOrdersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('orders', function (Blueprint $table) {
$table->boolean('is_settlable')->default(false)->comment('是否完成');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('orders', function (Blueprint $table) {
$table->dropColumn(['is_settlable']);
});
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class DelUserIdOrderIdProductIdUniqueIndexToDealerManageSubsidyLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('dealer_manage_subsidy_logs', function (Blueprint $table) {
$table->dropUnique(['user_id', 'order_id', 'product_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('dealer_manage_subsidy_logs', function (Blueprint $table) {
$table->unique(['user_id', 'order_id', 'product_id']);
});
}
}

View File

@ -130,6 +130,11 @@ class AdAddressSeeder extends Seeder
'dimensions'=> '213*246',
'is_show'=> true,
],
'merchant_top_navigation_banner'=>[
'name' =>'商户端首页顶部导航',
'dimensions'=> '58*58',
'is_show' =>true,
],
] as $key => $values) {
AdAddress::firstOrCreate(['key' => $key], $values);
}

View File

@ -190,6 +190,18 @@ class AppSettingSeeder extends Seeder
// 合约经销商升级金额
'upgrade_amount_'.DealerLvl::Contracted->value => '26400',
//单次下单最低金额
// 金牌经销商
'min_order_amount_'.DealerLvl::Gold->value => '1260',
// 特邀经销商
'min_order_amount_'.DealerLvl::Special->value => '1720',
// 签约约经销商
'min_order_amount_'.DealerLvl::Contracted->value => '2640',
// 二级签约约经销商
'min_order_amount_'.DealerLvl::Secondary->value => '2640',
// 一级签约约经销商
'min_order_amount_'.DealerLvl::Top->value => '2640',
// 渠道补贴规则
'channel_rules' => [
// 签约 -> 签约 ->签约

View File

@ -33,6 +33,7 @@ return [
'consignee_address' => '收货人详细地址',
'pay_info' => '收款信息',
'pay_image' => '打款凭证',
'pay_way'=>'支付方式',
'pay_time' => '支付时间',
'paied_time' => '确认收款时间',
'shipping_time' => '发货时间',

View File

@ -2,6 +2,7 @@
use App\Models\AfterSale;
use App\Models\Article;
use App\Models\DealerUserProductLog;
use App\Models\Order;
use App\Models\OrderProduct;
use App\Models\ProductSku;
@ -23,4 +24,5 @@ return [
AfterSale::class => '售后订单',
Article::class => '文章',
OrderPackage::class => '包裹',
DealerUserProductLog::class => '日志',
];