igorsimb / mp-monitor

Django app for scraping Wildberries
1 stars 0 forks source link

Expand quotas to be for all users, not just Demo users #151

Open igorsimb opened 3 weeks ago

igorsimb commented 3 weeks ago

Currently the quotas are only applicable to Demo users. We need to expand the quotas feature to apply to every user. For that:

igorsimb commented 3 weeks ago

Resetting quotas

Step-by-Step Implementation: Define Quota Settings Based on Status:

First, define the quota settings for each status. This can be done in your settings or as a dictionary within your task file.

# myapp/constants.py
QUOTA_SETTINGS = {
    'TRIALING': {
        'user_lifetime_hours': 10,
        'max_allowed_skus': 50,
        'manual_updates': 5,
        'scheduled_updates': 5,
    },
    'ACTIVE': {
        'user_lifetime_hours': 100,
        'max_allowed_skus': 500,
        'manual_updates': 50,
        'scheduled_updates': 50,
    },
    'EXEMPT': {
        'user_lifetime_hours': 0,  # Or some default value
        'max_allowed_skus': 0,
        'manual_updates': 0,
        'scheduled_updates': 0,
    },
    'CANCELED': {
        'user_lifetime_hours': 0,
        'max_allowed_skus': 0,
        'manual_updates': 0,
        'scheduled_updates': 0,
    },
    'TRIAL_EXPIRED': {
        'user_lifetime_hours': 0,
        'max_allowed_skus': 0,
        'manual_updates': 0,
        'scheduled_updates': 0,
    }
}

Update create_user_quota

It should create quota depending on the chosen plan or Status.

Update the Celery Task:

Modify the Celery task to reset quotas based on the user's current status.

# myapp/tasks.py
from celery import shared_task
from django.db import transaction
from myapp.models import UserQuota, Tenant
from myapp.constants import QUOTA_SETTINGS

@shared_task
def reset_quotas():
    with transaction.atomic():
        tenants = Tenant.objects.all()
        for tenant in tenants:
            status_name = Tenant.Status(tenant.status).name
            quotas = QUOTA_SETTINGS.get(status_name, {
                'user_lifetime_hours': 0,
                'max_allowed_skus': 0,
                'manual_updates': 0,
                'scheduled_updates': 0
            })
            UserQuota.objects.filter(user__tenant=tenant).update(
                user_lifetime_hours=quotas['user_lifetime_hours'],
                max_allowed_skus=quotas['max_allowed_skus'],
                manual_updates=quotas['manual_updates'],
                scheduled_updates=quotas['scheduled_updates']
            )

get(): A method of dictionaries in Python that retrieves the value for a given key. If the key is not found, it returns a default value instead of raising an error. The default value is a dictionary where all quota values are set to 0. This ensures that even if a tenant has an unknown or unexpected status, their quotas will be reset to zero instead of causing an error.

Schedule the Task:

Ensure the task is scheduled to run at 12 AM on the 1st of every month.

# myapp/celery.py
from celery import Celery
from celery.schedules import crontab

app = Celery('myapp')

app.conf.beat_schedule = {
    'reset-quotas-every-month': {
        'task': 'myapp.tasks.reset_quotas',
        'schedule': crontab(minute=0, hour=0, day_of_month=1),
    },
}

Explanation: Quota Settings: The QUOTA_SETTINGS dictionary defines the default quotas for each status. Adjust these values according to your requirements.

Celery Task:

The reset_quotas task iterates over all tenants. For each tenant, it determines their status and fetches the corresponding quota settings. The quotas are then reset using the update method of the UserQuota model, ensuring all related quotas are updated in a single query. Transactional Integrity: The task is wrapped in a transaction to ensure atomicity, meaning all updates will be rolled back if any part of the task fails.

igorsimb commented 3 weeks ago

Parse Units system

class UserQuota(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name="user_quotas")
    user_lifetime_hours = models.PositiveIntegerField(default=0, blank=True, null=True)
    max_allowed_skus = models.PositiveIntegerField(default=0, blank=True, null=True)
    manual_updates = models.PositiveIntegerField(default=0, blank=True, null=True)
    scheduled_updates = models.PositiveIntegerField(default=0, blank=True, null=True)
    allowed_parse_units = models.PositiveIntegerField(default=0, blank=True, null=True)  # New field for checks Единица проверки