@@ -572,87 +572,6 @@ def _check_slots_dates(self):
572572 slots = "\n " .join (f"- { slot .name } " for slot in slots_outside_event_bounds )
573573 ))
574574
575- # @api.constrains('seats_max', 'seats_limited', 'registration_ids')
576- # def _check_seats_availability(self, minimal_availability=0):
577- # sold_out_events = []
578- # for event in self:
579- # if event.seats_limited and event.seats_max and event.seats_available < minimal_availability:
580- # sold_out_events.append(_(
581- # '- "%(event_name)s": Missing %(nb_too_many)i seats.',
582- # event_name=event.name,
583- # nb_too_many=minimal_availability - event.seats_available,
584- # ))
585- # if sold_out_events:
586- # raise ValidationError(_('There are not enough seats available for:')
587- # + '\n%s\n' % '\n'.join(sold_out_events))
588-
589- def _verify_seats_availability (self , slot_id = False , ticket_id = False , minimal_availability = 0 ):
590- """ Check the number of seats available for the event.
591- :slot_id: for the specified slot if specified.
592- :ticket_id: for the specified ticket if specified.
593- :minimal_availability: A minimal availability can be specified to ensure there is
594- at least this number of seats left. Useful in the sale flow.
595- Raises:
596- ValidationError: If the event / slot / ticket / slot ticket do not have enough seats available.
597- """
598- sold_out_records = []
599- slot_tickets_nb_registrations = {
600- (slot .id , ticket .id ): count
601- for (slot , ticket , count ) in self .env ['event.registration' ]._read_group (
602- domain = [('event_id' , 'in' , self .ids ), ('state' , 'in' , ['open' , 'done' ]), ('active' , '=' , True )],
603- groupby = ['event_slot_id' , 'event_ticket_id' ],
604- aggregates = ['__count' ]
605- )
606- }
607- for event in self :
608- slot = False
609- ticket = False
610- if slot_id :
611- slot = self .env ['event.slot' ].browse (slot_id )
612- if ticket_id :
613- ticket = self .env ['event.event.ticket' ].browse (ticket_id )
614- # Event / slot seats_max
615- if event .seats_limited and event .seats_max :
616- # TODO: ne fonctionne pas parce que ça verifie les valeurs avant le write et on ne sait pas
617- # cb de registrations sont impactée, on pourrait vouloir write sur 6 registrations
618- if slot and slot .seats_available < minimal_availability :
619- sold_out_records .append (_ (
620- '- the slot "%(slot_name)s" (%(event_name)s): Missing %(nb_too_many)i seats.' ,
621- slot_name = slot .name ,
622- event_name = event .name ,
623- nb_too_many = minimal_availability - slot .seats_available ,
624- ))
625- # TODO: same
626- elif event .seats_available < minimal_availability :
627- sold_out_records .append (_ (
628- '- the event "%(event_name)s": Missing %(nb_too_many)i seats.' ,
629- event_name = event .name ,
630- nb_too_many = minimal_availability - event .seats_available ,
631- ))
632- # Ticket seats_max
633- if ticket and ticket .seats_max :
634- if slot :
635- # TODO: same
636- slot_ticket_seats_available = ticket .seats_max - slot_tickets_nb_registrations .get ((slot .id , ticket .id ), 0 )
637- if slot_ticket_seats_available <= minimal_availability :
638- sold_out_records .append (_ (
639- '- the slot ticket "%(slot_ticket_name)s" (%(event_name)s): Missing %(nb_too_many)i seats.' ,
640- slot_ticket_name = f'{ ticket .name } - { slot .name } ' ,
641- event_name = event .name ,
642- nb_too_many = minimal_availability - slot_ticket_seats_available ,
643- ))
644- # TODO: same
645- elif ticket .seats_available <= minimal_availability :
646- sold_out_records .append (_ (
647- '- the ticket "%(ticket_name)s" (%(event_name)s): Missing %(nb_too_many)i seats.' ,
648- ticket_name = ticket .name ,
649- event_name = event .name ,
650- nb_too_many = minimal_availability - ticket .seats_available ,
651- ))
652- if sold_out_records :
653- raise ValidationError (_ ('There are not enough seats available for:\n %(sold_out_records)s\n ' ,
654- sold_out_records = '\n ' .join (sold_out_records )))
655-
656575 @api .constrains ('date_begin' , 'date_end' )
657576 def _check_closing_date (self ):
658577 for event in self :
@@ -721,6 +640,84 @@ def _set_tz_context(self):
721640 self .ensure_one ()
722641 return self .with_context (tz = self .date_tz or 'UTC' )
723642
643+ def _get_seats_availability (self , slot_tickets ):
644+ """ Get availabilities for given combinations of slot / ticket. Returns
645+ a list following input order. None denotes no limit. """
646+ self .ensure_one ()
647+ if not (all (len (item ) == 2 for item in slot_tickets )):
648+ raise ValueError ('Input should be a list of tuples containing slot, ticket' )
649+
650+ slot_tickets_nb_registrations = {
651+ (slot .id , ticket .id ): count
652+ for (slot , ticket , count ) in self .env ['event.registration' ]._read_group (
653+ domain = [('event_id' , 'in' , self .ids ), ('state' , 'in' , ['open' , 'done' ]), ('active' , '=' , True )],
654+ groupby = ['event_slot_id' , 'event_ticket_id' ],
655+ aggregates = ['__count' ]
656+ )
657+ }
658+
659+ availabilities = []
660+ for slot , ticket in slot_tickets :
661+ available = None
662+ # event is constrained: max stands for either each slot, either global (no slots)
663+ if self .seats_max :
664+ if slot :
665+ available = slot .seats_available
666+ else :
667+ available = self .seats_available
668+ # ticket is constrained: max standard for either each slot / ticket, either global (no slots)
669+ if available != 0 and ticket and ticket .seats_max :
670+ if slot :
671+ ticket_available = ticket .seats_max - slot_tickets_nb_registrations .get ((slot .id , ticket .id ), 0 )
672+ else :
673+ ticket_available = ticket .seats_available
674+ available = ticket_available if available == None else min (available , ticket_available )
675+ availabilities .append (available )
676+ return availabilities
677+
678+ def _verify_seats_availability (self , slot_tickets ):
679+ """ Check event seats availability, for combinations of slot / ticket.
680+
681+ :slot_tickets: a list of tuples(slot, ticket, count). SLot and ticket
682+ are optional, depending on event configuration. If count is 0
683+ it is a simple check current values do not overflow limit. If count
684+ is given, it serves as a check there are enough remaining seats.
685+
686+ Raises:
687+ ValidationError: if the event / slot / ticket do not have enough
688+ available seats
689+ """
690+ self .ensure_one ()
691+ if not (all (len (item ) == 3 for item in slot_tickets )):
692+ raise ValueError ('Input should be a list of tuples containing slot, ticket, count' )
693+
694+ sold_out = []
695+ availabilities = self ._get_seats_availability ([(item [0 ], item [1 ]) for item in slot_tickets ])
696+ for (slot , ticket , count ), available in zip (slot_tickets , availabilities , strict = True ):
697+ if available is None : # unconstrained
698+ continue
699+ if available < count :
700+ if slot and ticket :
701+ name = f'{ ticket .name } - { slot .name } '
702+ elif slot :
703+ name = slot .name
704+ elif ticket :
705+ name = ticket .name
706+ else :
707+ name = self .name
708+ sold_out .append ((name , count - available ))
709+
710+ if sold_out :
711+ info = [] # note: somehow using list comprehension make translate.py crash in default lang
712+ for item in sold_out :
713+ info .append (_ ('%(slot_name)s: missing %(count)s seats' , slot_name = item [0 ], count = item [1 ]))
714+ raise ValidationError (
715+ _ ('There are not enough seats available for %(event_name)s:\n %(sold_out_info)s' ,
716+ event_name = self .name ,
717+ sold_out_info = '\n ' .join (info ),
718+ )
719+ )
720+
724721 # ------------------------------------------------------------
725722 # ACTIONS
726723 # ------------------------------------------------------------
0 commit comments