Repository: fossasia/open-event-server

Issue:
Same Discount Code is not able to be applied for two different events
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
Currently if you create two same discount codes for two events , You will see it is invalid for one of the event

**To Reproduce**

Steps to reproduce the behavior:

- Create Discount Code X for Event A
- Create Discount Code X for Event B
- Apply X to B 
- See Error

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
Same Discount Should be able to apply

#### Screenshot

<img width="1440" alt="Screenshot 2019-06-07 at 5 49 25 PM" src="https://user-images.githubusercontent.com/44091822/59103489-a3caaf80-894c-11e9-81a8-757cc6e7f3b3.png">



Discussion:
@uds5501 @shreyanshdwivedi Can you check reproducibility ?
@uds5501 Yes it is. I will take a look at it.
@uds5501 In case you are busy, can I take this one up.

@prateekj117 please feel free to do so, ask @kushthedude to assign you this issue
@uds5501 @kushthedude I am not able to face this issue, instead of going request to 'discount-code', the request goes to 'access-code', which makes me wonder what's the difference between them. The issue does not exist if there are two same 'access-codes' for different events.
@mrsaicharan1 @shreyanshdwivedi Your views on this?
@uds5501 @iamareebjamal @mrsaicharan1 Here the problem is, we query discount code only by its name, and event_id is not passed in params.
So there is no way to query it using event. What should be the way to go about it?
Paste the query here
@iamareebjamal 
`discount = db.session.query(DiscountCode).filter_by(code=kwargs.get('code'), deleted_at=None).first()`
>  we query discount code only by its name, and event_id is not passed in params.

The query browser is making

```python
discount = db.session.query(DiscountCode).filter_by(code=kwargs.get('code'), deleted_at=None).first()
```

That's really really bad
@iamareebjamal I checked the kwargs, event_id is not being passed from frontend as well.
> The query browser is making

