unit4-checkout 0.1.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86c9a4b5ced5591d1e29fab651f213c6b2650bb4704e11635161b3af16076442
4
- data.tar.gz: 015c9dcccbc32478e8ac41875d506588c1319835a57764e985d1cb4140396bcc
3
+ metadata.gz: 3539766a2698101358c85167d1f34d563461cdc23b24098439e1948c2e815fba
4
+ data.tar.gz: 40bc469e6c776039f1d2d424b73d9904e08546181af2f95a117fbd9b4e39d553
5
5
  SHA512:
6
- metadata.gz: 9918c0698cae46a2e02bf767b000a4da06173a023f72b8bae9d4694d09e6b3a92e0a2b1fbceaab4438635253a2bc3a5f9e198f1c6d4079ef8dc9567c174f1aea
7
- data.tar.gz: e511b5b0a2ddf526f51ee5adbbece0c8ba91642203a18ba806100f8c4348e76f6c5218fbb21c31ba2dce68703723b7bd94da078d2fbfdb7adcb8182609bca0c0
6
+ metadata.gz: 7abf3c6c31eeaff5105c9f966d8751e14e94aeb585c31a7a6c3e42321797429ce6ae1e6a7fcd083e30801df9b4795144be22967bb5d759c81ca94af447ce146d
7
+ data.tar.gz: d5c3abb4a0ce0c7599fc5193d44d73560b7de229b1bdb8c9a1607ee71ab2dd569a860292487a9b05fac605082f950a0e6d001fc20a9e119940b03490c6e4a073
data/Gemfile CHANGED
@@ -14,5 +14,3 @@ gem "rubocop", "~> 1.21"
14
14
  gem "activerecord"
15
15
 
16
16
  gem "erb"
