Skip to content

Commit 61f5639

Browse files
committed
version 1.0.3-snapshot
1 parent 0854477 commit 61f5639

File tree

9 files changed

+221
-52
lines changed

9 files changed

+221
-52
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ include README.md
33
recursive-include appointment/migrations *.py
44
recursive-include appointment/templates/appointment *.html
55
recursive-include appointment/templates/base_templates *.html
6+
recursive-include appointment/templates/email_sender *.html
67
recursive-include appointment/static/css *.css
78
recursive-include appointment/static/js *.js
89
recursive-include appointment *.py

README.md

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,60 +17,60 @@ Detailed documentation is in the ["docs"](docs/README.md) directory.
1717

1818
1. Add "appointment" to your INSTALLED_APPS setting like this:
1919

20-
```python
21-
INSTALLED_APPS = [
22-
...
23-
'appointment',
24-
]
25-
```
20+
```python
21+
INSTALLED_APPS = [
22+
# other apps
23+
'appointment',
24+
]
25+
```
2626

2727
2. Include the appointment URLconf in your project urls.py like this:
2828

29-
```python
30-
from django.urls import path, include
31-
32-
urlpatterns = [
33-
...
34-
path('appointment/', include('appointment.urls')),
35-
]
36-
```
29+
```python
30+
from django.urls import path, include
31+
32+
urlpatterns = [
33+
# other urls
34+
path('appointment/', include('appointment.urls')),
35+
]
36+
```
3737

3838
3. In your Django's settings.py, add the following:
3939

40-
```python
41-
APPOINTMENT_CLIENT_MODEL = file.UserModel # Not optional (e.g. auth.User, or client.UserClient)
42-
```
40+
```python
41+
APPOINTMENT_CLIENT_MODEL = models.UserModel # Not optional (e.g. auth.User, or client.UserClient)
42+
```
4343

44-
for example if you use the default Django user model:
44+
For example, if you use the default Django user model:
4545

46-
```python
47-
APPOINTMENT_CLIENT_MODEL = auth.User
48-
```
46+
```python
47+
APPOINTMENT_CLIENT_MODEL = auth.User
48+
```
4949

50-
or if you use a custom user model:
50+
Or, if you use a custom user model:
5151

52-
```python
53-
APPOINTMENT_CLIENT_MODEL = client.UserClient
54-
```
52+
```python
53+
APPOINTMENT_CLIENT_MODEL = client.UserClient
54+
```
5555

56-
Now if you have a custom user model, in your function create_user, you have to have the following arguments even if you
57-
don't use all of them:
56+
If you have a custom user model, make sure your create_user function includes the following arguments, even if you
57+
don't use all of them:
5858

59-
```python
60-
def create_user(first_name, email, username, **extra_fields):
61-
pass
62-
```
59+
```python
60+
def create_user(first_name, email, username, **extra_fields):
61+
pass
62+
```
6363

64-
This will create a user with the password = f"{APPOINTMENT_WEBSITE_NAME}{current_year}"
64+
This will create a user with a password in the format: f"{APPOINTMENT_WEBSITE_NAME}{current_year}"
6565

66-
For example if you put in your settings.py:
66+
For example, if you add this to your settings.py:
6767

68-
```python
69-
APPOINTMENT_WEBSITE_NAME = 'Chocolates'
70-
```
68+
```python
69+
APPOINTMENT_WEBSITE_NAME = 'Chocolates'
70+
```
7171

72-
and the current year is 2023, the password will be "Chocolates2023" if you don't provide an APPOINTMENT_WEBSITE_NAME,
73-
the default value is "Website", so the password will be "Website2023".
72+
And the current year is 2023, the password will be "Chocolates2023". If you don't provide an
73+
APPOINTMENT_WEBSITE_NAME, the default value is "Website", so the password will be "Website2023".
7474

7575
4. Run `python manage.py migrate` to create the appointment models.
7676

@@ -90,18 +90,18 @@ the default value is "Website", so the password will be "Website2023".
9090

9191
1. In your Django project's settings.py, you can override the default values for the appointment scheduler:
9292

93-
```python
94-
# Default values
95-
APPOINTMENT_SLOT_DURATION = 30 # minutes
96-
APPOINTMENT_LEAD_TIME = (9, 0) # (hour, minute) 24-hour format
97-
APPOINTMENT_FINISH_TIME = (16, 30) # (hour, minute) 24-hour format
98-
99-
# Additional configuration options
100-
APPOINTMENT_BASE_TEMPLATE = 'base_templates/base.html' # your base template
101-
APPOINTMENT_WEBSITE_NAME = 'Website'
102-
APPOINTMENT_PAYMENT_URL = None
103-
APPOINTMENT_THANK_YOU_URL = None
104-
```
93+
```python
94+
# Default values
95+
APPOINTMENT_SLOT_DURATION = 30 # minutes
96+
APPOINTMENT_LEAD_TIME = (9, 0) # (hour, minute) 24-hour format
97+
APPOINTMENT_FINISH_TIME = (16, 30) # (hour, minute) 24-hour format
98+
99+
# Additional configuration options
100+
APPOINTMENT_BASE_TEMPLATE = 'base_templates/base.html' # your base template
101+
APPOINTMENT_WEBSITE_NAME = 'Website'
102+
APPOINTMENT_PAYMENT_URL = None # example of pattern 'payment:payment_linked
103+
APPOINTMENT_THANK_YOU_URL = None # example of pattern 'payment:thank_you'
104+
```
105105

