Initial Ladill Transfer app — file sharing with QR links.

Scaffolded from the Ladill mini/events extraction pattern: multi-file transfers,
retention controls, public landing pages, analytics, and Gitea deploy workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-06-08 09:25:30 +00:00
co-authored by Cursor
commit c1e3d8b3ac
281 changed files with 36051 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class QrWallet extends Model
{
public const STATUS_ACTIVE = 'active';
public const STATUS_SUSPENDED = 'suspended';
protected $fillable = [
'user_id',
'credit_balance',
'qr_codes_total',
'scans_total',
'status',
];
protected $casts = [
'credit_balance' => 'decimal:4',
'qr_codes_total' => 'integer',
'scans_total' => 'integer',
];
public static function pricePerQr(): float
{
return (float) config('qr.price_per_qr_ghs', 5.0);
}
public static function minTopupGhs(): float
{
return (float) config('qr.min_topup_ghs', 5.0);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function transactions(): HasMany
{
return $this->hasMany(QrTransaction::class)->latest();
}
/**
* Single-wallet (siloing step 2): QR spends from the one UserWallet (tagged
* 'qr'). Delegates to the billing service (lazily folds any legacy
* credit_balance in). `spendableBalance()` is the unified balance for display.
*/
public function spendableBalance(): float
{
return $this->user
? app(\App\Services\Qr\QrWalletBillingService::class)->balanceCedis($this->user)
: (float) $this->credit_balance;
}
public function canCreateQr(): bool
{
return $this->user
? app(\App\Services\Qr\QrWalletBillingService::class)->canCreate($this->user)
: false;
}
}