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
Merged
86 changes: 74 additions & 12 deletions app/api/custom/orders.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
from flask import Blueprint, jsonify, request
import json

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'json' imported but unused


from flask import Blueprint, jsonify, request, make_response
from flask_jwt_extended import current_user, jwt_required
from flask_limiter.util import get_remote_address
from sqlalchemy.orm.exc import NoResultFound


from app import limiter
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.models.discount_code import DiscountCode
from app.models.order import Order
from app.models.order import 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 @@ -83,13 +87,71 @@ def resend_emails():
@order_blueprint.route('/calculate-amount', methods=['POST'])
@jwt_required
def calculate_amount():
data = request.get_json()
return jsonify(calculate_order_amount(data))


@order_blueprint.route('/create-order', methods=['POST'])
@jwt_required
def create_order():
data = request.get_json()
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()
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(data)
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)

return jsonify(calculate_order_amount(tickets, discount_code))
order.quantity = order.tickets_count
db.session.add(order)
db.session.commit()
db.session.refresh(order)
order_schema = OrderSchema()
return order_schema.dump(order)
20 changes: 15 additions & 5 deletions app/api/helpers/order.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import logging
from datetime import timedelta, datetime, timezone

from flask import render_template
from flask import render_template, jsonify

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'flask.jsonify' imported but unused


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.db import save_to_db, safe_query_without_soft_deleted_entries, get_count, safe_query
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
from app.models.ticket import Ticket
from app.models.discount_code import DiscountCode
from app.models.ticket_fee import TicketFees
from app.models.ticket_holder import TicketHolder
from app.models.order import OrderTicket
Expand Down Expand Up @@ -134,7 +135,16 @@ def create_onsite_attendees_for_order(data):
del data['on_site_tickets']


def calculate_order_amount(tickets, discount_code):
def calculate_order_amount(data):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change the function signature, it was fine. This should take tickets and discount code only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a wrapper function if you want to

from app.api.helpers.ticketing import TicketingManager
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()

event = tax = tax_included = fees = None
total_amount = total_tax = total_discount = 0.0
ticket_list = []
Expand Down Expand Up @@ -214,4 +224,4 @@ def calculate_order_amount(tickets, discount_code):
'sub_total': round(sub_total, 2)
})
return dict(tax_included=tax_included, total_amount=round(total_amount, 2), total_tax=round(total_tax, 2),
total_discount=round(total_discount, 2), tickets=ticket_list)
total_discount=round(total_discount, 2), tickets=ticket_list)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line over-indented for visual indent