caboose-cms 0.5.205 → 0.5.206

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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NjY4YWExNWMzMzgyNjg2ZDFkMDY0NTY3YzA4YzM5NzRiZDVlMmFjYg==
4
+ N2M0YTMyOGU2NDBhZDA1NTMxNGI3MmM0MDBmNzkxY2VlZThlYTZhMg==
5
5
  data.tar.gz: !binary |-
6
- OGIzNTA1YTk5M2Q2YmM0MDQ5YWFkNjU2N2I1ZWY0ZTgzMWJlZDdmZA==
6
+ YjE3ZDBhZjlkOTQxZjBlZDAxNWExYTM2M2MzOTFlMTkwYzM2OTlkMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MjhmZjU5YmNkY2VlZTllMmFlZmFkODVlOTBmNTFlYTMzZDBjY2YzNjllNWE3
10
- YjVlNTg0YjVhODAwMzU1N2IxMmFjYTAxZWIxZmE5YjAwOTc2OGJiYTJmMjRk
11
- NThiNTJlODE2YWRhNDQ5ZWU5NmZhOWE5M2YwZjU5MjZjYWRlM2I=
9
+ M2MwNmI0Zjg1ZjFjMWUyYTlmY2JlMjhjZWFiYzViNGNkYzAzZGVjMTYxZmQx
10
+ MDY1ZTBmNWRiMWIyYjU2ZjZiYzY4M2M0YWRkMGZiZmE1ZGJiNzUyYzdjODQ3
11
+ ODYyZmIxZGFiZDg5MWE0YjJjYzg0ODQwMGY5MjljZjY4NTM2NDU=
12
12
  data.tar.gz: !binary |-
