GithubHelp home page GithubHelp logo

longclawshop / longclaw Goto Github PK

View Code? Open in Web Editor NEW
392.0 392.0 83.0 1.9 MB

A shop for Wagtail CMS

License: MIT License

Makefile 0.66% Python 73.49% HTML 8.66% JavaScript 16.10% Dockerfile 0.06% CSS 0.61% Shell 0.41%
django e-commerce python python-2 python3 shop wagtail wagtail-cms

longclaw's People

Contributors

alexfromvl avatar bensturmfels avatar blake-g avatar bmoe872 avatar david-smejkal avatar dependabot[bot] avatar jamesramm avatar jan-capek avatar jghyllebert avatar michael-borisov avatar nickmoreton avatar patagoniapy avatar purple-skittles avatar pyup-bot avatar samuelm333 avatar sidnetopia avatar thenewguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

longclaw's Issues

Product requests

Description

On my own site (at http://104.236.209.115/) I have functionality to allow customers to request/register interest in products that are out of stock.

It is easily enabled by adding a request_count field to the ProductVariant and adding an api endpoint to augment it.

If there is interest this could be incorporated into longclaw. I would imagine it actually being a separate model so we can record the date of each request (and potentially other fields - user or ip etc..)

Product Reviews

Product review model & API.

Something along the lines of:

class ProductReview(models.Model):
    product = models.ForeignKey('longclawproducts.Product')
    rating = models.IntegerField(max=5)
    comments = models.CharField(max_length=128)

Couple of question to answer:

  • Should it be related to the Product model or ProductVariant model?
  • Should it be created as a separate app (not within longclaw?).
    Off the top of my head, pros of separate app are; it is in keeping with django philosophy, it keeps longclaw simple. Cons are; it is only usable if longclaw is installed anyway (cause of the foreign key) & a separate app may make setup of the whole longclaw system a bit more confusing to users?

Basket view

Provide a general 'basket' view which will provide the current basket items in the context

CSS changes to order detail view

Make the fulfillled/unfulfilled status stand out a bit more & improve spacings in buttons...something like this:

image

(use green for fulfilled orders)

Other changes:

  • Email should be an 'email' link
  • Currency symbol on the prices

Document checkout API

Document the checkout API.

  • Express payments (using javascript to create payments outside of longclaw (i.e. paypal express) then passing the transaction ID to create an order)

  • Endpoint is the same regardless of gateway

  • A payment is authorized & captured in one step

  • an Order containing OrderItem's is created - for both successful and unsuccessful payments (in the case of unsuccessful, the Order status is set to CANCELLED with a status_note stating payment failed

  • After successful payment the basket is destroyed (since the Order now carries all relevant info).

  • create_token endpoint

Shipping address default

Add to default SHIPPING ADDRESS - Goods shall be shipped to the Buyer on Ex–warehouse delivery terms.

The problem is that the shipping address field is mandatory. If there is not a single field, then it's impossible to create an order.

Adding an address will solve the problem of creating test orders.

0.1 Release

This issue is just to decide upon and iron out final details for a 0.1 release.

Ideally I will have the demo site fully functional before releasing, though I am hoping to be not more than 1 week away.

A few things that need ironing out:

  • Would be great if there is anyone out there willing to have a look through the docs and raise issues against anything missing/nonsensical

  • Docs need updating to reflect that longclaw can be installed from pypi (and the assets wont need building).

  • Build and upload to pypi (I'll do this)

  • Tag the master branch with the 0.1 release

  • Any other requirements for a 0.1 release?

Dummy payment backend

A dummy payment backend that requires no account with stripe/braintree/paypal would be useful for testing.

Address setup issues

Dependencies need properly documenting, as mentioned in #4.
Streamlining the process of setting up longclaw also needs to be addressed.

There are a few things to consider:

  • requirements.txt vs Pipfile vs setup.py. Longclaw is currently setup with requirements.txt, although this doesnt automatically get run when using setup.py. Wagtail itself seems to prefer listing dependencies entirely in in setup.py. Using a 'Pipfile', particularly with 'pipenv' is a growing, moden approach and I would certainly be in favour of exploring it.

  • Optional dependencies. Some libraries like stripe, braintree are required only if chosen as the payment backend. Need to properly document this

  • Get travis actually installing/running something to verify that the setup works & all dependencies are pulled in.

  • Consider providing a CLI to setup a project like in wagtail. Essentially this would run the wagtail setup and plonk longclaw into it (INSTALLED_APPS and urls.py). We can also setup a products app since I imagine 90% of users will want to customise the very basic ProductVariant model. @alexfromvl has already provided example templates in the project_template directory which can be expanded to include this.

  • We could consider exporting all the app names to a single LONGCLAW_APPS variable, so a user can do INSTALLED_APPS += LONGCLAW_APPS...this I believe is what django-oscar does. It may help since many of the apps are interdependent.

  • Consider doing the same thing for urls - perhaps a longclaw.urls file which gathers the urls from individual apps

Checkout and basket templates

The checkout and basket apps are currently written as a REST api, the primary motivation being that it allows total customisation of how you integrate it into your website (I was thinking react apps and nice popup modals for easy checkouts).

It would also be useful to provide generic views and templates for separate-page checkouts/basket views.

Allow 'express' payment integration (paypal)

Paypal (And likely other providers) often have an 'express checkout' service, where all details of payment are handled by paypal and the payment is submitted via javascript.
It would be very useful to support this as an easy way of getting set up.

Since paypal handles the payment, this will require an api endpoint which will accept the completed transaction id and create the order (i.e. capture_payment without any payment handling!)

This endpoint should also accept the shipping address ID as this will have to be created separately.

  • Address creation API (should return ID of created object)
  • Ensure there is an API for calculating postage costs
  • Order creation API for pre-created payments

GraphQL API

Exposing a graphql API (using graphene) would be useful and make for a richer experience when making react-based apps.
I think it should be optional (enabled in the settings) so that extra dependencies are are only required if it is enabled.

Client side JS library for the rest API

Description

In my own project, I have created a small JS file to call all the longclaw API endpoints:

/**
 * Helper functions to be used when making requests to the api.
 */
import JsCookie from 'js-cookie';
import fetch from 'isomorphic-fetch';

/**
 * Check the response status and raise an error if it's no good.
 * @param {object} response - the http response object as provided by fetch
 * @returns {object} - the http rsponse object or throws an error
 */
function checkStatus(response) {
  if (response.ok) {
    return response;
  }
  return response.json().then(json => {
    const error = new Error(response.statusText)
    throw Object.assign(error, { response, json })
  })
}

/**
 * Return an object given an http json response
 * @param {object} response - json encoded response object as provided by fetch
 * @returns {object} - The parsed json
 */
function parseJSON(response) {
  return response.json();
}


/**
 * Return the headers needed for put, post and delete requests
 * @returns {{Accept: string, Content-Type: string, X-CSRFToken: *}}
 */
function getRequestHeaders(form = false) {
  let contentType = 'application/json';
  const headers = {
    Accept: 'application/json, application/json, application/coreapi+json',
    
  };
  if (!form) headers['Content-Type'] = contentType;
  const csrf = JsCookie.get('csrftoken');
  if (csrf) headers['X-CSRFToken'] = csrf;
  return headers;
}

function get(url) {
  return fetch(
    url,
    {
      method: 'GET',
      headers: getRequestHeaders(),
      credentials: 'include'    }
  )
    .then(checkStatus)
    .then(parseJSON);
}

function post(url, data, isForm = false) {
  return fetch(
    url,
    {
      method: 'POST',
      headers: getRequestHeaders(isForm),
      credentials: 'include',
      body: isForm ? data : JSON.stringify(data)
    }
  )
    .then(checkStatus)
    .then(parseJSON);
}

function del(url, data, isForm = false) {
  return fetch(
    url,
    {
      method: 'DELETE',
      headers: getRequestHeaders(isForm),
      credentials: 'include',
      body: isForm ? data : JSON.stringify(data)
    }
  )
    .then(checkStatus)
    .then(parseJSON);
}

// ===================================================== //
//       Public functions                            //

export function getShipping(country_code, shipping_option='standard'){
  return get(`/api/shipping/cost/?country_code=${country_code}&shipping_option=${shipping_option}`, {country_code, shipping_option})
}

export function getShippingCountries() {
  return get('/api/shipping/countries/');
}

/*
 * data:
 *  data.amount: Amount (in GBP) to be paid
 *  data.shipping: Amount (in GBP) of shipping cost
 *  data.address.shipping: Object containing shipping address
 *  data.address.billing: Object containing billing address
 *  data.ip: IP address of client
 *  data.email: Email address of client
 *  data.payment_method_nonce: Stripe token of client card
 * 
 */
export function checkout(data){
  return post('/api/checkout/', data)
}
export function getToken(){
  return get('/api/checkout/token/');
}
export function getBasket() {
  return get("/api/basket/");
}

export function addToBasket(variant_id){
  return post('/api/basket/', {variant_id});
}

export function removeFromBasket(variant_id, quantity){
  return del(`/api/basket/${variant_id}/`, {quantity});
}

export function getTotalItems(){
  return get('/api/basket/count/');
}

export function requestProduct(variant_id){
  return post(`/api/basket/${variant_id}/request/`, {})
}

this makes it much easier to interact with longclaw throughout the javascript code and/or create e.g. react front ends.
I.e fetching all the basket items becomes fetchBasket().then(response => console.log("Handle the returned data!"))

Could be useful to have this as a lib in the longclaw source code and either:

  • Distribute it separately via npm
  • Build it along with the other longclaw assets (used in the backend) and provide a template tag to load it

Better URL naming

URL names (for resolving with reverse) should be prefixed with longclaw to make them unique. There are other things that can be done with URL namespacing...but this is simple and consistent.

I.e. A few names currently in use are basket, checkout and orders. These would be renamed to longclaw-basket, longclaw-checkout and longclaw-orders

Fix travis build

travis.yml is just the default file created by cookiecutter atm. It needs fixing to get the travis build working.

Order payment_date should not be auto now

The payment_date field on an Order is automatically filled whenever the order is created. This is misleading since Order objects are created for failed payments.
We should:

  • change payment_date to not be auto filled & only fill it when payment successfully goes through.
  • add a creation_date field which is auto filled.

ShippingCountry should not be a page

A ShippingCountry is currently a Page; it should just be a regular model since it is not strictly 'content', more of a setting. The admin interface can be a little confusing & crowded with multiple shipping countries.

Communication

What do you think about having an IRC Channel for communication amongst developers. There has been a few things i wanted to ask @JamesRamm, but don't feel its worth filing an issue. Doesn't have to be IRC of course, Slack, Mattermost or email but im sure wed all rather not have any more email coming in.

Orders template

Orders are viewable in the wagtail admin, but it is not particularly useful atm.
We could customise the admin template to allow:

  • A button to fufill orders
  • Full view of foreign key relationships (i.e. shipping address)

Need to limit django version to <1.11

  • longclaw version: 0.1

Description

pip install longclaw will end up installing django 1.11 (if django is not already installed). Wagtail doesnt support this yet and will end up throwing an error.
Need to specify Django>=1.8,<1.11 in setup.py

Email upon order

Setup email system to allow:

  • email notifications upon order (to admin)
  • email receipt/summary to customer upon order
  • email upon fulfillment

Payment tests

Tests are needed for the checkout api.

Specifically:

  • create_order in utils
  • create_order_with_token api function
  • capture_payment api function, using the BasePayment gateway initially (and ideally with some 'real' gateway)

Payment Form

Useful forms/widgets for the checkout process:

  • A 'country' field which only allows selection of countries which have shipping rates, or all countries if DEFAULT_SHIPPING_ENABLED is True

  • A general address form for shipping

  • a general payment form

Checkout View

Background

In creating the longclaw-demo site, one of the most fiddly parts with working with longclaw is the whole basket/checkout process.
I think a priority for 0.2.0 is making this simpler and minimising the amount of javascript a user needs to write to get it going (while still leaving the door fully open for custom front ends (react etc)).

Description

Create a view for the checkout. #2 and #50 already deal with some elements which will be useful for this view.
The view should provide the basket contents (like the basket view) and address form

Docs

Docs and hosting on readthedocs

shipping api broken

  • longclaw version: master (0.1.0)
  • Django version: 1.9
  • Python version: 3.5
  • Operating System: Linux

Description

due to changes to use django_countries, shipping_cost endpoint now returns:

django.core.exceptions.FieldError: Cannot resolve keyword 'country' into field. Choices are: carrier, countries, description, id, name, rate

Development project?

Developing longclaw requires setting a django project wagtail to run longclaw within...I wonder if we can make it simpler to setup for development by providing a dev project in the repo somehow?

Are there any django app development guidelines on this?

Failing build

Build is currently failing against Django 1.10 due to an issue in wagtail: wagtail/wagtail#3526

Options:

  • Suspend testing against Django 1.10 until a next release of wagtail
  • Rollback wagtail requirements to 1.7 (I don't recall this being a problem in the previous version)

Address should be a snippet

I think the Address model should be a wagtail snippet.
This will allow manual entry of addresses from the wagtail admin (thereby providing a solution to #42 while still allow future expansion into Customer models). The order model would be changed to have a SnippetChooserPanel for the billing & shipping address

We can then also make addresses searchable, we could be useful when there is a large number of customers.

This is a small but useful change, so I think it could be snuck in for 0.1

Basket api

  • longclaw version: 0.1.0
  • Django version: 1.10.6
  • Python version: 3.6.0
  • Operating System: Linux (arch)

Description

Attempting to hack on the basket templates and api but seem to be unable to reach the api urls.

What I Did

I have tried sending POST and GET Requests to the few api commands that i felt i could use without having items in a basket yet. Im getting 404 errors.

from what i can tell the api url is just /api/ so the format of the url i am sending data to is localhost:8000/api/add_to_basket/

I have attached some of the command history from httpie tool

http://localhost:8000/products/> cd pencil/
http://localhost:8000/products/pencil/> get
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Date: Wed, 29 Mar 2017 10:34:40 GMT
Server: WSGIServer/0.2 CPython/3.6.0
Set-Cookie:  csrftoken=ong9dNCJnKzs4X9DwkFDW36jRU5dyGbs45pd6rrCndOBO7qmk4UvPk9xGB2PV8W1; expires=Wed, 28-Mar-2018 10:34:40 GMT; Max-Age=31449600; Path=/
Vary: Cookie
X-Frame-Options: SAMEORIGIN

AttributeError: 'unicode' object has no attribute 'items'

Parse tree:
<Node called "action" matching "get">  <-- *** We were here. ***
    <RegexNode called "_" matching "">
    <Node called "method" matching "get">
        <RegexNode matching "get">
    <RegexNode called "_" matching "">
    <Node matching "">
    <Node matching "">
    <Node matching "">
    <RegexNode called "_" matching "">
http://localhost:8000/products/pencil/> cd /api/add_to_basket/
http://localhost:8000/api/add_to_basket/> X-CSRFToken:ong9dNCJnKzs4X9DwkFDW36jRU5dyGbs45pd6rrCndOBO7qmk4UvPk9xGB2PV8
W1
http://localhost:8000/api/add_to_basket/> post
HTTP/1.0 404 Not Found
Content-Type: text/html
Date: Wed, 29 Mar 2017 10:35:24 GMT
Server: WSGIServer/0.2 CPython/3.6.0
Vary: Cookie
X-Frame-Options: SAMEORIGIN

http://localhost:8000/api/add_to_basket/> 

Decimal in price_range (Product Models)

When you try to display a product page, the price appears (Decimal('100.00'), Decimal('100.00')).
I address the price in the page template via variable {{ page.price_range }}.
What could be the problem? How to output only numbers?

Shipping rates

Improve the current longclaw.checkout.models.ShippingCountry to allow more customisation of shipping rates

Products template

The project to add templates for products and other models.
Given that the products.models is now un fixed, it would be useful to create a template for her demo.

class ProductIndex(Page):
   pass

   def get_context(self, request):
       # Update context to include only published products, ordered by reverse-chron
       context = super(ProductIndex, self).get_context(request)
       product = self.get_children().live().order_by('-first_published_at')
       context['product'] = product
       return context

My example template:
Product_index.html

{% extends "base.html" %}

{% load wagtailcore_tags wagtailimages_tags %}

{% block body_class %}template-productindex{% endblock %}

{% block content %}
<h1>{{ page.title }}</h1>
<div class="row">
{% for post in product %}
   {% with post=post.specific %}
   <div><a href="{% pageurl post %}">
       <div class="caption_news">
           <h4>{{ post.title }}</h4>
           <p>{{ post.description|richtext }}</p>
       </div></a>
   </div>
   {% endwith %}
{% endfor %}
</div>
{% endblock %}

Walkthrough/Tutorial

Some walkthrough documentation would be nice. It should cover:

  • Setting up (installation & settings)
  • Adding products in the admin
  • Customising the product variant model
  • Creating templates for product_index.html and product.html
  • Integration with a payment backend (e.g. paypal)
    • Specifying the settings (Access tokens, which backend to use) & installing the client library
    • Creating a basket template
    • Using paypal express UI to gather shipping & payment details
    • Making the AJAX request to create the payment & order
  • Specifying shipping rates

Basket API more RESTful

Basket API urls are currently:

add_to_basket/
remove_from_basket/
get_basket/
basket_total_items/
get_item_count/

These could be better expressed as:

basket/ - Accepts GET and POST requests (as replacement for get_basket and add_to_basket)
basket/count/ - Accepts GET (basket_total_items)
basket/(?P<variant_id>[0-9]+)/ - Accepts GET and DEL requests (remove_from_basket)
basket/(?P<variant_id>[0-9]+)/count/ - Accepts GET (get_item_count)

Product 'profile'

Description

Longclaw 0.1.0 will offer easy customisation of the product variants, but there is nothing to offer customisation of the base product itself.
There may be situations where we need extra fields which should be the same for all variants (e.g. author or artist fields).

A simple and easy (to the user) way to customise the base product model is required.

I see this being a 0.2.0 release (or later) since such customisation can be achieved through the product variant; it just that it requires unnecessary duplication atm.

Address Form

Separating this from #28
A standard address form (using ModelForm) to aid with capturing addresses.
The country field should be limited to countries which are shipped to (which is dependent upon the DEFAULT_SHIPPING setting).

This may also help with discussion in #42 (although this is a front end component)

Order should store the transaction ID

All payment gateways create some sort of transaction ID related to the payment (on stripe it is the 'Charge ID', on braintree it is the Transaction ID, although the 'Transaction order_id' may be more useful for paypal payments made with braintree...)

This ID should be stored on the Order object so the user can cross reference against their payment account.

Easiest way of supporting this is to simply require the payment gateway interface to return the id in the create_payment method.

Returning some help text specific to the backend would be useful - i.e. what the ID refers to and where it can be found when the user logs into stripe/paypal etc...

Order refunds

Following on from #1, backend & front end functionality needed to provide refunds.

Document basket api

Documentation needed for basket and checkout API.

  • Endpoints (get_basket, add_to_basket, remove_from_basket, get_item_count, total_items)
  • What data is returned (and what request data is accepted)
  • Document that the basket is tied to a session

Move settings to single file

Longclaw settings are currently split between various app_settings files in each app, making it hard to document/see all the settings. They could be moved to a single settings.py file in the root longclaw directory.

Django-payments or continue developing own?

Payments are currently handled in the checkout app. They are:

  • Very loosely coupled. Nothing about the payment is stored in the database, instead trusting the payment backend to keep all relevant details. An new Order instance is created upon successful payment which contains all the order related details (essentially, what products and shipping address)
  • Easily extendable. All that is required is a class implementing the correct interface
  • Supports only Stripe, Braintree and Paypal VZero (through the braintree package)
  • Doesn't support refunds
  • Fairly fragile (needs testing & development).

We could potentially use django-payments as a more mature backend rather than continuing to develop our own, however, this requires a separate db model which most likely duplicates info in the order model and/or stores unnecessary info. It also has fairly low levels of activity but 20 odd outstanding issues...

Document payment backends

Write documentation to describe:

  • Configuring payment backends

    • Available payment backends
    • Selecting a payment backend (in the settings file)
    • Additional settings needed for each backend (i.e. authorisation tokens)
  • Developing new backends

    • BasePayment class
    • Methods that need implementing (create_payment)
    • Philosophy

Project setup CLI

Idea is to provide a CLI, much the same as wagtails' wagtail start my_project but using the longclaw template.

Running django-admin startproject --template ... can be a bother when you need to figure out where the longclaw directory is (especially when using virtual environments)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.