UrsPartnerDividendService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. <?php
  2. namespace App\Module\UrsPromotion\Services;
  3. use App\Module\UrsPromotion\Enums\UrsTalentLevel;
  4. use App\Module\UrsPromotion\Logics\UrsPartnerDividendLogic;
  5. use App\Module\UrsPromotion\Models\UrsPartnerDividendRecord;
  6. use App\Module\UrsPromotion\Models\UrsPartnerDividendDetail;
  7. use App\Module\UrsPromotion\Models\UrsUserTalent;
  8. use Illuminate\Support\Facades\Log;
  9. use Carbon\Carbon;
  10. /**
  11. * URS合伙人分红服务
  12. *
  13. * 对外提供URS合伙人分红相关服务接口
  14. */
  15. class UrsPartnerDividendService
  16. {
  17. /**
  18. * 执行每日合伙人分红
  19. *
  20. * @param string|null $date 分红日期,默认为今天
  21. * @return array 分红结果
  22. */
  23. public static function executeDailyDividend(?string $date = null): array
  24. {
  25. try {
  26. $logic = new UrsPartnerDividendLogic();
  27. return $logic->executeDailyDividend($date);
  28. } catch (\Exception $e) {
  29. Log::error('合伙人分红执行失败', [
  30. 'date' => $date ?? 'today',
  31. 'error' => $e->getMessage(),
  32. 'trace' => $e->getTraceAsString()
  33. ]);
  34. return [
  35. 'success' => false,
  36. 'message' => '分红执行失败: ' . $e->getMessage()
  37. ];
  38. }
  39. }
  40. /**
  41. * 获取合伙人列表
  42. *
  43. * @return array 合伙人列表
  44. */
  45. public static function getPartnerList(): array
  46. {
  47. try {
  48. // 获取所有顶级达人(合伙人)
  49. $talents = UrsUserTalent::where('talent_level', UrsTalentLevel::MASTER->value)
  50. ->get();
  51. $partners = [];
  52. foreach ($talents as $talent) {
  53. // UrsUserTalent表中的user_id就是农场用户ID
  54. $userId = $talent->user_id;
  55. // 获取对应的URS用户ID
  56. $ursUserId = UrsUserMappingService::getMappingUrsUserId($userId);
  57. if ($ursUserId) {
  58. $user = \App\Module\User\Models\User::find($userId);
  59. if ($user) {
  60. $partners[] = [
  61. 'user_id' => $userId,
  62. 'urs_user_id' => $ursUserId,
  63. 'username' => $user->username,
  64. 'talent_level' => $talent->talent_level,
  65. 'talent_level_name' => '合伙人',
  66. 'created_at' => $talent->created_at->format('Y-m-d H:i:s')
  67. ];
  68. }
  69. }
  70. }
  71. return [
  72. 'success' => true,
  73. 'data' => $partners,
  74. 'total' => count($partners)
  75. ];
  76. } catch (\Exception $e) {
  77. Log::error('获取合伙人列表失败', [
  78. 'error' => $e->getMessage()
  79. ]);
  80. return [
  81. 'success' => false,
  82. 'message' => '获取合伙人列表失败: ' . $e->getMessage(),
  83. 'data' => [],
  84. 'total' => 0
  85. ];
  86. }
  87. }
  88. /**
  89. * 获取分红历史记录
  90. *
  91. * @param string|null $startDate 开始日期
  92. * @param string|null $endDate 结束日期
  93. * @param int $limit 限制数量
  94. * @return array 分红历史
  95. */
  96. public static function getDividendHistory(?string $startDate = null, ?string $endDate = null, int $limit = 50): array
  97. {
  98. try {
  99. $query = UrsPartnerDividendRecord::with(['transferApp']);
  100. if ($startDate) {
  101. $query->where('dividend_date', '>=', $startDate);
  102. }
  103. if ($endDate) {
  104. $query->where('dividend_date', '<=', $endDate);
  105. }
  106. $records = $query->orderBy('dividend_date', 'desc')
  107. ->limit($limit)
  108. ->get();
  109. $history = [];
  110. foreach ($records as $record) {
  111. $history[] = [
  112. 'id' => $record->id,
  113. 'dividend_date' => $record->dividend_date->format('Y-m-d'),
  114. 'total_fee_amount' => $record->total_fee_amount,
  115. 'dividend_amount' => $record->dividend_amount,
  116. 'partner_count' => $record->partner_count,
  117. 'per_partner_amount' => $record->per_partner_amount,
  118. 'status' => $record->status,
  119. 'status_name' => $record->status_name,
  120. 'error_message' => $record->error_message,
  121. 'transfer_app_title' => $record->transferApp->title ?? '',
  122. 'created_at' => $record->created_at->format('Y-m-d H:i:s')
  123. ];
  124. }
  125. return [
  126. 'success' => true,
  127. 'data' => $history,
  128. 'total' => count($history)
  129. ];
  130. } catch (\Exception $e) {
  131. Log::error('获取分红历史失败', [
  132. 'start_date' => $startDate,
  133. 'end_date' => $endDate,
  134. 'error' => $e->getMessage()
  135. ]);
  136. return [
  137. 'success' => false,
  138. 'message' => '获取分红历史失败: ' . $e->getMessage(),
  139. 'data' => [],
  140. 'total' => 0
  141. ];
  142. }
  143. }
  144. /**
  145. * 获取分红详情
  146. *
  147. * @param int $dividendRecordId 分红记录ID
  148. * @return array 分红详情
  149. */
  150. public static function getDividendDetails(int $dividendRecordId): array
  151. {
  152. try {
  153. $record = UrsPartnerDividendRecord::with(['transferApp'])->find($dividendRecordId);
  154. if (!$record) {
  155. return [
  156. 'success' => false,
  157. 'message' => '分红记录不存在'
  158. ];
  159. }
  160. $details = UrsPartnerDividendDetail::getByDividendRecordId($dividendRecordId);
  161. $detailList = [];
  162. foreach ($details as $detail) {
  163. $detailList[] = [
  164. 'id' => $detail->id,
  165. 'user_id' => $detail->user_id,
  166. 'urs_user_id' => $detail->urs_user_id,
  167. 'username' => $detail->user->username ?? '',
  168. 'talent_level' => $detail->talent_level,
  169. 'talent_level_name' => $detail->talent_level_name,
  170. 'dividend_amount' => $detail->dividend_amount,
  171. 'status' => $detail->status,
  172. 'status_name' => $detail->status_name,
  173. 'error_message' => $detail->error_message,
  174. 'transfer_order_id' => $detail->transfer_order_id,
  175. 'created_at' => $detail->created_at->format('Y-m-d H:i:s')
  176. ];
  177. }
  178. return [
  179. 'success' => true,
  180. 'data' => [
  181. 'record' => [
  182. 'id' => $record->id,
  183. 'dividend_date' => $record->dividend_date->format('Y-m-d'),
  184. 'total_fee_amount' => $record->total_fee_amount,
  185. 'dividend_amount' => $record->dividend_amount,
  186. 'partner_count' => $record->partner_count,
  187. 'per_partner_amount' => $record->per_partner_amount,
  188. 'status' => $record->status,
  189. 'status_name' => $record->status_name,
  190. 'error_message' => $record->error_message,
  191. 'transfer_app_title' => $record->transferApp->title ?? '',
  192. 'created_at' => $record->created_at->format('Y-m-d H:i:s')
  193. ],
  194. 'details' => $detailList
  195. ]
  196. ];
  197. } catch (\Exception $e) {
  198. Log::error('获取分红详情失败', [
  199. 'dividend_record_id' => $dividendRecordId,
  200. 'error' => $e->getMessage()
  201. ]);
  202. return [
  203. 'success' => false,
  204. 'message' => '获取分红详情失败: ' . $e->getMessage()
  205. ];
  206. }
  207. }
  208. /**
  209. * 获取用户分红历史
  210. *
  211. * @param int $userId 用户ID
  212. * @return array 用户分红历史
  213. */
  214. public static function getUserDividendHistory(int $userId): array
  215. {
  216. try {
  217. $details = UrsPartnerDividendDetail::getUserDividendHistory($userId);
  218. $history = [];
  219. foreach ($details as $detail) {
  220. $history[] = [
  221. 'id' => $detail->id,
  222. 'dividend_date' => $detail->dividendRecord->dividend_date->format('Y-m-d'),
  223. 'dividend_amount' => $detail->dividend_amount,
  224. 'status' => $detail->status,
  225. 'status_name' => $detail->status_name,
  226. 'error_message' => $detail->error_message,
  227. 'transfer_order_id' => $detail->transfer_order_id,
  228. 'created_at' => $detail->created_at->format('Y-m-d H:i:s')
  229. ];
  230. }
  231. return [
  232. 'success' => true,
  233. 'data' => $history,
  234. 'total' => count($history)
  235. ];
  236. } catch (\Exception $e) {
  237. Log::error('获取用户分红历史失败', [
  238. 'user_id' => $userId,
  239. 'error' => $e->getMessage()
  240. ]);
  241. return [
  242. 'success' => false,
  243. 'message' => '获取用户分红历史失败: ' . $e->getMessage(),
  244. 'data' => [],
  245. 'total' => 0
  246. ];
  247. }
  248. }
  249. /**
  250. * 获取分红统计信息
  251. *
  252. * @return array 统计信息
  253. */
  254. public static function getDividendStatistics(): array
  255. {
  256. try {
  257. $totalRecords = UrsPartnerDividendRecord::count();
  258. $completedRecords = UrsPartnerDividendRecord::getCompletedCount();
  259. $totalDividendAmount = UrsPartnerDividendRecord::getTotalDividendAmount();
  260. $currentPartnerCount = UrsUserTalent::where('talent_level', 5)->count();
  261. return [
  262. 'success' => true,
  263. 'data' => [
  264. 'total_records' => $totalRecords,
  265. 'completed_records' => $completedRecords,
  266. 'total_dividend_amount' => $totalDividendAmount,
  267. 'current_partner_count' => $currentPartnerCount,
  268. 'success_rate' => $totalRecords > 0 ? round($completedRecords / $totalRecords * 100, 2) : 0
  269. ]
  270. ];
  271. } catch (\Exception $e) {
  272. Log::error('获取分红统计信息失败', [
  273. 'error' => $e->getMessage()
  274. ]);
  275. return [
  276. 'success' => false,
  277. 'message' => '获取分红统计信息失败: ' . $e->getMessage()
  278. ];
  279. }
  280. }
  281. /**
  282. * 重试失败的分红
  283. *
  284. * @param string $date 分红日期
  285. * @return array 重试结果
  286. */
  287. public static function retryFailedDividend(string $date): array
  288. {
  289. try {
  290. $logic = new UrsPartnerDividendLogic();
  291. return $logic->retryFailedDividend($date);
  292. } catch (\Exception $e) {
  293. Log::error('重试失败分红失败', [
  294. 'date' => $date,
  295. 'error' => $e->getMessage(),
  296. 'trace' => $e->getTraceAsString()
  297. ]);
  298. return [
  299. 'success' => false,
  300. 'message' => '重试失败分红失败: ' . $e->getMessage()
  301. ];
  302. }
  303. }
  304. /**
  305. * 检查分红状态和进度
  306. *
  307. * @param string $date 分红日期
  308. * @return array 状态信息
  309. */
  310. public static function checkDividendStatus(string $date): array
  311. {
  312. try {
  313. $record = UrsPartnerDividendRecord::getByDate($date);
  314. if (!$record) {
  315. return [
  316. 'success' => false,
  317. 'message' => '分红记录不存在'
  318. ];
  319. }
  320. // 获取分红详情统计
  321. $details = UrsPartnerDividendDetail::where('dividend_record_id', $record->id)->get();
  322. $statusCounts = $details->groupBy('status')->map->count();
  323. return [
  324. 'success' => true,
  325. 'data' => [
  326. 'record_id' => $record->id,
  327. 'date' => $record->dividend_date->format('Y-m-d'),
  328. 'status' => $record->status,
  329. 'status_name' => $record->status_name,
  330. 'total_fee_amount' => $record->total_fee_amount,
  331. 'dividend_amount' => $record->dividend_amount,
  332. 'partner_count' => $record->partner_count,
  333. 'per_partner_amount' => $record->per_partner_amount,
  334. 'error_message' => $record->error_message,
  335. 'details_status' => [
  336. 'pending' => $statusCounts['pending'] ?? 0,
  337. 'completed' => $statusCounts['completed'] ?? 0,
  338. 'failed' => $statusCounts['failed'] ?? 0,
  339. 'total' => $details->count()
  340. ],
  341. 'progress' => [
  342. 'completed_rate' => $details->count() > 0 ?
  343. round(($statusCounts['completed'] ?? 0) / $details->count() * 100, 2) : 0,
  344. 'failed_rate' => $details->count() > 0 ?
  345. round(($statusCounts['failed'] ?? 0) / $details->count() * 100, 2) : 0
  346. ],
  347. 'created_at' => $record->created_at->format('Y-m-d H:i:s'),
  348. 'updated_at' => $record->updated_at->format('Y-m-d H:i:s')
  349. ]
  350. ];
  351. } catch (\Exception $e) {
  352. Log::error('检查分红状态失败', [
  353. 'date' => $date,
  354. 'error' => $e->getMessage()
  355. ]);
  356. return [
  357. 'success' => false,
  358. 'message' => '检查分红状态失败: ' . $e->getMessage()
  359. ];
  360. }
  361. }
  362. }