Skip to content

Commit 358cd03

Browse files
committed
user verification code if email in db
1 parent 8e69237 commit 358cd03

File tree

10 files changed

+271
-55
lines changed

10 files changed

+271
-55
lines changed

appointment/admin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22

3-
from .models import Service, AppointmentRequest, Appointment
3+
from .models import Service, AppointmentRequest, Appointment, EmailVerificationCode
44

55

66
@admin.register(Service)
@@ -22,3 +22,8 @@ class AppointmentAdmin(admin.ModelAdmin):
2222
list_display = ('client', 'appointment_request', 'created_at', 'updated_at',)
2323
search_fields = ('client__user__username', 'appointment_request__service__name',)
2424
list_filter = ('client', 'appointment_request__service',)
25+
26+
27+
@admin.register(EmailVerificationCode)
28+
class EmailVerificationCodeAdmin(admin.ModelAdmin):
29+
list_display = ('user', 'code')

appointment/email_messages.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
thank_you_no_payment = f"We're excited to have you on board! Thank you for booking us. " \
2-
f"We hope you enjoy using our services and find them valuable."
3-
thank_you_payment = f"We're excited to have you on board! Thank you for booking us. The next step is to pay for " \
4-
f"the booking. You have the choice to pay the whole amount or a down deposit. " \
5-
f"If you choose the deposit, you will have to pay the rest of the amount on the day of the booking."
1+
thank_you_no_payment = ("""We're excited to have you on board! Thank you for booking us.
2+
We hope you enjoy using our services and find them valuable.""")
3+
4+
thank_you_payment_plus_down = ("""We're excited to have you on board! Thank you for booking us. The next step is to pay for
5+
the booking. You have the choice to pay the whole amount or a down deposit.
6+
If you choose the deposit, you will have to pay the rest of the amount on the day of the booking.""")
7+
8+
thank_you_payment = ("""We're excited to have you on board! Thank you for booking us. The next step is to pay for
9+
the booking.""")

appointment/models.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import datetime
2+
import random
3+
import string
24

35
from django.core.exceptions import ValidationError
46
from django.core.validators import RegexValidator
@@ -13,6 +15,11 @@
1315
message=_("Phone number must not contain spaces, letters, parentheses or dashes. It must contain 10 digits.")
1416
)
1517

18+
PAYMENT_TYPES = (
19+
('full', _('Full payment')),
20+
('down', _('Down payment')),
21+
)
22+
1623

1724
class Service(models.Model):
1825
name = models.CharField(max_length=100)
@@ -63,12 +70,16 @@ def get_updated_at(self):
6370
def is_a_paid_service(self):
6471
return self.price > 0
6572

73+
def accepts_down_payment(self):
74+
return self.down_payment > 0
75+
6676

6777
class AppointmentRequest(models.Model):
6878
date = models.DateField()
6979
start_time = models.TimeField()
7080
end_time = models.TimeField()
7181
service = models.ForeignKey(Service, on_delete=models.CASCADE)
82+
payment_type = models.CharField(max_length=4, choices=PAYMENT_TYPES, default='full')
7283
id_request = models.CharField(max_length=100, blank=True, null=True)
7384

7485
# meta data
@@ -122,6 +133,18 @@ def get_id_request(self):
122133
def is_a_paid_service(self):
123134
return self.service.is_a_paid_service()
124135

136+
def accepts_down_payment(self):
137+
return self.service.accepts_down_payment()
138+
139+
def get_payment_type(self):
140+
return self.payment_type
141+
142+
def get_created_at(self):
143+
return self.created_at
144+
145+
def get_updated_at(self):
146+
return self.updated_at
147+
125148

126149
class Appointment(models.Model):
127150
client = models.ForeignKey(APPOINTMENT_CLIENT_MODEL, on_delete=models.CASCADE)
@@ -149,6 +172,14 @@ def __str__(self):
149172
def save(self, *args, **kwargs):
150173
if self.id_request is None:
151174
self.id_request = f"{Utility.get_timestamp()}{self.appointment_request.id}{Utility.generate_random_id()}"
175+
if self.amount_to_pay is None or self.amount_to_pay == 0:
176+
payment_type = self.appointment_request.get_payment_type()
177+
if payment_type == 'full':
178+
self.amount_to_pay = self.appointment_request.get_service_price()
179+
elif payment_type == 'down':
180+
self.amount_to_pay = self.appointment_request.get_service_down_payment()
181+
else:
182+
self.amount_to_pay = 0
152183
return super().save(*args, **kwargs)
153184

