caboose-cms 0.7.85 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/caboose/{admin_edit_order.js → admin_edit_invoice.js} +332 -189
  3. data/app/assets/javascripts/caboose/cart.js +15 -15
  4. data/app/assets/javascripts/caboose/cart_old.js +2 -2
  5. data/app/assets/javascripts/caboose/checkout/authnet_payment_method_controller.js +120 -0
  6. data/app/assets/javascripts/caboose/checkout/billing_address_controller.js +85 -0
  7. data/app/assets/javascripts/caboose/checkout/cart_controller.js +257 -0
  8. data/app/assets/javascripts/caboose/checkout/checkout_controller.js +258 -0
  9. data/app/assets/javascripts/caboose/checkout/gift_cards_controller.js +57 -0
  10. data/app/assets/javascripts/caboose/checkout/shipping_address_controller.js +86 -0
  11. data/app/assets/javascripts/caboose/checkout/shipping_method_controller.js +121 -0
  12. data/app/assets/javascripts/caboose/checkout/stripe_payment_method_controller.js +155 -0
  13. data/app/assets/javascripts/caboose/checkout_login_register.js +2 -2
  14. data/app/assets/javascripts/caboose/checkout_module.js +8 -8
  15. data/app/assets/javascripts/caboose/checkout_old.js +151 -0
  16. data/app/assets/javascripts/caboose/{checkout_payment.js → checkout_payment_authnet.js} +1 -1
  17. data/app/assets/javascripts/caboose/checkout_payment_stripe.js +212 -0
  18. data/app/assets/javascripts/caboose/checkout_shipping.js +1 -1
  19. data/app/assets/javascripts/caboose/jquery.payment.js +1 -0
  20. data/app/assets/javascripts/caboose/model/attribute.js +3 -2
  21. data/app/assets/javascripts/caboose/model/bound_control.js +56 -14
  22. data/app/assets/javascripts/caboose/model/bound_select.js +9 -11
  23. data/app/assets/javascripts/caboose/model/bound_select_simple.js +215 -0
  24. data/app/assets/javascripts/caboose/model/bound_text.js +7 -8
  25. data/app/assets/javascripts/caboose/{my_account_edit_order.js → my_account_edit_invoice.js} +55 -55
  26. data/app/assets/javascripts/caboose/united_states.js +65 -0
  27. data/app/assets/stylesheets/caboose/{my_account_edit_order.css.scss → my_account_edit_invoice.css.scss} +1 -1
  28. data/app/assets/templates/caboose/cart/line_items.jst.ejs +3 -3
  29. data/app/assets/templates/caboose/checkout/line_items.jst.ejs +7 -7
  30. data/app/controllers/caboose/ab_options_controller.rb +4 -4
  31. data/app/controllers/caboose/ab_variants_controller.rb +5 -5
  32. data/app/controllers/caboose/admin_controller.rb +0 -6
  33. data/app/controllers/caboose/application_controller.rb +16 -15
  34. data/app/controllers/caboose/billing_addresses_controller.rb +22 -22
  35. data/app/controllers/caboose/block_type_sources_controller.rb +8 -8
  36. data/app/controllers/caboose/block_types_controller.rb +2 -42
  37. data/app/controllers/caboose/blocks_controller.rb +26 -26
  38. data/app/controllers/caboose/calendars_controller.rb +5 -5
  39. data/app/controllers/caboose/cart_controller.rb +55 -36
  40. data/app/controllers/caboose/categories_controller.rb +78 -76
  41. data/app/controllers/caboose/checkout_controller.rb +313 -340
  42. data/app/controllers/caboose/checkout_controller_bak.rb +620 -0
  43. data/app/controllers/caboose/domains_controller.rb +5 -5
  44. data/app/controllers/caboose/event_groups_controller.rb +26 -4
  45. data/app/controllers/caboose/events_controller.rb +7 -6
  46. data/app/controllers/caboose/fonts_controller.rb +2 -2
  47. data/app/controllers/caboose/gift_cards_controller.rb +113 -139
  48. data/app/controllers/caboose/google_spreadsheets_controller.rb +1 -1
  49. data/app/controllers/caboose/{order_packages_controller.rb → invoice_packages_controller.rb} +49 -49
  50. data/app/controllers/caboose/{order_reports_controller.rb → invoice_reports_controller.rb} +11 -13
  51. data/app/controllers/caboose/invoice_transactions_controller.rb +35 -0
  52. data/app/controllers/caboose/invoices_controller.rb +328 -0
  53. data/app/controllers/caboose/line_items_controller.rb +35 -34
  54. data/app/controllers/caboose/login_controller.rb +7 -7
  55. data/app/controllers/caboose/login_logs_controller.rb +4 -4
  56. data/app/controllers/caboose/logout_controller.rb +3 -1
  57. data/app/controllers/caboose/media_categories_controller.rb +9 -9
  58. data/app/controllers/caboose/media_controller.rb +21 -46
  59. data/app/controllers/caboose/modal_controller.rb +4 -3
  60. data/app/controllers/caboose/modification_values_controller.rb +6 -6
  61. data/app/controllers/caboose/modifications_controller.rb +7 -6
  62. data/app/controllers/caboose/my_account_controller.rb +2 -2
  63. data/app/controllers/caboose/my_account_invoices_controller.rb +166 -0
  64. data/app/controllers/caboose/my_account_line_items_controller.rb +15 -13
  65. data/app/controllers/caboose/page_custom_fields_controller.rb +9 -8
  66. data/app/controllers/caboose/page_permissions_controller.rb +3 -3
  67. data/app/controllers/caboose/pages_controller.rb +132 -135
  68. data/app/controllers/caboose/permissions_controller.rb +8 -7
  69. data/app/controllers/caboose/post_categories_controller.rb +22 -7
  70. data/app/controllers/caboose/post_custom_fields_controller.rb +9 -8
  71. data/app/controllers/caboose/posts_controller.rb +35 -43
  72. data/app/controllers/caboose/product_images_controller.rb +5 -5
  73. data/app/controllers/caboose/products_controller.rb +53 -47
  74. data/app/controllers/caboose/redirects_controller.rb +7 -7
  75. data/app/controllers/caboose/register_controller.rb +2 -2
  76. data/app/controllers/caboose/retargeting_controller.rb +2 -61
  77. data/app/controllers/caboose/reviews_controller.rb +1 -0
  78. data/app/controllers/caboose/roles_controller.rb +10 -9
  79. data/app/controllers/caboose/settings_controller.rb +9 -7
  80. data/app/controllers/caboose/shipping_addresses_controller.rb +18 -18
  81. data/app/controllers/caboose/shipping_packages_controller.rb +24 -21
  82. data/app/controllers/caboose/sites_controller.rb +35 -25
  83. data/app/controllers/caboose/smtp_controller.rb +3 -3
  84. data/app/controllers/caboose/sns_controller.rb +6 -6
  85. data/app/controllers/caboose/social_controller.rb +5 -6
  86. data/app/controllers/caboose/stackable_groups_controller.rb +10 -8
  87. data/app/controllers/caboose/station_controller.rb +3 -3
  88. data/app/controllers/caboose/store_controller.rb +93 -87
  89. data/app/controllers/caboose/subscriptions_controller.rb +153 -0
  90. data/app/controllers/caboose/users_controller.rb +25 -22
  91. data/app/controllers/caboose/variants_controller.rb +72 -93
  92. data/app/controllers/caboose/vendors_controller.rb +35 -32
  93. data/app/mailers/caboose/{orders_mailer.rb → invoices_mailer.rb} +21 -21
  94. data/app/mailers/caboose/login_mailer.rb +3 -3
  95. data/app/models/caboose/authnet.rb +295 -195
  96. data/app/models/caboose/comment_routes.rb +68 -41
  97. data/app/models/caboose/core_plugin.rb +1 -1
  98. data/app/models/caboose/discount.rb +14 -3
  99. data/app/models/caboose/domain_constraint.rb +11 -3
  100. data/app/models/caboose/gift_card.rb +8 -8
  101. data/app/models/caboose/invoice.rb +706 -0
  102. data/app/models/caboose/invoice_discount.rb +10 -0
  103. data/app/models/caboose/invoice_package.rb +76 -0
  104. data/app/models/caboose/{order_package_calculator.rb → invoice_package_calculator.rb} +20 -20
  105. data/app/models/caboose/{order_pdf.rb → invoice_pdf.rb} +30 -30
  106. data/app/models/caboose/{order_reporter.rb → invoice_reporter.rb} +5 -5
  107. data/app/models/caboose/invoice_transaction.rb +169 -0
  108. data/app/models/caboose/line_item.rb +11 -8
  109. data/app/models/caboose/payment_processors/authorizenet.rb +15 -15
  110. data/app/models/caboose/payment_processors/base.rb +3 -3
  111. data/app/models/caboose/{pending_orders_pdf.rb → pending_invoices_pdf.rb} +31 -31
  112. data/app/models/caboose/product.rb +2 -4
  113. data/app/models/caboose/schema.rb +159 -111
  114. data/app/models/caboose/shipping_calculator.rb +41 -139
  115. data/app/models/caboose/smtp_config.rb +2 -1
  116. data/app/models/caboose/store_config.rb +7 -7
  117. data/app/models/caboose/subscription.rb +32 -0
  118. data/app/models/caboose/tax_calculator.rb +36 -36
  119. data/app/models/caboose/user.rb +6 -0
  120. data/app/models/caboose/user_subscription.rb +142 -0
  121. data/app/models/caboose/wish_list.rb +14 -0
  122. data/app/models/caboose/wish_list_line_item.rb +13 -0
  123. data/app/views/caboose/blocks/_products.html.erb +10 -13
  124. data/app/views/caboose/checkout/_address_form.html.erb +14 -14
  125. data/app/views/caboose/checkout/_billing_form.html.erb +3 -3
  126. data/app/views/caboose/checkout/_cart.html.erb +7 -7
  127. data/app/views/caboose/checkout/_cart_old.html.erb +9 -9
  128. data/app/views/caboose/checkout/_confirm.html.erb +9 -9
  129. data/app/views/caboose/checkout/_order_discount.html.erb +3 -3
  130. data/app/views/caboose/checkout/_shipping_address.html.erb +1 -1
  131. data/app/views/caboose/checkout/_shipping_method.html.erb +1 -1
  132. data/app/views/caboose/checkout/addresses.html.erb +10 -10
  133. data/app/views/caboose/checkout/authnet.html.erb +34 -0
  134. data/app/views/caboose/checkout/authnet_response_handler.html.erb +3 -0
  135. data/app/views/caboose/checkout/checkout.html.erb +100 -0
  136. data/app/views/caboose/checkout/confirm_without_payment.html.erb +6 -6
  137. data/app/views/caboose/checkout/discount.html.erb +1 -1
  138. data/app/views/caboose/checkout/index.html.erb +4 -4
  139. data/app/views/caboose/checkout/payment_authnet.html.erb +140 -0
  140. data/app/views/caboose/checkout/payment_stripe.html.erb +95 -0
  141. data/app/views/caboose/checkout/shipping.html.erb +4 -4
  142. data/app/views/caboose/checkout/thanks.html.erb +3 -3
  143. data/app/views/caboose/gift_cards/admin_edit.html.erb +19 -19
  144. data/app/views/caboose/gift_cards/admin_index.html.erb +9 -9
  145. data/app/views/caboose/{orders → invoices}/_admin_footer.html.erb +0 -0
  146. data/app/views/caboose/{orders → invoices}/_admin_header.html.erb +0 -0
  147. data/app/views/caboose/{orders/_quickbooks_order.html.erb → invoices/_quickbooks_invoice.html.erb} +0 -0
  148. data/app/views/caboose/{orders → invoices}/admin_city_report.html.erb +1 -1
  149. data/app/views/caboose/invoices/admin_delete_form.html.erb +18 -0
  150. data/app/views/caboose/{orders → invoices}/admin_edit.html.erb +14 -14
  151. data/app/views/caboose/{orders → invoices}/admin_index.html.erb +24 -24
  152. data/app/views/caboose/{orders → invoices}/admin_invalid_order.html.erb +2 -2
  153. data/app/views/caboose/{orders → invoices}/admin_new.html.erb +7 -7
  154. data/app/views/caboose/{orders → invoices}/admin_print.html.erb +15 -15
  155. data/app/views/caboose/{orders → invoices}/admin_summary_report.html.erb +4 -4
  156. data/app/views/caboose/{orders_mailer/customer_new_order.html.erb → invoices_mailer/customer_new_invoice.html.erb} +21 -21
  157. data/app/views/caboose/invoices_mailer/customer_payment_authorization.html.erb +5 -0
  158. data/app/views/caboose/{orders_mailer → invoices_mailer}/customer_status_updated.html.erb +22 -22
  159. data/app/views/caboose/{orders_mailer/fulfillment_new_order.html.erb → invoices_mailer/fulfillment_new_invoice.html.erb} +23 -23
  160. data/app/views/caboose/{orders_mailer/shipping_order_ready.html.erb → invoices_mailer/shipping_invoice_ready.html.erb} +0 -0
  161. data/app/views/caboose/{orders_mailer → invoices_mailer}/test_email.html.erb +0 -0
  162. data/app/views/caboose/line_items/admin_new.html.erb +1 -1
  163. data/app/views/caboose/login_mailer/forgot_password_email.html.erb +2 -3
  164. data/app/views/caboose/my_account/index.html.erb +1 -1
  165. data/app/views/caboose/{my_account_orders → my_account_invoices}/authnet_relay.html.erb +0 -0
  166. data/app/views/caboose/{my_account_orders → my_account_invoices}/authnet_response.html.erb +0 -0
  167. data/app/views/caboose/{my_account_orders → my_account_invoices}/edit.html.erb +9 -9
  168. data/app/views/caboose/my_account_invoices/index.html.erb +36 -0
  169. data/app/views/caboose/{my_account_orders → my_account_invoices}/payment_form.html.erb +10 -10
  170. data/app/views/caboose/post_categories/admin_index.html.erb +1 -1
  171. data/app/views/caboose/sites/admin_edit.html.erb +1 -1
  172. data/app/views/caboose/store/admin_edit_general.html.erb +5 -3
  173. data/app/views/caboose/store/admin_edit_packages.html.erb +6 -6
  174. data/app/views/caboose/store/admin_edit_shipping.html.erb +3 -3
  175. data/app/views/caboose/store/admin_edit_tax.html.erb +1 -1
  176. data/app/views/caboose/subscriptions/admin_edit.html.erb +82 -0
  177. data/app/views/caboose/subscriptions/admin_index.html.erb +45 -0
  178. data/config/routes.rb +1 -759
  179. data/config/routes_old.rb +759 -0
  180. data/lib/caboose/version.rb +1 -1
  181. data/lib/tasks/caboose.rake +41 -15
  182. metadata +101 -61
  183. data/app/controllers/caboose/my_account_orders_controller.rb +0 -165
  184. data/app/controllers/caboose/orders_controller.rb +0 -310
  185. data/app/models/caboose/order.rb +0 -479
  186. data/app/models/caboose/order_discount.rb +0 -10
  187. data/app/models/caboose/order_package.rb +0 -133
  188. data/app/models/caboose/order_transaction.rb +0 -41
  189. data/app/models/caboose/payment_processors/payscape.rb +0 -94
  190. data/app/views/caboose/checkout/payment.html.erb +0 -146
  191. data/app/views/caboose/my_account_orders/index.html.erb +0 -36
  192. data/app/views/caboose/orders/admin_delete_form.html.erb +0 -21
  193. data/app/views/caboose/orders_mailer/customer_payment_authorization.html.erb +0 -5
