Skip to main content

Calculation code comments Calculation controller

On GitHub: app/controllers/calculator_controller.rb

2 class CalculatorController < ApplicationController

Include code from each of the modules for the different styles of calculation.

5   include Calculations::BicameralBothHousesSitting
6   include Calculations::BicameralSiEitherHouseSitting
7   include Calculations::CommonsOnlySi
8   include Calculations::CommonsOnlySittingDays
9   include Calculations::Pnsi
10   include Calculations::Treaty

This is the code to provide a list of calculators.

13   def index

We set the meta information for the page.

16     @page_title = "Calculators"
17     @description = "Calculators made available by #{$SITE_TITLE}."
18     @crumb << { label: 'Calculators', url: nil }
19     @section = 'calculators'
20   end

This is the code to provide information for the form that users can fill in to calculate the scrutiny period by procedure.

23   def scrutiny_period

We find all the active procedures in display order - to populate the procedure radio buttons on the form.

26     @procedures = Procedure.all.where( 'active is true' ).order( 'display_order asc' )

We set the meta information for the page.

29     @page_title = "Scrutiny end date calculator"
30     @multiline_page_title = "Calculators <span class='subhead'>Scrutiny end date</span>".html_safe
31     @description = "A calculator to determine the estimated end date of scrutiny for instruments before Parliament."
32     @crumb << { label: 'Calculators', url: calculator_list_url }
33     @crumb << { label: 'Scrutiny end date', url: nil }
34     @section = 'calculators'
35     @subsection = 'scrutiny-calculator'
36   end

This is the code to provide information for the form that users wishing to run a specific calculation style can fill in.

39   def style

We get the calculation style if it's been passed as a parameter.

42     calculation_style = params['calculation-style']
43     @calculation_style = calculation_style.to_i if calculation_style

We set the meta information for the page.

46     @page_title = "Scrutiny end date calculator for a calculation style"
47     @multiline_page_title = "Calculators <span class='subhead'>Scrutiny end date for a calculation style</span>".html_safe
48     @description = "A calculator to determine the estimated end date of scrutiny for instruments before Parliament for a given calculation style."
49     @crumb << { label: 'About', url: meta_list_url }
50     @crumb << { label: 'Librarian tools', url: meta_librarian_tools_url }
51     @crumb << { label: 'Scrutiny period calculator by calculation style', url: nil }
52   end

This code runs the scrutiny period calculation.

55   def calculate

In order to calculate the anticipated end date of the scrutiny period, we need:

  • the start date, for example: "2020-05-06"
60     start_date = params['start-date']
  • the day count and
63     day_count = params['day-count']
  • either the type of the procedure, which we refer to by a number
66     procedure = params['procedure']
  • or the calculation style, which we also refer to by a number
69     calculation_style = params['calculation-style']

Calling this method also sets instance variables for start date, day count, procedure and calculation style.

If we don't have enough information to proceed with the calculation ...

73     unless calculation_can_proceed?( start_date, day_count, procedure, calculation_style )

... we call the insufficient information method.

76       insufficient_information

Otherwise, if we do have enough information to proceed with the calculation ...

79     else

... if the day count has not been provided or the day count is invalid ...

82       if !@day_count or is_day_count_invalid?( @day_count )

... we set the meta information for the page ...

85         @page_title = "Scrutiny end date - number of days to count required"
86         @multiline_page_title = "Calculators <span class='subhead'>Scrutiny end date - number of days to count required</span>".html_safe
87         @description = "Number of days to count required for a calculation to determine the estimated end date of scrutiny for instruments before Parliament."
88         @crumb << { label: 'Calculators', url: calculator_list_url }
89         @crumb << { label: 'Scrutiny end date', url: calculator_form_url }
90         @crumb << { label: 'Number of days to count required', url: nil }
91         @section = 'calculators'
92         @subsection = 'scrutiny-calculator'

... and we render the day count form.

95         render :template => 'calculator/day_count_form'

Otherwise, if the day count has been provided and the day count is not invalid ...

98       else

If the procedure has been passed as a parameter ...

101         if @procedure

... to calculate the anticipated end date, we select the calculation based on the type of procedure:

104           case @procedure.id
  • Legislative Reform Orders, Public Body Orders, Localism Orders and enhanced affirmatives under the Investigatory Powers Act 2016
107             when 1, 17, 18, 19, 2, 4, 21, 22, 23
109               @start_date_type = "laying date"
110               @scrutiny_end_date = bicameral_calculation_both_houses_sitting( @start_date, @day_count )
  • Proposed Statutory Instruments (PNSIs)
