refactor: manage customer edit
This commit is contained in:
@@ -401,7 +401,7 @@ class CreateCustomerForm(forms.Form):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['preferences'].queryset = EventCategory.objects.all()
|
||||
|
||||
class UpdateOnboardedEventManagerForm(forms.Form):
|
||||
class UpdateCustomerForm(forms.Form):
|
||||
first_name = forms.CharField(max_length=255, required=True, label='First Name')
|
||||
last_name = forms.CharField(max_length=255, required=True, label='Last Name')
|
||||
business_name = forms.CharField(max_length=200, required=True, label="Business Name")
|
||||
@@ -443,69 +443,5 @@ class UpdateOnboardedEventManagerForm(forms.Form):
|
||||
self.fields['preferences'].queryset = EventCategory.objects.all()
|
||||
|
||||
|
||||
class UpdateEventManagerForm(forms.ModelForm):
|
||||
first_name = forms.CharField(max_length=255, required=True, label='First Name')
|
||||
last_name = forms.CharField(max_length=255, required=True, label='Last Name')
|
||||
business_name = forms.CharField(max_length=200, required=True, label="Business Name")
|
||||
email = forms.EmailField(required=True, label='Email', widget=forms.TextInput(attrs={'readonly': 'readonly'}))
|
||||
phone_no = PhoneNumberField(
|
||||
widget=forms.TextInput(),
|
||||
label="Phone No"
|
||||
)
|
||||
address_line1 = forms.CharField(widget=forms.Textarea(attrs={'rows': 4, 'cols': 40}))
|
||||
city = forms.CharField(max_length=200, required=False, label="Region")
|
||||
country = forms.CharField(max_length=200, required=False, label="Country")
|
||||
website = forms.URLField(max_length=255, required=False, label="Website")
|
||||
linkedin_profile = forms.URLField(max_length=200, required=False, label="LinkedIn")
|
||||
facebook_profile = forms.URLField(max_length=200, required=False, label="Facebook")
|
||||
instagram_profile = forms.URLField(max_length=200, required=False, label="Instagram")
|
||||
twitter_profile = forms.URLField(max_length=200, required=False, label="Twitter")
|
||||
is_active = forms.BooleanField(required=False, label='Active', help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",)
|
||||
|
||||
class Meta:
|
||||
model = models.IAmPrincipal
|
||||
fields = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"business_name",
|
||||
"email",
|
||||
"phone_no",
|
||||
'address_line1',
|
||||
'city',
|
||||
'country',
|
||||
"website",
|
||||
"linkedin_profile",
|
||||
"facebook_profile",
|
||||
"instagram_profile",
|
||||
"twitter_profile",
|
||||
"is_active",
|
||||
]
|
||||
|
||||
class UpdateEventUserForm(forms.ModelForm):
|
||||
first_name = forms.CharField(max_length=255, required=True, label='First Name')
|
||||
last_name = forms.CharField(max_length=255, required=True, label='Last Name')
|
||||
email = forms.EmailField(required=True, label='Email', widget=forms.TextInput(attrs={'readonly': 'readonly'}))
|
||||
phone_no = PhoneNumberField(
|
||||
widget=forms.TextInput(),
|
||||
label="Phone No"
|
||||
)
|
||||
address_line1 = forms.CharField(widget=forms.Textarea(attrs={'rows': 4, 'cols': 40}))
|
||||
city = forms.CharField(max_length=200, required=False, label="Region")
|
||||
country = forms.CharField(max_length=200, required=False, label="Country")
|
||||
is_active = forms.BooleanField(required=False, label='Active', help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",)
|
||||
|
||||
class Meta:
|
||||
model = models.IAmPrincipal
|
||||
fields = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"phone_no",
|
||||
'address_line1',
|
||||
'city',
|
||||
'country',
|
||||
"is_active",
|
||||
]
|
||||
|
||||
class UploadExcelForm(forms.Form):
|
||||
file = forms.FileField()
|
||||
|
||||
@@ -30,7 +30,7 @@ from manage_events.models import EventCategory, PrincipalPreference
|
||||
from manage_referrals.models import ReferralCode
|
||||
from manage_subscriptions.models import PrincipalSubscription, Subscription
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from . import resource_action
|
||||
|
||||
from .forms import (
|
||||
@@ -42,9 +42,7 @@ from .forms import (
|
||||
IAmPrincipalRoleAppResourceActionLinkForm,
|
||||
IAmPrincipalGroupLinkForm,
|
||||
ProfileEditForm,
|
||||
UpdateEventManagerForm,
|
||||
UpdateEventUserForm,
|
||||
UpdateOnboardedEventManagerForm,
|
||||
UpdateCustomerForm,
|
||||
UploadExcelForm,
|
||||
)
|
||||
from .models import (
|
||||
@@ -681,13 +679,29 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
|
||||
page_name = resource_action.RESOURCE_MANAGE_CUSTOMER
|
||||
resource = resource_action.RESOURCE_MANAGE_CUSTOMER
|
||||
model = IAmPrincipal
|
||||
template_name = None
|
||||
form_class = UpdateCustomerForm
|
||||
template_name = "accounts/customer/customer_edit.html"
|
||||
success_url = reverse_lazy("accounts:customer_list")
|
||||
success_message = "Updated Successfully"
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
def OnboardedEventManagerFormData(self, principal_obj):
|
||||
form_class = UpdateOnboardedEventManagerForm
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
principal_id = kwargs.get("pk")
|
||||
try:
|
||||
principal_obj = IAmPrincipal.objects.get(pk=principal_id)
|
||||
except Exception as e:
|
||||
messages.error(request, f"No Record of id {principal_id} is found")
|
||||
return redirect(self.success_url)
|
||||
|
||||
print(f"principal address is {principal_obj.address_line1}")
|
||||
|
||||
initial_data = {
|
||||
"first_name": principal_obj.first_name,
|
||||
@@ -720,40 +734,7 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
|
||||
initial_data["free_start_date"] = None
|
||||
initial_data["free_end_date"] = None
|
||||
|
||||
return form_class(initial=initial_data)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
principal_id = kwargs.get("pk")
|
||||
try:
|
||||
principal_obj = IAmPrincipal.objects.get(pk=principal_id)
|
||||
except Exception as e:
|
||||
messages.error(request, f"No Record of id {principal_id} is found")
|
||||
return redirect(self.success_url)
|
||||
|
||||
print(f"principal address is {principal_obj.address_line1}")
|
||||
|
||||
is_onboarded = False
|
||||
if hasattr(principal_obj, 'extended_data') and principal_obj.extended_data:
|
||||
is_onboarded = principal_obj.extended_data.is_onboarded
|
||||
|
||||
if is_onboarded and principal_obj.principal_type.name == resource_action.PRINCIPAL_TYPE_EVENT_MANAGER:
|
||||
form = self.OnboardedEventManagerFormData(principal_obj)
|
||||
self.template_name = "accounts/customer/customer_onboard_manager_edit.html"
|
||||
elif not is_onboarded and principal_obj.principal_type.name == resource_action.PRINCIPAL_TYPE_EVENT_MANAGER:
|
||||
form = UpdateEventManagerForm(instance=principal_obj)
|
||||
self.template_name = "accounts/customer/customer_manager_edit.html"
|
||||
elif principal_obj.principal_type.name == resource_action.PRINCIPAL_TYPE_EVENT_USER:
|
||||
form = UpdateEventUserForm(instance=principal_obj)
|
||||
self.template_name = "accounts/customer/customer_user_edit.html"
|
||||
|
||||
form = self.form_class(initial=initial_data)
|
||||
context = self.get_context_data(form=form, principal_obj=principal_obj)
|
||||
print("context dta is ", context)
|
||||
return render(request, self.template_name, context=context)
|
||||
@@ -765,31 +746,10 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
|
||||
except Exception as e:
|
||||
messages.error(request, f"No Record of customer id {principal_id} is found")
|
||||
return redirect(self.success_url)
|
||||
|
||||
is_onboarded = False
|
||||
if hasattr(principal_obj, 'extended_data') and principal_obj.extended_data:
|
||||
is_onboarded = principal_obj.extended_data.is_onboarded
|
||||
|
||||
# Dynamically choose the form based on the principal object's data
|
||||
if is_onboarded and principal_obj.principal_type.name == resource_action.PRINCIPAL_TYPE_EVENT_MANAGER:
|
||||
form_class = UpdateOnboardedEventManagerForm
|
||||
self.template_name = "accounts/customer/customer_onboard_manager_edit.html"
|
||||
elif not is_onboarded and principal_obj.principal_type.name == resource_action.PRINCIPAL_TYPE_EVENT_MANAGER:
|
||||
form_class = UpdateEventManagerForm
|
||||
self.template_name = "accounts/customer/customer_manager_edit.html"
|
||||
elif principal_obj.principal_type.name == resource_action.PRINCIPAL_TYPE_EVENT_USER:
|
||||
form_class = UpdateEventUserForm
|
||||
self.template_name = "accounts/customer/customer_user_edit.html"
|
||||
else:
|
||||
messages.error(request, "Invalid principal type")
|
||||
return redirect(self.success_url)
|
||||
|
||||
form = form_class(request.POST, instance=principal_obj)
|
||||
|
||||
form = self.form_class(request.POST)
|
||||
if not form.is_valid():
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
try:
|
||||
with transaction.atomic():
|
||||
# update principal data
|
||||
@@ -805,29 +765,29 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
|
||||
principal_obj.facebook_profile = form.cleaned_data.get("facebook_profile")
|
||||
principal_obj.instagram_profile = form.cleaned_data.get("instagram_profile")
|
||||
principal_obj.twitter_profile = form.cleaned_data.get("twitter_profile")
|
||||
principal_obj.is_active = form.cleaned_data.get("active")
|
||||
principal_obj.save()
|
||||
|
||||
if is_onboarded: # only update preference and subscription if it is added by admin
|
||||
# update principal preferences record
|
||||
principal_preference, _ = PrincipalPreference.objects.get_or_create(principal=principal_obj)
|
||||
principal_preference.preferred_categories.set(form.cleaned_data.get("preferences"))
|
||||
# update principal preferences record
|
||||
principal_preference, _ = PrincipalPreference.objects.get_or_create(principal=principal_obj)
|
||||
principal_preference.preferred_categories.set(form.cleaned_data.get("preferences"))
|
||||
|
||||
# update principal subscription record
|
||||
principal_subscription = PrincipalSubscription.objects.filter(principal=principal_obj).order_by('-end_date').first()
|
||||
if principal_subscription:
|
||||
principal_subscription.start_date = form.cleaned_data.get("free_start_date")
|
||||
principal_subscription.end_date = form.cleaned_data.get("free_end_date")
|
||||
principal_subscription.grace_period_end_date = form.cleaned_data.get("free_end_date") + datetime.timedelta(days=15)
|
||||
principal_subscription.save()
|
||||
else:
|
||||
PrincipalSubscription.objects.create(
|
||||
principal=principal_obj,
|
||||
start_date=form.cleaned_data.get("free_start_date"),
|
||||
end_date=form.cleaned_data.get("free_end_date"),
|
||||
grace_period_end_date=PrincipalSubscription.generate_grace_period_end_date(form.cleaned_data.get("free_end_date")),
|
||||
is_paid=True,
|
||||
subscription=Subscription.objects.filter().first() # Assuming you want to link a default subscription
|
||||
)
|
||||
# update principal subscription record
|
||||
principal_subscription = PrincipalSubscription.objects.filter(principal=principal_obj).order_by('-end_date').first()
|
||||
if principal_subscription:
|
||||
principal_subscription.start_date = form.cleaned_data.get("free_start_date")
|
||||
principal_subscription.end_date = form.cleaned_data.get("free_end_date")
|
||||
principal_subscription.grace_period_end_date = form.cleaned_data.get("free_end_date") + timedelta(days=15)
|
||||
principal_subscription.save()
|
||||
else:
|
||||
PrincipalSubscription.objects.create(
|
||||
principal=principal_obj,
|
||||
start_date=form.cleaned_data.get("free_start_date"),
|
||||
end_date=form.cleaned_data.get("free_end_date"),
|
||||
grace_period_end_date=PrincipalSubscription.generate_grace_period_end_date(form.cleaned_data.get("free_end_date")),
|
||||
is_paid=True,
|
||||
subscription=Subscription.objects.filter().first() # Assuming you want to link a default subscription
|
||||
)
|
||||
|
||||
messages.success(self.request, self.success_message)
|
||||
return redirect(self.success_url)
|
||||
|
||||
206
templates/accounts/customer/customer_edit.html
Normal file
206
templates/accounts/customer/customer_edit.html
Normal file
@@ -0,0 +1,206 @@
|
||||
{% extends 'layout/base_template.html' %}
|
||||
{% load static %}
|
||||
{% block stylesheet %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||
{% include "cdn_through_html/flatpicker_cdn_css.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row layout-top-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<a href="{% url 'accounts:customer_list'%}" style="height: fit-content;width: fit-content;display: inline-block;">
|
||||
<h3 class="card-title m-2 d-flex align-items-center gap-2" style="width: fit-content;"><span class="fw-bold material-symbols-outlined">
|
||||
arrow_back
|
||||
</span><span>{{operation}} Customer</span></h3>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if principal_obj.extended_data and not principal_obj.extended_data.is_transferred and principal_obj.extended_data.is_onboarded and principal_obj.principal_type.name == 'event_manager' %}
|
||||
<div class="col text-end">
|
||||
<a class="btn btn-dark mb-2 me-4" href="{% url 'accounts:customer_transfer' principal_obj.id %}">
|
||||
Transfer Account
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div class="row layout-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="statbox widget box box-shadow">
|
||||
<div class="widget-content widget-content-area">
|
||||
|
||||
<form method="post" id="addCustomer">
|
||||
{% csrf_token %}
|
||||
{% include 'includes/dynamic_template_form.html' with form=form %}
|
||||
<div class="mt-4 mb-0">
|
||||
<div class="d-grid"><button class="btn btn-primary btn-block" type="submit">Submit</button></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<!-- include required js cdn link through html here -->
|
||||
{% include "cdn_through_html/flatpicker_cdn_js.html" %}
|
||||
{% include "cdn_through_html/jquery_validate_cdn_js.html" %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
|
||||
-->
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
var start_date = flatpickr(document.getElementById('id_free_start_date'), {
|
||||
// minDate: "today",
|
||||
onChange: function(selectedDates, dateStr, instance) {
|
||||
end_date.set('minDate', selectedDates[0]);
|
||||
}
|
||||
});
|
||||
|
||||
var end_date = flatpickr(document.getElementById('id_free_end_date'), {
|
||||
minDate: null // initialize with no minimum date
|
||||
});
|
||||
|
||||
$('.js-example-basic-multiple').select2({
|
||||
placeholder: 'Select options',
|
||||
allowClear: true,
|
||||
tokenSeparators: [',', ' '], // Customize token separators
|
||||
closeOnSelect: false // Keep the dropdown open after selection
|
||||
});
|
||||
|
||||
|
||||
// Add custom validation method for email
|
||||
$.validator.addMethod("validEmail", function(value, element) {
|
||||
return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/.test(value);
|
||||
}, "Please enter a valid email address.");
|
||||
|
||||
// Add custom validation method to check for special characters
|
||||
$.validator.addMethod("noSpecialChars", function(value, element) {
|
||||
return /^[a-zA-Z\s]*$/.test(value); // Allow only letters and whitespace
|
||||
}, "Please enter only letters and spaces.");
|
||||
|
||||
// Add custom validation method to check for starting with a letter
|
||||
$.validator.addMethod("startsWithLetter", function(value, element) {
|
||||
return /^[a-zA-Z]/.test(value); // Check if the value starts with a letter
|
||||
}, "Please start with a letter.");
|
||||
|
||||
// Add custom validation method for greater than start date
|
||||
$.validator.addMethod("greaterThanStartDate", function(value, element) {
|
||||
var startDate = $('#id_free_start_date').val();
|
||||
if (!startDate || !value) {
|
||||
return true;
|
||||
}
|
||||
return new Date(value) > new Date(startDate);
|
||||
}, "The end date must be after the start date.");
|
||||
|
||||
|
||||
|
||||
$("#addCustomer").validate({
|
||||
rules: {
|
||||
first_name: {
|
||||
required: true,
|
||||
maxlength:15,
|
||||
noSpecialChars: true,
|
||||
startsWithLetter: true,
|
||||
},
|
||||
last_name: {
|
||||
required: true,
|
||||
maxlength: 15,
|
||||
noSpecialChars: true,
|
||||
startsWithLetter: true,
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
validEmail: true,
|
||||
},
|
||||
preferences: {
|
||||
required: true,
|
||||
minlength: 1
|
||||
},
|
||||
free_start_date: {
|
||||
required: true,
|
||||
// You can add a custom validation method for date format (optional)
|
||||
},
|
||||
free_end_date: {
|
||||
required: true,
|
||||
// You can add a custom validation method for date format (optional)
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
first_name: {
|
||||
required: "Please enter your first name.",
|
||||
maxlength: "First name must not exceed 20 characters.",
|
||||
noSpecialChars: "Please enter only letters and spaces.",
|
||||
startsWithLetter: "First name must start with a letter."
|
||||
},
|
||||
last_name: {
|
||||
required: "Please enter your last name.",
|
||||
maxlength: "First name must not exceed 20 characters.",
|
||||
noSpecialChars: "Please enter only letters and spaces.",
|
||||
startsWithLetter: "Last name must start with a letter."
|
||||
},
|
||||
email: {
|
||||
required: "Please enter your email address.",
|
||||
validEmail: "Please enter a valid email address."
|
||||
},
|
||||
preferences: {
|
||||
required: "Please select at least one preference.",
|
||||
minlength: "Please select at least one preference."
|
||||
},
|
||||
free_start_date: {
|
||||
required: "Please select a start date for the free period."
|
||||
},
|
||||
free_end_date: {
|
||||
required: "Please select an end date for the free period.",
|
||||
greaterThanStartDate: "The end date must be after the start date."
|
||||
}
|
||||
},
|
||||
errorElement: 'div',
|
||||
errorPlacement: function(error, element) {
|
||||
error.addClass('invalid-feedback');
|
||||
$(element).closest('.form-group').append(error);
|
||||
},
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
$(element).addClass('is-invalid').removeClass('is-valid');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
$(element).removeClass('is-invalid').addClass('is-valid');
|
||||
},
|
||||
submitHandler: function(form) {
|
||||
|
||||
// Check if form is valid before submission
|
||||
if ($(form).valid()) {
|
||||
// Disable the submit button to prevent multiple submissions
|
||||
$('button[type="submit"]').prop('disabled', true);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger validation for select2 fields on change
|
||||
$('#id_preferences').on('change', function() {
|
||||
$(this).valid();
|
||||
});
|
||||
|
||||
// Trigger validation for flatpickr fields on change
|
||||
$('#id_free_start_date').on('change', function() {
|
||||
$(this).valid();
|
||||
});
|
||||
$('#id_free_end_date').on('change', function() {
|
||||
$(this).valid();
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user