TransferService.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. <?php
  2. namespace App\Module\Transfer\Services;
  3. use App\Module\Transfer\Dtos\TransferAppDto;
  4. use App\Module\Transfer\Dtos\TransferOrderDto;
  5. use App\Module\Transfer\Logics\TransferLogic;
  6. use App\Module\Transfer\Models\TransferApp;
  7. use App\Module\Transfer\Models\TransferOrder;
  8. use App\Module\Transfer\Services\FeeService;
  9. /**
  10. * Transfer模块对外服务接口
  11. * 供其他模块调用的主要服务类
  12. */
  13. class TransferService
  14. {
  15. /**
  16. * 创建转出订单
  17. *
  18. * @param int $transferAppId 划转应用ID
  19. * @param int $userId 用户ID
  20. * @param string $amount 转出金额
  21. * @param string $password 安全密码
  22. * @param string|null $googleCode 谷歌验证码
  23. * @param string|null $outUserId 外部用户ID
  24. * @param string|null $remark 备注
  25. * @param array $callbackData 回调数据
  26. * @return TransferOrderDto|string 成功返回DTO,失败返回错误信息
  27. */
  28. public static function createTransferOut(
  29. int $transferAppId,
  30. int $userId,
  31. string $amount,
  32. string $password,
  33. ?string $googleCode = null,
  34. ?string $outUserId = null,
  35. ?string $remark = null,
  36. array $callbackData = []
  37. ): TransferOrderDto|string {
  38. try {
  39. $data = [
  40. 'transfer_app_id' => $transferAppId,
  41. 'user_id' => $userId,
  42. 'amount' => $amount,
  43. 'password' => $password,
  44. 'google_code' => $googleCode,
  45. 'out_user_id' => $outUserId,
  46. 'remark' => $remark,
  47. 'callback_data' => $callbackData,
  48. ];
  49. $order = TransferLogic::createTransferOutFromArray($data);
  50. return TransferOrderDto::fromModel($order);
  51. } catch (\Exception $e) {
  52. return $e->getMessage();
  53. }
  54. }
  55. /**
  56. * 创建转入订单
  57. *
  58. * @param int $transferAppId 划转应用ID
  59. * @param int $userId 用户ID
  60. * @param string $businessId 业务订单ID
  61. * @param string $amount 转入金额
  62. * @param string|null $outUserId 外部用户ID
  63. * @param string|null $remark 备注
  64. * @param array $callbackData 回调数据
  65. * @return TransferOrderDto|string 成功返回DTO,失败返回错误信息
  66. */
  67. public static function createTransferIn(
  68. int $transferAppId,
  69. int $userId,
  70. string $businessId,
  71. string $amount,
  72. ?string $outUserId = null,
  73. ?string $remark = null,
  74. array $callbackData = []
  75. ): TransferOrderDto|string {
  76. try {
  77. $data = [
  78. 'transfer_app_id' => $transferAppId,
  79. 'user_id' => $userId,
  80. 'business_id' => $businessId,
  81. 'amount' => $amount,
  82. 'out_user_id' => $outUserId,
  83. 'remark' => $remark,
  84. 'callback_data' => $callbackData,
  85. ];
  86. $order = TransferLogic::createTransferInFromArray($data);
  87. return TransferOrderDto::fromModel($order);
  88. } catch (\Exception $e) {
  89. return $e->getMessage();
  90. }
  91. }
  92. /**
  93. * 查询订单信息
  94. *
  95. * @param int $orderId 订单ID
  96. * @param int|null $userId 用户ID(可选,用于权限验证)
  97. * @return TransferOrderDto|null
  98. */
  99. public static function getOrderInfo(int $orderId, ?int $userId = null): ?TransferOrderDto
  100. {
  101. $query = TransferOrder::where('id', $orderId);
  102. if ($userId !== null) {
  103. $query->where('user_id', $userId);
  104. }
  105. $order = $query->first();
  106. return $order ? TransferOrderDto::fromModel($order) : null;
  107. }
  108. /**
  109. * 根据外部订单ID查询订单信息
  110. *
  111. * @param string $outOrderId 外部订单ID
  112. * @param int $outId 开放接口ID
  113. * @return TransferOrderDto|null
  114. */
  115. public static function getOrderByOutId(string $outOrderId, int $outId): ?TransferOrderDto
  116. {
  117. $order = TransferOrder::where('out_order_id', $outOrderId)
  118. ->where('out_id', $outId)
  119. ->first();
  120. return $order ? TransferOrderDto::fromModel($order) : null;
  121. }
  122. /**
  123. * 获取用户可用的划转应用列表
  124. *
  125. * @param int $userId 用户ID
  126. * @return TransferAppDto[]
  127. */
  128. public static function getAvailableApps(int $userId): array
  129. {
  130. $apps = TransferApp::where('is_enabled', true)->get();
  131. return $apps->map(function ($app) {
  132. return TransferAppDto::fromModel($app);
  133. })->toArray();
  134. }
  135. /**
  136. * 获取用户订单列表
  137. *
  138. * @param int $userId 用户ID
  139. * @param array $filters 筛选条件
  140. * @return array
  141. */
  142. public static function getUserOrders(int $userId, array $filters = []): array
  143. {
  144. $query = TransferOrder::where('user_id', $userId);
  145. // 应用筛选条件
  146. if (isset($filters['type'])) {
  147. $query->where('type', $filters['type']);
  148. }
  149. if (isset($filters['status'])) {
  150. $query->where('status', $filters['status']);
  151. }
  152. if (isset($filters['transfer_app_id'])) {
  153. $query->where('transfer_app_id', $filters['transfer_app_id']);
  154. }
  155. if (isset($filters['start_date'])) {
  156. $query->where('created_at', '>=', $filters['start_date']);
  157. }
  158. if (isset($filters['end_date'])) {
  159. $query->where('created_at', '<=', $filters['end_date']);
  160. }
  161. // 分页参数
  162. $page = $filters['page'] ?? 1;
  163. $perPage = $filters['per_page'] ?? 20;
  164. $orders = $query->orderBy('created_at', 'desc')
  165. ->paginate($perPage, ['*'], 'page', $page);
  166. return [
  167. 'data' => $orders->items(),
  168. 'current_page' => $orders->currentPage(),
  169. 'per_page' => $orders->perPage(),
  170. 'total' => $orders->total(),
  171. 'last_page' => $orders->lastPage(),
  172. ];
  173. }
  174. /**
  175. * 获取应用配置信息
  176. *
  177. * @param int $appId 应用ID
  178. * @return TransferAppDto|null
  179. */
  180. public static function getAppConfig(int $appId): ?TransferAppDto
  181. {
  182. $app = TransferApp::find($appId);
  183. return $app ? TransferAppDto::fromModel($app) : null;
  184. }
  185. /**
  186. * 根据应用标识获取配置信息
  187. *
  188. * @param string $keyname 应用标识
  189. * @return TransferAppDto|null
  190. */
  191. public static function getAppByKeyname(string $keyname): ?TransferAppDto
  192. {
  193. $app = TransferApp::where('keyname', $keyname)
  194. ->where('is_enabled', true)
  195. ->first();
  196. return $app ? TransferAppDto::fromModel($app) : null;
  197. }
  198. /**
  199. * 处理回调结果
  200. *
  201. * @param array $callbackData 回调数据
  202. * @return bool
  203. */
  204. public static function processCallback(array $callbackData): bool
  205. {
  206. try {
  207. return TransferLogic::processCallback($callbackData);
  208. } catch (\Exception $e) {
  209. \Log::error('Transfer callback processing failed', [
  210. 'error' => $e->getMessage(),
  211. 'data' => $callbackData
  212. ]);
  213. return false;
  214. }
  215. }
  216. /**
  217. * 快速创建转出订单(简化版本,用于测试或内部调用)
  218. *
  219. * @param int $transferAppId 划转应用ID
  220. * @param int $userId 用户ID
  221. * @param string $amount 转出金额
  222. * @param string $password 安全密码
  223. * @return TransferOrderDto|string
  224. */
  225. public static function quickCreateTransferOut(
  226. int $transferAppId,
  227. int $userId,
  228. string $amount,
  229. string $password
  230. ): TransferOrderDto|string {
  231. return self::createTransferOut(
  232. transferAppId: $transferAppId,
  233. userId: $userId,
  234. amount: $amount,
  235. password: $password
  236. );
  237. }
  238. /**
  239. * 快速创建转入订单(简化版本,用于测试或内部调用)
  240. *
  241. * @param int $transferAppId 划转应用ID
  242. * @param int $userId 用户ID
  243. * @param string $businessId 业务订单ID
  244. * @param string $amount 转入金额
  245. * @return TransferOrderDto|string
  246. */
  247. public static function quickCreateTransferIn(
  248. int $transferAppId,
  249. int $userId,
  250. string $businessId,
  251. string $amount
  252. ): TransferOrderDto|string {
  253. return self::createTransferIn(
  254. transferAppId: $transferAppId,
  255. userId: $userId,
  256. businessId: $businessId,
  257. amount: $amount
  258. );
  259. }
  260. /**
  261. * 从数组创建转出订单(向后兼容方法)
  262. *
  263. * @param array $data 订单数据
  264. * @return TransferOrderDto|string
  265. * @deprecated 建议使用 createTransferOut() 方法
  266. */
  267. public static function createTransferOutFromArray(array $data): TransferOrderDto|string
  268. {
  269. try {
  270. $order = TransferLogic::createTransferOutFromArray($data);
  271. return TransferOrderDto::fromModel($order);
  272. } catch (\Exception $e) {
  273. return $e->getMessage();
  274. }
  275. }
  276. /**
  277. * 从数组创建转入订单(向后兼容方法)
  278. *
  279. * @param array $data 订单数据
  280. * @return TransferOrderDto|string
  281. * @deprecated 建议使用 createTransferIn() 方法
  282. */
  283. public static function createTransferInFromArray(array $data): TransferOrderDto|string
  284. {
  285. try {
  286. $order = TransferLogic::createTransferInFromArray($data);
  287. return TransferOrderDto::fromModel($order);
  288. } catch (\Exception $e) {
  289. return $e->getMessage();
  290. }
  291. }
  292. /**
  293. * 计算转入手续费
  294. *
  295. * @param int $transferAppId 划转应用ID
  296. * @param string $amount 转入金额
  297. * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
  298. */
  299. public static function calculateInFee(int $transferAppId, string $amount): array
  300. {
  301. try {
  302. $app = TransferApp::findOrFail($transferAppId);
  303. return FeeService::calculateInFee($app, $amount);
  304. } catch (\Exception $e) {
  305. return [
  306. 'fee_rate' => 0.0000,
  307. 'fee_amount' => '0.0000',
  308. 'actual_amount' => $amount,
  309. 'error' => $e->getMessage(),
  310. ];
  311. }
  312. }
  313. /**
  314. * 计算转出手续费
  315. *
  316. * @param int $transferAppId 划转应用ID
  317. * @param string $amount 转出金额
  318. * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
  319. */
  320. public static function calculateOutFee(int $transferAppId, string $amount): array
  321. {
  322. try {
  323. $app = TransferApp::findOrFail($transferAppId);
  324. return FeeService::calculateOutFee($app, $amount);
  325. } catch (\Exception $e) {
  326. return [
  327. 'fee_rate' => 0.0000,
  328. 'fee_amount' => '0.0000',
  329. 'actual_amount' => $amount,
  330. 'error' => $e->getMessage(),
  331. ];
  332. }
  333. }
  334. /**
  335. * 获取应用的手续费配置
  336. *
  337. * @param int $transferAppId 划转应用ID
  338. * @return array
  339. */
  340. public static function getFeeConfig(int $transferAppId): array
  341. {
  342. try {
  343. $app = TransferApp::findOrFail($transferAppId);
  344. return FeeService::getFeeConfig($app);
  345. } catch (\Exception $e) {
  346. return [
  347. 'error' => $e->getMessage(),
  348. 'in' => ['rate' => 0, 'min' => 0, 'max' => 0, 'enabled' => false],
  349. 'out' => ['rate' => 0, 'min' => 0, 'max' => 0, 'enabled' => false],
  350. 'account_uid' => 0,
  351. ];
  352. }
  353. }
  354. /**
  355. * 获取手续费统计信息
  356. *
  357. * @param int $appId 应用ID(0表示所有应用)
  358. * @param string $startDate 开始日期
  359. * @param string $endDate 结束日期
  360. * @return array
  361. */
  362. public static function getFeeStatistics(int $appId = 0, string $startDate = '', string $endDate = ''): array
  363. {
  364. try {
  365. return FeeService::getFeeStatistics($appId, $startDate, $endDate);
  366. } catch (\Exception $e) {
  367. return [
  368. 'error' => $e->getMessage(),
  369. 'total_orders' => 0,
  370. 'total_fee' => 0,
  371. 'avg_fee_rate' => 0,
  372. 'in_orders' => 0,
  373. 'in_fee' => 0,
  374. 'out_orders' => 0,
  375. 'out_fee' => 0,
  376. ];
  377. }
  378. }
  379. /**
  380. * 获取应用的手续费收入统计
  381. *
  382. * @param int $appId 应用ID
  383. * @param int $days 统计天数
  384. * @return array
  385. */
  386. public static function getAppFeeIncome(int $appId, int $days = 30): array
  387. {
  388. try {
  389. return FeeService::getAppFeeIncome($appId, $days);
  390. } catch (\Exception $e) {
  391. return [
  392. 'error' => $e->getMessage(),
  393. 'app_id' => $appId,
  394. 'days' => $days,
  395. 'total_fee' => 0,
  396. 'total_orders' => 0,
  397. 'avg_daily_fee' => 0,
  398. 'daily_stats' => [],
  399. ];
  400. }
  401. }
  402. }