6
0
Fork 0

添加分区商品设置优惠券

release
vine_liutk 2021-12-23 13:16:42 +08:00
parent ffbbac4e18
commit 96937e6959
14 changed files with 418 additions and 21 deletions

View File

@ -0,0 +1,44 @@
<?php
namespace App\Admin\Actions\Grid;
use App\Admin\Forms\PartCoupon as PartCouponForm;
use Dcat\Admin\Grid\RowAction;
use Dcat\Admin\Widgets\Modal;
class PartCoupon extends RowAction
{
/**
* @return string
*/
protected $title = '<i class="feather icon-list grid-action-icon"></i>';
public function title()
{
if ($this->title) {
return $this->title.'&nbsp;赠券';
}
return '赠券';
}
/**
* @param Model|Authenticatable|HasPermissions|null $user
*
* @return bool
*/
protected function authorize($user): bool
{
return $user->can('dcat.admin.product_parts.coupons');
}
public function render()
{
$form = PartCouponForm::make()->payload(['id'=>$this->getKey()]);
return Modal::make()
->lg()
->title($this->title())
->body($form)
->button($this->title());
}
}

View File

@ -52,7 +52,7 @@ class AfterSaleFinanceShipping extends AbstractTool
try {
DB::beginTransaction();
$afterSale = AfterSale::where('state', AfterSale::STATE_FINANCE)->findOrFail($key);
$afterSaleService->finance($afterSale);
$afterSaleService->finance($afterSale, '同意换货');
DB::commit();
} catch (Throwable $th) {
DB::rollBack();

View File

@ -2,6 +2,7 @@
namespace App\Admin\Controllers;
use App\Admin\Actions\Grid\PartCoupon;
use App\Admin\Renderable\ProductPartSkuTable;
use App\Admin\Renderable\ProductSkuSimpleTable;
use App\Admin\Repositories\ProductPart;
@ -60,6 +61,9 @@ class ProductPartController extends AdminController
//删除以及自定义操作
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableDelete(Admin::user()->cannot('dcat.admin.product_parts.destroy'));
if (Admin::user()->can('dcat.admin.product_parts.coupons')) {
$actions->append(new PartCoupon());
}
});
/** 查询 **/
@ -128,6 +132,7 @@ class ProductPartController extends AdminController
$form->switch('is_show')->default(0);
$form->textarea('description');
$form->display('created_at');
$form->display('updated_at');

View File

@ -0,0 +1,97 @@
<?php
namespace App\Admin\Forms;
use App\Models\Coupon;
use App\Models\ProductPart;
use App\Models\ProductPartCoupon;
use Dcat\Admin\Contracts\LazyRenderable;
use Dcat\Admin\Form\NestedForm;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;
use Illuminate\Support\Facades\DB;
use Throwable;
class PartCoupon extends Form implements LazyRenderable
{
use LazyWidget;
/**
* @param Model|Authenticatable|HasPermissions|null $user
*
* @return bool
*/
protected function authorize($user): bool
{
return $user->can('dcat.admin.product_parts.coupons');
}
/**
* Handle the form request.
*
* @param array $input
*
* @return mixed
*/
public function handle(array $input)
{
$couponIds = [];
$coupons = [];
$delCouponIds = [];
foreach ($input['coupons'] as $coupon) {
if ($coupon['_remove_'] == 1) {
$delCouponIds[] = $coupon['id'];
} else {
if (is_null($coupon['id'])) {
$coupons[] = new ProductPartCoupon($coupon);
} else {
$_coupon = ProductPartCoupon::find($coupon['id']);
$_coupon->coupon_id = $coupon['coupon_id'];
$_coupon->num = $coupon['num'];
$coupons[] = $_coupon;
}
}
}
$partId = $input['part_id'];
$part = ProductPart::findOrFail($partId);
try {
DB::beginTransaction();
$part->coupons()->saveMany($coupons);
ProductPartCoupon::whereIn('id', $delCouponIds)->delete();
DB::commit();
} catch (Throwable $th) {
DB::rollBack();
report($th);
return $this->response()->error('操作失败:'.$th->getMessage())->refresh();
}
return $this->response()
->success(__('admin.update_succeeded'))
->refresh();
}
/**
* Build a form here.
*/
public function form()
{
$id = $this->payload['id'] ?? 0;
$part = ProductPart::with('coupons')->findOrFail($id);
$this->hasMany('coupons', function (NestedForm $form) {
$form->select('coupon_id')->options(function ($id) {
$coupon = Coupon::find($id);
if ($coupon) {
return [$coupon->id => $coupon->name];
}
})->ajax(admin_route('api.coupons'))->required();
$form->number('num')->min(1)->default(1);
})->customFormat(function () use ($part) {
return $part->coupons;
});
$this->hidden('part_id')->value($id);
}
}

