From 3741dc5234e3bfbba95d0d8ec83ba37c65de0716 Mon Sep 17 00:00:00 2001 From: JamesRamm Date: Mon, 31 Dec 2018 16:09:12 +0100 Subject: [PATCH] Update documentation --- README.md | 4 +- docs/{images => assets}/dashboard.png | Bin docs/{images => assets}/default_shipping.png | Bin docs/{images => assets}/order_detail.png | Bin docs/{images => assets}/order_list.png | Bin docs/{images => assets}/product.png | Bin docs/{images => assets}/product_index.png | Bin docs/{images => assets}/product_variant.png | Bin docs/{images => assets}/shipping.png | Bin docs/doc2.md | 7 - docs/doc3.md | 13 -- docs/exampledoc4.md | 6 - docs/exampledoc5.md | 6 - docs/guide/api.md | 131 +++++++++-------- docs/guide/basket.md | 55 ++++--- docs/guide/checkout.md | 38 ++--- docs/guide/checkout_api.md | 143 +++++++++---------- docs/guide/contrib.md | 18 +-- docs/guide/payments.md | 58 ++++---- docs/tutorial/checkout.md | 112 +++++++-------- docs/tutorial/frontend.md | 22 +-- docs/tutorial/products.md | 134 +++++++++-------- docs/tutorial/shipping.md | 38 +++-- website/siteConfig.js | 6 +- 24 files changed, 369 insertions(+), 422 deletions(-) rename docs/{images => assets}/dashboard.png (100%) rename docs/{images => assets}/default_shipping.png (100%) rename docs/{images => assets}/order_detail.png (100%) rename docs/{images => assets}/order_list.png (100%) rename docs/{images => assets}/product.png (100%) rename docs/{images => assets}/product_index.png (100%) rename docs/{images => assets}/product_variant.png (100%) rename docs/{images => assets}/shipping.png (100%) delete mode 100755 docs/doc2.md delete mode 100755 docs/doc3.md delete mode 100755 docs/exampledoc4.md delete mode 100755 docs/exampledoc5.md diff --git a/README.md b/README.md index b1c1d45..fcad68a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Checkout the [demo site](https://github.com/JamesRamm/longclaw_demo) and [docume Buy Me A Coffee -![Image of the dashboard](docs/images/dashboard.png) +![Image of the dashboard](docs/assets/dashboard.png) ## Quickstart @@ -42,7 +42,7 @@ Setup a Longclaw project ### Screenshots -![Order Detail](docs/images/order_detail.png) +![Order Detail](docs/assets/order_detail.png) ## Support diff --git a/docs/images/dashboard.png b/docs/assets/dashboard.png similarity index 100% rename from docs/images/dashboard.png rename to docs/assets/dashboard.png diff --git a/docs/images/default_shipping.png b/docs/assets/default_shipping.png similarity index 100% rename from docs/images/default_shipping.png rename to docs/assets/default_shipping.png diff --git a/docs/images/order_detail.png b/docs/assets/order_detail.png similarity index 100% rename from docs/images/order_detail.png rename to docs/assets/order_detail.png diff --git a/docs/images/order_list.png b/docs/assets/order_list.png similarity index 100% rename from docs/images/order_list.png rename to docs/assets/order_list.png diff --git a/docs/images/product.png b/docs/assets/product.png similarity index 100% rename from docs/images/product.png rename to docs/assets/product.png diff --git a/docs/images/product_index.png b/docs/assets/product_index.png similarity index 100% rename from docs/images/product_index.png rename to docs/assets/product_index.png diff --git a/docs/images/product_variant.png b/docs/assets/product_variant.png similarity index 100% rename from docs/images/product_variant.png rename to docs/assets/product_variant.png diff --git a/docs/images/shipping.png b/docs/assets/shipping.png similarity index 100% rename from docs/images/shipping.png rename to docs/assets/shipping.png diff --git a/docs/doc2.md b/docs/doc2.md deleted file mode 100755 index 20c0c95..0000000 --- a/docs/doc2.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: doc2 -title: document number 2 ---- - -This is a link to [another document.](doc3.md) -This is a link to an [external page.](http://www.example.com) diff --git a/docs/doc3.md b/docs/doc3.md deleted file mode 100755 index bcb9054..0000000 --- a/docs/doc3.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -id: doc3 -title: This is document number 3 ---- -Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac euismod odio, eu consequat dui. Nullam molestie consectetur risus id imperdiet. Proin sodales ornare turpis, non mollis massa ultricies id. Nam at nibh scelerisque, feugiat ante non, dapibus tortor. Vivamus volutpat diam quis tellus elementum bibendum. Praesent semper gravida velit quis aliquam. Etiam in cursus neque. Nam lectus ligula, malesuada et mauris a, bibendum faucibus mi. Phasellus ut interdum felis. Phasellus in odio pulvinar, porttitor urna eget, fringilla lectus. Aliquam sollicitudin est eros. Mauris consectetur quam vitae mauris interdum hendrerit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. - -Duis et egestas libero, imperdiet faucibus ipsum. Sed posuere eget urna vel feugiat. Vivamus a arcu sagittis, fermentum urna dapibus, congue lectus. Fusce vulputate porttitor nisl, ac cursus elit volutpat vitae. Nullam vitae ipsum egestas, convallis quam non, porta nibh. Morbi gravida erat nec neque bibendum, eu pellentesque velit posuere. Fusce aliquam erat eu massa eleifend tristique. - -Sed consequat sollicitudin ipsum eget tempus. Integer a aliquet velit. In justo nibh, pellentesque non suscipit eget, gravida vel lacus. Donec odio ante, malesuada in massa quis, pharetra tristique ligula. Donec eros est, tristique eget finibus quis, semper non nisl. Vivamus et elit nec enim ornare placerat. Sed posuere odio a elit cursus sagittis. - -Phasellus feugiat purus eu tortor ultrices finibus. Ut libero nibh, lobortis et libero nec, dapibus posuere eros. Sed sagittis euismod justo at consectetur. Nulla finibus libero placerat, cursus sapien at, eleifend ligula. Vivamus elit nisl, hendrerit ac nibh eu, ultrices tempus dui. Nam tellus neque, commodo non rhoncus eu, gravida in risus. Nullam id iaculis tortor. - -Nullam at odio in sem varius tempor sit amet vel lorem. Etiam eu hendrerit nisl. Fusce nibh mauris, vulputate sit amet ex vitae, congue rhoncus nisl. Sed eget tellus purus. Nullam tempus commodo erat ut tristique. Cras accumsan massa sit amet justo consequat eleifend. Integer scelerisque vitae tellus id consectetur. diff --git a/docs/exampledoc4.md b/docs/exampledoc4.md deleted file mode 100755 index 6f94ffe..0000000 --- a/docs/exampledoc4.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: doc4 -title: Other Document ---- - -this is another document diff --git a/docs/exampledoc5.md b/docs/exampledoc5.md deleted file mode 100755 index 92e2d0d..0000000 --- a/docs/exampledoc5.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: doc5 -title: Fifth Document ---- - -Another one diff --git a/docs/guide/api.md b/docs/guide/api.md index 81715dd..36d297a 100644 --- a/docs/guide/api.md +++ b/docs/guide/api.md @@ -3,91 +3,96 @@ title: API Client sidebar_label: API Client --- -Using the API client -===================== - Longclaw comes with a handy API javascript client to simplify making HTTP requests. To load the client into your HTML templates, you can use the template tags: -.. code-block:: django +```django {% load longclawcore_tags %} {% longclaw_vendors_bundle %} {% longclaw_client_bundle %} +``` -This will render the `` +``` -The first half uses the ``gateway_client_js`` template tag to load all the payment gateway javascript. There may be one or more. +The first half uses the `gateway_client_js` template tag to load all the payment gateway javascript. There may be one or more. The second half has three parts to it: -1. ``{% longclaw_client_bundle %}`` loads the longclaw client API, which is required by the checkout form javascript. -2. ``{{ checkout_form.media }}`` loads the javascript required by the checkout form. +1. `{% longclaw_client_bundle %}` loads the longclaw client API, which is required by the checkout form javascript. +2. `{{ checkout_form.media }}` loads the javascript required by the checkout form. 3. The last script initializes the checkout javascript. It requires the longclaw API url prefix (which you can customise in your settings) - to be passed in - there is a template tag to do this for you. You can also optionally specify the ``shippingCountrySelectId`` and ``shippingOptionSelectId``. + to be passed in - there is a template tag to do this for you. You can also optionally specify the `shippingCountrySelectId` and `shippingOptionSelectId`. These are the ID's of the select element. You would only need to pass these in if you are going to change them from the defaults. After this, when you change the shipping country, the shipping option should change appropriately. -..note:: We will hopefully improve this in future releases - any ideas and PR's are welcome! +> We will hopefully improve this in future releases - any ideas and PR's are welcome! -Payment forms -------------- +## Payment forms It is up to you to render a payment form and then pass the token in the POST data. Normally, the payment gateway chosen will have a javascript integration to render a form for you and tokenize the payment method (e.g. braintrees 'hosted fields') Longclaws' payment gateways provide some helpful utilities to load client javascript and generate tokens. -Loading ``longclawcheckout_tags`` in your template will allow you to retrieve the gateways' javascript libraries -as script tags (``{% gateway_client_js %}`` and generate a client token (``{% gateway_token %}``). +Loading `longclawcheckout_tags` in your template will allow you to retrieve the gateways' javascript libraries +as script tags (`{% gateway_client_js %}` and generate a client token (`{% gateway_token %}`). A little javascript is then required to setup your form and ask the gateway to tokenize the payment method for you. You should then add this token to the request POST data (e.g. with a hidden input field). diff --git a/docs/guide/checkout_api.md b/docs/guide/checkout_api.md index 469bb91..9bbfe6f 100644 --- a/docs/guide/checkout_api.md +++ b/docs/guide/checkout_api.md @@ -15,8 +15,8 @@ In the front end, you should: The first two are relatively simple to achieve. Longclaw provides some utilities to help with the rest. -Payment Capture -=============== +## Payment Capture + With Longclaw you can either tokenize the customers payment method (e.g. credit card) and send this to the server for the payment to be captured, or you can use a service such as paypal express checkout, which captures the payment directly and returns a token representing the transaction @@ -27,111 +27,106 @@ The second option is often easiest to integrate since the user is redirected to The first option offers tightest integration with the look and feel of your site, but invariable involves more front end work and validation. -Tokenizing the Payment -+++++++++++++++++++++++ +### Tokenizing the Payment + To capture the payment with a 3rd party service, you will include some external javascript on your page -and often designate a button or ``div`` to initialise the popup/redirect. You will also specify a submit +and often designate a button or `div` to initialise the popup/redirect. You will also specify a submit handler to receive the token representing the transaction. For example, the braintree javascript client allows express checkout using Paypal. Full details of how -to setup are `here `_. +to setup are [here](https://developers.braintreepayments.com/guides/paypal/checkout-with-paypal/javascript/v3). Other providers such as Stripe offer similar services. Once you have received this token, you should submit it, along with the shipping address, billing address, -email and shipping rate to the ``api/checkout/prepaid/`` endpoint. +email and shipping rate to the `api/checkout/prepaid/` endpoint. -.. note:: The ``api/`` prefix can be configured in your django settings under ``API_URL_PREFIX``. - For example, if you want to distinguish the longclaw API from your own, you could set ``API_URL_PREFIX="api/longclaw/"`` - The checkout url would then be ``api/longclaw/checkout/prepaid/`` +> The `api/` prefix can be configured in your django settings under `API_URL_PREFIX`. + For example, if you want to distinguish the longclaw API from your own, you could set `API_URL_PREFIX="api/longclaw/"` + The checkout url would then be `api/longclaw/checkout/prepaid/` The JSON request data would look like: -.. code-block:: json - +```json { - transaction_id: "...", - shipping_rate: 0.0, - email: "john@smith.com", - address: { - shipping_name: "john smith", - shipping_address_line_1": "...", - shipping_address_city: "", - shipping_address_zip: "", - shipping_address_country: "", - billing_name: "john smith", - billing_address_line_1: "...", - billing_address_city: "", - billing_address_zip: "", - billing_address_country: "", + "transaction_id": "...", + "shipping_rate": 0.0, + "email": "john@smith.com", + "address": { + "shipping_name": "john smith", + "shipping_address_line_1": "...", + "shipping_address_city": "", + "shipping_address_zip": "", + "shipping_address_country": "", + "billing_name": "john smith", + "billing_address_line_1": "...", + "billing_address_city": "", + "billing_address_zip": "", + "billing_address_country": "", } } +``` +`transaction_id` is the token returned from the payment processor e.g. paypal -transaction_id - The token returned from e.g. paypal +When using this method, you do not need to define the `PAYMENT_GATEWAY` setting. -When using this method, you do not need to define the ``PAYMENT_GATEWAY`` setting. - -Tokenizing the Payment method -+++++++++++++++++++++++++++++ +### Tokenizing the Payment method Alternatively, you can pass the payment method for Longclaw to manually capture the payment. Longclaw expects the payment details (i.e. credit card) to be passed as some kind of token in -a POST request to ``api/checkout/``. -Longclaw will then use the payment gateway defined by the ``PAYMENT_GATEWAY`` setting to capture +a POST request to `api/checkout/`. +Longclaw will then use the payment gateway defined by the `PAYMENT_GATEWAY` setting to capture the payment. To create the initial token representing the customers payment information, you may be able to use -the ``api/checkout/token/`` endpoint, passing the card information in the request data. This is dependent +the `api/checkout/token/` endpoint, passing the card information in the request data. This is dependent upon the backend and it may be preferable to use client javascript libraries provided by your payment -gateway (e.g. ``stripe.js`` or ``braintree-web`` ) to generate a token. +gateway (e.g. `stripe.js` or `braintree-web` ) to generate a token. -Once the token is generated, the request data to send to ``api/checkout/`` is very similar to that for -``api/checkout/prepaid/``: +Once the token is generated, the request data to send to `api/checkout/` is very similar to that for +`api/checkout/prepaid/`: -.. code-block:: json +```json { - token: "...", - shipping_rate: 0.0, - email: "john@smith.com", - address: { - shipping_name: "john smith", - shipping_address_line_1: "...", - shipping_address_city: "", - shipping_address_zip: "", - shipping_address_country: "", - billing_name: "john smith", - billing_address_line_1: "...", - billing_address_city: "", - billing_address_zip: "", - billing_address_country: "", + "token": "...", + "shipping_rate": 0.0, + "email": "john@smith.com", + "address": { + "shipping_name": "john smith", + "shipping_address_line_1": "...", + "shipping_address_city": "", + "shipping_address_zip": "", + "shipping_address_country": "", + "billing_name": "john smith", + "billing_address_line_1": "...", + "billing_address_city": "", + "billing_address_zip": "", + "billing_address_country": "", } } +``` -token - The token for customer details. The key name is dependent on the backend ("token" for stripe, "payment_method_nonce" for braintree) +| Parameter | Description +|:-------------:|------------------ +| token | The token for customer details. The key name is dependent on the backend ("token" for stripe, "payment_method_nonce" for braintree) +| shipping_rate | Number or string representation of a number (will be cast to float). The shipping costs +| email | The customers' email -shipping_rate - Number or string representation of a number (will be cast to float). The shipping costs +> The `"token"` key is dependent upon the payment backend and may be named differently. -email - The customers' email +Both `api/checkout/` and `api/checkout/prepaid/` return a 201 response with `order_id` in the JSON data. +If the payment fails, `api/checkout/` will return a 400 response with `order_id` and `message` in the JSON data. -.. note:: The ``"token"`` key is dependent upon the payment backend and may be named differently. +## Calculating Shipping Costs -Both ``api/checkout/`` and ``api/checkout/prepaid/`` return a 201 response with ``order_id`` in the JSON data. -If the payment fails, ``api/checkout/`` will return a 400 response with ``order_id`` and ``message`` in the JSON data. -Calculating Shipping Costs -========================== - -You will have noticed the need to send ``shipping_rate`` with the checkout. If you are using Longclaws' shipping -settings, you can easily calculate the shipping cost either in python or by using the ``api/shipping/cost/`` endpoint. +You will have noticed the need to send `shipping_rate` with the checkout. If you are using Longclaws' shipping +settings, you can easily calculate the shipping cost either in python or by using the `api/shipping/cost/` endpoint. Python example: -.. code-block:: python +```python from longclaw.shipping import utils from longclaw.configuration.models import Configuration @@ -148,12 +143,13 @@ Python example: # but the supplied option doesnt match any pass except InvalidShippingCountry: - # A shipping rate for this country does not exist and ``default_shipping_enabled`` - # is set to ``False`` in the longclaw admin settings + # A shipping rate for this country does not exist and `default_shipping_enabled` + # is set to `False` in the longclaw admin settings +``` Javascript example: -.. code-block:: javascript +```javascript fetch( "api/shipping/cost/", @@ -170,7 +166,4 @@ Javascript example: }) } ).then(response => {...}) - - - - +``` diff --git a/docs/guide/contrib.md b/docs/guide/contrib.md index 826b2db..a138d4c 100644 --- a/docs/guide/contrib.md +++ b/docs/guide/contrib.md @@ -4,36 +4,36 @@ sidebar_label: Product Requests --- This module allows customers to 'request' products which are otherwise out of stock. -The request date and product variant are stored, with the customer email optionally being stored (The ``ProductRequest`` model +The request date and product variant are stored, with the customer email optionally being stored (The `ProductRequest` model contains a field for this, but template tags by default do not collect this information - it is up to you to store it.) -To install, add it to your ``INSTALLED_APPS`` after other longclaw modules: +To install, add it to your `INSTALLED_APPS` after other longclaw modules: -.. code-block:: python +```python INSTALLED_APPS = ( ..., "longclaw.contrib.productrequests" ) - +``` To show a 'request' button, you can use the following template tag on your product page: -.. code-block:: django +```django {% load productrequests_tags %} {% for variant in page.variants.all %} {% make_request_btn variant_id=variant.id %} {% endfor %} +``` - -You can also pass ``btn_class`` and ``btn_text`` to change the CSS class and text of the resulting ``button`` element. -By default they are ``btn btn-default`` and ``Request Product``. +You can also pass `btn_class` and `btn_text` to change the CSS class and text of the resulting `button` element. +By default they are `btn btn-default` and `Request Product`. This template tag will take care of making the AJAX call to register a request against the product variant. In order to collect further information - i.e the customer email, you will need to create the button and necessary javascript -yourself. You can use the API client function ``requestList`` to post the collected data. +yourself. You can use the API client function `requestList` to post the collected data. You can view all requests in the admin index page for your product collections. When hovering over a product, alongside the usual `Edit`, `View Live` and `Add Child Page` buttons is a new `View Requests` button. This will take you to a page diff --git a/docs/guide/payments.md b/docs/guide/payments.md index eabe2cd..19edcba 100644 --- a/docs/guide/payments.md +++ b/docs/guide/payments.md @@ -3,60 +3,52 @@ title: Payment Backends sidebar_label: Integrations --- -Payment Backends -================== - Longclaw supports payment capture through Stripe, Braintree and Paypal (Using the Braintree VZero SDK). -To select the payment gateway to use, you must specify the ``PAYMENT_GATEWAY`` attribute in your ``settings.py``. +To select the payment gateway to use, you must specify the `PAYMENT_GATEWAY` attribute in your `settings.py`. The options are: -- ``longclaw.checkout.gateways.base.BasePayment``. A do-nothing base implementation -- ``longclaw.checkout.gateways.stripe.StripePayment``. Capture payments using Stripe. -- ``longclaw.checkout.gateways.braintree.BraintreePayment``. Capture payments using Braintree. -- ``longclaw.checkout.gateways.braintree.PaypalVZeroPayment``. Capture Paypal payments using the braintree v.zero SDK. +- `longclaw.checkout.gateways.base.BasePayment`. A do-nothing base implementation +- `longclaw.checkout.gateways.stripe.StripePayment`. Capture payments using Stripe. +- `longclaw.checkout.gateways.braintree.BraintreePayment`. Capture payments using Braintree. +- `longclaw.checkout.gateways.braintree.PaypalVZeroPayment`. Capture Paypal payments using the braintree v.zero SDK. -Additional Settings and dependencies ------------------------------------- +## Additional Settings and dependencies To use payment gateways it is necessary to specify API keys and install client SDK's for the chosen payment provider. -:Stripe: - ``STRIPE_PUBLISHABLE`` - Your public api key - ``STRIPE_SECRET`` - Your secret api key - You will need to install the stripe python sdk (``pip install stripe``) +## Stripe + `STRIPE_PUBLISHABLE` - Your public api key + `STRIPE_SECRET` - Your secret api key + You will need to install the stripe python sdk (`pip install stripe`) -:Braintree: - ``BRAINTREE_MERCHANT_ID`` - Your braintree merchant account ID. - ``BRAINTREE_PUBLIC_KEY`` - Your public api key - ``BRAINTREE_PRIVATE_KEY`` - Your secret api key +## Braintree + `BRAINTREE_MERCHANT_ID` - Your braintree merchant account ID. + `BRAINTREE_PUBLIC_KEY` - Your public api key + `BRAINTREE_PRIVATE_KEY` - Your secret api key -:Paypal: - ``VZERO_ACCESS_TOKEN`` - Your access token for the v.zero SDK. +## Paypal + `VZERO_ACCESS_TOKEN` - Your access token for the v.zero SDK. -Paypal and braintree require the braintree python SDK (``pip install braintree``) +Paypal and braintree require the braintree python SDK (`pip install braintree`) - -.. _custom-integrations: - -Custom Integrations -=================== +## Custom Integrations To implement your own payment integration, you must implement the payment gateway interface. This is simple: -- Inherit from ``longclaw.checkout.gateways.base.BasePayment`` -- Implement ``create_payment``. This should take a ``request`` object, an ``amount`` and optionally a ``description``. +- Inherit from `longclaw.checkout.gateways.base.BasePayment` +- Implement `create_payment`. This should take a `request` object, an `amount` and optionally a `description`. It should use these to capture the payment using your chosen provider. For examples see the implementations in - ``longclaw.checkout.gateways`` -- Implement the ``get_token`` method. This method should generate tokens used by the payment provider. It accepts a ``request`` - object containing post data (``request.data``). Tokens returned may represent different things depending on the + `longclaw.checkout.gateways` +- Implement the `get_token` method. This method should generate tokens used by the payment provider. It accepts a `request` + object containing post data (`request.data`). Tokens returned may represent different things depending on the payment provider - e.g. it may be used to tokenize payment details or generate authentication tokens. You can define your own requirements for the request data to be submitted to the functions. -``create_payment`` is called in a POST request to the ``checkout/`` api. ``get_token`` is similarly called -in a POST request to the ``checkout/token/`` api. +`create_payment` is called in a POST request to the `checkout/` api. `get_token` is similarly called +in a POST request to the `checkout/token/` api. Longclaw aims to be as minimal as possible in order to get the job done. This is why longclaw currently only offers the barest minimum support necessary to directly create payments with the backend payment provider. \ No newline at end of file diff --git a/docs/tutorial/checkout.md b/docs/tutorial/checkout.md index 6bf4e79..628f496 100644 --- a/docs/tutorial/checkout.md +++ b/docs/tutorial/checkout.md @@ -3,59 +3,55 @@ title: Configuring Payment sidebar_label: Payment --- - -Checkout with Braintree -============================ - Longclaw offers integration with a few payment gateways and it is also fairly easy to integrate your own. For this tutorial, we will use Braintree to process payments. -Settings and Dependencies -------------------------- +## Settings and Dependencies + The payment gateway to use must be set in the settings file: -.. code-block:: python - - PAYMENT_GATEWAY = 'longclaw.checkout.gateways.braintree.BraintreePayment' +```python +PAYMENT_GATEWAY = 'longclaw.checkout.gateways.braintree.BraintreePayment' +``` We also need to define settings for access tokens; -.. code-block:: python - +```python BRAINTREE_SANDBOX = False BRAINTREE_MERCHANT_ID = os.environ['BRAINTREE_MERCHANT_ID'] BRAINTREE_PUBLIC_KEY = os.environ['BRAINTREE_PUBLIC_KEY'] BRAINTREE_PRIVATE_KEY = os.environ['BRAINTREE_PRIVATE_KEY'] +``` -We will need to install this SDK as it is not an explicit dependency of longclaw:: +We will need to install this SDK as it is not an explicit dependency of longclaw: - pip install braintree +```bash +pip install braintree +``` That is all we need to do to configure our backend! -Front end integration ---------------------- +## Front end integration We will first show how to setup a checkout page using the Checkout view provided by longclaw. -The code shown here is very similar to the implementation of the checkout page here: `Ramshackle Audio`_ +The code shown here is very similar to the implementation of the checkout page here: [Ramshackle Audio](https://github.com/JamesRamm/ramshacklerecording) First, we should load some templatetags which will help us: -.. code-block:: django +```django +{% load longclawcheckout_tags longclawcore_tags %} +``` - {% load longclawcheckout_tags longclawcore_tags %} - -As an aside - you may wish to display the items in the basket on our checkout page. The basket items queryset is available as ``basket`` +As an aside - you may wish to display the items in the basket on our checkout page. The basket items queryset is available as `basket` in the views' context. Next, we need to setup the forms to gather customer information. There are 2 forms in the context. We will display and submit them as a single form. Here is an example layout: -.. code-block:: django - -
+```django + {% csrf_token %} {% for field in shipping_form %} {% if field.is_hidden %} @@ -96,20 +92,21 @@ display and submit them as a single form. Here is an example layout: {% endif %} {% endfor %} +``` -You may wish to layout the form differently. We have purposefully ignored the ``different_billing_address`` field +You may wish to layout the form differently. We have purposefully ignored the `different_billing_address` field since the Braintree dropin-ui will collect a billing postcode anyway, for its' own security checks. Before we close our `` element, there are 3 further items to add: -.. code-block:: django - - - -

Payment Details

-
- -
+```django + + +

Payment Details

+
+ + +``` We add a hidden field. This field will contain a token (string of characters) given by braintree which represents the payment method. Most payment gateways require something like this, although the name of the field will change between backends. @@ -120,16 +117,14 @@ most integrations offer some sort of 'dropin' which are increasingly customisabl Finally, we add a submit button. -The Javascript -*************** +### The Javascript OK, so now we have hidden elements, empty containers....we need to get this stuff populated! Each payment gateway integration provides the necessary javascript libraries to interact with the gateway. They are made available via a template tag. Add them like this: -.. code-block:: django - +```django {{ checkout_form.media }} +``` The checkout form also provides a little javascript to initialise shipping options (when the user selects a shipping country). Finally, we need to add a little of our own javascript to create the braintree dropin: -.. code-block:: django - +```django +``` Two things are happening in the above code. First, we initialise the shipping options. Note we are using a template tag to pass the longclaw API url prefix, since this is customisable in your settings.py Secondly, we initialise the braintree dropin. Again, we use a template tag to get a token for the gateway. -All payment backends provide the ``gateway_token`` template tag, although it is not always necessary. +All payment backends provide the `gateway_token` template tag, although it is not always necessary. You may wish to only show the braintree payment form if the user has anything in their basket. In which case you might qualify the above javascript with ``{% if basket.count > 0 %}`` in your template. @@ -199,8 +195,8 @@ for v0.2, but welcome any suggestions on how to make it easier! If you wish to forego the templatetags & forms (e.g. if making a fully React-based frontend), read on. Otherwise, that is the end of the tutorial! -Javascript-Only integration ----------------------------- +## Javascript-Only integration + Below is a walkthrough of integrating a payment gateway (PayPal) without the aid of templatetags etc.. @@ -219,21 +215,19 @@ We therefore have three things we need to do in our client-side javascript: 1. Call the longclaw API to generate a token -.. code-block:: javascript - - $.get({ - url: 'api/checkout/token/', - success: function(response){ - ... - } - }) - -2. Following this, configure the paypal express checkout functionality. This actually has two steps. +```javascript +$.get({ +url: 'api/checkout/token/', +success: function(response){ + ... +} +}) +``` +1. Following this, configure the paypal express checkout functionality. This actually has two steps. We must first create a braintree `client` using our new token. We then use this to create a braintree `paypal` instance. -.. code-block:: javascript - +```javascript braintree.client.create({ authorization: token }, (err, client) => { @@ -251,14 +245,14 @@ We therefore have three things we need to do in our client-side javascript: console.log("Paypal instance": paypalInstance); }); }); +``` -3. Once paypal has created the `nonce` for the entered payment details, we must submit this +1. Once paypal has created the `nonce` for the entered payment details, we must submit this to our server so longclaw can capture the payment. To do this, we must have a button which we want to use to launch the paypal express checkout window. We 'attach' the paypal instance we just created to the button like so: -.. code-block:: javascript - +```javascript paypalButton.addEventListener( 'click', function (){ @@ -279,14 +273,13 @@ We therefore have three things we need to do in our client-side javascript: } }); }); - +``` In this example `paypalButton` is a DOM node referring to the button element we wish to attach paypal to and ``handleSubmit`` is a function which will actually POST the payload to the longclaw api endpoint (``api/checkout/``) We can make all these nested API calls simpler if we use ES6 Promises and the fetch API: -.. code-block:: javascript - +```javascript // Wrap braintree js functions as promises function braintreeClientCreate(token){ return new Promise(function(resolve, reject){ @@ -414,6 +407,7 @@ We can make all these nested API calls simpler if we use ES6 Promises and the fe function parseJSON(response) { return response.json(); } +``` The total amount, shipping address, shipping rate and email address of the customer are passed into the setup function; it is up to the front end developer to create the necessary forms to gather these. diff --git a/docs/tutorial/frontend.md b/docs/tutorial/frontend.md index b8a88d1..087d898 100644 --- a/docs/tutorial/frontend.md +++ b/docs/tutorial/frontend.md @@ -10,16 +10,20 @@ Now we have created products and configured our shipping, we can start thinking Longclaw provides a REST API endpoint for retrieving basket data and a django view. -To use the django view, we must provide a template titled ``basket/basket.html``. -It is common to provide a link to the basket page in the header. We can use the ``url`` tag in -our site header to provide the link:: +To use the django view, we must provide a template titled `basket/basket.html`. +It is common to provide a link to the basket page in the header. We can use the `url` tag in +our site header to provide the link: - {% url 'longclaw-basket' %} +``` +{% url 'longclaw-basket' %} +``` -In the basket template, we have access to all basket items under the ``basket`` context:: +In the basket template, we have access to all basket items under the `basket` context: - {% for item in basket %} - ... - {% endfor %} +``` +{% for item in basket %} +... +{% endfor %} +``` -For the full implementation of the basket template, take a look at the `longclaw demo repository `_ +For the full implementation of the basket template, take a look at the [longclaw demo repository](https://github.com/JamesRamm/longclaw_demo/blob/master/longclaw_demo/templates/basket/basket.html) diff --git a/docs/tutorial/products.md b/docs/tutorial/products.md index 7a7088b..d22622f 100644 --- a/docs/tutorial/products.md +++ b/docs/tutorial/products.md @@ -6,119 +6,115 @@ sidebar_label: Adding Products Longclaw makes as few assumptions as possible when it comes to modelling your products, since the requirements of different shops can be wide and varied. -It is required that you create a ``ProductVariant`` model (it can be called anything) and implement +It is required that you create a `ProductVariant` model (it can be called anything) and implement a small number of fields Longclaw expects. -The easiest way to do this is by inheriting from ``longclaw.products.ProductVariantBase``. -Longclaws' project template will have setup a ``products`` app for you, with a ``ProductVariant`` model. +The easiest way to do this is by inheriting from `longclaw.products.ProductVariantBase`. +Longclaws' project template will have setup a `products` app for you, with a `ProductVariant` model. -You will also notice that the settings file has ``PRODUCT_VARIANT_MODEL`` set to the ``ProductVariant`` model. +You will also notice that the settings file has `PRODUCT_VARIANT_MODEL` set to the `ProductVariant` model. -The project template has also created a ``ProductIndex`` and ``Product`` model. -``Product`` is a regular Wagtail ``Page`` which ``ProductVariant`` is an line model of. +The project template has also created a `ProductIndex` and `Product` model. +`Product` is a regular Wagtail `Page` which `ProductVariant` is an line model of. -.. note:: - - This is just one way of modelling yor catalogue but you are not bound to it. ``ProductVariant`` is the only model +> This is just one way of modelling yor catalogue but you are not bound to it. `ProductVariant` is the only model required by Longclaw and precisely what this represents is up to your (e.g. it could be the product itself, or, as the name suggests, a variant of a product). You could create multiple 'index' pages, perhaps representing different lines - aswell as multiple 'product' type pages, or do away with ``Product`` completely. + aswell as multiple 'product' type pages, or do away with `Product` completely. -Creating the Product Index --------------------------- -Wagtails' ``Page`` models are organized in a tree structure. All our ``Product`` pages will therefore -need a parent. This is provided by the ``ProductIndex`` model. +## Creating the Product Index -.. note:: - Read more about Wagtail pages in the `Wagtail docs `_ +Wagtails' `Page` models are organized in a tree structure. All our `Product` pages will therefore +need a parent. This is provided by the `ProductIndex` model. + +> Read more about Wagtail pages in the [Wagtail docs](http://docs.wagtail.io/en/v1.9/topics/pages.html) To add a product index page: - Navigate to the admin and log in - Select the homepage from the explorer menu -- Select ``add child page`` -- Select ``Product index`` and enter the title (e.g. `Products`) +- Select `add child page` +- Select `Product index` and enter the title (e.g. `Products`) - .. figure:: ../_static/images/product_index.png +![Image of the product list](assets/product_index.png) -We can now add ``Product`` models as children of ``ProductIndex``. Only pages of type ``Product`` can be created under ``ProductIndex``. +We can now add `Product` models as children of `ProductIndex`. Only pages of type `Product` can be created under `ProductIndex`. -Adding a Product ----------------- +### Adding a Product -Under the explorer homepage, we should now see our newly created ``ProductIndex``. We can select ``Add child page`` to add our first -``Product``. The ``Product`` model is fairly minimal. It has: + +Under the explorer homepage, we should now see our newly created `ProductIndex`. We can select `Add child page` to add our first +`Product`. The `Product` model is fairly minimal. It has: - A title - A description -- One or more ``ProductVariant``s +- One or more `ProductVariant`s - Optionally some images and tags - .. figure:: ../_static/images/product.png +![Image of the product](assets/product.png) -Customising ------------- -As mentioned above, we can customise the ``ProductIndex`` and ``Product`` model completely - they -are not strict requirements for longclaw to operate. We reccomend using something similar to -the project layout so that ``Product``'s will appear in the Wagtail admin page explorer. +### Customising -``ProductVariant`` can be customised, as long as we inherit from ``ProductVariantBase`` in order to ensure +As mentioned above, we can customise the `ProductIndex` and `Product` model completely - they +are not strict requirements for longclaw to operate. We recommend using something similar to +the project layout so that `Product`'s will appear in the Wagtail admin page explorer. + +`ProductVariant` can be customised, as long as we inherit from `ProductVariantBase` in order to ensure the fields longclaw expects are present. -``ProductVariantBase`` provides the ``price``, ``ref`` and ``slug`` fields. +`ProductVariantBase` provides the `price`, `ref` and `slug` fields. -The ``ref`` field is intended to be used as a short description or sub-title to help distinguish a particular variant. -The ``slug`` field is autogenerated from the ``ref`` and the parent ``Product`` title. +The `ref` field is intended to be used as a short description or sub-title to help distinguish a particular variant. +The `slug` field is autogenerated from the `ref` and the parent `Product` title. -As we are creating a music shop, we are going to add a ``music_format`` field to the model. We will also -remove the ``description`` field as we dont have any real need for it at the moment: +As we are creating a music shop, we are going to add a `music_format` field to the model. We will also +remove the `description` field as we dont have any real need for it at the moment: -.. code-block:: python +```python +class ProductVariant(ProductVariantBase): + _MUSIC_FORMAT_CHOICES = ( + (1, 'CD'), + (2, 'Vinyl'), + ) - class ProductVariant(ProductVariantBase): - _MUSIC_FORMAT_CHOICES = ( - (1, 'CD'), - (2, 'Vinyl'), - ) - - music_format = models.IntegerField(max_length=3, choices=_MUSIC_FORMAT_CHOICES) + music_format = models.IntegerField(max_length=3, choices=_MUSIC_FORMAT_CHOICES) +``` After making and running migrations, we can now select the format for each variant: - .. figure:: ../_static/images/product_variant.png +![Product variant](assets/product_variant.png) -The actual model used for the product variant can be changed by changing the ``PRODUCT_VARIANT_MODEL`` setting in your ``settings.py`` +The actual model used for the product variant can be changed by changing the `PRODUCT_VARIANT_MODEL` setting in your `settings.py` -Creating the Front End -======================= +## Creating the Front End -Since ``ProductIndex`` and ``Product`` are Wagtail pages, we write templates for them just like any other page. -The Wagtail documentation already comprehensively covers `writing templates `_. -Our template project already has some basic templates for ``ProductIndex`` and ``Product``: +Since `ProductIndex` and `Product` are Wagtail pages, we write templates for them just like any other page. +The Wagtail documentation already comprehensively covers [writing templates](http://docs.wagtail.io/en/v1.9/topics/writing_templates.html). -- ``my_shop/my_shop/templates/products/product_index.html`` -- ``my_shop/my_shop/templates/products/product.html`` +Our template project already has some basic templates for `ProductIndex` and `Product`: + +- `my_shop/my_shop/templates/products/product_index.html` +- `my_shop/my_shop/templates/products/product.html` They contain just enough information to demonstrate how to traverse the products and their fields. -For a more complete template, take a look at the `demo project `_. +For a more complete template, take a look at the [demo project](https://github.com/JamesRamm/longclaw_demo). -Adding Products to the Basket ------------------------------ +### Adding Products to the Basket -Longclaw offers a helpful template tag to create an ``Add To Basket`` button for your products. -In your template, load the basket tags:: -.. code-block:: django +Longclaw offers a helpful template tag to create an `Add To Basket` button for your products. +In your template, load the basket tags: +```django {% load basket_tags %} +``` You can now use the tag to render a button for each product variant: -.. code-block:: django - +```django {% add_to_basket_btn variant.id btn_text="Add To Basket" btn_class="btn btn-default" %} - +``` If you wish to create a button manually, you can handle the click event by making an AJAX call to the longclaw API. Situations where you would prefer this over the tempaltetag might be to support non-button elements, such as @@ -127,8 +123,7 @@ dropdown buttons, or for React-based frontends. Here is an example with a single button whose 'variant id' will change depending on the selection in a dropdown box. We can acheive the drop down like this: -.. code-block:: django - +```django
Format
@@ -141,16 +136,18 @@ We can acheive the drop down like this:
+``` Add a button: -.. code-block:: django +```django +``` We can then write a jquery function to handle the click event: -.. code-block:: javascript +```javascript $('#add-button').click(function () { // Selected variant @@ -159,8 +156,9 @@ We can then write a jquery function to handle the click event: // Add to the basket $.post("api/add_to_basket/", { variant_id: variant_id }); }); +``` This is a basic example of integrating with the basket. You will likely need to incorporate more complex designs such as displaying a count of items in the basket, allowing the user to increase/decrease -quantity and so on. The :ref:`basket API ` allows all such interactions and all front end design decisions such as these are left up to the developer. +quantity and so on. The [basket API](#basket) allows all such interactions and all front end design decisions such as these are left up to the developer. It is worthwhile looking at the longclaw demo source code to see how e.g. a basket & item count in the page header is implemented. diff --git a/docs/tutorial/shipping.md b/docs/tutorial/shipping.md index 8b871f4..1d84feb 100644 --- a/docs/tutorial/shipping.md +++ b/docs/tutorial/shipping.md @@ -3,50 +3,44 @@ title: Configuring Shipping sidebar_label: Shipping --- -Configuring Shipping -==================== - Now we can display products and add them to the basket, we must configure our shipping rates before setting up the checkout process. -Per Country Rates ------------------- +## Per Country Rates -Shipping rates are set on a per-country basis via the ``Shipping`` page in the wagtail admin. + +Shipping rates are set on a per-country basis via the `Shipping` page in the wagtail admin. Initially, no countries will be available - Longclaw comes with a set of country data which can be loaded into the database -using the ``loadcountries`` command: +using the `loadcountries` command: - .. code-block:: bash - +```bash python manage.py loadcountries - +``` In the image below, we set a standard rate for the UK. It is possible to select multiple countries for a rate to apply to. We can also create more than one shipping rate for the same country. - .. figure:: ../_static/images/shipping.png +![Shipping](assets/shipping.png) -Default Shipping Rate ---------------------- +## Default Shipping Rate We can configure a default shipping rate to apply to all countries we have not explicitly specified. -.. note:: By enabling default shipping, you imply that you ship to *all* countries. If you do not wish this +> By enabling default shipping, you imply that you ship to *all* countries. If you do not wish this you should *not* enable default shipping. To enable default shipping: -- Select ``settings`` from the wagtail admin menu -- Select ``Longclaw Settings`` -- Fill in ``Default Shipping Rate`` and ``Default Shipping Carrier`` -- Ensure ``Enable Default Shipping`` is checked. +- Select `settings` from the wagtail admin menu +- Select `Longclaw Settings` +- Fill in `Default Shipping Rate` and `Default Shipping Carrier` +- Ensure `Enable Default Shipping` is checked. - .. figure:: ../_static/images/default_shipping.png +![Default shipping](assets/default_shipping.png) -Currency -******** +### Currency -You can also define the currency in ``Longclaw Settings``. This applies site wide. It is mostly semantic - +You can also define the currency in `Longclaw Settings`. This applies site wide. It is mostly semantic - Longclaw assumes all calculations & prices are in the same currency - however some payment gateways require the currency to be specified. diff --git a/website/siteConfig.js b/website/siteConfig.js index a95641b..5f6338b 100755 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -77,7 +77,7 @@ const siteConfig = { highlight: { // Highlight.js theme to use for syntax highlighting in code blocks. - theme: 'default', + theme: 'atom-one-dark', }, // Add custom scripts here that would be placed in