jh-admin/addon/aliapp/model/AliPayMessage.php

703 lines
26 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace addon\aliapp\model;
use app\model\BaseModel;
use think\Exception;
use think\facade\Db;
use think\facade\Log;
/**
* Common: 支付宝消息相关
* Author: wu-hui
* Time: 2023/01/04 14:52
* Class AliPayMessage
* @package addon\aliapp\model
*/
class AliPayMessage extends BaseModel
{
protected $site_id;
protected $minCodeModel;
protected $siteInfo;
protected $merchant_biz_type;
protected $param;
protected $order_info;
protected $item_order_list;
public function __construct($param, $merchant_biz_type = 'KX_SHOPPING')
{
$this->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日
];
}
}