Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store country band details in database #10476

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/country_bands_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def index

def edit
@number = id_from_params
unless CountryBand::BANDS.keys.include?(@number)
unless CountryBandDetail.exists?(number: @number)
flash[:danger] = "Unknown band number"
return redirect_to country_bands_path
end
Expand Down
39 changes: 1 addition & 38 deletions app/models/country_band.rb
Original file line number Diff line number Diff line change
@@ -1,46 +1,9 @@
# frozen_string_literal: true

class CountryBand < ApplicationRecord
BANDS = {
0 => {
value: 0.00,
},
1 => {
value: 0.19,
},
2 => {
value: 0.32,
},
3 => {
value: 0.45,
},
4 => {
value: 2.28,
},
5 => {
value: 3.00,
},
}.freeze

# According to WCA's current dues policy, the due amount per competitor is equivalent
# to this percent of registration fee. Only used if this due amount per competitor is
# larger than the due amount per competitor calculated from the competition's country band.
PERCENT_REGISTRATION_FEE_USED_FOR_DUE_AMOUNT = 0.15

def self.percent_registration_fee_used_for_due_amount(country_band)
return 0 if country_band.nil?
if country_band >= 3
0.15
elsif country_band >= 1
0.05
else
0.00
end
end

belongs_to :country, foreign_key: :iso2, primary_key: :iso2
belongs_to :country_band_detail, foreign_key: :number, primary_key: :number
validates_inclusion_of :iso2, in: Country::WCA_COUNTRY_ISO_CODES
validates_inclusion_of :number, in: BANDS.keys.freeze

def country
Country.find_by_iso2(self.iso2)
Expand Down
6 changes: 6 additions & 0 deletions app/models/country_band_detail.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

class CountryBandDetail < ApplicationRecord
scope :active, -> { where(end_date: nil).or(inactive.invert_where) }
scope :inactive, -> { where(end_date: ..Date.today) }
end
8 changes: 4 additions & 4 deletions app/views/country_bands/_show_band.html.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<div class="row list-group-item country-band">
<div class="col-xs-12 text-center title">
<%= t("country_bands.band_title", number: number) %>
(<%= t("country_bands.due_value", value: data[:value]) %>)
<%= t("country_bands.band_title", number: country_band_detail.number) %>
(<%= t("country_bands.due_value", value: country_band_detail.due_amount_per_competitor_in_cents.to_f / 100) %>)
<% if current_user&.can_admin_finances? %>
<%= link_to(ui_icon("pencil alt"), edit_country_band_path(id: number)) %>
<%= link_to(ui_icon("pencil alt"), edit_country_band_path(id: country_band_detail.number)) %>
<% end %>
</div>
<% (@country_bands_by_number[number] || []).map(&:country).sort_by(&:name).each do |c| %>
<% (@country_bands_by_number[country_band_detail.number] || []).map(&:country).sort_by(&:name).each do |c| %>
<div class="col-xs-6 col-sm-4 col-md-3 col">
<div class="country continent-<%= continent_id_as_class(c.continent.id) %>">
<div class="flag"><%= flag_icon c.iso2 %></div>
Expand Down
4 changes: 2 additions & 2 deletions app/views/country_bands/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
</div>
</div>
<div class="list-group">
<% CountryBand::BANDS.each do |number, data| %>
<%= render "show_band", number: number, data: data %>
<% CountryBandDetail.active.order(:number).each do |country_band_detail| %>
<%= render "show_band", country_band_detail: country_band_detail %>
<% end %>
</div>
</div>
Expand Down
14 changes: 14 additions & 0 deletions db/migrate/20241225030959_create_country_band_details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

class CreateCountryBandDetails < ActiveRecord::Migration[7.2]
def change
create_table :country_band_details do |t|
t.integer "number", null: false
t.date "start_date", null: false
t.date "end_date"
t.integer "due_amount_per_competitor_in_cents", null: false
t.integer "due_percent_registration_fee", null: false
t.timestamps
end
end
end
46 changes: 46 additions & 0 deletions db/migrate/20241225031242_populate_country_band_details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

class PopulateCountryBandDetails < ActiveRecord::Migration[7.2]
def up
CountryBandDetail.create!(
number: 0,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 0,
due_percent_registration_fee: 0,
)
CountryBandDetail.create!(
number: 1,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 19,
due_percent_registration_fee: 5,
)
CountryBandDetail.create!(
number: 2,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 32,
due_percent_registration_fee: 5,
)
CountryBandDetail.create!(
number: 3,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 45,
due_percent_registration_fee: 15,
)
CountryBandDetail.create!(
number: 4,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 228,
due_percent_registration_fee: 15,
)
CountryBandDetail.create!(
number: 5,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 300,
due_percent_registration_fee: 15,
)
end

