CurrencyService.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. namespace App\Module\Fund\Services;
  3. use App\Module\Fund\Dto\CurrencyDto;
  4. use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
  5. use App\Module\Fund\Enums\FUND_TYPE;
  6. use App\Module\Fund\Models\FundConfigModel;
  7. use App\Module\Fund\Models\FundCurrencyModel;
  8. use App\Module\System\Services\ConfigService;
  9. use Illuminate\Support\Facades\Cache;
  10. use UCore\Helper\Cache as CacheHelper;
  11. /**
  12. * 币种服务类
  13. *
  14. * 提供币种相关的服务,包括币种信息获取、币种检查等功能
  15. */
  16. class CurrencyService
  17. {
  18. /**
  19. * 缓存时间(秒)
  20. */
  21. const CACHE_TTL = 3600;
  22. /**
  23. * 检查两个账户的币种是否一致
  24. *
  25. * @param int $fund_id 账户种类ID1
  26. * @param int $fund_id2 账户种类ID2
  27. * @return bool 是否一致
  28. */
  29. static public function check($fund_id, $fund_id2): bool
  30. {
  31. // 获取两个账户种类对应的币种
  32. $currency1 = self::getCurrency2ByFundId($fund_id);
  33. $currency2 = self::getCurrency2ByFundId($fund_id2);
  34. // 如果任一币种信息获取失败,返回false
  35. if (!$currency1 || !$currency2) {
  36. return false;
  37. }
  38. // 检查两个币种ID是否一致(使用币种枚举值,不是数据库表ID)
  39. return $currency1 === $currency2;
  40. }
  41. /**
  42. * 获取账户种类对应的币种
  43. *
  44. * @param int $fund_id 账户种类ID
  45. * @return CurrencyDto|null 币种信息DTO
  46. */
  47. static public function getCurrencyByFundId($fund_id)
  48. {
  49. // 获取账户种类对应的币种枚举
  50. $currencyEnum = self::getCurrency2ByFundId($fund_id);
  51. if (!$currencyEnum) {
  52. return null;
  53. }
  54. // 通过币种枚举查找对应的数据库记录
  55. $currency = FundCurrencyModel::where('type', $currencyEnum)->first();
  56. if (!$currency) {
  57. return null;
  58. }
  59. // 转换为DTO
  60. return CurrencyDto::fromModel($currency);
  61. }
  62. /**
  63. * 账户转币种
  64. *
  65. * @param $fund_id
  66. * @return \App\Module\Fund\Enums\FUND_CURRENCY_TYPE|null
  67. */
  68. static public function getCurrency2ByFundId(int $fund_id)
  69. {
  70. return FUND_TYPE::typevalue2Currency($fund_id);
  71. }
  72. /**
  73. * 获取币种配置
  74. *
  75. * @param int|null $currency_id 币种ID(FUND_CURRENCY_TYPE枚举值),为null时返回所有币种配置
  76. * @return CurrencyDto|CurrencyDto[] 币种配置DTO或DTO数组
  77. */
  78. public function getConfig($currency_id = null)
  79. {
  80. if ($currency_id) {
  81. // 获取指定币种的配置
  82. return Cache::remember('currency_config_dto_' . $currency_id, self::CACHE_TTL, function () use ($currency_id) {
  83. $currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
  84. if (!$currencyEnum) {
  85. return null;
  86. }
  87. $currency = FundCurrencyModel::where('type', $currencyEnum)->first();
  88. if (!$currency) {
  89. return null;
  90. }
  91. return CurrencyDto::fromModel($currency);
  92. });
  93. } else {
  94. // 获取所有币种的配置
  95. return Cache::remember('currency_config_dto_all', self::CACHE_TTL, function () {
  96. $currencies = FundCurrencyModel::all();
  97. $dtoList = [];
  98. foreach ($currencies as $currency) {
  99. $dtoList[] = CurrencyDto::fromModel($currency);
  100. }
  101. return $dtoList;
  102. });
  103. }
  104. }
  105. /**
  106. * 获取币种名称列表
  107. *
  108. * @return array 币种ID => 币种名称
  109. */
  110. static public function getValueDesc()
  111. {
  112. return CacheHelper::cacheCall([ __CLASS__, __FUNCTION__ ], function () {
  113. $list = FundCurrencyModel::query()->pluck('name', 'id')->toArray();
  114. return $list;
  115. }, [], 10, [ ConfigService::CACHE_TAG ]);
  116. }
  117. /**
  118. * 获取币种标识列表
  119. *
  120. * @return array 币种ID => 币种标识
  121. */
  122. static public function getIdentifications()
  123. {
  124. return CacheHelper::cacheCall([ __CLASS__, __FUNCTION__ ], function () {
  125. $list = FundCurrencyModel::query()->pluck('identification', 'id')->toArray();
  126. return $list;
  127. }, [], 10, [ ConfigService::CACHE_TAG ]);
  128. }
  129. /**
  130. * 获取所有币种列表
  131. *
  132. * @param bool $refresh 是否刷新缓存
  133. * @return CurrencyDto[] 币种DTO列表
  134. */
  135. static public function getAllCurrencies($refresh = false)
  136. {
  137. $cacheKey = 'all_currencies_dto';
  138. if ($refresh) {
  139. Cache::forget($cacheKey);
  140. }
  141. return Cache::remember($cacheKey, self::CACHE_TTL, function () {
  142. $currencies = FundCurrencyModel::all();
  143. $dtoList = [];
  144. foreach ($currencies as $currency) {
  145. $dtoList[] = CurrencyDto::fromModel($currency);
  146. }
  147. return $dtoList;
  148. });
  149. }
  150. /**
  151. * 获取币种的精度
  152. *
  153. * @param int $currency_id 币种ID(FUND_CURRENCY_TYPE枚举值)
  154. * @return int 精度(小数位数)
  155. */
  156. static public function getCurrencyPrecision($currency_id)
  157. {
  158. // 直接通过币种ID(枚举值)获取精度
  159. $currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
  160. if (!$currencyEnum) {
  161. return 2; // 默认精度为2
  162. }
  163. // 从枚举中获取精度信息
  164. return $currencyEnum->getPrecision();
  165. }
  166. /**
  167. * 格式化金额显示
  168. *
  169. * @param string|int|float $amount 金额(小数形式)
  170. * @param int $currency_id 币种ID
  171. * @return string 格式化后的金额
  172. */
  173. static public function formatAmount($amount, $currency_id)
  174. {
  175. $precision = self::getCurrencyPrecision($currency_id);
  176. // 确保金额为数值类型
  177. $numericAmount = is_string($amount) ? (float)$amount : $amount;
  178. // 根据币种精度格式化金额
  179. $formattedAmount = number_format($numericAmount, $precision, '.', ',');
  180. // 获取币种标识(通过币种ID获取)
  181. $currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
  182. if ($currencyEnum) {
  183. // 通过枚举查找对应的数据库记录
  184. $currency = FundCurrencyModel::where('type', $currencyEnum)->first();
  185. $symbol = $currency ? $currency->identification : '';
  186. } else {
  187. $symbol = '';
  188. }
  189. return $symbol . ' ' . $formattedAmount;
  190. }
  191. /**
  192. * 验证金额精度是否符合币种要求
  193. *
  194. * @param float $amount 用户输入的金额
  195. * @param int $currency_id 币种ID
  196. * @return bool 是否符合精度要求
  197. */
  198. static public function validateAmountPrecision($amount, $currency_id)
  199. {
  200. $precision = self::getCurrencyPrecision($currency_id);
  201. // 获取小数部分的位数
  202. $decimalPart = (string)$amount;
  203. if (strpos($decimalPart, '.') !== false) {
  204. $decimalDigits = strlen(substr($decimalPart, strpos($decimalPart, '.') + 1));
  205. return $decimalDigits <= $precision;
  206. }
  207. return true; // 整数总是符合要求
  208. }
  209. /**
  210. * 格式化金额到指定精度
  211. *
  212. * @param float $amount 金额
  213. * @param int $currency_id 币种ID
  214. * @return float 格式化后的金额
  215. */
  216. static public function formatAmountToPrecision($amount, $currency_id)
  217. {
  218. $precision = self::getCurrencyPrecision($currency_id);
  219. return round($amount, $precision);
  220. }
  221. }