blackout
[wolnelektury.git] / src / club / payu / models.py
index 4ab2c0a..d50ee8b 100644 (file)
@@ -1,38 +1,50 @@
+# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
+#
 import json
 from urllib.parse import urlencode
 from urllib.request import HTTPError
 from django.contrib.sites.models import Site
 from django.db import models
 from django.urls import reverse
 import json
 from urllib.parse import urlencode
 from urllib.request import HTTPError
 from django.contrib.sites.models import Site
 from django.db import models
 from django.urls import reverse
+from django.utils.timezone import now
 from . import POSS
 
 
 class CardToken(models.Model):
     """ This should be attached to a payment schedule. """
 from . import POSS
 
 
 class CardToken(models.Model):
     """ This should be attached to a payment schedule. """
-    pos_id = models.CharField(max_length=255)
-    disposable_token = models.CharField(max_length=255)
-    reusable_token = models.CharField(max_length=255, null=True, blank=True)
-    created_at = models.DateTimeField(auto_now_add=True)
+    pos_id = models.CharField('POS id', max_length=255)
+    disposable_token = models.CharField('token jednorazowy', max_length=255)
+    reusable_token = models.CharField('token wielokrotnego użytku', max_length=255, null=True, blank=True)
+    created_at = models.DateTimeField('utworzony', auto_now_add=True)
 
     class Meta:
         abstract = True
 
     class Meta:
         abstract = True
+        verbose_name = 'token PayU karty płatniczej'
+        verbose_name_plural = 'tokeny PayU kart płatniczych'
 
 
 class Order(models.Model):
 
 
 class Order(models.Model):
-    pos_id = models.CharField(max_length=255)   # TODO: redundant?
-    customer_ip = models.GenericIPAddressField()
-    order_id = models.CharField(max_length=255, blank=True)
+    pos_id = models.CharField('POS id', max_length=255)   # TODO: redundant?
+    customer_ip = models.GenericIPAddressField('adres IP klienta')
+    order_id = models.CharField('ID zamówienia', max_length=255, blank=True)
 
     status = models.CharField(max_length=128, blank=True, choices=[
 
     status = models.CharField(max_length=128, blank=True, choices=[
-        ('PENDING', 'Pending'),
-        ('WAITING_FOR_CONFIRMATION', 'Waiting for confirmation'),
-        ('COMPLETED', 'Completed'),
-        ('CANCELED', 'Canceled'),
-        ('REJECTED', 'Rejected'),
+        ('PENDING', 'Czeka'),
+        ('WAITING_FOR_CONFIRMATION', 'Czeka na potwierdzenie'),
+        ('COMPLETED', 'Ukończone'),
+        ('CANCELED', 'Anulowane'),
+        ('REJECTED', 'Odrzucone'),
+
+        ('ERR-INVALID_TOKEN', 'Błędny token'),
     ])
     ])
+    created_at = models.DateTimeField(null=True, blank=True, auto_now_add=True)
+    completed_at = models.DateTimeField(null=True, blank=True)
 
     class Meta:
         abstract = True
 
     class Meta:
         abstract = True
+        verbose_name = 'Zamówienie PayU'
+        verbose_name_plural = 'Zamówienia PayU'
 
     # These need to be provided in a subclass.
 
 
     # These need to be provided in a subclass.
 
@@ -64,6 +76,9 @@ class Order(models.Model):
     def get_notify_url(self):
         raise NotImplementedError
 
     def get_notify_url(self):
         raise NotImplementedError
 
+    def get_thanks_url(self):
+        raise NotImplementedError
+
     def status_updated(self):
         pass
 
     def status_updated(self):
         pass
 
@@ -72,6 +87,11 @@ class Order(models.Model):
     def get_pos(self):
         return POSS[self.pos_id]
 
     def get_pos(self):
         return POSS[self.pos_id]
 
+    def get_continue_url(self):
+        return "https://{}{}".format(
+            Site.objects.get_current().domain,
+            self.get_thanks_url())
+
     def get_representation(self, token=None):
         rep = {
             "notifyUrl": self.get_notify_url(),
     def get_representation(self, token=None):
         rep = {
             "notifyUrl": self.get_notify_url(),
@@ -79,7 +99,7 @@ class Order(models.Model):
             "merchantPosId": self.pos_id,
             "currencyCode": self.get_pos().currency_code,
             "totalAmount": str(int(self.get_amount() * 100)),
             "merchantPosId": self.pos_id,
             "currencyCode": self.get_pos().currency_code,
             "totalAmount": str(int(self.get_amount() * 100)),
-            "extOrderId": "wolne-lektury-rcz-%d" % self.pk,
+            "extOrderId": "wolne-lektury-%d" % self.pk,
 
             "buyer": self.get_buyer() or {},
             "continueUrl": self.get_continue_url(),
 
             "buyer": self.get_buyer() or {},
             "continueUrl": self.get_continue_url(),
@@ -116,20 +136,30 @@ class Order(models.Model):
                 token.save()
             # else?
 
                 token.save()
             # else?
 
-        self.order_id = response['orderId']
-        self.save()
+        if 'orderId' not in response:
+            code = response.get('status', {}).get('codeLiteral', '')
+            if code:
+                self.status = 'ERR-' + str(code)
+                self.save()
+                self.status_updated()
+            else:
+                raise ValueError("Expecting dict with `orderId` key, got: %s" % response)
+        else:
+            self.order_id = response['orderId']
+            self.save()
 
 
-        
-        return response.get('redirectUri', self.schedule.get_absolute_url())
+        return response.get('redirectUri', self.get_thanks_url())
 
 
 class Notification(models.Model):
     """ Add `order` FK to real Order model. """
 
 
 class Notification(models.Model):
     """ Add `order` FK to real Order model. """
-    body = models.TextField()
-    received_at = models.DateTimeField(auto_now_add=True)
+    body = models.TextField('treść')
+    received_at = models.DateTimeField('odebrana', auto_now_add=True)
 
     class Meta:
         abstract = True
 
     class Meta:
         abstract = True
+        verbose_name = 'notyfikacja PayU'
+        verbose_name_plural = 'notyfikacje PayU'
 
     def get_status(self):
         return json.loads(self.body)['order']['status']
 
     def get_status(self):
         return json.loads(self.body)['order']['status']
@@ -138,5 +168,7 @@ class Notification(models.Model):
         status = self.get_status()
         if self.order.status not in (status, 'COMPLETED'):
             self.order.status = status
         status = self.get_status()
         if self.order.status not in (status, 'COMPLETED'):
             self.order.status = status
+            if status == 'COMPLETED':
+                self.order.completed_at = now()
             self.order.save()
             self.order.status_updated()
             self.order.save()
             self.order.status_updated()