106106
2. Modify these values as needed for your application, and the scheduler will adapt to the new settings.
107107

appointment/models.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class Service(models.Model):
1919
description = models.TextField(blank=True, null=True)
2020
duration = models.DurationField()
2121
price = models.DecimalField(max_digits=6, decimal_places=2)
22+
down_payment = models.DecimalField(max_digits=6, decimal_places=2, default=0)
2223
currency = models.CharField(max_length=3, default='USD')
2324
image = models.ImageField(upload_to='services/', blank=True, null=True)
2425

@@ -41,6 +42,9 @@ def get_duration(self):
4142
def get_price(self):
4243
return self.price
4344

45+
def get_down_payment(self):
46+
return self.down_payment
47+
4448
def get_currency(self):
4549
return self.currency
4650

@@ -100,6 +104,9 @@ def get_service_duration(self):
100104
def get_service_price(self):
101105
return self.service.get_price()
102106

107+
def get_service_down_payment(self):
108+
return self.service.get_down_payment()
109+
103110
def get_service_image(self):
104111
return self.service.get_image()
105112

@@ -159,6 +166,9 @@ def get_service_name(self):
159166
def get_service_price(self):
160167
return self.appointment_request.get_service_price()
161168

169+
def get_service_down_payment(self):
170+
return self.appointment_request.get_service_down_payment()
171+
162172
def get_service_img(self):
163173
return self.appointment_request.get_service_image()
164174

@@ -201,6 +211,10 @@ def get_created_at(self):
201211
def get_updated_at(self):
202212
return self.updated_at
203213

214+
def set_appointment_paid_status(self, status: bool):
215+
self.paid = status
216+
self.save()
217+
204218

205219
class Config(models.Model):
206220
slot_duration = models.PositiveIntegerField(
@@ -253,3 +267,8 @@ def get_name(self):
253267

254268
def get_img_url(self):
255269
return self.appointment.get_service_img_url()
270+
271+
def set_paid_status(self, status: bool):
272+
self.appointment.set_appointment_paid_status(status)
273+
274+

appointment/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.conf import settings
22

3-
APPOINTMENT_CLIENT_MODEL = getattr(settings, 'APPOINTMENT_CLIENT_MODEL')
3+
APPOINTMENT_CLIENT_MODEL = getattr(settings, 'APPOINTMENT_CLIENT_MODEL', 'auth.User')
44
APPOINTMENT_BASE_TEMPLATE = getattr(settings, 'APPOINTMENT_BASE_TEMPLATE', 'base_templates/base.html')
55
APPOINTMENT_WEBSITE_NAME = getattr(settings, 'APPOINTMENT_WEBSITE_NAME', 'Website')
66
APPOINTMENT_PAYMENT_URL = getattr(settings, 'APPOINTMENT_PAYMENT_URL', None)

appointment/templates/appointment/appointment_client_information.html

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,21 @@ <h1 class="description-title">{% trans "Tell us a bit about yourself" %}</h1>
105105
<div>{% trans "Total" %}</div>
106106
<div>${{ ar.get_service_price }}</div>
107107
</div>
108+
<div class="payment-options">
109+
<button type="submit" class="btn btn-dark btn-pay-full" name="payment_type"
110+
value="full_payment">
111+
{% trans "Pay" %}
112+
</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>
117+
</div>
108118
</div>
119+
{% else %}
120+
<button type="submit" class="btn btn-dark btn-submit-appointment">{{ buttonNext }}</button>
109121
{% endif %}
110-
<button type="submit" class="btn btn-dark btn-submit-appointment">{{ buttonNext }}</button>
122+
111123
</div>
112124
</form>
113125
</div>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{% load i18n %}
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<style>
8+
body {
9+
font-family: Arial, sans-serif;
10+
background-color: #f5f5f5;
11+
margin: 0;
12+
padding: 0;
13+
}
14+
15+
.email-container {
16+
max-width: 600px;
17+
margin: 0 auto;
18+
padding: 20px;
19+
background-color: #ffffff;
20+
border-radius: 4px;
21+
}
22+
23+
.header {
24+
text-align: center;
25+
padding: 20px;
26+
}
27+
28+
.header h1 {
29+
font-size: 24px;
30+
color: #333333;
31+
margin: 0;
32+
}
33+
34+
.content {
35+
padding: 20px;
36+
line-height: 1.5;
37+
color: #333333;
38+
}
39+
40+
.footer {
41+
text-align: center;
42+
padding: 20px;
43+
font-size: 12px;
44+
color: #999999;
45+
}
46+
</style>
47+
</head>
48+
<body>
49+
<div class="email-container">
50+
<div class="header">
51+
<h1>{% trans "Your booking session request has been accepted" %}!</h1>
52+
</div>
53+
<div class="content">
54+
<p>{% trans "Hello" %} {{ first_name }},</p>
55+
<p>
56+
{% if not payment %}
57+
{% blocktranslate %}
58+
We're excited to have you on board! Thank you for booking us. We hope you enjoy using our services
59+
and find them valuable.
60+
{% endblocktranslate %}
61+
{% else %}
62+
{% blocktranslate %}
63+
We're excited to have you on board! Thank you for booking us. The next step is to pay for the
64+
booking. You have the choice to pay the whole amount or a ${{ deposit }} down deposit. If you choose
65+
the deposit, you will have to pay the rest of the amount on the day of the booking.
66+
{% endblocktranslate %}
67+
{% endif %}
68+
</p>
69+
<p>
70+
{% blocktranslate %}
71+
If you have any questions or need assistance, please don't hesitate to reach out to our support team.
72+
{% endblocktranslate %}
73+
</p>
74+
<p>{% trans "Best regards" %},</p>
75+
<p>{% trans "The Team" %}</p>
76+
</div>
77+
<div class="footer">
78+
&copy; {{ current_year }} {{ company }}. {% trans "All rights reserved" %}.
79+
</div>
80+
</div>
81+
</body>
82+
</html>

appointment/views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from appointment.forms import AppointmentRequestForm
1414
from appointment.models import Service, Appointment, AppointmentRequest, PaymentInfo
1515
from appointment.utils import Utility
16+
from email_sender.email_sender import send_email
1617
from .settings import (APPOINTMENT_CLIENT_MODEL, APPOINTMENT_BASE_TEMPLATE, APPOINTMENT_WEBSITE_NAME,
1718
APPOINTMENT_PAYMENT_URL, APPOINTMENT_THANK_YOU_URL)
1819

@@ -132,6 +133,7 @@ def appointment_client_information(request, appointment_request_id, id_request):
132133
'name': request.POST.get('name'),
133134
'email': request.POST.get('email'),
134135
}
136+
payment_type = request.POST.get('payment_type')
135137
logger.info(f"Form data: {appointment_data} {client_data}")
136138

