adding subscription fee

This commit is contained in:
Flatlogic Bot 2026-01-24 03:30:04 +00:00
parent 081f578fb5
commit 9726a81f0c
11 changed files with 111 additions and 6 deletions

View File

@ -25,8 +25,8 @@ class TruckTypeAdmin(admin.ModelAdmin):
@admin.register(Profile) @admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin): class ProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'role', 'country_code', 'phone_number') list_display = ('user', 'role', 'country_code', 'phone_number', 'subscription_plan', 'is_subscription_active')
list_filter = ('role',) list_filter = ('role', 'subscription_plan', 'is_subscription_active')
search_fields = ('user__username', 'phone_number') search_fields = ('user__username', 'phone_number')
@admin.register(Truck) @admin.register(Truck)
@ -90,7 +90,13 @@ class WhatsAppConfigAdmin(admin.ModelAdmin):
@admin.register(AppSetting) @admin.register(AppSetting)
class AppSettingAdmin(admin.ModelAdmin): class AppSettingAdmin(admin.ModelAdmin):
list_display = ('app_name', 'contact_phone', 'contact_email') list_display = ('app_name', 'contact_phone', 'contact_email', 'subscription_enabled')
fieldsets = (
(None, {'fields': ('app_name', 'logo', 'slogan')}),
(_('Contact Information'), {'fields': ('contact_phone', 'contact_email', 'contact_address')}),
(_('Legal'), {'fields': ('registration_number', 'tax_number', 'terms_of_service', 'privacy_policy')}),
(_('Subscription'), {'fields': ('subscription_enabled', 'monthly_fee', 'annual_fee')}),
)
def has_add_permission(self, request): def has_add_permission(self, request):
# Only allow one configuration record # Only allow one configuration record

View File

@ -1,5 +1,5 @@
from django import forms from django import forms
from .models import Truck, Shipment, Bid, Profile, Country, OTPCode, City, TruckType from .models import Truck, Shipment, Bid, Profile, Country, OTPCode, City, TruckType, AppSetting
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -10,6 +10,8 @@ class UserRegistrationForm(UserCreationForm):
role = forms.ChoiceField(choices=[choice for choice in Profile.ROLE_CHOICES if choice[0] != 'ADMIN'], widget=forms.Select(attrs={'class': 'form-select'})) role = forms.ChoiceField(choices=[choice for choice in Profile.ROLE_CHOICES if choice[0] != 'ADMIN'], widget=forms.Select(attrs={'class': 'form-select'}))
country_code = forms.ChoiceField(choices=[], widget=forms.Select(attrs={'class': 'form-select'})) country_code = forms.ChoiceField(choices=[], widget=forms.Select(attrs={'class': 'form-select'}))
phone_number = forms.CharField(max_length=20, required=True, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '123456789'})) phone_number = forms.CharField(max_length=20, required=True, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '123456789'}))
subscription_plan = forms.ChoiceField(choices=[('MONTHLY', _('Monthly')), ('ANNUAL', _('Annual'))], required=False, widget=forms.Select(attrs={'class': 'form-select'}), label=_('Subscription Plan'))
accept_terms = forms.BooleanField(required=True, widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}), label=_('I have read and agree to the Terms and Conditions and Privacy Policy'))
class Meta(UserCreationForm.Meta): class Meta(UserCreationForm.Meta):
model = User model = User
@ -29,6 +31,16 @@ class UserRegistrationForm(UserCreationForm):
self.fields['country_code'].choices = [('966', 'Saudi Arabia (+966)')] self.fields['country_code'].choices = [('966', 'Saudi Arabia (+966)')]
self.fields['country_code'].initial = '966' self.fields['country_code'].initial = '966'
app_settings = AppSetting.objects.first()
if app_settings and app_settings.subscription_enabled:
self.fields['subscription_plan'].choices = [
('MONTHLY', _('Monthly (%(fee)s)') % {'fee': app_settings.monthly_fee}),
('ANNUAL', _('Annual (%(fee)s)') % {'fee': app_settings.annual_fee}),
]
self.fields['subscription_plan'].required = True
else:
self.fields['subscription_plan'].required = False
for field in self.fields.values(): for field in self.fields.values():
if not isinstance(field.widget, (forms.CheckboxInput, forms.Select)): if not isinstance(field.widget, (forms.CheckboxInput, forms.Select)):
field.widget.attrs.update({'class': 'form-control'}) field.widget.attrs.update({'class': 'form-control'})

View File

@ -0,0 +1,43 @@
# Generated by Django 5.2.7 on 2026-01-24 03:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0016_homesection'),
]
operations = [
migrations.AddField(
model_name='appsetting',
name='annual_fee',
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='Annual Fee'),
),
migrations.AddField(
model_name='appsetting',
name='monthly_fee',
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='Monthly Fee'),
),
migrations.AddField(
model_name='appsetting',
name='subscription_enabled',
field=models.BooleanField(default=False, verbose_name='Enable Subscription Fee'),
),
migrations.AddField(
model_name='profile',
name='is_subscription_active',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='profile',
name='subscription_expiry',
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name='profile',
name='subscription_plan',
field=models.CharField(choices=[('MONTHLY', 'Monthly'), ('ANNUAL', 'Annual'), ('NONE', 'None')], default='NONE', max_length=20),
),
]

