1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Insurance refunds calculation base classes.
22 # `RefundProcessor` manages the calculation of the refunds.
27 # Where to generate output file.
28 var output_file
: String is noinit
, writable
30 # Where to save usage statistics.
31 var stats_file
= "stats.json"
33 # Processes the `input_file` and write the output in `output_file`.
37 # 1. Parses the input_file and check json validity (see `load_input`).
38 # 2. Instantiates and checks the reclamation sheet against client rules
39 # (see `ReclamationSheet.from_json`).
40 # 3. Processes refunds (see `proces_refunds`).
41 # 4. Writes the output file (see `write_output`).
42 fun process
(input_file
, output_file
: String) is abstract
44 # Refunds allowed for the current reclamation sheet.
45 var current_refunds
= new HashMap[Care, Dollar]
47 # Computes allowed refunds for a given `Reclamation` found in a `ReclamationSheet`.
48 fun process_refund
(sheet
: ReclamationSheet, recl
: Reclamation): Dollar is abstract
50 # Shows stats values in console
51 fun show_stats
do print load_stats
53 # Loads stats from file as a RefundStats instance.
54 fun load_stats
: RefundStats is abstract
56 # Saves stats in file.
57 fun save_stats
(stats
: RefundStats) is abstract
59 # Outputs error object then exit.
60 fun die
(msg
: String) is abstract
64 # Basically delete the stats file.
65 fun clear_stats
do if stats_file
.file_exists
then stats_file
.file_delete
68 # Stats representation using a `Counter`.
73 # A `Client` can ask for refunds from the insurance company.
79 redef fun to_s
do return "#{number}"
82 # A `ReclamationSheet` is filled by the `Client` to obtain a `RefundSheet`.
83 class ReclamationSheet
85 # File used for this refund.
86 var file
: ReclFile is writable
88 # Month concerned by the refund.
89 var month
: ReclMonth is writable
91 # Array of reclamations.
92 var recls
= new Array[Reclamation] is writable
95 return "Refund (file: {file}, month: {month}, recls: {recls.length})"
99 # A File found in a `ReclamationSheet`.
101 # A File points to a `Contract` and a `Client`.
103 # Allowed format is: `X12345` where `X` is the contract kind and `12345` is the
108 var id
: String is writable
110 # Contract instance linked to this file.
111 var contract
: Contract is noinit
, writable
113 # Client instance linked to this file.
114 var client
: Client is noinit
, writable
116 # Returns the contract instance corresponding to `kind`.
117 fun contract_factory
(proc
: RefundProcessor, kind
: String): Contract do
118 if kind
== "A" then return new ContractA
119 if kind
== "B" then return new ContractB
120 if kind
== "C" then return new ContractC
121 if kind
== "D" then return new ContractD
122 if kind
== "E" then return new ContractE
123 proc
.die
("Unknown contract {kind}")
127 redef fun to_s
do return "{contract.kind}{client.number}"
130 # Month date formatted for contracts.
132 # Mainly used to factorize treatments on date calculation.
135 # Internal date used to store the month.
136 var date
: ReclDate is writable
138 # Is `date` in this month?
139 fun has
(date
: ReclDate): Bool do return self.date
.month
== date
.month
142 if date
.month
< 10 then
143 return "{date.year}-0{date.month}"
145 return "{date.year}-0{date.month}"
149 # The date on which a `Care` occured.
152 var year
: Int is writable
154 # Month number (`1` is January).
155 var month
: Int is writable
158 var day
: Int is writable
161 var res
= new FlatBuffer
164 res
.append
"0{month}-"
166 res
.append
"{month}-"
173 return res
.write_to_string
177 # `RefundRecl` are parts of the `RefundReclamation`.
179 # `Care` id concerned by this reclamation.
180 var care_id
: Int is writable
182 # Date this care was applied.
183 var date
: ReclDate is writable
185 # Amount of money given by the `Client` in exchange of this care.
186 var fees
: Dollar is writable
188 redef fun to_s
do return "Entry (care: {care_id}, date: {date}, fees: {fees})"
191 # A `Contract` specifies the refund applicable on care.
194 # Kind of the contract (specified by a letter).
195 var kind
: String is noinit
, writable
197 # Covered cares for this kind of contract.
198 var cares
= new Array[Care] is writable
200 # Adds a care to this contract.
201 fun add_care
(care
: Care) do cares
.add care
203 # Gets a `Care` instance by its id.
205 # Returns `null` if no `Care` found.
206 fun care_by_id
(id
: Int): nullable Care do
208 if care
.match_id
(id
) then return care
213 redef fun to_s
do return "{kind} ({cares.length} cares)"
217 # FIXME move contracts to a JSON configuration file.
219 private class ContractA
224 add_care
(new UniqCare.with_vals
(0, 25.0, null, null))
225 add_care
(new UniqCare.with_vals
(100, 35.0, null, 250.0.to_dollar
))
226 add_care
(new UniqCare.with_vals
(150, 0.0, null, null))
227 add_care
(new UniqCare.with_vals
(175, 50.0, null, 200.0.to_dollar
))
228 add_care
(new UniqCare.with_vals
(200, 25.0, null, 250.0.to_dollar
))
229 add_care
(new RangeCare.with_vals
([300..399], 0.0, null, null))
230 add_care
(new UniqCare.with_vals
(400, 0.0, null, null))
231 add_care
(new UniqCare.with_vals
(500, 25.0, null, 150.0.to_dollar
))
232 add_care
(new UniqCare.with_vals
(600, 40.0, null, 300.0.to_dollar
))
233 add_care
(new UniqCare.with_vals
(700, 0.0, null, null))
237 private class ContractB
242 add_care
(new UniqCare.with_vals
(0, 50.0, 40.0.to_dollar
, null))
243 add_care
(new UniqCare.with_vals
(100, 50.0, 50.0.to_dollar
, 250.0.to_dollar
))
244 add_care
(new UniqCare.with_vals
(150, 0.0, null, null))
245 add_care
(new UniqCare.with_vals
(175, 75.0, null, 200.0.to_dollar
))
246 add_care
(new UniqCare.with_vals
(200, 100.0,null, 250.0.to_dollar
))
247 add_care
(new RangeCare.with_vals
([300..399], 50.0, null, null))
248 add_care
(new UniqCare.with_vals
(400, 0.0, null, null))
249 add_care
(new UniqCare.with_vals
(500, 50.0, 50.0.to_dollar
, 150.0.to_dollar
))
250 add_care
(new UniqCare.with_vals
(600, 100.0,null, 300.0.to_dollar
))
251 add_care
(new UniqCare.with_vals
(700, 70.0, null, null))
255 private class ContractC
260 add_care
(new UniqCare.with_vals
(0, 90.0, null, null))
261 add_care
(new UniqCare.with_vals
(100, 95.0, null, 250.0.to_dollar
))
262 add_care
(new UniqCare.with_vals
(150, 85.0, null, null))
263 add_care
(new UniqCare.with_vals
(175, 90.0, null, 200.0.to_dollar
))
264 add_care
(new UniqCare.with_vals
(200, 90.0, null, 250.0.to_dollar
))
265 add_care
(new RangeCare.with_vals
([300..399], 90.0, null, null))
266 add_care
(new UniqCare.with_vals
(400, 90.0, null, null))
267 add_care
(new UniqCare.with_vals
(500, 90.0, null, 150.0.to_dollar
))
268 add_care
(new UniqCare.with_vals
(600, 75.0, null, 300.0.to_dollar
))
269 add_care
(new UniqCare.with_vals
(700, 90.0, null, null))
273 private class ContractD
278 add_care
(new UniqCare.with_vals
(0, 100.0, 85.0.to_dollar
, null))
279 add_care
(new UniqCare.with_vals
(100, 100.0, 75.0.to_dollar
, 250.0.to_dollar
))
280 add_care
(new UniqCare.with_vals
(150, 100.0, 150.0.to_dollar
, null))
281 add_care
(new UniqCare.with_vals
(175, 95.0, null, 200.0.to_dollar
))
282 add_care
(new UniqCare.with_vals
(200, 100.0, 100.0.to_dollar
, 250.0.to_dollar
))
283 add_care
(new RangeCare.with_vals
([300..399],100.0, null, null))
284 add_care
(new UniqCare.with_vals
(400, 100.0, 65.0.to_dollar
, null))
285 add_care
(new UniqCare.with_vals
(500, 100.0, null, 150.0.to_dollar
))
286 add_care
(new UniqCare.with_vals
(600, 100.0, 100.0.to_dollar
, 300.0.to_dollar
))
287 add_care
(new UniqCare.with_vals
(700, 100.0, 90.0.to_dollar
, null))
291 private class ContractE
296 add_care
(new UniqCare.with_vals
(0, 15.0, null, null))
297 add_care
(new UniqCare.with_vals
(100, 25.0, null, 250.0.to_dollar
))
298 add_care
(new UniqCare.with_vals
(150, 15.0, null, null))
299 add_care
(new UniqCare.with_vals
(175, 25.0, 20.0.to_dollar
, 200.0.to_dollar
))
300 add_care
(new UniqCare.with_vals
(200, 12.0, null, 250.0.to_dollar
))
301 add_care
(new RangeCare.with_vals
([300..399], 60.0, null, null))
302 add_care
(new UniqCare.with_vals
(400, 25.0, 15.0.to_dollar
, null))
303 add_care
(new UniqCare.with_vals
(500, 30.0, 20.0.to_dollar
, 150.0.to_dollar
))
304 add_care
(new UniqCare.with_vals
(600, 15.0, null, 300.0.to_dollar
))
305 add_care
(new UniqCare.with_vals
(700, 22.0, null, null))
309 # A `Care` is payed by the `Client` and can raises a `Refund`.
312 # Does `id` is acceptable for this care?
313 fun match_id
(id
: Int): Bool is abstract
315 # Percent covered for this kind of care.
316 fun cover
: Float is abstract
318 # Max amount covered for this kind of care by reclamation.
319 fun max
: nullable Dollar is abstract
321 # Max amount covered for this kind of care by month.
322 fun month_max
: nullable Dollar is abstract
324 # Computes the refund for this care.
325 fun process_refund
(fees
: Dollar): Dollar do
327 var val
= ((fees
.value
.to_f
* (cover
/ 100.0)) / 100.0).to_dollar
328 if max
!= null and val
> max
then val
= max
333 # A `UniqCare` refers to one and only one kind of `Care`.
335 # For example, the care `Ostéopathie` as the uniq id `200`.
342 redef fun match_id
(id
) do return self.id
== id
344 redef var cover
= 0.0
346 redef var month_max
= null
348 # Inits this `Care` with values.
350 # * `id`: the `Care` id.
351 # * `cover`: refund percentage covered for this `Care`.
352 # * `max`: max amount refunded for this `Care` in a reclamation sheet.
353 # * `month_max`: max amount refunded by month.
354 init with_vals
(id
: Int, cover
: Float, max
, month_max
: nullable Dollar) do
358 self.month_max
= month_max
361 redef fun to_s
do return id
.to_s
364 # A `RangeCare` refers to a set of id corresponding to the same `Care`.
366 # For example, the care `Soins Dentaires` is refered by the ids 300 to 399.
373 redef fun match_id
(id
) do return self.id
.has
(id
)
374 redef var cover
= 0.0
376 redef var month_max
= null
378 # Inits this `Care` with values.
380 # * `id`: the `Care` id.
381 # * `cover`: refund percentage covered for this `Care`.
382 # * `max`: max amount refunded for this `Care` in a reclamation sheet.
383 # * `month_max`: max amount refunded by month.
384 init with_vals
(id
: Range[Int], cover
: Float, max
, month_max
: nullable Dollar) do
388 self.month_max
= month_max
391 redef fun to_s
do return id
.first
.to_s
394 # Used to represent currencies values.
398 redef type OTHER: Dollar
403 # Inits `self` from a float `value`.
404 init from_float
(value
: Float) do
405 self.value
= (value
* 100.0).to_i
408 redef fun to_s
do return "{value / 100}.{value % 100}$"
409 redef fun <(o
) do return value
< o
.value
412 fun +(o
: Dollar): Dollar do return new Dollar(value
+ o
.value
)
414 # Dollars substraction.
415 fun -(o
: Dollar): Dollar do return new Dollar(value
- o
.value
)
419 # Returns `self` as a Dollar instance.
420 fun to_dollar
: Dollar do return new Dollar.from_float
(self)