137139
# Check if email is already in the database
@@ -148,10 +150,24 @@ def appointment_client_information(request, appointment_request_id, id_request):
148150
password = f"{APPOINTMENT_WEBSITE_NAME}{Utility.get_current_year()}"
149151
user.password = make_password(password=password)
150152
user.save()
153+
154+
# Email the user
155+
send_email(
156+
recipient_list=[client_data['email']], subject="Thank you for booking us.",
157+
template_url='email_sender/thank_you_email.html', context={'first_name': user.first_name,
158+
'current_year': datetime.datetime.now().year,
159+
'company': APPOINTMENT_WEBSITE_NAME,
160+
'payment': APPOINTMENT_PAYMENT_URL is not None,
161+
'deposit': ar.get_service_down_payment()},
162+
)
151163
messages.success(request, _("An account was created for you."))
152164

153165
# Create a new appointment
154166
appointment = Appointment.objects.create(client=user, appointment_request=ar, **appointment_data)
167+
if payment_type == 'full_payment':
168+
appointment.amount_to_pay = appointment.get_service_price()
169+
elif payment_type == 'down_payment':
170+
appointment.amount_to_pay = appointment.get_service_down_payment()
155171
appointment.save()
156172

157173
logger.info(

email_sender/__init__.py

Whitespace-only changes.

email_sender/email_sender.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from django.core.mail import mail_admins, send_mail
2+
from django.template import loader
3+
4+
5+
def send_email(recipient_list, subject: str, template_url: str = None, context: dict = None, from_email=None,
6+
message: str = None):
7+
if from_email is None:
8+
from_email = '[email protected]'
9+
10+
html_message = ""
11+
12+
if template_url:
13+
html_message = loader.render_to_string(
14+
template_name=template_url,
15+
context=context
16+
)
17+
18+
send_mail(
19+
subject=subject,
20+
message=message if not template_url else "",
21+
html_message=html_message if template_url else None,
22+
from_email=from_email,
23+
recipient_list=recipient_list,
24+
fail_silently=False,
25+
)
26+
27+
28+
def notify_admin(subject: str, template_url: str = None, context: dict = None, message: str = None):
29+
html_message = ""
30+
if template_url:
31+
html_message = loader.render_to_string(
32+
template_name=template_url,
33+
context=context
34+
)
35+
mail_admins(
36+
subject=subject,
37+
message=message if not template_url else "",
38+
html_message=html_message if template_url else None
39+
)

0 commit comments

Comments
 (0)