From 2e6d09e8e0fd340ad3def31b39b65e405f6b4756 Mon Sep 17 00:00:00 2001 From: vine_liutk <961510893@qq.com> Date: Tue, 18 Jan 2022 18:01:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B5=84=E9=87=91=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/Dealer/OrderProcessCommand.php | 1 + app/Console/Commands/QuotaV1SendCommand.php | 40 ++++-- .../Controllers/Dealer/EarningController.php | 107 +++++++++++++++ .../Dealer/DealerEarningResource.php | 34 +++++ .../Dealer/DealerEarningSimpleResource.php | 27 ++++ app/Endpoint/Api/routes.php | 6 + app/Enums/DealerEarningStatus.php | 17 ++- app/Models/DealerEarning.php | 127 ++++++++++++++++++ app/Models/QuotaV1SendLog.php | 9 +- app/Models/User.php | 19 ++- ...add_pay_image_to_dealer_earnings_table.php | 34 +++++ ...1_18_143452_add_bonds_to_dealers_table.php | 34 +++++ resources/lang/zh_CN/dealer.php | 5 +- 13 files changed, 439 insertions(+), 21 deletions(-) create mode 100644 app/Endpoint/Api/Http/Controllers/Dealer/EarningController.php create mode 100644 app/Endpoint/Api/Http/Resources/Dealer/DealerEarningResource.php create mode 100644 app/Endpoint/Api/Http/Resources/Dealer/DealerEarningSimpleResource.php create mode 100644 database/migrations/2022_01_18_142430_add_pay_image_to_dealer_earnings_table.php create mode 100644 database/migrations/2022_01_18_143452_add_bonds_to_dealers_table.php diff --git a/app/Console/Commands/Dealer/OrderProcessCommand.php b/app/Console/Commands/Dealer/OrderProcessCommand.php index d8cd5db1..6725e0ca 100644 --- a/app/Console/Commands/Dealer/OrderProcessCommand.php +++ b/app/Console/Commands/Dealer/OrderProcessCommand.php @@ -479,6 +479,7 @@ class OrderProcessCommand extends Command return $dealer; } } + return null; } /** diff --git a/app/Console/Commands/QuotaV1SendCommand.php b/app/Console/Commands/QuotaV1SendCommand.php index af58be15..57f35a70 100644 --- a/app/Console/Commands/QuotaV1SendCommand.php +++ b/app/Console/Commands/QuotaV1SendCommand.php @@ -40,29 +40,43 @@ class QuotaV1SendCommand extends Command UserInfo::with('user')->where('quota_v1', '>', 0)->chunkById(100, function ($userInfos) use ($totalQuotaV1, $job) { $walletService = new WalletService(); //依次分红 + $nowTime = now(); + $logs = []; foreach ($userInfos as $userInfo) { // if ($userInfo->bonusable) {//只针对享受分红的人发放 $quotaV1amount = round(bcmul(bcdiv($job->amount, $totalQuotaV1, 5), $userInfo->quota_v1, 3)); if ($quotaV1amount >0) { - $log = new QuotaV1SendLog(); - $log->user_id = $userInfo->user_id; - $log->job_id = $job->id; - $log->amount = $quotaV1amount; - $log->save(); + // $log = new QuotaV1SendLog(); + // $log->user_id = $userInfo->user_id; + // $log->job_id = $job->id; + // $log->amount = $quotaV1amount; + // $log->save(); // try { - // DB::beginTransaction(); - // $log->update(['status'=>1]); - // $walletService->changeBalance($userInfo->user, $log->amount, WalletLog::ACTION_QUOTA_V1, '老配额分红', $log); - // DB::commit(); - // } catch (Throwable $th) { - // DB::rollBack(); - // report($th); - // } + // DB::beginTransaction(); + // $log->update(['status'=>1]); + // $walletService->changeBalance($userInfo->user, $log->amount, WalletLog::ACTION_QUOTA_V1, '老配额分红', $log); + // DB::commit(); + // } catch (Throwable $th) { + // DB::rollBack(); + // report($th); + // } + $_log = [ + 'user_id'=>$userInfo->user_id, + 'job_id' =>$job->id, + 'amount' =>$quotaV1amount, + 'created_at'=>$nowTime, + 'updated_at'=>$nowTime, + ]; + $logs[] = $_log; } // } } + if (count($logs) > 0) { + QuotaV1SendLog::insert($logs); + } }); } + $job->update([ 'status' => 2, ]); diff --git a/app/Endpoint/Api/Http/Controllers/Dealer/EarningController.php b/app/Endpoint/Api/Http/Controllers/Dealer/EarningController.php new file mode 100644 index 00000000..09168216 --- /dev/null +++ b/app/Endpoint/Api/Http/Controllers/Dealer/EarningController.php @@ -0,0 +1,107 @@ +input('cate', '');//获取订单类别 + $user = $request->user(); + switch ($cate) { + case 'pending':// + $query = $user->dealerEarnings()->onlyPending()->whereNotNull('settle_at'); + break; + case 'paid': + $query = $user->dealerPayEarnings()->onlyPaid()->whereNotNull('settle_at'); + break; + default://全部 + $query = DealerEarning::where(function ($q) use ($user) { + return $q->where('user_id', $user->id)->orWhere('payer_id', $user->id); + }); + break; + } + + $earnings = $query->latest('id')->simplePaginate(Paginator::resolvePerPage('per_page', 20, 50)); + return DealerEarningSimpleResource::collection($earnings); + } + + /** + * 详情 + * + * @param [type] $id + * @param Request $request + * @return void + */ + public function show($id, Request $request) + { + $earning = $request->user()->dealerEarnings()->findOrFail($id); + return DealerEarningResource::make($earning); + } + + /** + * 确认打款 + * + * @param [type] $id + * @param Request $request + * @return void + */ + public function payEarning($id, Request $request) + { + $earning = DealerEarning::findOrFail($id); + + if (!$earning->isPayer($request->user()->id)) { + throw new BizException('无法操作该订单'); + } + + $input = $request->validate([ + 'pay_image' => ['bail', 'required', 'string'], + ]); + if ($earning->isPending()) { + $earning->update([ + 'status' => DealerEarningStatus::Paid, + 'pay_info' => $earning->getPayInfo(), + 'pay_image'=> $input['pay_image'], + 'pay_at' => now(), + ]); + } + return response()->noContent(); + } + + /** + * 确认收款 + * + * @param [type] $id + * @param Request $request + */ + public function confirmEarning($id, Request $request) + { + $earning = DealerEarning::findOrFail($id); + + if (!$earning->isUser($request->user()->id)) { + throw new BizException('无法操作该订单'); + } + + if ($earning->isPaid()) { + $earning->update([ + 'status' => DealerEarningStatus::Completed, + ]); + } + return response()->noContent(); + } +} diff --git a/app/Endpoint/Api/Http/Resources/Dealer/DealerEarningResource.php b/app/Endpoint/Api/Http/Resources/Dealer/DealerEarningResource.php new file mode 100644 index 00000000..31469c46 --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/Dealer/DealerEarningResource.php @@ -0,0 +1,34 @@ + $this->id, + 'type' => $this->type_name, + 'created_at' => $this->created_at->toDateTimeString(), + 'total_amount' => $this->total_amount, + 'fee_rate' => $this->fee_rate, + 'fee' => $this->fee, + 'total_earnings'=> $this->total_earnings, + 'status' => $this->status, + 'status_name' => $this->status_name, + 'remark' => $this->remark, + 'pay_info' => $this->getPayInfo(), + 'pay_image' => $this->pay_image, + 'pay_at' => $this->pay_at?->toDateTimeString(), + 'is_payer' => $this->payer_id ? ($this->payer_id == $request->user()->id) : false, + ]; + } +} diff --git a/app/Endpoint/Api/Http/Resources/Dealer/DealerEarningSimpleResource.php b/app/Endpoint/Api/Http/Resources/Dealer/DealerEarningSimpleResource.php new file mode 100644 index 00000000..57fe6945 --- /dev/null +++ b/app/Endpoint/Api/Http/Resources/Dealer/DealerEarningSimpleResource.php @@ -0,0 +1,27 @@ + $this->id, + 'type' => $this->type_name, + 'created_at' => $this->created_at->toDateTimeString(), + 'total_earnings'=> $this->total_earnings, + 'status' => $this->status, + 'status_name' => $this->status_name, + // 'settle_at' + ]; + } +} diff --git a/app/Endpoint/Api/routes.php b/app/Endpoint/Api/routes.php index bdca4fc0..904f1570 100644 --- a/app/Endpoint/Api/routes.php +++ b/app/Endpoint/Api/routes.php @@ -250,5 +250,11 @@ Route::group([ Route::post('orders/{order}/shippinged', [Dealer\OrderController::class, 'shippingedOrder']); //取消订单 Route::post('orders/{order}/cancel', [Dealer\OrderController::class, 'cancelOrder']); + + //资金列表 + Route::get('earnings', [Dealer\EarningController::class, 'index']); + Route::get('earnings/{earning}', [Dealer\EarningController::class, 'show']); + Route::post('earnings/{earning}/pay', [Dealer\EarningController::class, 'payEarning']); + Route::post('earnings/{earning}/confirm', [Dealer\EarningController::class, 'confirmEarning']); }); }); diff --git a/app/Enums/DealerEarningStatus.php b/app/Enums/DealerEarningStatus.php index 51e9e0be..8a0e722f 100644 --- a/app/Enums/DealerEarningStatus.php +++ b/app/Enums/DealerEarningStatus.php @@ -3,6 +3,19 @@ namespace App\Enums; enum DealerEarningStatus: int { - case Pending = 0; - case Completed = 5; + case Pending = 0;//待打款 + case Paid = 1;//已打款 + case Completed = 5;//已完成 + + /** + * @return string + */ + public function text() + { + return match ($this) { + static::Pending => '待打款', + static::Paid => '待收款', + static::Completed => '已完成', + }; + } } diff --git a/app/Models/DealerEarning.php b/app/Models/DealerEarning.php index 7575ef65..97d95562 100644 --- a/app/Models/DealerEarning.php +++ b/app/Models/DealerEarning.php @@ -2,12 +2,18 @@ namespace App\Models; +use App\Casts\JsonArray; use App\Enums\DealerEarningStatus; use App\Enums\DealerLvl; +use Dcat\Admin\Traits\HasDateTimeFormatter; +use EloquentFilter\Filterable; use Illuminate\Database\Eloquent\Model; class DealerEarning extends Model { + use HasDateTimeFormatter; + use Filterable; + protected $attributes = [ 'status' => DealerEarningStatus::Pending, ]; @@ -16,6 +22,9 @@ class DealerEarning extends Model 'lvl' => DealerLvl::class, 'is_manager'=> 'bool', 'status' => DealerEarningStatus::class, + 'pay_at' => 'datetime', + 'settle_at'=> 'datetime', + 'pay_info' => JsonArray::class, ]; protected $fillable = [ @@ -30,9 +39,127 @@ class DealerEarning extends Model 'fee_rate', 'payer_id', 'pay_info', + 'pay_image', 'pay_at', 'settle_at', 'status', 'remark', ]; + + public function user() + { + return $this->belongsTo(User::class, 'user_id'); + } + + public function payer() + { + return $this->belongsTo(User::class, 'payer_id'); + } + + /** + * 待打款 + * + * @param [type] $query + */ + public function scopeOnlyPending($query) + { + return $query->where('status', DealerEarningStatus::Pending); + } + + /** + * 待收款 + * + * @param [type] $query + */ + public function scopeOnlyPaid($query) + { + return $query->where('status', DealerEarningStatus::Paid); + } + + /** + * 待打款状态 + * + * @return boolean + */ + public function isPending() + { + return $this->status == DealerEarningStatus::Pending; + } + + /** + * 待收款 + * + * @return boolean + */ + public function isPaid() + { + return $this->status == DealerEarningStatus::Paid; + } + + /** + * 是否自己的 + * + * @param [type] $userId + * @return boolean + */ + public function isUser($userId) + { + return $this->user_id == $userId; + } + + /** + * 是否是支付人 + * + * @param [type] $userId + * @return boolean + */ + public function isPayer($userId) + { + return $this->payer_id ? ($this->payer_id == $userId) : false; + } + + public function getStatusNameAttribute() + { + if ($this->settle_at) { + return $this->status::text(); + } else { + return '待结算'; + } + } + + public function getTypeNameAttribute() + { + $name = '未知'; + switch ($this->attributes['earningable_type']) { + case (new DealerManagerSubsidy())->getMorphClass(): + $name = '管理者津贴'; + break; + case (new DealerManageSubsidy())->getMorphClass(): + $name = '管理津贴'; + break; + case (new DealerChannelSubsidyLog())->getMorphClass(): + $name = '渠道补贴'; + break; + default: + $name = '进货补贴'; + break; + } + + return $name; + } + + /** + * 获取用户的打款信息 + * + * @return void + */ + public function getPayInfo() + { + if ($this->isPending()) {//待打款订单显示发货人收款信息 + $payInfo = $this->user->dealer->pay_info; + } else { + $payInfo = $this->pay_info; + } + return $payInfo ?: null; + } } diff --git a/app/Models/QuotaV1SendLog.php b/app/Models/QuotaV1SendLog.php index 3c4f0044..7dcaf9a7 100644 --- a/app/Models/QuotaV1SendLog.php +++ b/app/Models/QuotaV1SendLog.php @@ -15,11 +15,16 @@ class QuotaV1SendLog extends Model public const STATUS_SUCCESS = 1; protected $attributes = [ - 'status'=>0, + 'status'=>self::STATUS_FAILED, ]; protected $fillable = [ + 'user_id', + 'job_id', + 'amount', 'status', + 'created_at', + 'updated_at', ]; public static $statusText = [ @@ -41,7 +46,7 @@ class QuotaV1SendLog extends Model { $query->where('status', static::STATUS_FAILED); - if ($hours = app_settings('quota_v1_receive', 0)) { + if ($hours = app_settings('distribution.quota_v1_receive', 0)) { return $query->where('created_at', '>', now()->subHours($hours)); } else { return $query; diff --git a/app/Models/User.php b/app/Models/User.php index 1a645136..e3c0e6f1 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -199,13 +199,28 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac } /** - * todo-确认这个用户是否是经销商 + * 确认这个用户是否是经销商 * * @return boolean */ public function isDealer(): bool { - return true; + return $this->dealer ? true : false; + } + + /** + * 用户收益记录 + * + * @return void + */ + public function dealerEarnings() + { + return $this->hasMany(DealerEarning::class, 'user_id'); + } + + public function dealerPayEarnings() + { + return $this->hasMany(DealerEarning::class, 'payer_id'); } /** diff --git a/database/migrations/2022_01_18_142430_add_pay_image_to_dealer_earnings_table.php b/database/migrations/2022_01_18_142430_add_pay_image_to_dealer_earnings_table.php new file mode 100644 index 00000000..8a371851 --- /dev/null +++ b/database/migrations/2022_01_18_142430_add_pay_image_to_dealer_earnings_table.php @@ -0,0 +1,34 @@ +string('pay_image')->nullable()->comment('打款凭证'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('dealer_earnings', function (Blueprint $table) { + // + $table->dropColumn('pay_image'); + }); + } +} diff --git a/database/migrations/2022_01_18_143452_add_bonds_to_dealers_table.php b/database/migrations/2022_01_18_143452_add_bonds_to_dealers_table.php new file mode 100644 index 00000000..65b521d1 --- /dev/null +++ b/database/migrations/2022_01_18_143452_add_bonds_to_dealers_table.php @@ -0,0 +1,34 @@ +unsignedDecimal('bonds')->default(0.00)->comment('已缴纳保证金'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('dealers', function (Blueprint $table) { + // + $table->dropColumn('bonds'); + }); + } +} diff --git a/resources/lang/zh_CN/dealer.php b/resources/lang/zh_CN/dealer.php index 6ca45485..d77c03b1 100644 --- a/resources/lang/zh_CN/dealer.php +++ b/resources/lang/zh_CN/dealer.php @@ -2,8 +2,8 @@ return [ 'labels' => [ - 'Dealer' => 'Dealer', - 'dealer' => 'Dealer', + 'Dealer' => '经销商管理', + 'dealers' => '经销商管理', ], 'fields' => [ 'user_id' => '用户ID', @@ -26,6 +26,7 @@ return [ 'is_sale' => '是否可销售', 'is_manager' => '是否是管理者', 'pay_info' => '用户保留的收款信息', + 'bonds' => '保证金', ], 'options' => [ ],