@@ -6,59 +6,80 @@ module Caboose
6
6
  end
7
7
 
8
8
  def CommentRoutes.controller_routes(controller = nil)
9
+
10
+ controller = controller[1] if controller && controller.is_a?(Array)
11
+ controller_paths = []
12
+ Gem.loaded_specs.each do |name, s|
13
+ controller_paths << s.full_gem_path
14
+ end
15
+ Rails.application.config.paths['app/controllers'].each do |controller_path|
16
+ controller_paths << Rails.root.join(controller_path)
17
+ end
9
18
 
10
- classes = {'zzz_all_domains' => []}
11
- Rails.application.config.paths['app/controllers'].each do |controller_path|
19
+ classes = {'zzz_all_domains' => []}
20
+ controller_paths.each do |controller_path|
12
21
  #files = Dir.glob(Rails.root.join(controller_path, '*.rb'))
13
22
  #files = controller ? Dir.glob(Rails.root.join(controller_path, "#{controller}_controller.rb")) : Dir.glob(Rails.root.join(controller_path, '**/*.rb'))
14
- files = controller ? Dir.glob(Rails.root.join(controller_path, "#{controller}_controller.rb")) : Dir.glob(Rails.root.join(controller_path, '*.rb'))
15
- for file in files
16
- f = Rails.root.join('app', 'controllers', file)
17
- f2 = File.open(f, "r")
23
+ #files = controller ? Dir.glob(Rails.root.join(controller_path, "#{controller}_controller.rb")) : Dir.glob(Rails.root.join(controller_path, '*.rb'))
24
+ #files = controller ? Dir.glob("#{controller_path}/#{controller}_controller.rb") : Dir.glob("#{controller_path}/*.rb")
25
+ files = controller ? Dir.glob("#{controller_path}/**/#{controller.gsub(/(.*?)::(.*?)/, '\2')}_controller.rb") : Dir.glob("#{controller_path}/**/*_controller.rb")
26
+ #files = Dir.glob("#{controller_path}/**/*_controller.rb")
27
+ for file in files
28
+ f2 = File.open(file, "r")
18
29
 
