All checks were successful
		
		
	
	Run unit tests / rubocop (push) Successful in 27s
				
			Run unit tests / check-licenses (push) Successful in 32s
				
			Run unit tests / copyright_notice (push) Successful in 36s
				
			Run unit tests / unit_tests (push) Successful in 1m22s
				
			Run unit tests / build-static-assets (push) Successful in 10m9s
				
			## Why The current way of creating and deleting simulations doesn't scale for big instances. We cannot generate 50 simulations every time a guest confirms attendance, and we should not delete existing valuable simulations. For example, if a guest confirms attendance and declines right after, previously generated simulations should still be valid. ## What In this PR we are introducing a series of changes that make simulations management easier: 1. We're removing the automatic creation of simulations. 2. Simulations are not removed anymore, neither manually nor automatically. 3. A new endpoint has been defined to create simulations on demand. 4. A digest property has been defined to determine whether a simulation is still valid (meaning there have not been any change in the list of guests involved). Reviewed-on: #222 Co-authored-by: Manuel Bustillo <bustikiller@bustikiller.com> Co-committed-by: Manuel Bustillo <bustikiller@bustikiller.com>
		
			
				
	
	
		
			77 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # Copyright (C) 2024-2025 LibreWeddingPlanner contributors
 | |
| 
 | |
| # frozen_string_literal: true
 | |
| 
 | |
| require_relative '../../extensions/tree_node_extension'
 | |
| 
 | |
| module Tables
 | |
|   class Distribution
 | |
|     class << self
 | |
|       def digest(wedding)
 | |
|         Digest::UUID.uuid_v5(wedding.id, wedding.guests.potential.order(:id).pluck(:id).join)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy
 | |
| 
 | |
|     def initialize(min_per_table:, max_per_table:)
 | |
|       @min_per_table = min_per_table
 | |
|       @max_per_table = max_per_table
 | |
|       @hierarchy = AffinityGroupsHierarchy.new
 | |
|       @tables = []
 | |
|     end
 | |
| 
 | |
|     def random_distribution(people)
 | |
|       min_tables = (people.count * 1.0 / @max_per_table).ceil
 | |
|       max_tables = (people.count * 1.0 / @min_per_table).ceil
 | |
|       @tables = people.in_groups(rand(min_tables..max_tables), false)
 | |
|                       .map { |group| Table.new(group) }
 | |
|                       .each { |table| table.min_per_table = @min_per_table }
 | |
|                       .each { |table| table.max_per_table = @max_per_table }
 | |
|     end
 | |
| 
 | |
|     def discomfort
 | |
|       @tables.map do |table|
 | |
|         local_discomfort(table)
 | |
|       end.sum
 | |
|     end
 | |
| 
 | |
|     def inspect
 | |
|       "#{@tables.count} tables, discomfort: #{discomfort}"
 | |
|     end
 | |
| 
 | |
|     def deep_dup
 | |
|       self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table).tap do |new_distribution|
 | |
|         new_distribution.tables = @tables.map(&:dup)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def save!
 | |
|       ActiveRecord::Base.transaction do
 | |
|         arrangement = TablesArrangement.create!
 | |
| 
 | |
|         records_to_store = []
 | |
| 
 | |
|         tables.each_with_index do |table, table_number|
 | |
|           table.each do |person|
 | |
|             records_to_store << { guest_id: person.id, tables_arrangement_id: arrangement.id, table_number: }
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         Seat.insert_all!(records_to_store)
 | |
| 
 | |
|         arrangement.update!(
 | |
|           discomfort:,
 | |
|           digest: self.class.digest(tables.first.first.wedding)
 | |
|         )
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     private
 | |
| 
 | |
|     def local_discomfort(table)
 | |
|       table.discomfort ||= DiscomfortCalculator.new(table:, hierarchy:).calculate
 | |
|     end
 | |
|   end
 | |
| end
 |