113             when 3
115               @start_date_type = "laying date"
116               @scrutiny_end_date = pnsi_calculation( @start_date, @day_count )
  • Commons only negative Statutory Instruments
119             when 5
121               @start_date_type = "laying date"
122               @scrutiny_end_date = commons_only_si_calculation( @start_date, @day_count )
  • Commons and Lords negative Statutory Instruments, proposed and draft affirmative remedial orders
125             when 6, 13, 14
127               @start_date_type = "laying date"
128               @scrutiny_end_date = bicameral_si_either_house_sitting_calculation( @start_date, @day_count )
  • Some Commons only made affirmative Statutory Instruments
131             when 7
133               @start_date_type = "making date"
134               @scrutiny_end_date = commons_only_si_calculation( @start_date, @day_count )
  • Commons and Lords made affirmative Statutory Instruments where both Houses are sitting
137             when 8
139               @start_date_type = "making date"
140               @scrutiny_end_date = bicameral_calculation_both_houses_sitting( @start_date, @day_count )
  • Commons and Lords made affirmative Statutory Instruments where either House is sitting and made affirmative remedial orders
143             when 9, 15, 16
145               @start_date_type = "making date"
146               @scrutiny_end_date = bicameral_si_either_house_sitting_calculation( @start_date, @day_count )
  • Treaty period A
149             when 10
151               @start_date_type = "laying date"
152               @scrutiny_end_date = treaty_calculation( @start_date, @day_count )
  • Treaty period B
155             when 11
157               @start_date_type = "date of Ministerial statement"
158               @scrutiny_end_date = treaty_calculation( @start_date, @day_count )
  • Published drafts under the European Union (Withdrawal) Act 2018
161             when 12
163               @start_date_type = "date of publication"
164               @scrutiny_end_date = bicameral_calculation_both_houses_sitting( @start_date, @day_count )
  • National Policy Statements.
167             when 20
169               @start_date_type = "laying date"
170               @scrutiny_end_date = commons_only_sitting_days( @start_date, @day_count )
171           end

Otherwise, if the calculation style has been selected ...

174         elsif @calculation_style

... to calculate the anticipated end date, we select the calculation based on the calculation style:

177           case @calculation_style
  • Calculation style 1
180             when 1
182               @scrutiny_end_date = bicameral_calculation_both_houses_sitting( @start_date, @day_count )
  • Calculation style 2
185             when 2
187               @scrutiny_end_date = bicameral_si_either_house_sitting_calculation( @start_date, @day_count )
  • Calculation style 3
190             when 3
192               @scrutiny_end_date = commons_only_si_calculation( @start_date, @day_count )
  • Calculation style 4
195             when 4
197               @scrutiny_end_date = pnsi_calculation( @start_date, @day_count )
  • Calculation style 5
200             when 5
202               @scrutiny_end_date = treaty_calculation( @start_date, @day_count )
  • Calculation style 6
205             when 6
207               @scrutiny_end_date = commons_only_sitting_days( @start_date, @day_count )
208             else

... we add a reason to the missing information array ...

211               @missing_information << 'a valid calculation style'

... and call the insufficient information method.

214               insufficient_information
215           end
216         end
217       end

We set the meta information for the page.

220       @page_title = "Scrutiny end date calculation"
221       @multiline_page_title = "Calculators <span class='subhead'>Scrutiny end date calculation</span>".html_safe
222       @description = "A calculation to determine the estimated end date of scrutiny for instruments before Parliament."
223       @json_url = request.original_fullpath.sub '?', '.json?'
224       @calendar_links << ['Anticipated end date of the scrutiny period', request.original_fullpath.sub( '?', '.ics?' )]
225       @crumb << { label: 'Calculators', url: calculator_list_url }
226       @crumb << { label: 'Scrutiny end date', url: calculator_form_url }
227       @crumb << { label: 'Calculation', url: nil }
228       @section = 'calculators'
229       @subsection = 'scrutiny-calculator'
230     end
231   end

A method to check if the scrutiny period calculation can proceed.

This method also creates the start date, day count, procedure and calculation style as instance variables.

235   def calculation_can_proceed?( start_date, day_count, procedure, calculation_style )

We create a variable to hold a boolean, determining if the scrutiny period calculation can proceed.

238     calculation_can_proceed = true

We create an array to hold any errors we find as a result of missing information.

241     @missing_information = []

We check for the presence of a valid start date.

If the start date is present ...

245     if start_date

... we attempt to convert the start date string into a date, storing the result as a instance variable.

248       begin
249          @start_date = Date.parse( start_date )

If the start date string cannot be converted into a date ...

252       rescue ArgumentError

... we flag that the calculation cannot proceed ...

255         calculation_can_proceed = false

... and add a reason to the missing information array.

258         @missing_information << 'a valid start date'
259       end

Otherwise, if the start date is not present ...

262     else

... we flag that the calculation cannot proceed ...

265       calculation_can_proceed = false

... and add a reason to the missing information array.

268       @missing_information << 'a start date'
269     end

We check for the presence of a valid day count.

If a day count has been passed ...

273     if day_count

... we convert the day count to an integer, storing the result as a instance variable.

276       @day_count = day_count.to_i

If the day count is an invalid day count ...

279       if is_day_count_invalid?( @day_count )

... we do not flag that the calculation cannot proceed because this will be picked up by the day count form.

We add a reason to the missing information array.

284         @missing_information << 'a valid day count'
285       end

Otherwise, if a day count has not been passed ...

288     else

... we do not flag that the calculation cannot proceed because this will be picked up by the day count form.

We add a reason to the missing information array.

293       @missing_information << 'a day count'
294     end

We check for the presence of a valid procedure or a valid calculation style.

If the calculation has been passed neither a procedure, nor a calculation style ...

298     if !procedure and !calculation_style

... we flag that the calculation cannot proceed ...

301       calculation_can_proceed = false

... and add a reason to the missing information array.

304       @missing_information << 'a procedure or calculation style'

Otherwise, if the calculation has been passed a procedure ...

307     elsif procedure

... we attempt to find the procedure, storing the result as a instance variable.

310       @procedure = Procedure.find_by_id( procedure )

If we fail to find the procedure ...

313       unless @procedure

... we flag that the calculation cannot proceed ...

316         calculation_can_proceed = false

... and add a reason to the missing information array.

319         @missing_information << 'a valid procedure'
320       end

Otherwise, if the calculation has been passed a calculation style ...

323     elsif calculation_style

... we convert the calculation style ID to an integer, storing the result as a instance variable.

326       @calculation_style = calculation_style.to_i

If the calculation style is an invalid calculation style ...

329       if is_calculation_style_invalid?( @calculation_style )

... we flag that the calculation cannot proceed ...

332         calculation_can_proceed = false

... and add a reason to the missing information array.

335         @missing_information << 'a valid calculation style'
336       end
337     end

We return the calculation can proceed boolean.

340     calculation_can_proceed
341   end

A method to check if the day count is valid.

344   def is_day_count_valid?( day_count )

We create a boolean to hold the validity of the day count.

347     is_day_count_valid = true

If the day count is zero or a negative number ...

350     if day_count == 0 or day_count.negative?

... we set the is day count valid boolean to false.

353       is_day_count_valid = false
354     end

We return the is day count valid boolean.

357     is_day_count_valid
358   end

A method to check if the day count is invalid.

361   def is_day_count_invalid?( day_count )

We flip the boolean returned by the is day count valid method.

364     !is_day_count_valid?( day_count )
365   end

A method to check if the calculation style is valid.

368   def is_calculation_style_valid?( calculation_style )

We create a boolean to hold the validity of the calculation style.

371     is_calculation_style_valid = true

If the calculation style is zero or a negative number ...

374     if calculation_style == 0 or calculation_style.negative?

... we set the is calculation style valid boolean to false.

377       is_calculation_style_valid = false
378     end

We return the is calculation style valid boolean.

381     is_calculation_style_valid
382   end

A method to check if the calculation style is invalid.

385   def is_calculation_style_invalid?( calculation_style )

We flip the boolean returned by the is calculation style valid method.

388     !is_calculation_style_valid?( calculation_style )
389   end

A method to report that we have insufficient information for the scrutiny period calculation to proceed.

392   def insufficient_information

We set the meta information for the page ...

395     @page_title = "Scrutiny end date - more information required"
396     @multiline_page_title = "Calculators <span class='subhead'>Scrutiny end date - more information required</span>".html_safe
397     @description = "More information required for a calculation to determine the estimated end date of scrutiny for instruments before Parliament."
398     @crumb << { label: 'Calculators', url: calculator_list_url }
399     @crumb << { label: 'Scrutiny end date', url: calculator_form_url }
400     @crumb << { label: 'More information required', url: nil }
401     @section = 'calculators'
402     @subsection = 'scrutiny-calculator'

... and display the not enough information message.

405     render :template => 'calculator/not_enough_information'
406   end
407 end