def down
CountryBandDetail.delete_all
end
end
12 changes: 11 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2024_11_24_050607) do
ActiveRecord::Schema[7.2].define(version: 2024_12_25_031242) do
create_table "Competitions", id: { type: :string, limit: 32, default: "" }, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
t.string "name", limit: 50, default: "", null: false
t.string "cityName", limit: 50, default: "", null: false
Expand Down Expand Up @@ -665,6 +665,16 @@
t.datetime "updated_at", null: false
end

create_table "country_band_details", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
t.integer "number", null: false
t.date "start_date", null: false
t.date "end_date"
t.integer "due_amount_per_competitor_in_cents", null: false
t.integer "due_percent_registration_fee", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "country_bands", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
t.integer "number", null: false
t.string "iso2", limit: 2, null: false
Expand Down
38 changes: 38 additions & 0 deletions db/seeds/country_band_details.seeds.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

CountryBandDetail.create!(
number: 0,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 0,
due_percent_registration_fee: 0,
)
CountryBandDetail.create!(
number: 1,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 19,
due_percent_registration_fee: 5,
)
CountryBandDetail.create!(
number: 2,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 32,
due_percent_registration_fee: 5,
)
CountryBandDetail.create!(
number: 3,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 45,
due_percent_registration_fee: 15,
)
CountryBandDetail.create!(
number: 4,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 228,
due_percent_registration_fee: 15,
)
CountryBandDetail.create!(
number: 5,
start_date: '2018-01-01',
due_amount_per_competitor_in_cents: 300,
due_percent_registration_fee: 15,
)
14 changes: 14 additions & 0 deletions lib/database_dumper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,20 @@ def self.actions_to_column_sanitizers(columns_by_action)
),
),
}.freeze,
"country_band_details" => {
column_sanitizers: actions_to_column_sanitizers(
copy: %w(
id
number
start_date
end_date
due_amount_per_competitor_in_cents
due_percent_registration_fee
created_at
updated_at
),
),
}.freeze,
"user_roles" => {
where_clause: "JOIN user_groups ON user_groups.id=group_id WHERE NOT user_groups.is_hidden",
column_sanitizers: actions_to_column_sanitizers(
Expand Down
15 changes: 9 additions & 6 deletions lib/dues_calculator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@ def self.dues_for_n_competitors(country_iso2, base_entry_fee_lowest_denomination

def self.dues_per_competitor_in_usd(country_iso2, base_entry_fee_lowest_denomination, currency_code)
country_band = CountryBand.find_by(iso2: country_iso2)&.number
country_band_detail = CountryBandDetail.find_by(number: country_band)
registration_fees = Money.new(base_entry_fee_lowest_denomination, currency_code).exchange_to("USD")

DuesCalculator.update_exchange_rates_if_needed
input_money_us_dollars = Money.new(base_entry_fee_lowest_denomination, currency_code).exchange_to("USD")

registration_fee_dues_us_dollars = input_money_us_dollars * CountryBand.percent_registration_fee_used_for_due_amount(country_band)
country_band_dues_us_dollars = country_band.present? && country_band > 0 ? CountryBand::BANDS[country_band][:value] : 0
# times 100 because Money require lowest currency subunit, which is cents for USD
country_band_dues_us_dollars_money = Money.new(country_band_dues_us_dollars * 100, "USD")
# Calculation of 'registration fee dues'
registration_fee_dues = Money.new(registration_fees * (country_band_detail&.due_percent_registration_fee.to_f || 0) / 100, "USD")

[registration_fee_dues_us_dollars, country_band_dues_us_dollars_money].max
# Calculation of 'country band dues'
country_band_dues = Money.new(country_band_detail&.due_amount_per_competitor_in_cents || 0, "USD")

# The maximum of the two is the total dues per competitor
[registration_fee_dues, country_band_dues].max
rescue Money::Currency::UnknownCurrency, CurrencyUnavailable
nil
end
Expand Down
2 changes: 1 addition & 1 deletion spec/models/country_band_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@

it "invalidates band with invalid band id" do
cb = CountryBand.new(number: 6, iso2: "HELLO")
expect(cb).to be_invalid_with_errors(number: ["is not included in the list"])
expect(cb).to be_invalid_with_errors(country: ["must exist"])
end
end
1 change: 1 addition & 0 deletions spec/support/test_db_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class TestDbManager
groups_metadata_councils
groups_metadata_teams_committees
groups_metadata_translators
country_band_details
).freeze

def self.fill_tables
Expand Down
Loading