13
- M2FmMDg4NmZjODU4OWRhMTU2MWFjZmIxNjczNmU1YjJlYTY0YjI1ODAzYzYw
14
- NjYxZmQwMjdiMTc2YzhlOWU4OWQ0MGU2MmRjOWM1Yjk5OWIxYjYwYWU0NGI0
15
- NjBhYzgyOGU1MTA3OWU1NWY4ZWM2ZDY1ZGY1NGY1MGU2ZWUwNTA=
13
+ N2YyZDU1MTVlZGU1MWRmZThjYTI5OWZlODcyOGZkNGZkMDM4NzgyNTRjNzQy
14
+ NDM4MDcyMTdjMzZiYjI0OThlYWY4MzdhYzMzNWUwMDA3ODYyMzc4NDQ5MWU0
15
+ Yjg4ODA5MDFlYzBhYWMyNTA3Yzk1ZDM2ZmQ1NDVlZGMzNmQwNmE=
@@ -0,0 +1,241 @@
1
+
2
+ var ModificationsController = function(params) { this.init(params); };
3
+
4
+ ModificationsController.prototype = {
5
+
6
+ product_id: false,
7
+ mods: false,
8
+
9
+ init: function(params) {
10
+ for (var i in params)
11
+ this[i] = params[i];
12
+ this.refresh(true);
13
+ },
14
+
15
+ refresh: function(reprint)
16
+ {
17
+ var that = this;
18
+ $.ajax({
19
+ url: '/admin/products/' + that.product_id + '/modifications/json',
20
+ type: 'get',
21
+ success: function(resp) {
22
+ that.mods = resp;
23
+ if (reprint)
24
+ {
25
+ that.print();
26
+ that.make_editable();
27
+ }
28
+ }
29
+ });
30
+ },
31
+
32
+ print: function()
33
+ {
34
+ var that = this;
35
+ $('#mods').empty()
36
+ .append(that.mods_table())
37
+ .append($('<div/>').attr('id', 'mods_message'))
38
+ .append($('<input/>').attr('type', 'button').val('New Modification').click(function(e) { that.add_mod(); }));
39
+ },
40
+
41
+ make_editable: function()
42
+ {
43
+ var that = this;
44
+ if (!that.mods || that.mods.length == 0)
45
+ return;
46
+
47
+ $.each(that.mods, function(i, mod) {
48
+
49
+ new ModelBinder({
50
+ name: 'Modification',
51
+ id: mod.id,
52
+ update_url: '/admin/products/' + that.product_id + '/modifications/' + mod.id,
53
+ authenticity_token: that.authenticity_token,
54
+ attributes: [
55
+ { name: 'name', nice_name: 'Modification Name', type: 'text', value: mod.name, width: 300, fixed_placeholder: true },
56
+ ]
57
+ });
58
+ if (mod.modification_values && mod.modification_values.length > 0)
59
+ {
60
+ $.each(mod.modification_values, function(j, mv) {
61
+ new ModelBinder({
62
+ name: 'ModificationValue',
63
+ id: mv.id,
64
+ update_url: '/admin/products/' + that.product_id + '/modifications/' + mod.id + '/values/' + mv.id,
65
+ authenticity_token: that.authenticity_token,
66
+ attributes: [
67
+ { name: 'value' , nice_name: 'Value' , type: 'text' , value: mv.value , width: 150, fixed_placeholder: false },
68
+ { name: 'is_default' , nice_name: 'Default' , type: 'checkbox' , value: mv.is_default ? true : false , width: 75, fixed_placeholder: false , mod_id: mod.id, mv_id: mv.id, after_update: function() { that.check_default_value(this.mod_id, this.mv_id); }},
69
+ { name: 'price' , nice_name: 'Price' , type: 'text' , value: mv.price , width: 150, fixed_placeholder: false },
70
+ { name: 'requires_input' , nice_name: 'Requires Input' , type: 'checkbox' , value: mv.requires_input ? true : false , width: 150, fixed_placeholder: false },
71
+ { name: 'input_description' , nice_name: 'Input Description' , type: 'text' , value: mv.input_description , width: 150, fixed_placeholder: false }
72
+ ]
73
+ });
74
+ });
75
+ }
76
+ });
77
+ },
78
+
79
+ check_default_value: function(mod_id, mod_value_id, checked)
80
+ {
81
+ var that = this;
82
+ if ($('#modificationvalue_' + mod_value_id + '_is_default').is(':checked'))
83
+ {
84
+ $.each(that.mods, function(i, mod) {
85
+ if (mod.id == mod_id)
86
+ {
87
+ $.each(mod.modification_values, function(j, mv) {
88
+ if (mv.id != parseInt(mod_value_id) && mv.is_default)
89
+ {
90
+ $('#modificationvalue_' + mv.id + '_is_default').attr('checked', false);
91
+ that.refresh();
92
+ }
93
+ });
94
+ }
95
+ });
96
+ }
97
+ },
98
+
99
+ mods_table: function()
100
+ {
101
+ var that = this;
102
+ if (!that.mods || that.mods.length == 0)
103
+ return $('<p/>').html("There are currently no modifications for this product.");
104
+
105
+ var div = $('<div/>');
106
+
107
+ $.each(that.mods, function(i, mod) {
108
+ var mdiv = $('<div/>').addClass('modification');
109
+ mdiv.append($('<div/>').attr('id', 'modification_' + mod.id + '_name'));
110
+ var mod_values = $('<div/>');
111
+ if (mod.modification_values && mod.modification_values.length > 0)
112
+ {
113
+ var tbody = $('<tbody>').append($('<tr/>')
114
+ .append($('<th/>').html('Default' ))
115
+ .append($('<th/>').html('Value' ))
116
+ .append($('<th/>').html('Price' ))
117
+ .append($('<th/>').html('Requires Input' ))
118
+ .append($('<th/>').html('Input Description' ))
119
+ );
120
+ $.each(mod.modification_values, function(j, mv) {
121
+ tbody.append($('<tr/>')
122
+ .append($('<td/>').append($('<div/>').attr('id', 'modificationvalue_' + mv.id + '_is_default')))
123
+ .append($('<td/>').append($('<div/>').attr('id', 'modificationvalue_' + mv.id + '_value')))
124
+ .append($('<td/>').append($('<div/>').attr('id', 'modificationvalue_' + mv.id + '_price')))
125
+ .append($('<td/>').append($('<div/>').attr('id', 'modificationvalue_' + mv.id + '_requires_input' )))
126
+ .append($('<td/>').append($('<div/>').attr('id', 'modificationvalue_' + mv.id + '_input_description' )))
127
+ .append($('<td/>').append($('<input/>').attr('type', 'button').data('mod_id', mod.id).data('mod_value_id', mv.id).val('Remove').click(function(e) { that.delete_mod_value($(this).data('mod_id'), $(this).data('mod_value_id')); })))
128
+ );
129
+ });
130
+ mod_values
131
+ .append($('<table/>').append(tbody))
132
+ .append($('<br/>'));
133
+ }
134
+ mdiv.append(mod_values);
135
+ mdiv.append($('<div/>').attr('id', 'mod_' + mod.id + '_message'));
136
+ mdiv
137
+ .append($('<input/>').attr('type', 'button').data('mod_id', mod.id).val('New Value' ).click(function(e) { that.add_mod_value($(this).data('mod_id')); })).append(' ')
138
+ .append($('<input/>').attr('type', 'button').data('mod_id', mod.id).val('Remove Modification' ).click(function(e) { that.delete_mod($(this).data('mod_id')); }));
139
+ div.append(mdiv);
140
+ });
141
+ return div
142
+ },
143
+
144
+ add_mod: function(name)
145
+ {
146
+ var that = this;
147
+ if (!name)
148
+ {
149
+ var p = $('<p/>').addClass('note confirm')
150
+ .append("Name: ")
151
+ .append($('<input/>').attr('type','text').attr('id', 'new_mod_name').css('width', '200px')).append(' ')
152
+ .append($('<input/>').attr('type','button').val('Add').click(function() { that.add_mod($('#new_mod_name').val()); })).append(' ')
153
+ .append($('<input/>').attr('type','button').val('Cancel').click(function() { $('#mods_message').empty(); }));
154
+ $('#mods_message').empty().append(p);
155
+ return;
156
+ }
157
+ $('#mods_message').html("<p class='loading'>Adding...</p>");
158
+ $.ajax({
159
+ url: '/admin/products/' + that.product_id + '/modifications',
160
+ type: 'post',
161
+ data: { name: name },
162
+ success: function(resp) {
163
+ if (resp.error) $('#mods_message').html("<p class='note error'>" + resp.error + "</p>");
164
+ if (resp.success) { $('#mods_message').empty(); that.refresh(true); }
165
+ }
166
+ });
167
+ },
168
+
169
+ add_mod_value: function(mod_id, value)
170
+ {
171
+ var that = this;
172
+ if (!value)
173
+ {
174
+ var p = $('<p/>').addClass('note confirm')
175
+ .append("Value: ")
176
+ .append($('<input/>').attr('type','text').attr('id', 'new_mod_value').css('width', '200px')).append(' ')
177
+ .append($('<input/>').attr('type','button').val('Add').click(function() { that.add_mod_value(mod_id, $('#new_mod_value').val()); })).append(' ')
178
+ .append($('<input/>').attr('type','button').val('Cancel').click(function() { $('#mod_' + mod_id + '_message').empty(); }));
179
+ $('#mod_' + mod_id + '_message').empty().append(p);
180
+ return;
181
+ }
182
+ $('#mod_' + mod_id + '_message').html("<p class='loading'>Adding...</p>");
183
+ $.ajax({
184
+ url: '/admin/products/' + that.product_id + '/modifications/' + mod_id + '/values',
185
+ type: 'post',
186
+ data: { value: value },
187
+ success: function(resp) {
188
+ if (resp.error) $('#mod_' + mod_id + '_message').html("<p class='note error'>" + resp.error + "</p>");
189
+ if (resp.success) { $('#mod_' + mod_id + '_message').empty(); that.refresh(true); }
190
+ }
191
+ });
192
+ },
193
+
194
+ delete_mod: function(mod_id, confirm)
195
+ {
196
+ var that = this;
197
+ if (!confirm)
198
+ {
199
+ var p = $('<p/>').addClass('note confirm')
200
+ .append("Are you sure you want to delete the modification? ")
201
+ .append($('<input/>').attr('type','button').val('Yes').click(function() { that.delete_mod(mod_id, true); })).append(' ')
202
+ .append($('<input/>').attr('type','button').val('No' ).click(function() { $('#mod_' + mod_id + '_message').empty(); }));
203
+ $('#mod_' + mod_id + '_message').empty().append(p);
204
+ return;
205
+ }
206
+ $('#mod_' + mod_id + '_message').html("<p class='loading'>Removing...</p>");
207
+ $.ajax({
208
+ url: '/admin/products/' + that.product_id + '/modifications/' + mod_id,
209
+ type: 'delete',
210
+ success: function(resp) {
211
+ if (resp.error) $('#mod_' + mod_id + '_message').html("<p class='note error'>" + resp.error + "</p>");
212
+ if (resp.success) { $('#mod_' + mod_id + '_message').empty(); that.refresh(true); }
213
+ }
214
+ });
215
+ },
216
+
217
+ delete_mod_value: function(mod_id, mod_value_id, confirm)
218
+ {
219
+ var that = this;
220
+ if (!confirm)
221
+ {
222
+ var p = $('<p/>').addClass('note confirm')
223
+ .append("Are you sure you want to delete the value? ")
224
+ .append($('<input/>').attr('type','button').val('Yes').click(function() { that.delete_mod_value(mod_id, mod_value_id, true); })).append(' ')
225
+ .append($('<input/>').attr('type','button').val('No' ).click(function() { $('#mod_' + mod_id + '_message').empty(); }));
226
+ $('#mod_' + mod_id + '_message').empty().append(p);
227
+ return;
228
+ }
229
+ $('#mod_' + mod_id + '_message').html("<p class='loading'>Removing...</p>");
230
+ $.ajax({
231
+ url: '/admin/products/' + that.product_id + '/modifications/' + mod_id + '/values/' + mod_value_id,
232
+ type: 'delete',
233
+ success: function(resp) {
234
+ if (resp.error) $('#mod_' + mod_id + '_message').html("<p class='note error'>" + resp.error + "</p>");
235
+ if (resp.success) { $('#mod_' + mod_id + '_message').empty(); that.refresh(true); }
236
+ }
237
+ });
238
+ }
239
+
240
+ };
241
+
@@ -0,0 +1,88 @@
1
+ module Caboose
2
+ class ModificationValuesController < Caboose::ApplicationController
3
+
4
+ # GET /admin/products/:product_id/modifications/:mod_id/values/json
5
+ def admin_json
6
+ return if !user_is_allowed('products', 'view')
7
+
8
+ m = Modification.find(params[:mod_id])
9
+ render :json => m.modification_values
10
+ end
11
+
12
+ # GET /admin/products/:product_id/modifications/:mod_id/values/:id/json
13
+ def admin_json_single
14
+ mv = ModificationValue.find(params[:id])
15
+ render :json => mv
16
+ end
17
+
18
+ # PUT /admin/products/:product_id/modifications/:mod_id/values/:id
19
+ def admin_update
20
+ return if !user_is_allowed('products', 'edit')
21
+
22
+ resp = Caboose::StdClass.new
23
+ mv = ModificationValue.find(params[:id])
24
+
25
+ save = true
26
+ params.each do |name,value|
27
+ case name
28
+ when 'sort_order' then mv.sort_order = value
29
+ when 'value' then mv.value = value
30
+ when 'is_default' then
31
+ if value.to_i == 1
32
+ ModificationValue.where(:modification_id => params[:mod_id]).all.each do |mv2|
33
+ mv2.is_default = false
34
+ mv2.save
35
+ end
36
+ end
37
+ mv.is_default = value
38
+
39
+ when 'price' then mv.price = value
40
+ when 'requires_input' then mv.requires_input = value
41
+ when 'input_description' then mv.input_description = value
42
+ end
43
+ end
44
+ resp.success = save && mv.save
45
+ render :json => resp
46
+ end
47
+
48
+ # POST /admin/products/:product_id/modifications/:mod_id/values
49
+ def admin_add
50
+ return if !user_is_allowed('products', 'add')
51
+
52
+ resp = Caboose::StdClass.new
53
+ value = params[:value]
54
+
55
+ if value.length == 0
56
+ resp.error = "The value cannot be empty."
57
+ else
58
+ last_mv = ModificationValue.where(:modification_id => params[:mod_id]).reorder("sort_order desc").limit(1).first
59
+ sort_order = last_mv ? last_mv.sort_order + 1 : 0
60
+ mv = ModificationValue.new(:modification_id => params[:mod_id], :value => value, :sort_order => sort_order)
61
+ mv.save
62
+ resp.success = true
63
+ end
64
+ render :json => resp
65
+ end
66
+
67
+ # DELETE /admin/products/:product_id/modifications/:mod_id/values/:id
68
+ def admin_delete
69
+ return if !user_is_allowed('products', 'delete')
70
+ mv = ModificationValue.find(params[:id]).destroy
71
+ render :json => Caboose::StdClass.new({
72
+ :success => true
73
+ })
74
+ end
75
+
76
+ # PUT /admin/products/:product_id/modifications/:mod_id/values/sort-order
77
+ def admin_update_sort_order
78
+ params[:modification_value_ids].each_with_index do |mv_id, i|
79
+ mv = ModificationValue.where(:id => mv_id).first
80
+ mv.sort_order = i
81
+ mv.save
82
+ end
83
+ render :json => { :success => true }
84
+ end
85
+
86
+ end
87
+ end
88
+
@@ -0,0 +1,73 @@
1
+ module Caboose
2
+ class ModificationsController < Caboose::ApplicationController
3
+
4
+ # GET /admin/products/:product_id/modifications/json
5
+ def admin_json
6
+ return if !user_is_allowed('products', 'view')
7
+
8
+ p = Product.find(params[:product_id])
9
+ render :json => p.modifications.as_json(:include => :modification_values)
10
+ end
11
+
12
+ # GET /admin/products/:product_id/modifications/:id/json
13
+ def admin_json_single
14
+ m = Modification.find(params[:id])
15
+ render :json => m.as_json(:include => :modification_values)
16
+ end
17
+
18
+ # PUT /admin/products/:product_id/modifications/:id
19
+ def admin_update
20
+ return if !user_is_allowed('products', 'edit')
21
+
22
+ resp = Caboose::StdClass.new
23
+ m = Modification.find(params[:id])
24
+
25
+ save = true
26
+ params.each do |name,value|
27
+ case name
28
+ when 'name' then m.name = value
29
+ end
30
+ end
31
+ resp.success = save && m.save
32
+ render :json => resp
33
+ end
34
+
35
+ # POST /admin/products/:product_id/modifications
36
+ def admin_add
37
+ return if !user_is_allowed('products', 'add')
38
+
39
+ resp = Caboose::StdClass.new
40
+ name = params[:name]
41
+
42
+ if name.length == 0
43
+ resp.error = "The name cannot be empty."
44
+ else
45
+ m = Modification.new(:product_id => params[:product_id], :name => name)
46
+ m.save
47
+ resp.success = true
48
+ end
49
+ render :json => resp
50
+ end
51
+
52
+ # DELETE /admin/products/:product_id/modifications/:id
53
+ def admin_delete
54
+ return if !user_is_allowed('products', 'delete')
55
+ m = Modification.find(params[:id]).destroy
56
+ render :json => Caboose::StdClass.new({
57
+ :success => true
58
+ })
59
+ end
60
+
61
+ # PUT /admin/products/:product_id/modifications/sort-order
62
+ def admin_update_sort_order
63
+ params[:modification_ids].each_with_index do |mod_id, i|
64
+ m = Modification.where(:id => mod_id).first
65
+ m.sort_order = i
66
+ m.save
67
+ end
68
+ render :json => { :success => true }
69
+ end
70
+
71
+ end
72
+ end
73
+
@@ -74,6 +74,12 @@ module Caboose
74
74
  when 'fedex_password' then sc.fedex_password = value
