-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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: New Create Order API #7047
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import json | ||
from datetime import datetime | ||
|
||
import pytz | ||
|
@@ -117,100 +118,45 @@ def resend_emails(): | |
@order_blueprint.route('/calculate-amount', methods=['POST']) | ||
def calculate_amount(): | ||
data, errors = OrderAmountInputSchema().load(request.get_json()) | ||
if errors: | ||
return make_response(jsonify(errors), 422) | ||
return jsonify(calculate_order_amount(data['tickets'], data.get('discount_code'))) | ||
|
||
|
||
@order_blueprint.route('/create-order', methods=['POST']) | ||
@jwt_required | ||
def create_order(): | ||
data = request.get_json() | ||
tickets, discount_code = data['tickets'], data['discount-code'] | ||
attendee = data['attendee'] | ||
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 {}.'.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 _ in range(ticket['quantity']): | ||
attendee = TicketHolder( | ||
**result[0], event_id=int(data['event_id']), ticket_id=int(ticket['id']) | ||
) | ||
db.session.add(attendee) | ||
attendee_list.append(attendee) | ||
# created_at not getting filled | ||
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'], | ||
data, errors = OrderAmountInputSchema().load(request.get_json()) | ||
if errors: | ||
return make_response(jsonify(errors), 422) | ||
|
||
tickets_dict = data['tickets'] | ||
order_amount = calculate_order_amount(tickets_dict, data.get('discount_code')) | ||
ticket_ids = {ticket['id'] for ticket in tickets_dict} | ||
ticket_map = {int(ticket['id']): ticket for ticket in tickets_dict} | ||
tickets = ( | ||
Ticket.query.filter_by(deleted_at=None).filter(Ticket.id.in_(ticket_ids)).all() | ||
) | ||
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 | ||
|
||
for ticket in order_tickets: | ||
od = OrderTicket( | ||
order_id=order.id, ticket_id=ticket, quantity=order_tickets[ticket] | ||
if not tickets: | ||
raise UnprocessableEntityError( | ||
{'source': 'tickets'}, "Tickets missing in Order request", | ||
) | ||
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) | ||
event = tickets[0].event | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. local variable 'event' is assigned to but never used |
||
|
||
try: | ||
attendees = [] | ||
for ticket in tickets: | ||
for _ in range(ticket_map[ticket.id]['quantity']): | ||
ticket.raise_if_unavailable() | ||
attendees.append(TicketHolder(firstname='', lastname='', ticket=ticket)) | ||
db.session.commit() | ||
except Exception as e: | ||
db.session.rollback() | ||
raise e | ||
|
||
return jsonify(order_amount) | ||
|
||
|
||
@order_blueprint.route('/complete-order/<order_id>', methods=['PATCH']) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import json | ||
|
||
import pytest | ||
|
||
from tests.factories.discount_code import DiscountCodeTicketSubFactory | ||
from .test_calculate_order_amount import _create_taxed_tickets, _create_tickets | ||
from tests.factories.user import UserFactory | ||
from flask_jwt_extended.utils import create_access_token | ||
from app.models.ticket_holder import TicketHolder | ||
from tests.factories.event import EventFactoryBasic | ||
from tests.factories.order import OrderFactory, OrderSubFactory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'tests.factories.order.OrderFactory' imported but unused |
||
from tests.factories.attendee import AttendeeFactoryBase | ||
|
||
|
||
@pytest.fixture | ||
def jwt(db): | ||
user = UserFactory() | ||
db.session.commit() | ||
|
||
return {'Authorization': "JWT " + create_access_token(user.id, fresh=True)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Black would make changes. |
||
|
||
|
||
def test_create_order(client, db, jwt): | ||
discount_code = DiscountCodeTicketSubFactory(type='percent', value=10.0, tickets=[]) | ||
tickets_dict = _create_taxed_tickets( | ||
db, tax_included=False, discount_code=discount_code | ||
) | ||
db.session.commit() | ||
|
||
response = client.post( | ||
'/v1/orders/create-order', | ||
content_type='application/json', | ||
headers=jwt, | ||
data=json.dumps( | ||
{'tickets': tickets_dict, 'discount-code': str(discount_code.id)} | ||
), | ||
) | ||
|
||
assert TicketHolder.query.count() == 12 | ||
|
||
assert response.status_code == 200 | ||
amount_data = json.loads(response.data) | ||
assert amount_data['sub_total'] == 4021.87 | ||
assert amount_data['total'] == 4745.81 | ||
assert amount_data['tax']['included'] is False | ||
assert amount_data['tax']['amount'] == 723.94 | ||
|
||
|
||
def test_throw_ticket_sold_out(client, db, jwt): | ||
event = EventFactoryBasic() | ||
tickets = _create_tickets([10, 20], event=event, quantity=2) | ||
order = OrderSubFactory(status='completed', event=event) | ||
AttendeeFactoryBase.create_batch(2, order=order, ticket=tickets[0], event=event) | ||
AttendeeFactoryBase.create_batch(2, order=order, ticket=tickets[1], event=event) | ||
db.session.commit() | ||
|
||
response = client.post( | ||
'/v1/orders/create-order', | ||
content_type='application/json', | ||
headers=jwt, | ||
data=json.dumps( | ||
{ | ||
'tickets': [ | ||
{'id': tickets[0].id, 'quantity': 2}, | ||
{'id': tickets[1].id, 'quantity': 3}, | ||
] | ||
} | ||
), | ||
) | ||
|
||
assert TicketHolder.query.count() == 0 | ||
|
||
assert response.status_code == 409 | ||
assert json.loads(response.data) == { | ||
'errors': [ | ||
{ | ||
'detail': 'Ticket 5 already sold out', | ||
'source': {'id': 5}, | ||
'status': 409, | ||
'title': 'Conflict', | ||
} | ||
], | ||
'jsonapi': {'version': '1.0'}, | ||
} | ||
|
||
|
||
def test_throw_empty_tickets(client, db, jwt): | ||
response = client.post( | ||
'/v1/orders/create-order', | ||
content_type='application/json', | ||
headers=jwt, | ||
data=json.dumps({'tickets': []}), | ||
) | ||
|
||
assert response.status_code == 422 | ||
assert json.loads(response.data) == { | ||
"errors": [ | ||
{ | ||
"status": 422, | ||
"source": {"source": "tickets"}, | ||
"title": "Unprocessable Entity", | ||
"detail": "Tickets missing in Order request", | ||
} | ||
], | ||
"jsonapi": {"version": "1.0"}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'json' imported but unused