154185
def get_client(self):
@@ -278,3 +309,20 @@ def get_user_email(self):
278309
return self.appointment.get_client().email
279310

280311

312+
class EmailVerificationCode(models.Model):
313+
user = models.ForeignKey(APPOINTMENT_CLIENT_MODEL, on_delete=models.CASCADE)
314+
code = models.CharField(max_length=6)
315+
316+
# meta data
317+
created_at = models.DateTimeField(auto_now_add=True)
318+
updated_at = models.DateTimeField(auto_now=True)
319+
320+
def __str__(self):
321+
return f"{self.code}"
322+
323+
@classmethod
324+
def generate_code(cls, user):
325+
code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
326+
verification_code = cls(user=user, code=code)
327+
verification_code.save()
328+
return code

appointment/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
APPOINTMENT_LEAD_TIME = getattr(settings, 'APPOINTMENT_LEAD_TIME', (9, 0))
1111
APPOINTMENT_FINISH_TIME = getattr(settings, 'APPOINTMENT_FINISH_TIME', (16, 30))
1212
APP_DEFAULT_FROM_EMAIL = getattr(settings, 'DEFAULT_FROM_EMAIL', DEFAULT_FROM_EMAIL)
13+
APP_TIME_ZONE = getattr(settings, 'TIME_ZONE', 'UTC')

appointment/templates/appointment/appointment_client_information.html

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,12 @@
4040
<div class="user-info" id="user-info">
4141
<h1 class="description-title">{% trans "Tell us a bit about yourself" %}</h1>
4242
<div class="already-have-account">
43+
<!--<div>
44+
{#{% trans 'Already have an account?' %}
45+
<a href="#">{% trans 'Log in' %}</a> {% trans 'for faster booking.' %}#}
46+
</div>-->
4347
<div>
44-
{% trans 'Already have an account?' %}
45-
<a href="#">{% trans 'Log in' %}</a> {% trans 'for faster booking.' %}
48+
{% trans 'All the fields with the * are mandatory.' %}
4649
</div>
4750
</div>
4851
<div class="name-email">
@@ -107,13 +110,15 @@ <h1 class="description-title">{% trans "Tell us a bit about yourself" %}</h1>
107110
</div>
108111
<div class="payment-options">
109112
<button type="submit" class="btn btn-dark btn-pay-full" name="payment_type"
110-
value="full_payment">
113+
value="full">
111114
{% trans "Pay" %}
112115
</button>
113-
<button type="submit" class="btn btn-dark btn-pay-down-payment" name="payment_type"
114-
value="down_payment">
115-
{% trans "Pay DP" %} (${{ ar.get_service_down_payment }})
116-
</button>
116+
{% if ar.accepts_down_payment %}
117+
<button type="submit" class="btn btn-dark btn-pay-down-payment" name="payment_type"
118+
value="down">
119+
{% trans "Pay DP" %} (${{ ar.get_service_down_payment }})
120+
</button>
121+
{% endif %}
117122
</div>
118123
</div>
119124
{% else %}

appointment/templates/appointment/appointments.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ <h1 class="page-title">{{ service.name }}</h1>
2626
{% trans "Select a date and time" %}
2727
</div>
2828
<div class="timezone-details">
29-
{% trans "Timezone" %}:&nbsp;{% trans "Eastern Daylight Time (EDT)" %}
29+
{% trans "Timezone" %}:&nbsp;{{ timezone }}
3030
</div>
3131
</div>
3232
<hr class="second-part">

appointment/templates/appointment/enter_verification_code.html

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,44 @@
55
<link rel="stylesheet" type="text/css" href="{% static 'css/thank_you.css' %}"/>
66
{% endblock %}
77
{% block title %}
8-
{{ page_title }}
8+
Enter Verification Code
99
{% endblock %}
1010
{% block description %}
11-
{{ page_description }}
11+
Enter Verification Code
1212
{% endblock %}
1313
{% block body %}
1414
<div class="container">
15-
<div class="main-content">
16-
<h1 class="thank-you-title">Thank You for Your Appointment</h1>
17-
<p class="thank-you-message">Your appointment has been successfully scheduled.</p>
18-
<p class="appointment-details-title">Appointment Details:</p>
19-
<ul class="appointment-details">
20-
<li>{% trans 'Service' %}: {{ appointment.get_service_name }}</li>
21-
<li>{% trans 'Appointment ID' %}: {{ appointment.id_request }}</li>
22-
<li>{% trans 'Appointment Date' %}: {{ appointment.get_appointment_date }}</li>
23-
<li>{% trans 'Appointment Time' %}: {{ appointment.get_start_time }}</li>
24-
</ul>
15+
{% if messages %}
16+
{% for message in messages %}
17+
<div class="alert alert-dismissible {% if message.tags %}alert-{% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}danger{% else %}{{ message.tags }}{% endif %}{% endif %}"
18+
role="alert">{{ message }}</div>
19+
{% endfor %}
20+
{% endif %}
21+
<div class="main-container">
22+
<div class="body-container">
23+
<h1>Enter Verification Code</h1>
24+
<p>We've sent a verification code to your email. Please enter it below:</p>
25+
<form method="post"
26+
action="{% url 'appointment:enter_verification_code' appointment_request_id id_request %}">
27+
{% csrf_token %}
28+
<label>Code:
29+
<input type="text" name="code" placeholder="Verification Code" required>
30+
</label>
31+
<button type="submit">Submit</button>
32+
</form>
33+
</div>
2534
</div>
2635
</div>
2736
{% endblock %}
37+
{% block customJS %}
38+
<script>
39+
document.addEventListener('DOMContentLoaded', function () {
40+
const messageElements = document.querySelectorAll('.alert-dismissible');
41+
setTimeout(function () {
42+
messageElements.forEach(function (element) {
43+
element.style.display = 'none';
44+
});
45+
}, 3000);
46+
});
47+
</script>
48+
{% endblock %}

appointment/urls.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.urls import path, include
22

33
from appointment.views import appointment_request, get_available_slots_ajax, get_next_available_date_ajax, \
4-
appointment_request_submit, appointment_client_information, default_thank_you
4+
appointment_request_submit, appointment_client_information, default_thank_you, enter_verification_code
55

66
app_name = 'appointment'
77

@@ -17,6 +17,8 @@
1717
path('request-submit/', appointment_request_submit, name='appointment_request_submit'),
1818
path('client-info/<int:appointment_request_id>/<str:id_request>/', appointment_client_information,
1919
name='appointment_client_information'),
20+
path('verification-code/<int:appointment_request_id>/<str:id_request>/', enter_verification_code,
21+
name='enter_verification_code'),
2022
path('thank-you/<int:appointment_id>/', default_thank_you, name='default_thank_you'),
2123
path('ajax/', include(ajax_urlpatterns)),
2224
]

