OrderNotice.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. <?php
  2. namespace loyalsoft\pay;
  3. /**
  4. * Description of OrderNotice
  5. * 通用支付订单通知模型
  6. * @version
  7. * 1.0.0 Created at 2017-12-26. by --gwang
  8. * @author gwang (mail@wanggangzero.cn)
  9. * @copyright ? 2017-12-26, SJZ LoyalSoft Corporation & gwang. All rights reserved.
  10. */
  11. class OrderNotice extends \loyalsoft\Object_ext {
  12. const orderTab = 'tab_order_tab';
  13. /**
  14. * uid,zoneid,cpOrderId
  15. * @var string 充值回调透传参数(len=250)
  16. */
  17. public $callbackInfo;
  18. /**
  19. * @var int 充值金额 单位:分
  20. */
  21. public $amount;
  22. /**
  23. * @var string 货币类型(默认:CNY)
  24. */
  25. public $currency = 'CNY';
  26. /**
  27. * @var string 订单ID (len=30)
  28. */
  29. public $cpOrderId;
  30. /**
  31. * @var string 平台UID(不含渠道串)
  32. */
  33. public $uid;
  34. /**
  35. * @var string 平台字符串
  36. */
  37. public $channel;
  38. /**
  39. *
  40. * @var type 订单状态: 0:创建订单,1:支付成功,2: 支付失败
  41. */
  42. public $status;
  43. /**
  44. *
  45. * @var type
  46. */
  47. protected $sdk_orderid;
  48. /**
  49. *
  50. * @var type
  51. */
  52. protected $otherInfo;
  53. /**
  54. * @return boolean 校验订单数据
  55. */
  56. public function Check() {
  57. // var_dump($this);
  58. $dbOrder = $this->dbOrder();
  59. // var_dump($dbOrder);
  60. \loyalsoft\CLog::pay('查询订单结果: ' . var_export($dbOrder, TRUE));
  61. if (!$dbOrder) {
  62. \loyalsoft\CLog::pay('订单不存在! ' . $this);
  63. return false;
  64. }
  65. if ($dbOrder->status == 1) {
  66. \loyalsoft\CLog::pay('订单已经完成!' . $this);
  67. return false;
  68. }
  69. // // 提取纯UID作比较
  70. // $pureUID = function($str) {
  71. //// var_dump($str);
  72. // if (!strpos($str, "-")) {
  73. // return $str;
  74. // }
  75. // return substr($str, strpos($str, "-") + 1);
  76. // };
  77. //// var_dump($this->uid);
  78. // if ($pureUID($dbOrder->uid) != $pureUID($this->uid)) {
  79. // \loyalsoft\CLog::pay('UID校验不匹配! ' . $pureUID($this->uid) . " (" . $pureUID($dbOrder->uid) . ")");
  80. // return false;
  81. // }
  82. if ($dbOrder->amount != $this->amount) {
  83. \loyalsoft\CLog::pay('金额校验不匹配! ' . $this->amount . " (" . $dbOrder->amount . ")");
  84. return false;
  85. }
  86. return true;
  87. }
  88. /**
  89. * 获取数据库中的订单记录
  90. * @return \loyalsoft\pay\dbOrder
  91. */
  92. public function dbOrder() {
  93. $dbOrder = \loyalsoft\daoInst()->select()->from(self::orderTab)
  94. ->where('cpOrderId')->eq($this->cpOrderId)
  95. ->limit(1)->fetch();
  96. return $dbOrder;
  97. }
  98. /**
  99. * 检查重复的渠道订单id(目前仅在ios平台做了校验,其他都是后台通知。
  100. * @return boolean true 验证通过,false 验证失败,已经存在相同的订单id
  101. */
  102. public function CheckDuplicateSdkOrder() {
  103. $n = \loyalsoft\daoInst()->select()->from(self::orderTab)
  104. ->where('sdk_orderid')->eq($this->sdk_orderid)
  105. ->count();
  106. return $n <= 0;
  107. }
  108. /**
  109. * @return boolean 更新订单状态
  110. */
  111. public function UpdateOrderStatus() {
  112. $n = \loyalsoft\daoInst()->update(self::orderTab)
  113. ->data(array('status' => $this->status,
  114. 'sdk_orderid' => $this->sdk_orderid,
  115. 'otherInfo' => $this->otherInfo,
  116. 'close_ts' => \loyalsoft\now()))
  117. ->where('cpOrderId')->eq($this->cpOrderId)
  118. ->exec();
  119. return $n > 0;
  120. }
  121. // <editor-fold defaultstate="collapsed" desc="通知消息转换为统一的Order对象">
  122. /**
  123. * 解析华为后台通知数据, 转化为order对象
  124. * @param type $args https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References/server-data-model-0000001050986133#section264617465219
  125. */
  126. public static function Parse_hwOrder($args) {
  127. $o = new OrderNotice();
  128. $callbackInfo = $args['developerPayload']; # uid,zoneid,cpOrderId,productid # 透传参数: uid,zoneid,cpOrderId
  129. $infoArr = explode(',', $callbackInfo);
  130. $o->channel = "huawei"; # 渠道代码
  131. $o->uid = $infoArr[0];
  132. $o->cpOrderId = $infoArr[2];
  133. $o->status = $args['purchaseState'] == 0 ? 1 : 2; # 华为通知中的支付状态: -1初始化, 0 成功, 1 已取消, 2 已撤销或已退款 3 待处理
  134. $o->amount = $args['price']; # 结算价格
  135. $o->currency = $args['currency']; # 结算货币类型
  136. $o->sdk_orderid = $args['orderId']; # 华为后台订单id.
  137. $o->callbackInfo = $callbackInfo; # 记录下透传信息
  138. // $o->otherInfo = $args['purchaseToken']; # 当前92位,后续存在扩展可能,如要进行存储,建议您预留128位的长度
  139. return $o;
  140. }
  141. /**
  142. * 识别UC后台通知数据
  143. * @param array $args
  144. * @return \loyalsoft\pay\OrderNotice
  145. */
  146. public static function Parse_UcOrder($args) {
  147. $o = new OrderNotice();
  148. $o->channel = "uc"; # 渠道代码
  149. $o->cpOrderId = $args["data"]["cpOrderId"]; # (后台)订单编号
  150. $o->status = ($args["data"]["orderStatus"] == "S") ? 1 : 2; # 订单状态(九游返回值: S/F)
  151. $o->uid = $args['data']['accountId']; # 玩家uid
  152. $o->amount = $args['data']['amount'] * 100; # 支付金额, uc 返回的单位是元
  153. $o->callbackInfo = $args['data']['callbackInfo']; # uid-uc,zoneid,cpOrderId
  154. $o->sdk_orderid = $args['orderId']; # UC订单ID
  155. $o->otherInfo = $args['failedDesc']; # 其他信息
  156. return $o;
  157. }
  158. /**
  159. * 解析易接后台通知数据
  160. * @param array $args
  161. */
  162. public static function Parse_1SDKOrder($args) {
  163. $o = new OrderNotice();
  164. $o->channel = "1sdk"; # 渠道代码
  165. $ext = explode(',', $args['cbi']);
  166. $o->cpOrderId = $ext[2]; # 这个字段藏在透传参数中
  167. $o->status = ($args["st"] == "1") ? 1 : 2; # 订单状态(易接SDK返回值: 1/成功,其他失败)
  168. $o->uid = $args['uid']; # 玩家uid
  169. $o->amount = $args['fee']; # 支付金额, 易接返回值单位是分
  170. $o->callbackInfo = $args['cbi']; # 透传参数, uid-uc,zoneid,cpOrderId
  171. $o->sdk_orderid = $args['ssid']; # 渠道订单id
  172. $o->otherInfo = $args['tcd']; # 易接订单id
  173. return $o;
  174. }
  175. /**
  176. * 生成苹果支付订单数据.
  177. * @param array $argsClient
  178. * @param array $receipt 苹果凭证
  179. */
  180. public static function reParse_IOSOrder($argsClient, $receipt) {
  181. $o = new OrderNotice();
  182. $o->channel = "ios"; # 渠道代码
  183. $o->uid = $argsClient->uid; # 玩家uid
  184. $o->cpOrderId = $argsClient->cpOrderId; # 这个字段藏在透传参数中
  185. $o->callbackInfo = $argsClient->callbackInfo; # 透传参数, uid-uc,zoneid,cpOrderId
  186. $o->status = ($receipt["status"] == "0") ? 1 : 2; # 订单状态(苹果返回值: 0/成功,其他失败)
  187. $product_id = $receipt['product_id']; # 道具ID
  188. $itemModel = \loyalsoft\GameConfig::shop_getItem($product_id); # 道具常量
  189. $o->amount = $itemModel->price * 100; # 入库单位是分, 后台单位是元
  190. $o->sdk_orderid = $receipt['transaction_id']; # 交易订单id
  191. $o->otherInfo = $receipt['purchase_date']; # 购买时间
  192. return $o;
  193. }
  194. /**
  195. * 解析支付宝通知
  196. * @param type $args
  197. * @return \loyalsoft\pay\OrderNotice
  198. */
  199. public static function Parse_alipayOrder($args) {
  200. $o = new OrderNotice();
  201. $callbackInfo = urldecode($args['passback_params']); # 透传参数(zfb进行过urlencode)
  202. $exts = explode(',', $callbackInfo);
  203. $o->channel = "soft"; # 渠道代码zfb?
  204. $o->cpOrderId = $args['out_trade_no']; # 订单编号(龙游)
  205. $o->status = ($args["trade_status"] == "TRADE_SUCCESS") ? 1 : 2; # 订单状态()
  206. $uid = $exts[0];
  207. $o->uid = $uid; // strpos($uid, '_') > 0 ? substr($uid, 0, strpos($uid, '_')) : $uid; # 玩家uid
  208. $o->amount = $args['total_amount'] * 100; # 订单金额。本次交易支付的订单金额,单位为人民币(元)。支持小数点后两位。 游戏后台单位是分
  209. $o->callbackInfo = $callbackInfo; # 透传参数, uid-uc,zoneid,cpOrderId
  210. $o->sdk_orderid = $args['trade_no']; # 支付宝订单id
  211. $o->otherInfo = "zfb:" . $args['buyer_logon_id']; # 支付宝登录账户号
  212. return $o;
  213. }
  214. /**
  215. * 解析微信通知
  216. * @param type $args
  217. * @return \loyalsoft\pay\OrderNotice
  218. */
  219. public static function Parse_weixinpayOrder($args) {
  220. $o = new OrderNotice();
  221. $exts = explode(',', $args['attach']); # 透传参数
  222. $o->channel = "soft"; # 渠道代码zfb?
  223. $o->cpOrderId = $args['out_trade_no']; # 订单编号(龙游)
  224. $o->status = ($args["result_code"] == "SUCCESS") ? 1 : 2; # 订单状态()
  225. $uid = $exts[0];
  226. $o->uid = $uid; // strpos($uid, '_') > 0 ? substr($uid, 0, strpos($uid, '_')) : $uid; # 玩家uid
  227. $o->amount = intval($args['total_fee']); # 支付金额(微信穿过来是分)。 游戏后台单位是分
  228. $o->callbackInfo = $args['attach']; # 透传参数, uid-uc,zoneid,cpOrderId
  229. $o->sdk_orderid = $args['transaction_id']; # 微信订单id
  230. $o->otherInfo = "wx:" . $args['openid']; # 付款者openid
  231. return $o;
  232. }
  233. /**
  234. * 解析小米通知 2023.6.16
  235. * @param type $args
  236. * @return \loyalsoft\pay\OrderNotice
  237. */
  238. public static function Parse_mipayOrder($args) {
  239. $o = new OrderNotice();
  240. // $exts = explode(',', $args['attach']); # 透传参数
  241. $o->channel = "mi"; # 渠道代码zfb?
  242. $o->cpOrderId = $args['cpOrderId']; # 订单编号(龙游)
  243. $o->status = ($args["orderStatus"] == "TRADE_SUCCESS") ? 1 : 2;
  244. $uidAry = explode('%2C', $args['cpUserInfo']);
  245. $uid = $uidAry[0];
  246. $o->accountId = $uid;
  247. $o->uid = $uid; # 玩家uid
  248. $o->amount = intval($args['payFee']); # 支付金额: 游戏后台单位是分
  249. $o->callbackInfo = str_replace('%2C', ',', $args['cpUserInfo']); # 透传参数, uid,zoneid,cpOrderId
  250. $o->sdk_orderid = $args['orderId']; # 小米订单id
  251. $o->otherInfo = "mi(uid):" . $args['uid']; # 付款者openid
  252. return $o;
  253. }
  254. /**
  255. * 解析应用宝充值通知 2023.5.10
  256. * @param array $args
  257. */
  258. public static function Parse_ysdkOrder($args) {
  259. $o = new OrderNotice();
  260. $o->channel = "yyb"; # 渠道代码
  261. $o->status = 1; # 订单状态(ysdk成功才通知)
  262. $o->uid = $args['openid']; // openid # 玩家uid(不带_yyb)
  263. $o->amount = $args['amt']; # 支付金额, 游戏后台统一单位是分
  264. $appmeta = $args['appmeta']; # 自定义字段*支付方式*平台渠道(qq)
  265. list($callbackInfo, $payType, $plat) = explode('*', $appmeta); # 提取
  266. $o->callbackInfo = $callbackInfo; # 透传参数, uid-uc,zoneid,cpOrderId
  267. list($uid, $zoneid, $cpOrderId) = explode(',', $callbackInfo); # 提取
  268. $o->cpOrderId = $cpOrderId; # 订单编号
  269. $o->otherInfo = $plat . ":" . $o->uid; # 手Qor微信的平台串
  270. return $o;
  271. }
  272. /**
  273. * 解析应用宝充值通知
  274. * @param array $args
  275. */
  276. public static function Parse_yybOrder($args) {
  277. $o = new OrderNotice();
  278. $o->channel = "yyb"; # 渠道代码
  279. $o->cpOrderId = $args['orderId']; # 订单编号
  280. $o->status = ($args["status"] == "1") ? 1 : 2; # 订单状态(易接SDK返回值: 1/成功,其他失败)
  281. $o->uid = $args['uid']; // openid # 玩家uid
  282. $o->amount = $args['amount'] * 100; # 支付金额, 游戏后台统一单位是分
  283. $o->callbackInfo = $args['extReserved']; # 透传参数, uid-uc,zoneid,cpOrderId
  284. $o->otherInfo = $args['pf']; # 手Qor微信的平台串
  285. return $o;
  286. }
  287. /**
  288. * 解析360充值通知
  289. */
  290. public static function Parse_360Order($args) {
  291. $exts = explode(',', $args['app_ext1']);
  292. $o = new OrderNotice();
  293. $o->channel = 'qihoo360';
  294. if (isset($args['app_order_id'])) {
  295. $o->cpOrderId = $args['app_order_id'];
  296. } else {
  297. $o->cpOrderId = $exts[2]; # 第三个参数是cpOrderId
  298. }
  299. $o->sdk_orderid = $args['order_id'];
  300. $o->status = ($args['gateway_flag'] == 'success') ? 1 : 2;
  301. $o->uid = $args['app_uid'];
  302. $o->amount = $args['amount']; # 360通知的单位是分,与后台一致
  303. $o->callbackInfo = $args['app_ext1'];
  304. $o->otherInfo = $args['user_id'];
  305. return $o;
  306. }
  307. /**
  308. * 解析vivo充值通知接口
  309. */
  310. public static function Parse_vivoOrder($args) {
  311. $o = new OrderNotice();
  312. $o->channel = 'vivo';
  313. $o->cpOrderId = $args['cpOrderNumber'];
  314. $o->sdk_orderid = $args['orderNumber'];
  315. $o->status = ($args['tradeStatus'] == '0000') ? 1 : 2;
  316. $o->uid = $args['uid'];
  317. $o->amount = $args['orderAmount']; # vivo通知的单位是分, 与游戏后台一致
  318. $o->callbackInfo = $args['extInfo'];
  319. $o->otherInfo = 'payTime:' . $args['payTime'];
  320. return $o;
  321. }
  322. /**
  323. * 解析联想支付通知
  324. * @param type $args
  325. */
  326. public static function Parse_lenovo($args) {
  327. // var_dump($args);
  328. $exts = explode(',', $args['cpprivate']);
  329. $o = new OrderNotice();
  330. $o->channel = 'lenovo';
  331. $o->cpOrderId = $args['exorderno'];
  332. $o->sdk_orderid = $args['transid'];
  333. $o->status = ($args['result'] == 0) ? 1 : 2;
  334. $o->uid = $exts[0];
  335. $o->amount = $args['money'];
  336. $o->callbackInfo = $args['cpprivate'];
  337. $o->otherInfo = 'payType:' . $args['paytype'];
  338. return $o;
  339. }
  340. /**
  341. * 解析金立支付通知
  342. * @param type $args
  343. */
  344. public static function Parse_gionee($args) {
  345. // var_dump($args);
  346. $exts = explode(',', $args['ext_info']); # 透传参数
  347. $o = new OrderNotice();
  348. $o->channel = 'gionee';
  349. $o->cpOrderId = $args['out_order_no'];
  350. // $o->sdk_orderid = $args['transid']; # 金立订单只在创建的时候返回,通知的时候没有╭(╯^╰)╮
  351. $o->status = 1; # 金立后台只将支付成功的订单进行返回,未成功订单不会有通知
  352. $o->uid = $exts[0];
  353. $o->amount = $args['deal_price'] * 100; # 金立后台单位是元, 游戏后台单位是分
  354. $o->callbackInfo = $args['ext_info'];
  355. // $o->otherInfo = ''; #
  356. return $o;
  357. }
  358. /**
  359. * 解析百度支付通知
  360. * @param type $args
  361. */
  362. public static function Parse_Baidu($args) {
  363. // var_dump($args);
  364. $o = new OrderNotice();
  365. $o->channel = 'baidu';
  366. $o->cpOrderId = $args['CooperatorOrderSerial']; # CP 订单号
  367. $o->sdk_orderid = $args['OrderSerial']; # SDK订单号
  368. $Contents = json_decode(base64_decode(urldecode($args['Content']))); # 数据结构
  369. $o->status = $Contents->OrderStatus == 1 ? 1 : 2; # 0 失败, 1 成功
  370. $o->uid = $Contents->UID; # UID
  371. $o->amount = $Contents->OrderMoney * 100; # 百度后台单位是元, 游戏后台单位是分
  372. $o->callbackInfo = $Contents->ExtInfo; # 透传参数
  373. $o->otherInfo = '银行到账时间:' . $Contents->BankDateTime # 其他信息
  374. . ' 代金券金额:' . $Contents->VoucherMoney; #
  375. return $o;
  376. }
  377. /**
  378. * 解析三星支付通知
  379. * @param type $args
  380. */
  381. public static function Parse_samsung($args) {
  382. $exts = explode(',', $args['cpprivate']);
  383. $o = new OrderNotice();
  384. $o->channel = 'samsung';
  385. if (isset($args['cporderid'])) {
  386. $o->cpOrderId = $args['cporderid'];
  387. } else {
  388. $o->cpOrderId = $exts[2]; // uid,zoneid,cporderid
  389. }
  390. $o->sdk_orderid = $args['transid']; // 平台流水号
  391. $o->status = ($args['result'] == 0) ? 1 : 2;
  392. $o->uid = $args['appuserid'];
  393. $o->amount = $args['money'] * 100; // float 单位:元, Ps.游戏后台是分
  394. $o->callbackInfo = $args['cpprivate'];
  395. $o->otherInfo = 'transtype:' . $args['transtype']; // 交易类型
  396. return $o;
  397. }
  398. /**
  399. * 解析小七手游支付通知
  400. * @param type $args
  401. */
  402. public static function Parse_x7sy($args) {
  403. $exts = explode(',', $args['extends_info_data']);
  404. $o = new OrderNotice();
  405. $o->channel = 'x7sy';
  406. if (isset($args['game_orderid'])) { // cpOrder
  407. $o->cpOrderId = $args['game_orderid'];
  408. } else {
  409. $o->cpOrderId = $exts[2]; // uid,zoneid,cporderid
  410. }
  411. $o->sdk_orderid = $args['xiao7_goid']; // 渠道流水号
  412. $o->status = 1; //($args['result'] == 0) ? 1 : 2; // 只要通知就是成功,不成功的不通知
  413. $o->uid = $args['guid'];
  414. $o->amount = $args['pay_price'] * 100; // float 单位:元, Ps.游戏后台是分
  415. // $o->callbackInfo = $args['cpprivate'];
  416. // $o->otherInfo = 'transtype:' . $args['transtype']; // 交易类型
  417. return $o;
  418. }
  419. // </editor-fold>
  420. //
  421. }