View File

@ -6,6 +6,7 @@ use App\Models\Coupon;
use App\Models\CouponSendTask;
use App\Models\CouponTaskLog;
use App\Models\UserCoupon;
use App\Services\CouponService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Throwable;
@ -53,7 +54,6 @@ class AdminSendCoupon extends Command
$logs = CouponTaskLog::where('status', '0')->where('num', '>', 0)->orderBy('id')->limit($this->limit)->get();
$logs = $logs->groupBy('task_id');
foreach ($logs as $taskId => $taskLogs) {
$nowTime = now();
$task = CouponSendTask::find($taskId);
$coupon = Coupon::find($task->coupon_id);
//如果优惠券限量,则获取优惠券余量,只发送前面的人;
@ -62,30 +62,12 @@ class AdminSendCoupon extends Command
$failedLogs = $taskLogs->slice($coupon->stock);
$taskLogs = $taskLogs->slice(0, $coupon->stock);
}
if ($coupon->use_start_at && $coupon->use_end_at) {
$useStartAt = $coupon->use_start_at;
$useEndAt = $coupon->use_end_at;
} else {
$useStartAt = now();
$useEndAt = now()->addDays($coupon->use_day);
}
//批量插入用户优惠券
$insertUserCoupons = [];
foreach ($taskLogs as $taskLog) {
for ($i=0; $i< $taskLog->num; $i++) {
$insertUserCoupons[] = [
'user_id' => $taskLog->user_id,
'coupon_id' => $taskLog->coupon_id,
'coupon_name' => $coupon->name,
'coupon_type' => $coupon->type,
'coupon_amount' => (int) bcmul($coupon->amount, 100),
'coupon_threshold'=> (int) bcmul($coupon->threshold, 100),
'use_start_at' => $useStartAt,
'use_end_at' => $useEndAt,
'created_at' => $nowTime,
'updated_at' => $nowTime,
];
$insertUserCoupons[] = CouponService::createUserCouponData($taskLog->user_id, $coupon);
}
}
try {

View File

@ -52,4 +52,12 @@ class ProductPart extends Model
{
return $this->belongsToMany(ProductSku::class, ProductPartSku::class, 'part_id', 'sku_id')->withTimestamps();
}
/**
* 此分区购买赠送的券
*/
public function coupons()
{
return $this->hasMany(ProductPartCoupon::class, 'part_id');
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ProductPartCoupon extends Model
{
use HasFactory;
protected $fillable = [
'part_id', 'coupon_id', 'num',
];
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ReceivePartCouponLog extends Model
{
use HasFactory;
protected $fillable = [
'user_id', 'part_id',
];
}

View File

@ -2,7 +2,11 @@
namespace App\Services;
use App\Models\Coupon;
use App\Models\ProductPart;
use App\Models\ReceivePartCouponLog;
use App\Models\User;
use App\Models\UserCoupon;
class CouponService
{
@ -50,4 +54,96 @@ class CouponService
return $availableCoupons;
}
/**
* 根据分区,领取优惠券
*/
public function receivePartCoupon(ProductPart $part, User $user)
{
//如果分区不显示,直接退出;
if (!$part->is_show) {
return;
}
//如果用户已领取过该分区设置的券,直接退出;
if (ReceivePartCouponLog::where(['user_id'=>$user->id, 'part_id'=>$part->id])->exists()) {
return;
}
//取出需要发放的券
$coupons = Coupon::whereIn('id', $part->coupons->pluck('coupon_id')->toArray())->get();
$coupons = $coupons->keyBy('id');
$someCoupons = [];
foreach ($part->coupons as $coupon) {
$someCoupons[] = [
'coupon'=>$coupons[$coupon->coupon_id],
'num'=>$coupon->num,
];
}
$this->receiveSomeCoupons($user, $someCoupons);
ReceivePartCouponLog::create(['user_id'=>$user->id, 'part_id'=>$part->id]);
}
/**
* 领取一批券
*
* @param User $user
* @param array $coupons
* @return void
*/
protected function receiveSomeCoupons(User $user, array $coupons)
{
$userCoupons = [];
foreach ($coupons as $coupon) {
for ($i=0; $i<$coupon['num']; $i++) {
$userCoupons[] = self::createUserCouponData($user->id, $coupon['coupon']);
}
}
UserCoupon::insert($userCoupons);
}
/**
* todo-领取指定券
*
* @param User $user
* @param Coupon $coupon
* @param int $num
* @return void
*/
public function receiveCoupon(User $user, Coupon $coupon, int $num = 1)
{
return;
}
/**
* 创建用户券数据
*
* @return array
*/
public static function createUserCouponData(int $userId, Coupon $coupon)
{
//如果userId小于等于0直接退出
if ($userId <= 0) {
return [];
}
if ($coupon->use_start_at && $coupon->use_end_at) {
$useStartAt = $coupon->use_start_at;
$useEndAt = $coupon->use_end_at;
} else {
$useStartAt = now();
$useEndAt = now()->addDays($coupon->use_day);
}
return [
'user_id' => $userId,
'coupon_id' => $coupon->id,
'coupon_name' => $coupon->name,
'coupon_type' => $coupon->type,
'coupon_amount' => (int) bcmul($coupon->amount, 100),
'coupon_threshold'=> (int) bcmul($coupon->threshold, 100),
'use_start_at' => $useStartAt,
'use_end_at' => $useEndAt,
'created_at' => now(),
'updated_at' => now(),
];
}
}

View File

@ -742,6 +742,9 @@ class OrderService
'status' => Order::STATUS_PAID,
]);
// todo 处理购买分区商品送券
$this->sendPartCoupon($order);
// todo 处理预收益
return $order;
@ -826,4 +829,31 @@ class OrderService
'status' => Order::STATUS_CANCELLED,
]);
}
/**
* 发送分区优惠券
*
* @param Order $order
* @return void
*/
protected function sendPartCoupon(Order $order)
{
$products = $order->products()->with('sku.parts')->get();
// 整理订单商品的分区
$inValidParts = [];
foreach ($products->pluck('sku.parts') as $parts) {
foreach ($parts as $part) {
if ($part->is_show) {
// 分区去重
$inValidParts[$part->id] = $part;
}
}
}
// 将有效的分区丢进去领券
$couponService = new CouponService();
foreach ($inValidParts as $inValidPart) {
$couponService->receivePartCoupon($inValidPart, $order->user);
}
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductPartCouponsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('product_part_coupons', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('part_id')->comment('分区ID');
$table->unsignedBigInteger('coupon_id')->comment('券ID');
$table->unsignedInteger('num')->default(0)->comment('张数');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('product_part_coupons');
}
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateReceivePartCouponLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('receive_part_coupon_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->comment('用户ID');
$table->unsignedBigInteger('part_id')->comment('分区ID');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('receive_part_coupon_logs');
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddDescriptionToProductPartsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('product_parts', function (Blueprint $table) {
//
$table->text('description')->nullable()->comment('分区描述');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('product_parts', function (Blueprint $table) {
//
$table->dropColumn('description');
});
}
}

View File

@ -13,6 +13,10 @@ return [
'skus'=> '分区商品',
'sku_id' => '商品名称',
'sort' => '排序',
'coupons'=>'赠券配置',
'coupon_id' => '优惠券',
'num'=>'数量',
'description'=>'分区描述',
],
'options' => [
],