Repository: fossasia/open-event-server

Issue:
Implement discount code for events and marketers
As we need to get marketers support to get the event system used, we need a way to identify which event organizer comes through which marketer. A way to achieve this is through discount codes.

To do this we need a way to create discount codes and link them to specific marketers accounts. So, for example a marketer gives out a discount code "X20482TOP" and that discount code gets organizers off 10% for an event over three months. Then in the monthly report the event organizer needs to get 10% off from the money he needs to pay.

In the admin sales overview we should also have a column "Marketer" to show all events with discount codes of a specific marketer. Based on the sales we can then share the income with a marketer.

Features we need are:
- [x] Implement Role "Marketer" as System role https://github.com/fossasia/open-event-orga-server/issues/2453
- [x] Possibility to create event discounts with percentage, number of times the discount voucher is valid and user account the voucher is linked to
- [x] Show of discounts in column in sales and show of linked marketer
- [x] Calculate discount in sales monthly
- [x] Implement Sales overview for events of marketers (where and how would that be best?)
- [x] In admin tab "Sales" show subtab sales "By Marketer" https://github.com/fossasia/open-event-orga-server/issues/2452
- [x] In admin tab "Sales" show subtab sales "By Discount Code" https://github.com/fossasia/open-event-orga-server/issues/2452



Discussion:
@mariobehling 
1. the discount vouchers for the **marketers** can be created by **sales admin** and the **administrator**. Correct ? 
2. Where would the new event organizer _enter_ the discount code that he/she has been given by the marketer ??

> 1. the discount vouchers for the **marketers** can be created by **sales admin** and the **administrator**. Correct ? 

Yes, correct.
1. Where would the new event organizer _enter_ the discount code that he/she has been given by the marketer ??

> It should probably go into a field "discount code" in the ticketing area of wizard step 1.

> Implement Sales overview for events of marketers (where and how would that be best?)

@mariobehling In the admin sales page, we could have a tab named **promoted events** and display only the events that have a discount code applied. The display format can be the same as that of the **By events** with an additional column with the discount code applied and marketer name.

@niranjan94 Yes, good idea. Please proceed.

There is an additional requirement - specific marketer should only see the events with codes assigned to him/herself. Can we do that?

@mariobehling yes. that can be done.


Resolving patch:
diff --git a/app/helpers/data_getter.py b/app/helpers/data_getter.py
--- a/app/helpers/data_getter.py
+++ b/app/helpers/data_getter.py
@@ -95,7 +95,7 @@ def get_all_events():
     def get_all_events_with_discounts():
         """Method return all events"""
         return Event.query.order_by(desc(Event.id)).filter_by(in_trash=False)\
-            .filter(Event.discount_code_id is not None).filter(Event.discount_code_id > 0).all()
+            .filter(Event.discount_code_id != None).filter(Event.discount_code_id > 0).all()
 
     @staticmethod
     def get_custom_placeholders():
diff --git a/app/helpers/ticketing.py b/app/helpers/ticketing.py
--- a/app/helpers/ticketing.py
+++ b/app/helpers/ticketing.py
@@ -55,7 +55,7 @@ def get_orders_of_user(user_id=None, upcoming_events=True):
             return query.filter(Event.end_time < datetime.now())
 
     @staticmethod
-    def get_orders(event_id=None, status=None, from_date=None, to_date=None, marketer_id=None):
+    def get_orders(event_id=None, status=None, from_date=None, to_date=None, marketer_id=None, promoted_event=False):
         if event_id:
             if status:
                 orders = Order.query.filter_by(event_id=event_id).filter_by(status=status) \
@@ -72,8 +72,9 @@ def get_orders(event_id=None, status=None, from_date=None, to_date=None, markete
             orders = orders.filter(Order.created_at >= from_date)
         if to_date:
             orders = orders.filter(Order.created_at <= to_date)
-        if marketer_id:
-            orders = orders.filter_by(marketer_id=marketer_id)
+
+        if promoted_event:
+            orders = orders.join(Order.event).filter(Event.discount_code_id != None)
 
             orders = orders.order_by(asc(Order.created_at))
 
diff --git a/app/views/admin/super_admin/sales.py b/app/views/admin/super_admin/sales.py
--- a/app/views/admin/super_admin/sales.py
+++ b/app/views/admin/super_admin/sales.py
@@ -227,19 +227,21 @@ def sales_by_events_view(self, path):
 
             return redirect(url_for('.sales_by_events_view', path=path))
 
-        marketer_role = CustomSysRole.query.filter_by(name='Marketer').first()
-        marketer_id = login.current_user.id if login.current_user.is_sys_role(marketer_role.id) else None
+        promoted_events = path == 'promoted-events'
 
         if from_date and to_date:
             orders = TicketingManager.get_orders(
                 from_date=datetime.strptime(from_date, '%d/%m/%Y'),
                 to_date=datetime.strptime(to_date, '%d/%m/%Y'),
-                marketer_id=marketer_id
+                promoted_event=promoted_events
             )
         else:
-            orders = TicketingManager.get_orders(marketer_id=marketer_id)
+            orders = TicketingManager.get_orders(promoted_event=promoted_events)
 
-        events = DataGetter.get_all_events()
+        if promoted_events:
+            events = DataGetter.get_all_events_with_discounts()
+        else:
+            events = DataGetter.get_all_events()
 
         completed_count = 0
         completed_amount = 0
@@ -274,6 +276,8 @@ def sales_by_events_view(self, path):
             tickets_summary_event_wise[str(event.id)] = {
                 'name': event.name,
                 'payment_currency': event.payment_currency,
+                'marketer': '',
+                'discount_code': '',
                 'completed': {
                     'tickets_count': 0,
                     'sales': 0
@@ -288,6 +292,13 @@ def sales_by_events_view(self, path):
                     'sales': 0
                 }
             }
+
+            if promoted_events:
+                tickets_summary_event_wise[str(event.id)]['marketer'] = \
+                    event.discount_code.marketer.email
+                tickets_summary_event_wise[str(event.id)]['discount_code'] = \
+                    str(event.discount_code.value) + '% off for ' + str(event.discount_code.max_quantity) + ' months'
+
             tickets_summary_organizer_wise[str(event.creator_id)] = \
                 copy.deepcopy(tickets_summary_event_wise[str(event.id)])
             if event.creator:
@@ -326,12 +337,13 @@ def sales_by_events_view(self, path):
                                                                                      status)]['sales'] += \
                         order_ticket.quantity * ticket.price
 
-        if path == 'events':
+        if path == 'events' or path == 'promoted-events':
             return self.render('/gentelella/admin/super_admin/sales/by_events.html',
                                tickets_summary=tickets_summary_event_wise,
                                display_currency=self.display_currency,
                                from_date=from_date,
                                to_date=to_date,
+                               path=path,
                                orders_summary=orders_summary)
         elif path == 'organizers':
             return self.render('/gentelella/admin/super_admin/sales/by_organizer.html',
@@ -339,6 +351,7 @@ def sales_by_events_view(self, path):
                                display_currency=self.display_currency,
                                from_date=from_date,
                                to_date=to_date,
+                               path=path,
                                orders_summary=orders_summary)
         elif path == 'locations':
             return self.render('/gentelella/admin/super_admin/sales/by_location.html',
@@ -346,6 +359,7 @@ def sales_by_events_view(self, path):
                                display_currency=self.display_currency,
                                from_date=from_date,
                                to_date=to_date,
+                               path=path,
                                orders_summary=orders_summary)
 
         else:


Test patch: