6
0
Fork 0

企业付款 todo

release
panliang 2022-05-12 17:49:04 +08:00
parent eecf325b41
commit 09c53981b5
20 changed files with 199 additions and 76 deletions

View File

@ -69,6 +69,8 @@ class OrderProfitController extends AdminController
$show->field('money');
$show->field('status')->using(OrderProfit::$statusMap)->dot(OrderProfit::$statusColor);
$show->field('paid_at');
$show->field('pay_way');
$show->field('pay_no');
$show->field('remarks');
$show->field('created_at');
$show->field('updated_at');

View File

@ -175,17 +175,19 @@ class StoreController extends AdminController
$form->text('remarks');
$form->disableDeleteButton();
// 管理员删除店铺
if ($form->isDeleting() && $canAdmin) {
$info = Store::find($form->getKey());
// 删除店铺关联的数据
$info->adminUsers()->detach();
$info->productSkus()->detach();
}
});
}
public function destroy($id)
{
$info = Store::find($id);
// 删除店铺关联的数据
$info->adminUsers()->detach();
$info->productSkus()->detach();
return parent::destroy($id);
}
protected function canAdmin()
{
return Admin::user()->isRole('administrator');

View File

@ -2,9 +2,8 @@
namespace App\Admin\Controllers;
use App\Admin\Repositories\Vip;
use App\Exceptions\BizException;
use App\Models\Vip as VipModel;
use App\Models\Vip;
use Dcat\Admin\Admin;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
@ -32,20 +31,20 @@ class VipController extends AdminController
/** 操作 **/
//新增
// if (Admin::user()->can('dcat.admin.vips.create')) {
// $grid->disableCreateButton(false);
// $grid->enableDialogCreate();
// }
if (Admin::user()->can('dcat.admin.vips.create')) {
$grid->disableCreateButton(false);
$grid->enableDialogCreate();
}
//修改
$grid->showQuickEditButton(Admin::user()->can('dcat.admin.vips.edit'));
//删除以及自定义操作
// $grid->actions(function (Grid\Displayers\Actions $actions) {
// $actions->disableDelete(Admin::user()->cannot('dcat.admin.vips.destroy'));
// });
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableDelete(Admin::user()->cannot('dcat.admin.vips.destroy'));
});
$grid->filter(function (Grid\Filter $filter) {
$filter->panel(false);
$filter->like('name');
$filter->like('name')->width(3);
});
});
}
@ -62,6 +61,8 @@ class VipController extends AdminController
return Show::make($id, new Vip(), function (Show $show) {
$show->field('id');
$show->field('name');
$show->field('sort');
$show->filed('slug');
$show->column('ratio')->as(function ($value) {
return $value . '%';
});
@ -80,18 +81,17 @@ class VipController extends AdminController
{
return Form::make(new Vip(), function (Form $form) {
$form->display('id');
$form->number('sort')->min(1)->required()->help('不可重复');
$form->text('name')->required();
$form->radio('slug')->options(Vip::$typeMap)->default(Vip::TYPE_FAVOITE);
$form->number('ratio')->min(0)->max(100)->help('例如: 60%, 填写 60 即可');
$form->number('growth_value')->min(0)->default(0);
$form->display('created_at');
$form->display('updated_at');
$form->number('growth_value')->min(0)->default(0)->help('升级到此等级所需的成长值');
});
}
public function destroy($id)
{
$vip = VipModel::findOrFail($id);
$vip = Vip::findOrFail($id);
if ($vip->hasUser()) {
throw new BizException(__('vip.options.deny_message'));
}

View File

@ -38,9 +38,18 @@ class ProfitSuccessForm extends Form implements LazyRenderable
{
$order = OrderProfit::findOrFail($this->payload['id']);
$service = new DistributeService();
if ($input['pay_way'] === 'wechat-transfer' && !$order->pay_no) {
$order->update([
'pay_no' => serial_number()
]);
}
try {
DB::beginTransaction();
$service->success($order, $input);
if ($input['pay_way'] === 'wechat-transfer') {
$service->wechatTransfer($order);
} else {
$service->success($order, $input);
}
DB::commit();
} catch (Throwable $th) {
DB::rollBack();

View File

@ -1,16 +0,0 @@
<?php
namespace App\Admin\Repositories;
use App\Models\Vip as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class Vip extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}

View File

@ -4,7 +4,7 @@ namespace App\Endpoint\Api\Http\Controllers\Order;
use App\Endpoint\Api\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\{OrderPre, ProductSku};
use App\Models\{OrderPre, ProductSku, Store};
use App\Services\OrderService;
use Illuminate\Support\Facades\DB;
use App\Exceptions\BizException;
@ -30,19 +30,29 @@ class OrderPreController extends Controller
'products.required' => '未选择商品'
]);
// 验证商品是否属于该店铺
$store = Store::findOrFail($request->input('store_id'));
$products = $request->input('products');
// 验证商品的购买数量 大于 发货数量
foreach($products as $item) {
$quantity = $item['quantity'];
$send = $item['send'];
$sku_id = $item['sku_id'];
// 验证商品是否属于该店铺
if (!$store->productSkus()->wherePivot('product_sku_id', $sku_id)->exists()) {
throw new BizException('商品未在该店铺出售, ' . $sku_id);
}
// 验证商品的购买数量 大于 发货数量
if ($send > $quantity) {
throw new BizException('商品购买数量大于发货数量, ' . $item['sku_id']);
throw new BizException('商品购买数量大于发货数量, ' . $sku_id);
}
}
$order_pre = OrderPre::create([
'user_id' => $user->id,
'store_id' => $request->input('store_id'),
'store_id' => $store->id,
'products' => $request->input('products'),
'remarks' => $request->input('remarks'),
'others' => [

View File

@ -24,7 +24,7 @@ class OrderProfit extends Model
3 => 'danger'
];
protected $fillable = ['id', 'order_id', 'from_user_id', 'user_id', 'role', 'role_name', 'growth_value', 'ratio', 'money', 'status', 'paid_at', 'pay_data', 'remarks'];
protected $fillable = ['id', 'order_id', 'from_user_id', 'user_id', 'role', 'role_name', 'growth_value', 'ratio', 'money', 'status', 'paid_at', 'pay_no', 'pay_way', 'pay_data', 'remarks'];
public function user()
{

View File

@ -15,6 +15,8 @@ class ShippingRule extends Model
public const TYPE_FREE = 1;//包邮
public const TYPE_WEIGHT = 2;//计算重量
protected $fillable = ['info', 'remarks', 'template_id', 'type', 'zones'];
protected $casts = [
// 'info' => JsonArray::class,
'zones' => JsonArray::class,

View File

@ -8,8 +8,17 @@ use Illuminate\Database\Eloquent\Model;
class Vip extends Model
{
use HasFactory;
use HasDateTimeFormatter;
use HasFactory, HasDateTimeFormatter;
const TYPE_FAVOITE = 'favoite';
const TYPE_AGENT = 'agent';
protected $fillable = ['growth_value', 'name', 'ratio', 'slug', 'sort'];
public static $typeMap = [
self::TYPE_FAVOITE => '爱好者',
self::TYPE_AGENT => '代理'
];
public function users()
{

View File

@ -3,6 +3,9 @@
namespace App\Services;
use App\Models\{User, Order, SalesValueLog, Vip, OrderProfit};
use App\Services\Payment\WxpayService;
use App\Enums\SocialiteType;
use App\Exceptions\BizException;
/**
* 分销模块
@ -94,6 +97,27 @@ class DistributeService
$order->profits()->createMany($profit_list);
}
/**
* 使用微信企业付款
* 调用之前, 需要提前生成商户订单号
*/
public function wechatTransfer(OrderProfit $profit)
{
$user = $profit->user;
$openid = $user->socialites()->where('socialite_type', SocialiteType::WechatMiniProgram->value)->value('socialite_id');
$result = (new WxpayService())->transfer([
'partner_trade_no' => $profit->pay_no,
'openid' => $openid,
'check_name' => 'NO_CHECK',
'amount' => $profit->money * 100,
'desc' => '推荐返利',
]);
$this->success($profit, [
'paid_at' => data_get($result, 'payment_time')
]);
}
/**
* 返现记录支付成功
*

View File

@ -55,6 +55,56 @@ class WxpayService
};
}
/**
* 微信企业付款到零钱
*
* @param array $params
* @return array
*/
public function transfer(array $params)
{
$config = config('wechat.payment.default');
if (!isset($params['openid']) && config('app.debug')) {
$params['openid'] = 'oU7xS5UspzVvpPEBqKZuW6N9WXDg';
}
$app = Factory::payment($config);
// 服务商模式 (子商户)
$appId = config('wechat.payment.sub.app_id');
$mchId = config('wechat.payment.sub.mch_id');
if ($appId && $mchId) {
$app->setSubMerchant($mchId, $appId);
}
/*
'partner_trade_no' => '1233455', // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
'openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
'check_name' => 'FORCE_CHECK', // NO_CHECK不校验真实姓名, FORCE_CHECK强校验真实姓名
're_user_name' => '王小帅', // 如果 check_name 设置为FORCE_CHECK则必填用户真实姓名
'amount' => 10000, // 企业付款金额,单位为分
'desc' => '理赔', // 企业付款操作说明信息。必填
*/
$result = $app->transfer->toBalance($params);
$this->validateResult($result);
return $result;
}
/**
* 查询 微信企业付款到零钱 的订单
*
* @param string $no 商户订单号
* @return array
*/
public function queryTransfer($no)
{
$config = config('wechat.payment.transfer');
$app = Factory::payment($config);
$result = $app->transfer->queryBalanceOrder($no);
$this->validateResult($result);
return $result;
}
/**
* 根据商户订单号退款
*

View File

@ -77,6 +77,15 @@ return [
'app_id' => env('WECHAT_PAYMENT_SUB_APPID'),
'mch_id' => env('WECHAT_PAYMENT_SUB_MCH_ID'),
],
// 企业付款
'transfer' => [
'sandbox' => env('WECHAT_PAYMENT_SANDBOX', false),
'app_id' => env('WECHAT_PAYMENT_SUB_APPID'),
'mch_id' => env('WECHAT_PAYMENT_SUB_MCH_ID'),
'key' => env('WECHAT_PAYMENT_SUB_KEY'),
'cert_path' => env('WECHAT_PAYMENT_SUB_CERT_PATH'),
'key_path' => env('WECHAT_PAYMENT_SUB_KEY_PATH'),
],
// 商城 - 微信小程序支付
'mini_program' => [
'sandbox' => env('WECHAT_PAYMENT_SANDBOX', false),

View File

@ -26,7 +26,9 @@ class CreateOrderProfitsTable extends Migration
$table->tinyInteger('status')->default(0)->comment('状态(0: 待付款, 1: 付款中, 2: 已付款)');
$table->string('remarks')->nullable()->comment('备注');
$table->timestamp('paid_at')->nullable()->comment('付款时间');
$table->text('pay_data')->nullable()->comment('支付信息{pay_way, pay_sn}');
$table->string('pay_way')->nullable()->comment('付款方式');
$table->string('pay_no')->nullable()->comment('付款流水号');
$table->text('pay_data')->nullable()->comment('支付信息');
$table->timestamps();
});
}

View File

@ -33,6 +33,7 @@ class AdminMenuSeeder extends Seeder
'icon' => '',
'uri' => 'users',
],
['title' => '代理等级', 'icon' => '', 'uri' => 'vips']
],
],
[
@ -248,31 +249,32 @@ class AdminMenuSeeder extends Seeder
'icon' => 'fa fa-jpy',
'uri'=> '',
'children'=>[
[
'title' => '可提账户',
'icon'=>'',
'uri' => 'wallet-logs',
],
[
'title' => '余额账户',
'icon' => '',
'uri' => 'balance-logs',
],
[
'title' => '积分账户',
'icon' => '',
'uri' => 'points-logs',
],
[
'title' =>'提现审核',
'icon' => '',
'uri' =>'wallet-to-bank-logs',
],
// [
// 'title' => '可提账户',
// 'icon'=>'',
// 'uri' => 'wallet-logs',
// ],
// [
// 'title' => '余额账户',
// 'icon' => '',
// 'uri' => 'balance-logs',
// ],
// [
// 'title' => '积分账户',
// 'icon' => '',
// 'uri' => 'points-logs',
// ],
// [
// 'title' =>'提现审核',
// 'icon' => '',
// 'uri' =>'wallet-to-bank-logs',
// ],
[
'title' => '售后打款',
'icon' => '',
'uri' =>'finance-after-sales?state=5',
],
['title' => '提成管理', 'icon' => '', 'uri' => 'profit']
],
],
[
@ -300,7 +302,6 @@ class AdminMenuSeeder extends Seeder
'icon' => '',
'uri' =>'auth/menus',
],
['title' => '代理等级', 'icon' => '', 'uri' => 'vips'],
[
'title' =>'配置管理',
'icon' => '',
@ -317,6 +318,7 @@ class AdminMenuSeeder extends Seeder
} catch (Throwable $th) {
DB::rollBack();
report($th);
dump($th->getMessage());
}
}

View File

@ -309,6 +309,17 @@ class AdminPermissionSeeder extends Seeder
'store' => [
'name' => '店铺管理',
'curd' => ['index', 'create', 'store', 'edit', 'update', 'destroy'],
],
'vip' => [
'name' => '代理等级管理',
'curd' => ['index', 'create', 'store', 'edit', 'update', 'destroy'],
],
'profit' => [
'name' => '提成管理',
'curd' => ['index', 'create', 'store', 'edit', 'update', 'destroy'],
'children' => [
'pay' => ['name' => '修改支付状态']
]
]
];
// try {

View File

@ -23,7 +23,7 @@ class AdminUserSeeder extends Seeder
$user = $userModel::create([
'username' => 'admin',
'password' => 'admin',
'password' => bcrypt('admin'),
'name' => '管理员',
]);

View File

@ -18,11 +18,13 @@ class ShippingSeeder extends Seeder
'name' => '自提'
]);
ShippingRule::create([
\DB::table('shipping_rules')->insert([
'template_id' => $template->id,
'type' => 1,
'info' => json_encode(["threshold" => "100"]),
'info' => json_encode(["threshold" => "0"]),
'zones' => json_encode(Zone::where('type', Zone::TYPE_AREA)->pluck('id')),
'created_at' => now(),
'updated_at' => now()
]);
}
}

View File

@ -23,7 +23,11 @@ class UserSeeder extends Seeder
DB::table('user_vips')->truncate();
DB::table('socialite_users')->truncate();
DB::table('personal_access_tokens')->truncate();
DB::table('wallets')->truncate();
DB::table('wallet_logs')->truncate();
DB::table('wallet_to_bank_logs')->truncate();
DB::table('balances')->truncate();
DB::table('users')->truncate();
$this->faker = $this->withFaker();

View File

@ -23,7 +23,7 @@ return [
'remarks' => '备注',
'paid_at' => '付款时间',
'pay_way' => '支付方式',
'pay_no' => '订单号',
'pay_no' => '流水号',
],
'options' => [
],

View File

@ -8,11 +8,12 @@ return [
'fields' => [
'name' => '等级名称',
'growth_value' => '升级',
'sort' => '排序',
'ratio' => '比例'
'sort' => '等级',
'ratio' => '比例',
'slug' => '类别'
],
'options' => [
'deny' => '删除失败',
'deny_message'=>'当前会员等级下会员人数大于0',
'deny_message'=> '该等级下还有用户, 无法删除',
],
];