Repository: fossasia/open-event-server

Issue:
Monthly invoice mails are erroring out
When deploying 1.6.2 last night, I noticed there are several errors in celery and APS and basically, no invoice email was sent most probably.

I could not copy logs as I was in middle of deployment. 

Write tests for the invoice mail generation and debug what could go wrong


Discussion:
@iamareebjamal On it.

I'll take this up. I've also found out what happened here.
Because there was no ticket fee set up on the admin system for USD, the emails started erroring out. 

```
  File "/Users/saicharan/Desktop/open-event-server/app/api/helpers/scheduled_jobs.py", line 253, in send_monthly_event_invoice
    db.session.query(TicketFees).filter_by(currency=currency).one()
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3332, in one
    raise orm_exc.NoResultFound("No row was found for one()")
sqlalchemy.orm.exc.NoResultFound: No row was found for one()
```
Will fix this up and add the test

Resolving patch:
diff --git a/app/api/helpers/scheduled_jobs.py b/app/api/helpers/scheduled_jobs.py
--- a/app/api/helpers/scheduled_jobs.py
+++ b/app/api/helpers/scheduled_jobs.py
@@ -2,6 +2,8 @@
 
 import pytz
 from dateutil.relativedelta import relativedelta
+from sqlalchemy.orm.exc import NoResultFound
+from flask_rest_jsonapi.exceptions import ObjectNotFound
 from flask import render_template
 from flask_celeryext import RequestContextTask
 
@@ -249,22 +251,27 @@ def send_monthly_event_invoice():
             user = event.owner
             admin_info = get_settings()
             currency = event.payment_currency
-            ticket_fee_object = (
-                db.session.query(TicketFees).filter_by(currency=currency).one()
-            )
+            try:
+                ticket_fee_object = (
+                    db.session.query(TicketFees).filter_by(currency=currency).one()
+                )
+            except NoResultFound:
+                raise ObjectNotFound(
+                    {'source': ''}, 'Ticket Fee not set for {}'.format(currency)
+                )
             ticket_fee_percentage = ticket_fee_object.service_fee
             ticket_fee_maximum = ticket_fee_object.maximum_fee
             orders = Order.query.filter_by(event=event).all()
             gross_revenue = event.calc_monthly_revenue()
-            ticket_fees = event.tickets_sold * (ticket_fee_percentage / 100)
-            if ticket_fees > ticket_fee_maximum:
-                ticket_fees = ticket_fee_maximum
-            net_revenue = gross_revenue - ticket_fees
+            invoice_amount = gross_revenue * (ticket_fee_percentage / 100)
+            if invoice_amount > ticket_fee_maximum:
+                invoice_amount = ticket_fee_maximum
+            net_revenue = gross_revenue - invoice_amount
             payment_details = {
                 'tickets_sold': event.tickets_sold,
                 'gross_revenue': gross_revenue,
                 'net_revenue': net_revenue,
-                'amount_payable': ticket_fees,
+                'amount_payable': invoice_amount,
             }
             # save invoice as pdf
             pdf = create_save_pdf(
@@ -286,7 +293,7 @@ def send_monthly_event_invoice():
             # save event_invoice info to DB
 
             event_invoice = EventInvoice(
-                amount=net_revenue, invoice_pdf_url=pdf, event_id=event.id
+                amount=invoice_amount, invoice_pdf_url=pdf, event_id=event.id
             )
             save_to_db(event_invoice)
 
diff --git a/app/factories/common.py b/app/factories/common.py
--- a/app/factories/common.py
+++ b/app/factories/common.py
@@ -22,7 +22,7 @@
 timezone_ = 'UTC'
 environment_ = 'testing'
 secret_ = 'ABCDefghIJKLmnop'
-fee_ = '1.23'
+fee_ = 1.23
 slug_ = factory.Sequence(lambda n: 'example_slug{0}'.format(n))
 
 


Test patch:
diff --git a/tests/all/integration/api/helpers/test_scheduled_jobs.py b/tests/all/integration/api/helpers/test_scheduled_jobs.py
--- a/tests/all/integration/api/helpers/test_scheduled_jobs.py
+++ b/tests/all/integration/api/helpers/test_scheduled_jobs.py
@@ -3,10 +3,15 @@
 from app.api.helpers.scheduled_jobs import (
     delete_ticket_holders_no_order_id,
     event_invoices_mark_due,
+    send_monthly_event_invoice,
 )
 import app.factories.common as common
 from app.factories.attendee import AttendeeFactory
+from app.factories.ticket_fee import TicketFeesFactory
 from app.factories.event_invoice import EventInvoiceFactory
+from app.factories.user import UserFactory
+from app.factories.event import EventFactoryBasic
+from app.factories.order import OrderFactory
 from app.models import db
 from app.models.event_invoice import EventInvoice
 from app.models.ticket_holder import TicketHolder
@@ -78,3 +83,31 @@ def test_delete_ticket_holder_with_valid_order_id(self):
             delete_ticket_holders_no_order_id()
             ticket_holder = TicketHolder.query.get(attendee_id)
             self.assertIsNot(ticket_holder, None)
+
+    def test_send_monthly_invoice(self):
+        """Method to test monthly invoices"""
+
+        with self.app.test_request_context():
+            TicketFeesFactory(service_fee=10.23, maximum_fee=11)
+
+            test_event = EventFactoryBasic(state='published')
+
+            test_user = UserFactory()
+
+            test_order = OrderFactory(status='completed')
+            test_order.completed_at = datetime.datetime.now() - datetime.timedelta(
+                days=30
+            )
+            test_order.amount = 100
+            test_order.event = test_event
+
+            test_ticket_holder = AttendeeFactory()
+            test_ticket_holder.event = test_event
+            test_ticket_holder.order = test_order
+
+            test_event.owner = test_user
+            db.session.commit()
+
+            send_monthly_event_invoice()
+            event_invoice = EventInvoice.query.get(1)
+            self.assertEqual(event_invoice.amount, 10.23)