1
+ from datetime import datetime
2
+ from operator import itemgetter
3
+
4
+ from django .contrib .admin .views .decorators import staff_member_required
5
+ from django .contrib .auth .decorators import login_required , permission_required , user_passes_test
6
+ from django .contrib .auth .mixins import LoginRequiredMixin , UserPassesTestMixin
1
7
from django .db .models import Sum
2
8
from django .shortcuts import render , get_object_or_404
9
+ from django .utils .decorators import method_decorator
10
+ from django .views import View
11
+
12
+ from paypalrestsdk .exceptions import MethodNotAllowed
13
+ from paypalrestsdk import BillingAgreement , ResourceNotFound
14
+
3
15
from .models import Month
16
+ from sitewide .models import ZappyUser
4
17
5
18
6
19
def home (request ):
@@ -22,3 +35,106 @@ def home(request):
22
35
def view_month (request , month_pk , month_slug ):
23
36
month = get_object_or_404 (Month , pk = month_pk )
24
37
return render (request , 'money/view_month.html' , {'month' : month })
38
+
39
+ class SuperuserRequiredMixin (LoginRequiredMixin , UserPassesTestMixin ):
40
+ def test_func (self ):
41
+ return self .request .user .is_superuser
42
+
43
+ class Paypal (SuperuserRequiredMixin , View ):
44
+ template_name = "paypal_mrr.html"
45
+
46
+ def __init__ (self ):
47
+ super ().__init__ ()
48
+ user_list = self .get_active_paypal_users ()
49
+ self .current_date = datetime .now ()
50
+ if user_list :
51
+ self .paypal_user_list = sorted (user_list , key = itemgetter ('username' ))
52
+ self .price_chart = self .get_subs_chart ()
53
+ else :
54
+ self .price_chart = None
55
+ self .paypal_user_list = None
56
+
57
+ def get (self , request , * args , ** kwargs ):
58
+ return render (request , "money/paypal_mrr.html" , {
59
+ "active_users" : self .paypal_user_list ,
60
+ "chart" : self .price_chart ,
61
+ "current_date" : self .current_date
62
+ })
63
+
64
+ def post (self , request , * args , ** kwargs ):
65
+ self .paypal_user_list = sorted (self .get_active_paypal_users (), key = itemgetter ('username' ))
66
+ self .price_chart = self .get_subs_chart ()
67
+ return render (request , "money/paypal_mrr.html" , {
68
+ "active_users" : self .paypal_user_list ,
69
+ "chart" : self .price_chart ,
70
+ "current_date" : self .current_date
71
+ })
72
+
73
+ @staticmethod
74
+ def get_active_paypal_users ():
75
+ """returns all active paypal users"""
76
+ paypal_users = ZappyUser .objects .filter (paypal_subscription_id__isnull = False )
77
+ paypal_active_users = []
78
+
79
+ for user in paypal_users :
80
+ # in case there is empty string instead PayPal sub id
81
+ if user .paypal_subscription_id :
82
+ try :
83
+ billing_agreement = BillingAgreement .find (user .paypal_subscription_id )
84
+ if not billing_agreement .id :
85
+ continue
86
+ except ResourceNotFound :
87
+ print ("Billing Agreement Not Found" )
88
+ continue
89
+ except MethodNotAllowed :
90
+ print ("Billing Agreement Not Found" )
91
+ continue
92
+
93
+ if billing_agreement .state .lower () == 'active' :
94
+ if billing_agreement .plan .payment_definitions [0 ].frequency == 'MONTH' :
95
+ sub_type = 'monthly'
96
+ else :
97
+ sub_type = 'yearly'
98
+
99
+ paypal_user = {
100
+ 'username' : user .username ,
101
+ 'email' : user .email ,
102
+ 'sub_price' : float (billing_agreement .plan .payment_definitions [0 ].amount .value ),
103
+ 'sub_type' : sub_type ,
104
+ }
105
+ paypal_active_users .append (paypal_user )
106
+
107
+ return paypal_active_users
108
+
109
+ def get_subs_chart (self ):
110
+ """prepares data for price table. Counts as well average subscriptions prices and MMR"""
111
+ chart = {
112
+ 'monthly' : {},
113
+ 'yearly' : {}
114
+ }
115
+ yearly , monthly = 0 , 0
116
+ # collect set of subscription prices and amount for each price
117
+ for pal in self .paypal_user_list :
118
+ chart [pal ['sub_type' ]][pal ['sub_price' ]] = chart [pal ['sub_type' ]].get (pal ['sub_price' ], 0 ) + 1
119
+
120
+ yearly_sum = sum ([k * v for k , v in chart ['yearly' ].items ()])
121
+ monthly_sum = sum ([k * v for k , v in chart ['monthly' ].items ()])
122
+
123
+ # count average prices of subscriptions. if statements to avoid division by 0
124
+ if chart ['yearly' ]:
125
+ yearly = yearly_sum / sum ([v for v in chart ['yearly' ].values ()])
126
+ if chart ['monthly' ]:
127
+ monthly = monthly_sum / sum ([v for v in chart ['monthly' ].values ()])
128
+
129
+ combined = (yearly / 12 + monthly )/ 2
130
+
131
+ chart ['avg' ] = {
132
+ 'yearly' : yearly ,
133
+ 'monthly' : monthly ,
134
+ 'combined' : combined ,
135
+ }
136
+
137
+ # count MRR
138
+ chart ['monthly_revenue' ] = yearly_sum / 12 + monthly_sum
139
+
140
+ return chart
0 commit comments