def test_reject_deleted_tickets(db): event = EventFactoryBasic() tickets = TicketSubFactory.create_batch(3, event=event) tickets.append(TicketSubFactory(deleted_at=datetime.now(), event=event)) db.session.commit() with pytest.raises(ObjectNotFound, match=r'Tickets not found for IDs: .*'): validate_tickets([ticket.id for ticket in tickets])
def test_reject_tickets_of_different_events(db): tickets = TicketSubFactory.create_batch(3) db.session.commit() with pytest.raises( UnprocessableEntityError, match=r'All tickets must belong to same event. Found: .*', ): validate_tickets([ticket.id for ticket in tickets])
def calculate_order_amount(tickets, discount_code=None): from app.api.helpers.ticketing import validate_discount_code, validate_tickets from app.models.discount_code import DiscountCode ticket_ids = {ticket['id'] for ticket in tickets} ticket_map = {int(ticket['id']): ticket for ticket in tickets} fetched_tickets = validate_tickets(ticket_ids) if tickets and discount_code: discount_code = validate_discount_code(discount_code, tickets=tickets) event = tax = tax_included = fees = None total_amount = total_tax = total_discount = 0.0 ticket_list = [] for ticket in fetched_tickets: ticket_info = ticket_map[ticket.id] discount_amount = 0.0 discount_data = None ticket_fee = 0.0 quantity = ticket_info.get('quantity', 1) # Default to single ticket if not event: event = ticket.event if event.deleted_at: raise ObjectNotFound({'pointer': 'tickets/event'}, f'Event: {event.id} not found') fees = TicketFees.query.filter_by( currency=event.payment_currency).first() if not tax and event.tax: tax = event.tax tax_included = tax.is_tax_included_in_price if ticket.type == 'donation': price = ticket_info.get('price') if not price or price > ticket.max_price or price < ticket.min_price: raise UnprocessableEntityError( {'pointer': 'tickets/price'}, f"Price for donation ticket should be present and within range " f"{ticket.min_price} to {ticket.max_price}", ) else: price = ticket.price if ticket.type != 'free' else 0.0 if discount_code and ticket.type != 'free': code = (DiscountCode.query.with_parent(ticket).filter_by( id=discount_code.id).first()) if code: if discount_code.id == code.id: if code.type == 'amount': discount_amount = min(code.value, price) discount_percent = (discount_amount / price) * 100 else: discount_amount = (price * code.value) / 100 discount_percent = code.value discount_data = { 'code': discount_code.code, 'percent': round(discount_percent, 2), 'amount': round(discount_amount, 2), 'total': round(discount_amount * quantity, 2), } total_discount += round(discount_amount * quantity, 2) if fees and not ticket.is_fee_absorbed: ticket_fee = fees.service_fee * (price * quantity) / 100 if ticket_fee > fees.maximum_fee: ticket_fee = fees.maximum_fee sub_total = ticket_fee + (price - discount_amount) * quantity total_amount = total_amount + sub_total ticket_list.append({ 'id': ticket.id, 'name': ticket.name, 'price': price, 'quantity': quantity, 'discount': discount_data, 'ticket_fee': round(ticket_fee, 2), 'sub_total': round(sub_total, 2), }) sub_total = total_amount tax_dict = None if tax: if tax_included: total_tax = total_amount - total_amount / (1 + tax.rate / 100) else: total_tax = total_amount * tax.rate / 100 total_amount += total_tax tax_dict = dict( included=tax_included, amount=round(total_tax, 2), percent=tax.rate if tax else 0.0, name=tax.name, ) return dict( tax=tax_dict, sub_total=round(sub_total, 2), total=round(total_amount, 2), discount=round(total_discount, 2), tickets=ticket_list, )
def test_validate_tickets(db): tickets = TicketSubFactory.create_batch(3, event=EventFactoryBasic()) db.session.commit() assert validate_tickets([str(ticket.id) for ticket in tickets]) == tickets
def test_validate_empty_tickets(): assert validate_tickets([]) == []