@@ -74,53 +74,27 @@ def create_invoice_items_for_product(product_id, quantity, discounted_amount)
7474 end
7575
7676 def apply_price_item_added ( product_id , base_price , price )
77- lines = ( state . lines + [ { product_id :, base_price :, price : } ] )
78- state . with ( lines :)
77+ state . add_line ( product_id , base_price , price )
7978 end
8079
8180 def apply_price_item_removed ( product_id )
82- lines = state . lines . dup
83- index_to_remove = lines . find_index { |line | line . fetch ( :product_id ) == product_id }
84- lines . delete_at ( index_to_remove )
85- state . with ( lines :)
81+ state . remove_line ( product_id )
8682 end
8783
8884 def apply_percentage_discount_set ( discount_type , discount_amount )
89- discounts = state . discounts . reject { |d | d . fetch ( :type ) == discount_type }
90- discounts = discounts + [ { type : discount_type , amount : discount_amount } ]
91- new_state = state . with ( discounts :)
92- apply_discounts_to_existing_lines ( new_state )
85+ state . set_discount ( discount_type , discount_amount )
9386 end
9487
9588 def apply_percentage_discount_changed ( discount_type , discount_amount )
96- discounts = state . discounts . reject { |d | d . fetch ( :type ) == discount_type }
97- discounts = discounts + [ { amount : discount_amount } ]
98- new_state = state . with ( discounts : discounts )
99- apply_discounts_to_existing_lines ( new_state )
89+ state . set_discount ( discount_type , discount_amount )
10090 end
10191
10292 def apply_percentage_discount_removed ( discount_type )
103- discounts = state . discounts . reject { |d | d . fetch ( :type ) == discount_type }
104- new_state = state . with ( discounts :)
105- apply_discounts_to_existing_lines ( new_state )
106- end
107-
108- def apply_discounts_to_existing_lines ( new_state )
109- total_discount_percentage = new_state . total_discount_percentage
110- final_discount_percentage = [ total_discount_percentage , 100 ] . min
111- discount_multiplier = ( 1 - final_discount_percentage / 100.0 )
112-
113- updated_lines = new_state . lines . map do |line |
114- base_price = line . fetch ( :base_price )
115- discounted_price = base_price * discount_multiplier
116- line . merge ( price : discounted_price )
117- end
118-
119- new_state . with ( lines : updated_lines )
93+ state . remove_discount ( discount_type )
12094 end
12195
12296 def apply_order_registered
123- state . with ( order_placed : true )
97+ state . mark_placed
12498 end
12599
126100 end
@@ -130,6 +104,50 @@ def initialize(lines: [], discounts: [], order_placed: false)
130104 super ( lines : lines . freeze , discounts : discounts . freeze , order_placed : order_placed )
131105 end
132106
107+ def add_line ( product_id , base_price , price )
108+ with ( lines : lines + [ { product_id :, base_price :, price : } ] )
109+ end
110+
111+ def remove_line ( product_id )
112+ new_lines = lines . dup
113+ index = new_lines . find_index { |line | line . fetch ( :product_id ) == product_id }
114+ new_lines . delete_at ( index )
115+ with ( lines : new_lines )
116+ end
117+
118+ def set_discount ( type , amount )
119+ new_discounts = discounts . reject { |d | d . fetch ( :type ) == type } +
120+ [ { type :, amount : } ]
121+ with_discounts_applied ( new_discounts )
122+ end
123+
124+ def remove_discount ( type )
125+ new_discounts = discounts . reject { |d | d . fetch ( :type ) == type }
126+ with_discounts_applied ( new_discounts )
127+ end
128+
129+ def mark_placed
130+ with ( order_placed : true )
131+ end
132+
133+ def placed?
134+ order_placed
135+ end
136+
137+ def apply_discounts_to_lines
138+ total_discount_percentage = self . total_discount_percentage
139+ final_discount_percentage = [ total_discount_percentage , 100 ] . min
140+ discount_multiplier = ( 1 - final_discount_percentage / 100.0 )
141+
142+ updated_lines = lines . map do |line |
143+ base_price = line . fetch ( :base_price )
144+ discounted_price = base_price * discount_multiplier
145+ line . merge ( price : discounted_price )
146+ end
147+
148+ with ( lines : updated_lines )
149+ end
150+
133151 def sub_amounts_total
134152 lines . each_with_object ( { } ) do |line , memo |
135153 product_id = line . fetch ( :product_id )
@@ -140,6 +158,13 @@ def sub_amounts_total
140158 end
141159 end
142160
161+ private
162+
163+ def with_discounts_applied ( new_discounts )
164+ new_state = with ( discounts : new_discounts )
165+ new_state . apply_discounts_to_lines
166+ end
167+
143168 def subtotal
144169 lines . sum { |line | line . fetch ( :price ) }
145170 end
@@ -155,10 +180,6 @@ def final_discount_percentage
155180 def discounted_value
156181 subtotal * ( 1 - final_discount_percentage / 100.0 )
157182 end
158-
159- def placed?
160- order_placed
161- end
162183 end
163184
164185 class MoneySplitter
0 commit comments