Merge branch 'release/1.3.6'
This commit is contained in:
commit
a6fb7feb1b
@ -3,15 +3,16 @@ from allauth.account.models import EmailAddress
|
||||
from .models import Address, User
|
||||
from .tasks import send_account_created_email
|
||||
|
||||
|
||||
def get_or_create_customer(request, form, shipping_address):
|
||||
address, a_created = Address.objects.get_or_create(
|
||||
first_name = shipping_address['first_name'],
|
||||
last_name = shipping_address['last_name'],
|
||||
street_address_1 = shipping_address['street_address_1'],
|
||||
street_address_2 = shipping_address['street_address_2'],
|
||||
city = shipping_address['city'],
|
||||
state = shipping_address['state'],
|
||||
postal_code = shipping_address['postal_code']
|
||||
first_name=shipping_address['first_name'],
|
||||
last_name=shipping_address['last_name'],
|
||||
street_address_1=shipping_address['street_address_1'],
|
||||
street_address_2=shipping_address['street_address_2'],
|
||||
city=shipping_address['city'],
|
||||
state=shipping_address['state'],
|
||||
postal_code=shipping_address['postal_code']
|
||||
)
|
||||
|
||||
if request.user.is_authenticated:
|
||||
@ -23,8 +24,8 @@ def get_or_create_customer(request, form, shipping_address):
|
||||
else:
|
||||
user, u_created = User.objects.get_or_create(
|
||||
email=form.cleaned_data['email'],
|
||||
defaults = {
|
||||
'username': form.cleaned_data['email'],
|
||||
defaults={
|
||||
'username': form.cleaned_data['email'].lower(),
|
||||
'is_staff': False,
|
||||
'is_active': True,
|
||||
'is_superuser': False,
|
||||
@ -39,7 +40,9 @@ def get_or_create_customer(request, form, shipping_address):
|
||||
user.addresses.add(address)
|
||||
user.save()
|
||||
|
||||
EmailAddress.objects.create(user=user, email=user.email, primary=True, verified=False)
|
||||
EmailAddress.objects.create(
|
||||
user=user, email=user.email, primary=True, verified=False
|
||||
)
|
||||
|
||||
u = {
|
||||
'full_name': user.get_full_name(),
|
||||
|
||||
@ -1 +1,190 @@
|
||||
[{"model": "core.product", "pk": 1, "fields": {"name": "Ethiopia", "description": "Spicy espresso reminiscent of Northern Italy, on the mild side. Perfect for espresso, and steamed milk drinks. Also, a full-bodied, earthy sweet drip or Americano. Contains organic beans from Indonesia, Africa and America.", "sku": "23468", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 4, "created_at": "2022-02-19T20:15:36.292Z", "updated_at": "2022-03-28T17:29:26.300Z"}}, {"model": "core.product", "pk": 2, "fields": {"name": "Sumatra", "description": "Dark heavy-bodied roast with a lingering chocolatey taste. Organic Single origin.", "sku": "89765", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 3, "created_at": "2022-02-19T20:15:59.741Z", "updated_at": "2022-03-28T17:29:08.706Z"}}, {"model": "core.product", "pk": 3, "fields": {"name": "Pantomime", "description": "Very Dark French Roast\r\nOur darkest drip. A blend of five different beans roasted two ways. Organic Africa, Indonesia, and South and Central America.", "sku": "565656", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 1, "created_at": "2022-02-23T17:59:00.711Z", "updated_at": "2022-03-28T17:28:58.670Z"}}, {"model": "core.product", "pk": 4, "fields": {"name": "Decaf", "description": "French Roast (Water Processed)\r\n\r\n“I can’t believe it’s decaf!”. The best-tasting Swiss water process decaf we have developed over the past 30 years, for an unbelievable espresso or drip coffee. Organic Africa, Indonesia and South and Central America.", "sku": "566565", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 2, "created_at": "2022-02-23T17:59:32.099Z", "updated_at": "2022-03-28T17:28:45.512Z"}}, {"model": "core.product", "pk": 5, "fields": {"name": "Moka Java Blend", "description": "Dark Roast\r\n\r\nA classic Moka Java style blend dark roasted with organic beans for a perfect body and sweetness with a hint of citrus.", "sku": "56466", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": false, "sorting": 5, "created_at": "2022-02-23T18:05:41.742Z", "updated_at": "2022-03-28T17:29:39.761Z"}}, {"model": "core.product", "pk": 6, "fields": {"name": "Loop d’ Loop", "description": "Mild Dark Roast\r\n\r\nOur most popular blend reminiscent of Central Italy. A dark, chocolaty flavor perfect for espresso or drip. It’s dark Vienna roast properties make it ideal for steamed milk drinks. Organic Indonesia, Africa and America.", "sku": "53264", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 6, "created_at": "2022-02-23T18:06:09.881Z", "updated_at": "2022-03-28T17:29:53.104Z"}}, {"model": "core.product", "pk": 7, "fields": {"name": "Dante’s Tornado", "description": "Medium Roast\r\n\r\nFull City spicy espresso roast reminiscent of Northern Italy, on the mild side. A full- bodied, earthy sweet drip or Americano. Organic Indonesia, Africa and America.", "sku": "78945", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 7, "created_at": "2022-02-23T18:06:35.593Z", "updated_at": "2022-03-28T17:30:11.445Z"}}, {"model": "core.product", "pk": 8, "fields": {"name": "Nicaragua", "description": "Mild Roast\r\n\r\nOur mildest roast with sweet and fruity notes, containing organic beans from Nicaragua. Single origin.", "sku": "12365", "price": "13.40", "weight": "16.0:oz", "visible_in_listings": true, "sorting": 8, "created_at": "2022-02-23T18:06:57.624Z", "updated_at": "2022-03-28T17:30:20.941Z"}}, {"model": "core.productphoto", "pk": 1, "fields": {"product": 1, "image": "products/images/slice2.png"}}, {"model": "core.productphoto", "pk": 2, "fields": {"product": 2, "image": "products/images/slice1.png"}}, {"model": "core.productphoto", "pk": 5, "fields": {"product": 5, "image": "products/images/moka_java.png"}}, {"model": "core.productphoto", "pk": 6, "fields": {"product": 6, "image": "products/images/loop_d_loop.png"}}, {"model": "core.productphoto", "pk": 7, "fields": {"product": 7, "image": "products/images/dantes_tornado.png"}}, {"model": "core.productphoto", "pk": 8, "fields": {"product": 8, "image": "products/images/nicaragua.png"}}, {"model": "core.productphoto", "pk": 15, "fields": {"product": 3, "image": "products/images/pantomime_800.png"}}, {"model": "core.productphoto", "pk": 16, "fields": {"product": 3, "image": "products/images/pantomime_beans.png"}}, {"model": "core.productphoto", "pk": 18, "fields": {"product": 2, "image": "products/images/pantomime_beans_J2bFBiH.png"}}, {"model": "core.productphoto", "pk": 19, "fields": {"product": 4, "image": "products/images/decaf_800.png"}}, {"model": "core.productphoto", "pk": 20, "fields": {"product": 4, "image": "products/images/pantomime_beans_Lo0hJRx.png"}}]
|
||||
[{
|
||||
"model": "core.product",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Ethiopia",
|
||||
"description": "Spicy espresso reminiscent of Northern Italy, on the mild side. Perfect for espresso, and steamed milk drinks. Also, a full-bodied, earthy sweet drip or Americano. Contains organic beans from Indonesia, Africa and America.",
|
||||
"sku": "23468",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 4,
|
||||
"created_at": "2022-02-19T20:15:36.292Z",
|
||||
"updated_at": "2022-03-28T17:29:26.300Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "Sumatra",
|
||||
"description": "Dark heavy-bodied roast with a lingering chocolatey taste. Organic Single origin.",
|
||||
"sku": "89765",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-19T20:15:59.741Z",
|
||||
"updated_at": "2022-03-28T17:29:08.706Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "Pantomime",
|
||||
"description": "Very Dark French Roast\r\nOur darkest drip. A blend of five different beans roasted two ways. Organic Africa, Indonesia, and South and Central America.",
|
||||
"sku": "565656",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T17:59:00.711Z",
|
||||
"updated_at": "2022-03-28T17:28:58.670Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "Decaf",
|
||||
"description": "French Roast (Water Processed)\r\n\r\n“I can’t believe it’s decaf!”. The best-tasting Swiss water process decaf we have developed over the past 30 years, for an unbelievable espresso or drip coffee. Organic Africa, Indonesia and South and Central America.",
|
||||
"sku": "566565",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 2,
|
||||
"created_at": "2022-02-23T17:59:32.099Z",
|
||||
"updated_at": "2022-03-28T17:28:45.512Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"name": "Moka Java Blend",
|
||||
"description": "Dark Roast\r\n\r\nA classic Moka Java style blend dark roasted with organic beans for a perfect body and sweetness with a hint of citrus.",
|
||||
"sku": "56466",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": false,
|
||||
"sorting": 5,
|
||||
"created_at": "2022-02-23T18:05:41.742Z",
|
||||
"updated_at": "2022-03-28T17:29:39.761Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"name": "Loop d’ Loop",
|
||||
"description": "Mild Dark Roast\r\n\r\nOur most popular blend reminiscent of Central Italy. A dark, chocolaty flavor perfect for espresso or drip. It’s dark Vienna roast properties make it ideal for steamed milk drinks. Organic Indonesia, Africa and America.",
|
||||
"sku": "53264",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 6,
|
||||
"created_at": "2022-02-23T18:06:09.881Z",
|
||||
"updated_at": "2022-03-28T17:29:53.104Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"name": "Dante’s Tornado",
|
||||
"description": "Medium Roast\r\n\r\nFull City spicy espresso roast reminiscent of Northern Italy, on the mild side. A full- bodied, earthy sweet drip or Americano. Organic Indonesia, Africa and America.",
|
||||
"sku": "78945",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 7,
|
||||
"created_at": "2022-02-23T18:06:35.593Z",
|
||||
"updated_at": "2022-03-28T17:30:11.445Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.product",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"name": "Nicaragua",
|
||||
"description": "Mild Roast\r\n\r\nOur mildest roast with sweet and fruity notes, containing organic beans from Nicaragua. Single origin.",
|
||||
"sku": "12365",
|
||||
"price": "13.40",
|
||||
"weight": "16.0:oz",
|
||||
"visible_in_listings": true,
|
||||
"sorting": 8,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-03-28T17:30:20.941Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"product": 1,
|
||||
"image": "products/images/slice2.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"product": 2,
|
||||
"image": "products/images/slice1.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"product": 5,
|
||||
"image": "products/images/moka_java.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"product": 6,
|
||||
"image": "products/images/loop_d_loop.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"product": 7,
|
||||
"image": "products/images/dantes_tornado.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"product": 8,
|
||||
"image": "products/images/nicaragua.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 15,
|
||||
"fields": {
|
||||
"product": 3,
|
||||
"image": "products/images/pantomime_800.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 16,
|
||||
"fields": {
|
||||
"product": 3,
|
||||
"image": "products/images/pantomime_beans.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 18,
|
||||
"fields": {
|
||||
"product": 2,
|
||||
"image": "products/images/pantomime_beans_J2bFBiH.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 19,
|
||||
"fields": {
|
||||
"product": 4,
|
||||
"image": "products/images/decaf_800.png"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": 20,
|
||||
"fields": {
|
||||
"product": 4,
|
||||
"image": "products/images/pantomime_beans_Lo0hJRx.png"
|
||||
}
|
||||
}]
|
||||
|
||||
@ -28,5 +28,24 @@
|
||||
<span class="object__item">No orders</span>
|
||||
{% endfor %}
|
||||
</section>
|
||||
<section>
|
||||
<div class="pagination">
|
||||
<p class="step-links">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page=1">« first</a>
|
||||
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="current">
|
||||
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
||||
</span>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}">next</a>
|
||||
<a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
{% endblock content %}
|
||||
|
||||
@ -134,6 +134,7 @@ class CouponDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
||||
class OrderListView(LoginRequiredMixin, ListView):
|
||||
model = Order
|
||||
template_name = 'dashboard/order_list.html'
|
||||
paginate_by = 50
|
||||
|
||||
def get_queryset(self):
|
||||
query = self.request.GET.get('status')
|
||||
|
||||
@ -6,7 +6,7 @@ load_dotenv()
|
||||
DEBUG = os.environ.get('DEBUG', 'True') == 'True'
|
||||
|
||||
DATABASE_CONFIG = {
|
||||
'ENGINE' : 'django.db.backends.postgresql',
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'OPTIONS': {
|
||||
'service': 'pg_service',
|
||||
'passfile': '.pgpass'
|
||||
@ -14,8 +14,8 @@ DATABASE_CONFIG = {
|
||||
}
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY', '')
|
||||
CACHE_CONFIG = {
|
||||
'LOCATION' : 'redis://127.0.0.1:6379',
|
||||
'BACKEND' : 'django.core.cache.backends.redis.RedisCache',
|
||||
'LOCATION': 'redis://127.0.0.1:6379',
|
||||
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
|
||||
}
|
||||
|
||||
PAYPAL_CLIENT_ID = os.environ.get('PAYPAL_CLIENT_ID', '')
|
||||
|
||||
@ -240,6 +240,16 @@ input[type=submit]:hover,
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.contact-form {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.contact-form p:nth-child(6),
|
||||
.contact-form p:last-child {
|
||||
grid-column: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ from core import CoffeeGrind
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PayPalClient:
|
||||
def __init__(self):
|
||||
self.client_id = settings.PAYPAL_CLIENT_ID
|
||||
@ -25,10 +26,14 @@ class PayPalClient:
|
||||
"""Setting up and Returns PayPal SDK environment with PayPal Access credentials.
|
||||
For demo purpose, we are using SandboxEnvironment. In production this will be
|
||||
LiveEnvironment."""
|
||||
if settings.PAYPAL_ENVIRONMENT == 'LIVE':
|
||||
self.environment = LiveEnvironment(client_id=self.client_id, client_secret=self.client_secret)
|
||||
if settings.PAYPAL_ENVIRONMENT == "LIVE":
|
||||
self.environment = LiveEnvironment(
|
||||
client_id=self.client_id, client_secret=self.client_secret
|
||||
)
|
||||
else:
|
||||
self.environment = SandboxEnvironment(client_id=self.client_id, client_secret=self.client_secret)
|
||||
self.environment = SandboxEnvironment(
|
||||
client_id=self.client_id, client_secret=self.client_secret
|
||||
)
|
||||
|
||||
""" Returns PayPal HTTP client instance with environment which has access
|
||||
credentials context. This can be used invoke PayPal API's provided the
|
||||
@ -44,97 +49,122 @@ class PayPalClient:
|
||||
itr = json_data.__dict__.iteritems()
|
||||
else:
|
||||
itr = json_data.__dict__.items()
|
||||
for key,value in itr:
|
||||
for key, value in itr:
|
||||
# Skip internal attributes.
|
||||
if key.startswith("__") or key.startswith("_"):
|
||||
continue
|
||||
result[key] = self.array_to_json_array(value) if isinstance(value, list) else\
|
||||
self.object_to_json(value) if not self.is_primittive(value) else\
|
||||
value
|
||||
result[key] = (
|
||||
self.array_to_json_array(value)
|
||||
if isinstance(value, list)
|
||||
else self.object_to_json(value)
|
||||
if not self.is_primittive(value)
|
||||
else value
|
||||
)
|
||||
return result
|
||||
|
||||
def array_to_json_array(self, json_array):
|
||||
result =[]
|
||||
result = []
|
||||
if isinstance(json_array, list):
|
||||
for item in json_array:
|
||||
result.append(self.object_to_json(item) if not self.is_primittive(item) \
|
||||
else self.array_to_json_array(item) if isinstance(item, list) else item)
|
||||
result.append(
|
||||
self.object_to_json(item)
|
||||
if not self.is_primittive(item)
|
||||
else self.array_to_json_array(item)
|
||||
if isinstance(item, list)
|
||||
else item
|
||||
)
|
||||
return result
|
||||
|
||||
def is_primittive(self, data):
|
||||
return isinstance(data, str) or isinstance(data, unicode) or isinstance(data, int)
|
||||
return (
|
||||
isinstance(data, str) or isinstance(data, unicode) or isinstance(data, int)
|
||||
)
|
||||
|
||||
|
||||
class CreateOrder(PayPalClient):
|
||||
|
||||
"""Setting up the JSON request body for creating the Order. The Intent in the
|
||||
request body should be set as "CAPTURE" for capture intent flow."""
|
||||
request body should be set as "CAPTURE" for capture intent flow."""
|
||||
|
||||
def build_request_body(self, params):
|
||||
"""Method to create body with CAPTURE intent"""
|
||||
processed_items = [{
|
||||
processed_items = [
|
||||
{
|
||||
# Shows within upper-right dropdown during payment approval
|
||||
'name': f'{item["product"]}: ' + ', '.join([next((f"{value['quantity']} x {v[1]}" for i, v in enumerate(CoffeeGrind.GRIND_CHOICES) if v[0] == key), None)
|
||||
for key, value in item['variations'].items()])[:100],
|
||||
# Item details will also be in the completed paypal.com transaction view
|
||||
|
||||
'description': item['product'].subtitle,
|
||||
'unit_amount': {
|
||||
'currency_code': settings.DEFAULT_CURRENCY,
|
||||
'value': f'{item["price"]}'
|
||||
"name": f'{item["product"]}: '
|
||||
", ".join(
|
||||
[
|
||||
next(
|
||||
(
|
||||
f"{value['quantity']} x {v[1]}"
|
||||
for i, v in enumerate(CoffeeGrind.GRIND_CHOICES)
|
||||
if v[0] == key
|
||||
),
|
||||
None,
|
||||
)
|
||||
for key, value in item["variations"].items()
|
||||
]
|
||||
)[:100],
|
||||
# Item details will also be in the completed paypal.com
|
||||
# transaction view
|
||||
"description": item["product"].subtitle,
|
||||
"unit_amount": {
|
||||
"currency_code": settings.DEFAULT_CURRENCY,
|
||||
"value": f'{item["price"]}',
|
||||
},
|
||||
'quantity': f'{item["quantity"]}'
|
||||
} for item in params['items']]
|
||||
"quantity": f'{item["quantity"]}',
|
||||
}
|
||||
for item in params["items"]
|
||||
]
|
||||
|
||||
request_body = {
|
||||
"intent": "CAPTURE",
|
||||
"application_context": {
|
||||
"return_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-done')}",
|
||||
"cancel_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-canceled')}",
|
||||
"brand_name": f"{self.site_name}",
|
||||
# "landing_page": "BILLING",
|
||||
# "shipping_preference": "SET_PROVIDED_ADDRESS",
|
||||
# "user_action": "CONTINUE"
|
||||
},
|
||||
"purchase_units": [
|
||||
{
|
||||
# "reference_id": "PUHF",
|
||||
"description": "Coffee",
|
||||
|
||||
# "custom_id": "CUST-HighFashions",
|
||||
# "soft_descriptor": "HighFashions",
|
||||
"amount": {
|
||||
"currency_code": "USD",
|
||||
"value": params['total_price'],
|
||||
"breakdown": {
|
||||
"item_total": {
|
||||
"currency_code": "USD",
|
||||
"value": params['item_total']
|
||||
},
|
||||
"shipping": {
|
||||
"currency_code": "USD",
|
||||
"value": params['shipping_price']
|
||||
},
|
||||
"tax_total": {
|
||||
"currency_code": "USD",
|
||||
"value": params['tax_total']
|
||||
},
|
||||
"discount": {
|
||||
"currency_code": "USD",
|
||||
"value": params['discount']
|
||||
}
|
||||
}
|
||||
"intent": "CAPTURE",
|
||||
"application_context": {
|
||||
"return_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-done')}",
|
||||
"cancel_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-canceled')}",
|
||||
"brand_name": f"{self.site_name}",
|
||||
# "landing_page": "BILLING",
|
||||
# "shipping_preference": "SET_PROVIDED_ADDRESS",
|
||||
# "user_action": "CONTINUE"
|
||||
},
|
||||
"purchase_units": [
|
||||
{
|
||||
# "reference_id": "PUHF",
|
||||
"description": "Coffee",
|
||||
# "custom_id": "CUST-HighFashions",
|
||||
# "soft_descriptor": "HighFashions",
|
||||
"amount": {
|
||||
"currency_code": "USD",
|
||||
"value": params["total_price"],
|
||||
"breakdown": {
|
||||
"item_total": {
|
||||
"currency_code": "USD",
|
||||
"value": params["item_total"],
|
||||
},
|
||||
"shipping": {
|
||||
"currency_code": "USD",
|
||||
"value": params["shipping_price"],
|
||||
},
|
||||
"tax_total": {
|
||||
"currency_code": "USD",
|
||||
"value": params["tax_total"],
|
||||
},
|
||||
"discount": {
|
||||
"currency_code": "USD",
|
||||
"value": params["discount"],
|
||||
},
|
||||
},
|
||||
"items": processed_items,
|
||||
"shipping": {
|
||||
"method": params['shipping_method'],
|
||||
"address": params['shipping_address']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"items": processed_items,
|
||||
"shipping": {
|
||||
"method": params["shipping_method"],
|
||||
"address": params["shipping_address"],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
logger.info(f'\nRequest body: {request_body}\n')
|
||||
logger.info(f"\nRequest body: {request_body}\n")
|
||||
|
||||
return request_body
|
||||
|
||||
@ -143,29 +173,37 @@ class CreateOrder(PayPalClient):
|
||||
|
||||
def create_order(self, params, debug=False):
|
||||
request = OrdersCreateRequest()
|
||||
request.headers['prefer'] = 'return=representation'
|
||||
request.headers["prefer"] = "return=representation"
|
||||
request.request_body(self.build_request_body(params))
|
||||
response = self.client.execute(request)
|
||||
if debug:
|
||||
logger.debug(f'\nStatus Code: {response.status_code}', )
|
||||
logger.debug(f'\nStatus: {response.result.status}', )
|
||||
logger.debug(f'\nOrder ID: {response.result.id}', )
|
||||
logger.debug(f'\nIntent: {response.result.intent}', )
|
||||
logger.debug(
|
||||
f"\nStatus Code: {response.status_code}",
|
||||
)
|
||||
logger.debug(
|
||||
f"\nStatus: {response.result.status}",
|
||||
)
|
||||
logger.debug(
|
||||
f"\nOrder ID: {response.result.id}",
|
||||
)
|
||||
logger.debug(
|
||||
f"\nIntent: {response.result.intent}",
|
||||
)
|
||||
logger.debug(f"\njson_data: {response.result}")
|
||||
|
||||
return response
|
||||
|
||||
class CaptureOrder(PayPalClient):
|
||||
|
||||
class CaptureOrder(PayPalClient):
|
||||
def capture_order(self, order_id, debug=False):
|
||||
"""Method to capture order using order_id"""
|
||||
request = OrdersCaptureRequest(order_id)
|
||||
response = self.client.execute(request)
|
||||
|
||||
data = response.result.__dict__['_dict']
|
||||
data['redirect_urls'] = {
|
||||
'return_url': f"https://{self.site_domain}{reverse_lazy('storefront:payment-done')}",
|
||||
'cancel_url': f"https://{self.site_domain}{reverse_lazy('storefront:payment-canceled')}"
|
||||
data = response.result.__dict__["_dict"]
|
||||
data["redirect_urls"] = {
|
||||
"return_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-done')}",
|
||||
"cancel_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-canceled')}",
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
25
src/templates/account/password_reset.html
Executable file
25
src/templates/account/password_reset.html
Executable file
@ -0,0 +1,25 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load account %}
|
||||
|
||||
{% block head_title %}{% trans "Password Reset" %} | {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<h1>{% trans "Password Reset" %}</h1>
|
||||
{% if user.is_authenticated %}
|
||||
{% include "account/snippets/already_logged_in.html" %}
|
||||
{% endif %}
|
||||
|
||||
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p>
|
||||
|
||||
<form method="POST" action="{% url 'account_reset_password' %}" class="password_reset">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="{% trans 'Reset My Password' %}" />
|
||||
</form>
|
||||
|
||||
<p>{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}</p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
@ -1,7 +1,18 @@
|
||||
{% extends 'base.html' %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load account %}
|
||||
|
||||
{% block head_title %}{% trans "Password Reset" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article class="panel">
|
||||
<p>An email with password reset instructions has been sent.</p>
|
||||
<article>
|
||||
<h1>{% trans "Password Reset" %}</h1>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
{% include "account/snippets/already_logged_in.html" %}
|
||||
{% endif %}
|
||||
|
||||
<p>{% blocktrans %}We have sent you an e-mail. If you have not received it please check your spam folder. Otherwise contact us if you do not receive it in a few minutes.{% endblocktrans %}</p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
<article class="panel">
|
||||
<h1>Reset your password</h1>
|
||||
<p>Enter your email address below and we'll send you instructions on how to reset your password.</p>
|
||||
<form method="post" action="{% url 'password_reset' %}">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<p>
|
||||
<input type="submit" value="Send me instructions" class="action-button">
|
||||
</p>
|
||||
</form>
|
||||
</article>
|
||||
{% endblock %}
|
||||
21
src/templates/account/password_reset_from_key.html
Normal file
21
src/templates/account/password_reset_from_key.html
Normal file
@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% block head_title %}{% trans "Change Password" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<h1>{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}</h1>
|
||||
|
||||
{% if token_fail %}
|
||||
{% url 'account_reset_password' as passwd_reset_url %}
|
||||
<p>{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a <a href="{{ passwd_reset_url }}">new password reset</a>.{% endblocktrans %}</p>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ action_url }}">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" name="action" value="{% trans 'change password' %}"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
</article>
|
||||
{% endblock %}
|
||||
11
src/templates/account/password_reset_from_key_done.html
Normal file
11
src/templates/account/password_reset_from_key_done.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% block head_title %}{% trans "Change Password" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<h1>{% trans "Change Password" %}</h1>
|
||||
<p>{% trans 'Your password is now changed.' %}</p>
|
||||
</article>
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user