diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index c9f108d..af5adc3 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index cb35ac5..4624d9c 100644 Binary files a/core/__pycache__/forms.cpython-311.pyc and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index c0eda85..9f1466b 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 5941460..8907a4f 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 502dd53..2c70ecf 100644 --- a/core/admin.py +++ b/core/admin.py @@ -25,8 +25,8 @@ class TruckTypeAdmin(admin.ModelAdmin): @admin.register(Profile) class ProfileAdmin(admin.ModelAdmin): - list_display = ('user', 'role', 'country_code', 'phone_number') - list_filter = ('role',) + list_display = ('user', 'role', 'country_code', 'phone_number', 'subscription_plan', 'is_subscription_active') + list_filter = ('role', 'subscription_plan', 'is_subscription_active') search_fields = ('user__username', 'phone_number') @admin.register(Truck) @@ -90,7 +90,13 @@ class WhatsAppConfigAdmin(admin.ModelAdmin): @admin.register(AppSetting) 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): # Only allow one configuration record @@ -109,4 +115,4 @@ class HomeSectionAdmin(admin.ModelAdmin): list_display = ('title', 'section_type', 'order', 'is_active') list_editable = ('order', 'is_active') list_filter = ('section_type', 'is_active', 'background_color') - search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar') + search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar') \ No newline at end of file diff --git a/core/forms.py b/core/forms.py index a8bfadc..7ee09ed 100644 --- a/core/forms.py +++ b/core/forms.py @@ -1,5 +1,5 @@ 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.contrib.auth.forms import UserCreationForm 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'})) 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'})) + 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): model = User @@ -29,6 +31,16 @@ class UserRegistrationForm(UserCreationForm): self.fields['country_code'].choices = [('966', 'Saudi Arabia (+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(): if not isinstance(field.widget, (forms.CheckboxInput, forms.Select)): field.widget.attrs.update({'class': 'form-control'}) diff --git a/core/migrations/0017_appsetting_annual_fee_appsetting_monthly_fee_and_more.py b/core/migrations/0017_appsetting_annual_fee_appsetting_monthly_fee_and_more.py new file mode 100644 index 0000000..105ece4 --- /dev/null +++ b/core/migrations/0017_appsetting_annual_fee_appsetting_monthly_fee_and_more.py @@ -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), + ), + ] diff --git a/core/migrations/__pycache__/0017_appsetting_annual_fee_appsetting_monthly_fee_and_more.cpython-311.pyc b/core/migrations/__pycache__/0017_appsetting_annual_fee_appsetting_monthly_fee_and_more.cpython-311.pyc new file mode 100644 index 0000000..ce3b160 Binary files /dev/null and b/core/migrations/__pycache__/0017_appsetting_annual_fee_appsetting_monthly_fee_and_more.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index ec465ab..1c6482e 100644 --- a/core/models.py +++ b/core/models.py @@ -53,6 +53,14 @@ class Profile(models.Model): ) user = models.OneToOneField(User, on_delete=models.CASCADE) 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") 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) terms_of_service = models.TextField(_('Terms of Service'), 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: verbose_name = _('App Setting') diff --git a/core/templates/registration/register.html b/core/templates/registration/register.html index be7b142..74fcb1e 100644 --- a/core/templates/registration/register.html +++ b/core/templates/registration/register.html @@ -47,6 +47,33 @@ {% elif field.name == 'phone_number' %} {# Handled above #} + {% elif field.name == 'subscription_plan' %} + {% if subscription_enabled %} +
+ + {{ field }} + {% if field.errors %} + {% for error in field.errors %} +
{{ error }}
+ {% endfor %} + {% endif %} +
+ {% endif %} + {% elif field.name == 'accept_terms' %} +
+ {{ field }} + + {% if field.errors %} + {% for error in field.errors %} +
{{ error }}
+ {% endfor %} + {% endif %} +
{% else %}
diff --git a/core/views.py b/core/views.py index 9a89dbc..d0ab69f 100644 --- a/core/views.py +++ b/core/views.py @@ -23,6 +23,8 @@ def home(request): return render(request, "core/index.html", context) def register(request): + app_settings = AppSetting.objects.first() + subscription_enabled = app_settings.subscription_enabled if app_settings else False if request.method == 'POST': form = UserRegistrationForm(request.POST) if form.is_valid(): @@ -34,6 +36,7 @@ def register(request): 'role': form.cleaned_data['role'], 'phone_number': form.cleaned_data['phone_number'], 'country_code': form.cleaned_data['country_code'], + 'subscription_plan': form.cleaned_data.get('subscription_plan', 'NONE'), } request.session['registration_data'] = registration_data @@ -50,7 +53,7 @@ def register(request): messages.error(request, _("Please correct the errors below.")) else: 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): registration_data = request.session.get('registration_data') @@ -78,6 +81,9 @@ def verify_otp_registration(request): profile.role = registration_data['role'] profile.phone_number = registration_data['phone_number'] 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() login(request, user)