// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\store\controller; use app\common\enum\merchant\balanceLog\Scene as SceneEnum; use app\common\lock\RedisLock; use app\common\model\store\Setting as SettingModel; use app\common\service\IdingjuOil; use app\common\service\SybOil; use app\store\model\Code as CodeModel; use app\store\model\Merchant as MerchantModel; use app\store\model\merchant\BalanceLog as BalanceLogModel; use app\store\model\Notify as NotifyModel; use app\store\model\Order as OrderModel; use app\store\model\OrderGoods as OrderGoodsModel; use app\store\model\Shop as ShopModel; use app\store\model\store\User; use app\store\model\store\User as UserModel; use app\store\model\Company as CompanyModel; use app\store\model\company\BalanceLog as CompanyBalanceLogModel; use app\store\model\order\QrCode as QrCodeModel; use GatewayWorker\Lib\Gateway; use think\facade\Cache; use think\facade\Db; use think\response\Json; use app\common\enum\order\OrderStatus as OrderStatusEnum; /** * 订单管理 * Class Order * @package app\store\controller */ class Order extends Controller { /** * 订单列表 * @param string $dataType * @return array */ public function list(string $dataType): Json { // 订单列表 $model = new OrderModel; $user = $this->store['user']; // $merchant = MerchantModel::getAll($user); $list = $model->getList($dataType, $this->request->param(), $user); $list['dataType'] = $dataType; return $this->renderSuccess($list); } /** * 订单详情 * @param int $orderId * @return array */ public function detail(int $orderId): Json { // 订单详情 $model = new OrderModel; if (!$detail = $model->getDetail($orderId)) { return $this->renderError('未找到该订单记录'); } return $this->renderSuccess(compact('detail')); } /** * 修改订单砖状态 * @return array * @throws \think\exception\DbException */ public function updatestatus(): Json { $postData = $this->postForm(); $postData['order_id'] = $this->request->param('orderId'); if(empty($postData['status'])){ return $this->renderError('请选择订单状态'); } $model = OrderModel::detail($postData['order_id']); $NotifyModel = new NotifyModel(); if ($model->updateStatus($postData)) { //已支付订单才进行回调通知 if ($postData['status'] == 20) { $codeModel = CodeModel::detail(['code_id'=>$model['old_code_id'],'status'=>1]); if($codeModel['code_id']){ $codeModel->modifyUsed($model['order_id']); //写入队列 $create_time = is_numeric($codeModel['create_time'])?$codeModel['create_time']:strtotime($codeModel['create_time']); $code_queue = ['code_id' => $codeModel['code_id'], 'expire_time' => $create_time + (float)$codeModel['expiration_time']]; // 过期时间 $code_json = json_encode($code_queue,320); Cache::store('redis')->lRem($codeModel['passageway'].'_'.round($codeModel['money'],2), $code_json, 1); } if ($NotifyModel->add($model)) { return $this->renderSuccess('修改成功'); } else { return $this->renderError($NotifyModel->getError() ?: '修改失败'); } }else{ return $this->renderSuccess('修改成功'); } } return $this->renderError($model->getError() ?: '修改失败'); } /** * 手动回调 * @param $order_id * @return array * @throws \think\exception\DbException */ public function callback(): Json { $postData = $this->postForm(); $postData['order_id'] = $this->request->param('orderId'); $order_id = $postData['order_id']; $password = $postData['password']; //验证密码 $user = UserModel::detail($this->store['user']['store_user_id']); if(!password_verify($password, $user['password'])){ return $this->renderError('登录密码错误'); } $model = OrderModel::detail($order_id); $NotifyModel = new NotifyModel(); if ($NotifyModel->add($model)) { return $this->renderSuccess('操作成功'); } return $this->renderError($model->getError() ?: '操作失败'); } /** 测试发送数据 * @return Json */ public function send(): Json { //Gateway::sendToClient('c0a8008a07d000000002',json_encode(['type' => 'test_send'])); Gateway::sendToUid($this->store['user']['store_user_id'], json_encode(['type' => 'test_send'])); } /** * 撤销分油 * @param $order_id * @return array * @throws \think\exception\DbException */ public function cancelShare(): Json { $postData = $this->postForm(); $postData['order_goods_id'] = $this->request->param('orderGoodsId'); $order_goods_id = $postData['order_goods_id']; $password = $postData['password']; //验证密码 $user = UserModel::detail($this->store['user']['store_user_id']); if(!password_verify($password, $user['password'])){ return $this->renderError('登录密码错误'); } $model = OrderGoodsModel::detail($order_goods_id); if ($model['oil_status'] != 1) { return $this->renderError('该订单状态不是已分油状态'); } if ($model['use_status'] != 0) { return $this->renderError('油卡已核销,无法撤销'); } $order = OrderModel::detail($model['order_id']); $company = CompanyModel::detail($model['company_id']); // 对接平台接口,撤销分油 $res = $this->oilOilCardCancelShare(['shareNo'=>$model['shareNo'],'amount'=>$model['goods_price'],'saleOrderNo'=>$order['order_no'],'type'=>'recovery','oilCardType'=>$model['oilCardType']], $company); if($res['code'] == '00'){ if ($model->cancelShare($postData)) { // 更新商户余额(增加) MerchantModel::setIncBalance((int)$model['merchant_id'], (float)$model['goods_price']); BalanceLogModel::add(SceneEnum::REFUND, [ 'merchant_id' => (int)$model['merchant_id'], 'money' => (float)$model['goods_price'], ], ['saleOrderNo' => $order['order_no']]); // 更新公司余额(增加) CompanyModel::setIncBalance((int)$model['company_id'], (float)$model['goods_price']); CompanyBalanceLogModel::add(SceneEnum::REFUND, [ 'company_id' => (int)$model['company_id'], 'money' => (float)$model['goods_price'], ], ['saleOrderNo' => $order['order_no']]); return $this->renderSuccess('操作成功'); } return $this->renderError($model->getError() ?: '操作失败'); }else{ return $this->renderError('平台撤销分油失败【'.($res['errMessage'] ?? $res['message']).'】'); } } /** * 获取支付二维码 * @return Json * @throws \think\db\exception\DbException */ public function qrCode(): Json { $postData = $this->postForm(); $postData['order_goods_id'] = $this->request->param('orderGoodsId'); $orderGoods = OrderGoodsModel::detail($postData['order_goods_id']); if($orderGoods['use_status'] != 0){ return $this->renderError('油券已核销'); }else { $company = CompanyModel::detail($orderGoods['company_id']); $IdingjuOil = new IdingjuOil(); // 对接平台接口 $res = $IdingjuOil->payQrCodeRequest(['order_no'=>$orderGoods['oilCardNo']], $company); if($res['code'] == '1' && isset($res['data']['useQrCodeUrl'])){ // 插入支付码记录 $QrCodeModel = new QrCodeModel(); $QrCodeModel->add([ 'oilCardNo'=>$orderGoods['oilCardNo'], 'qrCode'=>$res['data']['useQrCodeUrl'], 'amount'=>$orderGoods['goods_price'], 'order_id'=>$orderGoods['order_id'], 'user_id'=>$orderGoods['user_id'], 'store_id'=>$orderGoods['store_id'], ]); $res = [ 'qrCode'=>$res['data']['useQrCodeUrl'] ]; return $this->renderSuccess($res, '提交成功'); }else{ return $this->renderError($res['errMessage'] ?? $res['message']); } } } /** * @param $goodsNo * @return string */ public function getCompany($goodsNo): string { switch ($goodsNo) { case 'djgdface100': case 'djgdface200': case 'djgdface300': return 'umQZhIHKofyA'; case 'jmgxyyface100': case 'jmgxyyface200': case 'jmgxyyface300': case 'jmgzface100': case 'jmgzface200': case 'jmgzface300': case 'jmfjface100': case 'jmfjface200': case 'jmfjface300': return 'HpWqXIgYvTBg'; case 'face003': return 'NKJBgaaRNdiL'; // 测试参数 default: return ''; } } public function processUserOrders($companyId) { $redisLock = new RedisLock('user_order_lock'); $maxAttempts = 10; // 最大尝试次数 $attempt = 0; $sleepTime = 500000; // 每次尝试失败后的等待时间(微秒),500000微秒 = 0.5秒 while ($attempt < $maxAttempts) { $lockAcquired = $redisLock->acquireLock(); if ($lockAcquired) { break; } $attempt++; usleep($sleepTime); // 等待一段时间再尝试 } if (!$lockAcquired) { throwError('网络繁忙请稍后'); } $todayStart = strtotime(date('Y-m-d 00:00:00')); // 查找一个未被调用的用户 $account = Db::name('account') ->alias('a') ->join('company c', 'a.company_id = c.company_id') ->where('a.last_called_at', '<', $todayStart) ->where('a.is_delete', '=', 0) ->where('a.state', '=', 0) ->where('a.company_id', '=', $companyId) ->where('c.status', '=', 10) ->field('a.*') ->limit(1) ->find(); if (!$account) { throwError("没有可用的用户"); } // 更新用户的 `last_called_at` Db::name('account') ->where('account_id', $account['account_id']) ->update(['last_called_at' => time(), 'state' => 1]); $redisLock->releaseLock(); return $account; } /** * 手动分油 * @return Json * @throws \think\db\exception\DbException */ public function share(): Json { $IdingjuOil = new IdingjuOil(); $postData = $this->request->param(); $postData['order_goods_id'] = $this->request->param('orderGoodsId'); $goods = OrderGoodsModel::detail($postData['order_goods_id']); if($goods['oil_status'] != 0){ return $this->renderError('已分油'); }else { if($goods['oilCardType']) { $data['amount'] = $goods['total_price']; // 金额 $company = CompanyModel::detail(['orgNo' => $this->getCompany($goods['goods_no'])]); if (!$company) { return $this->renderError('已分油'); } try { // 查找一个未被调用的用户 $account = $this->processUserOrders($company['company_id']); } catch (\Throwable $e) { return $this->renderError($e->getMessage()); } // 查询公司余额 /*if ($data['amount'] > $company['balance']) { $this->error = '公司余额不足'; return false; }*/ // 对接平台接口 $res = $IdingjuOil->oilOilCardShare([ 'goodsNo'=>$goods['goods_no'], 'amount'=>$data['amount'], 'userNo'=>$account['userNo'], 'mobile'=>$account['mobile'], 'saleOrderNo'=>$goods['oilCardNo'], 'oilCardType'=>$goods['oilCardType'] ], $company); //$res = json_decode('{"code":"00","message":"请求成功","errCode":null,"errMessage":null,"data":{"oilCardNo":null,"amount":100,"balance":null,"shareNo":"CDV2408021928160001"}}', true); if ($res['code'] != 1) { return $this->renderError($res['errMessage'] ?? $res['message']); } $IdingjuOil->saveLogStore("分油接口结果".json_encode($res,320)); $item['account_id'] = $account['account_id']; $item['userNo'] = $account['userNo']; $item['mobile'] = $account['mobile']; $item['company_id'] = $company['company_id']; $item['shareNo'] = $res['data']['trade_no'] ?? ''; $item['qrCode'] = $res['data']['useUrl'] ?? ''; $item['oil_status_zsy'] = $res['data']['state'] ?? 0; $item['oil_time'] = time(); $item['oil_status'] = $item['oil_status_zsy'] == 2 ? 1 : 0; // 已发券 为1 $r = $goods->save($item); $IdingjuOil->saveLogStore("保存分油结果".json_encode($r,320)); return $this->renderSuccess('分油成功'); } } } }