def before_create_object(self, data, view_kwargs): """ before create object method for OrderListPost Class :param data: :param view_kwargs: :return: """ for ticket_holder in data['ticket_holders']: # Ensuring that the attendee exists and doesn't have an associated order. try: ticket_holder_object = self.session.query( TicketHolder).filter_by(id=int(ticket_holder), deleted_at=None).one() if ticket_holder_object.order_id: raise ConflictException( {'pointer': '/data/relationships/attendees'}, "Order already exists for attendee with id {}".format( str(ticket_holder))) except NoResultFound: raise ConflictException( {'pointer': '/data/relationships/attendees'}, "Attendee with id {} does not exists".format( str(ticket_holder))) if data.get('cancel_note'): del data['cancel_note'] if data.get('payment_mode') != 'free' and not data.get('amount'): raise ConflictException({'pointer': '/data/attributes/amount'}, "Amount cannot be null for a paid order") if not data.get('amount'): data['amount'] = 0 # Apply discount only if the user is not event admin if data.get('discount') and not has_access('is_coorganizer', event_id=data['event']): discount_code = safe_query_without_soft_deleted_entries( self, DiscountCode, 'id', data['discount'], 'discount_code_id') if not discount_code.is_active: raise UnprocessableEntity({'source': 'discount_code_id'}, "Inactive Discount Code") else: now = datetime.utcnow() valid_from = datetime.strptime(discount_code.valid_from, '%Y-%m-%d %H:%M:%S') valid_till = datetime.strptime(discount_code.valid_till, '%Y-%m-%d %H:%M:%S') if not (valid_from <= now <= valid_till): raise UnprocessableEntity({'source': 'discount_code_id'}, "Inactive Discount Code") if not TicketingManager.match_discount_quantity( discount_code, data['ticket_holders']): raise UnprocessableEntity({'source': 'discount_code_id'}, 'Discount Usage Exceeded') if discount_code.event.id != data[ 'event'] and discount_code.user_for == TICKET: raise UnprocessableEntity({'source': 'discount_code_id'}, "Invalid Discount Code")
def create_onsite_attendees_for_order(data): """ Creates on site ticket holders for an order and adds it into the request data. :param data: data initially passed in the POST request for order. :return: """ on_site_tickets = data.get('on_site_tickets') if not on_site_tickets: raise UnprocessableEntityError( {'pointer': 'data/attributes/on_site_tickets'}, 'on_site_tickets info missing') data['ticket_holders'] = [] for on_site_ticket in on_site_tickets: ticket_id = on_site_ticket['id'] quantity = int(on_site_ticket['quantity']) ticket = safe_query_without_soft_deleted_entries( Ticket, 'id', ticket_id, 'ticket_id') ticket_sold_count = get_count( db.session.query(TicketHolder.id).filter_by(ticket_id=int( ticket.id), deleted_at=None)) # Check if the ticket is already sold out or not. if ticket_sold_count + quantity > ticket.quantity: # delete the already created attendees. for holder in data['ticket_holders']: ticket_holder = (db.session.query(TicketHolder).filter( id == int(holder)).one()) db.session.delete(ticket_holder) try: db.session.commit() except Exception: logging.exception('DB Exception!') db.session.rollback() raise ConflictError( {'pointer': '/data/attributes/on_site_tickets'}, "Ticket with id: {} already sold out. You can buy at most {} tickets" .format(ticket_id, ticket.quantity - ticket_sold_count), ) for _ in range(1, quantity): ticket_holder = TicketHolder( firstname='onsite', lastname='attendee', email='*****@*****.**', ticket_id=ticket.id, event_id=data.get('event'), ) save_to_db(ticket_holder) data['ticket_holders'].append(ticket_holder.id) # delete from the data. del data['on_site_tickets']
def create_onsite_attendees_for_order(data): """ Creates on site ticket holders for an order and adds it into the request data. :param data: data initially passed in the POST request for order. :return: """ on_site_tickets = data.get('on_site_tickets') if not on_site_tickets: raise UnprocessableEntity({'pointer': 'data/attributes/on_site_tickets'}, 'on_site_tickets info missing') data['ticket_holders'] = [] for on_site_ticket in on_site_tickets: ticket_id = on_site_ticket['id'] quantity = int(on_site_ticket['quantity']) ticket = safe_query_without_soft_deleted_entries(db, Ticket, 'id', ticket_id, 'ticket_id') ticket_sold_count = get_count(db.session.query(TicketHolder.id). filter_by(ticket_id=int(ticket.id), deleted_at=None)) # Check if the ticket is already sold out or not. if ticket_sold_count + quantity > ticket.quantity: # delete the already created attendees. for holder in data['ticket_holders']: ticket_holder = db.session.query(TicketHolder).filter(id == int(holder)).one() db.session.delete(ticket_holder) try: db.session.commit() except Exception as e: logging.error('DB Exception! %s' % e) db.session.rollback() raise ConflictException( {'pointer': '/data/attributes/on_site_tickets'}, "Ticket with id: {} already sold out. You can buy at most {} tickets".format(ticket_id, ticket.quantity - ticket_sold_count) ) for _ in range(1, quantity): ticket_holder = TicketHolder(firstname='onsite', lastname='attendee', email='*****@*****.**', ticket_id=ticket.id, event_id=data.get('event')) save_to_db(ticket_holder) data['ticket_holders'].append(ticket_holder.id) # delete from the data. del data['on_site_tickets']
def before_create_object(self, data, view_kwargs): """ before create object method for OrderListPost Class :param data: :param view_kwargs: :return: """ for ticket_holder in data['ticket_holders']: # Ensuring that the attendee exists and doesn't have an associated order. try: ticket_holder_object = self.session.query(TicketHolder).filter_by(id=int(ticket_holder), deleted_at=None).one() if ticket_holder_object.order_id: raise ConflictException({'pointer': '/data/relationships/attendees'}, "Order already exists for attendee with id {}".format(str(ticket_holder))) except NoResultFound: raise ConflictException({'pointer': '/data/relationships/attendees'}, "Attendee with id {} does not exists".format(str(ticket_holder))) if data.get('cancel_note'): del data['cancel_note'] if data.get('payment_mode') != 'free' and not data.get('amount'): raise ConflictException({'pointer': '/data/attributes/amount'}, "Amount cannot be null for a paid order") # Apply discount only if the user is not event admin if data.get('discount') and not has_access('is_coorganizer', event_id=data['event']): discount_code = safe_query_without_soft_deleted_entries(self, DiscountCode, 'id', data['discount'], 'discount_code_id') if not discount_code.is_active: raise UnprocessableEntity({'source': 'discount_code_id'}, "Inactive Discount Code") else: now = datetime.utcnow() valid_from = datetime.strptime(discount_code.valid_from, '%Y-%m-%d %H:%M:%S') valid_till = datetime.strptime(discount_code.valid_till, '%Y-%m-%d %H:%M:%S') if not (valid_from <= now <= valid_till): raise UnprocessableEntity({'source': 'discount_code_id'}, "Inactive Discount Code") if not TicketingManager.match_discount_quantity(discount_code, data['ticket_holders']): raise UnprocessableEntity({'source': 'discount_code_id'}, 'Discount Usage Exceeded') if discount_code.event.id != data['event'] and discount_code.user_for == TICKET: raise UnprocessableEntity({'source': 'discount_code_id'}, "Invalid Discount Code")
def calculate_order_amount(tickets, discount_code): from app.api.helpers.ticketing import TicketingManager if discount_code: if not TicketingManager.match_discount_quantity(discount_code, tickets, None): return UnprocessableEntityError({'source': 'discount-code'}, 'Discount Usage Exceeded').respond() event = tax = tax_included = fees = None total_amount = total_tax = total_discount = 0.0 ticket_list = [] for ticket_info in tickets: tax_amount = tax_percent = 0.0 tax_data = {} discount_amount = discount_percent = 0.0 discount_data = {} sub_total = ticket_fee = 0.0 ticket_identifier = ticket_info['id'] quantity = ticket_info['quantity'] ticket = safe_query_without_soft_deleted_entries(db, Ticket, 'id', ticket_identifier, 'id') if not event: event = ticket.event fees = TicketFees.query.filter_by(currency=event.payment_currency).first() elif ticket.event.id != event.id: raise UnprocessableEntity({'source': 'data/tickets'}, "Invalid Ticket") 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 UnprocessableEntity({'source': 'data/tickets'}, "Price for donation ticket invalid") else: price = ticket.price if discount_code: for code in ticket.discount_codes: if discount_code.id == code.id: if code.type == 'amount': discount_amount = code.value 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) } if tax: if not tax_included: tax_amount = ((price - discount_amount) * tax.rate)/100 tax_percent = tax.rate else: tax_amount = ((price - discount_amount) * tax.rate)/(100 + tax.rate) tax_percent = tax.rate tax_data = { 'percent': round(tax_percent, 2), 'amount': round(tax_amount, 2), } total_tax = total_tax + tax_amount * quantity total_discount = total_discount + discount_amount*quantity 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 if tax_included: sub_total = ticket_fee + (price - discount_amount)*quantity else: sub_total = ticket_fee + (price + tax_amount - 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, 'tax': tax_data, 'ticket_fee': round(ticket_fee, 2), 'sub_total': round(sub_total, 2) }) return dict(tax_included=tax_included, total_amount=round(total_amount, 2), total_tax=round(total_tax, 2), total_discount=round(total_discount, 2), tickets=ticket_list)