bakool 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +120 -0
- data/lib/bakool/basket.rb +13 -0
- data/lib/bakool/catalogue.rb +9 -0
- data/lib/bakool/delivery_charge_rule.rb +11 -0
- data/lib/bakool/discount_strategies/default_discount.rb +8 -0
- data/lib/bakool/discount_strategies/discount.rb +12 -0
- data/lib/bakool/discount_strategies/fifty_percent_off_2nd_same_item_discount.rb +8 -0
- data/lib/bakool/product.rb +10 -0
- data/lib/bakool/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f6b718a875f6d825342d460912a7c58d03263727f6e333b7d1b235906d1c1e9
|
|
4
|
+
data.tar.gz: 287a1c88f79cfd3408603a60a74de5a4b33374ad1f7f295419c3ca6620416271
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec15dabe54e1dfffba8f6b57cd79ea392dbcbd97218e55388b4fee67ef05597302e9ceecff8f3114f054b0bd040d8ae48b3f0265dc3bae5522b6d71fda72b9cb
|
|
7
|
+
data.tar.gz: a503865557c9e83744cba6f209d8bfc21285b6caf3843e88da58fe58a234e56a3ecd9427e2db65543b28a60f0b4d2c2319fda615e000727cda4ece1d3eb7b113
|
data/README.md
CHANGED
|
@@ -88,6 +88,114 @@ The gem comes with a default catalogue containing:
|
|
|
88
88
|
| G01 | Green Widget | $24.95 |
|
|
89
89
|
| B01 | Blue Widget | $7.95 |
|
|
90
90
|
|
|
91
|
+
### Custom Catalogues
|
|
92
|
+
|
|
93
|
+
You can create your own custom catalogue with your own products. This is useful when you want to use different products or pricing than the default catalogue.
|
|
94
|
+
|
|
95
|
+
#### Creating a Custom Catalogue
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
# Create a new empty catalogue
|
|
99
|
+
catalogue = Bakool::Catalogue.new
|
|
100
|
+
|
|
101
|
+
# Add products to your catalogue
|
|
102
|
+
catalogue.add_product(Bakool::Product.new("Laptop", "LAP01", 999.99))
|
|
103
|
+
catalogue.add_product(Bakool::Product.new("Mouse", "MOU01", 25.50))
|
|
104
|
+
catalogue.add_product(Bakool::Product.new("Keyboard", "KEY01", 75.00))
|
|
105
|
+
catalogue.add_product(Bakool::Product.new("Monitor", "MON01", 299.99))
|
|
106
|
+
|
|
107
|
+
# Create a basket with your custom catalogue
|
|
108
|
+
basket = Bakool::Basket.new(catalogue: catalogue)
|
|
109
|
+
|
|
110
|
+
# Add products using your custom codes
|
|
111
|
+
basket.add("LAP01") # Laptop
|
|
112
|
+
basket.add("MOU01") # Mouse
|
|
113
|
+
basket.add("KEY01") # Keyboard
|
|
114
|
+
|
|
115
|
+
# Calculate total
|
|
116
|
+
total = basket.total
|
|
117
|
+
puts "Total: $#{total}"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Complete Custom Catalogue Example
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
# Create a custom catalogue for an electronics store
|
|
124
|
+
electronics_catalogue = Bakool::Catalogue.new
|
|
125
|
+
|
|
126
|
+
# Add electronics products
|
|
127
|
+
electronics_catalogue.add_product(Bakool::Product.new("iPhone 15", "IPH15", 799.99))
|
|
128
|
+
electronics_catalogue.add_product(Bakool::Product.new("AirPods Pro", "AIRPODS", 249.99))
|
|
129
|
+
electronics_catalogue.add_product(Bakool::Product.new("MacBook Air", "MBA", 1199.99))
|
|
130
|
+
electronics_catalogue.add_product(Bakool::Product.new("iPad Air", "IPAD", 599.99))
|
|
131
|
+
|
|
132
|
+
# Create custom delivery charge rule for electronics
|
|
133
|
+
electronics_delivery = Bakool::DeliveryChargeRule.new(lambda do |order_total|
|
|
134
|
+
if order_total < 10000 then 995 # $9.95 for orders under $100
|
|
135
|
+
elsif order_total < 50000 then 495 # $4.95 for orders under $500
|
|
136
|
+
else 0 # Free delivery for orders $500+
|
|
137
|
+
end
|
|
138
|
+
end)
|
|
139
|
+
|
|
140
|
+
# Create custom discount for AirPods (buy one get one 25% off)
|
|
141
|
+
class AirPodsDiscount < Bakool::Discount
|
|
142
|
+
def calculate(basket)
|
|
143
|
+
airpods = basket.items.filter { |item| item.code == "AIRPODS" }
|
|
144
|
+
if airpods.count >= 2
|
|
145
|
+
# Apply 25% discount to every second AirPod
|
|
146
|
+
(airpods.count / 2) * (airpods.first.price_in_cents * 0.25)
|
|
147
|
+
else
|
|
148
|
+
0
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Create basket with custom catalogue, delivery, and discount
|
|
154
|
+
basket = Bakool::Basket.new(
|
|
155
|
+
catalogue: electronics_catalogue,
|
|
156
|
+
delivery_charge_rule: electronics_delivery,
|
|
157
|
+
discount: AirPodsDiscount.new
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Add items
|
|
161
|
+
basket.add("IPH15") # iPhone 15
|
|
162
|
+
basket.add("AIRPODS") # AirPods Pro
|
|
163
|
+
basket.add("AIRPODS") # Second AirPods Pro (25% off)
|
|
164
|
+
basket.add("MBA") # MacBook Air
|
|
165
|
+
|
|
166
|
+
# Calculate total
|
|
167
|
+
total = basket.total
|
|
168
|
+
puts "Total: $#{total}"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Catalogue API Reference
|
|
172
|
+
|
|
173
|
+
##### `Bakool::Catalogue.new`
|
|
174
|
+
|
|
175
|
+
Creates a new empty catalogue.
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
catalogue = Bakool::Catalogue.new
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
##### `catalogue.add_product(product)`
|
|
182
|
+
|
|
183
|
+
Adds a product to the catalogue.
|
|
184
|
+
|
|
185
|
+
- `product` (Bakool::Product): Product object to add
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
catalogue.add_product(Bakool::Product.new("Product Name", "CODE", 29.99))
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
##### `Bakool::Catalogue.default_catalogue`
|
|
192
|
+
|
|
193
|
+
Returns a catalogue with the default products (Red Widget, Green Widget, Blue Widget).
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
default_catalogue = Bakool::Catalogue.default_catalogue
|
|
197
|
+
```
|
|
198
|
+
|
|
91
199
|
### Custom Delivery Charges
|
|
92
200
|
|
|
93
201
|
```ruby
|
|
@@ -225,16 +333,28 @@ Manages the product inventory.
|
|
|
225
333
|
|
|
226
334
|
Creates a new empty catalogue.
|
|
227
335
|
|
|
336
|
+
```ruby
|
|
337
|
+
catalogue = Bakool::Catalogue.new
|
|
338
|
+
```
|
|
339
|
+
|
|
228
340
|
#### `catalogue.add_product(product)`
|
|
229
341
|
|
|
230
342
|
Adds a product to the catalogue.
|
|
231
343
|
|
|
232
344
|
- `product` (Bakool::Product): Product object to add
|
|
233
345
|
|
|
346
|
+
```ruby
|
|
347
|
+
catalogue.add_product(Bakool::Product.new("Product Name", "CODE", 29.99))
|
|
348
|
+
```
|
|
349
|
+
|
|
234
350
|
#### `Bakool::Catalogue.default_catalogue`
|
|
235
351
|
|
|
236
352
|
Returns a catalogue with default products (Red Widget, Green Widget, Blue Widget).
|
|
237
353
|
|
|
354
|
+
```ruby
|
|
355
|
+
default_catalogue = Bakool::Catalogue.default_catalogue
|
|
356
|
+
```
|
|
357
|
+
|
|
238
358
|
### DeliveryChargeRule
|
|
239
359
|
|
|
240
360
|
Handles delivery charge calculations.
|
data/lib/bakool/basket.rb
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
# A shopping basket that can hold products and calculate totals with discounts and delivery charges
|
|
4
4
|
module Bakool
|
|
5
|
+
# Represents a shopping basket that can hold products and calculate totals
|
|
6
|
+
# with discounts and delivery charges applied.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# basket = Bakool::Basket.new
|
|
10
|
+
# basket.add("R01")
|
|
11
|
+
# basket.add("G01")
|
|
12
|
+
# total = basket.total
|
|
13
|
+
#
|
|
14
|
+
# @attr_reader catalogue [Bakool::Catalogue] The product catalogue
|
|
15
|
+
# @attr_reader items [Array<Bakool::Product>] The items in the basket
|
|
16
|
+
# @attr_reader delivery_charge_rule [Bakool::DeliveryChargeRule] The delivery charge calculation rule
|
|
17
|
+
# @attr_reader discount [Bakool::Discount] The discount strategy to apply
|
|
5
18
|
class Basket
|
|
6
19
|
attr_accessor :catalogue, :items, :delivery_charge_rule, :discount_rule, :discount
|
|
7
20
|
|
data/lib/bakool/catalogue.rb
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
# A catalogue that holds a collection of products
|
|
4
4
|
module Bakool
|
|
5
|
+
# Represents a catalogue that holds a collection of products.
|
|
6
|
+
# Provides methods to add products and retrieve the default catalogue.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# catalogue = Bakool::Catalogue.new
|
|
10
|
+
# catalogue.add_product(Bakool::Product.new("Widget", "W01", 10.00))
|
|
11
|
+
# default_catalogue = Bakool::Catalogue.default_catalogue
|
|
12
|
+
#
|
|
13
|
+
# @attr_reader products [Array<Bakool::Product>] The products in the catalogue
|
|
5
14
|
class Catalogue
|
|
6
15
|
attr_accessor :products
|
|
7
16
|
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
# A rule that calculates delivery charges based on order total
|
|
4
4
|
module Bakool
|
|
5
|
+
# Represents a rule that calculates delivery charges based on order total.
|
|
6
|
+
# Can be customized with a custom calculation function or use the default logic.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# rule = Bakool::DeliveryChargeRule.new
|
|
10
|
+
# charge = rule.calculate(5000) # 495 cents for orders over 0
|
|
11
|
+
#
|
|
12
|
+
# @example Custom rule
|
|
13
|
+
# custom_rule = Bakool::DeliveryChargeRule.new(->(total) { total > 5000 ? 0 : 1000 })
|
|
14
|
+
#
|
|
15
|
+
# @attr_reader func [Proc] The function that calculates delivery charges
|
|
5
16
|
class DeliveryChargeRule
|
|
6
17
|
attr_accessor :func
|
|
7
18
|
|
|
@@ -4,6 +4,14 @@ require_relative "discount"
|
|
|
4
4
|
|
|
5
5
|
# Default discount strategy that applies no discount
|
|
6
6
|
module Bakool
|
|
7
|
+
# Default discount strategy that applies no discount to the basket.
|
|
8
|
+
# This is the fallback discount strategy when no other discounts are applicable.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# discount = Bakool::DefaultDiscount.new
|
|
12
|
+
# amount = discount.calculate(basket) # Always returns 0
|
|
13
|
+
#
|
|
14
|
+
# @see Bakool::Discount
|
|
7
15
|
class DefaultDiscount < Discount
|
|
8
16
|
def calculate(_basket)
|
|
9
17
|
0
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
# Abstract base class for discount strategies
|
|
4
4
|
module Bakool
|
|
5
|
+
# Abstract base class for discount strategies.
|
|
6
|
+
# Subclasses must implement the #calculate method to provide specific discount logic.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# class MyDiscount < Bakool::Discount
|
|
10
|
+
# def calculate(basket)
|
|
11
|
+
# # Custom discount logic here
|
|
12
|
+
# 1000 # Return discount amount in cents
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# @abstract Subclasses must implement {#calculate}
|
|
5
17
|
class Discount
|
|
6
18
|
def calculate(basket)
|
|
7
19
|
raise NotImplementedError, "Subclasses must implement this method"
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
# Discount strategy that applies 50% off the second item of the same type
|
|
4
4
|
module Bakool
|
|
5
|
+
# Discount strategy that applies 50% off the second item of the same type.
|
|
6
|
+
# This discount is applied when there are 2 or more items with the same product code.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# discount = Bakool::FiftyPercentOff2ndSameItemDiscount.new("R01")
|
|
10
|
+
# amount = discount.calculate(basket) # Returns discount amount in cents
|
|
11
|
+
#
|
|
12
|
+
# @see Bakool::Discount
|
|
5
13
|
class FiftyPercentOff2ndSameItemDiscount < Discount
|
|
6
14
|
def initialize(item_code)
|
|
7
15
|
super()
|
data/lib/bakool/product.rb
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
# A product that can be added to a shopping basket
|
|
4
4
|
module Bakool
|
|
5
|
+
# Represents a product that can be added to a shopping basket.
|
|
6
|
+
# Each product has a name, code, and price.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# product = Bakool::Product.new("Red Widget", "R01", 32.95)
|
|
10
|
+
# price_in_cents = product.price_in_cents # 3295
|
|
11
|
+
#
|
|
12
|
+
# @attr_reader name [String] The product name
|
|
13
|
+
# @attr_reader code [String] The product code
|
|
14
|
+
# @attr_reader price [Numeric] The product price in dollars
|
|
5
15
|
class Product
|
|
6
16
|
attr_accessor :name, :code, :price
|
|
7
17
|
|
data/lib/bakool/version.rb
CHANGED