feature
This commit is contained in:
@@ -7,16 +7,33 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class WalletAddress extends Model
|
||||
{
|
||||
/** @var list<string> */
|
||||
public const COIN_COLUMNS = ['usdt', 'trx', 'eth', 'btc', 'bnb'];
|
||||
|
||||
/** Display decimal places per coin (UI). */
|
||||
public const DISPLAY_DECIMALS = [
|
||||
'usdt' => 2,
|
||||
'trx' => 6,
|
||||
'eth' => 6,
|
||||
'btc' => 8,
|
||||
'bnb' => 6,
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id', 'wallet_id', 'address', 'chain', 'balance',
|
||||
'symbol', 'telegram_notified', 'meta_json',
|
||||
'device_id', 'address', 'chain_type',
|
||||
'usdt', 'trx', 'eth', 'btc', 'bnb',
|
||||
'monitor', 'source',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'telegram_notified' => 'boolean',
|
||||
'meta_json' => 'array',
|
||||
'monitor' => 'integer',
|
||||
'usdt' => 'decimal:6',
|
||||
'trx' => 'decimal:6',
|
||||
'eth' => 'decimal:18',
|
||||
'btc' => 'decimal:8',
|
||||
'bnb' => 'decimal:18',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -25,8 +42,101 @@ class WalletAddress extends Model
|
||||
return $this->belongsTo(Device::class);
|
||||
}
|
||||
|
||||
public function wallet(): BelongsTo
|
||||
/**
|
||||
* Map a symbol=>amount payload into coin column attributes (only known coins).
|
||||
* Missing symbols are omitted (caller merges with existing row).
|
||||
*
|
||||
* @param array<string, mixed>|string|null $balance
|
||||
* @return array<string, string|int|float|null>
|
||||
*/
|
||||
public static function coinAttributesFromBalance(mixed $balance): array
|
||||
{
|
||||
return $this->belongsTo(Wallet::class);
|
||||
if (! is_array($balance)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($balance as $symbol => $value) {
|
||||
$col = strtolower((string) $symbol);
|
||||
if (! in_array($col, self::COIN_COLUMNS, true)) {
|
||||
continue;
|
||||
}
|
||||
if ($value === null || $value === '') {
|
||||
$out[$col] = null;
|
||||
continue;
|
||||
}
|
||||
if (! is_numeric($value)) {
|
||||
continue;
|
||||
}
|
||||
$out[$col] = $value;
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public static function displayDecimals(string $coin): int
|
||||
{
|
||||
$coin = strtolower($coin);
|
||||
|
||||
return self::DISPLAY_DECIMALS[$coin] ?? 6;
|
||||
}
|
||||
|
||||
public static function formatAmount(string $coin, mixed $amount): string
|
||||
{
|
||||
if ($amount === null || $amount === '') {
|
||||
return '';
|
||||
}
|
||||
if (! is_numeric($amount)) {
|
||||
return (string) $amount;
|
||||
}
|
||||
|
||||
$decimals = self::displayDecimals($coin);
|
||||
$formatted = number_format((float) $amount, $decimals, '.', '');
|
||||
$formatted = rtrim(rtrim($formatted, '0'), '.');
|
||||
|
||||
return $formatted === '' ? '0' : $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function formattedCoins(): array
|
||||
{
|
||||
$out = [];
|
||||
foreach (self::COIN_COLUMNS as $col) {
|
||||
$out[$col] = self::formatAmount($col, $this->{$col});
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function coinsSummary(): ?string
|
||||
{
|
||||
$parts = [];
|
||||
foreach (self::COIN_COLUMNS as $col) {
|
||||
$raw = $this->{$col};
|
||||
if ($raw === null || $raw === '' || (float) $raw == 0.0) {
|
||||
continue;
|
||||
}
|
||||
$parts[strtoupper($col)] = self::formatAmount($col, $raw);
|
||||
}
|
||||
|
||||
return $parts === [] ? null : json_encode($parts, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Snapshot of coin columns for change detection.
|
||||
*
|
||||
* @return array<string, string|null>
|
||||
*/
|
||||
public function coinSnapshot(): array
|
||||
{
|
||||
$out = [];
|
||||
foreach (self::COIN_COLUMNS as $col) {
|
||||
$v = $this->{$col};
|
||||
$out[$col] = $v === null || $v === '' ? null : (string) $v;
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user