refactor: manage customer edit

This commit is contained in:
bobbyvish
2024-09-26 13:18:34 +05:30
parent 389dbbe390
commit 449d8615c8
3 changed files with 250 additions and 148 deletions

View File

@@ -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()

View File

@@ -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)

View 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 %}