添加分区商品设置优惠券
parent
ffbbac4e18
commit
96937e6959
|
|
@ -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.' 赠券';
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
];
|
||||
}
|
||||
|
|
@ -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',
|
||||
];
|
||||
}
|
||||
|
|
@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,10 @@ return [
|
|||
'skus'=> '分区商品',
|
||||
'sku_id' => '商品名称',
|
||||
'sort' => '排序',
|
||||
'coupons'=>'赠券配置',
|
||||
'coupon_id' => '优惠券',
|
||||
'num'=>'数量',
|
||||
'description'=>'分区描述',
|
||||
],
|
||||
'options' => [
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue