PayMentService.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. namespace App\Services;
  3. use App\Http\Controllers\Api\AegPayController;
  4. use App\Http\Controllers\Api\AppleStorePayController;
  5. use App\Http\Controllers\Api\CryptoController;
  6. use App\Http\Controllers\Api\GooglePayController;
  7. use App\Http\Controllers\Api\GoopagoController;
  8. use App\Http\Controllers\Api\SitoBankController;
  9. use App\Http\Controllers\Api\WiwiPayController;
  10. use App\Http\Controllers\Api\WDPayController;
  11. use App\Http\Controllers\Api\CoinPayController;
  12. use App\Http\Controllers\Api\AiPayController;
  13. use App\Http\Controllers\Api\PagYeepPayController;
  14. use App\Http\Controllers\Api\AiNewPayController;
  15. use Illuminate\Support\Facades\DB;
  16. use Illuminate\Support\Facades\Log;
  17. use Illuminate\Support\Facades\Redis;
  18. class PayMentService
  19. {
  20. public static function pay_order($transport = null)
  21. {
  22. switch ($transport) {
  23. case 'WiwiPay':
  24. return new WiwiPayController();
  25. case 'WDPay':
  26. return new WDPayController();
  27. case 'CoinPay':
  28. return new CoinPayController();
  29. case 'AiPay':
  30. return new AiPayController();
  31. case 'PagYeepPay':
  32. return new PagYeepPayController();
  33. case 'AiNewPay':
  34. return new AiNewPayController();
  35. case 'apple':
  36. return new AppleStorePayController();
  37. case 'google':
  38. return new GooglePayController();
  39. default:
  40. throw new \Exception('unknown pay channel:'.$transport);
  41. }
  42. }
  43. /**
  44. * 根据支付方式随机获取充值渠道
  45. * @param $method
  46. * @param $channel
  47. * @return bool|mixed
  48. */
  49. /*public static function getServiceByPayMethod3($method, $channel)
  50. {
  51. // $switch = Redis::get("recharge_config_switch_{$channel}");
  52. // if ($channel && $switch) {
  53. // $services = DB::connection('write')
  54. // ->table('QPPlatformDB.dbo.ChannelOpenRecharge')
  55. // ->join(
  56. // 'agent.dbo.admin_configs',
  57. // 'admin_configs.id',
  58. // '=',
  59. // 'ChannelOpenRecharge.ConfigID'
  60. // )
  61. // ->where('admin_configs.new_pay_type', $method)
  62. // ->where('admin_configs.type', 'pay')
  63. // ->where('admin_configs.status', 1)
  64. // ->where('ChannelOpenRecharge.Status', 1)
  65. // ->where('ChannelOpenRecharge.Channel', $channel)
  66. // ->where('ChannelOpenRecharge.Sort', '>', 0)
  67. // ->selectRaw('admin_configs.config_key, ChannelOpenRecharge.Sort as sort')
  68. // ->get();
  69. // }
  70. $services = DB::table('agent.dbo.admin_configs')->where([
  71. 'new_pay_type' => $method,
  72. 'type' => 'pay',
  73. 'status' => 1,
  74. ])->get();
  75. if (!$services->count()) {
  76. Log::error('支付渠道配置异常', [
  77. 'method' => $method,
  78. ]);
  79. return false;
  80. }
  81. $matrix = [];
  82. foreach ($services as $v) {
  83. for ($i = 0; $i < $v->sort; $i++) {
  84. $matrix[] = $v->config_key;
  85. }
  86. }
  87. $res = $matrix[mt_rand(0, count($matrix)-1)];
  88. return $res;
  89. }*/
  90. /**
  91. * 根据支付方式随机获取充值渠道
  92. * @param $method
  93. * @param $channel
  94. * @return bool|mixed
  95. */
  96. public static function getServiceByPayMethod($method, $payAmt,$pay_method)
  97. {
  98. $services = DB::table('agent.dbo.admin_configs')->where([
  99. 'new_pay_type' => $method,
  100. 'type' => 'pay',
  101. 'status' => 1,
  102. ])->whereRaw('pay_types&'.$pay_method.'='.$pay_method)
  103. ->where('min_amount', '<=', $payAmt)
  104. ->where('max_amount', '>=', $payAmt)
  105. ->get();
  106. if (!$services->count()) {
  107. Log::error('支付渠道配置异常', [
  108. 'method' => $method,
  109. ]);
  110. return false;
  111. }
  112. $matrix = [];
  113. foreach ($services as $v) {
  114. $remarks = [];
  115. if (!empty($v->remarks)) {
  116. $decoded = json_decode($v->remarks, true);
  117. if (is_array($decoded)) {
  118. $remarks = $decoded;
  119. }
  120. }
  121. // 按支付类型校验金额是否在允许范围内:不满足则跳过该渠道
  122. if (isset($remarks['limit'])) {
  123. $typeKey = 'type_' . $pay_method;
  124. $limitConfig = $remarks['limit'][$typeKey] ?? null;
  125. if ($limitConfig !== null && !self::isAmountInLimit($payAmt, $limitConfig)) {
  126. continue;
  127. }
  128. }
  129. // 新逻辑:优先按支付方式独立权重分配渠道;未配置时回退旧 sort 逻辑
  130. $weight = self::resolveMethodWeight($remarks, $pay_method, (int)$v->sort);
  131. if ($weight <= 0) {
  132. continue;
  133. }
  134. for ($i = 0; $i < $weight; $i++) {
  135. $matrix[] = $v->config_key;
  136. }
  137. }
  138. if(count($matrix)==0) {
  139. foreach ($services as $v) {
  140. for ($i = 0; $i < $v->sort; $i++) {
  141. $matrix[] = $v->config_key;
  142. }
  143. }
  144. }
  145. $res = $matrix[mt_rand(0, count($matrix)-1)];
  146. return $res;
  147. }
  148. /**
  149. * 解析指定支付方式的渠道权重(从 remarks 读取),未配置时回退默认权重
  150. * remarks 支持:
  151. * {"weight":{"type_1":30,"type_2":20,"type_4":10,"type_8":40}}
  152. * {"weights":{"type_1":30,"type_2":20}}
  153. * @param array $remarks
  154. * @param int $payMethod
  155. * @param int $defaultWeight
  156. * @return int
  157. */
  158. public static function resolveMethodWeight(array $remarks, $payMethod, $defaultWeight = 0)
  159. {
  160. $typeKey = 'type_' . (int)$payMethod;
  161. $weightConfig = $remarks['weight'] ?? ($remarks['weights'] ?? null);
  162. if (is_array($weightConfig) && array_key_exists($typeKey, $weightConfig)) {
  163. return max(0, (int)$weightConfig[$typeKey]);
  164. }
  165. return max(0, (int)$defaultWeight);
  166. }
  167. /**
  168. * 判断支付金额是否在 limit 配置的取值范围内
  169. * @param float $payAmt 支付金额
  170. * @param mixed $limitConfig 配置:数组为允许金额列表;['min'=>x,'max'=>y] 为区间;'all' 或 ['全部'] 为不限制
  171. * @return bool
  172. */
  173. public static function isAmountInLimit($payAmt, $limitConfig)
  174. {
  175. if ($limitConfig === 'all' || $limitConfig === '全部' || $limitConfig === ['全部']) {
  176. return true;
  177. }
  178. if (isset($limitConfig['min']) && isset($limitConfig['max'])) {
  179. $min = (float)$limitConfig['min'];
  180. $max = (float)$limitConfig['max'];
  181. $amt = (float)$payAmt;
  182. return $amt >= $min && $amt <= $max;
  183. }
  184. if (is_array($limitConfig)) {
  185. $payAmtRounded = round((float)$payAmt, 2);
  186. foreach ($limitConfig as $allowed) {
  187. if (round((float)$allowed, 2) === $payAmtRounded) {
  188. return true;
  189. }
  190. }
  191. return false;
  192. }
  193. return true;
  194. }
  195. /**
  196. * 根据支付方式随机获取充值渠道
  197. * @param $method
  198. * @param $channel
  199. * @return bool|mixed
  200. */
  201. public static function getServiceByPayCountry($method, $channel,$country,$except_channelName="")
  202. {
  203. $except_configKeys=[$except_channelName];
  204. $switch = Redis::get("recharge_config_switch_{$channel}");
  205. if ($channel && $switch) {
  206. $services = DB::connection('write')
  207. ->table('QPPlatformDB.dbo.ChannelOpenRecharge')
  208. ->join(
  209. 'agent.dbo.admin_configs',
  210. 'admin_configs.id',
  211. '=',
  212. 'ChannelOpenRecharge.ConfigID'
  213. )
  214. ->where('admin_configs.new_pay_type', $method)
  215. ->whereNotIn('admin_configs.config_key',$except_configKeys)
  216. ->where('admin_configs.country', $country)
  217. ->where('admin_configs.type', 'pay')
  218. ->where('admin_configs.status', 1)
  219. ->where('ChannelOpenRecharge.Status', 1)
  220. ->where('ChannelOpenRecharge.Channel', $channel)
  221. ->where('ChannelOpenRecharge.Sort', '>', 0)
  222. ->selectRaw('admin_configs.config_key, ChannelOpenRecharge.Sort as sort')
  223. ->get();
  224. }
  225. if (!isset($services) || !$services->count()) {
  226. $services = DB::table('agent.dbo.admin_configs')->where([
  227. 'new_pay_type' => $method,
  228. 'type' => 'pay',
  229. 'status' => 1,
  230. 'country' => $country,
  231. ])->get();
  232. if (!$services->count()) {
  233. Log::error('支付渠道配置异常', [
  234. 'method' => $method,
  235. ]);
  236. return false;
  237. }
  238. }
  239. $matrix = [];
  240. foreach ($services as $v) {
  241. for ($i = 0; $i < $v->sort; $i++) {
  242. if(Redis::exists("PayErro_".$v->config_key)) continue;
  243. $matrix[] = $v->config_key;
  244. }
  245. }
  246. if(count($matrix)==0) {
  247. foreach ($services as $v) {
  248. for ($i = 0; $i < $v->sort; $i++) {
  249. $matrix[] = $v->config_key;
  250. }
  251. }
  252. }
  253. $res = $matrix[mt_rand(0, count($matrix)-1)];
  254. return $res;
  255. }
  256. }