wunder 0.1.0 → 0.1.3
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/Gemfile.lock +8 -0
- data/README.md +78 -10
- data/lib/interface.rb +16 -18
- data/lib/wunder/adjustment.rb +8 -5
- data/lib/wunder/basket.rb +1 -0
- data/lib/wunder/collections/item_collection.rb +1 -0
- data/lib/wunder/concerns/rule_validations.rb +3 -8
- data/lib/wunder/product.rb +2 -1
- data/lib/wunder/promotional/rule/basket_rule.rb +40 -0
- data/lib/wunder/promotional/rule/{quantity_price.rb → item_quantity_price_rule.rb} +12 -8
- data/lib/wunder/promotional_rule.rb +4 -0
- data/lib/wunder/version.rb +1 -1
- data/wunder.gemspec +1 -2
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20f583583705c30caecbe64d86d42c51fa75a81c70d825fded9aa914596dfdd2
|
4
|
+
data.tar.gz: 6bb8d8b8423368dc407632cda431e8aac60b47c5bd79406b04a17580fbf1b605
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9476befdb75097f7dac10e039e6a136bb672c2a52015ffc0e62067264c61be9fe965e15662052c4af6a8d0ae9655907e49ab2ea2e0424ef8e3107dbcf5cc8e43
|
7
|
+
data.tar.gz: 0a2a50de553eacd6f20a8f56177c5aac5155b2f1ba6cfd1bad0a749d4ea4ea1d683d1b68c98217799e024b464595b8d9cce1fc6529c80bb8672ab8c4a5bf48ca
|
data/Gemfile.lock
CHANGED
@@ -15,11 +15,13 @@ GEM
|
|
15
15
|
coderay (1.1.2)
|
16
16
|
concurrent-ruby (1.0.5)
|
17
17
|
diff-lcs (1.3)
|
18
|
+
docile (1.3.1)
|
18
19
|
faker (1.8.7)
|
19
20
|
i18n (>= 0.7)
|
20
21
|
i18n (1.0.1)
|
21
22
|
concurrent-ruby (~> 1.0)
|
22
23
|
jaro_winkler (1.5.1)
|
24
|
+
json (2.1.0)
|
23
25
|
method_source (0.9.0)
|
24
26
|
money (6.11.3)
|
25
27
|
i18n (>= 0.6.4, < 1.1)
|
@@ -56,6 +58,11 @@ GEM
|
|
56
58
|
rubocop-rspec (1.25.1)
|
57
59
|
rubocop (>= 0.53.0)
|
58
60
|
ruby-progressbar (1.9.0)
|
61
|
+
simplecov (0.16.1)
|
62
|
+
docile (~> 1.1)
|
63
|
+
json (>= 1.8, < 3)
|
64
|
+
simplecov-html (~> 0.10.0)
|
65
|
+
simplecov-html (0.10.2)
|
59
66
|
sub-inspector (0.1.5)
|
60
67
|
rubocop (~> 0.55)
|
61
68
|
rubocop-rspec (~> 1.25.1)
|
@@ -75,6 +82,7 @@ DEPENDENCIES
|
|
75
82
|
rake (~> 10.0)
|
76
83
|
rspec (~> 3.0)
|
77
84
|
rubocop (~> 0.57)
|
85
|
+
simplecov (~> 0.16)
|
78
86
|
sub-inspector (= 0.1.5)
|
79
87
|
wunder!
|
80
88
|
|
data/README.md
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
[](https://travis-ci.org/basicsaki/wunder)
|
2
2
|
|
3
3
|
|
4
|
-
#
|
4
|
+
# Wunder
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
TODO: Delete this and the text above, and describe your gem
|
6
|
+
Sample ruby code for a checkout system with flexible rules.
|
9
7
|
|
10
8
|
## Installation
|
11
9
|
|
12
10
|
Add this line to your application's Gemfile:
|
13
11
|
|
14
12
|
```ruby
|
15
|
-
gem '
|
13
|
+
gem 'wunder'
|
16
14
|
```
|
17
15
|
|
18
16
|
And then execute:
|
@@ -23,15 +21,84 @@ Or install it yourself as:
|
|
23
21
|
|
24
22
|
$ gem install checkout
|
25
23
|
|
26
|
-
##
|
24
|
+
## Steps to add a new rule
|
25
|
+
|
26
|
+
Create a new file in the folder
|
27
|
+
|
28
|
+
lib/wunder/promotional/rule/*.rb
|
29
|
+
|
30
|
+
Capture any value or paramters in the initialize method.
|
31
|
+
|
32
|
+
Make sure that the below mentioned methods are available in the file.
|
33
|
+
|
34
|
+
If the discount is on basket define adjustable method as mentioned below.
|
35
|
+
|
36
|
+
Total is the parameter after discounts on individual items.
|
37
|
+
Define calculate_discounted_price to compute the new value after discounts.
|
38
|
+
return false if your rule has only item specific discounts.
|
39
|
+
|
40
|
+
def adjustable?(total)
|
41
|
+
return true if total > value
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def calculate_discounted_price(basket_item, discount_type)
|
46
|
+
if discount_type == "percentage"
|
47
|
+
discount = compute_discount(basket_item)
|
48
|
+
basket_item.product.price = discount
|
49
|
+
elsif discount_type == "flat_rate"
|
50
|
+
basket_item.product.price = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
If the discount is on an item define eligible method as mentioned below.Item is the individual item scaned during the checkout.
|
55
|
+
Define calculate_total_discounted_price to compute the new value after discounts.
|
56
|
+
return false if your rule has only basket specific discounts.
|
57
|
+
|
58
|
+
def eligible?(_item)
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
def calculate_total_discounted_price(total, discount_type)
|
63
|
+
if discount_type == "percentage"
|
64
|
+
discount_price = total - ((total * value) / 100)
|
65
|
+
elsif discount_type == "flat_rate"
|
66
|
+
discount_price = total
|
67
|
+
end
|
68
|
+
discount_price
|
69
|
+
end
|
27
70
|
|
28
|
-
|
71
|
+
Methods in concerns/rule_validations can be used readily to validate the input parameters while capturing the rule.
|
29
72
|
|
30
|
-
##
|
73
|
+
##Example
|
31
74
|
|
32
|
-
|
75
|
+
An interface example has been added at path wunder/lib/interface.rb to calculate and add existing rules.
|
33
76
|
|
34
|
-
|
77
|
+
ruby lib/interface.rb
|
78
|
+
|
79
|
+
To run the tests
|
80
|
+
|
81
|
+
rspec spec
|
82
|
+
|
83
|
+
To check rubocop style guidelines
|
84
|
+
|
85
|
+
rubocop
|
86
|
+
|
87
|
+
To check dependent gem venerabilites
|
88
|
+
|
89
|
+
bundle audit
|
90
|
+
|
91
|
+
|
92
|
+
#Note
|
93
|
+
For rubocop enforcements using a gem sub-inspector for ruby gems.
|
94
|
+
|
95
|
+
|
96
|
+
#Ruby documentation
|
97
|
+
https://www.rubydoc.info/gems/wunder
|
98
|
+
|
99
|
+
##Future Scope
|
100
|
+
Making seperate modules for checkout,promotional rules and parsing products.
|
101
|
+
Adding priority to rules as many rules can be applied to many products. The order in which the rules are applied can be be sorted.
|
35
102
|
|
36
103
|
## Contributing
|
37
104
|
|
@@ -44,3 +111,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
44
111
|
## Code of Conduct
|
45
112
|
|
46
113
|
Everyone interacting in the Checkout project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/checkout/blob/master/CODE_OF_CONDUCT.md).
|
114
|
+
|
data/lib/interface.rb
CHANGED
@@ -4,36 +4,34 @@ require_relative "./wunder.rb"
|
|
4
4
|
# Parser
|
5
5
|
# new expects csv file path,validate {true or false},use mock file true or false
|
6
6
|
parser = Parser.new("", true, true)
|
7
|
-
parser.process_file
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
label = "Percentage discount on prices"
|
9
|
+
label1 = "Flat_rate discount on prices"
|
11
10
|
|
12
|
-
# promotion
|
13
|
-
promotion = Promotion.new("new_year", "1234")
|
14
11
|
|
15
12
|
# rules
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
quantity_rule1 = Promotional::Rule::ItemQuantityPriceRule.new(1, 10)
|
14
|
+
quantity_rule2 = Promotional::Rule::BasketRule.new(20)
|
15
|
+
# promotion
|
16
|
+
promotion = Promotion.new("New Year Flat Discount", "code_115")
|
17
|
+
promotion_rule1 = PromotionalRule.new(label, "percentage", true, quantity_rule1)
|
18
|
+
promotion_rule2 = PromotionalRule.new(label, "flat_rate", true, quantity_rule1)
|
19
|
+
promotion_rule3 = PromotionalRule.new(label1, "percentage", false, quantity_rule2)
|
20
|
+
promotion_rule4 = PromotionalRule.new(label1, "flat_rate", false, quantity_rule2)
|
21
|
+
rules = [promotion_rule1,promotion_rule2,promotion_rule3, promotion_rule4]
|
22
|
+
promotion.add_rules_in_bulk(rules)
|
25
23
|
|
26
24
|
|
27
|
-
|
25
|
+
#File processing
|
26
|
+
parser.process_file
|
27
|
+
products = parser.products
|
28
28
|
|
29
|
-
# promotional Rules
|
30
29
|
# Checkout interface
|
31
30
|
# scan(item) #remove_scan(item)
|
32
|
-
|
33
31
|
co = Checkout.new(promotion.promotion_rules)
|
34
|
-
|
35
32
|
co.scan(products[0])
|
36
33
|
co.scan(products[1])
|
34
|
+
co.remove_scan(products[1])
|
37
35
|
co.scan(products[2])
|
38
36
|
|
39
37
|
table = Print.new([co]).table
|
data/lib/wunder/adjustment.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
class Adjustment
|
2
|
-
attr_reader :basket, :promotional_rules
|
2
|
+
attr_reader :basket, :promotional_rules
|
3
3
|
|
4
4
|
def initialize(basket, promotional_rules)
|
5
5
|
@basket = basket
|
6
6
|
@promotional_rules = promotional_rules
|
7
|
+
@product_promotional_rules = []
|
8
|
+
@basket_promotional_rules = []
|
7
9
|
@applied_promotional_rules = []
|
8
10
|
end
|
9
11
|
|
@@ -31,10 +33,11 @@ class Adjustment
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def apply_basket_discounts(items_total)
|
34
|
-
@basket_promotional_rules =
|
36
|
+
@basket_promotional_rules =
|
37
|
+
eligible_basket_promotional_discounts(items_total)
|
35
38
|
|
36
39
|
unless @basket_promotional_rules.empty?
|
37
|
-
basket_promotional_rules.each do |promotional_rule|
|
40
|
+
@basket_promotional_rules.each do |promotional_rule|
|
38
41
|
items_total = promotional_rule.calculate_total(items_total)
|
39
42
|
end
|
40
43
|
end
|
@@ -56,9 +59,9 @@ class Adjustment
|
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
59
|
-
def eligible_basket_promotional_discounts
|
62
|
+
def eligible_basket_promotional_discounts(total)
|
60
63
|
promotional_rules.select do |promo_rule|
|
61
|
-
promo_rule.on_item == false
|
64
|
+
promo_rule.on_item == false && promo_rule.rule.adjustable?(total)
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
data/lib/wunder/basket.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module RuleValidations
|
2
2
|
DISCOUNT_TYPES = %w[percentage flat_rate].freeze
|
3
3
|
|
4
|
-
def should_be_present(name,
|
5
|
-
raise "#{name}
|
4
|
+
def should_be_present(name, attr)
|
5
|
+
raise "#{name}.capitalize should be present" if attr == "" || attr.nil?
|
6
6
|
end
|
7
7
|
|
8
8
|
def check_discount_type(discount_type)
|
@@ -15,16 +15,11 @@ module RuleValidations
|
|
15
15
|
raise "atleast fill out #{name}" if attr1.empty? && attr2.empty?
|
16
16
|
end
|
17
17
|
|
18
|
-
def atleast_one_should_be_present(name, attr1, attr2)
|
19
|
-
raise "either fill out #{name}" if
|
20
|
-
attr1.empty? == false && attr2.empty? == false
|
21
|
-
end
|
22
|
-
|
23
18
|
def should_be_a_number(name, attribute)
|
24
19
|
raise "#{name} should be a number" if attribute.is_a?(Numeric) == false
|
25
20
|
end
|
26
21
|
|
27
|
-
def
|
22
|
+
def should_be_more_than(name, attribute, number)
|
28
23
|
raise "#{name} should be >= #{number}" if attribute < number
|
29
24
|
end
|
30
25
|
|
data/lib/wunder/product.rb
CHANGED
@@ -4,7 +4,7 @@ class Product
|
|
4
4
|
def initialize(product_code, name, price, no_validate = false)
|
5
5
|
@product_code = product_code
|
6
6
|
@name = name
|
7
|
-
@price = BigDecimal(price)
|
7
|
+
@price = price.nil? ? nil : BigDecimal(price, 2)
|
8
8
|
|
9
9
|
validate if no_validate == false
|
10
10
|
end
|
@@ -13,5 +13,6 @@ class Product
|
|
13
13
|
[product_code, name, price].each do |parameter|
|
14
14
|
raise ArgumentError, "ProductParameterMissing" if parameter.nil?
|
15
15
|
end
|
16
|
+
nil
|
16
17
|
end
|
17
18
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Promotional
|
2
|
+
module Rule
|
3
|
+
class BasketRule < PromotionalRule
|
4
|
+
attr_reader :value
|
5
|
+
|
6
|
+
def initialize(value, no_validate = false)
|
7
|
+
@value = value
|
8
|
+
|
9
|
+
validate if no_validate == false
|
10
|
+
end
|
11
|
+
|
12
|
+
def adjustable?(total)
|
13
|
+
return true if total > value
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def eligible?(_item)
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def calculate_total_discounted_price(total, discount_type)
|
22
|
+
if discount_type == "percentage"
|
23
|
+
discount_price = total - ((total * value) / 100)
|
24
|
+
elsif discount_type == "flat_rate"
|
25
|
+
discount_price = total
|
26
|
+
end
|
27
|
+
|
28
|
+
discount_price
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate
|
32
|
+
should_be_present("BasketRule::Value", value)
|
33
|
+
should_be_a_number("BasketRule::Value",
|
34
|
+
value)
|
35
|
+
should_be_more_than("BasketRule::MinQuantity",
|
36
|
+
value, 1)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Promotional
|
2
2
|
module Rule
|
3
|
-
class
|
3
|
+
class ItemQuantityPriceRule < PromotionalRule
|
4
4
|
attr_reader :minimum_quantity, :value
|
5
5
|
|
6
6
|
def initialize(minimum_quantity, value, no_validate = false)
|
@@ -14,21 +14,25 @@ module Promotional
|
|
14
14
|
item.quantity >= minimum_quantity
|
15
15
|
end
|
16
16
|
|
17
|
+
def adjustable?(_total)
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
17
21
|
def calculate_discounted_price(basket_item, discount_type)
|
18
|
-
if discount_type == "percentage"
|
22
|
+
if discount_type == "percentage"
|
19
23
|
discount = compute_discount(basket_item)
|
20
24
|
basket_item.product.price = discount
|
21
|
-
elsif discount_type == "flat_rate"
|
25
|
+
elsif discount_type == "flat_rate"
|
22
26
|
basket_item.product.price = value
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
26
|
-
def calulate_total_discounted_price(total); end
|
27
|
-
|
28
30
|
def validate
|
29
|
-
should_be_present("
|
30
|
-
should_be_a_number("
|
31
|
-
|
31
|
+
should_be_present("ItemQuantityPriceRule::Value", value)
|
32
|
+
should_be_a_number("ItemQuantityPriceRule::MinimumQuantity",
|
33
|
+
minimum_quantity)
|
34
|
+
should_be_more_than("ItemQuantityPriceRule::MinQuantity",
|
35
|
+
minimum_quantity, 1)
|
32
36
|
end
|
33
37
|
|
34
38
|
private
|
@@ -18,6 +18,10 @@ class PromotionalRule
|
|
18
18
|
raise "Should be defined by the respective rule"
|
19
19
|
end
|
20
20
|
|
21
|
+
def adjustable?(_total)
|
22
|
+
raise "Should be defined by the respective rule"
|
23
|
+
end
|
24
|
+
|
21
25
|
def validate
|
22
26
|
should_be_present("label", label)
|
23
27
|
check_discount_type(discount_type)
|
data/lib/wunder/version.rb
CHANGED
data/wunder.gemspec
CHANGED
@@ -36,13 +36,12 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_dependency "terminal-table","~> 1.8"
|
37
37
|
|
38
38
|
spec.add_development_dependency "pry", "~> 0.11"
|
39
|
+
spec.add_development_dependency "simplecov","~> 0.16"
|
39
40
|
spec.add_development_dependency "faker", "~> 1.8"
|
40
41
|
spec.add_development_dependency "rubocop", "~> 0.57"
|
41
42
|
spec.add_development_dependency "sub-inspector", "0.1.5"
|
42
|
-
|
43
43
|
spec.add_development_dependency "bundler", "~> 1.16"
|
44
44
|
spec.add_development_dependency "bundler-audit","~> 0.6"
|
45
|
-
|
46
45
|
spec.add_development_dependency "rake", "~> 10.0"
|
47
46
|
spec.add_development_dependency "rspec", "~> 3.0"
|
48
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wunder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akhilesh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: money
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.11'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.16'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.16'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: faker
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,7 +198,8 @@ files:
|
|
184
198
|
- lib/wunder/print.rb
|
185
199
|
- lib/wunder/product.rb
|
186
200
|
- lib/wunder/promotion.rb
|
187
|
-
- lib/wunder/promotional/rule/
|
201
|
+
- lib/wunder/promotional/rule/basket_rule.rb
|
202
|
+
- lib/wunder/promotional/rule/item_quantity_price_rule.rb
|
188
203
|
- lib/wunder/promotional_rule.rb
|
189
204
|
- lib/wunder/version.rb
|
190
205
|
- wunder.gemspec
|