diff --git a/app/api/schema/discount_codes.py b/app/api/schema/discount_codes.py index dbac9506ad..166ec50915 100644 --- a/app/api/schema/discount_codes.py +++ b/app/api/schema/discount_codes.py @@ -8,6 +8,7 @@ from app.api.helpers.utilities import dasherize from app.api.schema.base import SoftDeletionSchema from app.models.discount_code import DiscountCode +from app.models.ticket import Ticket class DiscountCodeSchemaPublic(SoftDeletionSchema): @@ -153,6 +154,55 @@ def validate_quantity(self, data, original_data): raise UnprocessableEntity({'pointer': '/data/attributes/tickets-number'}, "tickets-number should be greater than max-quantity") + @validates_schema(pass_original=True) + def validate_value(self, data, original_data): + if 'id' in original_data['data']: + try: + discount_code = DiscountCode.query.filter_by(id=original_data['data']['id']).one() + except NoResultFound: + raise ObjectNotFound({'parameter': '{code}'}, "DiscountCode: not found") + + if 'type' not in data: + data['type'] = discount_code.type + + if 'value' not in data: + data['value'] = discount_code.value + + if data['type'] == "percent": + if 'tickets' in data: + for ticket in data['tickets']: + ticket_object = Ticket.query.filter_by(id=ticket).one() + if not ticket_object.price: + raise UnprocessableEntity( + {'pointer': '/data/attributes/tickets'}, + "discount code cannot be applied on free tickets" + ) + if data['value'] < 0 or data['value'] > 100: + raise UnprocessableEntity( + {'pointer': '/data/attributes/value'}, + "discount percent must be within range of 0 and 100" + ) + + if data['type'] == "amount": + if 'tickets' in data: + for ticket in data['tickets']: + ticket_object = Ticket.query.filter_by(id=ticket).one() + if not ticket_object.price: + raise UnprocessableEntity( + {'pointer': '/data/attributes/tickets'}, + "discount code cannot be applied on free tickets" + ) + if ticket_object.price < data['value']: + raise UnprocessableEntity( + {'pointer': '/data/attributes/value'}, + "discount amount cannot be more than ticket amount" + ) + if data['value'] < 0: + raise UnprocessableEntity( + {'pointer': '/data/attributes/value'}, + "discount amount cannot be less than zero" + ) + @validates_schema(pass_original=True) def validate_date(self, data, original_data): if 'id' in original_data['data']: diff --git a/tests/all/integration/api/validation/test_discount_codes.py b/tests/all/integration/api/validation/test_discount_codes.py index bba04b0be9..bcfdd9566a 100644 --- a/tests/all/integration/api/validation/test_discount_codes.py +++ b/tests/all/integration/api/validation/test_discount_codes.py @@ -4,9 +4,9 @@ from tests.all.integration.utils import OpenEventTestCase from app.api.helpers.exceptions import UnprocessableEntity from app.api.schema.discount_codes import DiscountCodeSchemaTicket -from app.factories.discount_code import DiscountCodeFactory -from app.models import db from app.api.helpers.db import save_to_db +from app.factories.discount_code import DiscountCodeFactory +from app.factories.ticket import TicketFactory from tests.all.integration.setup_database import Setup @@ -64,6 +64,71 @@ def test_quantity_max_gt_tickets_number(self): with self.assertRaises(UnprocessableEntity): DiscountCodeSchemaTicket.validate_quantity(schema, data, original_data) + def test_amount_lte_ticket_price(self): + """ + Discount Code Validate Amount Value - Tests if function runs without an exception + :return: + """ + with app.test_request_context(): + ticket = TicketFactory() + ticket.price = 100 + save_to_db(ticket) + + schema = DiscountCodeSchemaTicket() + original_data = { + 'data': {} + } + data = { + 'type': 'amount', + 'value': 70, + 'tickets': ['1'] + } + DiscountCodeSchemaTicket.validate_value(schema, data, original_data) + + def test_amount_gt_ticket_price(self): + """ + Discount Code Validate Amount Value - Tests if exception is raised when discount value is gt ticket price + :return: + """ + with app.test_request_context(): + ticket = TicketFactory() + ticket.price = 100 + save_to_db(ticket) + + schema = DiscountCodeSchemaTicket() + original_data = { + 'data': {} + } + data = { + 'type': 'amount', + 'value': 150, + 'tickets': ['1'] + } + with self.assertRaises(UnprocessableEntity): + DiscountCodeSchemaTicket.validate_value(schema, data, original_data) + + def test_free_ticket(self): + """ + Discount Code Validate Amount Value - Tests exception when discount code is created for free ticket + :return: + """ + with app.test_request_context(): + ticket = TicketFactory() + ticket.price = 0 + save_to_db(ticket) + + schema = DiscountCodeSchemaTicket() + original_data = { + 'data': {} + } + data = { + 'type': 'amount', + 'value': 150, + 'tickets': ['1'] + } + with self.assertRaises(UnprocessableEntity): + DiscountCodeSchemaTicket.validate_value(schema, data, original_data) + def test_quantity_db_populate(self): """ Discount Code Validate Quantity - Tests if validation works on values stored in db and not given in 'data' diff --git a/tests/all/unit/api/validation/test_discount_codes.py b/tests/all/unit/api/validation/test_discount_codes.py new file mode 100644 index 0000000000..93a2432c3f --- /dev/null +++ b/tests/all/unit/api/validation/test_discount_codes.py @@ -0,0 +1,45 @@ +import unittest + +from tests.all.integration.utils import OpenEventTestCase +from app.api.helpers.exceptions import UnprocessableEntity +from app.api.schema.discount_codes import DiscountCodeSchemaTicket + + +class TestDiscountCodeValidation(OpenEventTestCase): + + def test_percent_value_lte_hundred(self): + """ + Discount Code Validate Percentage Value - Tests if function runs without an exception + :return: + """ + schema = DiscountCodeSchemaTicket() + original_data = { + 'data': {} + } + data = { + 'type': 'percent', + 'value': 90, + 'tickets': [] + } + DiscountCodeSchemaTicket.validate_value(schema, data, original_data) + + def test_percent_value_gt_hundred(self): + """ + Discount Code Validate Percentage Value - Tests if exception is raised when percentage value is greater than 100 + :return: + """ + schema = DiscountCodeSchemaTicket() + original_data = { + 'data': {} + } + data = { + 'type': 'percent', + 'value': 110, + 'tickets': [] + } + with self.assertRaises(UnprocessableEntity): + DiscountCodeSchemaTicket.validate_value(schema, data, original_data) + + +if __name__ == '__main__': + unittest.main()