// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\store\model\dealer; use cores\exception\BaseException; use app\store\model\Payment as PaymentModel; use app\store\model\UserOauth as UserOauthModel; use app\store\model\dealer\User as DealerUserModel; use app\common\model\dealer\Withdraw as WithdrawModel; use app\common\enum\Client as ClientEnum; use app\common\enum\payment\Method as PaymentMethodEnum; use app\common\enum\dealer\withdraw\ApplyStatus as ApplyStatusEnum; use app\common\service\Order as OrderService; use app\common\library\payment\Facade as PaymentFacade; /** * 分销商提现明细模型 * Class Withdraw * @package app\store\model\dealer */ class Withdraw extends WithdrawModel { /** * 获取器:申请时间 * @param $value * @return false|string */ public function getAuditTimeAttr($value) { return $value > 0 ? format_time($value) : 0; } /** * 获取分销商提现列表 * @param array $param * @return \think\Paginator * @throws \think\db\exception\DbException */ public function getList(array $param = []): \think\Paginator { // 默认查询参数 $params = $this->setQueryDefaultValue($param, [ 'dealerId' => null, // 分销商ID 'search' => '', // 分销商ID 'applyStatus' => -1, // 申请状态 'payType' => -1, // 打款方式 ]); // 查询条件 $filter = []; $params['dealerId'] > 0 && $filter[] = ['m.user_id', '=', (int)$params['dealerId']]; !empty($params['search']) && $filter[] = ['dealer.real_name|dealer.mobile|user.nick_name', 'like', "%{$params['search']}%"]; $params['applyStatus'] > -1 && $filter[] = ['m.user_id', '=', (int)$params['applyStatus']]; $params['payType'] > -1 && $filter[] = ['m.pay_type', '=', (int)$params['payType']]; // 获取列表数据 return $this->alias('m') ->with(['user.avatar']) ->field('m.*, dealer.real_name, dealer.mobile') ->join('dealer_user dealer', 'dealer.user_id = m.user_id') ->join('user', 'user.user_id = m.user_id') ->where($filter) ->order(['m.create_time' => 'desc']) ->paginate(15); } /** * 分销商提现审核 * @param array $data * @return bool */ public function audit(array $data): bool { // 验证当前提现记录状态 if ($this['apply_status'] != ApplyStatusEnum::WAIT) { $this->error = '很抱歉,当前提现记录不合法'; return false; } // 验证驳回原因 if ( $data['apply_status'] == ApplyStatusEnum::REJECT && empty($data['reject_reason']) ) { $this->error = '请填写驳回原因'; return false; } $this->transaction(function () use ($data) { // 更新申请记录 $data['audit_time'] = time(); $this->save($data); // 提现驳回:解冻分销商资金 if ($data['apply_status'] == ApplyStatusEnum::REJECT) { User::backFreezeMoney($this['user_id'], $this['money']); } }); return true; } /** * 确认已打款 * @return bool */ public function payed(): bool { $this->transaction(function () { // 更新申请状态 $this->save([ 'apply_status' => 40, 'audit_time' => time(), ]); // 更新分销商累积提现佣金 User::totalMoney((int)$this['user_id'], $this['money']); // 记录分销商资金明细 Capital::add([ 'user_id' => $this['user_id'], 'flow_type' => 20, 'money' => -$this['money'], 'describe' => '申请提现', ]); }); return true; } /** * 分销商提现:微信支付企业付款 * @return bool * @throws BaseException * @throws \cores\exception\BaseException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function wechatPay(): bool { // 获取分销商用户微信小程序OpenID $openId = $this->getWeiXinOpenId($this['user_id'], $this['platform']); // 生成第三方交易订单号 $outTradeNo = OrderService::createOrderNo(); // 获取支付方式的配置信息 $options = $this->getPaymentConfig($this['platform']); // 整理下单接口所需的附加数据 $extra = ['openid' => $openId, 'desc' => '分销商提现付款']; // 构建支付模块 $Payment = PaymentFacade::store(PaymentMethodEnum::WECHAT)->setOptions($options, $this['platform']); // 执行第三方支付下单API if (!$Payment->transfers($outTradeNo, (string)$this['money'], $extra)) { throwError($Payment->getError() ?: '商家转账到零钱API请求失败'); } // 确认已打款 return $this->payed(); } /** * 获取支付方式的配置信息 * @param string $client 客户端 * @return mixed * @throws BaseException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function getPaymentConfig(string $client) { $PaymentModel = new PaymentModel; $templateInfo = $PaymentModel->getPaymentInfo(PaymentMethodEnum::WECHAT, $client, static::$storeId); $options = $templateInfo['template']['config'][PaymentMethodEnum::WECHAT]; if ($options['mchType'] === 'provider') { throwError('很抱歉,微信企业付款API不支持服务商模式'); } return $options; } /** * 获取分销商用户微信小程序OpenID * @param int $userId 分销商用户ID * @param string $platform 提现申请所在的客户端 (只能是微信小程序或者微信公众号) * @return string * @throws BaseException */ private function getWeiXinOpenId(int $userId, string $platform): string { if (!in_array($platform, [ClientEnum::MP_WEIXIN, ClientEnum::WXOFFICIAL])) { throwError('很抱歉,提现申请来源客户端必须是微信小程序'); } $openid = UserOauthModel::getOauthIdByUserId($userId, $platform); if (empty($openid)) { throwError('很抱歉,未找到当前分销商用户的openid'); } return $openid; } /** * 验证已冻结佣金是否合法 * @param int $userId 分销商用户ID * @param float $money 提现金额 * @return bool */ public function verifyUserFreezeMoney(int $userId, float $money): bool { $dealerUserInfo = DealerUserModel::detail($userId); if ($dealerUserInfo['freeze_money'] < $money) { $this->error = '数据错误:已冻结的佣金不能小于提现的金额'; return false; } return true; } }