From 99646970b0dd08f96d950b35e440780314e75843 Mon Sep 17 00:00:00 2001 From: wang hou sheng <76928547+wanghousheng@users.noreply.github.com> Date: Wed, 3 Apr 2024 00:26:33 +0800 Subject: [PATCH 1/5] 1 --- app/api/controller/Wholesaler.php | 128 ++++++++ app/api/model/wholesaler/Apply.php | 27 ++ app/api/model/wholesaler/Order.php | 48 +++ app/api/model/wholesaler/Set.php | 13 + app/api/service/Notify.php | 9 + app/api/service/wholesaler/PaySuccess.php | 349 ++++++++++++++++++++++ app/api/service/wholesaler/Payment.php | 299 ++++++++++++++++++ app/api/service/wholesaler/Wholesaler.php | 104 +++++++ app/common/enum/OrderType.php | 7 + app/common/enum/user/balanceLog/Scene.php | 9 +- app/common/model/wholesaler/Apply.php | 19 ++ app/common/model/wholesaler/Order.php | 19 ++ app/common/model/wholesaler/Set.php | 25 ++ app/store/controller/User.php | 5 +- app/store/controller/wholesaler/Set.php | 39 +++ app/store/model/wholesaler/Set.php | 31 ++ 16 files changed, 1128 insertions(+), 3 deletions(-) create mode 100644 app/api/controller/Wholesaler.php create mode 100644 app/api/model/wholesaler/Apply.php create mode 100644 app/api/model/wholesaler/Order.php create mode 100644 app/api/model/wholesaler/Set.php create mode 100644 app/api/service/wholesaler/PaySuccess.php create mode 100644 app/api/service/wholesaler/Payment.php create mode 100644 app/api/service/wholesaler/Wholesaler.php create mode 100644 app/common/model/wholesaler/Apply.php create mode 100644 app/common/model/wholesaler/Order.php create mode 100644 app/common/model/wholesaler/Set.php create mode 100644 app/store/controller/wholesaler/Set.php create mode 100644 app/store/model/wholesaler/Set.php diff --git a/app/api/controller/Wholesaler.php b/app/api/controller/Wholesaler.php new file mode 100644 index 00000000..a32f0b18 --- /dev/null +++ b/app/api/controller/Wholesaler.php @@ -0,0 +1,128 @@ +request->post('client'); + if (!$client) { + return $this->renderError('客户端不能为空'); + } + $model = new \app\api\service\wholesaler\Wholesaler(); + $list = $model->setClient($client)->center(); + return $this->renderSuccess($list); + } + + /** + * @notes:创建订单并支付 + * @return Json + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author: wanghousheng + */ + public function submit(): Json + { + $method = $this->request->post('method'); + if (!$method) { + return $this->renderError('支付方式不能为空'); + } + $client = $this->request->post('client'); + if (!$client) { + return $this->renderError('客户端不能为空'); + } + $priceInfo = Set::detail(); + if ($priceInfo->isEmpty()) { + return $this->renderError('后台价格未设置'); + } + $priceInfo = $priceInfo->toArray(); + $username = $this->request->post('username'); + if (!$username) { + return $this->renderError('姓名不能为空'); + } + $mobile = $this->request->post('mobile'); + if (!$mobile) { + return $this->renderError('手机号不能为空'); + } + $mobile_code = $this->request->post('mobile_code'); + if (!$mobile_code) { + return $this->renderError('手机号验证码不能为空'); + } + // 验证短信验证码是否匹配 +// try { +// CaptchaApi::checkSms($mobile_code, $mobile); +// } catch (Exception $e) { +// return $this->renderError($e->getMessage() ?: '短信验证码不正确'); +// } + $card_front_img_id = intval($this->request->post('card_front_img_id')); + if (!$card_front_img_id) { + return $this->renderError('身份证正面不能为空'); + } + $card_back_img_id = intval($this->request->post('card_back_img_id')); + if (!$card_back_img_id) { + return $this->renderError('身份证反面不能为空'); + } + $license_img_id = intval($this->request->post('license_img_id')); + if (!$license_img_id) { + return $this->renderError('营业执照不能为空'); + } + $card_no = $this->request->post('card_no'); + if (!$card_no) { + return $this->renderError('身份证号不能为空'); + } + $door_img_id = intval($this->request->post('door_img_id')); + if (!$door_img_id) { + return $this->renderError('门口照片不能为空'); + } + $province_id = intval($this->request->post('province_id')); + if (!$province_id) { + return $this->renderError('省份不能为空'); + } + $city_id = intval($this->request->post('city_id')); + if (!$city_id) { + return $this->renderError('城市不能为空'); + } + $company_name = $this->request->post('company_name'); + if (!$company_name) { + return $this->renderError('公司名称不能为空'); + } + $credit_code = $this->request->post('credit_code'); + if (!$credit_code) { + return $this->renderError('社会信用代码不能为空'); + } + $business = $this->request->post('business'); + if (!$business) { + return $this->renderError('经营类目不能为空'); + } + $data = compact('company_name', 'credit_code', 'city_id', 'province_id', 'door_img_id', 'business', 'card_no'); + $data = array_merge($data, compact('username', 'mobile', 'card_back_img_id', 'card_front_img_id', 'license_img_id')); + $data['total_price'] = $priceInfo['price']; + $data['pay_price'] = $priceInfo['price']; + $data['year'] = $priceInfo['year']; + $service = new \app\api\service\wholesaler\Wholesaler(); + $data = $service->setMethod($method) + ->setClient($client) + ->orderPay($data); + return $this->renderSuccess($data, $service->getMessage() ?: '申请成功'); + } + +} \ No newline at end of file diff --git a/app/api/model/wholesaler/Apply.php b/app/api/model/wholesaler/Apply.php new file mode 100644 index 00000000..15e6d875 --- /dev/null +++ b/app/api/model/wholesaler/Apply.php @@ -0,0 +1,27 @@ +save($data); + } +} \ No newline at end of file diff --git a/app/api/model/wholesaler/Order.php b/app/api/model/wholesaler/Order.php new file mode 100644 index 00000000..c881bd71 --- /dev/null +++ b/app/api/model/wholesaler/Order.php @@ -0,0 +1,48 @@ + UserService::getCurrentLoginUserId(), + 'order_no' => OrderService::createOrderNo(), + 'store_id' => self::$storeId, + ]; + $data = array_merge($arr, $data); + return $this->save($data); + } + + /** + * 获取订单详情 (待付款状态) + * @param string $orderNo 订单号 + * @return \app\common\model\wholesaler\Order|array|null + */ + public static function getPayDetail(string $orderNo) + { + return self::detail(['order_no' => $orderNo]); + } +} \ No newline at end of file diff --git a/app/api/model/wholesaler/Set.php b/app/api/model/wholesaler/Set.php new file mode 100644 index 00000000..afcbec59 --- /dev/null +++ b/app/api/model/wholesaler/Set.php @@ -0,0 +1,13 @@ +setPaymentData($paymentData) ->handle(); } + // 订单支付成功业务处理 (开通采购商) + if ($tradeInfo['order_type'] == OrderTypeEnum::WHOLESALER) { + $service = new wholesaler\PaySuccess(); + $service->setOrderNo($tradeInfo['order_no']) + ->setMethod($tradeInfo['pay_method']) + ->setTradeId($tradeInfo['trade_id']) + ->setPaymentData($paymentData) + ->handle(); + } Log::append('Notify-orderPaySucces', ['message' => '订单支付成功']); } catch (\Throwable $e) { // 记录错误日志 diff --git a/app/api/service/wholesaler/PaySuccess.php b/app/api/service/wholesaler/PaySuccess.php new file mode 100644 index 00000000..3c74d79b --- /dev/null +++ b/app/api/service/wholesaler/PaySuccess.php @@ -0,0 +1,349 @@ +orderId = $orderId; + return $this; + } + + /** + * 设置当前的订单号 + * @param string $orderNo + * @return $this + */ + public function setOrderNo(string $orderNo): PaySuccess + { + $this->orderNo = $orderNo; + return $this; + } + + /** + * 设置订单支付方式 + * @param string $method + * @return $this + */ + public function setMethod(string $method): PaySuccess + { + $this->method = $method; + return $this; + } + + /** + * 第三方支付交易记录ID + * @param int|null $tradeId + * @return $this + */ + public function setTradeId(?int $tradeId = null): PaySuccess + { + $this->tradeId = $tradeId; + return $this; + } + + /** + * 第三方支付成功返回的数据 + * @param array $paymentData + * @return $this + */ + public function setPaymentData(array $paymentData): PaySuccess + { + $this->paymentData = $paymentData; + return $this; + } + + /** + * 订单支付成功业务处理 + * @return bool + * @throws BaseException + */ + public function handle(): bool + { + // 验证当前参数是否合法 + $this->verifyParameters(); + // 当前订单开启并发锁 + $this->lockUp(); + // 验证当前订单是否允许支付 + if ($this->checkOrderStatusOnPay()) { + // 更新订单状态为已付款 + $this->updatePayStatus(); + } + // 当前订单解除并发锁 + $this->unLock(); + return true; + } + + /** + * 订单模型 + * @return Order|null + * @throws BaseException + */ + private function orderModel(): ?Order + { + return $this->getOrderInfo(); + } + + /** + * 订单已付款事件 + * @return void + * @throws BaseException + */ + private function updatePayStatus(): void + { + // 记录日志 + Log::append('PaySuccess --updatePayStatus', ['title' => '订单已付款事件']); + // 当前订单信息 + $orderInfo = $this->getOrderInfo(); + // 事务处理 + $this->orderModel()->transaction(function () use ($orderInfo) { + // 更新订单状态 + $this->updateOrderStatus(); + // 累积用户总消费金额 + UserModel::setIncPayMoney($orderInfo['user_id'], (float)$orderInfo['pay_price']); + // 记录订单支付信息 + $this->updatePayInfo(); + //添加申请记录 + $this->apply(); + }); + } + + /** + * 记录订单支付的信息 + * @throws BaseException + */ + private function updatePayInfo() + { + // 当前订单信息 + $orderInfo = $this->getOrderInfo(); + // 余额支付 + if ($this->method == PaymentMethodEnum::BALANCE) { + // 更新用户余额 + UserModel::setDecBalance((int)$orderInfo['user_id'], (float)$orderInfo['pay_price']); + // 新增余额变动记录 + BalanceLogModel::add(SceneEnum::WHOLESALER, [ + 'user_id' => (int)$orderInfo['user_id'], + 'money' => -$orderInfo['pay_price'], + ], ['order_no' => $orderInfo['order_no']]); + } + // 将第三方交易记录更新为已支付状态 + if (in_array($this->method, [PaymentMethodEnum::WECHAT, PaymentMethodEnum::ALIPAY])) { + $this->updateTradeRecord(); + } + } + + /** + * 将第三方交易记录更新为已支付状态 + */ + private function updateTradeRecord() + { + if ($this->tradeId && !empty($this->paymentData)) { + PaymentTradeModel::updateToPaySuccess($this->tradeId, $this->paymentData['tradeNo']); + } + } + + /** + * 更新订单状态 + * @throws BaseException + */ + private function updateOrderStatus(): void + { + // 更新订单状态 + $this->orderModel()->save([ + 'pay_method' => $this->method, + 'pay_status' => PayStatus::SUCCESS, + 'pay_time' => time(), + 'trade_id' => $this->tradeId ?: 0, + ]); + } + + /** + * 获取买家用户信息 + * @return UserModel|array|null + * @throws BaseException + */ + private function getUserInfo() + { + if (empty($this->userInfo)) { + $this->userInfo = UserModel::detail($this->getOrderInfo()['user_id']); + } + if (empty($this->userInfo)) { + throwError('未找到买家用户信息'); + } + return $this->userInfo; + } + + /** + * 验证当前参数是否合法 + * @throws BaseException + */ + private function verifyParameters() + { + if (empty($this->orderNo)) { + throwError('orderNo not found'); + } + if (empty($this->method)) { + throwError('method not found'); + } + if ($this->tradeId) { + empty($this->paymentData) && throwError('PaymentData not found'); + !isset($this->paymentData['tradeNo']) && throwError('PaymentData not found'); + } + // 记录日志 + Log::append('PaySuccess', [ + 'orderNo' => $this->orderNo, 'method' => $this->method, + 'tradeId' => $this->tradeId, 'paymentData' => $this->paymentData + ]); + } + + /** + * 验证当前订单是否允许支付 + * @return bool + * @throws BaseException + */ + private function checkOrderStatusOnPay(): bool + { + // 当前订单信息 + $orderInfo = $this->getOrderInfo(); + // 验证余额支付时用户余额是否满足 + if ($this->method == PaymentMethodEnum::BALANCE) { + if ($this->getUserInfo()['balance'] < $orderInfo['pay_price']) { + throwError('账户余额不足,无法使用余额支付'); + } + } + // 检查订单状态是否为已支付 + if ($orderInfo['pay_status'] == PayStatusEnum::SUCCESS) { + $this->onOrderPaid(); + return false; + } + return true; + } + + /** + * 处理订单已支付的情况 + * @throws BaseException + */ + private function onOrderPaid() + { + // 记录日志 + Log::append('PaySuccess --onOrderPaid', ['title' => '处理订单已支付的情况']); + // 当前订单信息 + $orderInfo = $this->getOrderInfo(); + // 余额支付直接返回错误信息 + if ($this->method == PaymentMethodEnum::BALANCE) { + throwError('当前订单已支付,无需重复支付'); + } + // 第三方支付判断是否为重复下单 (因异步回调可能存在网络延迟的原因,在并发的情况下会出现同时付款两次,这里需要容错) + // 如果订单记录中已存在tradeId并且和当前支付的tradeId不一致, 那么判断为重复的订单, 需进行退款处理 + if ($this->tradeId > 0 && $orderInfo['trade_id'] != $this->tradeId) { + // 执行原路退款 + throwError('当前订单异常'); + } + } + + /** + * 获取当前订单的详情信息 + * @return Order|null + * @throws BaseException + */ + private function getOrderInfo(): ?Order + { + // 获取订单详情 (待支付状态) + if (empty($this->orderInfo)) { + $this->orderInfo = Order::getPayDetail($this->orderNo); + } + // 判断订单是否存在 + if (empty($this->orderInfo)) { + throwError('未找到该订单信息'); + } + return $this->orderInfo; + } + + /** + * 订单锁:防止并发导致重复支付 + * @throws BaseException + */ + private function lockUp() + { + $orderInfo = $this->getOrderInfo(); + Lock::lockUp("OrderPaySuccess_{$orderInfo['order_id']}"); + } + + /** + * 订单锁:防止并发导致重复支付 + * @throws BaseException + */ + private function unLock() + { + $orderInfo = $this->getOrderInfo(); + Lock::unLock("OrderPaySuccess_{$orderInfo['order_id']}"); + } + + private function apply(): void + { + $orderInfo = $this->orderInfo; + $add['order_id'] = $orderInfo['order_id']; + $add['year'] = $orderInfo['year']; + $add['store_id'] = $orderInfo['store_id']; + $add['username'] = $orderInfo['username']; + $add['mobile'] = $orderInfo['mobile']; + $add['card_front_img_id'] = $orderInfo['card_front_img_id']; + $add['card_back_img_id'] = $orderInfo['card_back_img_id']; + $add['license_img_id'] = $orderInfo['license_img_id']; + $add['card_no'] = $orderInfo['card_no']; + $add['province_id'] = $orderInfo['province_id']; + $add['door_img_id'] = $orderInfo['door_img_id']; + $add['city_id'] = $orderInfo['city_id']; + $add['company_name'] = $orderInfo['company_name']; + $add['credit_code'] = $orderInfo['credit_code']; + $add['business'] = $orderInfo['business']; + $add['user_id'] = $orderInfo['user_id']; + $info = Apply::detail(['user_id' => $orderInfo['user_id']]); + if (empty($info->id)) { + (new Apply())->add($add); + } else { + $add['status'] = 10; + (new Apply())->where(['user_id' => $orderInfo['user_id']])->update($add); + } + } +} \ No newline at end of file diff --git a/app/api/service/wholesaler/Payment.php b/app/api/service/wholesaler/Payment.php new file mode 100644 index 00000000..932744ad --- /dev/null +++ b/app/api/service/wholesaler/Payment.php @@ -0,0 +1,299 @@ +method = $method; + return $this; + } + + /** + * 设置下单的客户端 + * @param string $client 客户端 + * @return $this + */ + public function setClient(string $client): Payment + { + $this->client = $client; + return $this; + } + + /** + * 确认订单支付事件 + * @param array $extra 附加数据 + * @return array[] + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function orderPay(array $data, array $extra = []): array + { + + // 创建订单信息 + $this->orderInfo = $this->createOrder($data); + // 订单支付事件 + $this->orderPayEvent(); + // 构建第三方支付请求的参数 + $payment = $this->unifiedorder($extra); + $this->recordPaymentTrade($payment); + // 返回结果 + return compact('payment'); + } + + /** + * 记录第三方交易信息 + * @param array $payment 第三方支付数据 + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + private function recordPaymentTrade(array $payment): void + { + if ($this->method != PaymentMethodEnum::BALANCE) { + PaymentTradeModel::record( + $this->orderInfo, + $this->method, + $this->client, + OrderTypeEnum::WHOLESALER, + $payment + ); + } + } + + /** + * 返回消息提示 + * @return string + */ + public function getMessage(): string + { + return $this->message; + } + + /** + * 获取支付方式的配置信息 + * @return mixed + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + private function getPaymentConfig() + { + $PaymentModel = new PaymentModel; + $templateInfo = $PaymentModel->getPaymentInfo($this->method, $this->client, $this->getStoreId()); + return $templateInfo['template']['config'][$this->method]; + } + + /** + * 构建第三方支付请求的参数 + * @param array $extra 附加数据 + * @return array + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + private function unifiedorder(array $extra = []): array + { + // 判断支付方式是否合法 + if (!in_array($this->method, [PaymentMethodEnum::WECHAT, PaymentMethodEnum::ALIPAY])) { + return []; + } + // 生成第三方交易订单号 (并非主订单号) + $outTradeNo = OrderService::createOrderNo(); + // 获取支付方式的配置信息 + $options = $this->getPaymentConfig(); + // 整理下单接口所需的附加数据 + $extra = $this->extraAsUnify($extra); + // 构建支付模块 + $Payment = PaymentFacade::store($this->method)->setOptions($options, $this->client); + // 执行第三方支付下单API + if (!$Payment->unify($outTradeNo, (string)$this->orderInfo['pay_price'], $extra)) { + throwError('第三方支付下单API调用失败'); + } + // 返回客户端需要的支付参数 + return $Payment->getUnifyResult(); + } + + /** + * 整理下单接口所需的附加数据 + * @param array $extra + * @return array + * @throws BaseException + */ + private function extraAsUnify(array $extra = []): array + { + // 微信支付时需要的附加数据 + if ($this->method === PaymentMethodEnum::WECHAT) { + // 微信小程序端和微信公众号端需要openid + if (in_array($this->client, [ClientEnum::WXOFFICIAL, ClientEnum::MP_WEIXIN])) { + $extra['openid'] = $this->getWechatOpenid(); + } + } + // 支付宝支付时需要的附加数据 + if ($this->method === PaymentMethodEnum::ALIPAY) { + // 支付宝小程序端需要buyerId + if ($this->client == ClientEnum::MP_ALIPAY) { + $extra['buyerId'] = $this->getAlipayBuyerId(); + } + } + return $extra; + } + + /** + * 获取微信端的用户openid(仅微信小程序和微信公众号) + * @return null + * @throws BaseException + */ + private function getWechatOpenid() + { + if (in_array($this->client, [ClientEnum::MP_WEIXIN, ClientEnum::WXOFFICIAL])) { + // 当前登录用户信息 + $useInfo = UserService::getCurrentLoginUser(true); + if (!$useInfo['currentOauth'] || empty($useInfo['currentOauth']['oauth_id'])) { + throwError('很抱歉,您当前不存在openid 无法发起微信支付'); + } + // 当前第三方用户标识 + return $useInfo['currentOauth']['oauth_id']; + } + return null; + } + + /** + * 订单支付事件 + * @return void + * @throws BaseException + * @author: wanghousheng + */ + private function orderPayEvent(): void + { + // 余额支付 + if ($this->method == PaymentMethodEnum::BALANCE) { + $this->orderPaySuccess($this->orderInfo['order_no']); + } + } + + /** + * 订单支付成功事件 + * @param string $orderNo 当前订单号 + * @param int|null $tradeId + * @param array $paymentData + * @return void + * @throws BaseException + * @author: wanghousheng + */ + private function orderPaySuccess(string $orderNo, ?int $tradeId = null, array $paymentData = []): void + { + $service = new PaySuccess(); + // 订单支付成功业务处理 + $service->setOrderNo($orderNo) + ->setMethod($this->method) + ->setTradeId($tradeId) + ->setPaymentData($paymentData); + if (!$service->handle()) { + throwError($service->getError() ?: '申请失败'); + } + $this->message = '恭喜您,申请成功'; + } + + /** + * 查询订单是否支付成功 (仅限第三方支付订单) + * @param string $outTradeNo 商户订单号 + * @return bool + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function tradeQuery(string $outTradeNo): bool + { + // 获取支付方式的配置信息 + $options = $this->getPaymentConfig(); + // 构建支付模块 + $Payment = PaymentFacade::store($this->method)->setOptions($options, $this->client); + // 执行第三方支付查询API + $result = $Payment->tradeQuery($outTradeNo); + // 订单支付成功事件 + if (!empty($result) && $result['paySuccess']) { + // 获取第三方交易记录信息 + $tradeInfo = PaymentTradeModel::detailByOutTradeNo($outTradeNo); + // 订单支付成功事件 + $this->orderPaySuccess($tradeInfo['order_no'], $tradeInfo['trade_id'], $result); + } + // 返回订单状态 + return $result ? $result['paySuccess'] : false; + } + + /** + * 获取支付宝端的用户buyerId(仅支付宝小程序端) + * @return null + * @throws BaseException + */ + private function getAlipayBuyerId() + { + if ($this->client == ClientEnum::MP_ALIPAY) { + // 当前登录用户信息 + $useInfo = UserService::getCurrentLoginUser(true); + if (!$useInfo['currentOauth'] || empty($useInfo['currentOauth']['oauth_id'])) { + throwError('很抱歉,您当前不存在buyerId 无法发起支付宝支付'); + } + // 当前第三方用户标识 + return $useInfo['currentOauth']['oauth_id']; + } + return null; + } + + /** + * 创建订单 + * @param array $data + * @return Order + * @throws BaseException + */ + private function createOrder(array $data): Order + { + $model = new Order(); + if (!$model->createOrder($data)) { + throwError($model->getError() ?: '创建订单失败'); + } + $model['order_id'] = (int)$model['order_id']; + return $model; + } +} \ No newline at end of file diff --git a/app/api/service/wholesaler/Wholesaler.php b/app/api/service/wholesaler/Wholesaler.php new file mode 100644 index 00000000..096f586e --- /dev/null +++ b/app/api/service/wholesaler/Wholesaler.php @@ -0,0 +1,104 @@ +method = $method; + return $this; + } + + /** + * 设置下单的客户端 + * @param string $client 客户端 + * @return $this + */ + public function setClient(string $client): Wholesaler + { + $this->client = $client; + return $this; + } + + /** + * 开通批发商页面数据 + * @return array + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function center(): array + { + // 当期用户信息 + $userInfo = UserService::getCurrentLoginUser(true); + // 获取充值方案列表 + $info = Set::detail(); + if (!$info->isEmpty()) { + $info = $info->toArray(); + } + //计算优惠价格 + // 根据指定客户端获取可用的支付方式 + $PaymentModel = new PaymentModel; + $methods = $PaymentModel->getMethodsByClient($this->client); + // 返回数据 + return [ + 'personal' => $userInfo, + 'info' => $info, + 'paymentMethods' => $methods + ]; + } + + /** + * 确认订单支付事件 + * @param array $data + * @param array $extra 附加数据 + * @return array[] + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function orderPay(array $data, array $extra = []): array + { + $PaymentService = new Payment(); + $result = $PaymentService->setMethod($this->method) + ->setClient($this->client) + ->orderPay($data, $extra); + $this->message = $PaymentService->getMessage(); + return $result; + } + + /** + * 返回消息提示 + * @return string + */ + public function getMessage(): string + { + return $this->message; + } +} \ No newline at end of file diff --git a/app/common/enum/OrderType.php b/app/common/enum/OrderType.php index bc7cc011..bfc05369 100644 --- a/app/common/enum/OrderType.php +++ b/app/common/enum/OrderType.php @@ -34,6 +34,9 @@ class OrderType extends EnumBasics // 回收订单 const RECOVERY = 50; + // 回收订单 + const WHOLESALER = 60; + // 余额充值订单 const RECHARGE = 100; @@ -68,6 +71,10 @@ class OrderType extends EnumBasics self::DEALER => [ 'name' => '开通分销订单', 'value' => self::DEALER, + ], + self::WHOLESALER => [ + 'name' => '开通采购商订单', + 'value' => self::WHOLESALER, ] ]; } diff --git a/app/common/enum/user/balanceLog/Scene.php b/app/common/enum/user/balanceLog/Scene.php index 07bdc686..a0bc8efb 100644 --- a/app/common/enum/user/balanceLog/Scene.php +++ b/app/common/enum/user/balanceLog/Scene.php @@ -39,6 +39,9 @@ class Scene extends EnumBasics //开通会员 const MEMBER = 80; + //开通采购商 + const WHOLESALER = 90; + /** * 获取订单类型值 * @return array @@ -75,8 +78,12 @@ class Scene extends EnumBasics 'name' => '开通会员', 'value' => self::MEMBER, 'describe' => '开通会员:%s', + ], + self::WHOLESALER => [ + 'name' => '开通采购商', + 'value' => self::WHOLESALER, + 'describe' => '开通采购商:%s', ] - ]; } } \ No newline at end of file diff --git a/app/common/model/wholesaler/Apply.php b/app/common/model/wholesaler/Apply.php new file mode 100644 index 00000000..00c9df5e --- /dev/null +++ b/app/common/model/wholesaler/Apply.php @@ -0,0 +1,19 @@ +recharge($target, $this->postForm())) { + if ($model->recharge($target, $this->postForm())) { return $this->renderSuccess('操作成功'); } return $this->renderError($model->getError() ?: '操作失败'); diff --git a/app/store/controller/wholesaler/Set.php b/app/store/controller/wholesaler/Set.php new file mode 100644 index 00000000..80ff50eb --- /dev/null +++ b/app/store/controller/wholesaler/Set.php @@ -0,0 +1,39 @@ +renderSuccess(compact('info')); + } + + public function setData(): Json + { + $price = helper::number2($this->request->post('price')); + if ($price <= 0) { + return $this->renderError('价格不能为空'); + } + $year = intval($this->request->post('year')); + if ($year <= 0) { + return $this->renderError('年限不能为空'); + } + $info = \app\store\model\wholesaler\Set::detail(); + $model = new \app\store\model\wholesaler\Set(); + if (!empty($info->id)) { + $res = $model->edit(compact('price', 'year')); + } else { + $res = $model->add(compact('price', 'year')); + } + if ($res) { + return $this->renderSuccess('操作成功'); + } + return $this->renderError('操作失败'); + } +} \ No newline at end of file diff --git a/app/store/model/wholesaler/Set.php b/app/store/model/wholesaler/Set.php new file mode 100644 index 00000000..42aa7884 --- /dev/null +++ b/app/store/model/wholesaler/Set.php @@ -0,0 +1,31 @@ +save($data); + } + + /** + * @notes:编辑 + * @param $data + * @return bool + * @author: wanghousheng + */ + public function edit($data): bool + { + return $this->update($data) != false; + } +} \ No newline at end of file From 3bdc6a36fc2330a9f7df3bf07e44f8f3a7bbfeea Mon Sep 17 00:00:00 2001 From: wang hou sheng <76928547+wanghousheng@users.noreply.github.com> Date: Wed, 3 Apr 2024 01:44:45 +0800 Subject: [PATCH 2/5] 1 --- app/api/controller/Wholesaler.php | 93 +++++++++++++++++++++++++++ app/api/model/wholesaler/Apply.php | 40 ++++++++++++ app/common/enum/WholesalerEnum.php | 35 ++++++++++ app/common/model/wholesaler/Apply.php | 84 +++++++++++++++++++++++- 4 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 app/common/enum/WholesalerEnum.php diff --git a/app/api/controller/Wholesaler.php b/app/api/controller/Wholesaler.php index a32f0b18..fbf6bf72 100644 --- a/app/api/controller/Wholesaler.php +++ b/app/api/controller/Wholesaler.php @@ -2,6 +2,7 @@ namespace app\api\controller; +use app\api\model\wholesaler\Apply; use app\api\model\wholesaler\Set; use cores\exception\BaseException; use think\db\exception\DataNotFoundException; @@ -125,4 +126,96 @@ class Wholesaler extends Controller return $this->renderSuccess($data, $service->getMessage() ?: '申请成功'); } + /** + * @notes:申请记录详情 + * @return Json + * @throws BaseException + * @author: wanghousheng + */ + public function applyInfo(): Json + { + $info = Apply::info(['cardFrontImg', 'cardBackImg', 'licenseImg', 'doorImg']); + if (!empty($info->cardFrontImg)) { + unset($info->cardFrontImg); + } + if (!empty($info->cardBackImg)) { + unset($info->cardBackImg); + } + if (!empty($info->licenseImg)) { + unset($info->licenseImg); + } + if (!empty($info->doorImg)) { + unset($info->doorImg); + } + return $this->renderSuccess(compact('info')); + } + + /** + * @notes:编辑申请记录 + * @return Json + * @throws BaseException + * @author: wanghousheng + */ + public function editApply(): Json + { + $username = $this->request->post('username'); + if (!$username) { + return $this->renderError('姓名不能为空'); + } + $mobile = $this->request->post('mobile'); + if (!$mobile) { + return $this->renderError('手机号不能为空'); + } + $mobile_code = $this->request->post('mobile_code'); + if (!$mobile_code) { + return $this->renderError('手机号验证码不能为空'); + } + $card_front_img_id = intval($this->request->post('card_front_img_id')); + if (!$card_front_img_id) { + return $this->renderError('身份证正面不能为空'); + } + $card_back_img_id = intval($this->request->post('card_back_img_id')); + if (!$card_back_img_id) { + return $this->renderError('身份证反面不能为空'); + } + $license_img_id = intval($this->request->post('license_img_id')); + if (!$license_img_id) { + return $this->renderError('营业执照不能为空'); + } + $card_no = $this->request->post('card_no'); + if (!$card_no) { + return $this->renderError('身份证号不能为空'); + } + $door_img_id = intval($this->request->post('door_img_id')); + if (!$door_img_id) { + return $this->renderError('门口照片不能为空'); + } + $province_id = intval($this->request->post('province_id')); + if (!$province_id) { + return $this->renderError('省份不能为空'); + } + $city_id = intval($this->request->post('city_id')); + if (!$city_id) { + return $this->renderError('城市不能为空'); + } + $company_name = $this->request->post('company_name'); + if (!$company_name) { + return $this->renderError('公司名称不能为空'); + } + $credit_code = $this->request->post('credit_code'); + if (!$credit_code) { + return $this->renderError('社会信用代码不能为空'); + } + $business = $this->request->post('business'); + if (!$business) { + return $this->renderError('经营类目不能为空'); + } + $data = compact('company_name', 'credit_code', 'city_id', 'province_id', 'door_img_id', 'business', 'card_no'); + $data = array_merge($data, compact('username', 'mobile', 'card_back_img_id', 'card_front_img_id', 'license_img_id')); + if ((new Apply())->edit($data)) { + return $this->renderSuccess('操作成功'); + } + return $this->renderError('操作失败'); + } + } \ No newline at end of file diff --git a/app/api/model/wholesaler/Apply.php b/app/api/model/wholesaler/Apply.php index 15e6d875..83037f27 100644 --- a/app/api/model/wholesaler/Apply.php +++ b/app/api/model/wholesaler/Apply.php @@ -2,6 +2,10 @@ namespace app\api\model\wholesaler; +use app\api\service\User as UserService; +use app\common\enum\WholesalerEnum; +use cores\exception\BaseException; + class Apply extends \app\common\model\wholesaler\Apply { /** @@ -12,6 +16,9 @@ class Apply extends \app\common\model\wholesaler\Apply 'create_time', 'update_time', 'store_id', + 'id', + 'order_id', + 'year' ]; /** @@ -24,4 +31,37 @@ class Apply extends \app\common\model\wholesaler\Apply { return $this->save($data); } + + /** + * @notes:详情 + * @throws BaseException + * @author: wanghousheng + */ + public static function info($with = []) + { + $userId = UserService::getCurrentLoginUserId(); + return self::detail(['user_id' => $userId], $with); + } + + /** + * @notes:更新记录 + * @param array $data + * @return bool + * @throws BaseException + * @author: wanghousheng + */ + public function edit(array $data): bool + { + $info = self::info(); + empty($info) && throwError('申请记录不存在'); + $info = $info->toArray(); + if ($info['status'] == WholesalerEnum::ADOPT) { + throwError('申请已通过无法编辑'); + } + $userId = UserService::getCurrentLoginUserId(); + if ($this->where(['user_id' => $userId])->update($data)) { + return true; + } + return false; + } } \ No newline at end of file diff --git a/app/common/enum/WholesalerEnum.php b/app/common/enum/WholesalerEnum.php new file mode 100644 index 00000000..422d7c30 --- /dev/null +++ b/app/common/enum/WholesalerEnum.php @@ -0,0 +1,35 @@ + [ + 'name' => '待审核', + 'value' => self::AUDITING, + ], + self::ADOPT => [ + 'name' => '已通过', + 'value' => self::ADOPT, + ], + self::REFUSE => [ + 'name' => '已拒绝', + 'value' => self::REFUSE, + ], + ]; + } +} \ No newline at end of file diff --git a/app/common/model/wholesaler/Apply.php b/app/common/model/wholesaler/Apply.php index 00c9df5e..8e00df78 100644 --- a/app/common/model/wholesaler/Apply.php +++ b/app/common/model/wholesaler/Apply.php @@ -2,7 +2,14 @@ namespace app\common\model\wholesaler; +use app\common\enum\WholesalerEnum; +use app\common\model\Region as RegionModel; +use app\common\model\UploadFile; use cores\BaseModel; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\model\relation\HasOne; class Apply extends BaseModel { @@ -12,8 +19,81 @@ class Apply extends BaseModel // 定义主键 protected $pk = 'id'; - public static function detail($where) + protected $append = ['region', 'status_text']; + + public static function detail($where, $with = []) + { + return static::get($where, $with); + } + + + /** + * 身份证正面图片 + * @return HasOne + */ + public function cardFrontImg(): HasOne + { + return $this->hasOne(UploadFile::class, 'file_id', 'card_front_img_id') + ->bind(['card_front_img' => 'preview_url']); + } + + /** + * 身份证反面图片 + * @return HasOne + */ + public function cardBackImg(): HasOne + { + return $this->hasOne(UploadFile::class, 'file_id', 'card_back_img_id') + ->bind(['card_back_img' => 'preview_url']); + } + + /** + * 营业执照 + * @return HasOne + */ + public function licenseImg(): HasOne { - return self::get($where); + return $this->hasOne(UploadFile::class, 'file_id', 'license_img_id') + ->bind(['license_img' => 'preview_url']); } + + /** + * 门头照片 + * @return HasOne + */ + public function doorImg(): HasOne + { + return $this->hasOne(UploadFile::class, 'file_id', 'door_img_id') + ->bind(['door_img' => 'preview_url']); + } + + /** + * @notes:地区名称 + * @param $value + * @param $data + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author: wanghousheng + */ + public function getRegionAttr($value, $data): array + { + return [ + 'province' => RegionModel::getNameById($data['province_id']), + 'city' => RegionModel::getNameById($data['city_id']), + ]; + } + + public function getStatusTextAttr($value, $data) + { + // 状态 + $result = WholesalerEnum::data(); + if (!empty($result[$data['status']]['name'])) { + return $result[$data['status']]['name']; + } + return '未知'; + } + + } \ No newline at end of file From b2be5c5533a8740c43fb8d1c5ae40b01aa02418d Mon Sep 17 00:00:00 2001 From: wang hou sheng <76928547+wanghousheng@users.noreply.github.com> Date: Wed, 3 Apr 2024 01:50:33 +0800 Subject: [PATCH 3/5] 1 --- app/api/controller/Wholesaler.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/api/controller/Wholesaler.php b/app/api/controller/Wholesaler.php index fbf6bf72..cca416ee 100644 --- a/app/api/controller/Wholesaler.php +++ b/app/api/controller/Wholesaler.php @@ -9,6 +9,7 @@ use think\db\exception\DataNotFoundException; use think\db\exception\DbException; use think\db\exception\ModelNotFoundException; use think\response\Json; +use yiovo\captcha\CaptchaApi; class Wholesaler extends Controller { @@ -68,12 +69,6 @@ class Wholesaler extends Controller if (!$mobile_code) { return $this->renderError('手机号验证码不能为空'); } - // 验证短信验证码是否匹配 -// try { -// CaptchaApi::checkSms($mobile_code, $mobile); -// } catch (Exception $e) { -// return $this->renderError($e->getMessage() ?: '短信验证码不正确'); -// } $card_front_img_id = intval($this->request->post('card_front_img_id')); if (!$card_front_img_id) { return $this->renderError('身份证正面不能为空'); @@ -114,6 +109,12 @@ class Wholesaler extends Controller if (!$business) { return $this->renderError('经营类目不能为空'); } + // 验证短信验证码是否匹配 + try { + CaptchaApi::checkSms($mobile_code, $mobile); + } catch (Exception $e) { + return $this->renderError($e->getMessage() ?: '短信验证码不正确'); + } $data = compact('company_name', 'credit_code', 'city_id', 'province_id', 'door_img_id', 'business', 'card_no'); $data = array_merge($data, compact('username', 'mobile', 'card_back_img_id', 'card_front_img_id', 'license_img_id')); $data['total_price'] = $priceInfo['price']; @@ -210,6 +211,12 @@ class Wholesaler extends Controller if (!$business) { return $this->renderError('经营类目不能为空'); } + // 验证短信验证码是否匹配 + try { + CaptchaApi::checkSms($mobile_code, $mobile); + } catch (Exception $e) { + return $this->renderError($e->getMessage() ?: '短信验证码不正确'); + } $data = compact('company_name', 'credit_code', 'city_id', 'province_id', 'door_img_id', 'business', 'card_no'); $data = array_merge($data, compact('username', 'mobile', 'card_back_img_id', 'card_front_img_id', 'license_img_id')); if ((new Apply())->edit($data)) { From 96c7082f32b3d975a2777b6da5060005de44d3bf Mon Sep 17 00:00:00 2001 From: wang hou sheng <76928547+wanghousheng@users.noreply.github.com> Date: Wed, 3 Apr 2024 03:44:11 +0800 Subject: [PATCH 4/5] 1 --- app/common/model/wholesaler/Apply.php | 5 + app/store/controller/wholesaler/Apply.php | 114 ++++++++++++++++++++++ app/store/model/wholesaler/Apply.php | 8 ++ 3 files changed, 127 insertions(+) create mode 100644 app/store/controller/wholesaler/Apply.php create mode 100644 app/store/model/wholesaler/Apply.php diff --git a/app/common/model/wholesaler/Apply.php b/app/common/model/wholesaler/Apply.php index 8e00df78..5a0e8582 100644 --- a/app/common/model/wholesaler/Apply.php +++ b/app/common/model/wholesaler/Apply.php @@ -5,6 +5,7 @@ namespace app\common\model\wholesaler; use app\common\enum\WholesalerEnum; use app\common\model\Region as RegionModel; use app\common\model\UploadFile; +use app\common\model\User; use cores\BaseModel; use think\db\exception\DataNotFoundException; use think\db\exception\DbException; @@ -26,6 +27,10 @@ class Apply extends BaseModel return static::get($where, $with); } + public function user(): HasOne + { + return $this->hasOne(User::class, 'user_id', 'user_id'); + } /** * 身份证正面图片 diff --git a/app/store/controller/wholesaler/Apply.php b/app/store/controller/wholesaler/Apply.php new file mode 100644 index 00000000..e0e9d6d1 --- /dev/null +++ b/app/store/controller/wholesaler/Apply.php @@ -0,0 +1,114 @@ +renderSuccess(compact('list')); + } + + /** + * @notes:申请记录 + * @return Json + * @throws DbException + * @author: wanghousheng + */ + public function list(): Json + { + $username = $this->request->post('username'); + $mobile = $this->request->post('mobile'); + $company_name = $this->request->post('company_name'); + $status = intval($this->request->post('status')); + $where = []; + if (!empty($username)) { + $where[] = ['username', 'like', "%$username%"]; + } + if (!empty($company_name)) { + $where[] = ['company_name', 'like', "%$company_name%"]; + } + if (!empty($mobile)) { + $where[] = ['mobile', 'like', "%$mobile%"]; + } + if ($status) { + $where[] = ['status', '=', $status]; + } + $model = new \app\store\model\wholesaler\Apply(); + $list = $model->where($where) + ->with(['user']) + ->order('id', 'desc') + ->paginate(15); + $data['list'] = $list->items(); + $data['total'] = $list->total(); + return $this->renderSuccess($data); + } + + public function detail(): Json + { + $id = intval($this->request->post('id')); + $info = \app\store\model\wholesaler\Apply::detail(['id' => $id], ['cardFrontImg', 'cardBackImg', 'licenseImg', 'doorImg', 'user']); + return $this->renderSuccess(compact('info')); + } + + /** + * @notes:审核 + * @return Json + * @throws Exception + * @author: wanghousheng + */ + public function audit(): Json + { + $id = intval($this->request->post('id')); + if (!$id) { + return $this->renderError('非法请求'); + } + $status = intval($this->request->post('status')); + if (!$status) { + return $this->renderError('非法请求'); + } + $remake = $this->request->post('remake'); + if ($status == WholesalerEnum::REFUSE && !$remake) { + return $this->renderError('驳回原因不能为空'); + } + $info = \app\store\model\wholesaler\Apply::detail(['id' => $id]); + if (empty($info)) { + return $this->renderError('数据异常'); + } + $info = $info->toArray(); + if ($info['status'] != WholesalerEnum::AUDITING) { + return $this->renderError('非法操作'); + } + //更新记录 + $model = new \app\store\model\wholesaler\Apply(); + $model->transaction(function () use ($status, $remake, $info, $model) { + $model->where(['id' => $info['id']])->update(['status' => $status, 'remake' => $remake]); + //通过开通采购商会员 + if ($status == WholesalerEnum::ADOPT) { + $date = new DateTime(date('Y-m-d')); + $date->add(new DateInterval("P{$info['year']}Y")); + $up['effective_time'] = $date->format('Y-m-d'); + $up['user_type'] = UserTypeEnum::MEMBER; + $userModel = new UserModel(); + $userModel->where(['user_id' => $info['user_id']])->save($up); + } + }); + return $this->renderSuccess('操作成功'); + } +} \ No newline at end of file diff --git a/app/store/model/wholesaler/Apply.php b/app/store/model/wholesaler/Apply.php new file mode 100644 index 00000000..58e6c393 --- /dev/null +++ b/app/store/model/wholesaler/Apply.php @@ -0,0 +1,8 @@ + Date: Wed, 3 Apr 2024 04:29:59 +0800 Subject: [PATCH 5/5] 1 --- app/common/model/Goods.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/common/model/Goods.php b/app/common/model/Goods.php index e4f2cb9f..16b48c3d 100644 --- a/app/common/model/Goods.php +++ b/app/common/model/Goods.php @@ -451,6 +451,9 @@ class Goods extends BaseModel if (isset($param['channel']) && $param['channel'] !== '') { $filter[] = ['goods.channel', '=', $params['channel']]; } + if (isset($param['is_grab']) && $param['is_grab'] !== '') { + $filter[] = ['goods.is_grab', '=', intval($params['is_grab'])]; + } if (isset($param['is_self']) && $param['is_self'] !== '') { $filter[] = ['goods.is_self', '=', $params['is_self']]; }