View File

@ -53,6 +53,14 @@ class Profile(models.Model):
) )
user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='SHIPPER') role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='SHIPPER')
SUBSCRIPTION_CHOICES = (
('MONTHLY', _('Monthly')),
('ANNUAL', _('Annual')),
('NONE', _('None')),
)
subscription_plan = models.CharField(max_length=20, choices=SUBSCRIPTION_CHOICES, default='NONE')
subscription_expiry = models.DateField(null=True, blank=True)
is_subscription_active = models.BooleanField(default=False)
country_code = models.CharField(max_length=5, blank=True, default="966") country_code = models.CharField(max_length=5, blank=True, default="966")
phone_number = models.CharField(max_length=20, unique=True, null=True) # Changed to unique and nullable for migration safety phone_number = models.CharField(max_length=20, unique=True, null=True) # Changed to unique and nullable for migration safety
@ -240,6 +248,9 @@ class AppSetting(models.Model):
contact_address = models.TextField(_('Contact Address'), blank=True) contact_address = models.TextField(_('Contact Address'), blank=True)
terms_of_service = models.TextField(_('Terms of Service'), blank=True) terms_of_service = models.TextField(_('Terms of Service'), blank=True)
privacy_policy = models.TextField(_('Privacy Policy'), blank=True) privacy_policy = models.TextField(_('Privacy Policy'), blank=True)
subscription_enabled = models.BooleanField(_('Enable Subscription Fee'), default=False)
monthly_fee = models.DecimalField(_('Monthly Fee'), max_digits=10, decimal_places=2, default=0.00)
annual_fee = models.DecimalField(_('Annual Fee'), max_digits=10, decimal_places=2, default=0.00)
class Meta: class Meta:
verbose_name = _('App Setting') verbose_name = _('App Setting')

View File

@ -47,6 +47,33 @@
</div> </div>
{% elif field.name == 'phone_number' %} {% elif field.name == 'phone_number' %}
{# Handled above #} {# Handled above #}
{% elif field.name == 'subscription_plan' %}
{% if subscription_enabled %}
<div class="mb-3">
<label class="form-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<div class="text-danger small">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
{% endif %}
{% elif field.name == 'accept_terms' %}
<div class="mb-3 form-check">
{{ field }}
<label class="form-check-label small" for="{{ field.id_for_label }}">
{% trans "I have read and agree to the" %}
<a href="{% url 'terms_of_service' %}" target="_blank">{% trans "Terms of Service" %}</a>
{% trans "and" %}
<a href="{% url 'privacy_policy' %}" target="_blank">{% trans "Privacy Policy" %}</a>
</label>
{% if field.errors %}
{% for error in field.errors %}
<div class="text-danger small">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
{% else %} {% else %}
<div class="mb-3"> <div class="mb-3">
<label class="form-label" for="{{ field.id_for_label }}">{{ field.label }}</label> <label class="form-label" for="{{ field.id_for_label }}">{{ field.label }}</label>

View File

@ -23,6 +23,8 @@ def home(request):
return render(request, "core/index.html", context) return render(request, "core/index.html", context)
def register(request): def register(request):
app_settings = AppSetting.objects.first()
subscription_enabled = app_settings.subscription_enabled if app_settings else False
if request.method == 'POST': if request.method == 'POST':
form = UserRegistrationForm(request.POST) form = UserRegistrationForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -34,6 +36,7 @@ def register(request):
'role': form.cleaned_data['role'], 'role': form.cleaned_data['role'],
'phone_number': form.cleaned_data['phone_number'], 'phone_number': form.cleaned_data['phone_number'],
'country_code': form.cleaned_data['country_code'], 'country_code': form.cleaned_data['country_code'],
'subscription_plan': form.cleaned_data.get('subscription_plan', 'NONE'),
} }
request.session['registration_data'] = registration_data request.session['registration_data'] = registration_data
@ -50,7 +53,7 @@ def register(request):
messages.error(request, _("Please correct the errors below.")) messages.error(request, _("Please correct the errors below."))
else: else:
form = UserRegistrationForm() form = UserRegistrationForm()
return render(request, 'registration/register.html', {'form': form}) return render(request, 'registration/register.html', {'form': form, 'subscription_enabled': subscription_enabled})
def verify_otp_registration(request): def verify_otp_registration(request):
registration_data = request.session.get('registration_data') registration_data = request.session.get('registration_data')
@ -78,6 +81,9 @@ def verify_otp_registration(request):
profile.role = registration_data['role'] profile.role = registration_data['role']
profile.phone_number = registration_data['phone_number'] profile.phone_number = registration_data['phone_number']
profile.country_code = registration_data['country_code'] profile.country_code = registration_data['country_code']
profile.subscription_plan = registration_data.get('subscription_plan', 'NONE')
if profile.subscription_plan != 'NONE':
profile.is_subscription_active = True
profile.save() profile.save()
login(request, user) login(request, user)