UserVipPaymentService.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <?php
  2. namespace app\data\service;
  3. use app\data\model\BaseUserPayment;
  4. use app\data\model\DataUserPayment;
  5. use app\data\model\ShopOrder;
  6. use app\data\service\payment\AlipayPaymentService;
  7. use app\data\service\payment\BalancePaymentService;
  8. use app\data\service\payment\EmptyPaymentService;
  9. use app\data\service\payment\JoinpayPaymentService;
  10. use app\data\service\payment\VoucherPaymentService;
  11. use app\data\service\payment\WechatPaymentService;
  12. use think\admin\Exception;
  13. use think\admin\Library;
  14. use think\App;
  15. /**
  16. * 支付基础服务
  17. * Class U
  18. * @package app\data\service
  19. */
  20. abstract class UserVipPaymentService
  21. {
  22. // 用户余额支付
  23. const PAYMENT_EMPTY = 'empty';
  24. const PAYMENT_BALANCE = 'balance';
  25. const PAYMENT_VOUCHER = 'voucher';
  26. // 汇聚支付参数
  27. const PAYMENT_JOINPAY_GZH = 'joinpay_gzh';
  28. const PAYMENT_JOINPAY_XCX = 'joinpay_xcx';
  29. // 微信商户支付
  30. const PAYMENT_WECHAT_APP = 'wechat_app';
  31. const PAYMENT_WECHAT_GZH = 'wechat_gzh';
  32. const PAYMENT_WECHAT_XCX = 'wechat_xcx';
  33. const PAYMENT_WECHAT_WAP = 'wechat_wap';
  34. const PAYMENT_WECHAT_QRC = 'wechat_qrc';
  35. // 支付宝支付参数
  36. const PAYMENT_ALIAPY_APP = 'alipay_app';
  37. const PAYMENT_ALIPAY_WAP = 'alipay_wap';
  38. const PAYMENT_ALIPAY_WEB = 'alipay_web';
  39. // 支付通道配置,不需要的可以注释
  40. const TYPES = [
  41. // 空支付,金额为零时自动完成支付
  42. self::PAYMENT_EMPTY => [
  43. 'type' => 'EMPTY',
  44. 'name' => '订单无需支付',
  45. 'bind' => [],
  46. ],
  47. // 余额支付,使用账号余额完成支付
  48. self::PAYMENT_BALANCE => [
  49. 'type' => 'BALANCE',
  50. 'name' => '账号余额支付',
  51. 'bind' => [
  52. UserAdminService::API_TYPE_WAP, UserAdminService::API_TYPE_WEB,
  53. UserAdminService::API_TYPE_WXAPP, UserAdminService::API_TYPE_WECHAT,
  54. UserAdminService::API_TYPE_IOSAPP, UserAdminService::API_TYPE_ANDROID,
  55. ],
  56. ],
  57. // 凭证支付,上传凭证后台审核支付
  58. self::PAYMENT_VOUCHER => [
  59. 'type' => 'VOUCHER',
  60. 'name' => '单据凭证支付',
  61. 'bind' => [
  62. UserAdminService::API_TYPE_WAP, UserAdminService::API_TYPE_WEB,
  63. UserAdminService::API_TYPE_WXAPP, UserAdminService::API_TYPE_WECHAT,
  64. UserAdminService::API_TYPE_IOSAPP, UserAdminService::API_TYPE_ANDROID,
  65. ],
  66. ],
  67. // 微信支付配置(不需要的直接注释)
  68. self::PAYMENT_WECHAT_WAP => [
  69. 'type' => 'MWEB',
  70. 'name' => '微信WAP支付',
  71. 'bind' => [UserAdminService::API_TYPE_WAP],
  72. ],
  73. self::PAYMENT_WECHAT_APP => [
  74. 'type' => 'APP',
  75. 'name' => '微信APP支付',
  76. 'bind' => [UserAdminService::API_TYPE_IOSAPP, UserAdminService::API_TYPE_ANDROID],
  77. ],
  78. self::PAYMENT_WECHAT_XCX => [
  79. 'type' => 'JSAPI',
  80. 'name' => '微信小程序支付',
  81. 'bind' => [UserAdminService::API_TYPE_WXAPP],
  82. ],
  83. self::PAYMENT_WECHAT_GZH => [
  84. 'type' => 'JSAPI',
  85. 'name' => '微信公众号支付',
  86. 'bind' => [UserAdminService::API_TYPE_WECHAT],
  87. ],
  88. self::PAYMENT_WECHAT_QRC => [
  89. 'type' => 'NATIVE',
  90. 'name' => '微信二维码支付',
  91. 'bind' => [UserAdminService::API_TYPE_WEB],
  92. ],
  93. // 支付宝支持配置(不需要的直接注释)
  94. self::PAYMENT_ALIPAY_WAP => [
  95. 'type' => '',
  96. 'name' => '支付宝WAP支付',
  97. 'bind' => [UserAdminService::API_TYPE_WAP],
  98. ],
  99. self::PAYMENT_ALIPAY_WEB => [
  100. 'type' => '',
  101. 'name' => '支付宝WEB支付',
  102. 'bind' => [UserAdminService::API_TYPE_WEB],
  103. ],
  104. self::PAYMENT_ALIAPY_APP => [
  105. 'type' => '',
  106. 'name' => '支付宝APP支付',
  107. 'bind' => [UserAdminService::API_TYPE_ANDROID, UserAdminService::API_TYPE_IOSAPP],
  108. ],
  109. // 汇聚支持配置(不需要的直接注释)
  110. self::PAYMENT_JOINPAY_XCX => [
  111. 'type' => 'WEIXIN_XCX',
  112. 'name' => '汇聚小程序支付',
  113. 'bind' => [UserAdminService::API_TYPE_WXAPP],
  114. ],
  115. self::PAYMENT_JOINPAY_GZH => [
  116. 'type' => 'WEIXIN_GZH',
  117. 'name' => '汇聚公众号支付',
  118. 'bind' => [UserAdminService::API_TYPE_WECHAT],
  119. ],
  120. ];
  121. /**
  122. * 支付服务对象
  123. * @var array
  124. */
  125. protected static $driver = [];
  126. /**
  127. * 当前应用
  128. * @var App
  129. */
  130. protected $app;
  131. /**
  132. * 支付参数编号
  133. * @var string
  134. */
  135. protected $code;
  136. /**
  137. * 默认支付类型
  138. * @var string
  139. */
  140. protected $type;
  141. /**
  142. * 当前支付参数
  143. * @var array
  144. */
  145. protected $params;
  146. /**
  147. * PaymentService constructor.
  148. * @param App $app 当前应用对象
  149. * @param string $code 支付参数编号
  150. * @param string $type 支付类型代码
  151. * @param array $params 支付参数配置
  152. */
  153. public function __construct(App $app, string $code, string $type, array $params)
  154. {
  155. [$this->app, $this->code, $this->type, $this->params] = [$app, $code, $type, $params];
  156. if (method_exists($this, 'initialize')) $this->initialize();
  157. }
  158. /**
  159. * 根据配置实例支付服务
  160. * @param string $code 支付配置编号
  161. * @return PaymentService
  162. * @throws \think\admin\Exception
  163. */
  164. public static function instance(string $code): PaymentService
  165. {
  166. if ($code === 'empty') {
  167. $vars = ['code' => 'empty', 'type' => 'empty', 'params' => []];
  168. return static::$driver[$code] = Library::$sapp->make(EmptyPaymentService::class, $vars);
  169. }
  170. [, $type, $params] = self::config($code);
  171. if (isset(static::$driver[$code])) return static::$driver[$code];
  172. $vars = ['code' => $code, 'type' => $type, 'params' => $params];
  173. // 实例化具体支付参数类型
  174. if (stripos($type, 'balance') === 0) {
  175. return static::$driver[$code] = Library::$sapp->make(BalancePaymentService::class, $vars);
  176. } elseif (stripos($type, 'voucher') === 0) {
  177. return static::$driver[$code] = Library::$sapp->make(VoucherPaymentService::class, $vars);
  178. } elseif (stripos($type, 'alipay_') === 0) {
  179. return static::$driver[$code] = Library::$sapp->make(AlipayPaymentService::class, $vars);
  180. } elseif (stripos($type, 'wechat_') === 0) {
  181. return static::$driver[$code] = Library::$sapp->make(WechatPaymentService::class, $vars);
  182. } elseif (stripos($type, 'joinpay_') === 0) {
  183. return static::$driver[$code] = Library::$sapp->make(JoinpayPaymentService::class, $vars);
  184. } else {
  185. throw new Exception(sprintf('支付驱动[%s]未定义', $type));
  186. }
  187. }
  188. /**
  189. * 获取支付配置参数
  190. * @param string $code
  191. * @param array $payment
  192. * @return array [code, type, params]
  193. * @throws Exception
  194. */
  195. public static function config(string $code, array $payment = []): array
  196. {
  197. try {
  198. if (empty($payment)) {
  199. $map = ['code' => $code, 'status' => 1, 'deleted' => 0];
  200. $payment = BaseUserPayment::mk()->where($map)->find();
  201. }
  202. if (empty($payment)) {
  203. throw new Exception("支付参数[#{$code}]禁用关闭");
  204. }
  205. $params = @json_decode($payment['content'], true);
  206. if (empty($params)) {
  207. throw new Exception("支付参数[#{$code}]配置无效");
  208. }
  209. if (empty(static::TYPES[$payment['type']])) {
  210. throw new Exception("支付参数[@{$payment['type']}]匹配失败");
  211. }
  212. return [$payment['code'], $payment['type'], $params];
  213. } catch (\Exception $exception) {
  214. throw new Exception($exception->getMessage(), $exception->getCode());
  215. }
  216. }
  217. /**
  218. * 获取支付支付名称
  219. * @param string $type
  220. * @return string
  221. */
  222. public static function name(string $type): string
  223. {
  224. return static::TYPES[$type]['name'] ?? $type;
  225. }
  226. /**
  227. * 获取支付类型
  228. * @param array $types 默认返回支付
  229. * @return array
  230. */
  231. public static function getTypeAll(array $types = []): array
  232. {
  233. $binds = array_keys(UserAdminService::TYPES);
  234. foreach (static::TYPES as $k => $v) if (isset($v['bind'])) {
  235. if (array_intersect($v['bind'], $binds)) $types[$k] = $v;
  236. }
  237. return $types;
  238. }
  239. /**
  240. * 筛选可用的支付类型
  241. * @param string $api 指定接口类型
  242. * @param array $types 默认返回支付
  243. * @return array
  244. */
  245. public static function getTypeApi(string $api = '', array $types = []): array
  246. {
  247. foreach (self::TYPES as $type => $attr) {
  248. if (in_array($api, $attr['bind'])) $types[] = $type;
  249. }
  250. return array_unique($types);
  251. }
  252. /**
  253. * 订单主动查询
  254. * @param string $orderNo
  255. * @return array
  256. */
  257. abstract public function query(string $orderNo): array;
  258. /**
  259. * 支付通知处理
  260. * @return string
  261. */
  262. abstract public function notify(): string;
  263. /**
  264. * 创建支付订单
  265. * @param string $openid 用户OPENID
  266. * @param string $orderNo 交易订单单号
  267. * @param string $payAmount 交易订单金额(元)
  268. * @param string $payTitle 交易订单名称
  269. * @param string $payRemark 交易订单描述
  270. * @param string $payReturn 支付回跳地址
  271. * @param string $payImage 支付凭证图片
  272. * @return array
  273. */
  274. abstract public function create(string $openid, string $orderNo, string $payAmount, string $payTitle, string $payRemark, string $payReturn = '', string $payImage = ''): array;
  275. /**
  276. * 创建支付行为
  277. * @param string $orderNo 商户订单单号
  278. * @param string $payTitle 商户订单标题
  279. * @param string $payAmount 需要支付金额
  280. */
  281. protected function createPaymentAction(string $orderNo, string $payTitle, string $payAmount)
  282. {
  283. DataUserPayment::mk()->insert([
  284. 'payment_code' => $this->code,
  285. 'payment_type' => $this->type,
  286. 'order_no' => $orderNo,
  287. 'order_name' => $payTitle,
  288. 'order_amount' => $payAmount,
  289. ]);
  290. }
  291. /**
  292. * 更新支付记录并更新订单
  293. * @param string $orderNo 商户订单单号
  294. * @param string $payTrade 平台交易单号
  295. * @param string $payAmount 实际到账金额
  296. * @param string $payRemark 平台支付备注
  297. * @return boolean
  298. */
  299. protected function updatePaymentAction(string $orderNo, string $payTrade, string $payAmount, string $payRemark = '在线支付'): bool
  300. {
  301. // 更新支付记录
  302. DataUserPayment::mUpdate([
  303. 'order_no' => $orderNo,
  304. 'payment_code' => $this->code,
  305. 'payment_type' => $this->type,
  306. 'payment_trade' => $payTrade,
  307. 'payment_amount' => $payAmount,
  308. 'payment_status' => 1,
  309. 'payment_datetime' => date('Y-m-d H:i:s'),
  310. ], 'order_no', [
  311. 'payment_code' => $this->code,
  312. 'payment_type' => $this->type,
  313. ]);
  314. // 更新记录状态
  315. return $this->updatePaymentOrder($orderNo, $payTrade, $payAmount, $payRemark);
  316. }
  317. /**
  318. * 订单支付更新操作
  319. * @param string $orderNo 订单单号
  320. * @param string $payTrade 交易单号
  321. * @param string $payAmount 支付金额
  322. * @param string $payRemark 支付描述
  323. * @param string $payImage 支付凭证
  324. * @return boolean
  325. */
  326. protected function updatePaymentOrder(string $orderNo, string $payTrade, string $payAmount, string $payRemark = '在线支付', string $payImage = ''): bool
  327. {
  328. $map = ['status' => 2, 'order_no' => $orderNo, 'payment_status' => 0];
  329. $order = ShopOrder::mk()->where($map)->findOrEmpty();
  330. if ($order->isEmpty()) return false;
  331. // 检查订单支付状态
  332. if ($this->type === self::PAYMENT_VOUCHER) {
  333. $status = 3; # 凭证支付需要审核
  334. } elseif (empty($order['truck_type'])) {
  335. $status = 6; # 虚拟订单直接完成
  336. } else {
  337. $status = 4; # 实物订单需要发货
  338. }
  339. // 更新订单支付状态
  340. $order['status'] = $status;
  341. $order['payment_code'] = $this->code;
  342. $order['payment_type'] = $this->type;
  343. $order['payment_trade'] = $payTrade;
  344. $order['payment_image'] = $payImage;
  345. $order['payment_amount'] = $payAmount;
  346. $order['payment_remark'] = $payRemark;
  347. $order['payment_status'] = 1;
  348. $order['payment_datetime'] = date('Y-m-d H:i:s');
  349. $order->save();
  350. // 触发订单更新事件
  351. if ($status >= 4) {
  352. $this->app->event->trigger('ShopOrderPayment', $orderNo);
  353. }
  354. return true;
  355. }
  356. }