We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Task send_event_fee_notification failing
```
raised unexpected: AttributeError("'Ticket' object has no attribute 'ticket_id'")
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/celery/app/trace.py", line 385, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/flask_celeryext/app.py", line 101, in __call__
    res = Task.__call__(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/celery/app/trace.py", line 650, in __protected_call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 161, in _inner
    reraise(*exc_info)
  File "/usr/local/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 57, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py", line 156, in _inner
    return f(*args, **kwargs)
  File "/data/app/app/api/helpers/scheduled_jobs.py", line 90, in send_event_fee_notification
    ticket = safe_query(db, Ticket, 'id', order_ticket.ticket_id, 'ticket_id')
AttributeError: 'Ticket' object has no attribute 'ticket_id'

```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `app/api/helpers/scheduled_jobs.py`
Content:
```
1 import datetime
2 
3 import pytz
4 from dateutil.relativedelta import relativedelta
5 from flask import render_template
6 from flask_celeryext import RequestContextTask
7 from app.instance import celery
8 
9 from app.api.helpers.db import safe_query, save_to_db
10 from app.api.helpers.mail import send_email_after_event, send_email_for_monthly_fee_payment, \
11     send_followup_email_for_monthly_fee_payment
12 from app.api.helpers.notification import send_notif_monthly_fee_payment, send_followup_notif_monthly_fee_payment, \
13     send_notif_after_event
14 from app.api.helpers.query import get_upcoming_events, get_user_event_roles_by_role_name
15 from app.api.helpers.utilities import monthdelta
16 from app.api.helpers.files import create_save_pdf
17 from app.api.helpers.storage import UPLOAD_PATHS
18 from app.models import db
19 from app.models.event import Event
20 from app.models.event_invoice import EventInvoice
21 from app.models.order import Order
22 from app.models.speaker import Speaker
23 from app.models.session import Session
24 from app.models.ticket import Ticket
25 from app.models.ticket_fee import TicketFees, get_fee
26 from app.models.ticket_holder import TicketHolder
27 
28 from app.settings import get_settings
29 
30 
31 @celery.task(base=RequestContextTask, name='send.after.event.mail')
32 def send_after_event_mail():
33     from app.instance import current_app as app
34     with app.app_context():
35         events = Event.query.filter_by(state='published', deleted_at=None).all()
36         for event in events:
37             organizers = get_user_event_roles_by_role_name(event.id, 'organizer')
38             speakers = Speaker.query.filter_by(event_id=event.id, deleted_at=None).all()
39             owner = get_user_event_roles_by_role_name(event.id, 'owner').first()
40             current_time = datetime.datetime.now(pytz.timezone(event.timezone))
41             time_difference = current_time - event.ends_at
42             time_difference_minutes = (time_difference.days * 24 * 60) + \
43                 (time_difference.seconds / 60)
44             frontend_url = get_settings()['frontend_url']
45             if current_time > event.ends_at and time_difference_minutes < 1440:
46                 for speaker in speakers:
47                     if not speaker.is_email_overridden:
48                         send_email_after_event(speaker.user.email, event.name, frontend_url)
49                         send_notif_after_event(speaker.user, event.name)
50                 for organizer in organizers:
51                     send_email_after_event(organizer.user.email, event.name, frontend_url)
52                     send_notif_after_event(organizer.user, event.name)
53                 if owner:
54                     send_email_after_event(owner.user.email, event.name, frontend_url)
55                     send_notif_after_event(owner.user, event.name)
56 
57 
58 @celery.task(base=RequestContextTask, name='change.session.state.on.event.completion')
59 def change_session_state_on_event_completion():
60     from app.instance import current_app as app
61     with app.app_context():
62         sessions_to_be_changed = Session.query.join(Event).filter(Session.state == 'pending')\
63                                  .filter(Event.ends_at < datetime.datetime.now())
64         for session in sessions_to_be_changed:
65             session.state = 'rejected'
66             save_to_db(session, 'Changed {} session state to rejected'.format(session.title))
67 
68 
69 @celery.task(base=RequestContextTask, name='send.event.fee.notification')
70 def send_event_fee_notification():
71     from app.instance import current_app as app
72     with app.app_context():
73         events = Event.query.filter_by(deleted_at=None, state='published').all()
74         for event in events:
75             latest_invoice = EventInvoice.query.filter_by(
76                 event_id=event.id).order_by(EventInvoice.created_at.desc()).first()
77 
78             if latest_invoice:
79                 orders = Order.query \
80                     .filter_by(event_id=event.id) \
81                     .filter_by(status='completed') \
82                     .filter(Order.completed_at > latest_invoice.created_at).all()
83             else:
84                 orders = Order.query.filter_by(
85                     event_id=event.id).filter_by(status='completed').all()
86 
87             fee_total = 0
88             for order in orders:
89                 for order_ticket in order.tickets:
90                     ticket = safe_query(db, Ticket, 'id', order_ticket.ticket_id, 'ticket_id')
91                     if order.paid_via != 'free' and order.amount > 0 and ticket.price > 0:
92                         fee = ticket.price * (get_fee(event.payment_country, order.event.payment_currency) / 100.0)
93                         fee_total += fee
94 
95             if fee_total > 0:
96                 owner = get_user_event_roles_by_role_name(event.id, 'owner').first()
97                 new_invoice = EventInvoice(
98                     amount=fee_total, event_id=event.id, user_id=owner.user.id)
99 
100                 if event.discount_code_id and event.discount_code:
101                     r = relativedelta(datetime.datetime.utcnow(), event.created_at)
102                     if r <= event.discount_code.valid_till:
103                         new_invoice.amount = fee_total - \
104                             (fee_total * (event.discount_code.value / 100.0))
105                         new_invoice.discount_code_id = event.discount_code_id
106 
107                 save_to_db(new_invoice)
108                 prev_month = monthdelta(new_invoice.created_at, 1).strftime(
109                     "%b %Y")  # Displayed as Aug 2016
110                 app_name = get_settings()['app_name']
111                 frontend_url = get_settings()['frontend_url']
112                 link = '{}/invoices/{}'.format(frontend_url, new_invoice.identifier)
113                 send_email_for_monthly_fee_payment(new_invoice.user.email,
114                                                    event.name,
115                                                    prev_month,
116                                                    new_invoice.amount,
117                                                    app_name,
118                                                    link)
119                 send_notif_monthly_fee_payment(new_invoice.user,
120                                                event.name,
121                                                prev_month,
122                                                new_invoice.amount,
123                                                app_name,
124                                                link,
125                                                new_invoice.event_id)
126 
127 
128 @celery.task(base=RequestContextTask, name='send.event.fee.notification.followup')
129 def send_event_fee_notification_followup():
130     from app.instance import current_app as app
131     with app.app_context():
132         incomplete_invoices = EventInvoice.query.filter(EventInvoice.status != 'paid').all()
133         for incomplete_invoice in incomplete_invoices:
134             if incomplete_invoice.amount > 0:
135                 prev_month = monthdelta(incomplete_invoice.created_at, 1).strftime(
136                     "%b %Y")  # Displayed as Aug 2016
137                 app_name = get_settings()['app_name']
138                 frontend_url = get_settings()['frontend_url']
139                 link = '{}/event-invoice/{}/review'.format(frontend_url,
140                                                incomplete_invoice.identifier)
141                 send_followup_email_for_monthly_fee_payment(incomplete_invoice.user.email,
142                                                             incomplete_invoice.event.name,
143                                                             prev_month,
144                                                             incomplete_invoice.amount,
145                                                             app_name,
146                                                             link)
147                 send_followup_notif_monthly_fee_payment(incomplete_invoice.user,
148                                                         incomplete_invoice.event.name,
149                                                         prev_month,
150                                                         incomplete_invoice.amount,
151                                                         app_name,
152                                                         link,
153                                                         incomplete_invoice.event.id)
154 
155 
156 @celery.task(base=RequestContextTask, name='expire.pending.tickets')
157 def expire_pending_tickets():
158     from app.instance import current_app as app
159     with app.app_context():
160         db.session.query(Order).filter(Order.status == 'pending',
161                                        (Order.created_at + datetime.timedelta(minutes=30)) <= datetime.datetime.now()).\
162                                        update({'status': 'expired'})
163         db.session.commit()
164 
165 
166 @celery.task(base=RequestContextTask, name='delete.ticket.holders.no.order.id')
167 def delete_ticket_holders_no_order_id():
168     from app.instance import current_app as app
169     with app.app_context():
170         order_expiry_time = get_settings()['order_expiry_time']
171         TicketHolder.query.filter(TicketHolder.order_id == None, TicketHolder.deleted_at.is_(None),
172                                   TicketHolder.created_at + datetime.timedelta(minutes=order_expiry_time)
173                                   < datetime.datetime.utcnow()).delete(synchronize_session=False)
174         db.session.commit()
175 
176 
177 @celery.task(base=RequestContextTask, name='event.invoices.mark.due')
178 def event_invoices_mark_due():
179     from app.instance import current_app as app
180     with app.app_context():
181         db.session.query(EventInvoice).filter(
182             EventInvoice.status == 'upcoming',
183             Event.id == EventInvoice.event_id,
184             Event.ends_at >= datetime.datetime.now(),
185             (EventInvoice.created_at + datetime.timedelta(days=30) <= datetime.datetime.now())
186         ).update({EventInvoice.status: 'due'}, synchronize_session=False)
187 
188 
189 @celery.task(base=RequestContextTask, name='send.monthly.event.invoice')
190 def send_monthly_event_invoice():
191     from app.instance import current_app as app
192     with app.app_context():
193         events = Event.query.filter_by(deleted_at=None, state='published').all()
194         for event in events:
195             # calculate net & gross revenues
196             user = event.owner
197             admin_info = get_settings()
198             currency = event.payment_currency
199             ticket_fee_object = db.session.query(TicketFees).filter_by(currency=currency).one()
200             ticket_fee_percentage = ticket_fee_object.service_fee
201             ticket_fee_maximum = ticket_fee_object.maximum_fee
202             orders = Order.query.filter_by(event=event).all()
203             gross_revenue = event.calc_monthly_revenue()
204             ticket_fees = event.tickets_sold * (ticket_fee_percentage / 100)
205             if ticket_fees > ticket_fee_maximum:
206                 ticket_fees = ticket_fee_maximum
207             net_revenue = gross_revenue - ticket_fees
208             payment_details = {
209                 'tickets_sold': event.tickets_sold,
210                 'gross_revenue': gross_revenue,
211                 'net_revenue': net_revenue,
212                 'amount_payable': ticket_fees
213             }
214             # save invoice as pdf
215             pdf = create_save_pdf(render_template('pdf/event_invoice.html', orders=orders, user=user,
216                                   admin_info=admin_info, currency=currency, event=event,
217                                   ticket_fee_object=ticket_fee_object, payment_details=payment_details,
218                                   net_revenue=net_revenue), UPLOAD_PATHS['pdf']['event_invoice'],
219                                   dir_path='/static/uploads/pdf/event_invoices/', identifier=event.identifier)
220             # save event_invoice info to DB
221 
222             event_invoice = EventInvoice(amount=net_revenue, invoice_pdf_url=pdf, event_id=event.id)
223             save_to_db(event_invoice)
224 
225 
226 @celery.on_after_configure.connect
227 def setup_scheduled_task(sender, **kwargs):
228     from celery.schedules import crontab
229     sender.add_periodic_task(crontab(hour='*/5', minute=30), send_after_event_mail)
230     sender.add_periodic_task(crontab(day_of_week='0-6'), send_event_fee_notification)
231     sender.add_periodic_task(crontab(minute=0, hour=0, day_of_month=1), send_event_fee_notification_followup)
232     sender.add_periodic_task(crontab(hour='*/5', minute=30), change_session_state_on_event_completion)
233     sender.add_periodic_task(crontab(minute='*/45'), expire_pending_tickets)
234     sender.add_periodic_task(crontab(minute=0, hour=0, day_of_month=1), send_monthly_event_invoice)
235     sender.add_periodic_task(crontab(minute=0, hour='*/5'), event_invoices_mark_due)
236     sender.add_periodic_task(crontab(minute='*/5'), delete_ticket_holders_no_order_id)
237
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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
@@ -86,8 +86,7 @@
 
             fee_total = 0
             for order in orders:
-                for order_ticket in order.tickets:
-                    ticket = safe_query(db, Ticket, 'id', order_ticket.ticket_id, 'ticket_id')
+                for ticket in order.tickets:
                     if order.paid_via != 'free' and order.amount > 0 and ticket.price > 0:
                         fee = ticket.price * (get_fee(event.payment_country, order.event.payment_currency) / 100.0)
                         fee_total += fee

{"golden_diff": "diff --git a/app/api/helpers/scheduled_jobs.py b/app/api/helpers/scheduled_jobs.py\n--- a/app/api/helpers/scheduled_jobs.py\n+++ b/app/api/helpers/scheduled_jobs.py\n@@ -86,8 +86,7 @@\n \n             fee_total = 0\n             for order in orders:\n-                for order_ticket in order.tickets:\n-                    ticket = safe_query(db, Ticket, 'id', order_ticket.ticket_id, 'ticket_id')\n+                for ticket in order.tickets:\n                     if order.paid_via != 'free' and order.amount > 0 and ticket.price > 0:\n                         fee = ticket.price * (get_fee(event.payment_country, order.event.payment_currency) / 100.0)\n                         fee_total += fee\n", "issue": "Task send_event_fee_notification failing\n```\r\nraised unexpected: AttributeError(\"'Ticket' object has no attribute 'ticket_id'\")\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python3.7/site-packages/celery/app/trace.py\", line 385, in trace_task\r\n    R = retval = fun(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.7/site-packages/flask_celeryext/app.py\", line 101, in __call__\r\n    res = Task.__call__(self, *args, **kwargs)\r\n  File \"/usr/local/lib/python3.7/site-packages/celery/app/trace.py\", line 650, in __protected_call__\r\n    return self.run(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py\", line 161, in _inner\r\n    reraise(*exc_info)\r\n  File \"/usr/local/lib/python3.7/site-packages/sentry_sdk/_compat.py\", line 57, in reraise\r\n    raise value\r\n  File \"/usr/local/lib/python3.7/site-packages/sentry_sdk/integrations/celery.py\", line 156, in _inner\r\n    return f(*args, **kwargs)\r\n  File \"/data/app/app/api/helpers/scheduled_jobs.py\", line 90, in send_event_fee_notification\r\n    ticket = safe_query(db, Ticket, 'id', order_ticket.ticket_id, 'ticket_id')\r\nAttributeError: 'Ticket' object has no attribute 'ticket_id'\r\n\r\n```\n", "before_files": [{"content": "import datetime\n\nimport pytz\nfrom dateutil.relativedelta import relativedelta\nfrom flask import render_template\nfrom flask_celeryext import RequestContextTask\nfrom app.instance import celery\n\nfrom app.api.helpers.db import safe_query, save_to_db\nfrom app.api.helpers.mail import send_email_after_event, send_email_for_monthly_fee_payment, \\\n    send_followup_email_for_monthly_fee_payment\nfrom app.api.helpers.notification import send_notif_monthly_fee_payment, send_followup_notif_monthly_fee_payment, \\\n    send_notif_after_event\nfrom app.api.helpers.query import get_upcoming_events, get_user_event_roles_by_role_name\nfrom app.api.helpers.utilities import monthdelta\nfrom app.api.helpers.files import create_save_pdf\nfrom app.api.helpers.storage import UPLOAD_PATHS\nfrom app.models import db\nfrom app.models.event import Event\nfrom app.models.event_invoice import EventInvoice\nfrom app.models.order import Order\nfrom app.models.speaker import Speaker\nfrom app.models.session import Session\nfrom app.models.ticket import Ticket\nfrom app.models.ticket_fee import TicketFees, get_fee\nfrom app.models.ticket_holder import TicketHolder\n\nfrom app.settings import get_settings\n\n\n@celery.task(base=RequestContextTask, name='send.after.event.mail')\ndef send_after_event_mail():\n    from app.instance import current_app as app\n    with app.app_context():\n        events = Event.query.filter_by(state='published', deleted_at=None).all()\n        for event in events:\n            organizers = get_user_event_roles_by_role_name(event.id, 'organizer')\n            speakers = Speaker.query.filter_by(event_id=event.id, deleted_at=None).all()\n            owner = get_user_event_roles_by_role_name(event.id, 'owner').first()\n            current_time = datetime.datetime.now(pytz.timezone(event.timezone))\n            time_difference = current_time - event.ends_at\n            time_difference_minutes = (time_difference.days * 24 * 60) + \\\n                (time_difference.seconds / 60)\n            frontend_url = get_settings()['frontend_url']\n            if current_time > event.ends_at and time_difference_minutes < 1440:\n                for speaker in speakers:\n                    if not speaker.is_email_overridden:\n                        send_email_after_event(speaker.user.email, event.name, frontend_url)\n                        send_notif_after_event(speaker.user, event.name)\n                for organizer in organizers:\n                    send_email_after_event(organizer.user.email, event.name, frontend_url)\n                    send_notif_after_event(organizer.user, event.name)\n                if owner:\n                    send_email_after_event(owner.user.email, event.name, frontend_url)\n                    send_notif_after_event(owner.user, event.name)\n\n\n@celery.task(base=RequestContextTask, name='change.session.state.on.event.completion')\ndef change_session_state_on_event_completion():\n    from app.instance import current_app as app\n    with app.app_context():\n        sessions_to_be_changed = Session.query.join(Event).filter(Session.state == 'pending')\\\n                                 .filter(Event.ends_at < datetime.datetime.now())\n        for session in sessions_to_be_changed:\n            session.state = 'rejected'\n            save_to_db(session, 'Changed {} session state to rejected'.format(session.title))\n\n\n@celery.task(base=RequestContextTask, name='send.event.fee.notification')\ndef send_event_fee_notification():\n    from app.instance import current_app as app\n    with app.app_context():\n        events = Event.query.filter_by(deleted_at=None, state='published').all()\n        for event in events:\n            latest_invoice = EventInvoice.query.filter_by(\n                event_id=event.id).order_by(EventInvoice.created_at.desc()).first()\n\n            if latest_invoice:\n                orders = Order.query \\\n                    .filter_by(event_id=event.id) \\\n                    .filter_by(status='completed') \\\n                    .filter(Order.completed_at > latest_invoice.created_at).all()\n            else:\n                orders = Order.query.filter_by(\n                    event_id=event.id).filter_by(status='completed').all()\n\n            fee_total = 0\n            for order in orders:\n                for order_ticket in order.tickets:\n                    ticket = safe_query(db, Ticket, 'id', order_ticket.ticket_id, 'ticket_id')\n                    if order.paid_via != 'free' and order.amount > 0 and ticket.price > 0:\n                        fee = ticket.price * (get_fee(event.payment_country, order.event.payment_currency) / 100.0)\n                        fee_total += fee\n\n            if fee_total > 0:\n                owner = get_user_event_roles_by_role_name(event.id, 'owner').first()\n                new_invoice = EventInvoice(\n                    amount=fee_total, event_id=event.id, user_id=owner.user.id)\n\n                if event.discount_code_id and event.discount_code:\n                    r = relativedelta(datetime.datetime.utcnow(), event.created_at)\n                    if r <= event.discount_code.valid_till:\n                        new_invoice.amount = fee_total - \\\n                            (fee_total * (event.discount_code.value / 100.0))\n                        new_invoice.discount_code_id = event.discount_code_id\n\n                save_to_db(new_invoice)\n                prev_month = monthdelta(new_invoice.created_at, 1).strftime(\n                    \"%b %Y\")  # Displayed as Aug 2016\n                app_name = get_settings()['app_name']\n                frontend_url = get_settings()['frontend_url']\n                link = '{}/invoices/{}'.format(frontend_url, new_invoice.identifier)\n                send_email_for_monthly_fee_payment(new_invoice.user.email,\n                                                   event.name,\n                                                   prev_month,\n                                                   new_invoice.amount,\n                                                   app_name,\n                                                   link)\n                send_notif_monthly_fee_payment(new_invoice.user,\n                                               event.name,\n                                               prev_month,\n                                               new_invoice.amount,\n                                               app_name,\n                                               link,\n                                               new_invoice.event_id)\n\n\n@celery.task(base=RequestContextTask, name='send.event.fee.notification.followup')\ndef send_event_fee_notification_followup():\n    from app.instance import current_app as app\n    with app.app_context():\n        incomplete_invoices = EventInvoice.query.filter(EventInvoice.status != 'paid').all()\n        for incomplete_invoice in incomplete_invoices:\n            if incomplete_invoice.amount > 0:\n                prev_month = monthdelta(incomplete_invoice.created_at, 1).strftime(\n                    \"%b %Y\")  # Displayed as Aug 2016\n                app_name = get_settings()['app_name']\n                frontend_url = get_settings()['frontend_url']\n                link = '{}/event-invoice/{}/review'.format(frontend_url,\n                                               incomplete_invoice.identifier)\n                send_followup_email_for_monthly_fee_payment(incomplete_invoice.user.email,\n                                                            incomplete_invoice.event.name,\n                                                            prev_month,\n                                                            incomplete_invoice.amount,\n                                                            app_name,\n                                                            link)\n                send_followup_notif_monthly_fee_payment(incomplete_invoice.user,\n                                                        incomplete_invoice.event.name,\n                                                        prev_month,\n                                                        incomplete_invoice.amount,\n                                                        app_name,\n                                                        link,\n                                                        incomplete_invoice.event.id)\n\n\n@celery.task(base=RequestContextTask, name='expire.pending.tickets')\ndef expire_pending_tickets():\n    from app.instance import current_app as app\n    with app.app_context():\n        db.session.query(Order).filter(Order.status == 'pending',\n                                       (Order.created_at + datetime.timedelta(minutes=30)) <= datetime.datetime.now()).\\\n                                       update({'status': 'expired'})\n        db.session.commit()\n\n\n@celery.task(base=RequestContextTask, name='delete.ticket.holders.no.order.id')\ndef delete_ticket_holders_no_order_id():\n    from app.instance import current_app as app\n    with app.app_context():\n        order_expiry_time = get_settings()['order_expiry_time']\n        TicketHolder.query.filter(TicketHolder.order_id == None, TicketHolder.deleted_at.is_(None),\n                                  TicketHolder.created_at + datetime.timedelta(minutes=order_expiry_time)\n                                  < datetime.datetime.utcnow()).delete(synchronize_session=False)\n        db.session.commit()\n\n\n@celery.task(base=RequestContextTask, name='event.invoices.mark.due')\ndef event_invoices_mark_due():\n    from app.instance import current_app as app\n    with app.app_context():\n        db.session.query(EventInvoice).filter(\n            EventInvoice.status == 'upcoming',\n            Event.id == EventInvoice.event_id,\n            Event.ends_at >= datetime.datetime.now(),\n            (EventInvoice.created_at + datetime.timedelta(days=30) <= datetime.datetime.now())\n        ).update({EventInvoice.status: 'due'}, synchronize_session=False)\n\n\n@celery.task(base=RequestContextTask, name='send.monthly.event.invoice')\ndef send_monthly_event_invoice():\n    from app.instance import current_app as app\n    with app.app_context():\n        events = Event.query.filter_by(deleted_at=None, state='published').all()\n        for event in events:\n            # calculate net & gross revenues\n            user = event.owner\n            admin_info = get_settings()\n            currency = event.payment_currency\n            ticket_fee_object = db.session.query(TicketFees).filter_by(currency=currency).one()\n            ticket_fee_percentage = ticket_fee_object.service_fee\n            ticket_fee_maximum = ticket_fee_object.maximum_fee\n            orders = Order.query.filter_by(event=event).all()\n            gross_revenue = event.calc_monthly_revenue()\n            ticket_fees = event.tickets_sold * (ticket_fee_percentage / 100)\n            if ticket_fees > ticket_fee_maximum:\n                ticket_fees = ticket_fee_maximum\n            net_revenue = gross_revenue - ticket_fees\n            payment_details = {\n                'tickets_sold': event.tickets_sold,\n                'gross_revenue': gross_revenue,\n                'net_revenue': net_revenue,\n                'amount_payable': ticket_fees\n            }\n            # save invoice as pdf\n            pdf = create_save_pdf(render_template('pdf/event_invoice.html', orders=orders, user=user,\n                                  admin_info=admin_info, currency=currency, event=event,\n                                  ticket_fee_object=ticket_fee_object, payment_details=payment_details,\n                                  net_revenue=net_revenue), UPLOAD_PATHS['pdf']['event_invoice'],\n                                  dir_path='/static/uploads/pdf/event_invoices/', identifier=event.identifier)\n            # save event_invoice info to DB\n\n            event_invoice = EventInvoice(amount=net_revenue, invoice_pdf_url=pdf, event_id=event.id)\n            save_to_db(event_invoice)\n\n\n@celery.on_after_configure.connect\ndef setup_scheduled_task(sender, **kwargs):\n    from celery.schedules import crontab\n    sender.add_periodic_task(crontab(hour='*/5', minute=30), send_after_event_mail)\n    sender.add_periodic_task(crontab(day_of_week='0-6'), send_event_fee_notification)\n    sender.add_periodic_task(crontab(minute=0, hour=0, day_of_month=1), send_event_fee_notification_followup)\n    sender.add_periodic_task(crontab(hour='*/5', minute=30), change_session_state_on_event_completion)\n    sender.add_periodic_task(crontab(minute='*/45'), expire_pending_tickets)\n    sender.add_periodic_task(crontab(minute=0, hour=0, day_of_month=1), send_monthly_event_invoice)\n    sender.add_periodic_task(crontab(minute=0, hour='*/5'), event_invoices_mark_due)\n    sender.add_periodic_task(crontab(minute='*/5'), delete_ticket_holders_no_order_id)\n", "path": "app/api/helpers/scheduled_jobs.py"}], "after_files": [{"content": "import datetime\n\nimport pytz\nfrom dateutil.relativedelta import relativedelta\nfrom flask import render_template\nfrom flask_celeryext import RequestContextTask\nfrom app.instance import celery\n\nfrom app.api.helpers.db import safe_query, save_to_db\nfrom app.api.helpers.mail import send_email_after_event, send_email_for_monthly_fee_payment, \\\n    send_followup_email_for_monthly_fee_payment\nfrom app.api.helpers.notification import send_notif_monthly_fee_payment, send_followup_notif_monthly_fee_payment, \\\n    send_notif_after_event\nfrom app.api.helpers.query import get_upcoming_events, get_user_event_roles_by_role_name\nfrom app.api.helpers.utilities import monthdelta\nfrom app.api.helpers.files import create_save_pdf\nfrom app.api.helpers.storage import UPLOAD_PATHS\nfrom app.models import db\nfrom app.models.event import Event\nfrom app.models.event_invoice import EventInvoice\nfrom app.models.order import Order\nfrom app.models.speaker import Speaker\nfrom app.models.session import Session\nfrom app.models.ticket import Ticket\nfrom app.models.ticket_fee import TicketFees, get_fee\nfrom app.models.ticket_holder import TicketHolder\n\nfrom app.settings import get_settings\n\n\n@celery.task(base=RequestContextTask, name='send.after.event.mail')\ndef send_after_event_mail():\n    from app.instance import current_app as app\n    with app.app_context():\n        events = Event.query.filter_by(state='published', deleted_at=None).all()\n        for event in events:\n            organizers = get_user_event_roles_by_role_name(event.id, 'organizer')\n            speakers = Speaker.query.filter_by(event_id=event.id, deleted_at=None).all()\n            owner = get_user_event_roles_by_role_name(event.id, 'owner').first()\n            current_time = datetime.datetime.now(pytz.timezone(event.timezone))\n            time_difference = current_time - event.ends_at\n            time_difference_minutes = (time_difference.days * 24 * 60) + \\\n                (time_difference.seconds / 60)\n            frontend_url = get_settings()['frontend_url']\n            if current_time > event.ends_at and time_difference_minutes < 1440:\n                for speaker in speakers:\n                    if not speaker.is_email_overridden:\n                        send_email_after_event(speaker.user.email, event.name, frontend_url)\n                        send_notif_after_event(speaker.user, event.name)\n                for organizer in organizers:\n                    send_email_after_event(organizer.user.email, event.name, frontend_url)\n                    send_notif_after_event(organizer.user, event.name)\n                if owner:\n                    send_email_after_event(owner.user.email, event.name, frontend_url)\n                    send_notif_after_event(owner.user, event.name)\n\n\n@celery.task(base=RequestContextTask, name='change.session.state.on.event.completion')\ndef change_session_state_on_event_completion():\n    from app.instance import current_app as app\n    with app.app_context():\n        sessions_to_be_changed = Session.query.join(Event).filter(Session.state == 'pending')\\\n                                 .filter(Event.ends_at < datetime.datetime.now())\n        for session in sessions_to_be_changed:\n            session.state = 'rejected'\n            save_to_db(session, 'Changed {} session state to rejected'.format(session.title))\n\n\n@celery.task(base=RequestContextTask, name='send.event.fee.notification')\ndef send_event_fee_notification():\n    from app.instance import current_app as app\n    with app.app_context():\n        events = Event.query.filter_by(deleted_at=None, state='published').all()\n        for event in events:\n            latest_invoice = EventInvoice.query.filter_by(\n                event_id=event.id).order_by(EventInvoice.created_at.desc()).first()\n\n            if latest_invoice:\n                orders = Order.query \\\n                    .filter_by(event_id=event.id) \\\n                    .filter_by(status='completed') \\\n                    .filter(Order.completed_at > latest_invoice.created_at).all()\n            else:\n                orders = Order.query.filter_by(\n                    event_id=event.id).filter_by(status='completed').all()\n\n            fee_total = 0\n            for order in orders:\n                for ticket in order.tickets:\n                    if order.paid_via != 'free' and order.amount > 0 and ticket.price > 0:\n                        fee = ticket.price * (get_fee(event.payment_country, order.event.payment_currency) / 100.0)\n                        fee_total += fee\n\n            if fee_total > 0:\n                owner = get_user_event_roles_by_role_name(event.id, 'owner').first()\n                new_invoice = EventInvoice(\n                    amount=fee_total, event_id=event.id, user_id=owner.user.id)\n\n                if event.discount_code_id and event.discount_code:\n                    r = relativedelta(datetime.datetime.utcnow(), event.created_at)\n                    if r <= event.discount_code.valid_till:\n                        new_invoice.amount = fee_total - \\\n                            (fee_total * (event.discount_code.value / 100.0))\n                        new_invoice.discount_code_id = event.discount_code_id\n\n                save_to_db(new_invoice)\n                prev_month = monthdelta(new_invoice.created_at, 1).strftime(\n                    \"%b %Y\")  # Displayed as Aug 2016\n                app_name = get_settings()['app_name']\n                frontend_url = get_settings()['frontend_url']\n                link = '{}/invoices/{}'.format(frontend_url, new_invoice.identifier)\n                send_email_for_monthly_fee_payment(new_invoice.user.email,\n                                                   event.name,\n                                                   prev_month,\n                                                   new_invoice.amount,\n                                                   app_name,\n                                                   link)\n                send_notif_monthly_fee_payment(new_invoice.user,\n                                               event.name,\n                                               prev_month,\n                                               new_invoice.amount,\n                                               app_name,\n                                               link,\n                                               new_invoice.event_id)\n\n\n@celery.task(base=RequestContextTask, name='send.event.fee.notification.followup')\ndef send_event_fee_notification_followup():\n    from app.instance import current_app as app\n    with app.app_context():\n        incomplete_invoices = EventInvoice.query.filter(EventInvoice.status != 'paid').all()\n        for incomplete_invoice in incomplete_invoices:\n            if incomplete_invoice.amount > 0:\n                prev_month = monthdelta(incomplete_invoice.created_at, 1).strftime(\n                    \"%b %Y\")  # Displayed as Aug 2016\n                app_name = get_settings()['app_name']\n                frontend_url = get_settings()['frontend_url']\n                link = '{}/event-invoice/{}/review'.format(frontend_url,\n                                               incomplete_invoice.identifier)\n                send_followup_email_for_monthly_fee_payment(incomplete_invoice.user.email,\n                                                            incomplete_invoice.event.name,\n                                                            prev_month,\n                                                            incomplete_invoice.amount,\n                                                            app_name,\n                                                            link)\n                send_followup_notif_monthly_fee_payment(incomplete_invoice.user,\n                                                        incomplete_invoice.event.name,\n                                                        prev_month,\n                                                        incomplete_invoice.amount,\n                                                        app_name,\n                                                        link,\n                                                        incomplete_invoice.event.id)\n\n\n@celery.task(base=RequestContextTask, name='expire.pending.tickets')\ndef expire_pending_tickets():\n    from app.instance import current_app as app\n    with app.app_context():\n        db.session.query(Order).filter(Order.status == 'pending',\n                                       (Order.created_at + datetime.timedelta(minutes=30)) <= datetime.datetime.now()).\\\n                                       update({'status': 'expired'})\n        db.session.commit()\n\n\n@celery.task(base=RequestContextTask, name='delete.ticket.holders.no.order.id')\ndef delete_ticket_holders_no_order_id():\n    from app.instance import current_app as app\n    with app.app_context():\n        order_expiry_time = get_settings()['order_expiry_time']\n        TicketHolder.query.filter(TicketHolder.order_id == None, TicketHolder.deleted_at.is_(None),\n                                  TicketHolder.created_at + datetime.timedelta(minutes=order_expiry_time)\n                                  < datetime.datetime.utcnow()).delete(synchronize_session=False)\n        db.session.commit()\n\n\n@celery.task(base=RequestContextTask, name='event.invoices.mark.due')\ndef event_invoices_mark_due():\n    from app.instance import current_app as app\n    with app.app_context():\n        db.session.query(EventInvoice).filter(\n            EventInvoice.status == 'upcoming',\n            Event.id == EventInvoice.event_id,\n            Event.ends_at >= datetime.datetime.now(),\n            (EventInvoice.created_at + datetime.timedelta(days=30) <= datetime.datetime.now())\n        ).update({EventInvoice.status: 'due'}, synchronize_session=False)\n\n\n@celery.task(base=RequestContextTask, name='send.monthly.event.invoice')\ndef send_monthly_event_invoice():\n    from app.instance import current_app as app\n    with app.app_context():\n        events = Event.query.filter_by(deleted_at=None, state='published').all()\n        for event in events:\n            # calculate net & gross revenues\n            user = event.owner\n            admin_info = get_settings()\n            currency = event.payment_currency\n            ticket_fee_object = db.session.query(TicketFees).filter_by(currency=currency).one()\n            ticket_fee_percentage = ticket_fee_object.service_fee\n            ticket_fee_maximum = ticket_fee_object.maximum_fee\n            orders = Order.query.filter_by(event=event).all()\n            gross_revenue = event.calc_monthly_revenue()\n            ticket_fees = event.tickets_sold * (ticket_fee_percentage / 100)\n            if ticket_fees > ticket_fee_maximum:\n                ticket_fees = ticket_fee_maximum\n            net_revenue = gross_revenue - ticket_fees\n            payment_details = {\n                'tickets_sold': event.tickets_sold,\n                'gross_revenue': gross_revenue,\n                'net_revenue': net_revenue,\n                'amount_payable': ticket_fees\n            }\n            # save invoice as pdf\n            pdf = create_save_pdf(render_template('pdf/event_invoice.html', orders=orders, user=user,\n                                  admin_info=admin_info, currency=currency, event=event,\n                                  ticket_fee_object=ticket_fee_object, payment_details=payment_details,\n                                  net_revenue=net_revenue), UPLOAD_PATHS['pdf']['event_invoice'],\n                                  dir_path='/static/uploads/pdf/event_invoices/', identifier=event.identifier)\n            # save event_invoice info to DB\n\n            event_invoice = EventInvoice(amount=net_revenue, invoice_pdf_url=pdf, event_id=event.id)\n            save_to_db(event_invoice)\n\n\n@celery.on_after_configure.connect\ndef setup_scheduled_task(sender, **kwargs):\n    from celery.schedules import crontab\n    sender.add_periodic_task(crontab(hour='*/5', minute=30), send_after_event_mail)\n    sender.add_periodic_task(crontab(day_of_week='0-6'), send_event_fee_notification)\n    sender.add_periodic_task(crontab(minute=0, hour=0, day_of_month=1), send_event_fee_notification_followup)\n    sender.add_periodic_task(crontab(hour='*/5', minute=30), change_session_state_on_event_completion)\n    sender.add_periodic_task(crontab(minute='*/45'), expire_pending_tickets)\n    sender.add_periodic_task(crontab(minute=0, hour=0, day_of_month=1), send_monthly_event_invoice)\n    sender.add_periodic_task(crontab(minute=0, hour='*/5'), event_invoices_mark_due)\n    sender.add_periodic_task(crontab(minute='*/5'), delete_ticket_holders_no_order_id)\n", "path": "app/api/helpers/scheduled_jobs.py"}]}