17
-
18
- # gem "sqlite3"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- unit4-checkout (0.1.0)
4
+ unit4-checkout (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,20 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record"
4
- require "erb"
5
-
6
3
  class Checkout
7
- attr_reader :promotional_rules, :total, :basket, :price_discount_applied_flag
4
+ attr_reader :total
8
5
 
9
- # {product_discounts: {001: {count:2, price: 3.25}, 004: {count:2, price: 3.25}}, total_price_discount: $50}
10
- def initialize(promotional_rules)
11
- # maybe raise another error if keys aren't ids or total price, possibly total_item_count
12
- raise TypeError, "expected a Hash, got #{promotional_rules.class.name}" unless promotional_rules.is_a? Hash
6
+ def initialize(promotional_rules = {})
7
+ raise PromotionalRulesTypeError, promotional_rules.class.name unless promotional_rules.is_a? Hash
8
+ raise PromotionalRulesForbiddenKeys unless correct_keys?(promotional_rules)
13
9
 
14
10
  @promotional_rules = promotional_rules
15
11
  @total = 0
16
12
  @basket = Basket.new
17
- establish_connection
13
+ create_db_connection
14
+ end
15
+
16
+ def correct_keys?(promotional_rules)
17
+ (promotional_rules.keys - %i[product_discounts total_price_discount]).empty?
18
+ end
19
+
20
+ def create_db_connection
21
+ Connection.new
18
22
  end
19
23
 
20
24
  # maybe facilitate scanning multiple items at once
@@ -23,46 +27,78 @@ class Checkout
23
27
  # check for item id
24
28
  add_to_basket(item)
25
29
  calculate_total(item)
26
- puts "#{item.capitalize} has been added to the basket successfully!"
30
+ puts "Item with ID '#{item}' has been added to the basket successfully!"
27
31
  end
28
32
 
29
33
  def calculate_total(item)
30
- item_price = find_item_price(item)
31
- new_discount_available?(item) ? apply_discounts : @total += item_price
32
- @total
34
+ item_price = item_price(item)
35
+ if @total_price_discount_applied_flag
36
+ item_discounted?(item) ? apply_item_and_total_discount(item, item_price) : apply_total_discount_on_item(item_price)
37
+ else
38
+ item_discounted?(item) ? apply_item_discount(item, item_price) : @total += item_price
39
+ apply_total_discount if total_price_discounted?
40
+ end
41
+ @total = @total.round(2)
42
+ end
43
+
44
+ def item_price(item)
45
+ # TODO: facilitate DB name different from products, i.e. ask gem user for db name???
46
+ PriceQuery.new(item).find_price
47
+ end
48
+
49
+ def apply_item_and_total_discount(item, item_price)
50
+ item_prom_rules = @promotional_rules[:product_discounts][item]
51
+ item_basket_count = @basket.items[item]
52
+ total_discount = (1 - @promotional_rules[:total_price_discount][:percent] / 100.00)
53
+ @total += item_and_total(item_basket_count, item_prom_rules, total_discount, item_price)
33
54
  end
34
55
 
35
- def find_item_price(item)
36
- query = "SELECT * FROM 'users' WHERE 'users'.'id' = ?"
37
- sanitized_query = ActiveRecord::Base.sanitize_sql_array([query, item])
38
- execute_statement(sanitized_query)
39
- ActiveRecord::Base.connection.exec_query(sanitized_query)
56
+ def item_and_total(item_basket_count, item_prom_rules, total_discount, item_price)
57
+ if item_basket_count == item_prom_rules[:count]
58
+ (item_basket_count * item_prom_rules[:price] - (item_basket_count - 1) * item_price) * total_discount
59
+ else
60
+ item_basket_count * item_prom_rules[:price] * total_discount
61
+ end
40
62
  end
41
63
 
42
- def apply_discounts; end
64
+ def apply_total_discount_on_item(item_price)
65
+ @total += item_price * (1 - @promotional_rules[:total_price_discount][:percent] / 100.00)
66
+ end
43
67
 
44
- def new_discount_available?(item); end
68
+ def item_discounted?(item)
69
+ return false unless item_in_discounts?(item)
45
70
 
46
- def execute_statement(sql)
47
- results = ActiveRecord::Base.connection.exec_query(sql)
48
- results if results.present?
71
+ @basket.items[item] >= @promotional_rules[:product_discounts][item][:count]
49
72
  end
50
73
 
51
- def establish_connection
52
- db_config = setup_db_config
53
- ActiveRecord::Base.establish_connection(adapter: db_config["adapter"], database: db_config["database"])
74
+ def item_in_discounts?(item)
75
+ @promotional_rules[:product_discounts] && @promotional_rules[:product_discounts][item]
54
76
  end
55
77
 
56
- def setup_db_config
57
- if defined? Rails && defined? Rails.env
58
- Rails.application.config.database_configuration[Rails.env]
59
- else
60
- # TODO: use current database instead of development
61
- YAML.safe_load(ERB.new(File.read("./config/database.yml")).result, aliases: true)["development"]
62
- end
78
+ def apply_item_discount(item, item_price)
79
+ item_prom_rules = @promotional_rules[:product_discounts][item]
80
+ item_basket_count = @basket.items[item]
81
+ @total += if item_basket_count == item_prom_rules[:count]
82
+ item_basket_count * item_prom_rules[:price] - (item_basket_count - 1) * item_price
83
+ else
84
+ item_prom_rules[:price]
85
+ end
63
86
  end
64
87
 
65
- # maybe add remove item function
88
+ def total_price_discounted?
89
+ return false unless total_price_in_discounts?
90
+
91
+ @total >= @promotional_rules[:total_price_discount][:price]
92
+ end
93
+
94
+ def total_price_in_discounts?
95
+ @promotional_rules[:total_price_discount] && @promotional_rules[:total_price_discount][:price]
96
+ end
97
+
98
+ def apply_total_discount
99
+ @total *= (1 - @promotional_rules[:total_price_discount][:percent] / 100.00)
100
+ @total_price_discount_applied_flag = true
101
+ end
66
102
 
67
103
  def add_to_basket(item)
68
104
  @basket.items[item] ? @basket.items[item] += 1 : @basket.items[item] = 1
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record"
4
+ require "erb"
5
+
6
+ class Connection
7
+ def initialize
8
+ db_config = setup_db_config
9
+ ActiveRecord::Base.establish_connection(adapter: db_config["adapter"], database: db_config["database"])
10
+ end
11
+
12
+ def setup_db_config
13
+ defined?(Rails) && defined?(Rails.env) ? rails_db_config : non_rails_db_config
14
+ end
15
+
16
+ def rails_db_config
17
+ Rails.application.config.database_configuration[Rails.env]
18
+ end
19
+
20
+ def non_rails_db_config
21
+ # TODO: use current database instead of development
22
+ YAML.safe_load(ERB.new(File.read("./config/database.yml")).result, aliases: true)["development"]
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PromotionalRulesTypeError < TypeError
4
+ def initialize(class_name, msg = "expected a Hash, got ", exception_type = "custom")
5
+ msg += class_name
6
+ @exception_type = exception_type
7
+ super(msg)
8
+ end
9
+ end
10
+
11
+ class PromotionalRulesForbiddenKeys < TypeError
12
+ def initialize(msg = "expected Hash with optional keys 'product_discounts' and 'total_price_discount", exception_type = "custom")
13
+ @exception_type = exception_type
14
+ super(msg)
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ class PriceQuery
2
+
3
+ def initialize(item)
4
+ @sanitized_query = prepare_sql_statement(item)
5
+ end
6
+
7
+ def prepare_sql_statement(item)
8
+ # TODO: keep seen items in cache or variable !!!!!!!!!
9
+ ActiveRecord::Base.sanitize_sql_array(["SELECT 'products'.'price' FROM 'products' WHERE 'products'.'id' = ?", item])
10
+ end
11
+
12
+ def find_price
13
+ results = ActiveRecord::Base.connection.exec_query(@sanitized_query)
14
+ results.rows.first.first if results.present?
15
+ end
16
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Unit4
4
4
  module Checkout
5
- VERSION = "0.1.2"
5
+ VERSION = "0.2.1"
6
6
  end
7
7
  end
@@ -3,6 +3,9 @@
3
3
  require_relative "checkout/version"
4
4
  require_relative "checkout/checkout"
5
5
  require_relative "checkout/basket"
6
+ require_relative "checkout/connection"
7
+ require_relative "checkout/price_query"
8
+ require_relative "checkout/exceptions"
6
9
 
7
10
  module Unit4
8
11
  module Checkout
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unit4-checkout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boyan Georgiev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-21 00:00:00.000000000 Z
11
+ date: 2022-07-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Initial commit
13
+ description: A Ruby gem that helps the user implement a checkout system by supplying
14
+ only the promotional rules
14
15
  email:
15
16
  - bbgeorgiev96@gmail.com
16
17
  executables: []
@@ -26,10 +27,14 @@ files:
26
27
  - lib/unit4/checkout.rb
27
28
  - lib/unit4/checkout/basket.rb
28
29
  - lib/unit4/checkout/checkout.rb
30
+ - lib/unit4/checkout/connection.rb
31
+ - lib/unit4/checkout/exceptions.rb
32
+ - lib/unit4/checkout/price_query.rb
29
33
  - lib/unit4/checkout/version.rb
30
34
  - sig/unit4/checkout.rbs
31
35
  homepage: https://github.com/BoyanGeorgiev96/unit4-checkout
32
- licenses: []
36
+ licenses:
37
+ - MIT
33
38
  metadata:
34
39
  allowed_push_host: https://rubygems.org/
35
40
  homepage_uri: https://github.com/BoyanGeorgiev96/unit4-checkout
@@ -52,5 +57,5 @@ requirements: []
52
57
  rubygems_version: 3.3.3
53
58
  signing_key:
54
59
  specification_version: 4
55
- summary: Initial commit
60
+ summary: Checkout gem for Unit4 technical task
56
61
  test_files: []