#Volume Directory for docker-compose
mysql/
-diggersdigest/static/media
\ No newline at end of file
+diggersdigest/static/media
FROM python:2.7
ENV PYTHONUNBUFFERED 1
+
RUN apt-get update &&\
apt-get -y install locales && \
echo fr_FR.UTF-8 UTF-8 >> /etc/locale.gen &&\
locale-gen
+
ENV LANG fr_FR.UTF-8
ENV LANGUAGE fr_FR:fr
ENV LC_ALL fr_FR.UTF-8
RUN mkdir /code
+RUN mkdir /opt/src
+
WORKDIR /code
+
ADD requirements.txt /code/
RUN pip install -r requirements.txt
-ADD . /code/
+ADD requirements-dev.txt /code/
+RUN pip install -r requirements-dev.txt --src /opt/src
+
+ADD . /code/
--- /dev/null
+#!/bin/sh
+
+app='diggersdigest'
+
+# paths
+root_dir='/code'
+app_dir=$root_dir'/'$app
+static=$root_dir'/static/'
+sandbox=$app_dir
+manage=$sandbox'/manage.py'
+wsgi=$sandbox'/wsgi.py'
+
+# waiting for other services
+# sh $app_dir/examples/deploy/wait.sh
+
+# django init
+python $manage migrate --noinput
+python $manage collectstatic --noinput
+
+# static files auto update
+#watchmedo shell-command --patterns="*.js;*.css" --recursive \
+# --command='python '$manage' collectstatic --noinput' $static &
+
+# app start
+#uwsgi --socket :8000 --wsgi-file $wsgi --chdir $sandbox --master --processes 4 --threads 2 --py-autoreload 3
+
+python $manage runserver 0.0.0.0:8000
}
}
-#######################
-# FILEBROWSER settings
-#######################
-#
-# Max. Upload Size in Bytes:
-# 10MB - 10485760
-# 20MB - 20971520
-# 50MB - 5242880
-# 100MB 104857600
-# 250MB - 214958080
-# 500MB - 429916160
-FILEBROWSER_MAX_UPLOAD_SIZE = 104857600
-
# EXTENSIONS AND FORMATS
# Allowed Extensions for File Upload. Lower case is important.
FILEBROWSER_EXTENSIONS = {
'audio': ['Audio'],
}
-
-#########
-# Shop
-#########
-
-# Add Migration Module path see : https://github.com/stephenmcd/mezzanine/blob/master/docs/model-customization.rst#field-injection-caveats
-MIGRATION_MODULES = {
- "shop": "diggersdigest.migrations.shop",
- "blog": "diggersdigest.migrations.blog"
-}
-
-# USE or EXTEND the custom callback-uuid form
-SHOP_CHECKOUT_FORM_CLASS = 'payments.multipayments.forms.base.CallbackUUIDOrderForm'
-
-PRIMARY_PAYMENT_PROCESSOR_IN_USE = True
-
-SECONDARY_PAYMENT_PROCESSORS = (
-# ...
-('paypal', {
-'name' : 'Pay With Pay-Pal',
-'form' : 'payments.multipayments.forms.paypal.PaypalSubmissionForm'
-}),
-# ...
-)
-
-# Currency type.
-PAYPAL_CURRENCY = "EUR"
-
-# Business account email. Sandbox emails look like this.
-PAYPAL_BUSINESS = 'pellerin@parisson.com'
-PAYPAL_RECEIVER_EMAIL = PAYPAL_BUSINESS
-
-# Use this to enable https on return URLs. This is strongly recommended! (Except for sandbox)
-PAYPAL_RETURN_WITH_HTTPS = False
-
-# Function that returns args for `reverse`.
-# URL is sent to PayPal as the for returning to a 'complete' landing page.
-PAYPAL_RETURN_URL = lambda cart, uuid, order_form: ('shop_complete', None, None)
-
-# Function that returns args for `reverse`.
-# URL is sent to PayPal as the URL to callback to for PayPal IPN.
-# Set to None if you do not wish to use IPN.
-PAYPAL_IPN_URL = lambda cart, uuid, order_form: ('my_paypal_ipn', None, {'uuid' : uuid})
-
-# URL the secondary-payment-form is submitted to
-# Dev example
-PAYPAL_SUBMIT_URL = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
-# Prod example
-PAYPAL_SUBMIT_URL = 'https://www.paypal.com/cgi-bin/webscr'
-
-# For real use set to False
-PAYPAL_TEST = True
-
###################
# DEPLOY SETTINGS #
###################
from django.utils.translation import ugettext_lazy as _
-######################
-# CARTRIDGE SETTINGS #
-######################
-
-# The following settings are already defined in cartridge.shop.defaults
-# with default values, but are common enough to be put here, commented
-# out, for conveniently overriding. Please consult the settings
-# documentation for a full list of settings Cartridge implements:
-# http://cartridge.jupo.org/configuration.html#default-settings
-
-# Sequence of available credit card types for payment.
-# SHOP_CARD_TYPES = ("Mastercard", "Visa", "Diners", "Amex")
-
-# Setting to turn on featured images for shop categories. Defaults to False.
-# SHOP_CATEGORY_USE_FEATURED_IMAGE = True
-
-# Set an alternative OrderForm class for the checkout process.
-# SHOP_CHECKOUT_FORM_CLASS = 'cartridge.shop.forms.OrderForm'
-
-# If True, the checkout process is split into separate
-# billing/shipping and payment steps.
-# SHOP_CHECKOUT_STEPS_SPLIT = True
-
-# If True, the checkout process has a final confirmation step before
-# completion.
-# SHOP_CHECKOUT_STEPS_CONFIRMATION = True
-
-# Controls the formatting of monetary values accord to the locale
-# module in the python standard library. If an empty string is
-# used, will fall back to the system's locale.
-#SHOP_CURRENCY_LOCALE = ''
-
-# Dotted package path and name of the function that
-# is called on submit of the billing/shipping checkout step. This
-# is where shipping calculation can be performed and set using the
-# function ``cartridge.shop.utils.set_shipping``.
-# SHOP_HANDLER_BILLING_SHIPPING = \
-# "cartridge.shop.checkout.default_billship_handler"
-
-# Dotted package path and name of the function that
-# is called once an order is successful and all of the order
-# object's data has been created. This is where any custom order
-# processing should be implemented.
-# SHOP_HANDLER_ORDER = "cartridge.shop.checkout.default_order_handler"
-
-# Dotted package path and name of the function that
-# is called on submit of the payment checkout step. This is where
-# integration with a payment gateway should be implemented.
-# SHOP_HANDLER_PAYMENT = "cartridge.shop.checkout.default_payment_handler"
-
-# Sequence of value/name pairs for order statuses.
-# SHOP_ORDER_STATUS_CHOICES = (
-# (1, "Unprocessed"),
-# (2, "Processed"),
-# )
-
-# Sequence of value/name pairs for types of product options,
-# eg Size, Colour. NOTE: Increasing the number of these will
-# require database migrations!
-#SHOP_OPTION_TYPE_CHOICES = (
-# (1, "Cover condition"),
-# (2, "Vinyl condition"),
-# )
-
-SHOP_USE_VARIATIONS = False
-
-# Sequence of indexes from the SHOP_OPTION_TYPE_CHOICES setting that
-# control how the options should be ordered in the admin,
-# SHOP_OPTION_ADMIN_ORDER = (1, 2)
-
-SHOP_USE_RATINGS = False
-
######################
# MEZZANINE SETTINGS #
######################
"django.db.models.CharField",
(),
{"blank" : False, "max_length" : 36},
- )
+ ),
# ...
# # Example of adding a field to *all* of Mezzanine's content types:
# (
SEARCH_MODEL_CHOICES = ('shop.Product',)
+
+######################
+# CARTRIDGE SETTINGS #
+######################
+
+# The following settings are already defined in cartridge.shop.defaults
+# with default values, but are common enough to be put here, commented
+# out, for conveniently overriding. Please consult the settings
+# documentation for a full list of settings Cartridge implements:
+# http://cartridge.jupo.org/configuration.html#default-settings
+
+# Sequence of available credit card types for payment.
+# SHOP_CARD_TYPES = ("Mastercard", "Visa", "Diners", "Amex")
+
+# Setting to turn on featured images for shop categories. Defaults to False.
+# SHOP_CATEGORY_USE_FEATURED_IMAGE = True
+
+# Set an alternative OrderForm class for the checkout process.
+# SHOP_CHECKOUT_FORM_CLASS = 'cartridge.shop.forms.OrderForm'
+
+# If True, the checkout process is split into separate
+# billing/shipping and payment steps.
+# SHOP_CHECKOUT_STEPS_SPLIT = True
+
+# If True, the checkout process has a final confirmation step before
+# completion.
+# SHOP_CHECKOUT_STEPS_CONFIRMATION = True
+
+# Controls the formatting of monetary values accord to the locale
+# module in the python standard library. If an empty string is
+# used, will fall back to the system's locale.
+#SHOP_CURRENCY_LOCALE = ''
+
+# Dotted package path and name of the function that
+# is called on submit of the billing/shipping checkout step. This
+# is where shipping calculation can be performed and set using the
+# function ``cartridge.shop.utils.set_shipping``.
+# SHOP_HANDLER_BILLING_SHIPPING = \
+# "cartridge.shop.checkout.default_billship_handler"
+
+# Dotted package path and name of the function that
+# is called once an order is successful and all of the order
+# object's data has been created. This is where any custom order
+# processing should be implemented.
+# SHOP_HANDLER_ORDER = "cartridge.shop.checkout.default_order_handler"
+
+# Dotted package path and name of the function that
+# is called on submit of the payment checkout step. This is where
+# integration with a payment gateway should be implemented.
+# SHOP_HANDLER_PAYMENT = "cartridge.shop.checkout.default_payment_handler"
+
+# Sequence of value/name pairs for order statuses.
+# SHOP_ORDER_STATUS_CHOICES = (
+# (1, "Unprocessed"),
+# (2, "Processed"),
+# )
+
+# Sequence of value/name pairs for types of product options,
+# eg Size, Colour. NOTE: Increasing the number of these will
+# require database migrations!
+#SHOP_OPTION_TYPE_CHOICES = (
+# (1, "Cover condition"),
+# (2, "Vinyl condition"),
+# )
+
+SHOP_USE_VARIATIONS = False
+
+# Sequence of indexes from the SHOP_OPTION_TYPE_CHOICES setting that
+# control how the options should be ordered in the admin,
+# SHOP_OPTION_ADMIN_ORDER = (1, 2)
+
+SHOP_USE_RATINGS = False
+
+# Add Migration Module path see : https://github.com/stephenmcd/mezzanine/blob/master/docs/model-customization.rst#field-injection-caveats
+MIGRATION_MODULES = {
+ "shop": "diggersdigest.migrations.shop",
+ "blog": "diggersdigest.migrations.blog"
+}
+
+# USE or EXTEND the custom callback-uuid form
+SHOP_CHECKOUT_FORM_CLASS = 'payments.multipayments.forms.base.CallbackUUIDOrderForm'
+
+PRIMARY_PAYMENT_PROCESSOR_IN_USE = False
+
+SECONDARY_PAYMENT_PROCESSORS = (
+ ('paypal', {
+ 'name' : 'Pay With Pay-Pal',
+ 'form' : 'payments.multipayments.forms.paypal.PaypalSubmissionForm'
+ }),
+)
+
+
+# Currency type.
+PAYPAL_CURRENCY = "EUR"
+
+# Business account email. Sandbox emails look like this.
+PAYPAL_BUSINESS = 'pellerin@parisson.com'
+PAYPAL_RECEIVER_EMAIL = PAYPAL_BUSINESS
+
+# Use this to enable https on return URLs. This is strongly recommended! (Except for sandbox)
+PAYPAL_RETURN_WITH_HTTPS = False
+
+# Function that returns args for `reverse`.
+# URL is sent to PayPal as the for returning to a 'complete' landing page.
+PAYPAL_RETURN_URL = lambda cart, uuid, order_form: ('shop_complete', None, None)
+
+# Function that returns args for `reverse`.
+# URL is sent to PayPal as the URL to callback to for PayPal IPN.
+# Set to None if you do not wish to use IPN.
+PAYPAL_IPN_URL = lambda cart, uuid, order_form: ('paypal.standard.ipn.views.ipn', None, {})
+
+
+# URL the secondary-payment-form is submitted to
+# Dev example
+PAYPAL_SUBMIT_URL = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
+# Prod example
+# PAYPAL_SUBMIT_URL = 'https://www.paypal.com/cgi-bin/webscr'
+
+# For real use set to False
+PAYPAL_TEST = True
+
########################
# MAIN DJANGO SETTINGS #
########################
+SITE_DOMAIN = 'localhost'
+
# Hosts/domain names that are valid for this site; required if DEBUG is False
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
# ("^%s/" % settings.SITE_PREFIX, include("mezzanine.urls"))
+ (r'^paypal-ipn-8c5erc9ye49ia51rn655mi4xs7/', include('paypal.standard.ipn.urls')),
+
)
# Adds ``STATIC_URL`` to the context of error pages, so that error
import datetime
import os
import fnmatch
+from importlib import import_module
from diggersdigest import settings
+# from mezzanine.conf import settings
from mezzanine.core.fields import FileField
from mezzanine.core.models import CONTENT_STATUS_DRAFT, CONTENT_STATUS_PUBLISHED
from mezzanine.blog.models import BlogPost
from mezzanine.utils.models import upload_to
-from cartridge.shop.models import Product, Category
+from cartridge.shop.models import Product, Category, Cart, Order, ProductVariation, DiscountCode
+from paypal.standard.ipn.signals import payment_was_successful
+from paypal.standard.models import ST_PP_COMPLETED
+from paypal.standard.ipn.signals import valid_ipn_received
# Auto-generated Django models with manage.py inspectdb on the old database
#visu1 = models.IntegerField()
# ordre : on laisse tombé ?
# published --> status / 0 --> CONTENT_STATUS_DRAFT = 1 / 1 CONTENT_STATUS_PUBLISHED = 2
+
+
+def payment_complete(sender, **kwargs):
+ """Performs the same logic as the code in
+ cartridge.shop.models.Order.complete(), but fetches the session,
+ order, and cart objects from storage, rather than relying on the
+ request object being passed in (which it isn't, since this is
+ triggered on PayPal IPN callback)."""
+
+ ipn_obj = sender
+
+ if ipn_obj.custom and ipn_obj.invoice and ipn_obj.payment_status == ST_PP_COMPLETED:
+ s_key, cart_pk = ipn_obj.custom.split(',')
+ SessionStore = import_module(settings.SESSION_ENGINE) \
+ .SessionStore
+ session = SessionStore(s_key)
+
+ try:
+ cart = Cart.objects.get(id=cart_pk)
+ try:
+ order = Order.objects.get(
+ transaction_id=ipn_obj.invoice)
+ for field in order.session_fields:
+ if field in session:
+ del session[field]
+ try:
+ del session["order"]
+ except KeyError:
+ pass
+
+ # Since we're manually changing session data outside of
+ # a normal request, need to force the session object to
+ # save after modifying its data.
+ session.save()
+
+ for item in cart:
+ try:
+ variation = ProductVariation.objects.get(
+ sku=item.sku)
+ except ProductVariation.DoesNotExist:
+ pass
+ else:
+ variation.update_stock(item.quantity * -1)
+ variation.product.actions.purchased()
+
+ code = session.get('discount_code')
+ if code:
+ DiscountCode.objects.active().filter(code=code) \
+ .update(uses_remaining=F('uses_remaining') - 1)
+ cart.delete()
+ except Order.DoesNotExist:
+ pass
+ except Cart.DoesNotExist:
+ pass
+
+payment_was_successful.connect(payment_complete)
+valid_ipn_received.connect(payment_complete)
-{% load i18n mezzanine_tags %}
-<fieldset>
- <legend>{% trans "Payment Details" %}</legend>
- {% fields_for form.card_name_field %}
- {% fields_for form.card_type_field %}
- {% with form.card_expiry_fields as card_expiry_fields %}
- <div class="form-group card-expiry-fields{% if card_expiry_fields.errors.card_expiry_year %} error{% endif %}">
- <label>{% trans "Card Expiry" %}</label>
- {% fields_for card_expiry_fields %}
- </div>
- <div class="clearfix"></div>
- {% endwith %}
- {% fields_for form.card_fields %}
-</fieldset>
+{% load i18n mezzanine_tags multipayment_forms %}
+
+{% if PRIMARY_PAYMENT_PROCESSOR_IN_USE %}
+ <fieldset>
+ <legend>{% trans "Payment Details" %}</legend>
+ {% fields_for form.card_name_field %}
+ {% fields_for form.card_type_field %}
+ {% with form.card_expiry_fields as card_expiry_fields %}
+ <div class="control-group card-expiry-fields{% if card_expiry_fields.errors.card_expiry_year %} error{% endif %}">
+ <label>{% trans "Card Expiry" %}</label>
+ {% fields_for card_expiry_fields %}
+ </div>
+ {% endwith %}
+ {% fields_for form.card_fields %}
+ </fieldset>
+{% endif %}
{% extends "shop/checkout.html" %}
-{% load i18n mezzanine_tags %}
+
+{% load i18n multipayment_forms %}
+
+
+<div class="form-actions clearfix">
+ <div class="form-actions-wrap">
+ <input type="submit" value="Next" class="btn btn-large btn-primary">
+
+ </div>
+ </div>
+
+{% block before-form %}
+ {% if request.cart.has_items %}
+ {% multipayment_forms request form as multipayment_forms %}
+ {% if multipayment_forms %}
+ <div class="form-actions clearfix">
+ <div class="form-actions-wrap">
+ {% for name,form in multipayment_forms %}<form method="post" action="{{ form.action }}">
+ {{ form.as_p }}
+ <input type="submit" value="{% trans name %}" class="btn btn-large">
+ </form>{% endfor %}
+ </div>
+ </div>
+ {% endif %}
+ {% endif %}
+{% endblock %}
{% block fields %}
-{% if request.cart.has_items %}
-{% errors_for form %}
-{% include "shop/includes/payment_fields.html" %}
-{% fields_for form.other_fields %}
-{% endif %}
+ {% if request.cart.has_items %}
+ {% include "shop/includes/payment_fields.html" %}
+ {% if not PRIMARY_PAYMENT_PROCESSOR_IN_USE %}<div style="display:none">{% endif %}
+ {{ form.other_fields.as_ul }}
+ {% if not PRIMARY_PAYMENT_PROCESSOR_IN_USE %}</div>{% endif %}
+ {% endif %}
{% endblock %}
+
+
+{% block nav-buttons %}
+ {% if request.cart.has_items %}
+ <div class="form-actions clearfix">
+ <div class="form-actions-wrap">
+ {% if PRIMARY_PAYMENT_PROCESSOR_IN_USE %}
+ <input type="submit" class="btn btn-large btn-primary" value="{% trans "Next" %}">
+ {% endif %}
+ {% if not CHECKOUT_STEP_FIRST %}
+ <input type="submit" class="btn btn-large" name="back" value="{% trans "Back" %}">
+ {% endif %}
+ </div>
+ </div>
+ {% else %}
+ {{ block.super }}
+ {% endif %}
+{% endblock %}
\ No newline at end of file
command: data only container for db
db:
- image: mysql
+ image: mysql
environment:
- MYSQL_ROOT_PASSWORD=mysecretpassword
- MYSQL_DATABASE=diggersdigest
web:
build: .
- command: python diggersdigest/manage.py runserver 0.0.0.0:8000
+ command: /bin/sh diggersdigest/deploy/start_app.sh
volumes:
- .:/code
ports:
- "8000:8000"
links:
- - db
\ No newline at end of file
+ - db
--- /dev/null
+
+-e git+https://github.com/Parisson/cartridge-payments.git#egg=cartridge-payments
+-e git+https://github.com/Parisson/django-paypal.git#egg=django-paypal-0.2.5
-Django==1.8.3
+--index-url https://pypi.python.org/simple/
+
+setuptools
+Django==1.8.4
MySQL-python==1.2.5
cartridge==0.10.0
-cartridge-payments==0.97.0
-django-paypal==0.2.5
django-uuidfield==0.5.0
django-newsletter==0.5.2
parsedatetime==1.5