credits adn tokens final correct setup
This commit is contained in:
@@ -109,8 +109,8 @@ class CreditUsageLog(AccountBaseModel):
|
||||
|
||||
class CreditCostConfig(models.Model):
|
||||
"""
|
||||
Configurable credit costs per AI function
|
||||
Admin-editable alternative to hardcoded constants
|
||||
Token-based credit pricing configuration.
|
||||
ALL operations use token-to-credit conversion.
|
||||
"""
|
||||
# Operation identification
|
||||
operation_type = models.CharField(
|
||||
@@ -120,26 +120,27 @@ class CreditCostConfig(models.Model):
|
||||
help_text="AI operation type"
|
||||
)
|
||||
|
||||
# Cost configuration
|
||||
credits_cost = models.IntegerField(
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text="Credits required for this operation"
|
||||
# Token-to-credit ratio (tokens per 1 credit)
|
||||
tokens_per_credit = models.IntegerField(
|
||||
default=100,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text="Number of tokens that equal 1 credit (e.g., 100 tokens = 1 credit)"
|
||||
)
|
||||
|
||||
# Unit of measurement
|
||||
UNIT_CHOICES = [
|
||||
('per_request', 'Per Request'),
|
||||
('per_100_words', 'Per 100 Words'),
|
||||
('per_200_words', 'Per 200 Words'),
|
||||
('per_item', 'Per Item'),
|
||||
('per_image', 'Per Image'),
|
||||
]
|
||||
# Minimum credits (for very small token usage)
|
||||
min_credits = models.IntegerField(
|
||||
default=1,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text="Minimum credits to charge regardless of token usage"
|
||||
)
|
||||
|
||||
unit = models.CharField(
|
||||
max_length=50,
|
||||
default='per_request',
|
||||
choices=UNIT_CHOICES,
|
||||
help_text="What the cost applies to"
|
||||
# Price per credit (for revenue reporting)
|
||||
price_per_credit_usd = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=4,
|
||||
default=Decimal('0.01'),
|
||||
validators=[MinValueValidator(Decimal('0.0001'))],
|
||||
help_text="USD price per credit (for revenue reporting)"
|
||||
)
|
||||
|
||||
# Metadata
|
||||
@@ -149,6 +150,7 @@ class CreditCostConfig(models.Model):
|
||||
# Status
|
||||
is_active = models.BooleanField(default=True, help_text="Enable/disable this operation")
|
||||
|
||||
|
||||
# Audit fields
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
@@ -162,10 +164,10 @@ class CreditCostConfig(models.Model):
|
||||
)
|
||||
|
||||
# Change tracking
|
||||
previous_cost = models.IntegerField(
|
||||
previous_tokens_per_credit = models.IntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Cost before last update (for audit trail)"
|
||||
help_text="Tokens per credit before last update (for audit trail)"
|
||||
)
|
||||
|
||||
# History tracking
|
||||
@@ -179,20 +181,92 @@ class CreditCostConfig(models.Model):
|
||||
ordering = ['operation_type']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.display_name} - {self.credits_cost} credits {self.unit}"
|
||||
return f"{self.display_name} - {self.tokens_per_credit} tokens/credit"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Track cost changes
|
||||
# Track token ratio changes
|
||||
if self.pk:
|
||||
try:
|
||||
old = CreditCostConfig.objects.get(pk=self.pk)
|
||||
if old.credits_cost != self.credits_cost:
|
||||
self.previous_cost = old.credits_cost
|
||||
if old.tokens_per_credit != self.tokens_per_credit:
|
||||
self.previous_tokens_per_credit = old.tokens_per_credit
|
||||
except CreditCostConfig.DoesNotExist:
|
||||
pass
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class BillingConfiguration(models.Model):
|
||||
"""
|
||||
System-wide billing configuration (Singleton).
|
||||
Global settings for token-credit pricing.
|
||||
"""
|
||||
# Default token-to-credit ratio
|
||||
default_tokens_per_credit = models.IntegerField(
|
||||
default=100,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text="Default: How many tokens equal 1 credit (e.g., 100)"
|
||||
)
|
||||
|
||||
# Credit pricing
|
||||
default_credit_price_usd = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=4,
|
||||
default=Decimal('0.01'),
|
||||
validators=[MinValueValidator(Decimal('0.0001'))],
|
||||
help_text="Default price per credit in USD"
|
||||
)
|
||||
|
||||
# Reporting settings
|
||||
enable_token_based_reporting = models.BooleanField(
|
||||
default=True,
|
||||
help_text="Show token metrics in all reports"
|
||||
)
|
||||
|
||||
# Rounding settings
|
||||
ROUNDING_CHOICES = [
|
||||
('up', 'Round Up'),
|
||||
('down', 'Round Down'),
|
||||
('nearest', 'Round to Nearest'),
|
||||
]
|
||||
|
||||
credit_rounding_mode = models.CharField(
|
||||
max_length=10,
|
||||
default='up',
|
||||
choices=ROUNDING_CHOICES,
|
||||
help_text="How to round fractional credits"
|
||||
)
|
||||
|
||||
# Audit fields
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
updated_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Admin who last updated"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
app_label = 'billing'
|
||||
db_table = 'igny8_billing_configuration'
|
||||
verbose_name = 'Billing Configuration'
|
||||
verbose_name_plural = 'Billing Configuration'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Enforce singleton pattern"""
|
||||
self.pk = 1
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_config(cls):
|
||||
"""Get or create the singleton config"""
|
||||
config, created = cls.objects.get_or_create(pk=1)
|
||||
return config
|
||||
|
||||
def __str__(self):
|
||||
return f"Billing Configuration (1 credit = {self.default_tokens_per_credit} tokens)"
|
||||
|
||||
|
||||
class PlanLimitUsage(AccountBaseModel):
|
||||
"""
|
||||
Track monthly usage of plan limits (ideas, words, images, prompts)
|
||||
|
||||
Reference in New Issue
Block a user