Repository: fossasia/open-event-server

Issue:
Make ticket_id and event_id not null in TicketHolder
Self explanatory


Discussion:
Working on this
hey ! is the issue resolved ? If not can I work on it ?
Hi @iamareebjamal  i am a newbie. Can i work on this issue ?
Yes
is this issue still open?
Looks like that to me
![image](https://user-images.githubusercontent.com/3874064/81781084-35577f80-9515-11ea-944f-96b01988e9f2.png)
 
This is my first time trying to contribute to an  open source, so please let me know can I take this issue if its still open
https://github.com/fossasia/open-event-server/issues/6669#issuecomment-627788095
Working on this issue if it's still open!

Can i work ?

Yes you can

On Mon, 22 Jun 2020 at 11:34 AM, satyasai7 <notifications@github.com> wrote:

> Can i work ?
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/fossasia/open-event-server/issues/6669#issuecomment-647315575>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AIFQY6SZKZLOX3BOUVDB34TRX33P5ANCNFSM4J27NSUQ>
> .
>

Can I work on this issue?
Yes you can

On Sat, 27 Jun 2020 at 11:55 AM, Burhanuddin Kamlapurwala <
notifications@github.com> wrote:

> Can I work on this issue?
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/fossasia/open-event-server/issues/6669#issuecomment-650509597>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AIFQY6VSBEPI6NOVNEKI7QDRYWJWBANCNFSM4J27NSUQ>
> .
>

This is gonna be my first contribution, Can you please navigate me to the file or location where I need to do the change
First you need to understand the project. Unfortunately, we can't spoonfeed you the steps
Sure, I will check it out. Thank you

Resolving patch:
diff --git a/app/api/custom/orders.py b/app/api/custom/orders.py
--- a/app/api/custom/orders.py
+++ b/app/api/custom/orders.py
@@ -149,7 +149,9 @@ def create_order():
         for ticket in tickets:
             for _ in range(ticket_map[ticket.id]['quantity']):
                 ticket.raise_if_unavailable()
-                attendees.append(TicketHolder(firstname='', lastname='', ticket=ticket))
+                attendees.append(
+                    TicketHolder(firstname='', lastname='', ticket=ticket, event=event)
+                )
                 db.session.commit()
     except Exception as e:
         db.session.rollback()
diff --git a/app/models/ticket_holder.py b/app/models/ticket_holder.py
--- a/app/models/ticket_holder.py
+++ b/app/models/ticket_holder.py
@@ -40,7 +40,7 @@ class TicketHolder(SoftDeletionModel):
     birth_date: datetime = db.Column(db.DateTime(timezone=True))
     pdf_url: str = db.Column(db.String)
     ticket_id: int = db.Column(
-        db.Integer, db.ForeignKey('tickets.id', ondelete='CASCADE')
+        db.Integer, db.ForeignKey('tickets.id', ondelete='CASCADE'), nullable=False
     )
     order_id: int = db.Column(db.Integer, db.ForeignKey('orders.id', ondelete='CASCADE'))
     is_checked_in: bool = db.Column(db.Boolean, default=False)
@@ -49,7 +49,9 @@ class TicketHolder(SoftDeletionModel):
     checkin_times: str = db.Column(db.String)
     checkout_times: str = db.Column(db.String)
     attendee_notes: str = db.Column(db.String)
-    event_id: int = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'))
+    event_id: int = db.Column(
+        db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'), nullable=False
+    )
     created_at: datetime = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
     modified_at: datetime = db.Column(
         db.DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow
diff --git a/migrations/versions/rev-2020-06-29-02:39:51-64439b77fa6d_.py b/migrations/versions/rev-2020-06-29-02:39:51-64439b77fa6d_.py
new file mode 100644
--- /dev/null
+++ b/migrations/versions/rev-2020-06-29-02:39:51-64439b77fa6d_.py
@@ -0,0 +1,38 @@
+"""empty message
+
+Revision ID: 64439b77fa6d
+Revises: abc8b96ce72c
+Create Date: 2020-06-29 02:39:51.364914
+
+"""
+
+from alembic import op
+import sqlalchemy as sa
+import sqlalchemy_utils
+
+
+# revision identifiers, used by Alembic.
+revision = '64439b77fa6d'
+down_revision = 'abc8b96ce72c'
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.alter_column('ticket_holders', 'event_id',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+    op.alter_column('ticket_holders', 'ticket_id',
+               existing_type=sa.INTEGER(),
+               nullable=False)
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.alter_column('ticket_holders', 'ticket_id',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+    op.alter_column('ticket_holders', 'event_id',
+               existing_type=sa.INTEGER(),
+               nullable=True)
+    # ### end Alembic commands ###


Test patch:
diff --git a/tests/all/integration/api/custom_forms/test_custom_forms_api.py b/tests/all/integration/api/custom_forms/test_custom_forms_api.py
--- a/tests/all/integration/api/custom_forms/test_custom_forms_api.py
+++ b/tests/all/integration/api/custom_forms/test_custom_forms_api.py
@@ -17,7 +17,6 @@ def test_custom_form_create(db, client, user, jwt):
                     "form": "attendee",
                     "type": "email",
                     "field-identifier": "email",
-                    "name": "Email",
                     "is-included": True,
                     "is-required": True,
                     "is-complex": True,
@@ -42,6 +41,7 @@ def test_custom_form_create(db, client, user, jwt):
 
     assert custom_form.form == 'attendee'
     assert custom_form.type == 'email'
+    assert custom_form.name == 'Email'
     assert custom_form.field_identifier == 'email'
     assert custom_form.is_complex is False
 
diff --git a/tests/all/integration/api/helpers/order/test_create_order.py b/tests/all/integration/api/helpers/order/test_create_order.py
--- a/tests/all/integration/api/helpers/order/test_create_order.py
+++ b/tests/all/integration/api/helpers/order/test_create_order.py
@@ -59,8 +59,11 @@ def test_create_order_without_discount(client, db, jwt):
     order = Order.query.get(order_dict['data']['id'])
     assert order_dict['data']['attributes']['amount'] == 5240.73
     assert order.amount == 5240.73
-    assert len(order.ticket_holders) == 12
+    ticket_holders = order.ticket_holders
+    assert len(ticket_holders) == 12
     assert order.discount_code is None
+    for ticket_holder in ticket_holders:
+        assert ticket_holder.event_id is not None
 
 
 def test_throw_ticket_sold_out(client, db, jwt):
diff --git a/tests/all/integration/api/helpers/order/test_validate_discount_code.py b/tests/all/integration/api/helpers/order/test_validate_discount_code.py
--- a/tests/all/integration/api/helpers/order/test_validate_discount_code.py
+++ b/tests/all/integration/api/helpers/order/test_validate_discount_code.py
@@ -104,11 +104,9 @@ def test_validate_discount_code_reject_future(db):
 
 def _create_discounted_attendees(db):
     discount, tickets = _create_discount_code(db)
-    order_with_discount = OrderSubFactory(
-        status='completed', discount_code=discount, event=discount.event
-    )
+    order_with_discount = OrderSubFactory(status='completed', discount_code=discount)
     AttendeeSubFactory.create_batch(
-        3, order=order_with_discount, event=discount.event, ticket_id=tickets[0]['id']
+        3, order=order_with_discount, ticket_id=tickets[0]['id']
     )
     db.session.commit()
 
diff --git a/tests/all/integration/api/helpers/test_order.py b/tests/all/integration/api/helpers/test_order.py
--- a/tests/all/integration/api/helpers/test_order.py
+++ b/tests/all/integration/api/helpers/test_order.py
@@ -9,7 +9,7 @@
 from app.models.order import Order
 from app.settings import get_settings
 from tests.all.integration.utils import OpenEventTestCase
-from tests.factories.attendee import AttendeeFactoryBase
+from tests.factories.attendee import AttendeeFactoryBase, AttendeeSubFactory
 from tests.factories.event import EventFactoryBasic
 from tests.factories.order import OrderFactory
 from tests.factories.ticket import TicketFactory
@@ -45,7 +45,7 @@ def test_should_delete_related_attendees(self):
         """Method to test to delete related attendees of an event"""
 
         with self.app.test_request_context():
-            attendee = AttendeeFactoryBase(event_id=EventFactoryBasic().id)
+            attendee = AttendeeSubFactory()
 
             obj = OrderFactory(event_id=attendee.event_id)
             obj.ticket_holders = [
@@ -61,6 +61,7 @@ def test_count_sold_and_reserved_tickets(self):
         """Method to test the count query of sold tickets"""
 
         with self.app.test_request_context():
+            event = EventFactoryBasic()
             ticket = TicketFactory()
             other_ticket = TicketFactory()
 
@@ -80,39 +81,45 @@ def test_count_sold_and_reserved_tickets(self):
             db.session.commit()
 
             # will not be counted as they have no order_id
-            AttendeeFactoryBase.create_batch(2, ticket_id=ticket.id)
+            AttendeeFactoryBase.create_batch(2, ticket_id=ticket.id, event_id=event.id)
             # will be counted as attendee have valid orders
             AttendeeFactoryBase.create_batch(
-                6, order_id=completed_order.id, ticket_id=ticket.id
+                6, order_id=completed_order.id, ticket_id=ticket.id, event_id=event.id
             )
             # will be counted as attendee has valid placed order
-            AttendeeFactoryBase(order_id=placed_order.id, ticket_id=ticket.id)
+            AttendeeFactoryBase(
+                order_id=placed_order.id, ticket_id=ticket.id, event_id=event.id
+            )
             # will not be counted as they are deleted
             AttendeeFactoryBase.create_batch(
                 3,
                 order_id=placed_order.id,
                 ticket_id=ticket.id,
+                event_id=event.id,
                 deleted_at=datetime.utcnow(),
             )
             # will be counted as attendee has initializing order under order expiry time
             AttendeeFactoryBase.create_batch(
-                4, order_id=initializing_order.id, ticket_id=ticket.id
+                4, order_id=initializing_order.id, ticket_id=ticket.id, event_id=event.id
             )
             # will be counted as attendee has pending order under 30+order expiry time
             AttendeeFactoryBase.create_batch(
-                2, order_id=pending_order.id, ticket_id=ticket.id
+                2, order_id=pending_order.id, ticket_id=ticket.id, event_id=event.id
             )
             # will not be counted as the order is not under order expiry time
             AttendeeFactoryBase.create_batch(
-                3, order_id=expired_time_order.id, ticket_id=ticket.id
+                3, order_id=expired_time_order.id, ticket_id=ticket.id, event_id=event.id
             )
             # will not be counted as the order has an expired state
             AttendeeFactoryBase.create_batch(
-                5, order_id=expired_order.id, ticket_id=ticket.id
+                5, order_id=expired_order.id, ticket_id=ticket.id, event_id=event.id
             )
             # will not be counted as the attendees have different ticket ID
             AttendeeFactoryBase.create_batch(
-                2, order_id=completed_order.id, ticket_id=other_ticket.id
+                2,
+                order_id=completed_order.id,
+                ticket_id=other_ticket.id,
+                event_id=event.id,
             )
 
             count = get_sold_and_reserved_tickets_count(ticket.id)
diff --git a/tests/all/integration/api/helpers/test_scheduled_jobs.py b/tests/all/integration/api/helpers/test_scheduled_jobs.py
--- a/tests/all/integration/api/helpers/test_scheduled_jobs.py
+++ b/tests/all/integration/api/helpers/test_scheduled_jobs.py
@@ -12,11 +12,7 @@
 from app.models.event_invoice import EventInvoice
 from app.models.ticket_holder import TicketHolder
 from app.settings import get_settings
-from tests.factories.attendee import (
-    AttendeeFactoryBase,
-    AttendeeOrderSubFactory,
-    AttendeeSubFactory,
-)
+from tests.factories.attendee import AttendeeOrderSubFactory, AttendeeSubFactory
 from tests.factories.event_invoice import EventInvoiceSubFactory
 from tests.factories.order import OrderSubFactory
 from tests.factories.ticket_fee import TicketFeesFactory
@@ -52,7 +48,7 @@ def test_delete_ticket_holder_with_valid_order_id(db):
 
 def test_delete_ticket_holders_with_no_order_id(db):
     """Method to test deleting ticket holders with no order id after expiry time"""
-    attendee = AttendeeFactoryBase(created_at=common.date_)
+    attendee = AttendeeSubFactory(created_at=common.date_)
     db.session.commit()
     attendee_id = attendee.id
     delete_ticket_holders_no_order_id()
diff --git a/tests/all/integration/api/helpers/test_ticketing.py b/tests/all/integration/api/helpers/test_ticketing.py
--- a/tests/all/integration/api/helpers/test_ticketing.py
+++ b/tests/all/integration/api/helpers/test_ticketing.py
@@ -1,13 +1,13 @@
 from tests.factories.attendee import AttendeeFactoryBase
 from tests.factories.discount_code import DiscountCodeTicketFactory
 from tests.factories.order import OrderFactory
-from tests.factories.ticket import TicketFactory
+from tests.factories.ticket import TicketSubFactory
 
 
 def test_match_discount_quantity(db):
     """Method to test the quantity calculation of discount code"""
 
-    ticket = TicketFactory()
+    ticket = TicketSubFactory()
     discount_code = DiscountCodeTicketFactory(tickets_number=5)
     discount_code.tickets.append(ticket)
 
@@ -17,7 +17,10 @@ def test_match_discount_quantity(db):
 
     # Attendees associated with the order without discount code should not be counted
     AttendeeFactoryBase.create_batch(
-        10, order_id=order_without_discount.id, ticket_id=ticket.id
+        10,
+        order_id=order_without_discount.id,
+        ticket_id=ticket.id,
+        event_id=ticket.event_id,
     )
 
     assert discount_code.is_available(ticket_holders=[1]) is True
@@ -30,7 +33,7 @@ def test_match_discount_quantity(db):
 
     # Attendees associated with the order with discount code should be counted
     AttendeeFactoryBase.create_batch(
-        5, order_id=order_with_discount.id, ticket_id=ticket.id
+        5, order_id=order_with_discount.id, ticket_id=ticket.id, event_id=ticket.event_id
     )
 
     assert discount_code.is_available(ticket_holders=[1]) is False
diff --git a/tests/factories/attendee.py b/tests/factories/attendee.py
--- a/tests/factories/attendee.py
+++ b/tests/factories/attendee.py
@@ -28,6 +28,7 @@ class Meta:
 
 class AttendeeSubFactory(AttendeeFactoryBase):
     event = factory.SubFactory(EventFactoryBasic)
+    ticket = factory.SubFactory(TicketSubFactory)
 
 
 class AttendeeOrderSubFactory(AttendeeSubFactory):
@@ -35,7 +36,7 @@ class AttendeeOrderSubFactory(AttendeeSubFactory):
 
 
 class AttendeeOrderTicketSubFactory(AttendeeOrderSubFactory):
-    ticket = factory.SubFactory(TicketSubFactory)
+    pass
 
 
 class AttendeeFactory(AttendeeFactoryBase):
@@ -43,3 +44,4 @@ class AttendeeFactory(AttendeeFactoryBase):
     ticket = factory.RelatedFactory(TicketFactory)
     order = factory.RelatedFactory(OrderFactory)
     event_id = 1
+    ticket_id = 1