market_town-checkout 0.1.1 → 0.1.2
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/lib/market_town/checkout.rb +2 -0
- data/lib/market_town/checkout/steps/address_step.rb +25 -0
- data/lib/market_town/checkout/steps/cart_step.rb +20 -0
- data/lib/market_town/checkout/steps/complete_step.rb +18 -0
- data/lib/market_town/checkout/steps/delivery_step.rb +17 -0
- data/lib/market_town/checkout/steps/step.rb +93 -1
- data/lib/market_town/checkout/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d56e8ab33f9b246e43a09187bafe27f4f1726337
|
4
|
+
data.tar.gz: f4365e815a8df693f3d0e0a146445b20310e2377
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b812c35b5a8e7942859866e7635f6eaefbf2d08107830352d2a2e63a434534ffde09a75c15bccf841b96a3cf317f8acc514dc51bbfdcbd173a7f34df157875b
|
7
|
+
data.tar.gz: 0103ea588a6c72642cd4ad491de1c7d09be48027b56b857cc93d12a7bf320b31d6879faf45caf897e24f45fae7d23e20f46f4d51ad2020cd25c9b87c8e53567f
|
data/lib/market_town/checkout.rb
CHANGED
@@ -32,6 +32,7 @@ module MarketTown
|
|
32
32
|
#
|
33
33
|
# ## Available steps
|
34
34
|
#
|
35
|
+
# - {CartStep} – Handles the initialisation of the checkout process
|
35
36
|
# - {AddressStep} – Handles the taking of billing and delivery addresses
|
36
37
|
# - {DeliveryStep} – Handles the choosing of delivery method
|
37
38
|
# - {CompleteStep} – Handles completion of order
|
@@ -56,6 +57,7 @@ require_relative './checkout/missing_dependency'
|
|
56
57
|
require_relative './checkout/dependencies'
|
57
58
|
require_relative './checkout/error'
|
58
59
|
require_relative './checkout/steps/step'
|
60
|
+
require_relative './checkout/steps/cart_step'
|
59
61
|
require_relative './checkout/steps/address_step'
|
60
62
|
require_relative './checkout/steps/delivery_step'
|
61
63
|
require_relative './checkout/steps/complete_step'
|
@@ -1,5 +1,13 @@
|
|
1
1
|
module MarketTown
|
2
2
|
module Checkout
|
3
|
+
# Handles addresses by validating them and optionally storing them.
|
4
|
+
#
|
5
|
+
# Dependencies:
|
6
|
+
# - fulfilments#can_fulfil_address?
|
7
|
+
# - address_storage#store
|
8
|
+
# - fulfilments#propose_shipments
|
9
|
+
# - finish#address_step
|
10
|
+
#
|
3
11
|
class AddressStep < Step
|
4
12
|
class InvalidAddressError < Error; end
|
5
13
|
class CannotFulfilAddressError < Error; end
|
@@ -14,20 +22,30 @@ module MarketTown
|
|
14
22
|
|
15
23
|
protected
|
16
24
|
|
25
|
+
# @raise [InvalidAddressError]
|
26
|
+
#
|
17
27
|
def validate_billing_address(state)
|
18
28
|
validate_address(:billing, state[:billing_address])
|
19
29
|
end
|
20
30
|
|
31
|
+
# Copies billing address into delivery address if requested
|
32
|
+
#
|
21
33
|
def use_billing_address_as_delivery_address(state)
|
22
34
|
if state[:use_billing_address] == true
|
23
35
|
state.merge(delivery_address: state[:billing_address])
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
39
|
+
# @raise [InvalidAddressError]
|
40
|
+
#
|
27
41
|
def validate_delivery_address(state)
|
28
42
|
validate_address(:delivery, state[:delivery_address])
|
29
43
|
end
|
30
44
|
|
45
|
+
# Tries to ensure delivery can be made to address
|
46
|
+
#
|
47
|
+
# @raise [CannotFulfilAddressError]
|
48
|
+
#
|
31
49
|
def ensure_delivery(state)
|
32
50
|
unless deps.fulfilments.can_fulfil_address?(state)
|
33
51
|
raise CannotFulfilAddressError.new(state[:delivery_address])
|
@@ -36,18 +54,25 @@ module MarketTown
|
|
36
54
|
add_dependency_missing_warning(state, :cannot_ensure_delivery)
|
37
55
|
end
|
38
56
|
|
57
|
+
# Tries to store addresses
|
58
|
+
#
|
39
59
|
def store_addresses(state)
|
40
60
|
deps.address_storage.store(state)
|
41
61
|
rescue MissingDependency
|
42
62
|
add_dependency_missing_warning(state, :cannot_store_address)
|
43
63
|
end
|
44
64
|
|
65
|
+
# Tries to proposes shipments to delivery address ready to be confirmed at
|
66
|
+
# delivery step.
|
67
|
+
#
|
45
68
|
def propose_shipments(state)
|
46
69
|
deps.fulfilments.propose_shipments(state)
|
47
70
|
rescue MissingDependency
|
48
71
|
add_dependency_missing_warning(state, :cannot_propose_shipments)
|
49
72
|
end
|
50
73
|
|
74
|
+
# Finishes address step
|
75
|
+
#
|
51
76
|
def finish_address_step(state)
|
52
77
|
deps.finish.address_step(state)
|
53
78
|
end
|
@@ -1,5 +1,14 @@
|
|
1
1
|
module MarketTown
|
2
2
|
module Checkout
|
3
|
+
# The place where a checkout process begins. This step represents the
|
4
|
+
# finalisation of a cart before the checkout process.
|
5
|
+
#
|
6
|
+
# Dependencies:
|
7
|
+
# - order#has_line_items?
|
8
|
+
# - address_storage#load_default
|
9
|
+
# - promotions#apply_cart_promotions
|
10
|
+
# - finish#cart_step
|
11
|
+
#
|
3
12
|
class CartStep < Step
|
4
13
|
class NoLineItemsError < Error; end
|
5
14
|
|
@@ -9,18 +18,29 @@ module MarketTown
|
|
9
18
|
|
10
19
|
protected
|
11
20
|
|
21
|
+
# @raise [NoLineItemsError] when no line items on order
|
22
|
+
#
|
12
23
|
def ensure_line_items(state)
|
13
24
|
unless deps.order.has_line_items?(state)
|
14
25
|
raise NoLineItemsError.new(state)
|
15
26
|
end
|
16
27
|
end
|
17
28
|
|
29
|
+
# Tries to load default addresses
|
30
|
+
#
|
18
31
|
def load_default_addresses(state)
|
19
32
|
deps.address_storage.load_default(state)
|
20
33
|
rescue MissingDependency
|
21
34
|
add_dependency_missing_warning(state, :cannot_load_default_addresses)
|
22
35
|
end
|
23
36
|
|
37
|
+
# Tries to apply cart promotions
|
38
|
+
#
|
39
|
+
def apply_cart_promotions(state)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Finishes cart step
|
43
|
+
#
|
24
44
|
def finish_cart_step(state)
|
25
45
|
deps.finish.cart_step(state)
|
26
46
|
end
|
@@ -1,5 +1,15 @@
|
|
1
1
|
module MarketTown
|
2
2
|
module Checkout
|
3
|
+
# Handles completion of checkout. All payments and options should have
|
4
|
+
# already been completed by this point. The purpose of this step is to
|
5
|
+
# request the fulfilment of the order and notify the customer.
|
6
|
+
#
|
7
|
+
# Dependencies:
|
8
|
+
# - finish#complete_step_finished?
|
9
|
+
# - fulfilments#fulfil
|
10
|
+
# - notifications#notify
|
11
|
+
# - finish#complete_step
|
12
|
+
#
|
3
13
|
class CompleteStep < Step
|
4
14
|
class AlreadyCompleteError < Error; end
|
5
15
|
|
@@ -10,24 +20,32 @@ module MarketTown
|
|
10
20
|
|
11
21
|
protected
|
12
22
|
|
23
|
+
# @raise [AlreadyCompleteError]
|
24
|
+
#
|
13
25
|
def ensure_incomplete(state)
|
14
26
|
if deps.finish.complete_step_finished?(state)
|
15
27
|
raise AlreadyCompleteError.new(state)
|
16
28
|
end
|
17
29
|
end
|
18
30
|
|
31
|
+
# Tries to fulfil order
|
32
|
+
#
|
19
33
|
def fulfil_order(state)
|
20
34
|
deps.fulfilments.fulfil(state)
|
21
35
|
rescue MissingDependency
|
22
36
|
add_dependency_missing_warning(state, :cannot_fulfil_order)
|
23
37
|
end
|
24
38
|
|
39
|
+
# Tries to send notifications about order complete
|
40
|
+
#
|
25
41
|
def send_order_complete_notice(state)
|
26
42
|
deps.notifications.notify(:order_complete, state)
|
27
43
|
rescue MissingDependency
|
28
44
|
add_dependency_missing_warning(state, :cannot_send_order_complete_notice)
|
29
45
|
end
|
30
46
|
|
47
|
+
# Finishes complete step
|
48
|
+
#
|
31
49
|
def finish_complete_step(state)
|
32
50
|
deps.finish.complete_step(state)
|
33
51
|
end
|
@@ -1,5 +1,12 @@
|
|
1
1
|
module MarketTown
|
2
2
|
module Checkout
|
3
|
+
# Handles delivery method and application of delivery promotions.
|
4
|
+
#
|
5
|
+
# Dependencies:
|
6
|
+
# - fulfilments#can_fulfil_shipments?
|
7
|
+
# - promotions#apply_delivery_promotions
|
8
|
+
# - finish#delivery_step
|
9
|
+
#
|
3
10
|
class DeliveryStep < Step
|
4
11
|
class InvalidDeliveryAddressError < Error; end
|
5
12
|
class CannotFulfilShipmentsError < Error; end
|
@@ -11,12 +18,18 @@ module MarketTown
|
|
11
18
|
|
12
19
|
protected
|
13
20
|
|
21
|
+
# @raise [InvalidDeliveryAddressError]
|
22
|
+
#
|
14
23
|
def validate_delivery_address(state)
|
15
24
|
Address.validate!(state[:delivery_address])
|
16
25
|
rescue Address::InvalidError => e
|
17
26
|
raise InvalidDeliveryAddressError.new(e.data)
|
18
27
|
end
|
19
28
|
|
29
|
+
# Tries to validate shipments
|
30
|
+
#
|
31
|
+
# @raise [CannotFulfilShipmentsError]
|
32
|
+
#
|
20
33
|
def validate_shipments(state)
|
21
34
|
unless deps.fulfilments.can_fulfil_shipments?(state)
|
22
35
|
raise CannotFulfilShipmentsError.new(state[:shipments])
|
@@ -25,12 +38,16 @@ module MarketTown
|
|
25
38
|
add_dependency_missing_warning(state, :cannot_validate_shipments)
|
26
39
|
end
|
27
40
|
|
41
|
+
# Tries to apply delivery promotions
|
42
|
+
#
|
28
43
|
def apply_delivery_promotions(state)
|
29
44
|
deps.promotions.apply_delivery_promotions(state)
|
30
45
|
rescue MissingDependency
|
31
46
|
add_dependency_missing_warning(state, :cannot_apply_delivery_promotions)
|
32
47
|
end
|
33
48
|
|
49
|
+
# Finish delivery step
|
50
|
+
#
|
34
51
|
def finish_delivery_step(state)
|
35
52
|
deps.finish.delivery_step(state)
|
36
53
|
end
|
@@ -1,6 +1,92 @@
|
|
1
1
|
module MarketTown
|
2
2
|
module Checkout
|
3
|
+
# Extended by all steps provided by {MarketTown::Checkout}.
|
4
|
+
#
|
5
|
+
# ## Creating your own {Step}
|
6
|
+
#
|
7
|
+
# If you wish to create your own step then you can extend {Step} or you can
|
8
|
+
# create a class that looks like step.
|
9
|
+
#
|
10
|
+
# ### Extending {Step}
|
11
|
+
#
|
12
|
+
# ``` ruby
|
13
|
+
# class MyStep < MarketTown::Checkout::Step
|
14
|
+
# steps :a_step,
|
15
|
+
# :a_second_step
|
16
|
+
#
|
17
|
+
# protected
|
18
|
+
#
|
19
|
+
# def a_step(state)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def a_second_step(state)
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# ```
|
26
|
+
#
|
27
|
+
# ### Duck typing {Step}
|
28
|
+
#
|
29
|
+
# ``` ruby
|
30
|
+
# class MyCustomStep
|
31
|
+
# def initialize(dependencies)
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# def process(state)
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# ```
|
38
|
+
#
|
39
|
+
# ## Extending an existing step
|
40
|
+
#
|
41
|
+
# You may want to alter the behaviour of a {Step}. You can do this quite
|
42
|
+
# easily by extending the class.
|
43
|
+
#
|
44
|
+
# In the example below we'll replace the behaviour of {AddressStep} to
|
45
|
+
# allow the use of delivery address as billing address instead of the
|
46
|
+
# default behaviour that does the opposite.
|
47
|
+
#
|
48
|
+
# ``` ruby
|
49
|
+
# class MyAddressStep < MarketTown::Checkout::AddressStep
|
50
|
+
# # Here we override the step order as defined in AddressStep. We
|
51
|
+
# # also replace #use_billing_address_as_delivery_address with
|
52
|
+
# # #use_delivery_address_as_billing_address.
|
53
|
+
# #
|
54
|
+
# steps :validate_delivery_address,
|
55
|
+
# :use_delivery_address_as_billing_address,
|
56
|
+
# :validate_billing_address,
|
57
|
+
# :ensure_delivery,
|
58
|
+
# :store_addresses,
|
59
|
+
# :propose_shipments,
|
60
|
+
# :finish_address_step
|
61
|
+
#
|
62
|
+
# protected
|
63
|
+
#
|
64
|
+
# def use_delivery_address_as_billing_address(state)
|
65
|
+
# if state[:use_delivery_address] == true
|
66
|
+
# state.merge(billing_address: state[:delivery_address])
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
# ```
|
71
|
+
#
|
72
|
+
#
|
3
73
|
class Step
|
74
|
+
# Set steps for a subclass of {Step}.
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# class MyStep < MarketTown::Checkout::Step
|
78
|
+
# steps :a_step,
|
79
|
+
# :a_second_step
|
80
|
+
#
|
81
|
+
# protected
|
82
|
+
#
|
83
|
+
# def a_step(state)
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# def a_second_step(state)
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
#
|
4
90
|
def self.steps(*steps)
|
5
91
|
if steps.empty?
|
6
92
|
@steps
|
@@ -11,11 +97,17 @@ module MarketTown
|
|
11
97
|
|
12
98
|
attr_reader :meta, :deps
|
13
99
|
|
100
|
+
# Setup step meta object.
|
101
|
+
#
|
102
|
+
# @param [Dependencies]
|
103
|
+
#
|
14
104
|
def initialize(dependencies = Dependencies.new)
|
15
105
|
@meta = { name: name_from_class }
|
16
106
|
@deps = dependencies
|
17
107
|
end
|
18
108
|
|
109
|
+
# Process each sub-step that makes up step.
|
110
|
+
#
|
19
111
|
def process(state)
|
20
112
|
self.class.steps.reduce(state) do |state, step|
|
21
113
|
send(step, state) || state
|
@@ -33,7 +125,7 @@ module MarketTown
|
|
33
125
|
end
|
34
126
|
|
35
127
|
def add_dependency_missing_warning(state, warning)
|
36
|
-
deps.logger.warn("MissingDependency so #{warning.to_s.
|
128
|
+
deps.logger.warn("MissingDependency so #{warning.to_s.gsub('_', ' ')}")
|
37
129
|
state.merge(warnings: state.fetch(:warnings, []).push(warning))
|
38
130
|
end
|
39
131
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: market_town-checkout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luke Morton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|