shoppe 0.0.16 → 0.0.17

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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +5 -6
  3. data/app/assets/javascripts/shoppe/application.coffee +19 -0
  4. data/app/assets/stylesheets/shoppe/application.scss +62 -20
  5. data/app/assets/stylesheets/shoppe/{chosen.css → chosen.scss} +18 -24
  6. data/app/assets/stylesheets/shoppe/dialog.scss +17 -2
  7. data/app/controllers/shoppe/orders_controller.rb +9 -7
  8. data/app/controllers/shoppe/payments_controller.rb +33 -0
  9. data/app/controllers/shoppe/settings_controller.rb +4 -0
  10. data/app/controllers/shoppe/tax_rates_controller.rb +1 -1
  11. data/app/controllers/shoppe/users_controller.rb +1 -1
  12. data/app/helpers/shoppe/application_helper.rb +0 -9
  13. data/app/models/shoppe/country.rb +17 -20
  14. data/app/models/shoppe/delivery_service.rb +16 -22
  15. data/app/models/shoppe/delivery_service_price.rb +10 -21
  16. data/app/models/shoppe/order/actions.rb +80 -0
  17. data/app/models/shoppe/order/billing.rb +99 -0
  18. data/app/models/shoppe/order/delivery.rb +196 -0
  19. data/app/models/shoppe/order/states.rb +69 -0
  20. data/app/models/shoppe/order.rb +29 -365
  21. data/app/models/shoppe/order_item.rb +52 -39
  22. data/app/models/shoppe/payment.rb +80 -0
  23. data/app/models/shoppe/product/product_attributes.rb +6 -4
  24. data/app/models/shoppe/product/variants.rb +20 -7
  25. data/app/models/shoppe/product.rb +37 -37
  26. data/app/models/shoppe/product_attribute.rb +13 -20
  27. data/app/models/shoppe/product_category.rb +6 -19
  28. data/app/models/shoppe/setting.rb +9 -0
  29. data/app/models/shoppe/stock_level_adjustment.rb +5 -18
  30. data/app/models/shoppe/tax_rate.rb +18 -21
  31. data/app/models/shoppe/user.rb +8 -15
  32. data/app/views/shoppe/delivery_service_prices/_form.html.haml +9 -3
  33. data/app/views/shoppe/delivery_service_prices/index.html.haml +6 -4
  34. data/app/views/shoppe/delivery_services/_form.html.haml +1 -1
  35. data/app/views/shoppe/orders/edit.html.haml +62 -0
  36. data/app/views/shoppe/orders/index.html.haml +2 -3
  37. data/app/views/shoppe/orders/show.html.haml +100 -63
  38. data/app/views/shoppe/payments/refund.html.haml +14 -0
  39. data/app/views/shoppe/product_categories/_form.html.haml +1 -1
  40. data/app/views/shoppe/products/_form.html.haml +8 -2
  41. data/app/views/shoppe/settings/edit.html.haml +1 -1
  42. data/app/views/shoppe/tax_rates/form.html.haml +5 -4
  43. data/app/views/shoppe/users/_form.html.haml +1 -1
  44. data/app/views/shoppe/variants/form.html.haml +2 -2
  45. data/config/routes.rb +3 -1
  46. data/db/migrate/20130926094549_create_shoppe_initial_schema.rb +1 -1
  47. data/db/migrate/20131024201501_add_address_type_to_shoppe_tax_rates.rb +5 -0
  48. data/db/migrate/20131024204815_create_shoppe_payments.rb +32 -0
  49. data/db/schema.rb +218 -0
  50. data/db/seeds.rb +15 -15
  51. data/lib/shoppe/engine.rb +7 -2
  52. data/lib/shoppe/errors/refund_failed.rb +15 -0
  53. data/lib/shoppe/settings.rb +0 -2
  54. data/lib/shoppe/version.rb +1 -1
  55. data/lib/shoppe/view_helpers.rb +16 -0
  56. data/lib/shoppe.rb +23 -6
  57. data/test/app/db/schema.rb +21 -6
  58. data/test/app/log/development.log +12782 -0
  59. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/application.scssc +0 -0
  60. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/chosen.scssc +0 -0
  61. data/test/app/tmp/cache/assets/development/sprockets/01d6eb5fc12044a487be4b93584690f2 +0 -0
  62. data/test/app/tmp/cache/assets/development/sprockets/02d3923383f72b56dd7919e301d22d24 +0 -0
  63. data/test/app/tmp/cache/assets/development/sprockets/0a6bca3e510625f255083bd154cc470b +0 -0
  64. data/test/app/tmp/cache/assets/development/sprockets/2f80004fb2e2ce07283a83ac15cf920a +0 -0
  65. data/test/app/tmp/cache/assets/development/sprockets/322295abdd8625fcce4da08f9565cc63 +0 -0
  66. data/test/app/tmp/cache/assets/development/sprockets/4c8cb5cfd87990ebddbaa5b5fd594be5 +0 -0
  67. data/test/app/tmp/cache/assets/development/sprockets/53c0f5159a54836310b1a3f5357bc4c6 +0 -0
  68. data/test/app/tmp/cache/assets/development/sprockets/7938636d16e11b754d4dd046b89863c4 +0 -0
  69. data/test/app/tmp/cache/assets/development/sprockets/7a90d9251a7c5506f33a3c72a224e571 +0 -0
  70. data/test/app/tmp/cache/assets/development/sprockets/9da17bb4868a0b762f8884db45c76ffd +0 -0
  71. data/test/app/tmp/cache/assets/development/sprockets/a692ba7ed6cff183bb840c2622233c87 +0 -0
  72. data/test/app/tmp/cache/assets/development/sprockets/a9befe910d55141b8ba02d8198b8f966 +0 -0
  73. data/test/app/tmp/cache/assets/development/sprockets/accc4dc17ef18d0b510917a005340da5 +0 -0
  74. data/test/app/tmp/cache/assets/development/sprockets/b9ad7ea18b7e55c3626a15d1dae142ed +0 -0
  75. data/test/app/tmp/cache/assets/development/sprockets/c733f1a2fe9d05a3a634ff64a394f64b +0 -0
  76. data/test/app/tmp/cache/assets/development/sprockets/da76586dcb6d9a408b2cf33307790d66 +0 -0
  77. metadata +62 -63
  78. data/README.rdoc +0 -1
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dcbba75865dfb23d23a64375e7706b6664bc1d19
4
+ data.tar.gz: f5b5ae13ac740c329f9f1b693a42708c632e6530
5
+ SHA512:
6
+ metadata.gz: 8cab21ef5ecd835b5a6afb468c1aa5dbc2a6064ffe536e72e0da60f1bac1ce6c4b1d61b7e60a66e67366a9736bbb47b3afbd74cef97126d2061abeb05ad0786e
7
+ data.tar.gz: ac7abebddd19f138855ed9cc86bda752bf3a2eb9d6156f717abc5dc7f839ab2c48919057e206d4e5f0c51013295d5c1fa7e1b549b5156d52e86f055d39a737a7
data/Rakefile CHANGED
@@ -18,16 +18,15 @@ Rake::TestTask.new(:test) do |t|
18
18
  end
