Repository: fossasia/open-event-server

Issue:
Add overall sales data to Event
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
Both the Frontend and the Orga app will need to display overall sales data: (number of tickets sold / number of available tickets) in public schema, net revenue in organizer schema. 

**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
These can be directly added to Event Schemas

**Would you like to work on this?**
Yes


Discussion:

Resolving patch:
diff --git a/app/api/schema/events.py b/app/api/schema/events.py
--- a/app/api/schema/events.py
+++ b/app/api/schema/events.py
@@ -92,6 +92,9 @@ def validate_timezone(self, data, original_data):
     is_ticketing_enabled = fields.Bool(default=True)
     payment_country = fields.Str(allow_none=True)
     payment_currency = fields.Str(allow_none=True)
+    tickets_available = fields.Float(dump_only=True)
+    tickets_sold = fields.Float(dump_only=True)
+    revenue = fields.Float(dump_only=True)
     paypal_email = fields.Str(allow_none=True)
     is_tax_enabled = fields.Bool(default=False)
     can_pay_by_paypal = fields.Bool(default=False)
diff --git a/app/models/event.py b/app/models/event.py
--- a/app/models/event.py
+++ b/app/models/event.py
@@ -10,6 +10,7 @@
 
 from app.api.helpers.db import get_count
 from app.models import db
+from app.models.order import Order
 from app.models.ticket_fee import get_fee
 from app.models.base import SoftDeletionModel
 from app.models.email_notification import EmailNotification
@@ -18,7 +19,8 @@
 from app.models.user import ATTENDEE, ORGANIZER
 from app.models.event_topic import EventTopic
 from app.models.search import sync
-
+from app.models.ticket import Ticket
+from app.models.ticket_holder import TicketHolder
 
 def get_new_event_identifier(length=8):
     identifier = str(binascii.b2a_hex(os.urandom(int(length / 2))), 'utf-8')
@@ -344,6 +346,36 @@ def get_staff_roles(self):
     def as_dict(self):
         return {c.name: getattr(self, c.name) for c in self.__table__.columns}
 
+    def calc_tickets_sold_count(self):
+        """Calculate total number of tickets sold for the event"""
+        return db.session.query(Order.event_id).filter_by(event_id=self.id, status='completed').join(TicketHolder)\
+            .count()
+
+    def calc_total_tickets_count(self):
+        """Calculate total available tickets for all types of tickets"""
+        total_available = db.session.query(func.sum(Ticket.quantity)).filter_by(event_id=self.id).scalar()
+        if total_available is None:
+            total_available = 0
+        return total_available
+
+    def calc_revenue(self):
+        """Returns total revenues of all completed orders for the given event"""
+        revenue = db.session.query(func.sum(Order.amount)).filter_by(event_id=self.id, status='completed').scalar()
+        if revenue is None:
+            revenue = 0
+        return revenue
+
+    @property
+    def tickets_available(self):
+        return self.calc_total_tickets_count()
+
+    @property
+    def tickets_sold(self):
+        return self.calc_tickets_sold_count()
+
+    @property
+    def revenue(self):
+        return self.calc_revenue()
 
 @event.listens_for(Event, 'after_update')
 @event.listens_for(Event, 'after_insert')


Test patch: