diff --git a/accounts/forms.py b/accounts/forms.py index a70b5f7..a6eab95 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -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): diff --git a/accounts/migrations/0014_iamprincipal_business_name.py b/accounts/migrations/0014_iamprincipal_business_name.py new file mode 100644 index 0000000..36e5e8d --- /dev/null +++ b/accounts/migrations/0014_iamprincipal_business_name.py @@ -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'), + ), + ] diff --git a/accounts/migrations/0015_iamprincipal_twitter_profile.py b/accounts/migrations/0015_iamprincipal_twitter_profile.py new file mode 100644 index 0000000..06cbd13 --- /dev/null +++ b/accounts/migrations/0015_iamprincipal_twitter_profile.py @@ -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'), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index d7c1dd4..a7c6968 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -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 = [] diff --git a/accounts/views.py b/accounts/views.py index 84c03a1..490ef43 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -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") - principal_obj = IAmPrincipal.objects.get(pk=principal_id) + 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 diff --git a/templates/accounts/customer/customer_detail.html b/templates/accounts/customer/customer_detail.html index 1cec652..1df353c 100644 --- a/templates/accounts/customer/customer_detail.html +++ b/templates/accounts/customer/customer_detail.html @@ -35,10 +35,18 @@