Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions app/api/attendees.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from datetime import datetime
import datetime

from flask import Blueprint, request, jsonify, abort, make_response
from flask_jwt_extended import current_user
from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship
from flask_rest_jsonapi.exceptions import ObjectNotFound
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy import or_, and_

from app.api.bootstrap import api
from app.api.helpers.db import safe_query, get_count
Expand All @@ -25,9 +26,27 @@
from app.models.ticket_holder import TicketHolder
from app.models.user import User

from app.settings import get_settings

attendee_misc_routes = Blueprint('attendee_misc', __name__, url_prefix='/v1')


def get_sold_and_reserved_tickets_count(event_id):
order_expiry_time = get_settings()['order_expiry_time']
return db.session.query(TicketHolder.id).join(Order).filter(TicketHolder.order_id == Order.id) \
.filter(Order.event_id == int(event_id),
Order.deleted_at.is_(None),
or_(Order.status == 'placed',
Order.status == 'completed',
and_(Order.status == 'initializing',
Copy link
Member

Choose a reason for hiding this comment

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

@iamareebjamal what about pending orders then? This condition will fail to count them.

Copy link
Member

Choose a reason for hiding this comment

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

How?

Copy link
Member

Choose a reason for hiding this comment

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

For pending order we give a window for 30 mins to complete payment.

Copy link
Member

Choose a reason for hiding this comment

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

So additional 30 minutes is granted to attendee inspite of order_expiry_time,which is not taken in account here.

Order.created_at + datetime.timedelta(
minutes=order_expiry_time) > datetime.datetime.utcnow()),
and_(Order.status == 'pending',
Order.created_at + datetime.timedelta(
minutes=30 + order_expiry_time) > (datetime.datetime.utcnow()))
)).count()


class AttendeeListPost(ResourceList):
"""
List and create Attendees through direct URL
Expand Down Expand Up @@ -56,8 +75,7 @@ def before_post(self, args, kwargs, data):
"Ticket belongs to a different Event"
)
# Check if the ticket is already sold out or not.
if get_count(db.session.query(TicketHolder.id).
filter_by(ticket_id=int(data['ticket']), deleted_at=None)) >= ticket.quantity:
Copy link
Member

Choose a reason for hiding this comment

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

See what was being counted

if get_sold_and_reserved_tickets_count(ticket.event_id) >= ticket.quantity:
raise ConflictException(
{'pointer': '/data/attributes/ticket_id'},
"Ticket already sold out"
Expand Down
11 changes: 7 additions & 4 deletions app/factories/attendee.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
from app.models.ticket_holder import db, TicketHolder


class AttendeeFactory(factory.alchemy.SQLAlchemyModelFactory):
class AttendeeFactoryBase(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = TicketHolder
sqlalchemy_session = db.session

event = factory.RelatedFactory(EventFactoryBasic)
ticket = factory.RelatedFactory(TicketFactory)
order = factory.RelatedFactory(OrderFactory)
firstname = common.string_
lastname = common.string_
email = common.email_
Expand All @@ -29,3 +26,9 @@ class Meta:
order_id = None
created_at = common.date_
modified_at = common.date_


class AttendeeFactory(AttendeeFactoryBase):
event = factory.RelatedFactory(EventFactoryBasic)
ticket = factory.RelatedFactory(TicketFactory)
order = factory.RelatedFactory(OrderFactory)
3 changes: 2 additions & 1 deletion app/models/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def __init__(self,
transaction_id=None,
paid_via=None,
is_billing_enabled=False,
created_at=datetime.datetime.now(datetime.timezone.utc),
Copy link
Member

Choose a reason for hiding this comment

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

This is the problem. created_at is static - set to the starting time of the server #6703

@kushthedude @codedsun

Copy link
Member

Choose a reason for hiding this comment

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

Making the PR

user_id=None,
discount_code_id=None,
event_id=None,
Expand All @@ -114,7 +115,7 @@ def __init__(self,
self.transaction_id = transaction_id
self.paid_via = paid_via
self.is_billing_enabled = is_billing_enabled
self.created_at = datetime.datetime.now(datetime.timezone.utc)
self.created_at = created_at
self.discount_code_id = discount_code_id
self.status = status
self.payment_mode = payment_mode
Expand Down
42 changes: 40 additions & 2 deletions tests/all/integration/api/helpers/test_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

from app.settings import get_settings
from app import current_app as app, db
from app.api.helpers.db import save_to_db
from app.api.helpers.order import set_expiry_for_order, delete_related_attendees_for_order
from app.factories.attendee import AttendeeFactory
import app.factories.common as common
from app.factories.attendee import AttendeeFactoryBase, AttendeeFactory
from app.factories.event import EventFactoryBasic
from app.factories.ticket import TicketFactory
from app.factories.order import OrderFactory
from app.models.order import Order
from app.api.helpers.db import save_to_db
from app.api.attendees import get_sold_and_reserved_tickets_count
from tests.all.integration.setup_database import Setup
from tests.all.integration.utils import OpenEventTestCase

Expand Down Expand Up @@ -54,6 +56,42 @@ def test_should_delete_related_attendees(self):
order = db.session.query(Order).filter(Order.id == obj.id).first()
self.assertEqual(len(order.ticket_holders), 0)

def test_count_sold_and_reserved_tickets(self):
"""Method to test the count query of sold tickets"""

with app.test_request_context():
ticket = TicketFactory()

completed_order = OrderFactory(status='completed')
placed_order = OrderFactory(status='placed')
initializing_order = OrderFactory(status='initializing',
created_at=datetime.utcnow() - timedelta(minutes=5))
pending_order = OrderFactory(status='pending',
created_at=datetime.utcnow() - timedelta(minutes=35))
expired_time_order = OrderFactory(status='initializing', created_at=common.date_)
expired_order = OrderFactory(status='expired')

db.session.commit()

# will not be counted as they have no order_id
AttendeeFactoryBase.create_batch(2)
# will be counted as attendee have valid orders
AttendeeFactoryBase.create_batch(6, order_id=completed_order.id)
# will be counted as attendee has valid placed order
AttendeeFactoryBase(order_id=placed_order.id)
# will be counted as attendee has initializing order under order expiry time
AttendeeFactoryBase.create_batch(4, order_id=initializing_order.id)
# will be counted as attendee has pending order under 30+order expiry time
AttendeeFactoryBase.create_batch(2, order_id=pending_order.id)
# will not be counted as the order is not under order expiry time
AttendeeFactoryBase.create_batch(3, order_id=expired_time_order.id)
# will not be counted as the order has an expired state
AttendeeFactoryBase.create_batch(5, order_id=expired_order.id)

count = get_sold_and_reserved_tickets_count(ticket.event_id)

self.assertEqual(count, 13)


if __name__ == '__main__':
unittest.main()