From 8b6b5a298cbfb42d15ed3b6429580e3433b68dbf Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Sun, 15 May 2022 10:30:49 -0600 Subject: [PATCH 1/2] pep8 fixes --- src/core/fixtures/products.json | 191 ++++++++++++++++++++++++++++++- src/ptcoffee/config.py | 6 +- src/storefront/payments.py | 196 +++++++++++++++++++------------- 3 files changed, 310 insertions(+), 83 deletions(-) diff --git a/src/core/fixtures/products.json b/src/core/fixtures/products.json index 0cba8ba..b8b7d29 100644 --- a/src/core/fixtures/products.json +++ b/src/core/fixtures/products.json @@ -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"}}] \ No newline at end of file +[{ + "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" + } +}] diff --git a/src/ptcoffee/config.py b/src/ptcoffee/config.py index eb89470..4d01a1d 100644 --- a/src/ptcoffee/config.py +++ b/src/ptcoffee/config.py @@ -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', '') diff --git a/src/storefront/payments.py b/src/storefront/payments.py index e31da49..46365fb 100644 --- a/src/storefront/payments.py +++ b/src/storefront/payments.py @@ -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 From 527d592e204fc9154286af3335f0d0b5430562a6 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Sun, 15 May 2022 15:11:40 -0600 Subject: [PATCH 2/2] Fix contact for on mobile screens to display as a single column --- src/static/styles/main.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/static/styles/main.css b/src/static/styles/main.css index dd76c08..613d29b 100644 --- a/src/static/styles/main.css +++ b/src/static/styles/main.css @@ -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; + } +} +