?
@prateekj117 That's why I asked, what query is coming from frontend?
@iamareebjamal 
![Screenshot from 2019-07-14 00-22-52](https://user-images.githubusercontent.com/31065687/61175469-a19fe480-a5cd-11e9-8909-849162095017.png)

Change the access code accessor to `/event/<event-id>/access-code/<access-code-id>` as it should have been

Change to be done in both server and client.

This is a high priority change. So don't take a lot of time please

Resolving patch:
diff --git a/app/api/__init__.py b/app/api/__init__.py
--- a/app/api/__init__.py
+++ b/app/api/__init__.py
@@ -1,90 +1,90 @@
+from app.api.access_codes import AccessCodeList, AccessCodeListPost, AccessCodeDetail, AccessCodeRelationshipRequired, \
+    AccessCodeRelationshipOptional
+from app.api.activities import ActivityList, ActivityDetail
+from app.api.admin_sales.discounted import AdminSalesDiscountedList
+from app.api.admin_sales.events import AdminSalesByEventsList
+from app.api.admin_sales.fees import AdminSalesFeesList
+from app.api.admin_sales.invoices import AdminSalesInvoicesList
+from app.api.admin_sales.locations import AdminSalesByLocationList
+from app.api.admin_sales.marketer import AdminSalesByMarketerList
+from app.api.admin_sales.organizer import AdminSalesByOrganizersList
+from app.api.admin_statistics_api.events import AdminStatisticsEventDetail
+from app.api.admin_statistics_api.mails import AdminStatisticsMailDetail
+from app.api.admin_statistics_api.sessions import AdminStatisticsSessionDetail
+from app.api.admin_statistics_api.users import AdminStatisticsUserDetail
+from app.api.attendees import AttendeeList, AttendeeDetail, AttendeeRelationshipOptional, \
+    AttendeeRelationshipRequired, AttendeeListPost
 from app.api.bootstrap import api
-from app.api.event_orga import EventOrgaDetail
-from app.api.stripe_authorization import StripeAuthorizationDetail, StripeAuthorizationRelationship, \
-    StripeAuthorizationListPost
-from app.api.ticket_fees import TicketFeeList, TicketFeeDetail
-from app.api.users import UserList, UserDetail, UserRelationship
-from app.api.user_emails import UserEmailListAdmin, UserEmailListPost, UserEmailList, UserEmailDetail, \
-    UserEmailRelationship
-from app.api.user_favourite_events import UserFavouriteEventListPost, UserFavouriteEventList, \
-    UserFavouriteEventDetail, UserFavouriteEventRelationship
-from app.api.notifications import NotificationList, NotificationListAdmin, NotificationDetail,\
-    NotificationRelationship, NotificationActionDetail, NotificationActionRelationship, NotificationActionList
+from app.api.custom_forms import CustomFormList, CustomFormListPost, CustomFormDetail, CustomFormRelationshipRequired
+from app.api.custom_placeholders import CustomPlaceholderList, CustomPlaceholderDetail, CustomPlaceholderRelationship
+from app.api.custom_system_roles import CustomSystemRoleList, CustomSystemRoleDetail, CustomSystemRoleRelationship
+from app.api.discount_codes import DiscountCodeList, DiscountCodeDetail, DiscountCodeRelationshipOptional, \
+    DiscountCodeRelationshipRequired, DiscountCodeListPost
 from app.api.email_notifications import EmailNotificationList, EmailNotificationListAdmin, EmailNotificationDetail, \
     EmailNotificationRelationshipOptional, EmailNotificationRelationshipRequired
-from app.api.tickets import TicketList, TicketListPost, TicketDetail, TicketRelationshipRequired, \
-    TicketRelationshipOptional
-from app.api.events import EventList, EventDetail, EventRelationship, EventCopyResource
-from app.api.event_types import EventTypeList, EventTypeDetail, EventTypeRelationship
+from app.api.event_copyright import EventCopyrightListPost, EventCopyrightDetail, EventCopyrightRelationshipRequired
+from app.api.event_image_sizes import EventImageSizeDetail
+from app.api.event_invoices import EventInvoiceList, EventInvoiceDetail, \
+    EventInvoiceRelationshipRequired, EventInvoiceRelationshipOptional
 from app.api.event_locations import EventLocationList
-from app.api.event_topics import EventTopicList, EventTopicDetail, EventTopicRelationship
+from app.api.event_orga import EventOrgaDetail
+from app.api.event_statistics import EventStatisticsGeneralDetail
 from app.api.event_sub_topics import EventSubTopicList, EventSubTopicListPost, EventSubTopicDetail, \
     EventSubTopicRelationshipRequired, EventSubTopicRelationshipOptional
+from app.api.event_topics import EventTopicList, EventTopicDetail, EventTopicRelationship
+from app.api.event_types import EventTypeList, EventTypeDetail, EventTypeRelationship
+from app.api.events import EventList, EventDetail, EventRelationship, EventCopyResource
+from app.api.events_role_permission import EventsRolePermissionList, EventsRolePermissionDetail, \
+    EventsRolePermissionRelationship
+from app.api.faq_types import FaqTypeList, FaqTypeListPost, FaqTypeDetail, FaqTypeRelationshipOptional, \
+    FaqTypeRelationshipRequired
+from app.api.faqs import FaqListPost, FaqList, FaqDetail, FaqRelationshipRequired, FaqRelationshipOptional
+from app.api.feedbacks import FeedbackListPost, FeedbackList, FeedbackDetail, \
+    FeedbackRelationship
+from app.api.full_text_search.events import EventSearchResultList
+from app.api.import_jobs import ImportJobList, ImportJobDetail
+from app.api.mails import MailList, MailDetail
+from app.api.message_settings import MessageSettingsList, MessageSettingsDetail
 from app.api.microlocations import MicrolocationList, MicrolocationListPost, MicrolocationDetail, \
     MicrolocationRelationshipRequired, MicrolocationRelationshipOptional
+from app.api.modules import ModuleDetail
+from app.api.notifications import NotificationList, NotificationListAdmin, NotificationDetail, \
+    NotificationRelationship, NotificationActionDetail, NotificationActionRelationship, NotificationActionList
+from app.api.order_statistics.events import OrderStatisticsEventDetail
+from app.api.order_statistics.tickets import OrderStatisticsTicketDetail
+from app.api.orders import OrdersList, OrderDetail, OrderRelationship, ChargeList, OrdersListPost
+from app.api.pages import PageList, PageDetail
+from app.api.panel_permissions import PanelPermissionList, PanelPermissionDetail, \
+    PanelPermissionRelationship
+from app.api.role_invites import RoleInviteListPost, RoleInviteList, RoleInviteDetail, RoleInviteRelationship
+from app.api.roles import RoleList, RoleDetail
+from app.api.service import ServiceList, ServiceDetail
+from app.api.session_types import SessionTypeList, SessionTypeListPost, SessionTypeDetail, \
+    SessionTypeRelationshipRequired, SessionTypeRelationshipOptional
 from app.api.sessions import SessionList, SessionListPost, SessionDetail, SessionRelationshipRequired, \
     SessionRelationshipOptional
+from app.api.settings import SettingDetail
+from app.api.social_links import SocialLinkList, SocialLinkListPost, SocialLinkDetail, SocialLinkRelationship
+from app.api.speaker_image_sizes import SpeakerImageSizeDetail
 from app.api.speakers import SpeakerList, SpeakerListPost, SpeakerDetail, SpeakerRelationshipRequired, \
     SpeakerRelationshipOptional
-from app.api.service import ServiceList, ServiceDetail
-from app.api.social_links import SocialLinkList, SocialLinkListPost, SocialLinkDetail, SocialLinkRelationship
-from app.api.sponsors import SponsorList, SponsorListPost, SponsorDetail, SponsorRelationship
-from app.api.tracks import TrackList, TrackListPost, TrackDetail, TrackRelationshipOptional, TrackRelationshipRequired
 from app.api.speakers_calls import SpeakersCallList, SpeakersCallDetail, SpeakersCallRelationship
-from app.api.event_invoices import EventInvoiceList, EventInvoiceDetail, \
-    EventInvoiceRelationshipRequired, EventInvoiceRelationshipOptional
-from app.api.role_invites import RoleInviteListPost, RoleInviteList, RoleInviteDetail, RoleInviteRelationship
-from app.api.event_image_sizes import EventImageSizeDetail
-from app.api.speaker_image_sizes import SpeakerImageSizeDetail
-from app.api.roles import RoleList, RoleDetail
-from app.api.custom_system_roles import CustomSystemRoleList, CustomSystemRoleDetail, CustomSystemRoleRelationship
-from app.api.session_types import SessionTypeList, SessionTypeListPost, SessionTypeDetail, \
-    SessionTypeRelationshipRequired, SessionTypeRelationshipOptional
-from app.api.event_copyright import EventCopyrightListPost, EventCopyrightDetail, EventCopyrightRelationshipRequired
-from app.api.pages import PageList, PageDetail
-from app.api.user_permission import UserPermissionList, UserPermissionDetail
-from app.api.events_role_permission import EventsRolePermissionList, EventsRolePermissionDetail, \
-    EventsRolePermissionRelationship
-from app.api.panel_permissions import PanelPermissionList, PanelPermissionDetail, \
-    PanelPermissionRelationship
-from app.api.message_settings import MessageSettingsList, MessageSettingsDetail
+from app.api.sponsors import SponsorList, SponsorListPost, SponsorDetail, SponsorRelationship
+from app.api.stripe_authorization import StripeAuthorizationDetail, StripeAuthorizationRelationship, \
+    StripeAuthorizationListPost
 from app.api.tax import TaxList, TaxDetail, TaxRelationship
-from app.api.settings import SettingDetail
-from app.api.discount_codes import DiscountCodeList, DiscountCodeDetail, DiscountCodeRelationshipOptional, \
-    DiscountCodeRelationshipRequired, DiscountCodeListPost
+from app.api.ticket_fees import TicketFeeList, TicketFeeDetail
 from app.api.ticket_tags import TicketTagList, TicketTagListPost, TicketTagDetail, TicketTagRelationshipOptional, \
     TicketTagRelationshipRequired
-from app.api.attendees import AttendeeList, AttendeeDetail, AttendeeRelationshipOptional, \
-    AttendeeRelationshipRequired, AttendeeListPost
-from app.api.access_codes import AccessCodeList, AccessCodeListPost, AccessCodeDetail, AccessCodeRelationshipRequired, \
-    AccessCodeRelationshipOptional
-from app.api.custom_forms import CustomFormList, CustomFormListPost, CustomFormDetail, CustomFormRelationshipRequired
-from app.api.faqs import FaqListPost, FaqList, FaqDetail, FaqRelationshipRequired, FaqRelationshipOptional
-from app.api.feedbacks import FeedbackListPost, FeedbackList, FeedbackDetail, \
-    FeedbackRelationship
-from app.api.modules import ModuleDetail
-from app.api.custom_placeholders import CustomPlaceholderList, CustomPlaceholderDetail, CustomPlaceholderRelationship
-from app.api.activities import ActivityList, ActivityDetail
-from app.api.orders import OrdersList, OrderDetail, OrderRelationship, ChargeList, OrdersListPost
-from app.api.event_statistics import EventStatisticsGeneralDetail
-from app.api.mails import MailList, MailDetail
-from app.api.admin_statistics_api.sessions import AdminStatisticsSessionDetail
-from app.api.admin_statistics_api.events import AdminStatisticsEventDetail
-from app.api.admin_statistics_api.users import AdminStatisticsUserDetail
-from app.api.admin_statistics_api.mails import AdminStatisticsMailDetail
-from app.api.order_statistics.events import OrderStatisticsEventDetail
-from app.api.order_statistics.tickets import OrderStatisticsTicketDetail
-from app.api.faq_types import FaqTypeList, FaqTypeListPost, FaqTypeDetail, FaqTypeRelationshipOptional, \
-    FaqTypeRelationshipRequired
-from app.api.admin_sales.events import AdminSalesByEventsList
-from app.api.admin_sales.organizer import AdminSalesByOrganizersList
-from app.api.admin_sales.locations import AdminSalesByLocationList
-from app.api.admin_sales.marketer import AdminSalesByMarketerList
-from app.api.admin_sales.discounted import AdminSalesDiscountedList
-from app.api.admin_sales.fees import AdminSalesFeesList
-from app.api.admin_sales.invoices import AdminSalesInvoicesList
-from app.api.full_text_search.events import EventSearchResultList
-from app.api.import_jobs import ImportJobList, ImportJobDetail
+from app.api.tickets import TicketList, TicketListPost, TicketDetail, TicketRelationshipRequired, \
+    TicketRelationshipOptional
+from app.api.tracks import TrackList, TrackListPost, TrackDetail, TrackRelationshipOptional, TrackRelationshipRequired
+from app.api.user_emails import UserEmailListAdmin, UserEmailListPost, UserEmailList, UserEmailDetail, \
+    UserEmailRelationship
+from app.api.user_favourite_events import UserFavouriteEventListPost, UserFavouriteEventList, \
+    UserFavouriteEventDetail, UserFavouriteEventRelationship
+from app.api.user_permission import UserPermissionList, UserPermissionDetail
+from app.api.users import UserList, UserDetail, UserRelationship
 
 # users
 api.route(UserList, 'user_list', '/users')
@@ -474,7 +474,7 @@
           '/tickets/<int:ticket_id>/discount-codes')
 api.route(DiscountCodeDetail, 'discount_code_detail', '/discount-codes/<int:id>',
           '/events/<int:event_id>/discount-code', '/event-invoices/<int:event_invoice_id>/discount-code',
-          '/discount-codes/<code>')
+          '/event/<int:discount_event_id>/discount-code/<code>')
 api.route(DiscountCodeRelationshipRequired, 'discount_code_event',
           '/discount-codes/<int:id>/relationships/event')
 api.route(DiscountCodeRelationshipOptional, 'discount_code_events',
@@ -541,7 +541,8 @@
 api.route(AccessCodeList, 'access_code_list', '/events/<int:event_id>/access-codes',
           '/events/<event_identifier>/access-codes', '/users/<int:user_id>/access-codes',
           '/tickets/<int:ticket_id>/access-codes')
-api.route(AccessCodeDetail, 'access_code_detail', '/access-codes/<int:id>', '/access-codes/<code>')
+api.route(AccessCodeDetail, 'access_code_detail', '/access-codes/<int:id>',
+          '/event/<int:access_event_id>/access-code/<code>')
 api.route(AccessCodeRelationshipRequired, 'access_code_event',
           '/access-codes/<int:id>/relationships/event')
 api.route(AccessCodeRelationshipOptional, 'access_code_user',
diff --git a/app/api/access_codes.py b/app/api/access_codes.py
--- a/app/api/access_codes.py
+++ b/app/api/access_codes.py
@@ -111,8 +111,9 @@ def before_get(self, args, kwargs):
         :return:
         """
         # Any registered user can fetch access code details using the code.
-        if kwargs.get('code'):
-            access = db.session.query(AccessCode).filter_by(code=kwargs.get('code')).first()
+        if kwargs.get('code') and kwargs.get('access_event_id'):
+            access = db.session.query(AccessCode).filter_by(code=kwargs.get('code'),
+                                                            event_id=kwargs.get('access_event_id')).first()
             if access:
                 kwargs['id'] = access.id
             else:
diff --git a/app/api/discount_codes.py b/app/api/discount_codes.py
--- a/app/api/discount_codes.py
+++ b/app/api/discount_codes.py
@@ -209,7 +209,9 @@ def before_get(self, args, kwargs):
         if kwargs.get('code'):
             # filter on deleted_at is required to catch the id of a
             # discount code which has not been deleted.
-            discount = db.session.query(DiscountCode).filter_by(code=kwargs.get('code'), deleted_at=None).first()
+            discount = db.session.query(DiscountCode).filter_by(code=kwargs.get('code'),
+                                                                event_id=kwargs.get('discount_event_id'),
+                                                                deleted_at=None).first()
             if discount:
                 kwargs['id'] = discount.id
                 discount_tz = discount.valid_from.tzinfo


Test patch:
diff --git a/tests/hook_main.py b/tests/hook_main.py
--- a/tests/hook_main.py
+++ b/tests/hook_main.py
@@ -2804,7 +2804,7 @@ def discount_delete(transaction):
 @hooks.before("Discount Codes > Get Discount Code Detail using the code > Get Discount Code Detail")
 def discount_code_get_detail_using_code(transaction):
     """
-    GET /discount-codes/DC101
+    GET event/1/discount-codes/DC101
     :param transaction:
     :return:
     """
@@ -2815,6 +2815,7 @@ def discount_code_get_detail_using_code(transaction):
 
         discount_code = DiscountCodeFactory(event_id=1)
         discount_code.code = 'DC101'
+        discount_code.event_id = 1
         db.session.add(discount_code)
         db.session.commit()
 
@@ -2940,11 +2941,15 @@ def access_code_delete(transaction):
 @hooks.before("Access Codes > Access Code Detail using the Code > Access Code Detail")
 def access_code_get_detail_using_code(transaction):
     """
-    GET /access-codes/AC101
+    GET event/1/access-code/AC101
     :param transaction:
     :return:
     """
     with stash['app'].app_context():
+        event = EventFactoryBasic()
+        db.session.add(event)
+        db.session.commit()
+
         access_code = AccessCodeFactory()
         access_code.code = 'AC101'
         db.session.add(access_code)