diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d3ea22..90407a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.33] - 2023-03-28 + +### Added + +- Temporary remove payments [@AivGitHub](https://github.com/AivGitHub/). + ## [0.0.32] - 2023-03-23 ### Improved diff --git a/accounts/models.py b/accounts/models.py index 683b472..2e4fea2 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -13,10 +13,9 @@ from django.db.models.fields.files import FieldFile from django.template.defaultfilters import filesizeformat from django.utils import timezone -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_lazy as _, pgettext_lazy import magic -from payments import PaymentStatus -from payments.models import BasePayment +from phonenumber_field.modelfields import PhoneNumberField from accounts.dataclasses import SignedURLReturnObject from accounts.enums import SignedURLMethod @@ -679,6 +678,83 @@ def get_payment_hex(): return get_uuid_hex(Payment, 'payment_hex') +class PaymentStatus: + WAITING = 'waiting' + PREAUTH = 'preauth' + CONFIRMED = 'confirmed' + REJECTED = 'rejected' + REFUNDED = 'refunded' + ERROR = 'error' + INPUT = "input" + + CHOICES = [ + (WAITING, pgettext_lazy('payment status', 'Waiting for confirmation')), + (PREAUTH, pgettext_lazy('payment status', 'Pre-authorized')), + (CONFIRMED, pgettext_lazy('payment status', 'Confirmed')), + (REJECTED, pgettext_lazy('payment status', 'Rejected')), + (REFUNDED, pgettext_lazy('payment status', 'Refunded')), + (ERROR, pgettext_lazy('payment status', 'Error')), + (INPUT, pgettext_lazy('payment status', 'Input')), + ] + + +class FraudStatus: + UNKNOWN = 'unknown' + ACCEPT = 'accept' + REJECT = 'reject' + REVIEW = 'review' + + CHOICES = [ + (UNKNOWN, pgettext_lazy('fraud status', 'Unknown')), + (ACCEPT, pgettext_lazy('fraud status', 'Passed')), + (REJECT, pgettext_lazy('fraud status', 'Rejected')), + (REVIEW, pgettext_lazy('fraud status', 'Review')), + ] + + +class BasePayment(models.Model): + variant = models.CharField(max_length=255) + status = models.CharField( + max_length=10, choices=PaymentStatus.CHOICES, default=PaymentStatus.WAITING + ) + fraud_status = models.CharField( + _('fraud check'), + max_length=10, + choices=FraudStatus.CHOICES, + default=FraudStatus.UNKNOWN, + ) + fraud_message = models.TextField(blank=True, default='') + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + transaction_id = models.CharField(max_length=255, blank=True) + currency = models.CharField(max_length=10) + total = models.DecimalField(max_digits=9, decimal_places=2, default='0.0') + delivery = models.DecimalField(max_digits=9, decimal_places=2, default='0.0') + tax = models.DecimalField(max_digits=9, decimal_places=2, default='0.0') + description = models.TextField(blank=True, default='') + billing_first_name = models.CharField(max_length=256, blank=True) + billing_last_name = models.CharField(max_length=256, blank=True) + billing_address_1 = models.CharField(max_length=256, blank=True) + billing_address_2 = models.CharField(max_length=256, blank=True) + billing_city = models.CharField(max_length=256, blank=True) + billing_postcode = models.CharField(max_length=256, blank=True) + billing_country_code = models.CharField(max_length=2, blank=True) + billing_country_area = models.CharField(max_length=256, blank=True) + billing_email = models.EmailField(blank=True) + billing_phone = PhoneNumberField(blank=True) + customer_ip_address = models.GenericIPAddressField(blank=True, null=True) + extra_data = models.TextField(blank=True, default='') + message = models.TextField(blank=True, default='') + token = models.CharField(max_length=36, blank=True, default='') + captured_amount = models.DecimalField(max_digits=9, decimal_places=2, default='0.0') + + class Meta: + abstract = True + + def __str__(self): + return self.variant + + class Payment(BasePayment): payment_hex = models.CharField( _('Payment hex'), @@ -711,9 +787,6 @@ def get_success_url(self) -> str: return 'https://%s/accounts/callbacks/success/?ph=%s' % (settings.PAYMENT_HOST, self.payment_hex) def configure_user(self): - if self.status != PaymentStatus.CONFIRMED: - return - self.client.subscription = self.product self.client.save() diff --git a/accounts/views.py b/accounts/views.py index 4861d4c..44e13b3 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -13,13 +13,10 @@ from django.shortcuts import redirect, render from django.template.loader import render_to_string from django.urls import reverse -from django.utils import timezone from django.utils.datastructures import MultiValueDictKeyError from django.utils.html import strip_tags from django.utils.translation import gettext as _ from django.views import View -from payments import PaymentStatus -from payments import get_payment_model, RedirectNeeded from accounts.dataclasses import SignedURLReturnObject from accounts.enums import TransferType, UploadAction, UploadStatus @@ -29,8 +26,6 @@ from base.exceptions import FatalSignatureError, SignatureExpiredError from base.utils import decode_jwt_signature, generate_jwt_signature -PAYMENT_MODEL = get_payment_model() - BOOK_CONTENT_TYPES = ( 'application/vnd.amazon.ebook', @@ -635,120 +630,24 @@ def post(self, request, *args, **kwargs): except Subscription.DoesNotExist: raise PermissionDenied() - payment = PAYMENT_MODEL.objects.create( - variant='default', - total=product.price, - currency=product.currency, - customer_ip_address=request.META.get('REMOTE_ADDR', ''), - billing_email=request.user.email, - client=request.user, - product=product - ) - - return redirect( - reverse( - 'accounts:process_payment', - kwargs={ - 'payment_hex': payment.payment_hex - } - ) - ) + raise PermissionDenied() class ProcessPaymentView(LoginRequiredMixin, View): template_name = 'accounts/payment.html' - ALLOWED_STATUSES = ( - PaymentStatus.INPUT, - PaymentStatus.PREAUTH, - PaymentStatus.WAITING, - ) - - def get_payment(self, payment_hex): - try: - payment = PAYMENT_MODEL.objects.get(payment_hex=payment_hex) - except PAYMENT_MODEL.DoesNotExist: - raise PermissionDenied() - - if payment.status not in self.ALLOWED_STATUSES: - raise PermissionDenied() - - return payment def get(self, request, *args, **kwargs): - payment_hex = kwargs.get('payment_hex') - - if payment_hex is None: - raise PermissionDenied() - - payment = self.get_payment(payment_hex) - - form = payment.get_form() - - return render( - request, - template_name=self.template_name, - context={ - 'form': form, - 'payment': payment, - } - ) + raise PermissionDenied() def post(self, request, *args, **kwargs): - payment_hex = kwargs.get('payment_hex') - - if payment_hex is None: - raise PermissionDenied() - - payment = self.get_payment(payment_hex) - - try: - form = payment.get_form(data=request.POST) - except RedirectNeeded as redirect_link: - return redirect('%s' % redirect_link) - - return render( - request, - template_name=self.template_name, - context={ - 'form': form, - 'payment': payment, - } - ) + raise PermissionDenied() class PaymentCallbackView(LoginRequiredMixin, View): template_name = 'accounts/callbacks/payment.html' - ALLOWED_PAYMENT_STATUSES = ('success', 'failure',) - EXPIRATION_TIME = 60 * 30 - - def is_payment_expired(self, payment): - return payment.created + timedelta(seconds=self.EXPIRATION_TIME) < timezone.now() def get(self, request, *args, **kwargs): - payment_status = kwargs.get('payment_status') - payment_hex = request.GET.get('ph') - - if payment_hex is None or payment_status not in self.ALLOWED_PAYMENT_STATUSES: - raise PermissionDenied() - - try: - payment = PAYMENT_MODEL.objects.get(payment_hex=payment_hex) - except PAYMENT_MODEL.DoesNotExist: - raise PermissionDenied() - - if self.is_payment_expired(payment): - raise PermissionDenied() - - payment.configure_user() - - return render( - request, - template_name=self.template_name, - context={ - 'payment': payment, - 'is_success': payment_status == 'success', - } - ) + raise PermissionDenied() class SettingsView(LoginRequiredMixin, View): diff --git a/core/settings.py b/core/settings.py index 60a2e57..40c7db8 100644 --- a/core/settings.py +++ b/core/settings.py @@ -70,7 +70,6 @@ 'django.contrib.messages', 'django.contrib.staticfiles', # 3rd party apps - 'payments', 'fontawesomefree', # Custom apps 'accounts', @@ -219,16 +218,8 @@ # Payments PAYMENT_HOST = ENV.get_value('BF_PAYMENT_HOST') -PAYMENT_MODEL = 'accounts.Payment' - PAYMENT_USES_SSL = DEBUG -PAYMENT_VARIANTS = { - 'default': ( - 'payments.stripe.StripeProvider', - { - 'public_key': ENV.get_value('STRIPE_PUBLIC_KEY'), - 'secret_key': ENV.get_value('STRIPE_SECRET_KEY'), - } - ) -} +STRIPE_PUBLIC_KEY = ENV.get_value('STRIPE_PUBLIC_KEY') +STRIPE_SECRET_KEY = ENV.get_value('STRIPE_SECRET_KEY') +STRIPE_ENDPOINT_SECRET = ENV.get_value('STRIPE_ENDPOINT_SECRET') diff --git a/core/urls.py b/core/urls.py index c65e157..87c1c92 100644 --- a/core/urls.py +++ b/core/urls.py @@ -28,7 +28,6 @@ path('health/', Health.as_view(), name='health'), path('accounts/', include('accounts.urls'), name='accounts'), path('robots.txt', TemplateView.as_view(template_name='base/robots.txt', content_type='text/plain'), name='robots'), - path('payments/', include('payments.urls')), path('docs/', include('docs.urls')), path('api/', include('api.urls')), ]