Merge branch 'bugfix/contact-form-styling' into develop

This commit is contained in:
Nathan Chapman 2022-05-15 15:11:53 -06:00
commit 020819b1a9
4 changed files with 320 additions and 83 deletions

View File

@ -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 cant believe its 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. Its 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": "Dantes 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 cant believe its 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. Its 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": "Dantes 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"
}
}]

View File

@ -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', '')

View File

@ -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;
}
}

View File

@ -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,25 +49,36 @@ 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):
@ -72,19 +88,34 @@ class CreateOrder(PayPalClient):
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",
@ -100,41 +131,40 @@ class CreateOrder(PayPalClient):
{
# "reference_id": "PUHF",
"description": "Coffee",
# "custom_id": "CUST-HighFashions",
# "soft_descriptor": "HighFashions",
"amount": {
"currency_code": "USD",
"value": params['total_price'],
"value": params["total_price"],
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": params['item_total']
"value": params["item_total"],
},
"shipping": {
"currency_code": "USD",
"value": params['shipping_price']
"value": params["shipping_price"],
},
"tax_total": {
"currency_code": "USD",
"value": params['tax_total']
"value": params["tax_total"],
},
"discount": {
"currency_code": "USD",
"value": params['discount']
}
}
"value": params["discount"],
},
},
},
"items": processed_items,
"shipping": {
"method": params['shipping_method'],
"address": params['shipping_address']
"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