19
19
 
20
20
  namespace :shoppe do
21
-
22
- desc "Generate RDoc documentation into doc/"
23
- task :generate_docs do
24
- system("rm -Rf doc")
25
- system("bundle exec sdoc app/models lib README.rdoc")
21
+ desc 'Publish the release notes'
22
+ task :changelog do
23
+ system "scp CHANGELOG.md rubyapps@tryshoppe.com:/opt/rubyapps/shoppe-website/shared/CHANGELOG.md"
26
24
  end
27
25
 
28
26
  desc "Publish RDoc documentation from doc to api.tryshoppe.com"
29
- task :publish_docs do
27
+ task :docs do
30
28
  if File.exist?("doc")
29
+ system "yard"
31
30
  system "ssh root@tryshoppe.com rm -Rf /var/www/shoppe-api"
32
31
  system "scp -r doc root@tryshoppe.com:/var/www/shoppe-api"
33
32
  else
@@ -42,12 +42,23 @@ $ ->
42
42
  # Chosen
43
43
  $('select.chosen').chosen()
44
44
  $('select.chosen-with-deselect').chosen({allow_single_deselect: true})
45
+ $('select.chosen-basic').chosen({disable_search_threshold:100})
45
46
 
46
47
  # Printables
47
48
  $('a[rel=print]').on 'click', ->
