Order.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. namespace addons\cms\library;
  3. use addons\cms\model\Archives;
  4. use app\common\library\Auth;
  5. use app\common\model\User;
  6. use fast\Http;
  7. use fast\Random;
  8. use think\Db;
  9. use think\Exception;
  10. use think\Hook;
  11. use think\Request;
  12. use think\View;
  13. use Yansongda\Pay\Exceptions\GatewayException;
  14. class Order
  15. {
  16. /**
  17. * 获取查询条件
  18. * @return \Closure
  19. */
  20. protected static function getQueryCondition()
  21. {
  22. $condition = function ($query) {
  23. $auth = Auth::instance();
  24. $user_id = $auth->isLogin() ? $auth->id : 0;
  25. $ip = Request::instance()->ip(0, false);
  26. $config = get_addon_config('cms');
  27. //如果开启支付需要登录,则只判断user_id
  28. if ($config['ispaylogin']) {
  29. $query->where('user_id', $user_id);
  30. } else {
  31. if ($user_id) {
  32. $query->whereOr('user_id', $user_id)->whereOr('ip', $ip);
  33. } else {
  34. $query->where('user_id', 0)->where('ip', $ip);
  35. }
  36. }
  37. };
  38. return $condition;
  39. }
  40. /**
  41. * 检查订单
  42. * @param int $id 订单号
  43. * @return bool
  44. */
  45. public static function check($id)
  46. {
  47. $archives = Archives::get($id);
  48. if (!$archives) {
  49. return false;
  50. }
  51. $where = [
  52. 'archives_id' => $id,
  53. 'status' => 'paid',
  54. ];
  55. //如果是作者则直接允许查看
  56. $auth = Auth::instance();
  57. $user_id = $auth->isLogin() ? $auth->id : 0;
  58. if ($user_id && $user_id == $archives->user_id) {
  59. return true;
  60. }
  61. //匹配已支付订单
  62. $order = \addons\cms\model\Order::where($where)->where(self::getQueryCondition())->order('id', 'desc')->find();
  63. return $order ? true : false;
  64. }
  65. /**
  66. * 发起订单支付
  67. *
  68. * @param int $archives_id 文档ID
  69. * @param string $paytype 支付类型
  70. * @param string $method 支付方法
  71. * @param string $openid Openid
  72. * @param string $notifyurl 通知地址
  73. * @param string $returnurl 返回地址
  74. * @return \addons\epay\library\Collection|\addons\epay\library\RedirectResponse|\addons\epay\library\Response|null
  75. * @throws OrderException
  76. */
  77. public static function submit($archives_id, $paytype = 'wechat', $method = 'web', $openid = '', $notifyurl = '', $returnurl = '')
  78. {
  79. $archives = Archives::get($archives_id);
  80. if (!$archives) {
  81. throw new OrderException('文档未找到');
  82. }
  83. $order = \addons\cms\model\Order::where('archives_id', $archives->id)
  84. ->where(self::getQueryCondition())
  85. ->order('id', 'desc')
  86. ->find();
  87. if ($order && $order['status'] == 'paid') {
  88. throw new OrderException('订单已支付');
  89. }
  90. $auth = Auth::instance();
  91. $request = Request::instance();
  92. if (!$order || (time() - $order->createtime) > 600 || $order->amount != $archives->price) {
  93. $orderid = date("YmdHis") . mt_rand(100000, 999999);
  94. $data = [
  95. 'user_id' => $auth->id ? $auth->id : 0,
  96. 'orderid' => $orderid,
  97. 'archives_id' => $archives->id,
  98. 'title' => "付费阅读",
  99. 'amount' => $archives->price,
  100. 'payamount' => 0,
  101. 'paytype' => $paytype,
  102. 'method' => $method,
  103. 'ip' => $request->ip(0, false),
  104. 'useragent' => substr($request->server('HTTP_USER_AGENT'), 0, 255),
  105. 'status' => 'created'
  106. ];
  107. $order = \addons\cms\model\Order::create($data);
  108. } else {
  109. //支付方式变更
  110. if (($order['method'] && $order['paytype'] == $paytype && $order['method'] != $method)) {
  111. $orderid = date("YmdHis") . mt_rand(100000, 999999);
  112. $order->save(['orderid' => $orderid]);
  113. }
  114. //更新支付类型和方法
  115. $order->save(['paytype' => $paytype, 'method' => $method]);
  116. if ($order->amount != $archives->price || $order->paytype != $paytype) {
  117. $order->amount = $archives->price;
  118. $order->paytype = $paytype;
  119. $order->save();
  120. }
  121. }
  122. //使用余额支付
  123. if ($paytype == 'balance') {
  124. if (!$auth->id) {
  125. throw new OrderException('需要登录后才能够支付');
  126. }
  127. if ($auth->money < $archives->price) {
  128. throw new OrderException('余额不足,无法进行支付');
  129. }
  130. Db::startTrans();
  131. try {
  132. User::money(-$archives->price, $auth->id, '购买付费文档:' . $archives['title']);
  133. self::settle($order->orderid);
  134. Db::commit();
  135. } catch (Exception $e) {
  136. Db::rollback();
  137. throw new OrderException($e->getMessage());
  138. }
  139. throw new OrderException('余额支付成功', 1);
  140. }
  141. $response = null;
  142. $epay = get_addon_info('epay');
  143. if ($epay && $epay['state']) {
  144. $notifyurl = $notifyurl ? $notifyurl : $request->root(true) . '/addons/cms/order/epay/type/notify/paytype/' . $paytype;
  145. $returnurl = $returnurl ? $returnurl : $request->root(true) . '/addons/cms/order/epay/type/return/paytype/' . $paytype . '/orderid/' . $order->orderid;
  146. //保证取出的金额一致,不一致将导致订单重复错误
  147. $amount = sprintf("%.2f", $order->amount);
  148. $params = [
  149. 'amount' => $amount,
  150. 'orderid' => $order->orderid,
  151. 'type' => $paytype,
  152. 'title' => "支付{$amount}元",
  153. 'notifyurl' => $notifyurl,
  154. 'returnurl' => $returnurl,
  155. 'method' => $method,
  156. 'openid' => $openid
  157. ];
  158. try {
  159. $response = \addons\epay\library\Service::submitOrder($params);
  160. } catch (GatewayException $e) {
  161. throw new OrderException(config('app_debug') ? $e->getMessage() : "支付失败,请稍后重试");
  162. }
  163. } else {
  164. $result = \think\Hook::listen('cms_order_submit', $order);
  165. if (!$result) {
  166. throw new OrderException("请在后台安装配置微信支付宝整合插件");
  167. }
  168. }
  169. return $response;
  170. }
  171. /**
  172. * 订单结算
  173. * @param mixed $orderid 订单号
  174. * @param mixed $payamount 金额
  175. * @param string $memo 备注
  176. * @return bool
  177. */
  178. public static function settle($orderid, $payamount = null, $memo = '')
  179. {
  180. $order = \addons\cms\model\Order::getByOrderid($orderid);
  181. if (!$order) {
  182. return false;
  183. }
  184. if ($order['status'] != 'paid') {
  185. $payamount = $payamount ? $payamount : $order->amount;
  186. //计算收益
  187. $config = get_addon_config('cms');
  188. list($systemRatio, $userRatio) = explode(':', $config['archivesratio']);
  189. User::money($systemRatio * $payamount, $config['system_user_id'], '付费文章收益');
  190. User::money($userRatio * $payamount, $order->archives->user_id, '付费文章收益');
  191. $order->payamount = $payamount;
  192. $order->paytime = time();
  193. $order->status = 'paid';
  194. $order->memo = $memo;
  195. $order->save();
  196. }
  197. return true;
  198. }
  199. }