Source code for shoop.core.models._service_payment

# -*- coding: utf-8 -*-
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals, with_statement

from django.db import models
from django.http.response import HttpResponseRedirect
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from parler.models import TranslatedFields

from ._order_lines import OrderLineType
from ._orders import Order, PaymentStatus
from ._service_base import Service, ServiceChoice, ServiceProvider
from ._service_behavior import (
    RoundingBehaviorComponent, StaffOnlyBehaviorComponent
)


class PaymentMethod(Service):
    payment_processor = models.ForeignKey(
        "PaymentProcessor", null=True, blank=True, on_delete=models.SET_NULL,
        verbose_name=_("payment processor"))

    translations = TranslatedFields(
        name=models.CharField(max_length=100, verbose_name=_("name")),
        description=models.CharField(
            max_length=500, blank=True, verbose_name=_("description")),
    )

    line_type = OrderLineType.PAYMENT
    provider_attr = 'payment_processor'
    shop_product_m2m = "payment_methods"

    class Meta:
        verbose_name = _("payment method")
        verbose_name_plural = _("payment methods")

[docs] def can_delete(self): return not Order.objects.filter(payment_method=self).exists()
[docs] def get_payment_process_response(self, order, urls): self._make_sure_is_usable() return self.provider.get_payment_process_response(self, order, urls)
[docs] def process_payment_return_request(self, order, request): self._make_sure_is_usable() self.provider.process_payment_return_request(self, order, request)
class PaymentProcessor(ServiceProvider): """ Service provider interface for payment processing. Services provided by a payment processor are `payment methods <PaymentMethod>`. To create a new payment method for a payment processor, use the `create_service` method. Implementers of this interface will provide provide a list of payment service choices and each related payment method should have one of those service choices assigned to it. Payment processing is handled with `get_payment_process_response` and `process_payment_return_request` methods. Note: `PaymentProcessor` objects should never be created on their own but rather through a concrete subclass. """ service_model = PaymentMethod
[docs] def delete(self, *args, **kwargs): PaymentMethod.objects.filter(payment_processor=self).update(**{"enabled": False}) super(PaymentProcessor, self).delete(*args, **kwargs)
[docs] def get_payment_process_response(self, service, order, urls): """ Get payment process response for given order. :type service: shoop.core.models.PaymentMethod :type order: shoop.core.models.Order :type urls: PaymentUrls :rtype: django.http.HttpResponse|None """ return HttpResponseRedirect(urls.return_url)
[docs] def process_payment_return_request(self, service, order, request): """ Process payment return request for given order. Should set ``order.payment_status``. Default implementation just sets it to `~PaymentStatus.DEFERRED` if it is `~PaymentStatus.NOT_PAID`. :type service: shoop.core.models.PaymentMethod :type order: shoop.core.models.Order :type request: django.http.HttpRequest :rtype: None """ if order.payment_status == PaymentStatus.NOT_PAID: order.payment_status = PaymentStatus.DEFERRED order.add_log_entry("Payment status set to deferred by %s" % self) order.save(update_fields=("payment_status",))
def _create_service(self, choice_identifier, **kwargs): return PaymentMethod.objects.create( payment_processor=self, choice_identifier=choice_identifier, **kwargs) class PaymentUrls(object): """ Container for URLs used in payment processing. """ def __init__(self, payment_url, return_url, cancel_url): self.payment_url = payment_url self.return_url = return_url self.cancel_url = cancel_url class CustomPaymentProcessor(PaymentProcessor): """ Payment processor without any integration or special processing. Can be used for payment methods whose payments are processed manually. """ class Meta: verbose_name = _("custom payment processor") verbose_name_plural = _("custom payment processors")
[docs] def get_service_choices(self): return [ ServiceChoice('manual', _("Manually processed payment")), ServiceChoice('cash', _("Cash payment")) ]
def _create_service(self, choice_identifier, **kwargs): service = super(CustomPaymentProcessor, self)._create_service( choice_identifier, **kwargs) if choice_identifier == 'cash': service.behavior_components.add( RoundingBehaviorComponent.objects.create()) service.behavior_components.add( StaffOnlyBehaviorComponent.objects.create()) return service
[docs] def process_payment_return_request(self, service, order, request): if service == 'cash': if not order.is_paid(): order.create_payment( order.taxful_total_price, payment_identifier="Cash-%s" % now().isoformat(), description="Cash Payment" ) super(CustomPaymentProcessor, self).process_payment_return_request(service, order, request)