19
30
  domains = []
31
+ module_name = nil
20
32
  class_name = nil
21
33
  class_priority = 20
22
34
  route_priority = 20
35
+ custom_route_priority = false
23
36
  uris = []
24
37
  actions = []
25
38
  f2.each_line do |line|
26
39
  line = line.strip
27
- if line =~ /^(.*?)class (.*?)Controller(.*?)$/
40
+ if line =~ /^module (.*?)$/
41
+ module_name = line.gsub(/^module (.*?)$/, '\1').gsub(/([A-Z])/, '_\1').downcase
42
+ module_name[0] = '' if module_name[0] == '_'
43
+ elsif line =~ /^(.*?)class (.*?)Controller(.*?)$/
28
44
  class_name = line.gsub(/^(.*?)class (.*?)Controller(.*?)$/, '\2').gsub(/([A-Z])/, '_\1').downcase
29
45
  class_name[0] = '' if class_name[0] == '_'
46
+ class_name = "#{module_name}::#{class_name}" if module_name
30
47
  elsif line =~ /# @route_domain (.*?)$/
31
48
  domain = line.gsub(/# @route_domain (.*?)$/, '\1')
32
- domains << domain if !domains.include?(domain)
49
+ domains << domain if !domains.include?(domain)
50
+ elsif line =~ /# @route_constraints (.*?)$/
51
+ constraints = line.gsub(/# @route_constraints (.*?)$/, '\1')
52
+ uris.last[1] = constraints if uris.length > 0
53
+ constraints = nil
33
54
  elsif line =~ /# @class_route_priority \d/
34
55
  class_priority = line.gsub(/# @class_route_priority (\d*?)$/, '\1').to_i
35
56
  elsif line =~ /# @route_priority \d/
36
- route_priority = line.gsub(/# @route_priority (\d*?)$/, '\1').to_i
37
- elsif line.starts_with?('def ')
38
- actions << [line.gsub('def ', ''), uris, route_priority]
57
+ custom_route_priority = line.gsub(/# @route_priority (\d*?)$/, '\1').to_i
58
+ elsif line.starts_with?('def ')
59
+ actions << [line.gsub('def ', ''), uris, custom_route_priority ? custom_route_priority : route_priority]
39
60
  uris = []
40
- route_priority = 20
41
- elsif line =~ /# @route GET (.*?)/ then uris << "get \"#{line.gsub(/# @route GET (.*?)/ , '\1')}\""
42
- elsif line =~ /# @route POST (.*?)/ then uris << "post \"#{line.gsub(/# @route POST (.*?)/ , '\1')}\""
43
- elsif line =~ /# @route PUT (.*?)/ then uris << "put \"#{line.gsub(/# @route PUT (.*?)/ , '\1')}\""
44
- elsif line =~ /# @route DELETE (.*?)/ then uris << "delete \"#{line.gsub(/# @route DELETE (.*?)/ , '\1')}\""
45
- end
46
- end
47
- if domains.count > 0
48
- domains.each do |domain|
49
- classes[domain] = [] if classes[domain].nil?
50
- classes[domain] << [class_name, actions, class_priority]
61
+ route_priority = route_priority + 1 if !custom_route_priority
62
+ custom_route_priority = false
63
+ constraints = nil
64
+ elsif line =~ /# @route GET (.*?)/ then uris << ["get \"#{line.gsub(/# @route GET (.*?)/ , '\1').strip}\"", nil]
65
+ elsif line =~ /# @route POST (.*?)/ then uris << ["post \"#{line.gsub(/# @route POST (.*?)/ , '\1').strip}\"", nil]
66
+ elsif line =~ /# @route PUT (.*?)/ then uris << ["put \"#{line.gsub(/# @route PUT (.*?)/ , '\1').strip}\"", nil]
67
+ elsif line =~ /# @route DELETE (.*?)/ then uris << ["delete \"#{line.gsub(/# @route DELETE (.*?)/ , '\1').strip}\"", nil]
51
68
  end
52
- else
53
- classes['zzz_all_domains'] << [class_name, actions, class_priority]
54
69
  end
70
+ ds = domains.count > 0 ? domains.sort.join(' ') : 'zzz_all_domains'
71
+ classes[ds] = [] if classes[ds].nil?
72
+ classes[ds] << [class_name, actions, class_priority]
55
73
  end
56
74
  end
57
75
 
58
76
  routes = []
59
77
  classes.sort_by{ |domain, domain_classes| domain }.to_h.each do |domain, domain_classes|
60
-
61
- routes << "constraints Caboose::DomainConstraint.new('#{domain}') do" if domain != 'zzz_all_domains'
78
+
79
+ if domain != 'zzz_all_domains'
80
+ domains = domain.split(' ').collect{ |d| "'#{d}'" }.join(', ')
81
+ routes << "constraints Caboose::DomainConstraint.new([#{domains}]) do"
82
+ end
62
83
  domain_classes.sort_by{ |arr| arr[2] }.each do |carr|
63
84
 
64
85
  class_name = carr[0]
@@ -66,16 +87,20 @@ module Caboose
66
87
 
67
88
  # Get the longest URI so we can make routes that line up vertically
68
89
  longest = ''
69
- actions.each{ |action, uris| uris.each{ |uri| longest = uri if uri.length > longest.length }}
90
+ actions.each{ |action, uris| uris.each{ |uri_arr| longest = uri_arr[0] if uri_arr[0].length > longest.length }}
70
91
  length = longest.length + 1
71
92
 
72
- # Make the route line
93
+ # Make the route line
73
94
  actions.sort_by{ |arr| arr[2] }.each do |arr|
74
95
  action = arr[0]
75
96
  uris = arr[1]
76
- uris.each do |uri|
77
- # puts "#{uri.ljust(length, ' ')} => \"#{class_name}\##{action}\""
78
- routes << "#{uri.ljust(length, ' ')} => \"#{class_name}\##{action}\""
97
+ uris.each do |uri_arr|
98
+ uri = uri_arr[0]
99
+ constraints = uri_arr[1]
100
+ # puts "#{uri.ljust(length, ' ')} => \"#{class_name}\##{action}\""
101
+ route = "#{uri.ljust(length, ' ')} => \"#{class_name}\##{action}\""
102
+ route = "#{route}, :constraints => #{constraints}" if constraints
103
+ routes << route
79
104
  end
80
105
  end
81
106
  #puts ""
@@ -117,17 +142,19 @@ module Caboose
117
142
  return false
118
143
  end
119
144
 
120
- def CommentRoutes.compare_routes
121
-
145
+ def CommentRoutes.compare_routes(controller, route_file)
146
+
147
+ controller = controller[1] if controller && controller.is_a?(Array)
122
148
  routes_in_routes_file = []
123
- file = File.open(Rails.root.join('config', 'routes.rb'), "r")
149
+ file = File.open(route_file ? route_file : Rails.root.join('config', 'routes.rb'), "r")
124
150
  file.each_line do |line|
125
151
  line = line.strip
126
- routes_in_routes_file << self.split_route(line)
152
+ arr = self.split_route(line)
153
+ routes_in_routes_file << arr if arr && arr[2].starts_with?("#{controller}#")
127
154
  end
128
-
155
+
129
156
  routes_in_controllers = []
130
- self.controller_routes.split("\n").each do |route|
157
+ self.controller_routes(controller).split("\n").each do |route|
131
158
  route = route.strip
132
159
  next if route.length == 0
133
160
  routes_in_controllers << self.split_route(route)
@@ -138,8 +165,8 @@ module Caboose
138
165
  # See what routes are in the controller routes but not in routes file
139
166
  routes_not_in_routes_file = []
140
167
  routes_in_controllers.each do |route|
141
- next if route.nil? || route.count != 3
142
- all_routes << [route[0], route[1], route[2], 'Y', self.in_routes_array(route, routes_in_routes_file) ? 'Y' : '']
168
+ next if route.nil? || route.count != 3
169
+ all_routes << [route[0], route[1], route[2], 'Yes', self.in_routes_array(route, routes_in_routes_file) ? 'Yes' : 'No']
143
170
  end
144
171
 
145
172
  # See what routes are in the routes file but not in the controllers
@@ -147,7 +174,7 @@ module Caboose
147
174
  routes_in_routes_file.each do |route|
148
175
  next if route.nil? || route.count != 3
149
176
  if !self.in_routes_array(route, all_routes)
150
- all_routes << [route[0], route[1], route[2], '', 'Y']
177
+ all_routes << [route[0], route[1], route[2], 'No', 'Yes']
151
178
  end
152
179
  end
153
180
 
@@ -161,7 +188,7 @@ module Caboose
161
188
  puts "#{"Verb".ljust(lengths[0], ' ')} #{"URI".ljust(lengths[1], ' ')} #{"Action".ljust(lengths[2], ' ')} #{"In Controller".ljust(14, ' ')} #{"In Routes File".ljust(14, ' ')}"
162
189
  puts "#{"".ljust(lengths[0], '-')} #{"".ljust(lengths[1], '-')} #{"".ljust(lengths[2], '-')} #{"".ljust(14, '-')} #{"".ljust(14, '-')}"
163
190
  all_routes.each do |route|
164
- next if route[3] == 'Y' && route[4] == 'Y'
191
+ #next if route[3] == 'Y' && route[4] == 'Y'
165
192
  puts "#{route[0].ljust(lengths[0], ' ')} #{route[1].ljust(lengths[1], ' ')} #{route[2].ljust(lengths[2], ' ')} #{route[3].ljust(14, ' ')} #{route[4].ljust(14, ' ')}"
166
193
  end
167
194
  puts "\n"
@@ -35,7 +35,7 @@ class Caboose::CorePlugin < Caboose::CaboosePlugin
35
35
  item = { 'id' => 'store', 'text' => 'Store', 'children' => [] }
36
36
  item['children'] << { 'id' => 'categories' , 'href' => '/admin/categories' , 'text' => 'Categories' , 'modal' => false } if user.is_allowed('categories' , 'view')
37
37
  item['children'] << { 'id' => 'giftcards' , 'href' => '/admin/gift-cards' , 'text' => 'Gift Cards' , 'modal' => false } if user.is_allowed('giftcards' , 'view')
38
- item['children'] << { 'id' => 'orders' , 'href' => '/admin/orders' , 'text' => 'Orders' , 'modal' => false } if user.is_allowed('orders' , 'view')
38
+ item['children'] << { 'id' => 'invoices' , 'href' => '/admin/invoices' , 'text' => 'Invoices' , 'modal' => false } if user.is_allowed('invoices' , 'view')
39
39
  item['children'] << { 'id' => 'products' , 'href' => '/admin/products' , 'text' => 'Products' , 'modal' => false } if user.is_allowed('products' , 'view')
40
40
  item['children'] << { 'id' => 'shippingpackages' , 'href' => '/admin/shipping-packages' , 'text' => 'Shipping Packages' , 'modal' => false } if user.is_allowed('shippingpackages' , 'view')
41
41
  item['children'] << { 'id' => 'vendors' , 'href' => '/admin/vendors' , 'text' => 'Vendors' , 'modal' => false } if user.is_allowed('vendors' , 'view')
@@ -1,18 +1,29 @@
1
1
  module Caboose
2
2
  class Discount < ActiveRecord::Base
3
- self.table_name = 'store_order_discounts'
3
+ self.table_name = 'store_invoice_discounts'
4
4
  self.primary_key = 'id'
5
5
 
6
6
  belongs_to :gift_card
7
- belongs_to :order
7
+ belongs_to :invoice
8
8
  attr_accessible :id,
9
9
  :gift_card_id,
10
- :order_id,
10
+ :invoice_id,
11
11
  :amount
12
12
 
13
13
  after_find do |d|
14
14
  d.amount = 0.00 if d.amount.nil?
15
15
  end
16
+
17
+ def calculate_amount
18
+ gc = self.gift_card
19
+ self.amount = case self.gift_card.card_type
20
+ when GiftCard::CARD_TYPE_AMOUNT then (self.order.total >= gc.balance ? gc.balance : self.order.total)
21
+ when GiftCard::CARD_TYPE_PERCENTAGE then self.order.subtotal * gc.total
22
+ when GiftCard::CARD_TYPE_NO_SHIPPING then self.order.shipping
23
+ when GiftCard::CARD_TYPE_NO_TAX then self.order.tax
24
+ end
25
+ self.save
26
+ end
16
27
 
17
28
  end
18
29
  end
@@ -1,9 +1,17 @@
1
1
  class Caboose::DomainConstraint
2
- def initialize(domain)
3
- @domains = [domain].flatten
2
+ def initialize(domains)
3
+ @domains = domains.is_a?(Array) ? domains.flatten : [domains].flatten
4
4
  end
5
5
 
6
6
  def matches?(request)
7
- return @domains.include?(request.host)
7
+ m = false
8
+ @domains.each do |d|
9
+ if request.host =~ /#{d.gsub("\\","\\\\")}/
10
+ m = true
11
+ break
12
+ end
13
+ end
14
+ return m
15
+ #return @domains.include?(request.host)
8
16
  end
9
17
  end
@@ -5,7 +5,7 @@ module Caboose
5
5
 
6
6
  belongs_to :site
7
7
  has_many :discounts
8
- has_many :orders, :through => :discounts
8
+ has_many :invoices, :through => :discounts
9
9
  attr_accessible :id,
10
10
  :site_id,
11
11
  :name, # The name of this discount
@@ -13,7 +13,7 @@ module Caboose
13
13
  :card_type,
14
14
  :total,
15
15
  :balance,
16
- :min_order_total, # The minimum order total required to be able to use the card
16
+ :min_invoice_total, # The minimum invoice total required to be able to use the card
17
17
  :date_available,
18
18
  :date_expires,
19
19
  :status
@@ -30,20 +30,20 @@ module Caboose
30
30
  after_initialize :check_nil_fields
31
31
 
32
32
  def check_nil_fields
33
- self.total = 0.00 if self.total.nil?
34
- self.balance = 0.00 if self.balance.nil?
35
- self.min_order_total = 0.00 if self.min_order_total.nil?
33
+ self.total = 0.00 if self.total.nil?
34
+ self.balance = 0.00 if self.balance.nil?
35
+ self.min_invoice_total = 0.00 if self.min_invoice_total.nil?
36
36
  end
37
37
 
38
- def valid_for_order?(order)
38
+ def valid_for_invoice?(invoice)
39
39
  return false if self.status != GiftCard::STATUS_ACTIVE
40
40
  return false if self.date_available && DateTime.now.utc < self.date_available
41
41
  return false if self.date_expires && DateTime.now.utc > self.date_expires
42
42
  return false if self.card_type == GiftCard::CARD_TYPE_AMOUNT && self.balance <= 0
43
- return false if self.min_order_total && order.total < self.min_order_total
43
+ return false if self.min_invoice_total && invoice.total < self.min_invoice_total
44
44
  return true
45
45
  end
46
-
46
+
47
47
  end
48
48
  end
49
49
 
@@ -0,0 +1,706 @@
1
+ #
2
+ # Invoice
3
+ #
4
+
5
+ module Caboose
6
+ class Invoice < ActiveRecord::Base
7
+ self.table_name = 'store_invoices'
8
+ self.primary_key = 'id'
9
+
10
+ belongs_to :site
11
+ belongs_to :customer, :class_name => 'Caboose::User'
12
+ belongs_to :shipping_address, :class_name => 'Caboose::Address'
13
+ belongs_to :billing_address, :class_name => 'Caboose::Address'
14
+ has_many :discounts
15
+ has_many :line_items, :order => :id
16
+ has_many :invoice_packages, :class_name => 'Caboose::InvoicePackage'
17
+ has_many :invoice_transactions
18
+
19
+ attr_accessible :id,
20
+ :site_id ,
21
+ :invoice_number ,
22
+ :alternate_id ,
23
+ :subtotal ,
24
+ :tax ,
25
+ :tax_rate ,
26
+ :shipping ,
27
+ :handling ,
28
+ :gift_wrap ,
29
+ :custom_discount ,
30
+ :discount ,
31
+ :total ,
32
+ :cost ,
33
+ :profit ,
34
+ :customer_id ,
35
+ :financial_status ,
36
+ :shipping_address_id ,
37
+ :billing_address_id ,
38
+ :notes ,
39
+ :status ,
40
+ :payment_terms ,
41
+ :date_created ,
42
+ :date_authorized ,
43
+ :date_captured ,
44
+ :date_shipped ,
45
+ :date_due ,
46
+ :referring_site ,
47
+ :landing_page ,
48
+ :landing_page_ref ,
49
+ :auth_amount ,
50
+ :gift_message ,
51
+ :include_receipt
52
+
53
+ STATUS_CART = 'cart'
54
+ STATUS_PENDING = 'pending'
55
+ STATUS_CANCELED = 'canceled'
56
+ STATUS_READY_TO_SHIP = 'ready to ship'
57
+ STATUS_SHIPPED = 'shipped'
58
+ STATUS_TESTING = 'testing'
59
+
60
+ # New
61
+ #STATUS_PENDING = 'Pending'
62
+ #STATUS_OVERDUE = 'Overdue'
63
+ #STATUS_UNDER_REVIEW = 'Under Review'
64
+ #STATUS_PAID = 'Paid'
65
+ #STATUS_PAID_BY_CHECK = 'Paid By Check'
66
+ #STATUS_CANCELED = 'Canceled'
67
+ #STATUS_WAIVED = 'Waived'
68
+
69
+ FINANCIAL_STATUS_PENDING = 'pending'
70
+ FINANCIAL_STATUS_AUTHORIZED = 'authorized'
71
+ FINANCIAL_STATUS_CAPTURED = 'captured'
72
+ FINANCIAL_STATUS_REFUNDED = 'refunded'
73
+ FINANCIAL_STATUS_VOIDED = 'voided'
74
+
75
+ PAYMENT_TERMS_PIA = 'pia'
76
+ PAYMENT_TERMS_NET7 = 'net7'
77
+ PAYMENT_TERMS_NET10 = 'net10'
78
+ PAYMENT_TERMS_NET30 = 'net30'
79
+ PAYMENT_TERMS_NET60 = 'net60'
80
+ PAYMENT_TERMS_NET90 = 'net90'
81
+ PAYMENT_TERMS_EOM = 'eom'
82
+
83
+ #
84
+ # Scopes
85
+ #
86
+ scope :cart , where('status = ?', 'cart')
87
+ scope :pending , where('status = ?', 'pending')
88
+ scope :canceled , where('status = ?', 'canceled')
89
+ scope :shipped , where('status = ?', 'shipped')
90
+ scope :test , where('status = ?', 'testing')
91
+
92
+ scope :authorized , where('financial_status = ?', 'authorized')
93
+ scope :captured , where('financial_status = ?', 'captured')
94
+ scope :refunded , where('financial_status = ?', 'refunded')
95
+ scope :voided , where('financial_status = ?', 'voided')
96
+
97
+ #
98
+ # Validations
99
+ #
100
+
101
+ validates :status, :inclusion => {
102
+ :in => ['cart', 'pending', 'canceled', 'ready to ship', 'shipped', 'testing'],
103
+ :message => "%{value} is not a valid status. Must be either 'pending' or 'shipped'"
104
+ }
105
+
106
+ validates :financial_status, :inclusion => {
107
+ :in => ['pending', 'authorized', 'captured', 'refunded', 'voided'],
108
+ :message => "%{value} is not a valid financial status. Must be 'authorized', 'captured', 'refunded' or 'voided'"
109
+ }
110
+
111
+ after_initialize :check_nil_fields
112
+
113
+ def check_nil_fields
114
+ self.subtotal = 0.00 if self.subtotal.nil?
115
+ self.tax = 0.00 if self.tax.nil?
116
+ self.shipping = 0.00 if self.shipping.nil?
117
+ self.handling = 0.00 if self.handling.nil?
118
+ self.custom_discount = 0.00 if self.custom_discount.nil?
119
+ self.discount = 0.00 if self.discount.nil?
120
+ self.total = 0.00 if self.total.nil?
121
+ end
122
+
123
+ def decrement_quantities
124
+ self.line_items.each do |line_item|
125
+ line_item.variant.update_attribute(:quantity_in_stock, line_item.variant.quantity_in_stock - line_item.quantity)
126
+ end
127
+ end
128
+
129
+ def increment_quantities
130
+ self.line_items.each do |line_item|
131
+ line_item.variant.update_attribute(:quantity_in_stock, line_item.variant.quantity_in_stock - line_item.quantity)
132
+ end
133
+ end
134
+
135
+ def resend_confirmation
136
+ InvoicesMailer.configure_for_site(self.site_id).customer_new_invoice(self).deliver
137
+ end
138
+
139
+ def test?
140
+ self.status == 'testing'
141
+ end
142
+
143
+ def authorized?
144
+ self.financial_status == 'authorized'
145
+ end
146
+
147
+ #def refund
148
+ # PaymentProcessor.refund(self)
149
+ #end
150
+ #
151
+ #def void
152
+ # PaymentProcessor.void(self)
153
+ #end
154
+
155
+ def calculate
156
+ self.update_column(:subtotal , self.calculate_subtotal )
157
+ self.update_column(:tax , self.calculate_tax )
158
+ self.update_column(:shipping , self.calculate_shipping )
159
+ self.update_column(:handling , self.calculate_handling )
160
+ self.update_column(:gift_wrap , self.calculate_gift_wrap )
161
+
162
+ # Calculate the total without the discounts first
163
+ self.discounts.each{ |d| d.update_column(:amount, 0.0) } if self.discounts
164
+ self.update_column(:total , self.calculate_total )
165
+
166
+ self.update_column(:discount , self.calculate_discount )
167
+ self.update_column(:total , self.calculate_total )
168
+ self.update_column(:cost , self.calculate_cost )
169
+ self.update_column(:profit , self.calculate_profit )
170
+ end
171
+
172
+ def calculate_subtotal
173
+ return 0.0 if self.line_items.empty?
174
+ self.line_items.each{ |li| li.verify_unit_price } # Make sure the unit prices are populated
175
+ x = 0.0
176
+ self.line_items.each{ |li| x = x + (li.unit_price * li.quantity) } # Fixed issue with quantity
177
+ return x
178
+ end
179
+
180
+ def calculate_tax
181
+ return TaxCalculator.tax(self)
182
+ end
183
+
184
+ def calculate_shipping
185
+ return 0.0 if self.invoice_packages.nil? || self.invoice_packages.count == 0
186
+ x = 0.0
187
+ self.invoice_packages.all.each{ |op| x = x + op.total }
188
+ return x
189
+ end
190
+
191
+ def calculate_handling
192
+ return 0.0 if self.site.nil? || self.site.store_config.nil?
193
+ self.subtotal * self.site.store_config.handling_percentage.to_f
194
+ end
195
+
196
+ def calculate_gift_wrap
197
+ x = 0.0
198
+ self.line_items.each do |li|
199
+ next if !li.gift_wrap
200
+ next if !li.variant.product.allow_gift_wrap
201
+ x = x + li.variant.product.gift_wrap_price * li.quantity
202
+ end
203
+ return x
204
+ end
205
+
206
+ def calculate_discount
207
+ x = 0.0
208
+ if self.discounts && self.discounts.count > 0
209
+ self.discounts.each do |d|
210
+ d.calculate_amount
211
+ x = x + d.amount
212
+ end
213
+ end
214
+ x = x + self.custom_discount if self.custom_discount
215
+ return x
216
+ end
217
+
218
+ def calculate_total
219
+ return (self.subtotal + self.tax + self.shipping + self.handling + self.gift_wrap) - self.discount
220
+ end
221
+
222
+ def calculate_cost
223
+ x = 0.0
224
+ invalid_cost = false
225
+ self.line_items.each do |li|
226
+ invalid_cost = true if li.variant.nil? || li.variant.cost.nil?
227
+ x = x + (li.variant.cost * li.quantity)
228
+ end
229
+ return 0.00 if invalid_cost
230
+ return x
231
+ end
232
+
233
+ def calculate_profit
234
+ return 0.00 if self.cost.nil?
235
+ return (self.total - (self.tax ? self.tax : 0.00) - (self.shipping ? self.shipping : 0.00) - (self.handling ? self.handling : 0.00) - (self.gift_wrap ? self.gift_wrap : 0.00)) - self.cost
236
+ end
237
+
238
+ def shipping_and_handling
239
+ (self.shipping ? self.shipping : 0.0) + (self.handling ? self.handling : 0.0)
240
+ end
241
+
242
+ def item_count
243
+ count = 0
244
+ self.line_items.each{ |li| count = count + li.quantity } if self.line_items
245
+ return count
246
+ end
247
+
248
+ def take_gift_card_funds
249
+ return if self.discounts.nil? || self.discounts.count == 0
250
+ self.discounts.each do |d|
251
+ gc = d.gift_card
252
+ gc.balance = gc.balance - d.amount
253
+ gc.save
254
+ end
255
+ end
256
+
257
+ def has_empty_shipping_methods?
258
+ return true if self.invoice_packages.nil?
259
+ return true if self.invoice_packages.count == 0
260
+ self.invoice_packages.all.each do |op|
261
+ return true if op.shipping_method_id.nil?
262
+ end
263
+ return false
264
+ end
265
+
266
+ def has_downloadable_items?
267
+ self.line_items.each do |li|
268
+ return true if li.variant.downloadable
269
+ end
270
+ return false
271
+ end
272
+
273
+ def has_shippable_items?
274
+ self.line_items.each do |li|
275
+ return true if !li.variant.downloadable
276
+ end
277
+ return false
278
+ end
279
+
280
+ def has_taxable_items?
281
+ self.line_items.each do |li|
282
+ return true if li.variant.taxable && li.variant.taxable == true
283
+ end
284
+ return false
285
+ end
286
+
287
+ # Capture funds from a previously authorized transaction
288
+ def capture_funds
289
+
290
+ resp = StdClass.new
291
+ it = InvoiceTransaction.where(:invoice_id => self.id, :success => true).first
292
+
293
+ if self.financial_status == Invoice::FINANCIAL_STATUS_CAPTURED
294
+ resp.error = "Funds for this invoice have already been captured."
295
+ elsif self.total > it.amount
296
+ resp.error = "The invoice total exceeds the authorized amount."
297
+ elsif it.nil?
298
+ resp.error = "This invoice doesn't seem to be authorized."
299
+ else
300
+
301
+ sc = self.site.store_config
302
+ case sc.pp_name
303
+
304
+ #when 'authorize.net'
305
+ # transaction = AuthorizeNet::AIM::Transaction.new(sc.authnet_api_login_id, sc.authnet_api_transaction_key)
306
+ # response = transaction.prior_auth_capture(t.transaction_id, self.total)
307
+ #
308
+ # ot = Caboose::InvoiceTransaction.create(
309
+ # :invoice_id => self.id,
310
+ # :date_processed => DateTime.now.utc,
311
+ # :transaction_type => InvoiceTransaction::TYPE_CAPTURE,
312
+ # :amount => self.total,
313
+ # :success => response.response_code && response.response_code == '1',
314
+ # :transaction_id => response.transaction_id,
315
+ # :auth_code => response.authorization_code,
316
+ # :response_code => response.response_code
317
+ # )
318
+ # if ot.success
319
+ # self.date_captured = DateTime.now.utc
320
+ # self.save
321
+ # end
322
+ # self.update_attribute(:financial_status, Invoice::FINANCIAL_STATUS_CAPTURED)
323
+ # resp.success = 'Captured funds successfully'
324
+
325
+ when StoreConfig::PAYMENT_PROCESSOR_STRIPE
326
+
327
+ it = Caboose::InvoiceTransaction.where(:invoice_id => self.id, :success => true).first
328
+ if it.nil?
329
+ resp.error = "Error capturing funds for invoice #{self.id}. No previous successful authorization for this invoice exists."
330
+ return false
331
+ else
332
+ Stripe.api_key = sc.stripe_secret_key.strip
333
+ bt = nil
334
+ begin
335
+ c = Stripe::Charge.retrieve(it.transaction_id)
336
+ c = c.capture
337
+ bt = Stripe::BalanceTransaction.retrieve(c.balance_transaction)
338
+ rescue Exception => ex
339
+ resp.error = "Error during capture process\n#{ex.message}"
340
+ end
341
+
342
+ if resp.error.nil?
343
+ InvoiceTransaction.create(
344
+ :invoice_id => self.id,
345
+ :transaction_id => bt.id,
346
+ :transaction_type => InvoiceTransaction::TYPE_CAPTURE,
347
+ :amount => bt.amount / 100,
348
+ :date_processed => DateTime.strptime(bt.created.to_s, '%s'),
349
+ :success => bt.status == 'succeeded' || bt.status == 'pending'
350
+ )
351
+ if bt.status == 'succeeded' || bt.status == 'pending'
352
+ self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
353
+ self.save
354
+ resp.success = true
355
+ else
356
+ resp.error = "Error capturing funds."
357
+ end
358
+ end
359
+ end
360
+
361
+ end
362
+ end
363
+ return resp
364
+ end
365
+
366
+ # Void an authorized invoice
367
+ def void
368
+
369
+ resp = StdClass.new
370
+ t = InvoiceTransaction.where(:invoice_id => self.id, :transaction_type => InvoiceTransaction::TYPE_AUTHORIZE, :success => true).first
371
+
372
+ if self.financial_status == Invoice::FINANCIAL_STATUS_CAPTURED
373
+ resp.error = "This invoice has already been captured, you will need to refund instead"
374
+ elsif t.nil?
375
+ resp.error = "This invoice doesn't seem to be authorized."
376
+ else
377
+
378
+ sc = self.site.store_config
379
+ ot = Caboose::InvoiceTransaction.new(
380
+ :invoice_id => self.id,
381
+ :date_processed => DateTime.now.utc,
382
+ :transaction_type => InvoiceTransaction::TYPE_VOID,
383
+ :amount => self.total
384
+ )
385
+
386
+ case sc.pp_name
387
+ when 'authorize.net'
388
+ response = AuthorizeNet::SIM::Transaction.new(
389
+ sc.authnet_api_login_id,
390
+ sc.authnet_api_transaction_key,
391
+ self.total,
392
+ :transaction_type => InvoiceTransaction::TYPE_VOID,
393
+ :transaction_id => t.transaction_id,
394
+ :test => sc.pp_testing
395
+ )
396
+ self.update_attributes(
397
+ :financial_status => Invoice::FINANCIAL_STATUS_VOIDED,
398
+ :status => Invoice::STATUS_CANCELED
399
+ )
400
+ self.save
401
+ # TODO: Add the variant quantities invoiceed back
402
+ resp.success = "Invoice voided successfully"
403
+
404
+ ot.success = response.response_code && response.response_code == '1'
405
+ ot.transaction_id = response.transaction_id
406
+ #ot.auth_code = response.authorization_code
407
+ ot.response_code = response.response_code
408
+ ot.save
409
+
410
+ when 'stripe'
411
+ # TODO: Implement void invoice for strip
412
+
413
+ when 'payscape'
414
+ # TODO: Implement void invoice for payscape
415
+
416
+ end
417
+
418
+ end
419
+ return resp
420
+ end
421
+
422
+ # Refund an order
423
+ def refund(amount = nil)
424
+
425
+ resp = StdClass.new
426
+ it = InvoiceTransaction.where(:invoice_id => self.id, :success => true).first
427
+ amount = self.total - self.amount_refunded if amount.nil?
428
+
429
+ if self.financial_status == Invoice::FINANCIAL_STATUS_REFUNDED
430
+ resp.error = "Funds for this invoice have already been refunded."
431
+ elsif amount > self.amount_refunded
432
+ resp.error = "The amount to refund exceeds the amount available to refund."
433
+ elsif it.nil?
434
+ resp.error = "This invoice doesn't seem to be authorized."
435
+ else
436
+
437
+ sc = self.site.store_config
438
+ case sc.pp_name
439
+
440
+ when StoreConfig::PAYMENT_PROCESSOR_STRIPE
441
+
442
+ it = Caboose::InvoiceTransaction.where(:invoice_id => self.id, :success => true).first
443
+ if it.nil?
444
+ resp.error = "Error capturing funds for invoice #{self.id}. No previous successful authorization for this invoice exists."
445
+ return false
446
+ else
447
+ Stripe.api_key = sc.stripe_secret_key.strip
448
+ bt = nil
449
+ begin
450
+ c = Stripe::Charge.retrieve(it.transaction_id)
451
+ c = c.capture
452
+ bt = Stripe::BalanceTransaction.retrieve(c.balance_transaction)
453
+ rescue Exception => ex
454
+ resp.error = "Error during capture process\n#{ex.message}"
455
+ end
456
+
457
+ if resp.error.nil?
458
+ InvoiceTransaction.create(
459
+ :invoice_id => self.id,
460
+ :transaction_id => bt.id,
461
+ :transaction_type => InvoiceTransaction::TYPE_CAPTURE,
462
+ :amount => bt.amount / 100,
463
+ :date_processed => DateTime.strptime(bt.created.to_s, '%s'),
464
+ :success => bt.status == 'succeeded' || bt.status == 'pending'
465
+ )
466
+ if bt.status == 'succeeded' || bt.status == 'pending'
467
+ self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
468
+ self.save
469
+ resp.success = true
470
+ else
471
+ resp.error = "Error capturing funds."
472
+ end
473
+ end
474
+ end
475
+
476
+ end
477
+ end
478
+ return resp
479
+ end
480
+
481
+ def send_payment_authorization_email
482
+ InvoicesMailer.configure_for_site(self.site_id).customer_payment_authorization(self).deliver
483
+ end
484
+
485
+ def determine_statuses
486
+
487
+ auth = false
488
+ capture = false
489
+ void = false
490
+ refund = false
491
+
492
+ self.invoice_transactions.each do |it|
493
+ auth = true if it.transaction_type == InvoiceTransaction::TYPE_AUTHORIZE && it.success == true
494
+ capture = true if it.transaction_type == InvoiceTransaction::TYPE_CAPTURE && it.success == true
495
+ void = true if it.transaction_type == InvoiceTransaction::TYPE_VOID && it.success == true
496
+ refund = true if it.transaction_type == InvoiceTransaction::TYPE_REFUND && it.success == true
497
+ end
498
+
499
+ if refund then self.financial_status = Invoice::FINANCIAL_STATUS_REFUNDED
500
+ elsif void then self.financial_status = Invoice::FINANCIAL_STATUS_VOIDED
501
+ elsif capture then self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
502
+ elsif auth then self.financial_status = Invoice::FINANCIAL_STATUS_AUTHORIZED
503
+ else self.financial_status = Invoice::FINANCIAL_STATUS_PENDING
504
+ end
505
+
506
+ self.status = Invoice::STATUS_PENDING if self.status == Invoice::STATUS_CART && (refund || void || capture || auth)
507
+
508
+ self.save
509
+
510
+ end
511
+
512
+ def hide_prices_for_any_line_item?
513
+ self.line_items.each do |li|
514
+ return true if li.hide_prices
515
+ end
516
+ return false
517
+ end
518
+
519
+ def amount_not_paid
520
+ amount = self.vendor_transactions.where(:success => true).all.collect{ |vt| vt.amount }.sum
521
+ return self.total - amount
522
+ end
523
+
524
+ #===========================================================================
525
+
526
+ def verify_invoice_packages
527
+
528
+ Caboose.log("Verifying invoice packages....")
529
+
530
+ # See if any there are any empty invoice packages
531
+ self.invoice_packages.each do |ip|
532
+ count = 0
533
+ self.line_items.each do |li|
534
+ count = count + 1 if li.invoice_package_id == ip.id
535
+ end
536
+ ip.destroy if count == 0
537
+ end
538
+
539
+ # See if any line items aren't associated with an invoice package
540
+ line_items_attached = true
541
+ self.line_items.each do |li|
542
+ line_items_attached = false if li.invoice_package_id.nil?
543
+ end
544
+ shipping_packages_attached = true
545
+ self.invoice_packages.each do |ip|
546
+ shipping_packages_attached = false if ip.shipping_package_id.nil?
547
+ end
548
+ ips = self.invoice_packages
549
+ if ips.count == 0 || !line_items_attached || !shipping_packages_attached
550
+ self.calculate
551
+ LineItem.where(:invoice_id => self.id).update_all(:invoice_package_id => nil)
552
+ InvoicePackage.where(:invoice_id => self.id).destroy_all
553
+ self.create_invoice_packages
554
+ end
555
+
556
+ end
557
+
558
+ # Calculates the shipping packages required for all the items in the invoice
559
+ def create_invoice_packages
560
+
561
+ Caboose.log("Creating invoice packages...")
562
+
563
+ store_config = self.site.store_config
564
+ if !store_config.auto_calculate_packages
565
+ InvoicePackage.custom_invoice_packages(store_config, self)
566
+ return
567
+ end
568
+
569
+ # Make sure all the line items in the invoice have a quantity of 1
570
+ extra_line_items = []
571
+ self.line_items.each do |li|
572
+ if li.quantity > 1
573
+ (1..li.quantity).each{ |i|
574
+ extra_line_items << li.copy
575
+ }
576
+ li.quantity = 1
577
+ li.save
578
+ end
579
+ end
580
+ extra_line_items.each do |li|
581
+ li.quantity = 1
582
+ li.save
583
+ end
584
+
585
+ # Make sure all the items in the invoice have attributes set
586
+ self.line_items.each do |li|
587
+ v = li.variant
588
+ next if v.downloadable
589
+ Caboose.log("Error: variant #{v.id} has a zero weight") and return false if v.weight.nil? || v.weight == 0
590
+ next if v.volume && v.volume > 0
591
+ Caboose.log("Error: variant #{v.id} has a zero length") and return false if v.length.nil? || v.length == 0
592
+ Caboose.log("Error: variant #{v.id} has a zero width" ) and return false if v.width.nil? || v.width == 0
593
+ Caboose.log("Error: variant #{v.id} has a zero height") and return false if v.height.nil? || v.height == 0
594
+ v.volume = v.length * v.width * v.height
595
+ v.save
596
+ end
597
+
598
+ # Reorder the items in the invoice by volume
599
+ line_items = self.line_items.sort_by{ |li| li.quantity * (li.variant.volume ? li.variant.volume : 0.00) * -1 }
600
+
601
+ # Get all the packages we're going to use
602
+ all_packages = ShippingPackage.where(:site_id => self.site_id).reorder(:flat_rate_price).all
603
+
604
+ # Now go through each variant and fit it in a new or existing package
605
+ line_items.each do |li|
606
+ next if li.variant.downloadable
607
+
608
+ # See if the item will fit in any of the existing packages
609
+ it_fits = false
610
+ self.invoice_packages.all.each do |op|
611
+ it_fits = op.fits(li)
612
+ if it_fits
613
+ li.invoice_package_id = op.id
614
+ li.save
615
+ break
616
+ end
617
+ end
618
+ next if it_fits
619
+
620
+ # Otherwise find the cheapest package the item will fit into
621
+ it_fits = false
622
+ all_packages.each do |sp|
623
+ it_fits = sp.fits(li.variant)
624
+ if it_fits
625
+ op = InvoicePackage.create(:invoice_id => self.id, :shipping_package_id => sp.id)
626
+ li.invoice_package_id = op.id
627
+ li.save
628
+ break
629
+ end
630
+ end
631
+ next if it_fits
632
+
633
+ Caboose.log("Error: line item #{li.id} (#{li.variant.product.title}) does not fit into any package.")
634
+ end
635
+ end
636
+
637
+ def refresh_transactions
638
+ InvoiceTransaction.where(:invoice_id => self.id).destroy_all
639
+ sc = self.site.store_config
640
+ case sc.pp_name
641
+ when StoreConfig::PAYMENT_PROCESSOR_STRIPE
642
+
643
+ Stripe.api_key = sc.stripe_secret_key.strip
644
+ charges = Stripe::Charge.list(:limit => 100, :customer => self.customer.stripe_customer_id)
645
+
646
+ self.financial_status = Invoice::FINANCIAL_STATUS_PENDING
647
+ charges.each do |c|
648
+ invoice_id = c.metadata && c.metadata['invoice_id'] ? c.metadata['invoice_id'].to_i : nil
649
+ next if invoice_id.nil? || invoice_id != self.id
650
+
651
+ if c.refunded then self.financial_status = Invoice::FINANCIAL_STATUS_REFUNDED
652
+ elsif c.status == 'succeeded' && c.captured then self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
653
+ elsif c.status == 'succeeded' then self.financial_status = Invoice::FINANCIAL_STATUS_AUTHORIZED
654
+ end
655
+
656
+ auth_trans = InvoiceTransaction.create(
657
+ :invoice_id => self.id,
658
+ :transaction_id => c.id,
659
+ :transaction_type => c.captured ? InvoiceTransaction::TYPE_AUTHCAP : InvoiceTransaction::TYPE_AUTHORIZE,
660
+ :amount => c.amount / 100.0,
661
+ :amount_refunded => c.amount_refunded,
662
+ :date_processed => DateTime.strptime(c.created.to_s, '%s'),
663
+ :success => c.status == 'succeeded',
664
+ :captured => c.captured,
665
+ :refunded => c.refunded
666
+ )
667
+ if c.balance_transaction
668
+ bt = Stripe::BalanceTransaction.retrieve(c.balance_transaction)
669
+ capture_trans = InvoiceTransaction.create(
670
+ :invoice_id => self.id,
671
+ :parent_id => auth_trans.id,
672
+ :transaction_id => bt.id,
673
+ :transaction_type => InvoiceTransaction::TYPE_CAPTURE,
674
+ :amount => bt.amount / 100.0,
675
+ :date_processed => DateTime.strptime(bt.created.to_s, '%s'),
676
+ :success => bt.status == 'succeeded' || bt.status == 'pending'
677
+ )
678
+ end
679
+ if c.refunds && c.refunds['total_count'] > 0
680
+ total = 0
681
+ c.refunds['data'].each do |r|
682
+ total = total + r.amount
683
+ InvoiceTransaction.create(
684
+ :invoice_id => self.id,
685
+ :parent_id => auth_trans.id,
686
+ :transaction_id => r.id,
687
+ :transaction_type => InvoiceTransaction::TYPE_REFUND,
688
+ :amount => r.amount / 100.0,
689
+ :date_processed => DateTime.strptime(r.created.to_s, '%s'),
690
+ :success => r.status == 'succeeded' || r.status == 'pending'
691
+ )
692
+ end
693
+ total = total.to_f / 100
694
+ if total >= auth_trans.amount
695
+ auth_trans.refunded = true
696
+ auth_trans.save
697
+ end
698
+ end
699
+ end
700
+ self.save
701
+ end
702
+ end
703
+
704
+ end
705
+ end
706
+