User.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <?php
  2. namespace App\Module\Fund\Logic;
  3. use App\Module\Fund\Enums\LOG_TYPE;
  4. use App\Module\Fund\Events\FundChangedEvent;
  5. use App\Module\Fund\Models\FundLogModel;
  6. use App\Module\Fund\Models\FundModel;
  7. use Illuminate\Support\Facades\Event;
  8. use UCore\Helper\Logger;
  9. /**
  10. * Class User 用户的资金操作
  11. *
  12. * @package App\Logic\Fund\Service
  13. */
  14. class User
  15. {
  16. /**
  17. * 列表
  18. *
  19. * @param $where
  20. * @param $page
  21. * @param int $rows
  22. */
  23. public static function fund_list($where, $page, $rows = 10)
  24. {
  25. $query = FundModel::query();
  26. // 应用过滤条件
  27. if (isset($where['user_id'])) {
  28. $query->where('user_id', $where['user_id']);
  29. }
  30. if (isset($where['fund_id'])) {
  31. $query->where('fund_id', $where['fund_id']);
  32. }
  33. // 返回分页结果
  34. return $query->paginate($rows, ['*'], 'page', $page);
  35. }
  36. /**
  37. * 用户资金修改日志
  38. *
  39. * @param $user_id 用户uid
  40. * @param $page 当前页数
  41. * @param int $rows 每页行数
  42. */
  43. public static function log_list($user_id, $fund_id, $where, $page, $rows = 10)
  44. {
  45. }
  46. /**
  47. *
  48. * 资金处理
  49. *
  50. * @param $user_id
  51. * @param $fund_id
  52. * @param $amount
  53. * @param $type
  54. * @param $id
  55. * @param $remark
  56. * @return bool|string
  57. */
  58. public static function handle($user_id, int $fund_id, int $amount, LOG_TYPE $type, $id, $remark)
  59. {
  60. # 读取信息
  61. $data_Model = self::get_account($user_id, $fund_id);
  62. if ($data_Model === false) {
  63. return "_don~t have this account";
  64. }
  65. if (!($data_Model instanceof FundModel)) {
  66. return $data_Model;
  67. }
  68. # 记录变更前的余额
  69. $beforeBalance = $data_Model->balance;
  70. # 预先验证余额是否充足(在扣除之前检查)
  71. $afterBalance = $data_Model->balance + $amount;
  72. if ($afterBalance < 0) {
  73. // 可用资金不足,拒绝操作
  74. Logger::error("fund -handle $user_id - $fund_id insufficient funds: current={$data_Model->balance}, amount=$amount, after=$afterBalance");
  75. return "not-sufficient-funds $user_id - $fund_id : $amount ; {$data_Model->balance}";
  76. }
  77. # 先写入日志
  78. $re26 = self::log($data_Model, $user_id, $fund_id, $amount, $type, $id, $remark);
  79. if (is_string($re26)) {
  80. return $re26;
  81. }
  82. # 更新资金信息(此时已经验证过余额充足)
  83. $data_Model->update_time = time();
  84. $data_Model->balance = $afterBalance;
  85. if ($data_Model->save() === false) {
  86. return $data_Model->getMessage();
  87. }
  88. # 触发资金变更事件
  89. Event::dispatch(new FundChangedEvent(
  90. $user_id,
  91. $fund_id,
  92. $amount,
  93. $beforeBalance,
  94. $data_Model->balance,
  95. $type->value(),
  96. $id,
  97. $remark
  98. ));
  99. return true;
  100. }
  101. /**
  102. * 获取账户模型
  103. *
  104. * @param $user_id
  105. * @param $fund_id
  106. * @return fund|string
  107. */
  108. public static function get_account($user_id, $fund_id, $create = false)
  109. {
  110. $Model = FundModel::getAccount($user_id, $fund_id);
  111. if ($Model === null) {
  112. if ($create) {
  113. # 当前账户不存在尝试创建
  114. $Model = self::create_account($user_id, $fund_id);
  115. if (is_string($Model)) {
  116. // 创建失败
  117. return $Model;
  118. }
  119. } else {
  120. throw new \Exception("账户不存在$user_id - $fund_id .");
  121. }
  122. return FundModel::getAccount($user_id, $fund_id);
  123. }
  124. return $Model;
  125. }
  126. /**
  127. * 创建账户 不会进行账户是否存在验证
  128. *
  129. * @param $user_id
  130. * @param $fund_id
  131. * @return \Fund\Model\Fund|string
  132. */
  133. private static function create_account($user_id, $fund_id)
  134. {
  135. $data = [
  136. 'user_id' => $user_id,
  137. 'fund_id' => $fund_id,
  138. 'balance' => 0,
  139. 'create_time' => time(),
  140. 'update_time' => time(),
  141. ];
  142. $fundModel = new FundModel();
  143. $fundModel->setData($data);
  144. if ($fundModel->save() === false) {
  145. return 'sys error';
  146. }
  147. return $fundModel;
  148. }
  149. /**
  150. * 写入更新日志
  151. *
  152. * @param $user_id
  153. * @param $fund_id
  154. * @param $amount
  155. * @param $type
  156. * @param $id
  157. * @param $remark
  158. */
  159. private static function log(
  160. FundModel $data_Model,
  161. $user_id,
  162. $fund_id,
  163. $amount,
  164. LOG_TYPE $type,
  165. $id,
  166. $remark,
  167. $create_ip = ''
  168. ) {
  169. // 读取最新的余额信息
  170. $later_balance = $data_Model->balance + $amount;
  171. $before_balance = $data_Model->balance;
  172. # 读取最后一条记录进行验证
  173. $lastLog = FundLogModel::findLastUserFund($user_id, $fund_id);
  174. // dump($data8);
  175. # 读取最新的余额信息
  176. if ($lastLog === null) {
  177. $data8_arr = [];
  178. # 没有日志判断是否为0
  179. if (bccomp(0, $data_Model->balance, 3) !== 0) {
  180. # 前后效验不通过,
  181. Logger::error('前后效验不通过'." user_id: $user_id , fund_id :$fund_id ");
  182. return '_fund-log-validation-fails-201';
  183. }
  184. } else {
  185. // dump($lastLog);
  186. if (bccomp($lastLog->later_balance, $data_Model->balance, 3) !== 0) {
  187. # 前后效验不通过,
  188. Logger::error('fund-error', [$lastLog->toArray(), $data_Model->toArray()]);
  189. return '_fund-log-validation-fails-210';
  190. }
  191. }
  192. return Log::create_log($user_id, $fund_id, $amount, $remark, $later_balance, $before_balance, $id,
  193. $type->value(), $lastLog);
  194. }
  195. /**
  196. * 获取账户信息
  197. *
  198. * @param $user_id
  199. * @param $fund_id
  200. */
  201. public static function info($user_id, $fund_id)
  202. {
  203. $ModelData = self::get_account($user_id, $fund_id);
  204. return $ModelData->toArray();
  205. }
  206. /**
  207. * @param $userId
  208. * @param $fundIds
  209. * @return mixed[]
  210. * 获取用户全部资金账户
  211. */
  212. public static function getAllAccount($userId,$fundIds)
  213. {
  214. $modelData = FundModel::getAllAccount($userId,$fundIds);
  215. return $modelData->toArray();
  216. }
  217. }