48
49
  window.open($(this).attr('href'), 'despatchnote', 'width=700,height=800')
49
50
  false
50
51
 
52
+ # Order editting
53
+ toggleDeliveryFieldsetForOrder = ->
54
+ fieldset = $('form.edit_order fieldset.delivery')
55
+ if $('form.edit_order input#order_separate_delivery_address').prop('checked') then fieldset.show() else fieldset.hide()
56
+ $('form.edit_order input#order_separate_delivery_address').on 'change', toggleDeliveryFieldsetForOrder
57
+ toggleDeliveryFieldsetForOrder()
58
+
59
+ # Close dialog
60
+ $('body').on 'click', 'a[rel=closeDialog]', Nifty.Dialog.closeTopDialog
61
+
51
62
  # Open AJAX dialogs
52
63
  $('a[rel=dialog]').on 'click', ->
53
64
  element = $(this)
@@ -59,6 +70,14 @@ $ ->
59
70
  options.url = element.attr('href')
60
71
  Nifty.Dialog.open(options)
61
72
  false
73
+
74
+ # Format money values to 2 decimal places
75
+ formatMoneyField = ->
76
+ value = $(this).val()
77
+ if value.length
78
+ $(this).val(parseFloat(value).toFixed(2))
79
+ $('div.moneyInput input').each formatMoneyField
80
+ $('div.moneyInput input').on('blur', formatMoneyField)
62
81
 
63
82
  #
64
83
  # Stock Level Adjustment dialog beavior
