spree_abandoned_cart 0.3.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +17 -0
- data/.gitlab-ci.yml +15 -0
- data/.rspec +1 -0
- data/Gemfile +8 -0
- data/LICENSE +26 -0
- data/README.md +69 -0
- data/Rakefile +15 -0
- data/app/controllers/spree/admin/abandoned_orders_controller.rb +35 -0
- data/app/mailers/spree/abandoned_cart_mailer.rb +20 -0
- data/app/models/order_decorator.rb +38 -0
- data/app/models/order_updater_decorator.rb +25 -0
- data/app/models/spree/abandoned_cart_email_configuration.rb +5 -0
- data/app/models/spree/abandoned_order.rb +30 -0
- data/app/overrides/add_button_to_orders_tab_for_abandoned_index_page.rb +8 -0
- data/app/views/spree/abandoned_cart_mailer/abandoned_email.html.erb +145 -0
- data/app/views/spree/abandoned_cart_mailer/abandoned_second_email.html.erb +145 -0
- data/app/views/spree/abandoned_cart_mailer/abandoned_third_email.html.erb +145 -0
- data/app/views/spree/admin/abandoned_orders/_filters_bar.html.haml +49 -0
- data/app/views/spree/admin/abandoned_orders/_list.html.haml +22 -0
- data/app/views/spree/admin/abandoned_orders/_list_respond.js.erb +1 -0
- data/app/views/spree/admin/abandoned_orders/_order_summary.html.haml +16 -0
- data/app/views/spree/admin/abandoned_orders/_titles.html.haml +6 -0
- data/app/views/spree/admin/abandoned_orders/index.html.haml +3 -0
- data/app/views/spree/admin/abandoned_orders/index.js.haml +1 -0
- data/app/views/spree/admin/abandoned_orders/show.html.haml +2 -0
- data/config/initializers/load_preferences.rb +5 -0
- data/config/locales/en.yml +17 -0
- data/config/locales/ru.yml +17 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20130722151112_add_abandoned_email_sent_at_to_spree_orders.rb +5 -0
- data/db/migrate/20150825122125_create_spree_abandoned_orders.rb +12 -0
- data/lib/generators/spree_abandoned_cart/install/install_generator.rb +21 -0
- data/lib/spree_abandoned_cart.rb +3 -0
- data/lib/spree_abandoned_cart/engine.rb +22 -0
- data/lib/spree_abandoned_cart/factories.rb +6 -0
- data/script/rails +7 -0
- data/spec/models/order_spec.rb +35 -0
- data/spec/spec_helper.rb +86 -0
- data/spree_abandoned_cart.gemspec +38 -0
- metadata +68 -16
@@ -0,0 +1,145 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
<title><%= Spree.t("abandoned_cart.email.subject") %></title>
|
6
|
+
<style type="text/css">
|
7
|
+
#outlook a{padding:0;} /* Force Outlook to provide a "view in browser" button. */
|
8
|
+
body{width:100% !important;} .ReadMsgBody{width:100%;} .ExternalClass{width:100%;} /* Force Hotmail to display emails at full width */
|
9
|
+
body{-webkit-text-size-adjust:none;} /* Prevent Webkit platforms from changing default text sizes. */
|
10
|
+
|
11
|
+
body{font-family:Arial;margin:0; padding:0;}
|
12
|
+
img{border:0; height:auto; line-height:100%; outline:none; text-decoration:none;}
|
13
|
+
table td{border-collapse:collapse;}
|
14
|
+
#backgroundTable{height:100% !important; margin:0; padding:0; width:100% !important;}
|
15
|
+
|
16
|
+
body, #backgroundTable{
|
17
|
+
background-color:#FAFAFA;
|
18
|
+
}
|
19
|
+
|
20
|
+
#templateContainer{
|
21
|
+
border: 1px solid #DDDDDD;
|
22
|
+
margin-top: 10px;
|
23
|
+
padding: 20px;
|
24
|
+
}
|
25
|
+
|
26
|
+
h1, .h1{
|
27
|
+
color:#202020;
|
28
|
+
display:block;
|
29
|
+
font-family:Arial;
|
30
|
+
font-size:34px;
|
31
|
+
font-weight:bold;
|
32
|
+
line-height:100%;
|
33
|
+
margin-top:0;
|
34
|
+
margin-right:0;
|
35
|
+
margin-bottom:10px;
|
36
|
+
margin-left:0;
|
37
|
+
text-align:left;
|
38
|
+
}
|
39
|
+
|
40
|
+
h2, .h2{
|
41
|
+
color:#202020;
|
42
|
+
display:block;
|
43
|
+
font-family:Arial;
|
44
|
+
font-size:30px;
|
45
|
+
font-weight:bold;
|
46
|
+
line-height:100%;
|
47
|
+
margin-top:0;
|
48
|
+
margin-right:0;
|
49
|
+
margin-bottom:10px;
|
50
|
+
margin-left:0;
|
51
|
+
text-align:left;
|
52
|
+
}
|
53
|
+
|
54
|
+
h3, .h3{
|
55
|
+
color:#202020;
|
56
|
+
display:block;
|
57
|
+
font-family:Arial;
|
58
|
+
font-size:26px;
|
59
|
+
font-weight:bold;
|
60
|
+
line-height:100%;
|
61
|
+
margin-top:0;
|
62
|
+
margin-right:0;
|
63
|
+
margin-bottom:10px;
|
64
|
+
margin-left:0;
|
65
|
+
text-align:left;
|
66
|
+
}
|
67
|
+
|
68
|
+
h4, .h4{
|
69
|
+
color:#202020;
|
70
|
+
display:block;
|
71
|
+
font-family:Arial;
|
72
|
+
font-size:22px;
|
73
|
+
font-weight:bold;
|
74
|
+
line-height:100%;
|
75
|
+
margin-top:0;
|
76
|
+
margin-right:0;
|
77
|
+
margin-bottom:10px;
|
78
|
+
margin-left:0;
|
79
|
+
text-align:left;
|
80
|
+
}
|
81
|
+
|
82
|
+
#templateContainer, .bodyContent{
|
83
|
+
background-color:#FFFFFF;
|
84
|
+
}
|
85
|
+
|
86
|
+
.bodyContent div{
|
87
|
+
color:#505050;
|
88
|
+
font-family:Arial;
|
89
|
+
font-size:14px;
|
90
|
+
line-height:150%;
|
91
|
+
text-align:left;
|
92
|
+
}
|
93
|
+
|
94
|
+
.bodyContent div a:link, .bodyContent div a:visited, /* Yahoo! Mail Override */ .bodyContent div a .yshortcuts /* Yahoo! Mail Override */{
|
95
|
+
color:#336699;
|
96
|
+
font-weight:normal;
|
97
|
+
text-decoration:underline;
|
98
|
+
}
|
99
|
+
|
100
|
+
.bodyContent img{
|
101
|
+
display:inline;
|
102
|
+
height:auto;
|
103
|
+
}
|
104
|
+
|
105
|
+
#items {
|
106
|
+
margin: 10px 0;
|
107
|
+
}
|
108
|
+
</style>
|
109
|
+
</head>
|
110
|
+
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
|
111
|
+
<center>
|
112
|
+
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="backgroundTable">
|
113
|
+
<tr>
|
114
|
+
<td align="center" valign="top">
|
115
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateContainer">
|
116
|
+
<tr>
|
117
|
+
<td align="center" valign="top">
|
118
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateBody">
|
119
|
+
<tr>
|
120
|
+
<td valign="top" class="bodyContent">
|
121
|
+
We noticed you still have some things in your shopping cart — if you need help with sizes or have questions, please call, email, or chat and we'll do our best.
|
122
|
+
|
123
|
+
<table cellpadding="0" cellspacing="0" border="0" align="center" id="items">
|
124
|
+
<% @order.line_items.each do |line_item| %>
|
125
|
+
<% variant = line_item.variant %>
|
126
|
+
<tr>
|
127
|
+
<td class="cart-item-description" data-hook="cart_item_description">
|
128
|
+
<strong><%= link_to variant.product.name, spree.product_url(variant.product) %></strong>
|
129
|
+
</td>
|
130
|
+
</tr>
|
131
|
+
<% end %>
|
132
|
+
</table>
|
133
|
+
</td>
|
134
|
+
</tr>
|
135
|
+
</table>
|
136
|
+
</td>
|
137
|
+
</tr>
|
138
|
+
</table>
|
139
|
+
<br />
|
140
|
+
</td>
|
141
|
+
</tr>
|
142
|
+
</table>
|
143
|
+
</center>
|
144
|
+
</body>
|
145
|
+
</html>
|
@@ -0,0 +1,145 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
<title><%= Spree.t("abandoned_cart.email.subject") %></title>
|
6
|
+
<style type="text/css">
|
7
|
+
#outlook a{padding:0;} /* Force Outlook to provide a "view in browser" button. */
|
8
|
+
body{width:100% !important;} .ReadMsgBody{width:100%;} .ExternalClass{width:100%;} /* Force Hotmail to display emails at full width */
|
9
|
+
body{-webkit-text-size-adjust:none;} /* Prevent Webkit platforms from changing default text sizes. */
|
10
|
+
|
11
|
+
body{font-family:Arial;margin:0; padding:0;}
|
12
|
+
img{border:0; height:auto; line-height:100%; outline:none; text-decoration:none;}
|
13
|
+
table td{border-collapse:collapse;}
|
14
|
+
#backgroundTable{height:100% !important; margin:0; padding:0; width:100% !important;}
|
15
|
+
|
16
|
+
body, #backgroundTable{
|
17
|
+
background-color:#FAFAFA;
|
18
|
+
}
|
19
|
+
|
20
|
+
#templateContainer{
|
21
|
+
border: 1px solid #DDDDDD;
|
22
|
+
margin-top: 10px;
|
23
|
+
padding: 20px;
|
24
|
+
}
|
25
|
+
|
26
|
+
h1, .h1{
|
27
|
+
color:#202020;
|
28
|
+
display:block;
|
29
|
+
font-family:Arial;
|
30
|
+
font-size:34px;
|
31
|
+
font-weight:bold;
|
32
|
+
line-height:100%;
|
33
|
+
margin-top:0;
|
34
|
+
margin-right:0;
|
35
|
+
margin-bottom:10px;
|
36
|
+
margin-left:0;
|
37
|
+
text-align:left;
|
38
|
+
}
|
39
|
+
|
40
|
+
h2, .h2{
|
41
|
+
color:#202020;
|
42
|
+
display:block;
|
43
|
+
font-family:Arial;
|
44
|
+
font-size:30px;
|
45
|
+
font-weight:bold;
|
46
|
+
line-height:100%;
|
47
|
+
margin-top:0;
|
48
|
+
margin-right:0;
|
49
|
+
margin-bottom:10px;
|
50
|
+
margin-left:0;
|
51
|
+
text-align:left;
|
52
|
+
}
|
53
|
+
|
54
|
+
h3, .h3{
|
55
|
+
color:#202020;
|
56
|
+
display:block;
|
57
|
+
font-family:Arial;
|
58
|
+
font-size:26px;
|
59
|
+
font-weight:bold;
|
60
|
+
line-height:100%;
|
61
|
+
margin-top:0;
|
62
|
+
margin-right:0;
|
63
|
+
margin-bottom:10px;
|
64
|
+
margin-left:0;
|
65
|
+
text-align:left;
|
66
|
+
}
|
67
|
+
|
68
|
+
h4, .h4{
|
69
|
+
color:#202020;
|
70
|
+
display:block;
|
71
|
+
font-family:Arial;
|
72
|
+
font-size:22px;
|
73
|
+
font-weight:bold;
|
74
|
+
line-height:100%;
|
75
|
+
margin-top:0;
|
76
|
+
margin-right:0;
|
77
|
+
margin-bottom:10px;
|
78
|
+
margin-left:0;
|
79
|
+
text-align:left;
|
80
|
+
}
|
81
|
+
|
82
|
+
#templateContainer, .bodyContent{
|
83
|
+
background-color:#FFFFFF;
|
84
|
+
}
|
85
|
+
|
86
|
+
.bodyContent div{
|
87
|
+
color:#505050;
|
88
|
+
font-family:Arial;
|
89
|
+
font-size:14px;
|
90
|
+
line-height:150%;
|
91
|
+
text-align:left;
|
92
|
+
}
|
93
|
+
|
94
|
+
.bodyContent div a:link, .bodyContent div a:visited, /* Yahoo! Mail Override */ .bodyContent div a .yshortcuts /* Yahoo! Mail Override */{
|
95
|
+
color:#336699;
|
96
|
+
font-weight:normal;
|
97
|
+
text-decoration:underline;
|
98
|
+
}
|
99
|
+
|
100
|
+
.bodyContent img{
|
101
|
+
display:inline;
|
102
|
+
height:auto;
|
103
|
+
}
|
104
|
+
|
105
|
+
#items {
|
106
|
+
margin: 10px 0;
|
107
|
+
}
|
108
|
+
</style>
|
109
|
+
</head>
|
110
|
+
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
|
111
|
+
<center>
|
112
|
+
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="backgroundTable">
|
113
|
+
<tr>
|
114
|
+
<td align="center" valign="top">
|
115
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateContainer">
|
116
|
+
<tr>
|
117
|
+
<td align="center" valign="top">
|
118
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateBody">
|
119
|
+
<tr>
|
120
|
+
<td valign="top" class="bodyContent">
|
121
|
+
We noticed you still have some things in your shopping cart — if you need help with sizes or have questions, please call, email, or chat and we'll do our best.
|
122
|
+
|
123
|
+
<table cellpadding="0" cellspacing="0" border="0" align="center" id="items">
|
124
|
+
<% @order.line_items.each do |line_item| %>
|
125
|
+
<% variant = line_item.variant %>
|
126
|
+
<tr>
|
127
|
+
<td class="cart-item-description" data-hook="cart_item_description">
|
128
|
+
<strong><%= link_to variant.product.name, spree.product_url(variant.product) %></strong>
|
129
|
+
</td>
|
130
|
+
</tr>
|
131
|
+
<% end %>
|
132
|
+
</table>
|
133
|
+
</td>
|
134
|
+
</tr>
|
135
|
+
</table>
|
136
|
+
</td>
|
137
|
+
</tr>
|
138
|
+
</table>
|
139
|
+
<br />
|
140
|
+
</td>
|
141
|
+
</tr>
|
142
|
+
</table>
|
143
|
+
</center>
|
144
|
+
</body>
|
145
|
+
</html>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
- content_for :table_filter do
|
2
|
+
%div{"data-hook" => "admin_orders_index_search"}
|
3
|
+
= search_form_for [:admin, @search] do |f|
|
4
|
+
.row
|
5
|
+
.date-range-filter.col-md-8
|
6
|
+
.form-group
|
7
|
+
= label_tag :q_created_at, Spree.t('abandoned_cart.date_range_created')
|
8
|
+
.row.no-padding-bottom
|
9
|
+
.col-md-6
|
10
|
+
.input-group
|
11
|
+
= f.text_field :created_at_gt, class: 'datepicker datepicker-from form-control', value: params[:q][:created_at_gt], placeholder: Spree.t(:start)
|
12
|
+
%span.input-group-addon
|
13
|
+
%i.icon.icon-calendar
|
14
|
+
.col-md-6
|
15
|
+
.input-group
|
16
|
+
= f.text_field :created_at_lt, class: 'datepicker datepicker-to form-control', value: params[:q][:created_at_lt], placeholder: Spree.t(:stop)
|
17
|
+
%span.input-group-addon
|
18
|
+
%i.icon.icon-calendar
|
19
|
+
.row
|
20
|
+
.date-range-filter.col-md-8
|
21
|
+
.form-group
|
22
|
+
= label_tag :q_updated_at, Spree.t('abandoned_cart.date_range_sent_emails')
|
23
|
+
.row.no-padding-bottom
|
24
|
+
.col-md-6
|
25
|
+
.input-group
|
26
|
+
= f.text_field :updated_at_gt, class: 'datepicker datepicker-to form-control', value: params[:q][:updated_at_gt], placeholder: Spree.t(:start)
|
27
|
+
%span.input-group-addon
|
28
|
+
%i.icon.icon-calendar
|
29
|
+
.col-md-6
|
30
|
+
.input-group
|
31
|
+
= f.text_field :updated_at_lt, class: 'datepicker datepicker-to form-control', value: params[:q][:updated_at_lt], placeholder: Spree.t(:stop)
|
32
|
+
%span.input-group-addon
|
33
|
+
%i.icon.icon-calendar
|
34
|
+
.row
|
35
|
+
.col-md-4
|
36
|
+
.form-group
|
37
|
+
= label_tag :q_send_emails_count, Spree.t(:email)
|
38
|
+
= f.select :send_emails_count_eq, [[Spree.t('abandoned_cart.filters.attempt_one'), 1],
|
39
|
+
[Spree.t('abandoned_cart.filters.attempt_two'), 2],
|
40
|
+
[Spree.t('abandoned_cart.filters.attempt_three'), 3]],
|
41
|
+
{include_blank: true}, class: 'select2 js-filterable'
|
42
|
+
.col-md-4
|
43
|
+
.form-group
|
44
|
+
.checkbox
|
45
|
+
= label_tag 'q_completed_at_not_null' do
|
46
|
+
= f.check_box :order_accomplished_eq, {checked: false }
|
47
|
+
= Spree.t(:show_only_accomplished)
|
48
|
+
.form-actions{"data-hook" => "admin_orders_index_search_buttons"}
|
49
|
+
= button Spree.t(:filter_results), 'search'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
%table#listing_abandoned_carts.table{'data-hook' => '', 'data-sortable-link' => update_positions_admin_abandoned_orders_path}
|
2
|
+
%thead
|
3
|
+
%tr{'data-hook' => 'abandoned_carts_header'}
|
4
|
+
%th Order number
|
5
|
+
%th Emails sent
|
6
|
+
%th Last email sent at
|
7
|
+
%th Accomplished
|
8
|
+
%th Accomplished at
|
9
|
+
%th Campaign
|
10
|
+
%th.actions
|
11
|
+
%tbody
|
12
|
+
- abandoned_carts.each do |abandoned_cart|
|
13
|
+
%tr{ class: "state-#{abandoned_cart.order.state.downcase} #{cycle('odd', 'even')}", 'data-hook' => 'abandoned_cart_row', id: abandoned_cart.id}
|
14
|
+
%td= link_to abandoned_cart.order.number, admin_abandoned_order_path(abandoned_cart)
|
15
|
+
%td= abandoned_cart.send_emails_count
|
16
|
+
%td= abandoned_cart.updated_at
|
17
|
+
%td= abandoned_cart.order_accomplished
|
18
|
+
%td= abandoned_cart.accomplished_at
|
19
|
+
%td Base
|
20
|
+
%td.actions.actions-1
|
21
|
+
= link_to_with_icon 'trash', Spree.t(:delete), admin_abandoned_order_path(abandoned_cart), { method: :delete, data: { confirm:'Are you sure?' }, no_text: true, remote: true}
|
22
|
+
= paginate abandoned_carts
|
@@ -0,0 +1 @@
|
|
1
|
+
$('table#listing_abandoned_carts').html('<%= j(render('list', abandoned_carts: @abandoned_carts))%>');
|
@@ -0,0 +1,16 @@
|
|
1
|
+
- @order = @abandoned_cart.order
|
2
|
+
= render 'spree/admin/shared/order_tabs', current: :cart
|
3
|
+
%div{"data-hook" => "admin_order_edit_header"}
|
4
|
+
= render 'spree/admin/shared/error_messages', target: @order
|
5
|
+
- if @order.payments.exists? && @order.considered_risky?
|
6
|
+
= render 'spree/admin/orders/risk_analysis', latest_payment: @order.payments.order("created_at DESC").first
|
7
|
+
= render 'spree/admin/orders/add_line_item' if can?(:update, @order)
|
8
|
+
- if @order.line_items.empty?
|
9
|
+
.alert.alert-warning
|
10
|
+
= Spree.t(:your_order_is_empty_add_product)
|
11
|
+
%div{"data-hook" => "admin_order_edit_form"}
|
12
|
+
#order-form-wrapper
|
13
|
+
= render 'spree/admin/orders/line_items_edit_form', order: @order
|
14
|
+
- content_for :head do
|
15
|
+
= javascript_tag 'var expand_variants = true;'
|
16
|
+
= render 'spree/admin/shared/order_summary'
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'list_respond'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
en:
|
2
|
+
spree:
|
3
|
+
abandoned_index: Abandoned carts
|
4
|
+
show_only_accomplished: Show only accomplished
|
5
|
+
abandoned_cart:
|
6
|
+
date_range_created: Date range - created
|
7
|
+
date_range_sent_emails: Date range - emails sending
|
8
|
+
email:
|
9
|
+
subject: There are still items in your shopping cart!
|
10
|
+
subject_second: We remind you that you have forgotten your cart!
|
11
|
+
subject_third: Last chance to pick up your goods!
|
12
|
+
filters:
|
13
|
+
abandoned: Abandoned
|
14
|
+
success: Success
|
15
|
+
attempt_one: Sent 1 email
|
16
|
+
attempt_two: Sent 2 emails
|
17
|
+
attempt_three: Sent 3 emails
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ru:
|
2
|
+
spree:
|
3
|
+
abandoned_index: Брошенные корзины
|
4
|
+
show_only_accomplished: Показать только выполненые
|
5
|
+
abandoned_cart:
|
6
|
+
date_range_created: Диапазон дат - создано
|
7
|
+
date_range_sent_emails: Диапазон дат - последняя отправка
|
8
|
+
email:
|
9
|
+
subject: В вашей корзине остались товары!
|
10
|
+
subject_second: Напомним вам, что вы забыли товары!
|
11
|
+
subject_third: Последний шанс, чтобы забрать ваши товары!
|
12
|
+
filters:
|
13
|
+
abandoned: Брошена
|
14
|
+
success: Куплена
|
15
|
+
attempt_one: Отослано 1 письмо
|
16
|
+
attempt_two: Отослано 2 письма
|
17
|
+
attempt_three: Отослано 3 письма
|