Merge pull request #84 from WDI-Ideas/feature/module_1

Feature/module 1
This commit is contained in:
BOBBY VISHWAKARMA
2024-08-13 15:21:56 +05:30
committed by GitHub
7 changed files with 233 additions and 20 deletions

View File

@@ -364,7 +364,12 @@ class IAmPrincipalResourceLinkForm(IAmPrincipalForm):
class CreateCustomerForm(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")
email = forms.EmailField(required=True, label='Email')
phone_no = PhoneNumberField(
widget=forms.TextInput(),
label="Phone No"
)
preferences = forms.ModelMultipleChoiceField(
queryset=EventCategory.objects.all(),
widget=forms.widgets.SelectMultiple(
@@ -383,6 +388,14 @@ class CreateCustomerForm(forms.Form):
label=_('Free period end date'),
help_text=_('Enter the end date of the free period')
)
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")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -391,7 +404,12 @@ class CreateCustomerForm(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")
email = forms.EmailField(required=True, label='Email', widget=forms.TextInput(attrs={'readonly': 'readonly'}))
phone_no = PhoneNumberField(
widget=forms.TextInput(),
label="Phone No"
)
preferences = forms.ModelMultipleChoiceField(
queryset=EventCategory.objects.all(),
widget=forms.widgets.SelectMultiple(
@@ -410,6 +428,14 @@ class UpdateCustomerForm(forms.Form):
label=_('Free period end date'),
help_text=_('Enter the end date of the free period')
)
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")
active = forms.BooleanField(required=False, label='Active', help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",)
def __init__(self, *args, **kwargs):

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-08-11 16:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0013_iamprincipalextendeddata_pwd_changed_post_transfer'),
]
operations = [
migrations.AddField(
model_name='iamprincipal',
name='business_name',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Business Name'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-08-12 08:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0014_iamprincipal_business_name'),
]
operations = [
migrations.AddField(
model_name='iamprincipal',
name='twitter_profile',
field=models.URLField(blank=True, max_length=255, null=True, verbose_name='Principal Twitter'),
),
]

View File

@@ -320,6 +320,8 @@ class IAmPrincipal(AbstractUser):
blank=True,
null=True,
)
business_name = models.CharField(verbose_name="Business Name", max_length=200, blank=True, null=True)
twitter_profile = models.URLField(verbose_name="Principal Twitter", max_length=255, null=True, blank=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []

View File

@@ -627,11 +627,21 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
email=form.cleaned_data.get('email'),
first_name=form.cleaned_data.get('first_name'),
last_name=form.cleaned_data.get('last_name'),
business_name=form.cleaned_data.get('business_name'),
phone_no=form.cleaned_data.get('phone_no'),
password=make_password("goodtimes#2024"),
username=form.cleaned_data.get("email"),
email_verified=True,
register_complete=True,
principal_type=IAmPrincipalType.objects.get(name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER),
address_line1=form.cleaned_data.get("address_line1"),
city=form.cleaned_data.get("city"),
country=form.cleaned_data.get("country"),
website=form.cleaned_data.get("website"),
linkedin_profile=form.cleaned_data.get("linkedin_profile"),
facebook_profile=form.cleaned_data.get("facebook_profile"),
instagram_profile=form.cleaned_data.get("instagram_profile"),
twitter_profile=form.cleaned_data.get("twitter_profile"),
)
# generate referralcode of manager
@@ -648,7 +658,7 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
principal_preference = PrincipalPreference.objects.create(principal=principal_obj)
principal_preference.preferred_categories.set(form.cleaned_data.get("preferences"))
principal_subscription= PrincipalSubscription.objects.create(
principal_subscription = PrincipalSubscription.objects.create(
start_date=form.cleaned_data.get("free_start_date"),
end_date=form.cleaned_data.get("free_end_date"),
principal=principal_obj,
@@ -660,6 +670,7 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
messages.success(self.request, constants.REGISTRATION_SUCCESS)
return redirect(self.success_url)
except Exception as e:
print("errror is ", e)
messages.error(self.request, str(e))
context = self.get_context_data(form=form)
return render(request, self.template_name, context=context)
@@ -685,12 +696,28 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
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,
"last_name": principal_obj.last_name,
"email": principal_obj.email,
"business_name": principal_obj.business_name,
"phone_no": principal_obj.phone_no,
"address_line1": principal_obj.address_line1,
"city": principal_obj.city,
"country": principal_obj.country,
"website": principal_obj.website,
"linkedin_profile": principal_obj.linkedin_profile,
"facebook_profile": principal_obj.facebook_profile,
"instagram_profile": principal_obj.instagram_profile,
"twitter_profile": principal_obj.twitter_profile,
"active": principal_obj.is_active
}
@@ -714,8 +741,12 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
return render(request, self.template_name, context=context)
def post(self, request, *args, **kwargs):
customer_id = kwargs.get("pk")
principal_obj = IAmPrincipal.objects.get(pk=customer_id)
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 customer id {principal_id} is found")
return redirect(self.success_url)
form = self.form_class(request.POST)
if not form.is_valid():
context = self.get_context_data(form=form)
@@ -725,6 +756,16 @@ class CustomerUpdateView(LoginRequiredMixin, generic.View):
# update principal data
principal_obj.first_name = form.cleaned_data.get('first_name')
principal_obj.last_name = form.cleaned_data.get('last_name')
principal_obj.business_name = form.cleaned_data.get("business_name")
principal_obj.phone_no = form.cleaned_data.get("phone_no")
principal_obj.address_line1 = form.cleaned_data.get("address_line1")
principal_obj.city = form.cleaned_data.get("city")
principal_obj.country = form.cleaned_data.get("country")
principal_obj.website = form.cleaned_data.get("website")
principal_obj.linkedin_profile = form.cleaned_data.get("linkedin_profile")
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.save()
# update principal preferences record
@@ -881,26 +922,75 @@ from django.http import HttpResponse
# wb.save(response)
# return response
# from openpyxl.styles import Font
def export_excel_template(request):
# Define the columns and create an empty DataFrame
columns = ['First Name', 'Last Name', 'Email', 'Preferences(should be seperated by comma)', 'Free period start date(YYYY-MM-DD)', 'Free period end date(YYYY-MM-DD)']
# Define the columns for the Customer Registration sheet
columns = [
'First Name',
'Last Name',
'Business Name',
'Email',
'Phone No',
'Preferences (should be separated by comma)',
'Free period start date (YYYY-MM-DD)',
'Free period end date (YYYY-MM-DD)',
'Address',
'Region',
'Country',
'Website',
'LinkedIn',
'Facebook',
'Instagram',
'Twitter',
]
df = pd.DataFrame(columns=columns)
# Create a workbook and select the active worksheet
# Create a workbook and add the Customer Registration worksheet
wb = Workbook()
ws = wb.active
ws.title = 'Customer Registration'
ws_customer = wb.active
ws_customer.title = 'Manager Onboarding'
# Write the column headers
# Write the column headers for the Customer Registration sheet
for col_num, column_title in enumerate(df.columns, 1):
cell = ws.cell(row=1, column=col_num, value=column_title)
cell = ws_customer.cell(row=1, column=col_num, value=column_title)
cell.font = Font(bold=True)
# Create the Readme worksheet
ws_readme = wb.create_sheet(title='Readme')
# Add information about each field to the Readme sheet
readme_data = [
['Field Name', 'Description'],
['First Name', 'The first name of the customer. This is a required field.'],
['Last Name', 'The last name of the customer. This is a required field.'],
['Business Name', 'The official name of the customer\'s business or organization.'],
['Email', 'The email address of the customer. This must be a unique email not already used in the system. This is a required Field'],
['Phone No', 'The business phone number. It should include the country code if applicable.'],
['Category', 'A comma-separated list of event categories the customer is interested in. These should match existing categories in the system. This is a required Field'],
['Free period start date', 'The start date of the customer\'s free trial period, formatted as YYYY-MM-DD.'],
['Free period end date', 'The end date of the customer\'s free trial period, formatted as YYYY-MM-DD. This date must be later than the start date.'],
['Address', 'The complete business address, including street, city, and postal code.'],
['Region', 'The geographic region where the business operates.'],
['Country', 'The country where the business is based.'],
['Website', 'The URL of the business\'s official website. Ensure it includes "http://" or "https://".'],
['LinkedIn', 'The LinkedIn profile URL of the business. Ensure it includes "http://" or "https://".'],
['Facebook', 'The Facebook page URL of the business. Ensure it includes "http://" or "https://".'],
['Instagram', 'The Instagram profile URL of the business. Ensure it includes "http://" or "https://".'],
['Twitter', 'The Twitter handle or profile URL of the business. Ensure it includes "http://" or "https://".'],
]
# Write the Readme data to the Readme worksheet
for row_num, row_data in enumerate(readme_data, 1):
for col_num, cell_value in enumerate(row_data, 1):
cell = ws_readme.cell(row=row_num, column=col_num, value=cell_value)
if row_num == 1: # Make the header bold
cell.font = Font(bold=True)
# Save the workbook to a bytes buffer
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=customer_registration_template.xlsx'
wb.save(response)
return response
class CustomerTransferView(LoginRequiredMixin, generic.View):
@@ -921,7 +1011,7 @@ class CustomerTransferView(LoginRequiredMixin, generic.View):
# Send the email
try:
temp_password="goodtimes#2024"
temp_password = "goodtimes#2024"
principal_obj.password = make_password(temp_password)
principal_obj.save()
email_service.load_template(
@@ -968,12 +1058,19 @@ class CustomerImportView(LoginRequiredMixin, generic.View):
excel_file = request.FILES['file']
wb = load_workbook(filename=excel_file)
ws = wb.active
# Check if the specific sheet exists
if 'Manager Onboarding' not in wb.sheetnames:
form.add_error('file', 'The required sheet "Manager Onboarding" is not present in the uploaded file.')
return render(request, self.template_name, context=context)
# Load the "Manager Onboarding" worksheet
ws = wb['Manager Onboarding']
error_log = []
principals = []
preferences_l = []
preferences_list = []
subscriptions = []
principal_type = IAmPrincipalType.objects.get(name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER)
free_subscription = Subscription.objects.filter(is_free=True, active=True).first()
@@ -983,7 +1080,7 @@ class CustomerImportView(LoginRequiredMixin, generic.View):
return render(request, self.template_name, context=context)
for idx, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):
first_name, last_name, email, preferences, start_date, end_date = row
first_name, last_name, business_name, email, phone_no, preferences, start_date, end_date, address, region, country, website, linkedin, facebook, instagram, twitter = row
print(f"{first_name}, {last_name, email, preferences, start_date, end_date}")
# validate all data
@@ -1017,16 +1114,26 @@ class CustomerImportView(LoginRequiredMixin, generic.View):
username=email.strip(),
email_verified=True,
register_complete=True,
principal_type=principal_type
principal_type=principal_type,
business_name=business_name,
phone_no=str(phone_no),
address_line1=address,
city=region,
country=country,
website=website,
linkedin_profile=linkedin,
facebook_profile=facebook,
instagram_profile=instagram,
twitter_profile=twitter
)
principals.append(principal)
# Collect preferences to be set later
preferences_l.append((principal, event_categories, start_date, end_date))
preferences_list.append((principal, event_categories, start_date, end_date))
if error_log:
context = self.get_context_data(form=form, error_log=error_log)
messages.error(request, "No recore is created check error log and fix the error in the file ")
messages.error(request, "No record is created check error log and fix the error in the file ")
return render(request, self.template_name, context=context)
# Use transaction.atomic to ensure all-or-nothing
@@ -1039,7 +1146,7 @@ class CustomerImportView(LoginRequiredMixin, generic.View):
principals = IAmPrincipal.objects.filter(email__in=[p.email for p in principals])
# Create subscriptions and preferences
for principal, event_categories, start_date, end_date in preferences_l:
for principal, event_categories, start_date, end_date in preferences_list:
principal = principals.get(email=principal.email)
# Generate referral code for the manager

View File

@@ -35,10 +35,18 @@
<div class="col-md-3">Last Name</div>
<div class="col-md-9">{{principal_obj.last_name}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Business Name</div>
<div class="col-md-9">{{principal_obj.business_name}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Email Address</div>
<div class="col-md-9">{{principal_obj.email}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Phone No</div>
<div class="col-md-9">{{principal_obj.phone_no}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Preferences</div>
<div class="col-md-9">
@@ -61,6 +69,38 @@
<div class="col-md-3">End Date</div>
<div class="col-md-9">{% if principal_subscription %}{{ principal_subscription.end_date }}{% else %}No subscription found{% endif %}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Address</div>
<div class="col-md-9">{{principal_obj.address_line1}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Region</div>
<div class="col-md-9">{{principal_obj.city}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Country</div>
<div class="col-md-9">{{principal_obj.country}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Website</div>
<div class="col-md-9">{{principal_obj.website}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Facebook</div>
<div class="col-md-9">{{principal_obj.facebook_profile}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">LinkedIn</div>
<div class="col-md-9">{{principal_obj.linkedin_profile}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Instagram</div>
<div class="col-md-9">{{principal_obj.instagram_profile}}</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Twitter</div>
<div class="col-md-9">{{principal_obj.twitter_profile}}</div>
</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 %}">

View File

@@ -129,6 +129,7 @@
</td> -->
<td class="text-center">
<ul class="table-controls">
{% if data_obj.extended_data.is_onboarded%}
<li><a href="{% url 'accounts:customer_edit' data_obj.id%}" class="bs-tooltip"
data-bs-toggle="tooltip" data-bs-placement="top" title=""
data-original-title="Edit" data-bs-original-title="Edit"
@@ -141,6 +142,7 @@
d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z">
</path>
</svg></a></li>
{%endif%}
<li><a href="{% url 'accounts:customer_detail' data_obj.id%}" class="bs-tooltip" data-bs-toggle="tooltip" data-bs-placement="top" title="" data-original-title="View" data-bs-original-title="View" aria-label="View">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
</a></li>