appointment/utils.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
from django.utils.translation import to_locale, get_language
55

6-
from appointment.settings import APPOINTMENT_SLOT_DURATION, APPOINTMENT_LEAD_TIME, APPOINTMENT_FINISH_TIME
6+
from appointment.settings import APPOINTMENT_SLOT_DURATION, APPOINTMENT_LEAD_TIME, APPOINTMENT_FINISH_TIME, \
7+
APP_TIME_ZONE
78

89

910
class Utility:
@@ -107,3 +108,25 @@ def get_current_year():
107108
:return: int, the current year
108109
"""
109110
return datetime.datetime.now().year
111+
112+
@staticmethod
113+
def get_timezone():
114+
"""
115+
Get the current timezone as a string.
116+
117+
:return: str, the current timezone
118+
"""
119+
tmz = APP_TIME_ZONE
120+
timezone_map = {
121+
'UTC': 'Universal Time Coordinated (UTC)',
122+
'US/Eastern': 'Eastern Daylight Time (US & Canada)',
123+
'US/Central': 'Central Time (US & Canada)',
124+
'US/Mountain': 'Mountain Time (US & Canada)',
125+
'US/Pacific': 'Pacific Time (US & Canada)',
126+
'US/Alaska': 'Alaska Time (US & Canada)',
127+
'US/Hawaii': 'Hawaii Time (US & Canada)',
128+
'Europe/Paris': 'Paris Time (Europe)',
129+
'Europe/London': 'London Time (Europe)'
130+
}
131+
132+
return timezone_map.get(tmz, 'Universal Time Coordinated (UTC)')

0 commit comments

Comments
 (0)