线下订单 增加备注
parent
2de5eb7e43
commit
141639ab84
|
|
@ -89,6 +89,8 @@ class OfflineOrderController extends AdminController
|
||||||
$grid->column('status')->display(fn($v) => $v->dot());
|
$grid->column('status')->display(fn($v) => $v->dot());
|
||||||
$grid->column('payment_method')->display(fn($v) => $v?->dot());
|
$grid->column('payment_method')->display(fn($v) => $v?->dot());
|
||||||
$grid->column('payment_time');
|
$grid->column('payment_time');
|
||||||
|
$grid->column('user_remark');
|
||||||
|
$grid->column('staff_remark');
|
||||||
$grid->column('created_at');
|
$grid->column('created_at');
|
||||||
|
|
||||||
$grid->filter(function (Grid\Filter $filter) {
|
$grid->filter(function (Grid\Filter $filter) {
|
||||||
|
|
@ -207,6 +209,8 @@ class OfflineOrderController extends AdminController
|
||||||
$show->field('out_trade_no');
|
$show->field('out_trade_no');
|
||||||
$show->field('created_at');
|
$show->field('created_at');
|
||||||
$show->field('revoked_at');
|
$show->field('revoked_at');
|
||||||
|
$show->field('user_remark');
|
||||||
|
$show->field('staff_remark');
|
||||||
});
|
});
|
||||||
$show->panel()->tools(function (Show\Tools $tools) use ($show) {
|
$show->panel()->tools(function (Show\Tools $tools) use ($show) {
|
||||||
$tools->disableEdit();
|
$tools->disableEdit();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use App\Models\OrderProduct;
|
||||||
use App\Models\PointLog;
|
use App\Models\PointLog;
|
||||||
use App\Models\UserInfo;
|
use App\Models\UserInfo;
|
||||||
use App\Models\UserVip;
|
use App\Models\UserVip;
|
||||||
|
use App\Models\Store\Store;
|
||||||
use Dcat\Admin\Admin;
|
use Dcat\Admin\Admin;
|
||||||
use Dcat\Admin\Grid;
|
use Dcat\Admin\Grid;
|
||||||
use Dcat\Admin\Http\Controllers\AdminController;
|
use Dcat\Admin\Http\Controllers\AdminController;
|
||||||
|
|
@ -33,12 +34,13 @@ class PointLogController extends AdminController
|
||||||
CSS
|
CSS
|
||||||
);
|
);
|
||||||
|
|
||||||
$builder = PointLogRepository::with(['user', 'administrator']);
|
$builder = PointLogRepository::with(['user', 'administrator', 'store']);
|
||||||
|
|
||||||
return Grid::make($builder, function (Grid $grid) {
|
return Grid::make($builder, function (Grid $grid) {
|
||||||
|
|
||||||
$grid->export()->titles([
|
$grid->export()->titles([
|
||||||
'id' => 'ID',
|
'id' => 'ID',
|
||||||
|
'store_id' => __('point-log.fields.store_id'),
|
||||||
'username' => '用户昵称',
|
'username' => '用户昵称',
|
||||||
'user_id' => __('point-log.fields.user.phone'),
|
'user_id' => __('point-log.fields.user.phone'),
|
||||||
'first_rechare_time' => '首次充值时间',
|
'first_rechare_time' => '首次充值时间',
|
||||||
|
|
@ -65,6 +67,7 @@ class PointLogController extends AdminController
|
||||||
$vipCount = $userVips->count();
|
$vipCount = $userVips->count();
|
||||||
|
|
||||||
$row['user_id'] = data_get($row, 'user.phone');
|
$row['user_id'] = data_get($row, 'user.phone');
|
||||||
|
$row['store_id'] = data_get($row, 'store.title');
|
||||||
$row['username'] = data_get($userInfo, 'nickname');
|
$row['username'] = data_get($userInfo, 'nickname');
|
||||||
|
|
||||||
$row['first_rechare_time'] = $firstVip ? $firstVip->success_time->format('Y-m-d H:i:s') : '';
|
$row['first_rechare_time'] = $firstVip ? $firstVip->success_time->format('Y-m-d H:i:s') : '';
|
||||||
|
|
@ -108,6 +111,7 @@ class PointLogController extends AdminController
|
||||||
$grid->model()->orderBy('id', 'desc');
|
$grid->model()->orderBy('id', 'desc');
|
||||||
|
|
||||||
$grid->column('id')->sortable();
|
$grid->column('id')->sortable();
|
||||||
|
$grid->column('store.title', __('point-log.fields.store_id'));
|
||||||
$grid->column('user.phone')->copyable();
|
$grid->column('user.phone')->copyable();
|
||||||
$grid->column('action')->display(fn ($action) => $action->label())->label();
|
$grid->column('action')->display(fn ($action) => $action->label())->label();
|
||||||
$grid->column('change_points')->display(function ($value) {
|
$grid->column('change_points')->display(function ($value) {
|
||||||
|
|
@ -144,7 +148,9 @@ class PointLogController extends AdminController
|
||||||
});
|
});
|
||||||
|
|
||||||
$grid->filter(function (Grid\Filter $filter) {
|
$grid->filter(function (Grid\Filter $filter) {
|
||||||
|
$stores = Store::pluck('title', 'id')->all();
|
||||||
$filter->panel(false);
|
$filter->panel(false);
|
||||||
|
$filter->equal('store_id', __('point-log.fields.store_id'))->select($stores)->width(3);
|
||||||
$filter->equal('user.phone')->width(3);
|
$filter->equal('user.phone')->width(3);
|
||||||
$filter->like('administrator.name', '操作人')->width(3);
|
$filter->like('administrator.name', '操作人')->width(3);
|
||||||
$filter->in('action')->multipleSelect(PointLogAction::options())->width(3);
|
$filter->in('action')->multipleSelect(PointLogAction::options())->width(3);
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class OrderController extends AdminController
|
||||||
$grid->column('sn')->copyable();
|
$grid->column('sn')->copyable();
|
||||||
$grid->column('user_id')->display(function () {
|
$grid->column('user_id')->display(function () {
|
||||||
$nickname = $this->userInfo?->nickname ?? '---';
|
$nickname = $this->userInfo?->nickname ?? '---';
|
||||||
$avatar = $this->userInfo?->avatar ?? 'https://via.placeholder.com/45x45.png';
|
$avatar = $this->userInfo?->avatar ?? asset('images/avatar.jpeg');
|
||||||
$phone = $this->user?->phone;
|
$phone = $this->user?->phone;
|
||||||
return <<<HTML
|
return <<<HTML
|
||||||
<img src="{$avatar}" width="45" />
|
<img src="{$avatar}" width="45" />
|
||||||
|
|
@ -59,7 +59,7 @@ class OrderController extends AdminController
|
||||||
});
|
});
|
||||||
$grid->column('inviter_id')->display(function () {
|
$grid->column('inviter_id')->display(function () {
|
||||||
$nickname = $this->inviterInfo?->nickname ?? '---';
|
$nickname = $this->inviterInfo?->nickname ?? '---';
|
||||||
$avatar = $this->inviterInfo?->avatar ?? 'https://via.placeholder.com/45x45.png';
|
$avatar = $this->inviterInfo?->avatar ?? asset('images/avatar.jpeg');
|
||||||
$phone = $this->inviter?->phone;
|
$phone = $this->inviter?->phone;
|
||||||
return <<<HTML
|
return <<<HTML
|
||||||
<img src="{$avatar}" width="45" />
|
<img src="{$avatar}" width="45" />
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Admin\Controllers;
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
use App\Models\{UserVip, Vip};
|
use App\Models\{UserVip, Vip};
|
||||||
|
use App\Models\Store\Store;
|
||||||
use Dcat\Admin\Form;
|
use Dcat\Admin\Form;
|
||||||
use Dcat\Admin\Grid;
|
use Dcat\Admin\Grid;
|
||||||
use Dcat\Admin\Http\Controllers\AdminController;
|
use Dcat\Admin\Http\Controllers\AdminController;
|
||||||
|
|
@ -17,11 +18,12 @@ class UserVipController extends AdminController
|
||||||
*/
|
*/
|
||||||
protected function grid()
|
protected function grid()
|
||||||
{
|
{
|
||||||
return Grid::make(UserVip::with(['user']), function (Grid $grid) {
|
return Grid::make(UserVip::with(['user', 'store']), function (Grid $grid) {
|
||||||
|
|
||||||
$grid->model()->where('status', UserVip::STATUS_SUCCESS)->latest('created_at');
|
$grid->model()->where('status', UserVip::STATUS_SUCCESS)->latest('created_at');
|
||||||
|
|
||||||
$grid->column('user.phone');
|
$grid->column('user.phone');
|
||||||
|
$grid->column('store.title');
|
||||||
$grid->column('name');
|
$grid->column('name');
|
||||||
$grid->column('times')->display(function ($v) {
|
$grid->column('times')->display(function ($v) {
|
||||||
return data_get($v, 'text');
|
return data_get($v, 'text');
|
||||||
|
|
@ -34,7 +36,9 @@ class UserVipController extends AdminController
|
||||||
$grid->disableViewButton(false);
|
$grid->disableViewButton(false);
|
||||||
|
|
||||||
$grid->filter(function (Grid\Filter $filter) {
|
$grid->filter(function (Grid\Filter $filter) {
|
||||||
|
$stores = Store::pluck('title', 'id')->all();
|
||||||
$filter->panel(false);
|
$filter->panel(false);
|
||||||
|
$filter->equal('store_id', __('user-vip.fields.store.title'))->select($stores)->width(3);
|
||||||
$filter->like('user.phone')->width(3);
|
$filter->like('user.phone')->width(3);
|
||||||
$filter->like('name')->width(3);
|
$filter->like('name')->width(3);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ class PointChange extends Form implements LazyRenderable
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
|
|
||||||
(new PointService())->change($user, $changePoints, $action, $input['remark'], null, Admin::user());
|
(new PointService())->change($user, $changePoints, $action, [
|
||||||
|
'remark' => $input['remark'],
|
||||||
|
'administrator' => Admin::user()
|
||||||
|
]);
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
} catch (Throwable $th) {
|
} catch (Throwable $th) {
|
||||||
|
|
|
||||||
|
|
@ -38,44 +38,21 @@ class MiniprogramController extends Controller
|
||||||
$time = now();
|
$time = now();
|
||||||
$ip = $request->realIp();
|
$ip = $request->realIp();
|
||||||
|
|
||||||
$inviter = null;
|
|
||||||
if ($request->filled('invite_code')) {
|
|
||||||
$inviter = $this->findUserByCode($request->input('invite_code', ''));
|
|
||||||
if (!$inviter) {
|
|
||||||
throw new BizException('邀请人不存在');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
|
|
||||||
$user_social = SocialiteUser::where(['socialite_id' => $openid, 'socialite_type' => $type])->first();
|
$user_social = SocialiteUser::firstOrCreate(['socialite_id' => $openid, 'socialite_type' => $type]);
|
||||||
|
$user = $user_social->user;
|
||||||
if (!$user_social) {
|
$token = '';
|
||||||
$attributes = [
|
if ($user) {
|
||||||
'register_ip' => $ip,
|
$token = $user->createToken($type)->plainTextToken;
|
||||||
'last_login_at' => $time,
|
|
||||||
'last_login_ip' => $ip,
|
|
||||||
];
|
|
||||||
$user = User::create($attributes, $inviter);
|
|
||||||
$user->socialites()->create([
|
|
||||||
'socialite_id' => $openid,
|
|
||||||
'socialite_type' => $type,
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
$user = $user_social->user;
|
|
||||||
}
|
}
|
||||||
if (!$user) {
|
|
||||||
throw new BizException($openid);
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = $user->createToken($type);
|
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'openid' => $openid,
|
'openid' => $openid,
|
||||||
'token' => $token->plainTextToken
|
'token' => $token
|
||||||
]);
|
]);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
|
|
@ -89,7 +66,6 @@ class MiniprogramController extends Controller
|
||||||
|
|
||||||
public function bindPhone(Request $request)
|
public function bindPhone(Request $request)
|
||||||
{
|
{
|
||||||
$user = $request->user();
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'code' => 'required'
|
'code' => 'required'
|
||||||
], [
|
], [
|
||||||
|
|
@ -105,19 +81,26 @@ class MiniprogramController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$phone = data_get($result, 'phone_info.purePhoneNumber');
|
$phone = data_get($result, 'phone_info.purePhoneNumber');
|
||||||
|
$openid = $request->input('openid');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
// 检测手机号是否已经注册
|
$user = User::where('phone', $phone)->first();
|
||||||
$old_user = User::where('phone', $phone)->where('status', User::STATUS_ACTIVE)->where('id', '!=', $user->id)->first();
|
if (!$user) {
|
||||||
if ($old_user) {
|
$time = now();
|
||||||
// 禁用新用户
|
$ip = $request->realIp();
|
||||||
throw new BizException('手机号已经注册');
|
$inviter = $this->findUserByCode($request->input('invite_code', ''));
|
||||||
} else {
|
$user = User::create([
|
||||||
$user->update([
|
'register_ip' => $ip,
|
||||||
'phone' => $phone,
|
'last_login_at' => $time,
|
||||||
'phone_verified_at' => now(),
|
'last_login_ip' => $ip,
|
||||||
]);
|
], $inviter);
|
||||||
|
}
|
||||||
|
if ($openid) {
|
||||||
|
SocialiteUser::updateOrCreate(
|
||||||
|
['socialite_id' => $openid, 'socialite_type' => SocialiteType::WechatMiniProgram->value],
|
||||||
|
['user_id' => $user->id]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $user->createToken(SocialiteType::WechatMiniProgram->value);
|
$token = $user->createToken(SocialiteType::WechatMiniProgram->value);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ class OfflineOrderController extends Controller
|
||||||
$request->user(),
|
$request->user(),
|
||||||
$preview,
|
$preview,
|
||||||
bcmul($request->input('points', 0), 100),
|
bcmul($request->input('points', 0), 100),
|
||||||
|
['user_remark' => $request->input('user_remark')]
|
||||||
);
|
);
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
|
|
||||||
|
|
@ -35,43 +35,52 @@ class OfflineOrderPreviewController extends Controller
|
||||||
'store_id' => $store->id,
|
'store_id' => $store->id,
|
||||||
'staff_id' => $user->id,
|
'staff_id' => $user->id,
|
||||||
'payload' => ['items' => $request->input('items')],
|
'payload' => ['items' => $request->input('items')],
|
||||||
|
'remark' => $request->input('remark')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$scene = http_build_query([
|
if (config('app.env') != "local") {
|
||||||
'oo' => $preview->id,
|
$scene = http_build_query([
|
||||||
'i' => $user->userInfo->code,
|
'oo' => $preview->id,
|
||||||
]);
|
'i' => $user->userInfo->code,
|
||||||
|
|
||||||
// 生成小程序码
|
|
||||||
$app = Factory::miniProgram(config('wechat.mini_program.default'));
|
|
||||||
|
|
||||||
$response = $app->app_code->getUnlimit($scene, [
|
|
||||||
'page' => 'pages/welcome/index',
|
|
||||||
'check_path' => false,
|
|
||||||
'env_version' => app()->isProduction() ? 'release' : $request->input('env_version', 'trial'),
|
|
||||||
'width' => $request->input('width', 200),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 保存小程序码
|
|
||||||
if ($response instanceof StreamResponse) {
|
|
||||||
$directory = 'offline-order-preview';
|
|
||||||
$filename = "{$preview->id}.png";
|
|
||||||
|
|
||||||
$disk = Storage::disk('public');
|
|
||||||
|
|
||||||
$response->save($disk->path($directory), $filename);
|
|
||||||
|
|
||||||
$preview->update(['qrcode' => $disk->url("{$directory}/{$filename}")]);
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'id' => $preview->id,
|
|
||||||
'qrcode' => $preview->qrcode,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 生成小程序码
|
||||||
|
$app = Factory::miniProgram(config('wechat.mini_program.default'));
|
||||||
|
|
||||||
|
$response = $app->app_code->getUnlimit($scene, [
|
||||||
|
'page' => 'pages/welcome/index',
|
||||||
|
'check_path' => false,
|
||||||
|
'env_version' => app()->isProduction() ? 'release' : $request->input('env_version', 'trial'),
|
||||||
|
'width' => $request->input('width', 200),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 保存小程序码
|
||||||
|
if ($response instanceof StreamResponse) {
|
||||||
|
$directory = 'offline-order-preview';
|
||||||
|
$filename = "{$preview->id}.png";
|
||||||
|
|
||||||
|
$disk = Storage::disk('public');
|
||||||
|
|
||||||
|
$response->save($disk->path($directory), $filename);
|
||||||
|
|
||||||
|
$preview->update(['qrcode' => $disk->url("{$directory}/{$filename}")]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'id' => $preview->id,
|
||||||
|
'qrcode' => $preview->qrcode,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger('offline_order_preview 小程序码生成失败', $response);
|
||||||
|
|
||||||
|
throw new BizException('生成失败, 请重试');
|
||||||
}
|
}
|
||||||
|
|
||||||
logger('offline_order_preview 小程序码生成失败', $response);
|
return response()->json([
|
||||||
|
'id' => $preview->id,
|
||||||
|
'qrcode' => asset("images/logo.png")
|
||||||
|
]);
|
||||||
|
|
||||||
throw new BizException('生成失败, 请重试');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show($id)
|
public function show($id)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class VipController extends Controller
|
||||||
$service = new VipService();
|
$service = new VipService();
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
$user_vip = $service->buy($request->user(), $vip);
|
$user_vip = $service->buy($request->user(), $vip, $request->only(['store_id']));
|
||||||
|
|
||||||
$result = $service->pay($user_vip, $request->input('pay_way'));
|
$result = $service->pay($user_vip, $request->input('pay_way'));
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ Route::group([
|
||||||
// 微信小程序
|
// 微信小程序
|
||||||
Route::group(['prefix' => 'wechat-mini'], function () {
|
Route::group(['prefix' => 'wechat-mini'], function () {
|
||||||
Route::post('login', [MiniprogramController::class, 'login']);
|
Route::post('login', [MiniprogramController::class, 'login']);
|
||||||
Route::group(['middleware' => ['auth:api', \App\Endpoint\Api\Http\Middleware\CheckUserStatus::class]], function () {
|
Route::group(['middleware' => [\App\Endpoint\Api\Http\Middleware\CheckUserStatus::class]], function () {
|
||||||
Route::post('bind-phone', [MiniprogramController::class, 'bindPhone']);
|
Route::post('bind-phone', [MiniprogramController::class, 'bindPhone']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ class OfflineOrder extends Model
|
||||||
'revoked_at',
|
'revoked_at',
|
||||||
'orderable_type',
|
'orderable_type',
|
||||||
'orderable_id',
|
'orderable_id',
|
||||||
|
'user_remark',
|
||||||
|
'staff_remark',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function store()
|
public function store()
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class OfflineOrderPreview extends Model
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'store_id', 'staff_id', 'payload', 'qrcode',
|
'store_id', 'staff_id', 'payload', 'qrcode', 'remark'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function store()
|
public function store()
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use App\Models\Admin\Administrator;
|
||||||
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use App\Models\Store\Store;
|
||||||
|
|
||||||
class PointLog extends Model
|
class PointLog extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -22,6 +23,7 @@ class PointLog extends Model
|
||||||
'after_points',
|
'after_points',
|
||||||
'remark',
|
'remark',
|
||||||
'administrator_id',
|
'administrator_id',
|
||||||
|
'store_id'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|
@ -33,6 +35,11 @@ class PointLog extends Model
|
||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function store()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Store::class, 'store_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function administrator()
|
public function administrator()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Administrator::class);
|
return $this->belongsTo(Administrator::class);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门店
|
||||||
|
*/
|
||||||
class Store extends Model
|
class Store extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, HasDateTimeFormatter;
|
use HasFactory, HasDateTimeFormatter;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Store\Store;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
||||||
|
|
@ -14,7 +15,7 @@ class UserVip extends Model
|
||||||
const STATUS_SUCCESS = 1;
|
const STATUS_SUCCESS = 1;
|
||||||
const STATUS_PROCESSING = 2;
|
const STATUS_PROCESSING = 2;
|
||||||
|
|
||||||
protected $fillable = ['user_id', 'vip_id', 'name', 'price', 'times', 'gift', 'status', 'expired', 'success_time'];
|
protected $fillable = ['user_id', 'vip_id', 'name', 'price', 'times', 'gift', 'status', 'expired', 'success_time', 'store_id'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'times' => 'json',
|
'times' => 'json',
|
||||||
|
|
@ -34,6 +35,11 @@ class UserVip extends Model
|
||||||
return $this->belongsTo(User::class, 'user_id');
|
return $this->belongsTo(User::class, 'user_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function store()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Store::class, 'store_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function vip()
|
public function vip()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Vip::class, 'vip_id');
|
return $this->belongsTo(Vip::class, 'vip_id');
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,10 @@ class AfterSaleService
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($afterSale->points > 0) {
|
if ($afterSale->points > 0) {
|
||||||
(new PointService())->change($order->user, $afterSale->points, PointLogAction::Refund, "售后单{$afterSale->sn}退还积分", $afterSale);
|
(new PointService())->change($order->user, $afterSale->points, PointLogAction::Refund, [
|
||||||
|
'remark' => "售后单{$afterSale->sn}退还积分",
|
||||||
|
'loggable' => $afterSale,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//执行实际退款操作;
|
//执行实际退款操作;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,11 @@ use App\Models\SocialiteUser;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\Payment\WxpayService;
|
use App\Services\Payment\WxpayService;
|
||||||
|
|
||||||
|
use function EasyWeChat\Kernel\data_get;
|
||||||
|
|
||||||
class OfflineOrderService
|
class OfflineOrderService
|
||||||
{
|
{
|
||||||
public function create(User $user, OfflineOrderPreview $orderPreview, int $points = 0): OfflineOrder
|
public function create(User $user, OfflineOrderPreview $orderPreview, int $points = 0, $params = []): OfflineOrder
|
||||||
{
|
{
|
||||||
$items = $this->mapItems($orderPreview->payload['items']);
|
$items = $this->mapItems($orderPreview->payload['items']);
|
||||||
|
|
||||||
|
|
@ -54,13 +55,19 @@ class OfflineOrderService
|
||||||
'status' => OfflineOrderStatus::Pending,
|
'status' => OfflineOrderStatus::Pending,
|
||||||
'orderable_type' => $orderPreview->getMorphClass(),
|
'orderable_type' => $orderPreview->getMorphClass(),
|
||||||
'orderable_id' => $orderPreview->id,
|
'orderable_id' => $orderPreview->id,
|
||||||
|
'user_remark' => data_get($params, 'user_remark'),
|
||||||
|
'staff_remark' => $orderPreview->remark,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->insertOrderItems($order, $items);
|
$this->insertOrderItems($order, $items);
|
||||||
|
|
||||||
// 扣除积分
|
// 扣除积分
|
||||||
if ($points > 0) {
|
if ($points > 0) {
|
||||||
(new PointService)->change($user, -$points, PointLogAction::Consumption, "线下订单{$order->sn}使用积分", $order);
|
(new PointService)->change($user, -$points, PointLogAction::Consumption, [
|
||||||
|
'remark' => "线下订单{$order->sn}使用积分",
|
||||||
|
'loggable' => $order,
|
||||||
|
'store_id' => $orderPreview->store_id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($order->payment_amount === 0) {
|
if ($order->payment_amount === 0) {
|
||||||
|
|
@ -178,7 +185,11 @@ class OfflineOrderService
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($order->points_deduction_amount > 0) {
|
if ($order->points_deduction_amount > 0) {
|
||||||
(new PointService())->change($order->user, $order->points_deduction_amount, PointLogAction::Refund, "线下订单{$order->sn}退还积分", $order);
|
(new PointService())->change($order->user, $order->points_deduction_amount, PointLogAction::Refund, [
|
||||||
|
'remark' => "线下订单{$order->sn}退还积分",
|
||||||
|
'loggable' => $order,
|
||||||
|
'store_id' => $order->store_id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$order->update([
|
$order->update([
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,10 @@ class OrderService
|
||||||
|
|
||||||
// 扣除积分
|
// 扣除积分
|
||||||
if ($points > 0) {
|
if ($points > 0) {
|
||||||
(new PointService)->change($user, -$points, PointLogAction::Consumption, "订单{$order->sn}使用积分", $order);
|
(new PointService)->change($user, -$points, PointLogAction::Consumption, [
|
||||||
|
'remark' => "订单{$order->sn}使用积分",
|
||||||
|
'loggable' => $order
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $order;
|
return $order;
|
||||||
|
|
@ -1418,7 +1421,11 @@ class OrderService
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($order->point_discount_amount > 0) {
|
if ($order->point_discount_amount > 0) {
|
||||||
(new PointService())->change($order->user, $order->point_discount_amount, PointLogAction::Refund, "订单{$order->sn}退还积分", $order);
|
(new PointService())->change($order->user, $order->point_discount_amount, PointLogAction::Refund, [
|
||||||
|
'remark' => "订单{$order->sn}退还积分",
|
||||||
|
'loggable' => $order,
|
||||||
|
'store_id' => $order->store_id
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$order->update([
|
$order->update([
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,20 @@ class PointService
|
||||||
/**
|
/**
|
||||||
* 变更积分
|
* 变更积分
|
||||||
*
|
*
|
||||||
|
* @param User $user 用户
|
||||||
|
* @param int $points 积分
|
||||||
|
* @param PointLogAction $action 操作
|
||||||
|
* @param $options {remark: 备注, loggable: 来源, administrator: 操作人, store_id: 所属门店}
|
||||||
* @throws \App\Exceptions\BizException
|
* @throws \App\Exceptions\BizException
|
||||||
*/
|
*/
|
||||||
public function change(
|
public function change(
|
||||||
User $user,
|
User $user,
|
||||||
int $points,
|
int $points,
|
||||||
PointLogAction $action,
|
PointLogAction $action,
|
||||||
?string $remark = null,
|
// ?string $remark = null,
|
||||||
?Model $loggable = null,
|
// ?Model $loggable = null,
|
||||||
?Administrator $administrator = null,
|
// ?Administrator $administrator = null,
|
||||||
|
$options = []
|
||||||
) {
|
) {
|
||||||
if ($points === 0) {
|
if ($points === 0) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -56,6 +61,9 @@ class PointService
|
||||||
$userinfo->update([
|
$userinfo->update([
|
||||||
'points' => $after,
|
'points' => $after,
|
||||||
]);
|
]);
|
||||||
|
$remark = data_get($options, 'remark');
|
||||||
|
$loggable = data_get($options, 'loggable');
|
||||||
|
$administrator = data_get($options, 'administrator');
|
||||||
|
|
||||||
PointLog::create([
|
PointLog::create([
|
||||||
'loggable_id' => $loggable?->id,
|
'loggable_id' => $loggable?->id,
|
||||||
|
|
@ -67,6 +75,7 @@ class PointService
|
||||||
'after_points' => $after,
|
'after_points' => $after,
|
||||||
'remark' => $remark,
|
'remark' => $remark,
|
||||||
'administrator_id' => $administrator?->id,
|
'administrator_id' => $administrator?->id,
|
||||||
|
'store_id' => data_get($options, 'store_id'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use Carbon\Carbon;
|
||||||
|
|
||||||
class VipService
|
class VipService
|
||||||
{
|
{
|
||||||
public function buy(User $user, Vip $vip)
|
public function buy(User $user, Vip $vip, $params = [])
|
||||||
{
|
{
|
||||||
if (!$vip->status) {
|
if (!$vip->status) {
|
||||||
throw new BizException('该会员卡已关闭');
|
throw new BizException('该会员卡已关闭');
|
||||||
|
|
@ -22,6 +22,7 @@ class VipService
|
||||||
'price' => $vip->price,
|
'price' => $vip->price,
|
||||||
'times' => $vip->times,
|
'times' => $vip->times,
|
||||||
'gift' => $vip->gift,
|
'gift' => $vip->gift,
|
||||||
|
'store_id' => data_get($params, 'store_id')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $user_vip;
|
return $user_vip;
|
||||||
|
|
@ -79,7 +80,7 @@ class VipService
|
||||||
* @param UserVip $userVip 购买记录
|
* @param UserVip $userVip 购买记录
|
||||||
* @param array $params {'pay_at':'购买时间'}
|
* @param array $params {'pay_at':'购买时间'}
|
||||||
*/
|
*/
|
||||||
public function success(UserVip $userVip, array $params = null)
|
public function success(UserVip $userVip, array $params = [])
|
||||||
{
|
{
|
||||||
if ($userVip->status == UserVip::STATUS_SUCCESS) {
|
if ($userVip->status == UserVip::STATUS_SUCCESS) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -133,13 +134,11 @@ class VipService
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($gift['points']) && bccomp($gift['points'], 0, 2) === 1) {
|
if (isset($gift['points']) && bccomp($gift['points'], 0, 2) === 1) {
|
||||||
(new PointService())->change(
|
(new PointService())->change($user, bcmul($gift['points'], 100), PointLogAction::Recharge, [
|
||||||
$user,
|
'remarks' => "购买【{$userVip->name}】赠送积分",
|
||||||
bcmul($gift['points'], 100),
|
'loggable' => $userVip,
|
||||||
PointLogAction::Recharge,
|
'store_id' => $userVip->store_id,
|
||||||
"购买【{$userVip->name}】赠送积分",
|
]);
|
||||||
$userVip,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ class CreateVipsTable extends Migration
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->unsignedBigInteger('user_id')->comment('用户ID');
|
$table->unsignedBigInteger('user_id')->comment('用户ID');
|
||||||
$table->unsignedBigInteger('vip_id')->comment('会员ID');
|
$table->unsignedBigInteger('vip_id')->comment('会员ID');
|
||||||
|
$table->unsignedBigInteger('store_id')->nullable()->comment('开通门店');
|
||||||
$table->string('name')->comment('名称');
|
$table->string('name')->comment('名称');
|
||||||
$table->decimal('price', 12, 2)->default(0)->comment('价格');
|
$table->decimal('price', 12, 2)->default(0)->comment('价格');
|
||||||
$table->text('times')->comment('时效{num,unit,text}');
|
$table->text('times')->comment('时效{num,unit,text}');
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class CreatePointLogsTable extends Migration
|
||||||
$table->unsignedBigInteger('before_points')->comment('变更前的积分');
|
$table->unsignedBigInteger('before_points')->comment('变更前的积分');
|
||||||
$table->unsignedBigInteger('after_points')->comment('变更后的积分');
|
$table->unsignedBigInteger('after_points')->comment('变更后的积分');
|
||||||
$table->string('remark')->nullable()->comment('备注');
|
$table->string('remark')->nullable()->comment('备注');
|
||||||
|
$table->unsignedBigInteger('store_id')->nullable()->comment('所属门店');
|
||||||
$table->unsignedBigInteger('administrator_id')->nullable()->comment('管理员ID');
|
$table->unsignedBigInteger('administrator_id')->nullable()->comment('管理员ID');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
|
|
@ -23,6 +23,8 @@ return [
|
||||||
'status' => '状态',
|
'status' => '状态',
|
||||||
'revoked_at' => '取消时间',
|
'revoked_at' => '取消时间',
|
||||||
'items' => '品类',
|
'items' => '品类',
|
||||||
|
'user_remark' => '用户备注',
|
||||||
|
'staff_remark' => '员工备注',
|
||||||
],
|
],
|
||||||
'options' => [
|
'options' => [
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ return [
|
||||||
'point-logs' => '积分流水',
|
'point-logs' => '积分流水',
|
||||||
],
|
],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
|
'store_id' => '所属门店',
|
||||||
'user_id' => '用户ID',
|
'user_id' => '用户ID',
|
||||||
'user'=>[
|
'user'=>[
|
||||||
'phone' => '手机号',
|
'phone' => '手机号',
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ return [
|
||||||
'points' => '赠送积分',
|
'points' => '赠送积分',
|
||||||
'expired' => '会员有效期',
|
'expired' => '会员有效期',
|
||||||
'price' => '价格',
|
'price' => '价格',
|
||||||
|
'store' => [
|
||||||
|
'title' => '开通门店'
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'options' => [
|
'options' => [
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue