param = $param; $this->site_id = $param['site_id']; $this->merchant_biz_type = $merchant_biz_type; $this->minCodeModel = new MinCode($this->site_id); if (isset($param['order_id'])) { $order_id = $param["order_id"]; $this->order_info = model('order') ->getInfo([["order_id", "=", $order_id]], "out_trade_no,order_type,order_no,mobile,member_id,order_name,pay_time,create_time,pay_money,order_money,close_time"); $this->item_order_list = $this->getGoodsInfo($this->param['order_id'], '');// 商品信息; } } /*** * 订单创建同步消息 * @param $param * @return void * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function OrderCreateMsg() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'CREATE', $path); return $res; } /*** * 支付成功消息 * @param $param * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function messagePaySuccess() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'PAID', $path); return $res; } /** * 订单发货 * @param $param * @return void */ public function messageOrderDelivery() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'IN_DELIVERY', $path); return $res; } /*** * 订单催款 * @param $param * @return void */ public function messageOrderUrgePayment() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'WAIT_PAY', $path); return $res; } /*** * 退款中 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function MessageOrderRefundinG(){ $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'REFUNDING', $path); return $res; } /*** * 订单完成 * @param $param * @return void */ public function messageBuyerOrderComplete() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'FINISHED', $path); return $res; } /*** * 订单关闭 * @param $param * @return void */ public function messageOrderClose() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'CLOSED', $path); return $res; } /*** * 商家同意退款 * @return void */ public function messageOrderRefundAgree() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'REFUNDED', $path); return $res; } /** * 商家拒绝退款 * @return void */ public function messageOrderRefundRefuse() { } /*** * 订单核销 * @return void */ public function messageOrderVerify() { $path = $this->handleUrl(); $url = urlencode('/pages/index/index'); $business_info = [ 'come_again' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}" ]; $res = $this->AlipayOrderSyncMsg($business_info, 'REFUNDED', $path); return $res; } /*** * 发送订单消息 * @param $orderInfo */ public function SendAccMessage($orderInfo, $order_scene = '') { $order_scene = $orderInfo['order_scene'] ?? $order_scene; switch ($order_scene) { case 'cashier': $business_info = [ 'consumption_project' => '消费买单', 'card_balance' => '您的会员余额未消费', 'consumption_amount' => '本次消费' . $orderInfo['order_money'] . '元', ]; $typeStatus = 'CONSUME_S'; $merchant_biz_type = 'STORED_VALUE_ACCOUNT_N'; $item_order_list = [ 'item_name' => '用户买单', 'ext_info' => [ [ 'ext_key' => 'image_material_id', 'ext_value' => $this->getCacheImageMaterialID('cashier', 'cashier', 'upload/cashier/mbuy.png'), ] ] ]; $this->AlipayOrderSyncMsg($orderInfo, $business_info, $item_order_list, $typeStatus, $merchant_biz_type); break; case 'recharge': $balance = Db::name('member')->where('member_id', '=', $orderInfo['member_id'])->value('balance'); $business_info = [ 'recharge_amount' => '实际支付' . $orderInfo['buy_price'] . '元', 'consumption_project' => '会员充值', 'card_balance' => '您的会员余额' . $balance . '元', //会员卡余额 'recharge_time' => date('Y-m-d H:i:s', $orderInfo['create_time']), //'consumption_amount'=>'本次充值'.$orderInfo['buy_price'].'元', // 'details'=>'会员卡充值赠送'.$orderInfo['face_value'].'元', ]; $typeStatus = 'RECHARGE_S'; $merchant_biz_type = 'STORED_VALUE_ACCOUNT_N'; $item_order_list = [ 'item_name' => '会员充值', 'ext_info' => [ [ 'ext_key' => 'image_material_id', 'ext_value' => $this->getCacheImageMaterialID('cashier', 'cashier', 'upload/cashier/mbuy.png'), ] ] ]; $orderInfo['order_money'] = $orderInfo['buy_price']; $orderInfo['out_trade_no'] = $orderInfo['order_no']; $this->AlipayOrderSyncMsg($orderInfo, $business_info, $item_order_list, $typeStatus, $merchant_biz_type); break; case 'reservation': //预约 $storeInfo = Db::name('store')->where(['store_id' => $orderInfo['store_id']])->cache('storeInfo_' . $orderInfo['store_id'], null, 'alipay_msg')->field('store_name,telphone,address')->find(); $types = [ 'wait_confirm' => 'BOOK_SUCCESSFULLY', //待商家确认 'wait_to_store' => 'ORDER_CHANGE', //待到到店 'cancelled' => 'CLOSED', //服务取消 'arrived_store' => 'DELIVERED', //已到店 'completed' => 'PAID', //完成 ]; $orderInfo = model('reserve')->getInfo(['reserve_id' => $orderInfo['reserve_id']]); $business_info = [ 'book_item' => $orderInfo['reserve_item'], //项目名称 'address' => $storeInfo['address'], //店铺位置 'booking_name' => $orderInfo['reserve_name'], //预约师傅 'shop_name' => $storeInfo['store_name'] ?? $this->getSiteName(), 'shop_phone' => $storeInfo['telphone'], 'start_time' => '您的预约时间' . date('Y-m-d H:i:s', $orderInfo['reserve_time']), 'end_time' => date('Y-m-d H:i:s', $orderInfo['reserve_time'] + 3600), ]; $typeStatus = $types[$orderInfo['reserve_state']] ?? ''; $merchant_biz_type = 'TO_SHOP'; $item_order_list = [ 'item_name' => $orderInfo['reserve_item'], 'ext_info' => [ [ 'ext_key' => 'image_material_id', 'ext_value' => $this->getCacheImageMaterialID('cashier', 'cashier', 'upload/cashier/mbuy.png'), ] ] ]; $orderInfo['out_trade_no'] = $orderInfo['reserve_id']; $orderInfo['pay_time'] = $orderInfo['create_time']; $this->AlipayOrderSyncMsg($orderInfo, $business_info, $item_order_list, $typeStatus, $merchant_biz_type); break; case 'online': break; } return $this->success(); } /** * 发送同步消息 * @param $orderInfo * @param $typeStatus * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function AlipayOrderSyncMsg(array $business_info, $typeStatus = 'CONSUME_S', $path = '/pages/index/index') { // 参数获取 $appid = $this->getAppid();// 获取小程序id $orderInfo = $this->order_info; $item_order_list = $this->item_order_list; $merchant_biz_type = $this->merchant_biz_type; $aliOpenid = $this->getAliOpenId($orderInfo['member_id']); if ($aliOpenid) { $siteName = $this->getSiteName(); $params = [ 'out_biz_no' => $orderInfo['out_trade_no'],// 外部订单号 'buyer_id' => $aliOpenid,// 买家userId 'amount' => $orderInfo['order_money'] ?? '',// 订单金额,单位为【元】 'pay_amount' => $orderInfo['pay_money'] ?? '',// 支付金额,单位为【元】 'order_type' => 'SERVICE_ORDER',// 订单类型,新接入商户统一传入SERVICE_ORDER(服务订单) 'order_create_time' => date('Y-m-d H:i:s', $orderInfo['create_time']),//订单创建时间 当order_type为SERVICE_ORDER时必传 日期 'order_modified_time' => date('Y-m-d H:i:s', $orderInfo['create_time']),// 订单修改时间 'order_pay_time' => $orderInfo['pay_time'] > 0 ? date('Y-m-d H:i:s', $orderInfo['pay_time']) : '',// 订单支付时间 当pay_channel为非ALIPAY时 且订单状态已流转到“支付”或支付后时,需要将支付时间传入 'item_order_list' => $item_order_list, 'shop_info' => [ 'name' => $siteName, ], 'ext_info' => [ ['ext_key' => 'tiny_app_id', 'ext_value' => $appid], ['ext_key' => 'merchant_biz_type', 'ext_value' => $merchant_biz_type], ['ext_key' => 'merchant_order_status', 'ext_value' => $typeStatus], ['ext_key' => 'merchant_order_link_page', 'ext_value' => $path], [ 'ext_key' => 'business_info', 'ext_value' => json_encode($business_info) ] ] ]; if (!$params['amount']) unset($params['amount']); if (!$params['pay_amount']) unset($params['pay_amount']); // 发起请求 $result = $this->minCodeModel->requestApi('alipay.merchant.order.sync', $params, []); $result = $result['alipay_merchant_order_sync_response']; if ($result['code'] == 10000) { return $this->success($result); } else { return $this->error('', $result['sub_msg']); } } } /** * 获取会员openid * @param $member_id * @return mixed */ public function getAliOpenId($member_id) { $aliOpenid = Db::name('member') ->where(['member_id' => $member_id]) ->cache('ali_openid_' . $member_id, null, 'alipay_msg') ->value('ali_openid'); return $aliOpenid; } /** * 获取站点名称 * @return mixed */ public function getSiteName() { $siteName = Db::name('site') ->where('site_id', $this->site_id) ->cache('ali_site_id_' . $this->site_id, null, 'alipay_msg') ->value('site_name'); return $siteName; } /** * Common: 订单中心 —— 获取小程序id * Author: wu-hui * Time: 2023/01/04 16:15 * @return mixed */ public function getAppid() { return Db::name('uni_account') ->cache('aliapp_appid_key_' . $this->site_id, null, 'alipay_msg') ->where('site_id', $this->site_id) ->where('app_type', '=', 'aliapp') ->value('appid'); } /*** * 获取缓存ID * @param $type * @param $imgName * @param $path * @return mixed|string */ public function getCacheImageMaterialID($type, $imgName, $path) { if ($Images = cache('material' . $type . $this->site_id)) { return $Images['image_id']; } else { try { $upImages = $this->minCodeModel->imageUpload($imgName, img($path), true); $response = $upImages['alipay_offline_material_image_upload_response']; if ($response['code'] == 10000) { cache('material' . $type . $this->site_id, $response, null, 'ImageMaterialId'); return $response['image_id']; } else { return 'A*iEHnTLFEG5wAAAAAAAAAAAAABKd2AQ'; } } catch (Exception $e) { Log::write('消息发送 - 图片id获取失败:' . $e->getMessage()); return 'A*iEHnTLFEG5wAAAAAAAAAAAAABKd2AQ'; } } } /** * Common: 订单中心 —— 获取会员卡信息 * Author: wu-hui * Time: 2023/01/04 16:44 * @param $orderId * @return array|mixed|Db|\think\Model|null * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getCardInfo($orderId) { return Db::name('member_goods_card') ->field('card_id,end_time') ->where('order_id', $orderId) ->find(); } /** * Common: 订单中心 —— 获取商品信息 * Author: wu-hui * Time: 2023/01/04 16:28 * @param $orderId * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getGoodsInfo($orderId, $scene = '') { // MERCHANT_SECURITIES=商家核销;STORED_VALUE_ACCOUNT=储值动账(到店版) $data = []; $list = Db::name('order_goods') ->field('sku_id,num,price,sku_name,sku_image') ->cache(true, null, $orderId . 'alipayGetGoodsInfo') ->where('order_id', $orderId) ->select()->toArray(); if ($list) { $url = urlencode('/pages_market/order/detail?order_id=' . $orderId); foreach ($list as $item) { $data[] = [ 'quantity' => $item['num'], 'unit_price' => $item['price'], 'sku_id' => $item['sku_id'], 'item_name' => $item['sku_name'], 'ext_info' => [ [ "ext_key" => "image_material_id", "ext_value" => $this->uploadImage($item) ], [ 'ext_key' => 'merchant_item_link_page', 'ext_value' => "alipays://platformapi/startapp?appId={$this->getAppid()}&page={$url}", ] ] ]; } } switch ($scene) { case 'MERCHANT_SECURITIES': break; // 商家核销 case 'STORED_VALUE_ACCOUNT': break;// 储值动账(到店版) } return $data; } /** * 处理订单链接 * @param $order_type * @param $order_id * @return string */ public function handleUrl() { switch ($this->order_info['order_type']) { case 2: return '/pages_market/order/detail_pickup?order_id=' . $this->param['order_id']; case 3: return '/pages_market/order/detail_local_delivery?order_id=' . $this->param['order_id']; case 4: return '/pages_tool/order/detail_virtual?order_id=' . $this->param['order_id']; default: return '/pages_market/order/detail?order_id=' . $this->param['order_id']; } } /** * Common: 订单中心 —— 商品图片上传 * Author: wu-hui * Time: 2023/04/12 14:36 * @param $item * @return mixed|string */ public function uploadImage($item) { // 图片上传支付宝 ///image_id A*iEHnTLFEG5wAAAAAAAAAAAAABKd2AQ $imgUploadResult = $this->minCodeModel->imageUpload($item['sku_name'], img($item['sku_image']), true); return $imgUploadResult['alipay_offline_material_image_upload_response']['image_id'] ?? 'A*iEHnTLFEG5wAAAAAAAAAAAAABKd2AQ'; } /** * Common: 订阅消息发送 —— 开始 * Author: wu-hui * Time: 2023/01/10 16:12 * @param $uid * @param $keywords * @param array $params * @param string $page * @return array */ public function sendMessage($uid, $keywords, $params = [], $page = 'pages/index/index') { try { // 通过用户user_id $userId = Db::name('member')->where('member_id', $uid)->value('ali_openid'); if (!$userId) return $this->error('', '用户不存在支付宝小程序user_id!'); // 判断:用户是否订阅当前消息 $subscribeInfo = $this->userIsSubscribeMessage($uid, $keywords); // 消息发送 $sendData = $this->getSendData($keywords, $params); $params = [ 'to_user_id' => $userId, 'user_template_id' => $subscribeInfo['template_id'], 'page' => $page, 'data' => json_encode($sendData, JSON_UNESCAPED_UNICODE), ]; // 发起请求 $result = (new MinCode($this->site_id))->requestApi('alipay.open.app.mini.templatemessage.send', $params, []); $result = $result['alipay_open_app_mini_templatemessage_send_response']; if ($result['code'] == 10000) { // 发送成功后的处理 Db::name('message_form_id')->where($subscribeInfo)->delete();// 删除记录 // 发送记录 $this->sendLog($keywords, $params, $result, 1); return $this->success($result); } else { // 发送记录 $this->sendLog($keywords, $params, $result, 0); return $this->error('', $result['sub_msg']); } } catch (Exception $e) { // 发送记录 $this->sendLog($keywords, $params, ['error_msg' => $e->getMessage()], 0); return $this->error('', $e->getMessage()); } } /** * Common: 订阅消息发送 —— 判断:用户是否订阅当前消息 * Author: wu-hui * Time: 2023/01/10 15:13 * @param $uid * @param $keywords * @return array|mixed|Db|\think\Model * @throws Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function userIsSubscribeMessage($uid, $keywords) { // 获取模板id $templateId = Db::name('message') ->where('site_id', $this->site_id) ->where('keywords', $keywords) ->where('aliapp_is_open', 1) ->value('aliapp_template_id'); if (!$templateId) throw new Exception('当前模板消息未开启或未设置!'); // 获取用户订阅消息 $subscribeInfo = Db::name('message_form_id') ->where('template_id', $templateId) ->where('uid', $uid) ->where('type', 'aliapp') ->order('create_time', 'ASC') ->find(); if (!$subscribeInfo) throw new Exception('当前用户未订阅该信息!'); return $subscribeInfo; } /** * Common: 订阅消息发送 —— 获取发送信息 * Author: wu-hui * Time: 2023/01/10 15:40 * @param $keywords * @param $params * @return mixed * @throws Exception */ private function getSendData($keywords, $params) { // 键名转驼峰 方法名称 $nameArr = array_map(function ($item) { return ucwords(strtolower($item)); }, explode('_', $keywords)); $classList = get_class_methods(self::class); $className = 'message' . implode($nameArr); if (in_array($className, $classList)) return $this->$className($params); else throw new Exception('未获取发送信息!'); } /** * Common: 订阅消息发送 —— 发送记录 * Author: wu-hui * Time: 2023/01/10 16:10 * @param $keywords * @param $params * @param $sendResult * @param $isSuccess * @return int|string */ private function sendLog($keywords, $params, $sendResult, $isSuccess) { $sendLog = [ 'site_id' => $this->site_id, 'keywords' => $keywords, 'message_type' => 'aliapp', 'addon' => '', 'title' => '', 'message_json' => json_encode($params, JSON_UNESCAPED_UNICODE), 'create_time' => time(), 'send_time' => time(), 'send_log' => json_encode($sendResult, JSON_UNESCAPED_UNICODE), 'is_success' => $isSuccess, ]; return Db::name('message_send_log')->insert($sendLog); } /** * Common: 订阅消息发送信息 —— 权益即将过期通知 * Author: wu-hui * Time: 2023/01/10 15:40 * @param $params * @return array[] */ private function messageInterestExpirationNotice($params) { return [ 'keyword1' => ['value' => $params['store_name']], // 商家名称 'keyword2' => ['value' => $params['surplus']],// 剩余次数 'keyword3' => ['value' => $params['content']],// 优惠内容 ]; } /** * Common: 订阅消息发送信息 —— 服务开通成功提醒 * Author: wu-hui * Time: 2023/01/10 15:40 * @param $params * @return array[] */ private function messageServiceOpenedSuccess($params) { return [ 'keyword1' => ['value' => $params['end_time']], // 到期时间 日期:2022年1月18日 'keyword2' => ['value' => $params['nickname']],// 姓名 'keyword3' => ['value' => $params['start_time']],// 开通时间 日期:2022年1月18日 'keyword4' => ['value' => $params['content']],// 服务项目 ]; } /** * Common: 订阅消息发送信息 —— 核销提醒 * Author: wu-hui * Time: 2023/01/10 15:40 * @param $params * @return array[] */ private function messageVerify($params) { return [ 'keyword1' => ['value' => $params['goods_name']], // 核销产品 'keyword2' => ['value' => $params['store_name']],// 核销商户 'keyword3' => ['value' => $params['start_time']],// 核销时间 日期:2022年1月18日 ]; } }