75
75
  when 'fedex_key' then sc.fedex_key = value
76
76
  when 'fedex_account' then sc.fedex_account = value
77
+ when 'ups_min' then sc.ups_min = value
78
+ when 'ups_max' then sc.ups_max = value
79
+ when 'usps_min' then sc.usps_min = value
80
+ when 'usps_max' then sc.usps_max = value
81
+ when 'fedex_min' then sc.fedex_min = value
82
+ when 'fedex_max' then sc.fedex_max = value
77
83
  when 'taxcloud_api_id' then sc.taxcloud_api_id = value
78
84
  when 'taxcloud_api_key' then sc.taxcloud_api_key = value
79
85
  when 'origin_address1' then sc.origin_address1 = value
@@ -93,6 +99,7 @@ module Caboose
93
99
  when 'custom_tax_function' then sc.custom_tax_function = value
94
100
  when 'length_unit' then sc.length_unit = value
95
101
  when 'weight_unit' then sc.weight_unit = value
102
+ when 'download_instructions' then sc.download_instructions = value
96
103
  when 'download_url_expires_in' then sc.download_url_expires_in = value
97
104
  when 'starting_order_number' then sc.starting_order_number = value
98
105
  end
@@ -0,0 +1,18 @@
1
+
2
+ module Caboose
3
+ class LineItemModification < ActiveRecord::Base
4
+ self.table_name = 'store_line_item_modifications'
5
+ self.primary_key = 'id'
6
+
7
+ belongs_to :line_item, :class_name => 'Caboose::LineItem'
8
+ belongs_to :modification, :class_name => 'Caboose::Modification'
9
+ belongs_to :modification_value, :class_name => 'Caboose::ModificationValue'
10
+ attr_accessible :id,
11
+ :line_item_id,
12
+ :modification_id,
13
+ :modification_value_id,
14
+ :input
15
+
16
+ end
17
+ end
18
+
@@ -0,0 +1,20 @@
1
+
2
+ module Caboose
3
+ class Modification < ActiveRecord::Base
4
+ self.table_name = 'store_modifications'
5
+ self.primary_key = 'id'
6
+
7
+ belongs_to :product, :class_name => 'Caboose::Product'
8
+ has_many :modification_values, :class_name => 'Caboose::ModificationValue', :order => 'sort_order'
9
+ attr_accessible :id,
10
+ :product_id,
11
+ :sort_order,
12
+ :name
13
+
14
+ def values
15
+ return self.modification_values
16
+ end
17
+
18
+ end
19
+ end
20
+
@@ -0,0 +1,19 @@
1
+
2
+ module Caboose
3
+ class ModificationValue < ActiveRecord::Base
4
+ self.table_name = 'store_modification_values'
5
+ self.primary_key = 'id'
6
+
7
+ belongs_to :modification, :class_name => 'Caboose::Modification'
8
+ attr_accessible :id,
9
+ :modification_id,
10
+ :sort_order,
11
+ :value,
12
+ :is_default,
13
+ :price,
14
+ :requires_input,
15
+ :input_description
16
+
17
+ end
18
+ end
19
+
@@ -44,12 +44,17 @@ module Caboose
44
44
  case sc.pp_name
45
45
  when 'authorize.net'
46
46
 
47
- t = AuthorizeNet::Reporting::Transaction.new(sc.pp_username, sc.pp_password)
48
- resp = t.get_transaction_details(ot.transaction_id)
49
- t2 = resp.transaction
50
- if t2
51
- self.card_type = t2.payment_method.card_type.upcase
52
- self.card_number = t2.payment_method.card_number.gsub('X', '')
47
+ if ot
48
+ t = AuthorizeNet::Reporting::Transaction.new(sc.pp_username, sc.pp_password)
49
+ resp = t.get_transaction_details(ot.transaction_id)
50
+ t2 = resp.transaction
51
+ if t2
52
+ self.card_type = t2.payment_method.card_type.upcase
53
+ self.card_number = t2.payment_method.card_number.gsub('X', '')
54
+ end
55
+ else
56
+ self.card_type = ""
57
+ self.card_number = ""
53
58
  end
54
59
 
55
60
  end
@@ -219,26 +224,30 @@ module Caboose
219
224
  { :content => "Card Type", :width => 127, :border_width => 0 },
220
225
  { :content => self.card_type.blank? ? "N/A" : self.card_type, :width => 128, :border_width => 0 }
221
226
  ]
222
- tbl2 << [
223
- { :content => "Transaction ID", :width => 127, :border_width => 0 },
224
- { :content => trans.transaction_id.to_s, :width => 128, :border_width => 0 }
225
- ]
226
- tbl2 << [
227
- { :content => "Gateway Response", :width => 127, :border_width => 0},
228
- { :content => trans.response_code.to_s, :width => 128, :border_width => 0 }
229
- ]
227
+ if trans
228
+ tbl2 << [
229
+ { :content => "Transaction ID", :width => 127, :border_width => 0 },
230
+ { :content => trans.transaction_id.to_s, :width => 128, :border_width => 0 }
231
+ ]
232
+ tbl2 << [
233
+ { :content => "Gateway Response", :width => 127, :border_width => 0},
234
+ { :content => trans.response_code.to_s, :width => 128, :border_width => 0 }
235
+ ]
236
+ end
230
237
  tbl3 << [
231
238
  { :content => "Card Number", :width => 127, :border_width => 0},
232
239
  { :content => self.card_number ? ("XXXX XXXX XXXX " + self.card_number) : "N/A", :width => 128, :border_width => 0 }
233
240
  ]
234
- tbl3 << [
235
- { :content => "Transaction Time", :width => 127, :border_width => 0},
236
- { :content => trans.date_processed.strftime("%d %b %Y %H:%M:%S %p"), :width => 128, :border_width => 0 }
237
- ]
238
- tbl3 << [
239
- { :content => "Payment Process", :width => 127, :border_width => 0},
240
- { :content => trans.success ? "Successful" : "Failed", :width => 128, :border_width => 0 }
241
- ]
241
+ if trans
242
+ tbl3 << [
243
+ { :content => "Transaction Time", :width => 127, :border_width => 0},
244
+ { :content => trans.date_processed.strftime("%d %b %Y %H:%M:%S %p"), :width => 128, :border_width => 0 }
245
+ ]
246
+ tbl3 << [
247
+ { :content => "Payment Process", :width => 127, :border_width => 0},
248
+ { :content => trans.success ? "Successful" : "Failed", :width => 128, :border_width => 0 }
249
+ ]
250
+ end
242
251
  tbl << [
243
252
  { :content => "Authorization Details", :colspan => 2, :font_style => :bold }
244
253
  ]
@@ -25,7 +25,9 @@ class Caboose::Post < ActiveRecord::Base
25
25
  :styles => {
26
26
  :tiny => '75x75>',
27
27
  :thumb => '150x150>',
28
- :large => '400x400>'
28
+ :large => '400x400>',
29
+ :huge => '1000x1000'
30
+
29
31
  }
30
32
  do_not_validate_attachment_file_type :image
31
33
 
@@ -13,6 +13,7 @@ module Caboose
13
13
  has_many :variants, :class_name => 'Caboose::Variant', :order => 'option1_sort_order, option2_sort_order, option3_sort_order'
14
14
  has_many :product_images, :class_name => 'Caboose::ProductImage'
15
15
  has_many :product_inputs, :class_name => 'Caboose::ProductInput'
16
+ has_many :modifications, :class_name => 'Caboose::Modification', :order => 'sort_order'
16
17
  has_many :reviews, :class_name => 'Caboose::Review'
17
18
  has_many :product_category_sorts, :class_name => 'Caboose::ProductCategorySort'
18
19
 
@@ -309,6 +309,12 @@ class Caboose::Schema < Caboose::Utilities::Schema
309
309
  [ :gift_wrap , :boolean , { :default => false }],
310
310
  [ :hide_prices , :boolean , { :default => false }]
311
311
  ],
312
+ Caboose::LineItemModification => [
313
+ [ :line_item_id , :integer ],
314
+ [ :modification_id , :integer ],
315
+ [ :modification_value_id , :integer ],
316
+ [ :input , :string ]
317
+ ],
312
318
  Caboose::MediaCategory => [
313
319
  [ :parent_id , :integer ],
314
320
  [ :site_id , :integer ],
@@ -326,6 +332,20 @@ class Caboose::Schema < Caboose::Utilities::Schema
326
332
  [ :description , :text ],
327
333
  [ :file , :attachment ]
328
334
  ],
335
+ Caboose::Modification => [
336
+ [ :product_id , :integer ],
337
+ [ :sort_order , :integer , { :default => 0 }],
338
+ [ :name , :string ]
339
+ ],
340
+ Caboose::ModificationValue => [
341
+ [ :modification_id , :integer ],
342
+ [ :sort_order , :integer , { :default => 0 }],
343
+ [ :value , :string ],
344
+ [ :is_default , :boolean , { :default => false }],
345
+ [ :price , :decimal , { :precision => 8, :scale => 2 }],
346
+ [ :requires_input , :boolean , { :default => false }],
347
+ [ :input_description , :string ]
348
+ ],
329
349
  Caboose::OrderTransaction => [
330
350
  [ :order_id , :integer ],
331
351
  [ :date_processed , :datetime ],
@@ -645,11 +665,17 @@ class Caboose::Schema < Caboose::Utilities::Schema
645
665
  [ :ups_origin_account , :string ],
646
666
  [ :usps_username , :string ],
647
667
  [ :usps_secret_key , :string ],
648
- [ :usps_publishable_key , :string ],
668
+ [ :usps_publishable_key , :string ],
649
669
  [ :fedex_username , :string ],
650
670
  [ :fedex_password , :string ],
651
671
  [ :fedex_key , :string ],
652
672
  [ :fedex_account , :string ],
673
+ [ :ups_min , :decimal , { :precision => 8, :scale => 2 }],
674
+ [ :ups_max , :decimal , { :precision => 8, :scale => 2 }],
675
+ [ :usps_min , :decimal , { :precision => 8, :scale => 2 }],
676
+ [ :usps_max , :decimal , { :precision => 8, :scale => 2 }],
677
+ [ :fedex_min , :decimal , { :precision => 8, :scale => 2 }],
678
+ [ :fedex_max , :decimal , { :precision => 8, :scale => 2 }],
653
679
  [ :taxcloud_api_id , :string ],
654
680
  [ :taxcloud_api_key , :string ],
655
681
  [ :origin_address1 , :string ],
@@ -666,7 +692,8 @@ class Caboose::Schema < Caboose::Utilities::Schema
666
692
  [ :auto_calculate_tax , :boolean , { :default => true }],
667
693
  [ :custom_packages_function , :text ],
668
694
  [ :custom_shipping_function , :text ],
669
- [ :custom_tax_function , :text ],
695
+ [ :custom_tax_function , :text ],
696
+ [ :download_instructions , :text ],
670
697
  [ :length_unit , :string , { :default => 'in' }],
671
698
  [ :weight_unit , :string , { :default => 'oz' }],
672
699
  [ :download_url_expires_in , :string , { :default => 5 }],
@@ -21,6 +21,12 @@ module Caboose
21
21
  :fedex_password,
22
22
  :fedex_key,
23
23
  :fedex_account,
24
+ :ups_min,
25
+ :ups_max,
26
+ :usps_min,
27
+ :usps_max,
28
+ :fedex_min,
29
+ :fedex_max,
24
30
  :taxcloud_api_id,
25
31
  :taxcloud_api_key,
26
32
  :origin_country,
@@ -37,6 +43,7 @@ module Caboose
37
43
  :custom_shipping_function,
38
44
  :custom_tax_function,
39
45
  :length_unit,
46
+ :download_instructions,
40
47
  :weight_unit
41
48
 
42
49
  WEIGHT_UNIT_METRIC = 'g'
@@ -27,4 +27,4 @@
27
27
  <% content_for :js do %>
28
28
  <script id='facebook-jssdk' src='//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=759174044117392&version=v2.0'></script>
29
29
  <script id='twitter-wjs' src='https://platform.twitter.com/widgets.js'></script>
30
- <% end %>
30
+ <% end %>
@@ -3,7 +3,9 @@
3
3
  <p>Please allow up to 48 hours for your order to be processed. Orders are processed during normal business hours Monday through Friday.</p>
4
4
 
5
5
  <% if @last_order.has_downloadable_items? %>
6
- <p>Your order contained downloadable items. Download your items with the links below:</p>
6
+ <% sc = Caboose::StoreConfig.where(:site_id => @site.id).last %>
7
+ <% instr = (sc && !sc.download_instructions.blank?) ? sc.download_instructions : "Your order contained downloadable items. Download your items with the links below:" %>
8
+ <p><%= instr %></p>
7
9
  <ul id='downloads'>
8
10
  <% @last_order.line_items.each do |li| %>
9
11
  <% if li.variant.downloadable %>
@@ -7,11 +7,15 @@ may_delete3 = p.variants.collect{|v| v.option3 }.uniq.count == 1
7
7
  %>
8
8
  <%= render :partial => 'caboose/products/admin_header' %>
9
9
 
10
- <p class='note' style='font-size: 85%; font-weight: normal; line-height: 140%;'>Product options allow you to present a group of similar products as a single
11
- product to the end user. Common options include color, size, and style.
12
- But an option can be anything. So for example, you could create a "Sleave" option for
13
- shirts that are either long or short sleeved. Or you could create a "Tip" option
14
- for chopsticks that are either rounded or squared at the tip. It's up to you.</p>
10
+ <h2>Options</h2>
11
+
12
+ <p class='note' style='font-size: 85%; font-weight: normal; line-height: 140%;'>
13
+ Product options allow you to present a group of similar products as a single
14
+ product to the end user. Common options include color, size, and style.
15
+ But an option can be anything. So for example, you could create a "Sleave" option for
16
+ shirts that are either long or short sleeved. Or you could create a "Tip" option
17
+ for chopsticks that are either rounded or squared at the tip. It's up to you.
18
+ </p>
15
19
 
16
20
  <table>
17
21
  <tr><td><div id='product_<%= p.id %>_option1'></div></td><td><div id='product_<%= p.id %>_default1'></div></td></tr>
@@ -19,17 +23,23 @@ for chopsticks that are either rounded or squared at the tip. It's up to you.</
19
23
  <tr><td><div id='product_<%= p.id %>_option3'></div></td><td><div id='product_<%= p.id %>_default3'></div></td></tr>
20
24
  </table>
21
25
 
26
+ <h2>Modifications</h2>
27
+
28
+ <p class='note' style='font-size: 85%; font-weight: normal; line-height: 140%;'>
29
+ Product modifications are similar to options, but they don't affect the inventory.
30
+ Modifications are things that are done to a product after it has been ordered.
31
+ For example, engraved vs not engraved.
32
+ </p>
33
+
34
+ <div id='mods'></div>
22
35
  <div id='message'></div>
23
36
 
24
37
  <%= render :partial => 'caboose/products/admin_footer' %>
25
38
  <% content_for :caboose_js do %>
39
+ <%= javascript_include_tag 'caboose/admin_edit_modifications' %>
26
40
  <script type='text/javascript'>
27
41
 
28
- var modal = false;
29
- $(window).load(function() {
30
- modal = new CabooseModal(800);
31
- });
32
-
42
+ var mods_controller = false;
33
43
  $(document).ready(function() {
34
44
  m = new ModelBinder({
35
45
  name: 'Product',
@@ -45,7 +55,17 @@ $(document).ready(function() {
45
55
  { name: 'default3' , nice_name: 'Default value' , type: 'text', value: <%= raw Caboose.json(p.default3) %>, width: 285, fixed_placeholder: true }
46
56
  ]
47
57
  });
58
+
59
+ mods_controller = new ModificationsController({
60
+ product_id: <%= p.id %>,
61
+ authenticity_token: '<%= form_authenticity_token %>',
62
+ });
48
63
  });
49
64
 
50
65
  </script>
51
66
  <% end %>
67
+ <% content_for :caboose_css do %>
68
+ <style type='text/css'>
69
+ div.modification { border: #ccc 1px solid; padding: 10px; margin-bottom: 10px; }
70
+ </style>
71
+ <% end %>
@@ -32,7 +32,7 @@ $(document).ready(function() {
32
32
  { name: 'facebook_page_id' , nice_name: 'Facebook Page ID' , type: 'text', value: <%= raw Caboose.json(sc.facebook_page_id) %>, width: 500 },
33
33
  { name: 'twitter_username' , nice_name: 'Twitter Username' , type: 'text', value: <%= raw Caboose.json(sc.twitter_username) %>, width: 500 },
34
34
  { name: 'instagram_username' , nice_name: 'Instagram Username' , type: 'text', value: <%= raw Caboose.json(sc.instagram_username) %>, width: 500 },
35
- { name: 'youtube_url' , nice_name: 'YouTube Username/Channel ID' , type: 'text', value: <%= raw Caboose.json(sc.youtube_url) %>, width: 500 },
35
+ { name: 'youtube_url' , nice_name: 'YouTube Channel ID' , type: 'text', value: <%= raw Caboose.json(sc.youtube_url) %>, width: 500 },
36
36
  { name: 'pinterest_url' , nice_name: 'Pinterest URL' , type: 'text', value: <%= raw Caboose.json(sc.pinterest_url) %>, width: 500 },
37
37
  { name: 'vimeo_url' , nice_name: 'Vimeo URL' , type: 'text', value: <%= raw Caboose.json(sc.vimeo_url) %>, width: 500 },
38
38
  { name: 'rss_url' , nice_name: 'RSS Feed URL' , type: 'text', value: <%= raw Caboose.json(sc.rss_url) %>, width: 500 },
@@ -10,10 +10,13 @@ sc = @store_config
10
10
  <p><div id='storeconfig_<%= sc.id %>_download_url_expires_in' ></div></p>
11
11
  <p><div id='storeconfig_<%= sc.id %>_starting_order_number' ></div></p>
12
12
 
13
- <h2>Dimension Units</h2>
14
- <p><div id='storeconfig_<%= sc.id %>_length_unit' ></div></p>
13
+ <h3 style="margin-bottom:5px;">Dimension Units</h3>
14
+ <div id='storeconfig_<%= sc.id %>_length_unit' ></div>
15
15
  <p><div id='storeconfig_<%= sc.id %>_weight_unit' ></div></p>
16
16
 
17
+ <h3 style="margin-bottom:5px;">Download Instructions</h3>
18
+ <div id='storeconfig_<%= sc.id %>_download_instructions' ></div>
19
+
17
20
  <%= render :partial => 'caboose/store/admin_footer' %>
18
21
 
19
22
  <% content_for :caboose_js do %>
@@ -44,7 +47,8 @@ $(document).ready(function() {
44
47
  { name: 'length_unit' , nice_name: 'Length' , type: 'select' , value: <%= raw Caboose.json(sc.length_unit ) %>, width: 400 , options_url: '/admin/store/length-unit-options' },
45
48
  { name: 'weight_unit' , nice_name: 'Weight' , type: 'select' , value: <%= raw Caboose.json(sc.weight_unit ) %>, width: 400 , options_url: '/admin/store/weight-unit-options' },
46
49
  { name: 'download_url_expires_in' , nice_name: 'Download URL Expires In (minutes)' , type: 'text' , value: <%= raw Caboose.json(sc.download_url_expires_in ) %>, width: 400 },
47
- { name: 'starting_order_number' , nice_name: 'Starting Order Number' , type: 'text' , value: <%= raw Caboose.json(sc.starting_order_number ) %>, width: 400 }
50
+ { name: 'starting_order_number' , nice_name: 'Starting Order Number' , type: 'text' , value: <%= raw Caboose.json(sc.starting_order_number ) %>, width: 400 },
51
+ { name: 'download_instructions' , nice_name: 'Download Instructions' , type: 'textarea' , value: <%= raw Caboose.json(sc.download_instructions ) %>, width: 800, height: 200, fixed_placeholder: false }
48
52
  ]
49
53
  });
50
54
 
@@ -33,13 +33,19 @@ sc = @store_config
33
33
  <p><div id='storeconfig_<%= sc.id %>_ups_password' ></div></p>
34
34
  <p><div id='storeconfig_<%= sc.id %>_ups_key' ></div></p>
35
35
  <p><div id='storeconfig_<%= sc.id %>_ups_origin_account' ></div></p>
36
+ <p><div id='storeconfig_<%= sc.id %>_ups_min' ></div></p>
37
+ <p><div id='storeconfig_<%= sc.id %>_ups_max' ></div></p>
36
38
  <p><div id='storeconfig_<%= sc.id %>_usps_username' ></div></p>
37
39
  <p><div id='storeconfig_<%= sc.id %>_usps_secret_key' ></div></p>
38
40
  <p><div id='storeconfig_<%= sc.id %>_usps_publishable_key' ></div></p>
41
+ <p><div id='storeconfig_<%= sc.id %>_usps_min' ></div></p>
42
+ <p><div id='storeconfig_<%= sc.id %>_usps_max' ></div></p>
39
43
  <p><div id='storeconfig_<%= sc.id %>_fedex_username' ></div></p>
40
44
  <p><div id='storeconfig_<%= sc.id %>_fedex_password' ></div></p>
41
45
  <p><div id='storeconfig_<%= sc.id %>_fedex_key' ></div></p>
42
46
  <p><div id='storeconfig_<%= sc.id %>_fedex_account' ></div></p>
47
+ <p><div id='storeconfig_<%= sc.id %>_fedex_min' ></div></p>
48
+ <p><div id='storeconfig_<%= sc.id %>_fedex_max' ></div></p>
43
49
 
44
50
  <%= render :partial => 'caboose/store/admin_footer' %>
45
51
 
@@ -65,6 +71,12 @@ $(document).ready(function() {
65
71
  { name: 'fedex_password' , nice_name: 'FedEx Password' , type: 'text' , value: <%= raw Caboose.json(sc.fedex_password ) %>, width: 400 },
66
72
  { name: 'fedex_key' , nice_name: 'FedEx Key' , type: 'text' , value: <%= raw Caboose.json(sc.fedex_key ) %>, width: 400 },
67
73
  { name: 'fedex_account' , nice_name: 'FedEx Account' , type: 'text' , value: <%= raw Caboose.json(sc.fedex_account ) %>, width: 400 },
74
+ { name: 'ups_min' , nice_name: 'UPS Min' , type: 'text' , value: <%= raw Caboose.json(sc.ups_min ) %>, width: 400 },
75
+ { name: 'ups_max' , nice_name: 'UPS Max' , type: 'text' , value: <%= raw Caboose.json(sc.ups_max ) %>, width: 400 },
76
+ { name: 'usps_min' , nice_name: 'USPS Min' , type: 'text' , value: <%= raw Caboose.json(sc.usps_min ) %>, width: 400 },
77
+ { name: 'usps_max' , nice_name: 'USPS Max' , type: 'text' , value: <%= raw Caboose.json(sc.usps_max ) %>, width: 400 },
78
+ { name: 'fedex_min' , nice_name: 'FedEx Min' , type: 'text' , value: <%= raw Caboose.json(sc.fedex_min ) %>, width: 400 },
79
+ { name: 'fedex_max' , nice_name: 'FedEx Max' , type: 'text' , value: <%= raw Caboose.json(sc.fedex_max ) %>, width: 400 },
68
80
  { name: 'origin_address1' , nice_name: 'Address 1' , type: 'text' , value: <%= raw Caboose.json(sc.origin_address1 ) %>, width: 400 },
69
81
  { name: 'origin_address2' , nice_name: 'Address 2' , type: 'text' , value: <%= raw Caboose.json(sc.origin_address2 ) %>, width: 400 },
70
82
  { name: 'origin_city' , nice_name: 'City' , type: 'text' , value: <%= raw Caboose.json(sc.origin_city ) %>, width: 400 },
@@ -455,6 +455,25 @@ Caboose::Engine.routes.draw do
455
455
  post '/checkout/authnet-response/:order_id' => 'checkout#authnet_response'
456
456
  get '/checkout/empty' => 'checkout#empty'
457
457
 
458
+ #=============================================================================
459
+ # Product Modifications
460
+ #=============================================================================
461
+
462
+ get "/admin/products/:product_id/modifications/:mod_id/values/json" => "modification_values#admin_json"
463
+ get "/admin/products/:product_id/modifications/:mod_id/values/:id/json" => "modification_values#admin_json_single"
464
+ put "/admin/products/:product_id/modifications/:mod_id/values/:id" => "modification_values#admin_update"
465
+ post "/admin/products/:product_id/modifications/:mod_id/values" => "modification_values#admin_add"
466
+ delete "/admin/products/:product_id/modifications/:mod_id/values/:id" => "modification_values#admin_delete"
467
+ put "/admin/products/:product_id/modifications/:mod_id/values/sort-order" => "modification_values#admin_update_sort_order"
468
+
469
+ get "/admin/products/:product_id/modifications/json" => "modifications#admin_json"
470
+ get "/admin/products/:product_id/modifications/:id/json" => "modifications#admin_json_single"
471
+ put "/admin/products/:product_id/modifications/:id" => "modifications#admin_update"
472
+ post "/admin/products/:product_id/modifications" => "modifications#admin_add"
473
+ delete "/admin/products/:product_id/modifications/:id" => "modifications#admin_delete"
474
+ put "/admin/products/:product_id/modifications/sort-order" => "modifications#admin_update_sort_order"
475
+
476
+
458
477
  #=============================================================================
459
478
  # Products
460
479
  #=============================================================================
@@ -1,3 +1,3 @@
1
1
  module Caboose
2
- VERSION = '0.5.205'
2
+ VERSION = '0.5.206'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caboose-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.205
4
+ version: 0.5.206
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Barry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-29 00:00:00.000000000 Z
11
+ date: 2015-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -396,6 +396,7 @@ files:
396
396
  - app/assets/images/caboose/search.png
397
397
  - app/assets/javascripts/caboose/admin.js
398
398
  - app/assets/javascripts/caboose/admin_block_edit.js
399
+ - app/assets/javascripts/caboose/admin_edit_modifications.js
399
400
  - app/assets/javascripts/caboose/admin_edit_order.js
400
401
  - app/assets/javascripts/caboose/admin_images_index.js
401
402
  - app/assets/javascripts/caboose/admin_main.js
@@ -540,6 +541,8 @@ files:
540
541
  - app/controllers/caboose/logout_controller.rb
541
542
  - app/controllers/caboose/media_categories_controller.rb
542
543
  - app/controllers/caboose/modal_controller.rb
544
+ - app/controllers/caboose/modification_values_controller.rb
545
+ - app/controllers/caboose/modifications_controller.rb
543
546
  - app/controllers/caboose/my_account_controller.rb
544
547
  - app/controllers/caboose/my_account_line_items_controller.rb
545
548
  - app/controllers/caboose/my_account_orders_controller.rb
@@ -609,12 +612,15 @@ files:
609
612
  - app/models/caboose/domain.rb
610
613
  - app/models/caboose/gift_card.rb
611
614
  - app/models/caboose/line_item.rb
615
+ - app/models/caboose/line_item_modification.rb
612
616
  - app/models/caboose/media_category.rb
613
617
  - app/models/caboose/media_file.rb
614
618
  - app/models/caboose/media_image.rb
615
619
  - app/models/caboose/menu_block.rb
616
620
  - app/models/caboose/message.rb
617
621
  - app/models/caboose/model_binder.rb
622
+ - app/models/caboose/modification.rb
623
+ - app/models/caboose/modification_value.rb
618
624
  - app/models/caboose/order.rb
619
625
  - app/models/caboose/order_discount.rb
620
626
  - app/models/caboose/order_package.rb