diff --git a/app/admin/controller/Wxwholesaler.php b/app/admin/controller/Wxwholesaler.php index 7ba5dd0b..2058fa0a 100644 --- a/app/admin/controller/Wxwholesaler.php +++ b/app/admin/controller/Wxwholesaler.php @@ -188,6 +188,20 @@ class Wxwholesaler extends Controller return $this->renderError('操作失败'); } + public function commitOne(): Json + { + $appid = $this->request->get('appid'); + $obj = new Wholesaler(); + $msg = $obj->privacyInfo($appid); + if ($msg == 'ok') { + $msg = $obj->submitAudit($appid); + if ($msg == 'ok') { + return $this->renderSuccess('success'); + } + } + return $this->renderError($msg); + } + /** * @notes:获取版本信息 * @return Json diff --git a/app/api/controller/Retail.php b/app/api/controller/Retail.php new file mode 100644 index 00000000..5503a1da --- /dev/null +++ b/app/api/controller/Retail.php @@ -0,0 +1,91 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); +namespace app\api\controller; + +use think\response\Json; +use app\api\model\Retail as RetailModel; +use app\api\model\RetailOrder as RetailOrderModel; +use app\api\model\Agreement as AgreementModel; +use app\api\service\order\Checkout as CheckoutService; + +class Retail extends Controller +{ + + /** + * 获取零售批发会员列表 + * @param int $retailType + * @return Json + */ + public function list(int $retailType): Json + { + $list = RetailModel::withoutGlobalScope()->where('retail_type',$retailType)->where('retail_status',10)->select(); + return $this->renderSuccess(compact('list')); + } + + /** + * 获取软件付费协议 + * @return Json + */ + public function getSoftAgreement(): Json + { + $params = $this->request->param(); + if (empty($params['type'])) { + return $this->renderSuccess("参数错误"); + } + $detail = AgreementModel::detail(['type' => $params['type']]); + if (!empty($detail->content)) { + $detail->content = str_ireplace('nowrap', 'inherit', $detail->content); + } + return $this->renderSuccess(compact('detail')); + } + + + /** + * 获取零售批发会员列表 + * @param int $retailType + * @return Json + */ + public function retailPayList(): Json + { + $client = $this->request->post(); + if (!$client['client']) { + return $this->renderError('客户端不能为空'); + } + $model =new \app\api\model\user\Retail(); + $list = $model->userCenter($client); + + return $this->renderSuccess(compact('list')); + } + + public function submit(): Json + { + $method = $this->request->post('method'); + if (!$method) { + return $this->renderError('支付方式不能为空'); + } + $client = $this->request->post('client'); + if (!$client) { + return $this->renderError('客户端不能为空'); + } + $retailPriceId = intval($this->request->post('retail_price_id')); + if (!$retailPriceId) { + return $this->renderError('缺少必要参数'); + } + $service = new \app\api\service\Retail(); + $data = $service->setMethod($method) + ->setClient($client) + ->orderPay($retailPriceId); + return $this->renderSuccess($data, $service->getMessage() ?: '下单成功'); + } + + +} \ No newline at end of file diff --git a/app/api/model/Retail.php b/app/api/model/Retail.php new file mode 100644 index 00000000..e260138a --- /dev/null +++ b/app/api/model/Retail.php @@ -0,0 +1,114 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\api\model; +use app\common\model\Retail as RetailModel; +use app\api\model\Payment as PaymentModel; +use app\api\service\identity\Payment; +use app\api\service\User as UserService; + +class Retail extends RetailModel +{ + // 提示信息 + private string $message = ''; + + // 支付方式 (微信支付、支付宝、余额) + private string $method; + + // 下单的客户端 + private string $client; + + //隐藏字段 + protected $hidden = [ + 'create_time', + 'update_time', + 'store_id', + ]; + + public function setMethod(string $method): Retail + { + $this->method = $method; + return $this; + } + public static function getRetailList() + { + return self::select(); + } + /** + * 设置下单的客户端 + * @param string $client 客户端 + * @return $this + */ + public function setClient(string $client): Retail + { + $this->client = $client; + return $this; + } + + /** + * 返回消息提示 + * @return string + */ + public function getMessage(): string + { + return $this->message; + } + + + public static function detail(array $where = []) + { + $where = [ + 'retail_price_id'=>$where['retail_price_id'], + 'retail_status'=>10 + ]; + + return RetailModel::where($where)->select(); + } + + + + private function cheapPrice($data): array + { + $one_data = $data[0]; + + foreach ($data as $key => $value) { + $data[$key]['cheap_price'] = 0; + if (!empty($one_data)) { + if ($key > 0) { + $price = $value['month'] * $one_data['price']; + $data[$key]['cheap_price'] = $price - $value['price']; + } + } + } + return $data; + } + + /** + * 确认订单支付事件 + * @param int $identityId + * @param array $extra 附加数据 + * @return array[] + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function orderPay(int $identityId, array $extra = []): array + { + $PaymentService = new Payment(); + $result = $PaymentService->setMethod($this->method) + ->setClient($this->client) + ->orderPay($identityId, $extra); + $this->message = $PaymentService->getMessage(); + return $result; + } +} \ No newline at end of file diff --git a/app/api/model/RetailOrder.php b/app/api/model/RetailOrder.php new file mode 100644 index 00000000..2d682503 --- /dev/null +++ b/app/api/model/RetailOrder.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\api\model; +use app\common\model\RetailOrder as RetailOrderModel; + +class RetailOrder extends RetailOrderModel +{ + + +} \ No newline at end of file diff --git a/app/api/model/user/Retail.php b/app/api/model/user/Retail.php new file mode 100644 index 00000000..e0e231fb --- /dev/null +++ b/app/api/model/user/Retail.php @@ -0,0 +1,20 @@ + UserService::getCurrentLoginUserId(),//用户id + 'order_no' => OrderService::createOrderNo(),//订单号 + 'retail_price_id' => $identityInfo['retail_price_id'],//会员id + 'order_type' => $identityInfo['retail_type'],//订单类型 + 'pay_price' => $price, + 'year' => $identityInfo['year'], + 'platform' => getPlatform(), + 'pay_method' => $method, + 'store_id' => self::$storeId, + ]; + return $this->save($data); + } + + /** + * 获取订单详情 (待付款状态) + * @param string $orderNo 订单号 + * @return array|null|static + */ + public static function getPayDetail(string $orderNo) + { + return self::detail(['order_no' => $orderNo]); + } + + /** + * @notes:编辑 + * @param $data + * @return bool + * @author: wanghousheng + */ + public function edit($data): bool + { + return $this->save($data) !== false; + } + + public function identity(): HasOne + { + return $this->hasOne(Identity::class, 'identity_id', 'identity_id') + ->bind(['identity_name' => 'name']); + } + + /** + * @notes:开卡记录 + * @param array $where + * @return array + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author: wanghousheng + */ + public function cardList(array $where = []): array + { + $userId = UserService::getCurrentLoginUserId(); + $params['user_id'] = $userId; + $params['pay_status'] = PayStatus::SUCCESS; + $where = array_merge($where, $params); + $list = $this->where($where) + ->with(['identity']) + ->order('pay_time', 'desc') + ->limit(20) + ->select(); + $data = []; + if (!empty($list)) { + foreach ($list as $value) { + $end_time = date("Y-m-d", strtotime("+{$value['month']} months", $value['pay_time'])); + $is_valid = false; + if (strtotime(date("Y-m-d")) < strtotime($end_time)) { + $is_valid = true; + } + $data[] = [ + 'start_time' => date("Y-m-d", $value['pay_time']), + 'end_time' => $end_time, + 'name' => $value['identity_name'], + 'month' => $value['month'], + 'is_valid' => $is_valid + ]; + } + } + return $data; + } +} \ No newline at end of file diff --git a/app/api/service/Retail.php b/app/api/service/Retail.php new file mode 100644 index 00000000..f10baaad --- /dev/null +++ b/app/api/service/Retail.php @@ -0,0 +1,142 @@ +method = $method; + return $this; + } + + /** + * 设置下单的客户端 + * @param string $client 客户端 + * @return $this + */ + public function setClient(string $client): Retail + { + $this->client = $client; + return $this; + } + + /** + * 开通会员页面数据 + * @param string $client 当前客户端 + * @return array + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function userCenter(array $client): array + { + // 当期用户信息 + $userInfo = UserService::getCurrentLoginUser(true); +// //是否分销商 +// if (UserService::isDealerMember() || UserService::isStore()) { +// throwError('非法操作'); +// } + // 获取充值方案列表 + $model = new RetailModel(); + $planList = $model->getList(['retail_type' => $client['retail_type']]); + if (!$planList->isEmpty()) { + // $planList = $this->cheapPrice($planList->toArray()); + } + //计算优惠价格 + // 根据指定客户端获取可用的支付方式 + $PaymentModel = new PaymentModel; + $methods = $PaymentModel->getMethodsByClient($client['client']); + // 返回数据 + return [ + 'personal' => $userInfo, + 'list' => $planList, + 'paymentMethods' => $methods + ]; + } + + private function cheapPrice($data): array + { + $one_data = $data[0]; + foreach ($data as $key => $value) { + $data[$key]['cheap_price'] = 0; + if (!empty($one_data)) { + if ($key > 0) { + $price = $value['month'] * $one_data['price']; + $data[$key]['cheap_price'] = $price - $value['price']; + } + } + } + return $data; + } + + /** + * 确认订单支付事件 + * @param int $identityId + * @param array $extra 附加数据 + * @return array[] + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function orderPay(int $identityId, array $extra = []): array + { + $PaymentService = new Payment(); + $result = $PaymentService->setMethod($this->method) + ->setClient($this->client) + ->orderPay($identityId); + $this->message = $PaymentService->getMessage(); + return $result; + } + + /** + * 交易查询 + * 查询第三方支付订单是否付款成功 + * @param string $outTradeNo 商户订单号 + * @return bool + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function tradeQuery(string $outTradeNo): bool + { + $PaymentService = new Payment(); + return $PaymentService->setMethod($this->method)->setClient($this->client)->tradeQuery($outTradeNo); + } + + /** + * 返回消息提示 + * @return string + */ + public function getMessage(): string + { + return $this->message; + } +} \ No newline at end of file diff --git a/app/api/service/Retail/PaySuccess.php b/app/api/service/Retail/PaySuccess.php new file mode 100644 index 00000000..76cd928f --- /dev/null +++ b/app/api/service/Retail/PaySuccess.php @@ -0,0 +1,409 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\api\service\identity; + +use app\api\model\PaymentTrade as PaymentTradeModel; +use app\api\model\recharge\Order as OrderModel; +use app\api\model\User as UserModel; +use app\api\model\user\BalanceLog as BalanceLogModel; +use app\api\model\user\IdentityOrder; +use app\common\enum\order\PayStatus; +use app\common\enum\payment\Method as PaymentMethodEnum; +use app\common\enum\recharge\order\PayStatus as PayStatusEnum; +use app\common\enum\user\balanceLog\Scene as SceneEnum; +use app\common\enum\user\IdentityEnum; +use app\common\enum\user\UserTypeEnum; +use app\common\library\Lock; +use app\common\library\Log; +use app\common\service\BaseService; +use app\store\model\dealer\User; +use cores\exception\BaseException; + +/** + * 余额充值订单支付成功服务类 + * Class PaySuccess + * @package app\api\service\order + */ +class PaySuccess extends BaseService +{ + // 当前订单信息 + public IdentityOrder $orderInfo; + + // 当前用户信息 + private UserModel $userInfo; + + // 当前订单号 + private string $orderNo; + + // 当前订单ID + private int $orderId; + + // 订单支付方式 + private string $method; + + // 第三方交易记录ID + private ?int $tradeId = null; + + // 第三方支付成功返回的数据 + private array $paymentData = []; + + private int $type; + + /** + * 设置支付的订单ID + * @param int $orderId 订单ID + */ + public function setOrderId(int $orderId): PaySuccess + { + $this->orderId = $orderId; + return $this; + } + + public function setType($type): PaySuccess + { + $this->type = $type; + 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; + } + + /** + * 验证当前参数是否合法 + * @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 IdentityOrder|null + * @throws BaseException + */ + private function orderModel(): ?IdentityOrder + { + 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->activate(); + }); + } + + + /** + * 记录订单支付的信息 + * @throws BaseException + */ + private function updatePayInfo() + { + // 当前订单信息 + $orderInfo = $this->getOrderInfo(); + // 余额支付 + if ($this->method == PaymentMethodEnum::BALANCE) { + // 更新用户余额 + UserModel::setDecBalance((int)$orderInfo['user_id'], (float)$orderInfo['pay_price']); + // 新增余额变动记录 + $type = SceneEnum::MEMBER; + if ($this->type == IdentityEnum::DEALER) { + $type = SceneEnum::DEALER; + } + BalanceLogModel::add($type, [ + '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; + } + + /** + * 验证当前订单是否允许支付 + * @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 OrderModel|null + * @throws BaseException + */ + private function getOrderInfo(): ?IdentityOrder + { + // 获取订单详情 (待支付状态) + if (empty($this->orderInfo)) { + $this->orderInfo = IdentityOrder::getPayDetail($this->orderNo); + } + // 判断订单是否存在 + if (empty($this->orderInfo)) { + throwError('未找到该订单信息'); + } + return $this->orderInfo; + } + + /** + * 订单锁:防止并发导致重复支付 + * @throws BaseException + */ + private function lockUp() + { + $orderInfo = $this->getOrderInfo(); + Lock::lockUp("IdentityOrderPaySuccess_{$orderInfo['order_id']}"); + } + + /** + * 订单锁:防止并发导致重复支付 + * @throws BaseException + */ + private function unLock() + { + $orderInfo = $this->getOrderInfo(); + Lock::unLock("IdentityOrderPaySuccess_{$orderInfo['order_id']}"); + } + + /** + * @notes:修改会员身份信息 + * @throws BaseException + * @author: wanghousheng + */ + private function activate(): void + { + $orderInfo = $this->getOrderInfo(); + $userInfo = $this->getUserInfo(); + //判断当前用户角色 + $orderType = $orderInfo['order_type']; + $userType = $userInfo['user_type']; + if ($userType == UserTypeEnum::STORE) { + return; + } + $userModel = new UserModel(); + $up = []; + $time = date('Y-m-d'); + //已经是会员或者未开通会员 + if ($orderType == IdentityEnum::MEMBER && $userType != UserTypeEnum::DEALER) { + $up['user_type'] = UserTypeEnum::MEMBER; + //已经是会员 + if ($userType == UserTypeEnum::MEMBER) { + //是否到期 + if (!empty($userInfo['effective_time']) && strtotime($userInfo['effective_time']) > strtotime(date('Y-m-d'))) { + $time = $userInfo['effective_time']; + } + } + $up['effective_time'] = date("Y-m-d", strtotime("+{$orderInfo['month']} months", strtotime($time))); + } else { + $up['user_type'] = UserTypeEnum::DEALER; + //已经是分销商 + if ($userType == UserTypeEnum::DEALER) { + //是否到期 + if (!empty($userInfo['fx_effective_time']) && strtotime($userInfo['fx_effective_time']) > strtotime(date('Y-m-d'))) { + $time = $userInfo['fx_effective_time']; + } + } + if (!User::isDealerUser($userInfo['user_id'])) { + // 新增分销商用户 + $model = new UserModel(); + $mobile = $model->where(['user_id' => $userInfo['user_id']])->value('mobile'); + User::add($userInfo['user_id'], [ + 'real_name' => $mobile, + 'mobile' => $mobile, + 'store_id' => $userInfo['store_id'] ?? 0, + ]); + } else { + //更新分销用户 + User::update(['is_delete' => 0], ['user_id' => $userInfo['user_id']]); + } + $up['fx_effective_time'] = date("Y-m-d", strtotime("+{$orderInfo['month']} months", strtotime($time))); + } + $userModel->where(['user_id' => $userInfo['user_id']])->save($up); + } +} \ No newline at end of file diff --git a/app/api/service/Retail/Payment.php b/app/api/service/Retail/Payment.php new file mode 100644 index 00000000..609d68ab --- /dev/null +++ b/app/api/service/Retail/Payment.php @@ -0,0 +1,344 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\api\service\Retail; + +use app\api\model\Payment as PaymentModel; +use app\api\model\PaymentTrade as PaymentTradeModel; +use app\api\model\Retail as RetailModel; +use app\api\model\user\Retail; +use app\api\model\user\RetailOrder; +use app\api\service\identity\PaySuccess as RetailPaySuccessService; +use app\api\service\Order as OrderService; +use app\api\service\User as UserService; +use app\common\enum\Client as ClientEnum; +use app\common\enum\OrderType as OrderTypeEnum; +use app\common\enum\payment\Method as PaymentMethodEnum; +use app\common\enum\user\IdentityEnum; +use app\common\library\payment\Facade as PaymentFacade; +use app\common\service\BaseService; +use cores\exception\BaseException; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * 开通会员/分销商订单付款服务类 + * Class Payment + * @package app\api\controller + */ +class Payment extends BaseService +{ + // 提示信息 + private string $message = ''; + + // 订单信息 + private RetailOrder $orderInfo; + + // 支付方式 (微信支付、支付宝,余额) + private string $method = ''; + + // 下单的客户端 + private string $client = ''; + + private int $type; + + /** + * 设置当前支付方式 + * @param string $method 支付方式 + * @return $this + */ + public function setMethod(string $method): Payment + { + $this->method = $method; + return $this; + } + + public function setType($type): Payment + { + $this->type = $type; + return $this; + } + + /** + * 设置下单的客户端 + * @param string $client 客户端 + * @return $this + */ + public function setClient(string $client): Payment + { + $this->client = $client; + return $this; + } + + /** + * 确认订单支付事件 + * @param int $retailPriceId + * @param array $extra 附加数据 + * @return array[] + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function orderPay(int $retailPriceId, array $extra = []): array + { + // 创建订单信息 + $this->orderInfo = $this->createOrder($retailPriceId); + // 订单支付事件 + $this->orderPayEvent(); + // 构建第三方支付请求的参数 + $payment = $this->unifiedorder($extra); + // 记录第三方交易信息 + $order_type = OrderTypeEnum::MEMBER;//开通会员 + if ($this->orderInfo['order_type'] == IdentityEnum::DEALER) { + $order_type = OrderTypeEnum::DEALER;//开通分销商 + } + $this->recordPaymentTrade($payment, $order_type); + // 返回结果 + return compact('payment'); + } + + /** + * 订单支付事件 + * @return void + * @throws BaseException + * @author: wanghousheng + */ + private function orderPayEvent(): void + { + // 余额支付 + if ($this->method == PaymentMethodEnum::BALANCE) { + $this->setType($this->orderInfo['order_type'])->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 RetailPaySuccessService(); + // 订单支付成功业务处理 + $service->setOrderNo($orderNo) + ->setMethod($this->method) + ->setTradeId($tradeId) + ->setType($this->type) + ->setPaymentData($paymentData); + if (!$service->handle()) { + throwError($service->getError() ?: '订单支付失败'); + } + $this->message = '恭喜您,订单支付成功'; + } + + /** + * 创建订单 + * @param int $identityId + * @return RetailOrder + * @throws BaseException + */ + private function createOrder(int $retailPriceId ,array $extra = []): RetailOrder + { + $extra = $this->request->post('year'); + $model = new RetailOrder(); + $info = Retail::detail(['retail_price_id' => $retailPriceId]); + $info['year'] = $extra; + if ($info->isEmpty()) { + throwError('记录不存在'); + } + //店主不可操作 + if (UserService::isStore()) { + throwError('非法操作'); + } + if (UserService::isDealerMember() && $info['type'] != IdentityEnum::DEALER) { + throwError('非法操作'); + } + if (!$model->createOrder($info->toArray(), $this->method)) { + throwError($model->getError() ?: '创建订单失败'); + } + $model['order_id'] = (int)$model['order_id']; + return $model; + } + + /** + * 查询订单是否支付成功 (仅限第三方支付订单) + * @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; + } + + /** + * 记录第三方交易信息 + * @param array $payment 第三方支付数据 + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + private function recordPaymentTrade(array $payment, int $orderType): void + { + if ($this->method != PaymentMethodEnum::BALANCE) { + PaymentTradeModel::record( + $this->orderInfo, + $this->method, + $this->client, + $orderType, + $payment + ); + } + } + + /** + * 返回消息提示 + * @return string + */ + public function getMessage(): string + { + return $this->message; + } + + /** + * 构建第三方支付请求的参数 + * @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(); + } + + /** + * 获取支付方式的配置信息 + * @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 + */ + 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; + } + + /** + * 获取支付宝端的用户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; + } +} \ No newline at end of file diff --git a/app/common/library/baidu/OcrLicense.php b/app/common/library/baidu/OcrLicense.php index a446a083..ab80e7d8 100644 --- a/app/common/library/baidu/OcrLicense.php +++ b/app/common/library/baidu/OcrLicense.php @@ -17,8 +17,8 @@ class OcrLicense public function __construct(string $clientId, string $clientSecret) { - $this->clientId = $clientId; - $this->clientSecret = $clientSecret; + $this->clientId = trim($clientId); + $this->clientSecret = trim($clientSecret); } public function check($img_url): array @@ -31,6 +31,7 @@ class OcrLicense $data['risk_warn'] = 'true'; $url = self::LICENSEURL . '?access_token=' . $token; $result = $this->post($url, $data); + $this->msg = json_encode($result); $this->validateData($result); return $this->resultHandle(); } diff --git a/app/common/library/wxserver/Server.php b/app/common/library/wxserver/Server.php index d7773552..595bfdef 100644 --- a/app/common/library/wxserver/Server.php +++ b/app/common/library/wxserver/Server.php @@ -660,6 +660,7 @@ class Server { $token = $this->authorizerAccessToken($appid); if ($token) { + $url = "https://api.weixin.qq.com/wxa/setwebviewdomain?access_token=$token"; $data['action'] = 'set'; $data['webviewdomain'] = $domain; diff --git a/app/common/library/wxserver/Wholesaler.php b/app/common/library/wxserver/Wholesaler.php index 7568d1b6..3a4136b1 100644 --- a/app/common/library/wxserver/Wholesaler.php +++ b/app/common/library/wxserver/Wholesaler.php @@ -508,9 +508,9 @@ class Wholesaler if ($token) { $url = "https://api.weixin.qq.com/wxa/modify_domain_directly?access_token=$token"; $data['action'] = 'set'; - $data['requestdomain'] = [$domain, 'https://apis.map.gg.com','https://qiniu.shop.royaum.com.cn']; - $data['uploaddomain'] = [$domain,'https://qiniu.shop.royaum.com.cn']; - $data['downloaddomain'] = [$domain,'https://qiniu.shop.royaum.com.cn']; + $data['requestdomain'] = [$domain, 'https://apis.map.gg.com', 'https://qiniu.shop.royaum.com.cn']; + $data['uploaddomain'] = [$domain, 'https://qiniu.shop.royaum.com.cn']; + $data['downloaddomain'] = [$domain, 'https://qiniu.shop.royaum.com.cn']; $result = $this->curlPost($url, json_encode($data)); Db::table('yoshop_wx_server')->insertGetId(['content' => "设置域名信息", 'created_at' => date('Y-m-d H:i:s')]); Db::table('yoshop_wx_server')->insertGetId(['content' => $result, 'created_at' => date('Y-m-d H:i:s')]); @@ -546,8 +546,6 @@ class Wholesaler $data['owner_setting']['contact_qq'] = '527264601'; $data['owner_setting']['notice_method'] = '公告'; $result = $this->curlPost($url, json_encode($data)); - Db::table('yoshop_wx_server')->insertGetId(['content' => "设置隐私信息", 'created_at' => date('Y-m-d H:i:s')]); - Db::table('yoshop_wx_server')->insertGetId(['content' => $result, 'created_at' => date('Y-m-d H:i:s')]); $result = json_decode($result, true); if ($result && !empty($result['errmsg']) && $result['errmsg'] == 'ok') { return true; @@ -659,8 +657,6 @@ class Wholesaler $data['action'] = 'set'; $data['webviewdomain'] = $domain; $result = $this->curlPost($url, json_encode($data)); - Db::table('yoshop_wx_server')->insertGetId(['content' => "业务域名", 'created_at' => date('Y-m-d H:i:s')]); - Db::table('yoshop_wx_server')->insertGetId(['content' => $result, 'created_at' => date('Y-m-d H:i:s')]); $result = json_decode($result, true); if ($result && !empty($result['errmsg']) && $result['errmsg'] == 'ok') { return true; @@ -698,8 +694,9 @@ class Wholesaler return 0; } - public function submitAudit($appid): bool + public function submitAudit($appid) { + $msg = 'ok'; $access_token = $this->authorizerAccessToken($appid); if ($access_token) { $url = 'https://api.weixin.qq.com/wxa/submit_audit?access_token=' . $access_token; @@ -718,11 +715,12 @@ class Wholesaler $up['audit_time'] = date('Y-m-d H:i:s'); $up['auditid'] = $result['auditid']; $model->update($up, ['appid' => $appid]); - return true; + } else { + $msg = !empty($result['errmsg']) ? $result['errmsg'] : '提交失败(未知错误)'; } } - return false; + return $msg; } /** diff --git a/app/common/model/Retail.php b/app/common/model/Retail.php new file mode 100644 index 00000000..8cc5eb98 --- /dev/null +++ b/app/common/model/Retail.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\common\model; + +use cores\BaseModel; + +class Retail extends BaseModel +{ + // 定义表名 + protected $name = 'retail_price'; + // 定义主键 + protected $pk = 'retail_price_id'; + + // 开启自动写入时间戳 + protected $autoWriteTimestamp = true; + + // 创建时间字段 + protected $createTime = 'create_time'; + + // 更新时间字段 + protected $updateTime = 'update_time'; + + public function getList(array $where) + { + return $this->where($where)->order('sort', 'asc')->select(); + } + + /** + * @notes:详情 + * @param $where + * @param array $with + * @return static|array|null + * @author: wanghousheng + */ + public static function detail($where, array $with = []) + { + return static::get($where, $with); + } + +} \ No newline at end of file diff --git a/app/common/model/RetailOrder.php b/app/common/model/RetailOrder.php new file mode 100644 index 00000000..89275202 --- /dev/null +++ b/app/common/model/RetailOrder.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\common\model; + +use cores\BaseModel; + +class RetailOrder extends BaseModel +{ + // 定义表名 + protected $name = 'retail_order'; + // 定义主键 + protected $pk = 'retail_order_id'; + + // 开启自动写入时间戳 + protected $autoWriteTimestamp = true; + + // 创建时间字段 + protected $createTime = 'create_time'; + + // 更新时间字段 + protected $updateTime = 'update_time'; + + + +} \ No newline at end of file diff --git a/app/store/controller/Retail.php b/app/store/controller/Retail.php new file mode 100644 index 00000000..73aebb0c --- /dev/null +++ b/app/store/controller/Retail.php @@ -0,0 +1,100 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\store\controller; + +use think\response\Json; +use app\store\model\Retail as RetailModel; + +use function Symfony\Component\VarDumper\Dumper\esc; + +class Retail extends Controller +{ + + /** + * 查看所有会员售价 + * @return Json + */ + public function list(): Json + { + $where = []; + $type = $this->request->post('retailType'); + if ($type) { + $where['retail_type'] = $type; + } + // $model = new RetailModel(); + // $list = $model->getList($where); + $list = RetailModel::withoutGlobalScope()->where($where)->select(); + return $this->renderSuccess(compact('list')); + } + + /** + * @notes:新增 + * @return Json + * + */ + public function add(): Json + { + $data = $this->postForm(); + $id = $this->getStoreId(); + if (!$data) { + return $this->renderError('缺少必要参数'); + } + $model = new RetailModel(); + if ($model->add($data)) { + return $this->renderSuccess('添加成功'); + } + return $this->renderError($model->getError() ?: '添加失败'); + } + + /** + * @notes:编辑 + * @param int $retailPriceId + * @return Json + * @author: + */ + public function edit(int $retailPriceId): Json + { + $data = $this->postForm(); + if (!$data) { + return $this->renderError('缺少必要参数'); + } + $model = RetailModel::withoutGlobalScope()->where('retail_price_id', $retailPriceId)->find(); + if (!$model) { + return $this->renderError('找不到指定的数据'); + } + $data['update_time']=time(); + RetailModel::withoutGlobalScope()->where('retail_price_id', $retailPriceId)->update($data); + return $this->renderSuccess('编辑成功'); + + } + + /** + * @notes:删除 + * @param array $identityId + * @return Json + * @author: wanghousheng + */ + public function delete(array $retailPriceId): Json + { + $model = new RetailModel; + if ($model->remove($retailPriceId)) { + return $this->renderSuccess('删除成功'); + } + return $this->renderError('删除失败'); + } + + + + + +} \ No newline at end of file diff --git a/app/store/model/Retail.php b/app/store/model/Retail.php new file mode 100644 index 00000000..5e22ff2a --- /dev/null +++ b/app/store/model/Retail.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\store\model; + +use app\common\model\Retail as RetailModel; + +class Retail extends RetailModel +{ + + public function getList(array $where) + { + return $this->where($where)->order('sort', 'asc')->select(); + } + + /** + * @notes:新增 + * @param $data + * @return bool + */ + public function add($data): bool + { + $data['store_id'] = self::$storeId; + return $this->save($data); + } + + /** + * @notes:编辑 + * @param $data + * @return bool + */ + public function edit($data): bool + { + return $this->save($data) !== false; + } + + /** + * @notes:详情 + * @param $where + * @param array $with + * @return static|array|null + * @author: wanghousheng + */ + public static function detail($where, array $with = []) + { + return static::get($where, $with); + } + + /** + * @notes:删除 + * @param array $IdentityId + * @return bool + * @author: wanghousheng + */ + public function remove(array $retailPriceId): bool + { + if (static::whereIn('retail_price_id', $retailPriceId)->delete()) { + return true; + } + return false; + } + + +} \ No newline at end of file