Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Single endpoint for creating creating an order #6635

Merged
merged 16 commits into from
Jan 5, 2020
92 changes: 81 additions & 11 deletions app/api/custom/orders.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
from flask import Blueprint, jsonify, request
from flask import Blueprint, jsonify, request, make_response
from flask_jwt_extended import current_user, jwt_required
from sqlalchemy.orm.exc import NoResultFound


from app.models import db
from app.api.auth import return_file
from app.api.helpers.db import safe_query
from app.api.helpers.db import safe_query, get_count
from app.api.helpers.mail import send_email_to_attendees
from app.api.helpers.errors import ForbiddenError, UnprocessableEntityError, NotFoundError
from app.api.helpers.order import calculate_order_amount, create_pdf_tickets_for_holder
from app.api.helpers.storage import UPLOAD_PATHS
from app.api.helpers.storage import generate_hash
from app.api.helpers.ticketing import TicketingManager
from app.api.schema.attendees import AttendeeSchema
from app.api.schema.orders import OrderSchema
from app.api.helpers.permission_manager import has_access
from app.extensions.limiter import limiter
from app.models.discount_code import DiscountCode
from app.models.order import Order
from app.models.order import Order, OrderTicket
from app.models.ticket import Ticket
from app.models.ticket_holder import TicketHolder

order_blueprint = Blueprint('order_blueprint', __name__, url_prefix='/v1/orders')
ticket_blueprint = Blueprint('ticket_blueprint', __name__, url_prefix='/v1/tickets')
Expand Down Expand Up @@ -79,16 +81,84 @@ def resend_emails():
return ForbiddenError({'source': ''}, "Co-Organizer Access Required").respond()


@order_blueprint.route('/calculate-amount', methods=['POST'])
@jwt_required
def calculate_amount():
data = request.get_json()
def calculate_order_amount_wrapper(data):
tickets = data['tickets']
discount_code = None
if 'discount-code' in data:
discount_code_id = data['discount-code']
discount_code = safe_query(db, DiscountCode, 'id', discount_code_id, 'id')
if not TicketingManager.match_discount_quantity(discount_code, tickets, None):
return UnprocessableEntityError({'source': 'discount-code'}, 'Discount Usage Exceeded').respond()
return tickets, discount_code


@order_blueprint.route('/calculate-amount', methods=['POST'])
@jwt_required
def calculate_amount():
data = request.get_json()
tickets, discount_code = calculate_order_amount_wrapper(data)
return jsonify(calculate_order_amount(tickets, discount_code))


@order_blueprint.route('/create-order', methods=['POST'])
@jwt_required
def create_order():
data = request.get_json()
tickets, discount_code = calculate_order_amount_wrapper(data)
attendee = data['attendee']
prateekj117 marked this conversation as resolved.
Show resolved Hide resolved
for attribute in attendee:
attendee[attribute.replace('-', '_')] = attendee.pop(attribute)
schema = AttendeeSchema()
json_api_attendee = {"data": {"attributes": data['attendee'], "type": "attendee"}}
result = schema.load(json_api_attendee)
if result.errors:
return make_response(jsonify(result.errors), 422)
ticket_ids = {int(ticket['id']) for ticket in tickets}
quantity = {int(ticket['id']): ticket['quantity'] for ticket in tickets}
ticket_list = db.session.query(Ticket).filter(Ticket.id.in_(ticket_ids)).filter_by(event_id=data['event_id'],
deleted_at=None).all()
ticket_ids_found = {ticket_information.id for ticket_information in ticket_list}
tickets_not_found = ticket_ids - ticket_ids_found
if tickets_not_found:
return make_response(jsonify(status='Order Unsuccessful', error='Tickets with id {} were not found in Event {}.'
prateekj117 marked this conversation as resolved.
Show resolved Hide resolved
.format(tickets_not_found, data['event_id'])), 404)
for ticket_info in ticket_list:
if (ticket_info.quantity - get_count(db.session.query(TicketHolder.id).filter_by(
ticket_id=int(ticket_info.id), deleted_at=None))) < quantity[ticket_info.id]:
return make_response(jsonify(status='Order Unsuccessful', error='Ticket already sold out.'), 409)
attendee_list = []
for ticket in tickets:
for ticket_amount in range(ticket['quantity']):
prateekj117 marked this conversation as resolved.
Show resolved Hide resolved
prateekj117 marked this conversation as resolved.
Show resolved Hide resolved
attendee = TicketHolder(**result[0], event_id=int(data['event_id']), ticket_id=int(ticket['id']))
prateekj117 marked this conversation as resolved.
Show resolved Hide resolved
db.session.add(attendee)
attendee_list.append(attendee)
ticket_pricing = calculate_order_amount(tickets, discount_code)
if not has_access('is_coorganizer', event_id=data['event_id']):
data['status'] = 'initializing'
# create on site attendees
# check if order already exists for this attendee.
# check for free tickets and verified user
order = Order(amount=ticket_pricing['total_amount'], user_id=current_user.id, event_id=int(data['event_id']),
status=data['status'])
db.session.add(order)
db.session.commit()
db.session.refresh(order)
order_tickets = {}
for holder in attendee_list:
holder.order_id = order.id
db.session.add(holder)
if not order_tickets.get(holder.ticket_id):
order_tickets[holder.ticket_id] = 1
else:
order_tickets[holder.ticket_id] += 1

create_pdf_tickets_for_holder(order)

for ticket in order_tickets:
od = OrderTicket(order_id=order.id, ticket_id=ticket, quantity=order_tickets[ticket])
db.session.add(od)

order.quantity = order.tickets_count
db.session.add(order)
db.session.commit()
db.session.refresh(order)
order_schema = OrderSchema()
return order_schema.dump(order)
7 changes: 6 additions & 1 deletion app/api/helpers/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from flask import render_template

from app.settings import get_settings
from app.api.helpers import ticketing
from app.api.helpers.db import save_to_db, safe_query_without_soft_deleted_entries, get_count
from app.api.helpers.exceptions import UnprocessableEntity, ConflictException
from app.api.helpers.errors import UnprocessableEntityError
from app.api.helpers.files import create_save_pdf
from app.api.helpers.storage import UPLOAD_PATHS
from app.models import db
Expand Down Expand Up @@ -135,6 +135,11 @@ def create_onsite_attendees_for_order(data):


def calculate_order_amount(tickets, discount_code):
from app.api.helpers.ticketing import TicketingManager
if discount_code:
if not TicketingManager.match_discount_quantity(discount_code, tickets, None):
return UnprocessableEntityError({'source': 'discount-code'}, 'Discount Usage Exceeded').respond()

event = tax = tax_included = fees = None
total_amount = total_tax = total_discount = 0.0
ticket_list = []
Expand Down