@@ -129,17 +129,25 @@ header.main {
129
129
  &.received { color:#909091; background-image:image-url('shoppe/statuses/received.svg'); }
130
130
  }
131
131
 
132
+ //
133
+ // fieldset
134
+ //
135
+ fieldset {
136
+ border:1px solid #dce2eb;
137
+ background:#fff;
138
+ padding-top:15px;
139
+ padding-bottom:25px;
140
+ margin-bottom:15px;
141
+ legend {color:#5B6270; margin:0 25px; font-weight:300; font-size:1.5em;}
142
+ &.padded { padding:15px 25px 25px 25px;}
143
+ &.padded legend { margin:0;}
144
+ }
145
+
132
146
  //
133
147
  // forms
134
148
  //
135
149
  form {
136
150
  fieldset {
137
- border:1px solid #dce2eb;
138
- background:#fff;
139
- padding-top:15px;
140
- padding-bottom:25px;
141
- margin-bottom:15px;
142
- legend {color:#5B6270; margin:0 25px; font-weight:300; font-size:1.5em;}
143
151
 
144
152
  .splitContainer { margin:0 25px; margin-bottom:15px; height:50px;}
145
153
  .splitContainer:last-child { margin-bottom:0;}
@@ -162,6 +170,8 @@ header.main {
162
170
  padding-top:4px;
163
171
  input,label { margin-right:10px;}
164
172
  }
173
+ dd.space { margin-bottom:5px;}
174
+ dd.space:last-child { margin-bottom:0;}
165
175
  &.half {
166
176
  width:49%;
167
177
  margin:0;
@@ -272,6 +282,7 @@ header.main {
272
282
  dl {
273
283
  dt { float:left; width:30%; text-align:right; color:#888;white-space:nowrap}
274
284
  dd { font-weight:bold; margin-left:35%; margin-bottom:6px; white-space:nowrap}
285
+ dd a { color:inherit;}
275
286
  dt.padding { padding-top:6px;}
276
287
  }
277
288
 
@@ -289,7 +300,7 @@ header.main {
289
300
  margin:45px 0;
290
301
  overflow:hidden;
291
302
  ul {
292
- li { width:25%;float:left; text-align:center; background:image-url('shoppe/statuses/shipped.svg') no-repeat center 0; background-size:36px; padding-top:42px;z-index:10;}
303
+ li { width:33%;float:left; text-align:center; background:image-url('shoppe/statuses/shipped.svg') no-repeat center 0; background-size:36px; padding-top:42px;z-index:10;}
293
304
  h4 { color:#E32479;}
294
305
  li p { margin-top:5px; font-size:0.9em; color:#999;}
295
306
  li a { color:inherit;}
@@ -304,29 +315,50 @@ header.main {
304
315
  }
305
316
  }
306
317
 
307
- .notes {
308
- background:#fff;
309
- border:1px solid #CED2D8;
310
- p { padding:15px;}
311
- p textarea { border:0; padding:0; width:100%; resize:none; height:100px; font-family:$font; font-size:1.1em}
312
- h4 { background:#F7F9FC; padding:10px 15px; font-weight:500;}
313
- h4 input { float:right; margin-top:-3px;}
314
- }
315
-
316
318
  .order_items {
317
- margin:25px 0;
318
319
  table.data {
319
320
  .money { text-align:right; width:8%}
320
321
  .product { width:42%;}
321
322
  .sku { width:18%;}
322
323
  .qty {text-align:center; width:5%;}
323
- tfoot td { background:#5B6270; color:#fff; border:1px solid #5B6270; font-weight:bold; font-size:1.1em;}
324
324
  }
325
325
  }
326
326
  }
327
327
 
328
328
  //
329
- // orer search
329
+ // payments
330
+ //
331
+ fieldset.orderPayments {
332
+ h4 { font-weight:bold; text-transform:uppercase; color:#5B6270;}
333
+ .table {
334
+ margin-bottom:20px;
335
+ table td.refund { width:10%; text-align:center;}
336
+ table td.confirmed { width:5%; text-align:center;}
337
+ }
338
+ form {
339
+ overflow:hidden;
340
+ background:#F7F9FC;
341
+ border:1px solid #DCE2EB;
342
+ padding:15px;
343
+ dl {
344
+ width:23%;float:left;
345
+ dt { margin-bottom:4px; font-size:0.9em;color:#A9AEB5; font-weight:500;}
346
+ &.text { width:27%;margin-right:2%;}
347
+ &.amount { width:25%;}
348
+ &.submit { width:15%; text-align:right; margin-top:15px;}
349
+ }
350
+ }
351
+ p.notice {
352
+ background:#fffff3;
353
+ padding:10px;
354
+ color:#F67C00;
355
+ border:1px solid #F6B721;
356
+ margin-bottom:15px;
357
+ }
358
+ }
359
+
360
+ //
361
+ // order search
330
362
  //
331
363
  div.orderSearch {
332
364
  overflow:hidden;
@@ -366,13 +398,22 @@ footer {
366
398
  }
367
399
  }
368
400
 
369
- span.boolean span.true { color:#38BA4F}
401
+ span.boolean span.true { color:#96BF48}
370
402
  span.boolean span.false { color:#c04a4a}
371
403
 
372
404
  .float-right { float:right;}
373
405
 
374
406
  div.field_with_errors { display:inline;}
375
407
 
408
+ //
409
+ // money input box
410
+ //
411
+ div.moneyInput {
412
+ overflow:hidden;
413
+ div.currency {float:left; background:#f3f6ec; color:#74884a; padding:5px; width:20px; text-align:center;border:1px solid #c5ceb1; font-size:1.1em; border-right:0;}
414
+ input { width:100px; font-size:1.1em;}
415
+ }
416
+
376
417
  //
377
418
  // standard text input box
378
419
  //
@@ -425,6 +466,7 @@ div.table {
425
466
  td.desc input[type=text] { width:95%;}
426
467
  td.adjustment input[type=text] { width:50px; margin-right:5px;}
427
468
  }
469
+ tfoot td { background:#5B6270; color:#fff; border:1px solid #5B6270; font-weight:bold; font-size:1.1em;}
428
470
  }
429
471
  }
430
472
 
@@ -74,7 +74,7 @@
74
74
  display: block;
75
75
  width: 12px;
76
76
  height: 12px;
77
- background: url('chosen-sprite.png') -42px 1px no-repeat;
77
+ background: image-url('shoppe/chosen-sprite.png') -42px 1px no-repeat;
78
78
  font-size: 1px;
79
79
  }
80
80
  .chosen-container-single .chosen-single abbr:hover {
@@ -95,7 +95,7 @@
95
95
  display: block;
96
96
  width: 100%;
97
97
  height: 100%;
98
- background: url('chosen-sprite.png') no-repeat 0px 2px;
98
+ background: image-url('shoppe/chosen-sprite.png') no-repeat 0px 2px;
99
99
  }
100
100
  .chosen-container-single .chosen-search {
101
101
  position: relative;
@@ -114,12 +114,12 @@
114
114
  height: auto;
115
115
  outline: 0;
116
116
  border: 1px solid #ccc;
117
- background: white url('chosen-sprite.png') no-repeat 100% -20px;
118
- background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
119
- background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
120
- background: url('chosen-sprite.png') no-repeat 100% -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
121
- background: url('chosen-sprite.png') no-repeat 100% -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
122
- background: url('chosen-sprite.png') no-repeat 100% -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
117
+ background: white image-url('shoppe/chosen-sprite.png') no-repeat 100% -20px;
118
+ background: image-url('shoppe/chosen-sprite.png') no-repeat 100% -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
119
+ background: image-url('shoppe/chosen-sprite.png') no-repeat 100% -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
120
+ background: image-url('shoppe/chosen-sprite.png') no-repeat 100% -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
121
+ background: image-url('shoppe/chosen-sprite.png') no-repeat 100% -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
122
+ background: image-url('shoppe/chosen-sprite.png') no-repeat 100% -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
123
123
  font-size: 1em;
124
124
  font-family: sans-serif;
125
125
  line-height: normal;
@@ -197,17 +197,12 @@
197
197
  -moz-box-sizing: border-box;
198
198
  box-sizing: border-box;
199
199
  margin: 0;
200
- padding: 0;
200
+ padding: 5px;
201
201
  width: 100%;
202
202
  height: auto !important;
203
203
  height: 1%;
204
204
  border: 1px solid #ccc;
205
205
  background-color: #fff;
206
- background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
207
- background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
208
- background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
209
- background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
210
- background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
211
206
  cursor: text;
212
207
  }
213
208
  .chosen-container-multi .chosen-choices li {
@@ -261,7 +256,7 @@
261
256
  display: block;
262
257
  width: 12px;
263
258
  height: 12px;
264
- background: url('chosen-sprite.png') -42px 1px no-repeat;
259
+ background: image-url('shoppe/chosen-sprite.png') -42px 1px no-repeat;
265
260
  font-size: 1px;
266
261
  }
267
262
  .chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
@@ -298,7 +293,7 @@
298
293
  /* @group Active */
299
294
  .chosen-container-active .chosen-single {
300
295
  border: 1px solid #9AC835;
301
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
296
+ //box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
302
297
  }
303
298
  .chosen-container-active.chosen-with-drop .chosen-single {
304
299
  border: 1px solid #ccc;
@@ -322,7 +317,6 @@
322
317
  }
323
318
  .chosen-container-active .chosen-choices {
324
319
  border: 1px solid #9AC835;
325
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
326
320
  }
327
321
  .chosen-container-active .chosen-choices li.search-field input[type="text"] {
328
322
  color: #111 !important;
@@ -397,12 +391,12 @@
397
391
  }
398
392
  .chosen-rtl .chosen-search input[type="text"] {
399
393
  padding: 4px 5px 4px 20px;
400
- background: white url('chosen-sprite.png') no-repeat -30px -20px;
401
- background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
402
- background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
403
- background: url('chosen-sprite.png') no-repeat -30px -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
404
- background: url('chosen-sprite.png') no-repeat -30px -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
405
- background: url('chosen-sprite.png') no-repeat -30px -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
394
+ background: white image-url('shoppe/chosen-sprite.png') no-repeat -30px -20px;
395
+ background: image-url('shoppe/chosen-sprite.png') no-repeat -30px -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
396
+ background: image-url('shoppe/chosen-sprite.png') no-repeat -30px -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
397
+ background: image-url('shoppe/chosen-sprite.png') no-repeat -30px -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
398
+ background: image-url('shoppe/chosen-sprite.png') no-repeat -30px -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
399
+ background: image-url('shoppe/chosen-sprite.png') no-repeat -30px -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
406
400
  direction: rtl;
407
401
  }
408
402
  .chosen-rtl.chosen-container-single .chosen-single div b {
@@ -422,7 +416,7 @@
422
416
  .chosen-container-multi .chosen-choices .search-choice .search-choice-close,
423
417
  .chosen-container .chosen-results-scroll-down span,
424
418
  .chosen-container .chosen-results-scroll-up span {
425
- background-image: url('chosen-sprite@2x.png') !important;
419
+ background-image: image-url('shoppe/chosen-sprite@2x.png') !important;
426
420
  background-size: 52px 37px !important;
427
421
  background-repeat: no-repeat !important;
428
422
  }
@@ -1,10 +1,25 @@
1
1
  div.niftyDialog {
2
2
  h2 {
3
3
  background:#fff;
4
- border-bottom:1px solid #efefef;
5
- font-size:1.2em;
4
+ border:0;
5
+ padding:0;
6
+ font-size:1.3em;
7
+ border-bottom:1px solid #000;
8
+ padding-bottom:4px;
9
+ margin-bottom:10px;
6
10
  color:#111;
7
11
  }
8
12
  padding:15px;
9
13
  nav.pagination { margin:0; margin-top:15px;}
14
+ p.intro { line-height:1.5; color:#666; margin:6px 0;}
15
+
16
+ form.refundForm {
17
+ overflow:hidden;
18
+ margin:10px;
19
+ p.intro { margin-bottom:25px;}
20
+ .moneyInput { float:left; }
21
+ .moneyInput .currency { font-size:1.4em;}
22
+ .moneyInput input { font-size:1.4em}
23
+ p.submit { float:right;}
24
+ }
10
25
  }
@@ -8,10 +8,17 @@ module Shoppe
8
8
  @query = Shoppe::Order.ordered.received.includes(:order_items => :ordered_item).page(params[:page]).search(params[:q])
9
9
  @orders = @query.result
10
10
  end
11
+
12
+ def show
13
+ @payments = @order.payments.to_a
14
+ end
11
15
 
12
16
  def update
13
- @order.update_attributes!(params[:order].permit(:notes))
14
- redirect_to @order, :notice => "Order has been saved successfully"
17
+ if @order.update_attributes(params[:order].permit(:notes, :first_name, :last_name, :company, :billing_address1, :billing_address2, :billing_address3, :billing_address4, :billing_postcode, :billing_country_id, :separate_delivery_address,:delivery_name, :delivery_address1, :delivery_address2, :delivery_address3, :delivery_address4, :delivery_postcode, :delivery_country_id, :email_address, :phone_number))
18
+ redirect_to @order, :notice => "Order has been saved successfully"
19
+ else
20
+ render :action => "edit"
21
+ end
15
22
  end
16
23
 
17
24
  def search
@@ -34,11 +41,6 @@ module Shoppe
34
41
  redirect_to @order, :notice => "Order has been shipped successfully"
35
42
  end
36
43
 
37
- def pay
38
- @order.pay!(params[:payment_reference], params[:payment_method].blank? ? 'Unknown' : params[:payment_method])
39
- redirect_to @order, :notice => "Order has been marked as paid successfully"
40
- end
41
-
42
44
  def despatch_note
43
45
  render :layout => 'shoppe/printable'
44
46
  end
@@ -0,0 +1,33 @@
1
+ module Shoppe
2
+ class PaymentsController < ApplicationController
3
+
4
+ before_filter { @order = Shoppe::Order.find(params[:order_id]) }
5
+ before_filter { params[:id] && @payment = @order.payments.find(params[:id]) }
6
+
7
+ def create
8
+ payment = @order.payments.build(params[:payment].permit(:amount, :method, :reference))
9
+ if payment.save
10
+ redirect_to @order, :notice => "Payment has been added successfully"
11
+ else
12
+ redirect_to @order, :alert => payment.errors.full_messages.to_sentence
13
+ end
14
+ end
15
+
16
+ def destroy
17
+ @payment.destroy
18
+ redirect_to @order, :notice => "Payment has been removed successfully"
19
+ end
20
+
21
+ def refund
22
+ if request.post?
23
+ @payment.refund!(params[:amount])
24
+ redirect_to @order, :notice => "Refund has been processed successfully."
25
+ else
26
+ render :layout => false
27
+ end
28
+ rescue Shoppe::Errors::RefundFailed => e
29
+ redirect_to @order, :alert => e.message
30
+ end
31
+
32
+ end
33
+ end
@@ -4,6 +4,10 @@ module Shoppe
4
4
  before_filter { @active_nav = :settings }
5
5
 
6
6
  def update
7
+ if Shoppe.settings.demo_mode?
8
+ raise Shoppe::Error, "You cannot make changes to settings in demo mode. Sorry about that."
9
+ end
10
+
7
11
  Shoppe::Setting.update_from_hash(params[:settings].permit!)
8
12
  redirect_to :settings, :notice => "Settings have been updated successfully."
9
13
  end
@@ -42,7 +42,7 @@ module Shoppe
42
42
  private
43
43
 
44
44
  def safe_params
45
- params[:tax_rate].permit(:name, :rate, :country_ids => [])
45
+ params[:tax_rate].permit(:name, :rate, :address_type, :country_ids => [])
46
46
  end
47
47
 
48
48
  end
@@ -5,7 +5,7 @@ module Shoppe
5
5
  before_filter { params[:id] && @user = Shoppe::User.find(params[:id]) }
6
6
  before_filter(:only => [:create, :update, :destroy]) do
7
7
  if Shoppe.settings.demo_mode?
8
- raise Shoppe::Error, "You cannot make changes to user in demo mode. Sorry about that."
8
+ raise Shoppe::Error, "You cannot make changes to users in demo mode. Sorry about that."
9
9
  end
10
10
  end
11
11
 
@@ -1,15 +1,6 @@
1
1
  module Shoppe
2
2
  module ApplicationHelper
3
3
 
4
- def number_to_currency(number, options = {})
5
- options[:unit] ||= Shoppe.settings.currency_unit
6
- super
7
- end
8
-
9
- def number_to_weight(kg)
10
- "#{kg}#{t('shoppe.helpers.number_to_weight.kg', :default => 'kg')}"
11
- end
12
-
13
4
  def status_tag(status)
14
5
  content_tag :span, status, :class => "status-tag #{status}"
15
6
  end
@@ -1,30 +1,27 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_countries
4
- #
5
- # id :integer not null, primary key
6
- # name :string(255)
7
- # code2 :string(255)
8
- # code3 :string(255)
9
- # continent :string(255)
10
- # tld :string(255)
11
- # currency :string(255)
12
- # eu_member :boolean default(FALSE)
13
- #
14
-
15
1
  module Shoppe
2
+
3
+ # The Shoppe::Country model stores countries which can be used for delivery & billing
4
+ # addresses for orders.
5
+ #
6
+ # You can use the Shoppe::CountryImporter to import a pre-defined list of countries
7
+ # into your database. This automatically happens when you run the 'shoppe:setup'
8
+ # rake task.
9
+
16
10
  class Country < ActiveRecord::Base
17
-
18
- # Set the table name
11
+
19
12
  self.table_name = 'shoppe_countries'
20
-
21
- # Relationships
13
+
14
+ # All orders which have this country set as their billing country
22
15
  has_many :billed_orders, :dependent => :restrict_with_exception, :class_name => 'Shoppe::Order', :foreign_key => 'billing_country_id'
23
- has_many :delivered_orders, :dependent => :restrict_with_exception, :class_name => 'Shoppe::Order', :foreign_key => 'delivery_country_id'
24
16
 
17
+ # All orders which have this country set as their delivery country
18
+ has_many :delivered_orders, :dependent => :restrict_with_exception, :class_name => 'Shoppe::Order', :foreign_key => 'delivery_country_id'
25
19
 
26
- # Scopes
20
+ # All countries ordered by their name asending
27
21
  scope :ordered, -> { order('shoppe_countries.name asc') }
28
22
 
23
+ # Validations
24
+ validates :name, :presence => true
25
+
29
26
  end
30
27
  end
@@ -1,38 +1,32 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_delivery_services
4
- #
5
- # id :integer not null, primary key
6
- # name :string(255)
7
- # code :string(255)
8
- # default :boolean default(FALSE)
9
- # active :boolean default(TRUE)
10
- # created_at :datetime
11
- # updated_at :datetime
12
- # courier :string(255)
13
- # tracking_url :string(255)
14
- #
15
-
16
1
  module Shoppe
17
2
  class DeliveryService < ActiveRecord::Base
18
3
 
19
- # Set the table name
20
4
  self.table_name = 'shoppe_delivery_services'
21
-
5
+
22
6
  # Validations
23
7
  validates :name, :presence => true
24
8
  validates :courier, :presence => true
25
9
 
26
- # Relationships
10
+ # Orders which are assigned to this delivery service
27
11
  has_many :orders, :dependent => :restrict_with_exception, :class_name => 'Shoppe::Order'
12
+
13
+ # Prices for the different levels of service within this delivery service
28
14
  has_many :delivery_service_prices, :dependent => :destroy, :class_name => 'Shoppe::DeliveryServicePrice'
29
15
 
30
- # Scopes
16
+ # All active delivery services
31
17
  scope :active, -> { where(:active => true)}
32
18
 
33
- # Return the tracking URL for the given consignment number
34
- def tracking_url_for(consignment_number)
35
- tracking_url.gsub("{{consignment_number}}", consignment_number)
19
+ # Returns a tracking URL for the passed order
20
+ #
21
+ # @param order [Shoppe::Order]
22
+ # @return [String] the full URL for the order.
23
+ def tracking_url_for(order)
24
+ return nil if self.tracking_url.blank?
25
+ tracking_url = self.tracking_url.dup
26
+ tracking_url.gsub!("{{consignment_number}}", CGI.escape(order.consignment_number.to_s))
27
+ tracking_url.gsub!("{{delivery_postcode}}", CGI.escape(order.delivery_postcode.to_s))
28
+ tracking_url.gsub!("{{billing_postcode}}", CGI.escape(order.billing_postcode.to_s))
29
+ tracking_url
36
30
  end
37
31
 
38
32
  end
@@ -1,41 +1,30 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_delivery_service_prices
4
- #
5
- # id :integer not null, primary key
6
- # delivery_service_id :integer
7
- # code :string(255)
8
- # price :decimal(8, 2)
9
- # cost_price :decimal(8, 2)
10
- # tax_rate_id :integer
11
- # min_weight :decimal(8, 2)
12
- # max_weight :decimal(8, 2)
13
- # created_at :datetime
14
- # updated_at :datetime
15
- # country_ids :text
16
- #
17
-
18
1
  module Shoppe
19
2
  class DeliveryServicePrice < ActiveRecord::Base
20
3
 
21
4
  # Set the table name
22
5
  self.table_name = 'shoppe_delivery_service_prices'
23
6
 
24
- # Tax rates are associated with countries
25
7
  include Shoppe::AssociatedCountries
26
8
 
27
- # Relationships
9
+ # The delivery service which this price belongs to
28
10
  belongs_to :delivery_service, :class_name => 'Shoppe::DeliveryService'
11
+
12
+ # The tax rate which should be applied
29
13
  belongs_to :tax_rate, :class_name => "Shoppe::TaxRate"
30
-
14
+
31
15
  # Validations
16
+ validates :code, :presence => true
32
17
  validates :price, :numericality => true
33
18
  validates :cost_price, :numericality => true, :allow_blank => true
34
19
  validates :min_weight, :numericality => true
35
20
  validates :max_weight, :numericality => true
36
21
 
37
- # Scopes
22
+ # All prices ordered by their price ascending
38
23
  scope :ordered, -> { order('price asc')}
24
+
25
+ # All prices which are suitable for the weight passed.
26
+ #
27
+ # @param weight [BigDecimal] the weight of the order
39
28
  scope :for_weight, -> weight { where("min_weight <= ? AND max_weight >= ?", weight, weight) }
40
29
 
41
30
  end