PayPlusCashierLogic.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <?php
  2. namespace App\Http\logic\api;
  3. use App\dao\Estatisticas\RechargeWithDraw;
  4. use App\Http\helper\NumConfig;
  5. use App\Inter\CashierInterFace;
  6. use App\Models\PrivateMail;
  7. use App\Models\RecordUserDataStatistics;
  8. use App\Services\PayPlus;
  9. use App\Services\StoredProcedure;
  10. use App\Util;
  11. use Illuminate\Support\Facades\DB;
  12. use Illuminate\Support\Facades\Redis;
  13. class PayPlusCashierLogic implements CashierInterFace
  14. {
  15. const AGENT = 109;
  16. protected $service;
  17. public function __construct(PayPlus $service = null)
  18. {
  19. $this->service = $service ?: (new PayPlus())->getPayoutService();
  20. }
  21. public function payment(
  22. $RecordID,
  23. $amount,
  24. $accountName,
  25. $phone,
  26. $email,
  27. $OrderId,
  28. $PixNum,
  29. $PixType,
  30. $IFSCNumber,
  31. $BranchBank,
  32. $BankNO
  33. ) {
  34. $query = DB::connection('write')
  35. ->table('QPAccountsDB.dbo.OrderWithDraw')
  36. ->where('RecordID', $RecordID)
  37. ->first();
  38. if (!$query) {
  39. return 'fail';
  40. }
  41. $result = $this->createBeneficiaryAndPayout([
  42. 'user_id' => $query->UserID,
  43. 'amount' => round($amount / NumConfig::NUM_VALUE, 2),
  44. 'currency' => $this->service->getConfig()['currency'] ?? 'USD',
  45. 'order_id' => $OrderId,
  46. 'pix_type' => $PixType,
  47. 'cashapp_account' => $PixNum,
  48. 'email' => $email,
  49. 'phone' => $phone,
  50. 'name' => $accountName,
  51. ]);
  52. if ($result && isset($result['code']) && (int) $result['code'] === 200) {
  53. return $result;
  54. }
  55. return 'fail';
  56. }
  57. public function createBeneficiaryAndPayout(array $input)
  58. {
  59. $beneficiary = $this->resolveBeneficiary($input);
  60. if (!$beneficiary) {
  61. return false;
  62. }
  63. $payload = [
  64. 'amount' => (float) $input['amount'],
  65. 'currency' => strtoupper($input['currency'] ?? ($this->service->getConfig()['currency'] ?? 'USD')),
  66. 'reference_id' => (string) $input['order_id'],
  67. 'beneficiary_id' => (int) $beneficiary['beneficiary_id'],
  68. ];
  69. if ((int) ($input['pix_type'] ?? 1) === 2) {
  70. $payload['paypal_email'] = $input['email'] ?: $beneficiary['email'];
  71. return $this->service->postPayout('/rest/v2/payouts/paypal', $payload);
  72. }
  73. $cashAppAccount = (string) ($input['cashapp_account'] ?? '');
  74. if ($cashAppAccount !== '' && strpos($cashAppAccount, '$') !== 0) {
  75. $cashAppAccount = '$' . $cashAppAccount;
  76. }
  77. $payload['cashapp_account'] = $cashAppAccount ?: '$unknown';
  78. return $this->service->postPayout('/rest/v2/payouts/cashApp', $payload);
  79. }
  80. public function resolveBeneficiary(array $input)
  81. {
  82. $payload = $this->service->buildBeneficiaryPayload($input);
  83. $created = $this->service->postPayout('/rest/v2/beneficiaries/create', $payload);
  84. if ((int) ($created['code'] ?? 0) === 200 && !empty($created['data']['beneficiary_id'])) {
  85. return $created['data'];
  86. }
  87. if ((int) ($created['code'] ?? 0) !== 4002001) {
  88. Util::WriteLog('PayPlus_error', 'beneficiary create failed: ' . json_encode($created));
  89. return false;
  90. }
  91. $query = $this->service->postPayout('/rest/v2/beneficiaries/query', [
  92. 'payee_id' => $payload['payee_id'],
  93. ]);
  94. if ((int) ($query['code'] ?? 0) === 200 && !empty($query['data']['beneficiary_id'])) {
  95. return $query['data'];
  96. }
  97. Util::WriteLog('PayPlus_error', 'beneficiary query failed: ' . json_encode($query));
  98. return false;
  99. }
  100. public function notify($post)
  101. {
  102. if (!is_array($post)) {
  103. $post = json_decode($post, true) ?: [];
  104. }
  105. $detail = $this->queryPayoutDetailForNotify($post);
  106. if (empty($detail)) {
  107. return 'success';
  108. }
  109. $orderId = $detail['reference_id'] ?? ($post['reference_id'] ?? '');
  110. if ($orderId === '') {
  111. return 'success';
  112. }
  113. $query = DB::connection('write')
  114. ->table('QPAccountsDB.dbo.OrderWithDraw')
  115. ->where('OrderId', $orderId)
  116. ->first();
  117. if (!$query || ($query->State != 5 && $query->State != 7)) {
  118. return 'success';
  119. }
  120. $orderStatus = $this->resolvePayoutStatus($detail['transaction_status'] ?? '');
  121. if (!$orderStatus) {
  122. return 'success';
  123. }
  124. $agent = DB::connection('write')->table('agent.dbo.admin_configs')
  125. ->where('config_value', self::AGENT)
  126. ->where('type', 'cash')
  127. ->select('id')
  128. ->first();
  129. $agentId = $agent->id ?? '';
  130. $now = now();
  131. $userId = $query->UserID;
  132. $takeMoney = $query->WithDraw + $query->ServiceFee;
  133. $withdrawData = [
  134. 'agent' => $agentId,
  135. 'finishDate' => $now,
  136. 'remark' => json_encode([
  137. 'notify' => $post,
  138. 'query' => $detail,
  139. ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
  140. ];
  141. if ($orderStatus === 1) {
  142. $withdrawData['State'] = 2;
  143. $this->handleSuccess($query, $takeMoney);
  144. } else {
  145. $withdrawData['State'] = 6;
  146. $failedMessage = $detail['description'] ?? ($post['msg'] ?? 'REJECTED');
  147. PrivateMail::failMail($userId, $orderId, $takeMoney, $failedMessage, '30000,' . $takeMoney);
  148. }
  149. DB::connection('write')->table('QPAccountsDB.dbo.AccountsRecord')->updateOrInsert(
  150. ['RecordID' => $query->RecordID, 'type' => 1],
  151. [
  152. 'before_state' => $query->State,
  153. 'after_state' => $withdrawData['State'],
  154. 'RecordID' => $query->RecordID,
  155. 'update_at' => date('Y-m-d H:i:s'),
  156. ]
  157. );
  158. DB::connection('write')
  159. ->table('QPAccountsDB.dbo.OrderWithDraw')
  160. ->where('OrderId', $query->OrderId)
  161. ->update($withdrawData);
  162. return 'success';
  163. }
  164. public function queryPayoutDetailForNotify(array $post)
  165. {
  166. $transactionId = (string) ($post['transaction_id'] ?? '');
  167. $referenceId = (string) ($post['reference_id'] ?? '');
  168. if ($transactionId === '' && $referenceId === '') {
  169. return [];
  170. }
  171. try {
  172. $result = $this->service->queryPayoutOrder($transactionId, $referenceId);
  173. } catch (\Exception $exception) {
  174. Util::WriteLog('PayPlus_error', 'payout query failed: ' . $exception->getMessage());
  175. return [];
  176. }
  177. if ((int) ($result['code'] ?? 0) !== 200 || empty($result['data']) || !is_array($result['data'])) {
  178. Util::WriteLog('PayPlus_error', 'payout query invalid response: ' . json_encode($result));
  179. return [];
  180. }
  181. return $result['data'];
  182. }
  183. public function resolvePayoutStatus($status)
  184. {
  185. switch (strtoupper((string) $status)) {
  186. case 'PAID':
  187. return 1;
  188. case 'REJECTED':
  189. case 'REFUNDED':
  190. return 2;
  191. default:
  192. return 0;
  193. }
  194. }
  195. protected function handleSuccess($query, $takeMoney)
  196. {
  197. $userId = $query->UserID;
  198. $first = DB::connection('write')
  199. ->table('QPAccountsDB.dbo.UserTabData')
  200. ->where('UserID', $userId)
  201. ->first();
  202. if ($first) {
  203. DB::connection('write')
  204. ->table('QPAccountsDB.dbo.UserTabData')
  205. ->where('UserID', $userId)
  206. ->increment('TakeMoney', $takeMoney);
  207. } else {
  208. DB::connection('write')
  209. ->table('QPAccountsDB.dbo.UserTabData')
  210. ->insert(['TakeMoney' => $takeMoney, 'UserID' => $userId]);
  211. PrivateMail::praiseSendMail($userId);
  212. }
  213. try {
  214. StoredProcedure::addPlatformData($userId, 4, $takeMoney);
  215. } catch (\Exception $exception) {
  216. Util::WriteLog('StoredProcedure', $exception);
  217. }
  218. RecordUserDataStatistics::updateOrAdd($userId, $takeMoney, 0, $query->ServiceFee);
  219. (new RechargeWithDraw())->withDraw($userId, $takeMoney, 0, $query->ServiceFee);
  220. Redis::connection()->incr('draw_' . date('Ymd') . $userId);
  221. PrivateMail::successMail($userId, $query->OrderId, $takeMoney);
  222. StoredProcedure::user_label($userId, 2, $takeMoney);
  223. }
  224. }