Repository: fossasia/open-event-server

Issue:
Feature to send receipt to attendee via email
**Is your feature request related to a problem? Please describe.**
After an order is created there should be a feature to send the receipt of the order to the attendee. In the Eventbrite Organizers app, there is a feature to send a receipt of the order to the email of the attendee through a common email ```orders@eventbrite.com```.

**Screenshot**
![ezgif com-resize 27](https://user-images.githubusercontent.com/20684618/42098147-aa4bc84a-7bd7-11e8-85c4-b124c311ed17.gif)

**Willing to work on this issue**
No. Please anyone take this up.


Discussion:
There is a function to send email to attendees after an order is completed:
https://github.com/fossasia/open-event-server/blob/1cd188b9df867945af354a1ad544017e16253c8d/app/api/orders.py#L125

Is this the feature you're looking for?
@schedutron That is sent once the order is completed. Only once. What he wants is some sort of feature so that the receipt/email can be sent again. (something like resending the verification email).

You can take it if you want. 
@schedutron @mayank8318 @Kreijstal If anyone is short of issues then please take this one. It's a blocker in the orga app. 

Resolving patch:
diff --git a/app/__init__.py b/app/__init__.py
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -114,14 +114,15 @@ def create_app():
 
     # development api
     with app.app_context():
+        from app.api.admin_statistics_api.events import event_statistics
+        from app.api.auth import auth_routes
+        from app.api.attendees import attendee_misc_routes
         from app.api.bootstrap import api_v1
-        from app.api.uploads import upload_routes
-        from app.api.exports import export_routes
-        from app.api.imports import import_routes
         from app.api.celery_tasks import celery_routes
-        from app.api.auth import auth_routes
-        from app.api.admin_statistics_api.events import event_statistics
         from app.api.event_copy import event_copy
+        from app.api.exports import export_routes
+        from app.api.imports import import_routes
+        from app.api.uploads import upload_routes
         from app.api.users import user_misc_routes
 
         app.register_blueprint(api_v1)
@@ -133,6 +134,7 @@ def create_app():
         app.register_blueprint(auth_routes)
         app.register_blueprint(event_statistics)
         app.register_blueprint(user_misc_routes)
+        app.register_blueprint(attendee_misc_routes)
 
     sa.orm.configure_mappers()
 
diff --git a/app/api/attendees.py b/app/api/attendees.py
--- a/app/api/attendees.py
+++ b/app/api/attendees.py
@@ -1,5 +1,8 @@
-from flask_jwt import current_identity
+from flask import Blueprint, request, jsonify, abort, make_response
+from flask_jwt import current_identity, jwt_required
 from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship
+from flask_rest_jsonapi.exceptions import ObjectNotFound
+from sqlalchemy.orm.exc import NoResultFound
 
 from app.api.bootstrap import api
 from app.api.helpers.db import safe_query, get_count
@@ -8,6 +11,7 @@
     ForbiddenException,
     UnprocessableEntity,
 )
+from app.api.helpers.mail import send_email_to_attendees
 from app.api.helpers.permission_manager import has_access
 from app.api.helpers.permissions import jwt_required
 from app.api.helpers.query import event_query
@@ -19,6 +23,7 @@
 from app.models.ticket_holder import TicketHolder
 from app.models.user import User
 
+attendee_misc_routes = Blueprint('attendee_misc', __name__, url_prefix='/v1')
 
 class AttendeeListPost(ResourceList):
     """
@@ -183,3 +188,30 @@ class AttendeeRelationshipOptional(ResourceRelationship):
     schema = AttendeeSchema
     data_layer = {'session': db.session,
                   'model': TicketHolder}
+
+
+@attendee_misc_routes.route('/attendees/send-receipt', methods=['POST'])
+@jwt_required
+def send_receipt():
+    order_id = request.json.get('order-id')
+    if order_id:
+        try:
+            order = db.session.query(Order).filter_by(id=int(order_id)).one()
+        except NoResultFound:
+            raise ObjectNotFound({'parameter': '{id}'}, "Order not found")
+
+        if order.user_id != current_identity.id:
+            abort(
+                make_response(jsonify(error="You cannot send reciept for an order not created by you"), 403)
+            )
+        elif order.status != 'completed':
+            abort(
+                make_response(jsonify(error="Cannot send receipt for an incomplete order"), 409)
+            )
+        else:
+            send_email_to_attendees(order, current_identity.id)
+            return jsonify(message="receipt sent to attendees")
+    else:
+        abort(
+            make_response(jsonify(error="Order id missing"), 422)
+        )


Test patch: