caboose-cms 0.5.205 → 0.5.206

Sign up to get free protection for your applications and to get access to all the features.
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