cash_register 0.1.0 → 0.1.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 +85 -0
- data/lib/cash_register/deal.rb +17 -0
- data/lib/cash_register/deals.rb +23 -0
- data/lib/cash_register/discount_item.rb +18 -0
- data/lib/cash_register/free_item.rb +8 -0
- data/lib/cash_register/helper.rb +7 -0
- data/lib/cash_register/list_item.rb +25 -0
- data/lib/cash_register/normal_item.rb +26 -0
- data/lib/cash_register/promotions.rb +22 -0
- data/lib/cash_register/two4one_item.rb +12 -0
- data/lib/cash_register.rb +3 -9
- data/spec/cash_register/deals_spec.rb +5 -1
- data/spec/cash_register/helper_spec.rb +9 -0
- metadata +13 -3
- data/spec/cash_register/util_spec.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b6e16af5305bd7b90f3dce3eab1641d4b499a48
|
4
|
+
data.tar.gz: b8593e873e1e91fd160590e731daa64fc307070d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d283e22982a79dede3e124b965e52484006fc783b18ad66b888bdd60d1d41966e8ce45bcffa995557354ba5521f8e91dcb04edcd9fed74f4d3f6a077ee026f17
|
7
|
+
data.tar.gz: d7d9695fd22acdb2aa341570ed94c23dfe640917fe56ff8f7f65c49d408a45c707f0adc8d7657caa37b1239b6353bee2fa1e6e6492cdf7ba5ef498c15f97124a
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
A basic cash register
|
2
|
+
|
3
|
+
商店里进行购物结算时会使用收银机系统,这台收银机会在结算时根据客户的购物车中的商品和商店正在进行的优惠活动进行结算和打印购物小票。
|
4
|
+
|
5
|
+
已知商品信息包含:名称,数量单位,单价,类别和条形码(伪)。
|
6
|
+
已知我们可以对收银机进行设置,使之支持各种优惠。
|
7
|
+
|
8
|
+
我们需要实现一个名为打印小票的小模块,收银机会将输入的数据转换成一个JSON数据然后一次性传给我们这个小模块,我们将从控制台中输出结算清单的文本。
|
9
|
+
|
10
|
+
输入格式(样例):
|
11
|
+
```Ruby
|
12
|
+
[
|
13
|
+
'ITEM000001',
|
14
|
+
'ITEM000001',
|
15
|
+
'ITEM000001',
|
16
|
+
'ITEM000001',
|
17
|
+
'ITEM000001',
|
18
|
+
'ITEM000003-2',
|
19
|
+
'ITEM000005',
|
20
|
+
'ITEM000005',
|
21
|
+
'ITEM000005'
|
22
|
+
]
|
23
|
+
```
|
24
|
+
其中对'ITEM000003-2'来说,"-"之前的是标准的条形码,"-"之后的是数量。
|
25
|
+
当我们购买需要称量的物品的时候,由称量的机器生成此类条形码,收银机负责识别生成小票。
|
26
|
+
|
27
|
+
该商店正在对部分商品进行“买二赠一”的优惠活动和对部分商品进行95折的优惠活动。其中:
|
28
|
+
* “买二赠一”是指,每当买进两个商品,就可以免费再买一个相同商品。
|
29
|
+
* “95折”是指,在计算小计的时候按单价的95%计算每个商品。
|
30
|
+
* 每一种优惠都详细标记了哪些条形码对应的商品可以享受此优惠。
|
31
|
+
* 店员设置,当“95折”和“买二赠一”发生冲突的时候,也就是一款商品既符合享受“买二赠一”优惠的条件,又符合享受“95折”优惠的 * 条件时,只享受“买二赠一”优惠。
|
32
|
+
* 要求写代码支持上述的功能,并根据输入和设置的不同,输出下列小票。
|
33
|
+
小票内容及格式(样例):
|
34
|
+
|
35
|
+
当购买的商品中,有符合“买二赠一”优惠条件的商品时:
|
36
|
+
```Ruby
|
37
|
+
***<没钱赚商店>购物清单***
|
38
|
+
名称:可口可乐,数量:3瓶,单价:3.00(元),小计:6.00(元)
|
39
|
+
名称:羽毛球,数量:5个,单价:1.00(元),小计:4.00(元)
|
40
|
+
名称:苹果,数量:2斤,单价:5.50(元),小计:11.00(元)
|
41
|
+
----------------------
|
42
|
+
买二赠一商品:
|
43
|
+
名称:可口可乐,数量:1瓶
|
44
|
+
名称:羽毛球,数量:1个
|
45
|
+
----------------------
|
46
|
+
总计:21.00(元)
|
47
|
+
节省:4.00(元)
|
48
|
+
**********************
|
49
|
+
```
|
50
|
+
当购买的商品中,没有符合“买二赠一”优惠条件的商品时:
|
51
|
+
```Ruby
|
52
|
+
***<没钱赚商店>购物清单***
|
53
|
+
名称:可口可乐,数量:3瓶,单价:3.00(元),小计:9.00(元)
|
54
|
+
名称:羽毛球,数量:5个,单价:1.00(元),小计:5.00(元)
|
55
|
+
名称:苹果,数量:2斤,单价:5.50(元),小计:11.00(元)
|
56
|
+
----------------------
|
57
|
+
总计:25.00(元)
|
58
|
+
**********************
|
59
|
+
```
|
60
|
+
当购买的商品中,有符合“95折”优惠条件的商品时
|
61
|
+
```Ruby
|
62
|
+
***<没钱赚商店>购物清单***
|
63
|
+
名称:可口可乐,数量:3瓶,单价:3.00(元),小计:9.00(元)
|
64
|
+
名称:羽毛球,数量:5个,单价:1.00(元),小计:5.00(元)
|
65
|
+
名称:苹果,数量:2斤,单价:5.50(元),小计:10.45(元),节省0.55(元)
|
66
|
+
----------------------
|
67
|
+
总计:24.45(元)
|
68
|
+
节省:0.55(元)
|
69
|
+
**********************
|
70
|
+
```
|
71
|
+
当购买的商品中,有符合“95折”优惠条件的商品,又有符合“买二赠一”优惠条件的商品时
|
72
|
+
```Ruby
|
73
|
+
***<没钱赚商店>购物清单***
|
74
|
+
名称:可口可乐,数量:3瓶,单价:3.00(元),小计:6.00(元)
|
75
|
+
名称:羽毛球,数量:6个,单价:1.00(元),小计:4.00(元)
|
76
|
+
名称:苹果,数量:2斤,单价:5.50(元),小计:10.45(元),节省0.55(元)
|
77
|
+
----------------------
|
78
|
+
买二赠一商品:
|
79
|
+
名称:可口可乐,数量:1瓶
|
80
|
+
名称:羽毛球,数量:2个
|
81
|
+
----------------------
|
82
|
+
总计:20.45(元)
|
83
|
+
节省:4.55(元)
|
84
|
+
**********************
|
85
|
+
```
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#商品类
|
3
|
+
module CashRegister
|
4
|
+
class Deal
|
5
|
+
attr_accessor :code, :name, :price, :unit
|
6
|
+
def initialize(args)
|
7
|
+
assign_attributes(args)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def assign_attributes(args)
|
12
|
+
args.each do |attribute, value|
|
13
|
+
send "#{attribute}=", value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#商品列表
|
3
|
+
require 'json'
|
4
|
+
module CashRegister
|
5
|
+
module Deals
|
6
|
+
class InvalidDealError < ::StandardError
|
7
|
+
end
|
8
|
+
class << self
|
9
|
+
def init_deals(deals_json_path)
|
10
|
+
@deals ||= {}
|
11
|
+
(JSON.parse(File.read(deals_json_path)) rescue []).map do |deal|
|
12
|
+
@deals[deal['code']] = Deal.new(deal)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_by_code(code = '')
|
17
|
+
deal = @deals[code]
|
18
|
+
raise InvalidDealError if deal.nil?
|
19
|
+
deal
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative "normal_item"
|
3
|
+
module CashRegister
|
4
|
+
class DiscountItem < NormalItem
|
5
|
+
def saving
|
6
|
+
deal.price * count * 0.05
|
7
|
+
end
|
8
|
+
|
9
|
+
def billing
|
10
|
+
total = super
|
11
|
+
total - saving
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
super + ",节省:#{format_price saving}(元)"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module CashRegister
|
3
|
+
class ListItem
|
4
|
+
attr_accessor :deal, :count
|
5
|
+
attr_reader :free_item, :item
|
6
|
+
|
7
|
+
def initialize(code, count)
|
8
|
+
@deal = Deals.find_by_code(code)
|
9
|
+
@count = count
|
10
|
+
@item ||= if Promotions.is_two_for_one?(deal.code)
|
11
|
+
free_num = count/3
|
12
|
+
@free_item = FreeItem.new(deal, free_num)
|
13
|
+
Two4OneItem.new(deal, count)
|
14
|
+
elsif Promotions.is_discount?(deal.code)
|
15
|
+
DiscountItem.new(deal, count)
|
16
|
+
else
|
17
|
+
NormalItem.new(deal, count)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
item.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative "helper"
|
3
|
+
|
4
|
+
module CashRegister
|
5
|
+
class NormalItem
|
6
|
+
include CashRegister::Helper
|
7
|
+
attr_accessor :deal, :count
|
8
|
+
|
9
|
+
def initialize(deal, count)
|
10
|
+
@deal = deal
|
11
|
+
@count = count
|
12
|
+
end
|
13
|
+
|
14
|
+
def billing
|
15
|
+
@billing ||= deal.price * count
|
16
|
+
end
|
17
|
+
|
18
|
+
def saving
|
19
|
+
0
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"名称:#{deal.name},数量:#{count}#{deal.unit},单价:#{format_price deal.price}(元),小计:#{format_price billing}(元)"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json'
|
2
|
+
module CashRegister
|
3
|
+
#促销列表
|
4
|
+
module Promotions
|
5
|
+
class << self
|
6
|
+
def init_promotions(promotions_json_path)
|
7
|
+
@promotions ||= {}
|
8
|
+
(JSON.parse(File.read(promotions_json_path)) rescue []).map do |promotion|
|
9
|
+
@promotions[promotion['type']] = promotion['deals']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_two_for_one?(code = '')
|
14
|
+
(@promotions['TWO_FOR_ONE_FREE'] || []).include?(code)
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_discount?(code = '')
|
18
|
+
(@promotions['DISCOUNT'] || []).include?(code)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/cash_register.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
require 'json'
|
3
3
|
Dir["#{File.dirname(__FILE__)}/cash_register/*.rb"].sort.each { |f| require f }
|
4
|
-
|
4
|
+
require_relative 'cash_register/helper'
|
5
5
|
module CashRegister
|
6
6
|
class << self
|
7
|
-
include
|
7
|
+
include CashRegister::Helper
|
8
8
|
|
9
9
|
def output_bill(input_list)
|
10
10
|
output = []
|
@@ -24,10 +24,6 @@ module CashRegister
|
|
24
24
|
output
|
25
25
|
end
|
26
26
|
|
27
|
-
def root
|
28
|
-
File.dirname __dir__
|
29
|
-
end
|
30
|
-
|
31
27
|
private
|
32
28
|
def dashed_line
|
33
29
|
'-'*22
|
@@ -38,7 +34,6 @@ module CashRegister
|
|
38
34
|
end
|
39
35
|
|
40
36
|
def output_summary(items)
|
41
|
-
p items.map(&:billing)
|
42
37
|
output = []
|
43
38
|
output << dashed_line
|
44
39
|
total_payment = items.map(&:billing).inject(&:+)
|
@@ -59,8 +54,7 @@ module CashRegister
|
|
59
54
|
free_items.map{ |free_item| free_item.to_s }
|
60
55
|
end
|
61
56
|
|
62
|
-
def read_list(
|
63
|
-
input_list_path = File.join(CashRegister.root, input_list)
|
57
|
+
def read_list(input_list_path)
|
64
58
|
(JSON.parse(File.read(input_list_path)) rescue []).inject({}) do |mem, input_item|
|
65
59
|
code, count = input_item.split('-')
|
66
60
|
mem[code] ||= 0
|
@@ -6,8 +6,12 @@ RSpec.describe CashRegister::Deals do
|
|
6
6
|
CashRegister::Deals.init_deals('spec/fixture/all_deals.json')
|
7
7
|
end
|
8
8
|
|
9
|
-
it "
|
9
|
+
it "Valid Deal" do
|
10
10
|
deal = CashRegister::Deals.find_by_code('ITEM000001')
|
11
11
|
expect(deal.name).to eq('可口可乐')
|
12
12
|
end
|
13
|
+
|
14
|
+
it "Invalid Deal" do
|
15
|
+
expect{ CashRegister::Deals.find_by_code('ITEM00') }.to raise_error(CashRegister::Deals::InvalidDealError)
|
16
|
+
end
|
13
17
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cash_register
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clark King
|
@@ -30,16 +30,26 @@ executables: []
|
|
30
30
|
extensions: []
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
|
+
- README.md
|
33
34
|
- lib/cash_register.rb
|
35
|
+
- lib/cash_register/deal.rb
|
36
|
+
- lib/cash_register/deals.rb
|
37
|
+
- lib/cash_register/discount_item.rb
|
38
|
+
- lib/cash_register/free_item.rb
|
39
|
+
- lib/cash_register/helper.rb
|
40
|
+
- lib/cash_register/list_item.rb
|
41
|
+
- lib/cash_register/normal_item.rb
|
42
|
+
- lib/cash_register/promotions.rb
|
43
|
+
- lib/cash_register/two4one_item.rb
|
34
44
|
- spec/cash_register/deal_spec.rb
|
35
45
|
- spec/cash_register/deals_spec.rb
|
36
46
|
- spec/cash_register/discount_item_spec.rb
|
37
47
|
- spec/cash_register/free_item_spec.rb
|
48
|
+
- spec/cash_register/helper_spec.rb
|
38
49
|
- spec/cash_register/list_item_spec.rb
|
39
50
|
- spec/cash_register/normal_item_spec.rb
|
40
51
|
- spec/cash_register/promotions_spec.rb
|
41
52
|
- spec/cash_register/two4one_item_spec.rb
|
42
|
-
- spec/cash_register/util_spec.rb
|
43
53
|
- spec/cash_register_spec.rb
|
44
54
|
- spec/fixture/all_deals.json
|
45
55
|
- spec/fixture/deals_dual_promotion.json
|
@@ -78,11 +88,11 @@ test_files:
|
|
78
88
|
- spec/cash_register/free_item_spec.rb
|
79
89
|
- spec/cash_register/two4one_item_spec.rb
|
80
90
|
- spec/cash_register/deal_spec.rb
|
91
|
+
- spec/cash_register/helper_spec.rb
|
81
92
|
- spec/cash_register/normal_item_spec.rb
|
82
93
|
- spec/cash_register/deals_spec.rb
|
83
94
|
- spec/cash_register/list_item_spec.rb
|
84
95
|
- spec/cash_register/discount_item_spec.rb
|
85
|
-
- spec/cash_register/util_spec.rb
|
86
96
|
- spec/cash_register/promotions_spec.rb
|
87
97
|
- spec/spec_helper.rb
|
88
98
|
- spec/cash_register_spec.rb
|