@@ -572,87 +572,6 @@ def _check_slots_dates(self):
572
572
slots = "\n " .join (f"- { slot .name } " for slot in slots_outside_event_bounds )
573
573
))
574
574
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
-
656
575
@api .constrains ('date_begin' , 'date_end' )
657
576
def _check_closing_date (self ):
658
577
for event in self :
@@ -721,6 +640,84 @@ def _set_tz_context(self):
721
640
self .ensure_one ()
722
641
return self .with_context (tz = self .date_tz or 'UTC' )
723
642
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
+
724
721
# ------------------------------------------------------------
725
722
# ACTIONS
726
723
# ------------------------------------------------------------
0 commit comments