Files
lab-app/lib/models/platform_admin.dart
2026-06-20 18:24:40 +03:00

299 lines
9.0 KiB
Dart

import 'tenant.dart';
enum PlatformRole {
superAdmin,
support,
financeOps,
operations,
readOnly,
;
String get value => switch (this) {
PlatformRole.superAdmin => 'super_admin',
PlatformRole.support => 'support',
PlatformRole.financeOps => 'finance_ops',
PlatformRole.operations => 'operations',
PlatformRole.readOnly => 'read_only',
};
String get label => switch (this) {
PlatformRole.superAdmin => 'Super Admin',
PlatformRole.support => 'Destek',
PlatformRole.financeOps => 'Finans Operasyon',
PlatformRole.operations => 'Operasyon',
PlatformRole.readOnly => 'Sadece Görüntüleme',
};
static PlatformRole parse(String raw) => switch (raw) {
'super_admin' => PlatformRole.superAdmin,
'support' => PlatformRole.support,
'finance_ops' => PlatformRole.financeOps,
'operations' => PlatformRole.operations,
'read_only' => PlatformRole.readOnly,
_ => PlatformRole.readOnly,
};
}
class PlatformMembership {
const PlatformMembership({
required this.id,
required this.userId,
required this.role,
this.status = 'active',
});
final String id;
final String userId;
final PlatformRole role;
final String status;
bool get isActive => status == 'active';
bool get isSuperAdmin => role == PlatformRole.superAdmin && isActive;
bool get canManageBilling =>
isActive &&
(role == PlatformRole.superAdmin || role == PlatformRole.financeOps);
bool get canManageTenants =>
isActive &&
(role == PlatformRole.superAdmin ||
role == PlatformRole.operations ||
role == PlatformRole.support);
factory PlatformMembership.fromJson(Map<String, dynamic> json) {
return PlatformMembership(
id: json['id'] as String,
userId: json['user_id'] as String,
role: PlatformRole.parse(json['role'] as String? ?? ''),
status: (json['status'] as String?) ?? 'active',
);
}
}
enum SubscriptionStatus { trialing, active, pastDue, cancelled, paused }
extension SubscriptionStatusX on SubscriptionStatus {
String get value => switch (this) {
SubscriptionStatus.trialing => 'trialing',
SubscriptionStatus.active => 'active',
SubscriptionStatus.pastDue => 'past_due',
SubscriptionStatus.cancelled => 'cancelled',
SubscriptionStatus.paused => 'paused',
};
static SubscriptionStatus parse(String raw) => switch (raw) {
'trialing' => SubscriptionStatus.trialing,
'active' => SubscriptionStatus.active,
'past_due' => SubscriptionStatus.pastDue,
'cancelled' => SubscriptionStatus.cancelled,
'paused' => SubscriptionStatus.paused,
_ => SubscriptionStatus.trialing,
};
}
class TenantSubscription {
const TenantSubscription({
required this.id,
required this.tenantId,
required this.plan,
required this.status,
this.billingProvider,
this.providerCustomerId,
this.providerSubscriptionId,
this.periodStart,
this.periodEnd,
this.aiMonthlyCredits = 0,
this.aiBonusCredits = 0,
});
final String id;
final String tenantId;
final TenantPlan plan;
final SubscriptionStatus status;
final String? billingProvider;
final String? providerCustomerId;
final String? providerSubscriptionId;
final DateTime? periodStart;
final DateTime? periodEnd;
final int aiMonthlyCredits;
final int aiBonusCredits;
int get totalAiCredits => aiMonthlyCredits + aiBonusCredits;
factory TenantSubscription.fromJson(Map<String, dynamic> json) {
return TenantSubscription(
id: json['id'] as String,
tenantId: json['tenant_id'] as String,
plan: Tenant.parsePlanValue(json['plan'] as String?),
status: SubscriptionStatusX.parse(json['status'] as String? ?? ''),
billingProvider: json['billing_provider'] as String?,
providerCustomerId: json['provider_customer_id'] as String?,
providerSubscriptionId: json['provider_subscription_id'] as String?,
periodStart: _parseDate(json['period_start']),
periodEnd: _parseDate(json['period_end']),
aiMonthlyCredits: (json['ai_monthly_credits'] as num?)?.toInt() ?? 0,
aiBonusCredits: (json['ai_bonus_credits'] as num?)?.toInt() ?? 0,
);
}
}
enum AiCreditEntryType {
monthlyAllocation,
bonusAllocation,
usageDebit,
manualAdjustment,
refund,
expire,
;
String get value => switch (this) {
AiCreditEntryType.monthlyAllocation => 'monthly_allocation',
AiCreditEntryType.bonusAllocation => 'bonus_allocation',
AiCreditEntryType.usageDebit => 'usage_debit',
AiCreditEntryType.manualAdjustment => 'manual_adjustment',
AiCreditEntryType.refund => 'refund',
AiCreditEntryType.expire => 'expire',
};
static AiCreditEntryType parse(String raw) => switch (raw) {
'monthly_allocation' => AiCreditEntryType.monthlyAllocation,
'bonus_allocation' => AiCreditEntryType.bonusAllocation,
'usage_debit' => AiCreditEntryType.usageDebit,
'manual_adjustment' => AiCreditEntryType.manualAdjustment,
'refund' => AiCreditEntryType.refund,
'expire' => AiCreditEntryType.expire,
_ => AiCreditEntryType.manualAdjustment,
};
}
class AiCreditLedgerEntry {
const AiCreditLedgerEntry({
required this.id,
required this.tenantId,
required this.entryType,
required this.delta,
required this.balanceAfter,
this.referenceType,
this.referenceId,
this.note,
this.createdByUserId,
this.createdAt,
});
final String id;
final String tenantId;
final AiCreditEntryType entryType;
final int delta;
final int balanceAfter;
final String? referenceType;
final String? referenceId;
final String? note;
final String? createdByUserId;
final DateTime? createdAt;
factory AiCreditLedgerEntry.fromJson(Map<String, dynamic> json) {
return AiCreditLedgerEntry(
id: json['id'] as String,
tenantId: json['tenant_id'] as String,
entryType: AiCreditEntryType.parse(json['entry_type'] as String? ?? ''),
delta: (json['delta'] as num?)?.toInt() ?? 0,
balanceAfter: (json['balance_after'] as num?)?.toInt() ?? 0,
referenceType: json['reference_type'] as String?,
referenceId: json['reference_id'] as String?,
note: json['note'] as String?,
createdByUserId: json['created_by_user_id'] as String?,
createdAt: _parseDate(json['created']),
);
}
}
class AiUsageLog {
const AiUsageLog({
required this.id,
required this.tenantId,
required this.userId,
required this.action,
required this.creditCost,
this.model,
this.jobId,
this.tokenInput,
this.tokenOutput,
this.latencyMs,
this.createdAt,
});
final String id;
final String tenantId;
final String userId;
final String action;
final int creditCost;
final String? model;
final String? jobId;
final int? tokenInput;
final int? tokenOutput;
final int? latencyMs;
final DateTime? createdAt;
factory AiUsageLog.fromJson(Map<String, dynamic> json) {
return AiUsageLog(
id: json['id'] as String,
tenantId: json['tenant_id'] as String,
userId: json['user_id'] as String,
action: json['action'] as String? ?? '',
creditCost: (json['credit_cost'] as num?)?.toInt() ?? 0,
model: json['model'] as String?,
jobId: json['job_id'] as String?,
tokenInput: (json['token_input'] as num?)?.toInt(),
tokenOutput: (json['token_output'] as num?)?.toInt(),
latencyMs: (json['latency_ms'] as num?)?.toInt(),
createdAt: _parseDate(json['created']),
);
}
}
class AdminAuditLog {
const AdminAuditLog({
required this.id,
required this.actorUserId,
required this.actorRole,
required this.actionType,
this.targetCollection,
this.targetRecordId,
this.targetTenantId,
this.summary,
this.metadata,
this.createdAt,
});
final String id;
final String actorUserId;
final PlatformRole actorRole;
final String actionType;
final String? targetCollection;
final String? targetRecordId;
final String? targetTenantId;
final String? summary;
final Map<String, dynamic>? metadata;
final DateTime? createdAt;
factory AdminAuditLog.fromJson(Map<String, dynamic> json) {
final metadata = json['metadata'];
return AdminAuditLog(
id: json['id'] as String,
actorUserId: json['actor_user_id'] as String,
actorRole: PlatformRole.parse(json['actor_role'] as String? ?? ''),
actionType: json['action_type'] as String? ?? '',
targetCollection: json['target_collection'] as String?,
targetRecordId: json['target_record_id'] as String?,
targetTenantId: json['target_tenant_id'] as String?,
summary: json['summary'] as String?,
metadata: metadata is Map<String, dynamic> ? metadata : null,
createdAt: _parseDate(json['created']),
);
}
}
DateTime? _parseDate(dynamic raw) {
final value = raw as String?;
if (value == null || value.isEmpty) return null;
return DateTime.tryParse(value);
}