smartkiosk-server 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (254) hide show
  1. data/.gitignore +32 -0
  2. data/.rspec +1 -0
  3. data/Capfile +4 -0
  4. data/Gemfile +71 -0
  5. data/Gemfile.lock +439 -0
  6. data/Guardfile +25 -0
  7. data/LICENSE +287 -0
  8. data/README.md +13 -0
  9. data/Rakefile +5 -0
  10. data/app/acquirers/cards_mkb_acquirer.rb +87 -0
  11. data/app/acquirers/cash_acquirer.rb +22 -0
  12. data/app/admin/agents.rb +108 -0
  13. data/app/admin/collections.rb +62 -0
  14. data/app/admin/commissions.rb +87 -0
  15. data/app/admin/gateways.rb +183 -0
  16. data/app/admin/limits.rb +82 -0
  17. data/app/admin/payments.rb +246 -0
  18. data/app/admin/provider_groups.rb +60 -0
  19. data/app/admin/provider_profiles.rb +11 -0
  20. data/app/admin/provider_receipt_templates.rb +82 -0
  21. data/app/admin/providers.rb +201 -0
  22. data/app/admin/rebates.rb +83 -0
  23. data/app/admin/report_results.rb +66 -0
  24. data/app/admin/report_templates.rb +209 -0
  25. data/app/admin/reports.rb +158 -0
  26. data/app/admin/revisions.rb +120 -0
  27. data/app/admin/system_receipt_templates.rb +76 -0
  28. data/app/admin/terminal_builds.rb +39 -0
  29. data/app/admin/terminal_profiles.rb +123 -0
  30. data/app/admin/terminals.rb +388 -0
  31. data/app/admin/users.rb +117 -0
  32. data/app/admin/versions.rb +131 -0
  33. data/app/admin/welcome.rb +64 -0
  34. data/app/assets/fonts/PT_Sans-Web-Bold.eot +0 -0
  35. data/app/assets/fonts/PT_Sans-Web-Bold.svg +6386 -0
  36. data/app/assets/fonts/PT_Sans-Web-Bold.ttf +0 -0
  37. data/app/assets/fonts/PT_Sans-Web-Bold.woff +0 -0
  38. data/app/assets/fonts/PT_Sans-Web-Regular.eot +0 -0
  39. data/app/assets/fonts/PT_Sans-Web-Regular.svg +5650 -0
  40. data/app/assets/fonts/PT_Sans-Web-Regular.ttf +0 -0
  41. data/app/assets/fonts/PT_Sans-Web-Regular.woff +0 -0
  42. data/app/assets/images/chosen-sprite.png +0 -0
  43. data/app/assets/javascripts/active_admin/chosen.js.erb.coffee +12 -0
  44. data/app/assets/javascripts/active_admin/qtip.js.coffee +22 -0
  45. data/app/assets/javascripts/active_admin/sortable_forms.js.coffee +14 -0
  46. data/app/assets/javascripts/active_admin.js.coffee +9 -0
  47. data/app/assets/javascripts/application.js +15 -0
  48. data/app/assets/javascripts/report_templates.js.coffee +10 -0
  49. data/app/assets/javascripts/terminals.js.coffee +12 -0
  50. data/app/assets/stylesheets/active_admin/PIE.css.scss +18 -0
  51. data/app/assets/stylesheets/active_admin/filter_numeric_range.css.scss +14 -0
  52. data/app/assets/stylesheets/active_admin/selectable_check_boxes.css.scss +12 -0
  53. data/app/assets/stylesheets/active_admin/sortable_forms.css.scss +11 -0
  54. data/app/assets/stylesheets/active_admin.css.scss +705 -0
  55. data/app/assets/stylesheets/fonts.css.scss +14 -0
  56. data/app/assets/stylesheets/provider_groups.css.scss +12 -0
  57. data/app/assets/stylesheets/provider_receipt_templates.css.scss +12 -0
  58. data/app/assets/stylesheets/terminals.css.scss +9 -0
  59. data/app/controllers/application_controller.rb +12 -0
  60. data/app/controllers/collections_controller.rb +10 -0
  61. data/app/controllers/payments_controller.rb +73 -0
  62. data/app/controllers/system_receipt_templates_controller.rb +10 -0
  63. data/app/controllers/terminal_builds_controller.rb +5 -0
  64. data/app/controllers/terminal_orders_controller.rb +25 -0
  65. data/app/controllers/terminal_pings_controller.rb +45 -0
  66. data/app/controllers/welcome_controller.rb +5 -0
  67. data/app/helpers/active_admin/report_templates_helper.rb +56 -0
  68. data/app/helpers/active_admin/views_helper.rb +20 -0
  69. data/app/helpers/application_helper.rb +2 -0
  70. data/app/mailers/.gitkeep +0 -0
  71. data/app/models/.gitkeep +0 -0
  72. data/app/models/ability.rb +30 -0
  73. data/app/models/agent.rb +24 -0
  74. data/app/models/collection.rb +65 -0
  75. data/app/models/commission.rb +77 -0
  76. data/app/models/commission_section.rb +75 -0
  77. data/app/models/gateway.rb +99 -0
  78. data/app/models/gateway_attachment.rb +9 -0
  79. data/app/models/gateway_setting.rb +7 -0
  80. data/app/models/gateway_switch.rb +7 -0
  81. data/app/models/limit.rb +77 -0
  82. data/app/models/limit_section.rb +58 -0
  83. data/app/models/payment.rb +322 -0
  84. data/app/models/provider.rb +59 -0
  85. data/app/models/provider_field.rb +7 -0
  86. data/app/models/provider_gateway.rb +47 -0
  87. data/app/models/provider_group.rb +45 -0
  88. data/app/models/provider_profile.rb +9 -0
  89. data/app/models/provider_rebate.rb +69 -0
  90. data/app/models/provider_receipt_template.rb +85 -0
  91. data/app/models/rebate.rb +84 -0
  92. data/app/models/report.rb +71 -0
  93. data/app/models/report_result.rb +11 -0
  94. data/app/models/report_template.rb +56 -0
  95. data/app/models/revision.rb +104 -0
  96. data/app/models/role.rb +48 -0
  97. data/app/models/system_receipt_template.rb +13 -0
  98. data/app/models/terminal.rb +126 -0
  99. data/app/models/terminal_build.rb +62 -0
  100. data/app/models/terminal_order.rb +42 -0
  101. data/app/models/terminal_ping.rb +120 -0
  102. data/app/models/terminal_profile.rb +51 -0
  103. data/app/models/terminal_profile_promotion.rb +18 -0
  104. data/app/models/terminal_profile_provider.rb +11 -0
  105. data/app/models/terminal_profile_provider_group.rb +19 -0
  106. data/app/models/user.rb +38 -0
  107. data/app/models/user_role.rb +45 -0
  108. data/app/reports/agents_report.rb +81 -0
  109. data/app/reports/collections_report.rb +151 -0
  110. data/app/reports/payments_report.rb +189 -0
  111. data/app/reports/terminals_report.rb +123 -0
  112. data/app/uploaders/file_uploader.rb +53 -0
  113. data/app/uploaders/icon_uploader.rb +15 -0
  114. data/app/uploaders/zip_uploader.rb +53 -0
  115. data/app/views/admin/gateways/providers.html.arb +10 -0
  116. data/app/views/admin/revisions/payments.html.arb +28 -0
  117. data/app/views/admin/terminal_profiles/_tree.html.haml +35 -0
  118. data/app/views/admin/terminal_profiles/sort.html.haml +21 -0
  119. data/app/views/admin/terminals/pings.html.arb +55 -0
  120. data/app/views/admin/terminals/upgrade_build.html.arb +30 -0
  121. data/app/views/layouts/application.html.erb +1 -0
  122. data/app/views/welcome/index.html.erb +25 -0
  123. data/app/workers/pay_worker.rb +11 -0
  124. data/app/workers/report_worker.rb +7 -0
  125. data/app/workers/revise_worker.rb +7 -0
  126. data/config/acquiring.yml +13 -0
  127. data/config/application.rb +75 -0
  128. data/config/boot.rb +6 -0
  129. data/config/database.yml +17 -0
  130. data/config/deploy/roundlake-passenger.rb +3 -0
  131. data/config/deploy/roundlake-trinidad.rb +3 -0
  132. data/config/deploy.rb +37 -0
  133. data/config/environment.rb +5 -0
  134. data/config/environments/development.rb +39 -0
  135. data/config/environments/production.rb +67 -0
  136. data/config/environments/test.rb +37 -0
  137. data/config/initializers/active_admin.rb +31 -0
  138. data/config/initializers/backtrace_silencers.rb +7 -0
  139. data/config/initializers/devise.rb +232 -0
  140. data/config/initializers/inflections.rb +15 -0
  141. data/config/initializers/mime_types.rb +5 -0
  142. data/config/initializers/money.rb +6 -0
  143. data/config/initializers/redis.rb +4 -0
  144. data/config/initializers/secret_token.rb +7 -0
  145. data/config/initializers/session_store.rb +8 -0
  146. data/config/initializers/setup_rack.rb +1 -0
  147. data/config/initializers/wrap_parameters.rb +14 -0
  148. data/config/locales/active_admin.ru.yml +71 -0
  149. data/config/locales/activerecord.ru.yml +645 -0
  150. data/config/locales/devise.ru.yml +57 -0
  151. data/config/locales/ru.yml +33 -0
  152. data/config/locales/smartkiosk.gateways.ru.yml +241 -0
  153. data/config/locales/smartkiosk.hardware.ru.yml +38 -0
  154. data/config/locales/smartkiosk.reports.ru.yml +56 -0
  155. data/config/locales/smartkiosk.ru.yml +163 -0
  156. data/config/nginx.conf +9 -0
  157. data/config/redis.yml +9 -0
  158. data/config/routes.rb +48 -0
  159. data/config/schedule.rb +13 -0
  160. data/config/sidekiq.yml +5 -0
  161. data/config/trinidad.yml +6 -0
  162. data/config.ru +4 -0
  163. data/db/migrate/20120825083035_create_terminals.rb +47 -0
  164. data/db/migrate/20120825083305_create_payments.rb +51 -0
  165. data/db/migrate/20120827062618_devise_create_users.rb +50 -0
  166. data/db/migrate/20120827132621_create_admin_notes.rb +17 -0
  167. data/db/migrate/20120827132622_move_admin_notes_to_comments.rb +25 -0
  168. data/db/migrate/20120903193346_create_providers.rb +24 -0
  169. data/db/migrate/20120922075345_create_collections.rb +26 -0
  170. data/db/migrate/20120922080440_create_agents.rb +29 -0
  171. data/db/migrate/20120922081104_create_commissions.rb +10 -0
  172. data/db/migrate/20120927035841_create_gateways.rb +13 -0
  173. data/db/migrate/20120927040626_create_provider_gateways.rb +13 -0
  174. data/db/migrate/20120927091849_create_limits.rb +10 -0
  175. data/db/migrate/20120927164647_create_roles.rb +14 -0
  176. data/db/migrate/20121003131522_create_report_templates.rb +18 -0
  177. data/db/migrate/20121007135652_create_reports.rb +13 -0
  178. data/db/migrate/20121008073905_create_report_results.rb +10 -0
  179. data/db/migrate/20121017114538_create_gateway_settings.rb +12 -0
  180. data/db/migrate/20121017114556_create_gateway_attachments.rb +10 -0
  181. data/db/migrate/20121019132606_create_revisions.rb +19 -0
  182. data/db/migrate/20121023073501_create_gateway_switches.rb +10 -0
  183. data/db/migrate/20121112142743_create_terminal_orders.rb +13 -0
  184. data/db/migrate/20121118191553_create_versions.rb +19 -0
  185. data/db/migrate/20121125093414_create_system_receipt_templates.rb +9 -0
  186. data/db/migrate/20121127192257_create_terminal_builds.rb +10 -0
  187. data/db/migrate/20121212053441_create_rebates.rb +15 -0
  188. data/db/migrate/20121216143855_create_provider_receipt_templates.rb +9 -0
  189. data/db/migrate/20130101091100_create_terminal_profiles.rb +13 -0
  190. data/db/migrate/20130101091734_create_provider_rebates.rb +21 -0
  191. data/db/migrate/20130102164447_create_limit_sections.rb +14 -0
  192. data/db/migrate/20130102164503_create_commission_sections.rb +17 -0
  193. data/db/migrate/20130102171743_create_provider_profiles.rb +10 -0
  194. data/db/migrate/20130103152507_create_provider_fields.rb +17 -0
  195. data/db/migrate/20130103154526_create_provider_groups.rb +10 -0
  196. data/db/migrate/20130104063628_create_terminal_profile_providers.rb +11 -0
  197. data/db/migrate/20130104090957_create_terminal_profile_provider_groups.rb +11 -0
  198. data/db/migrate/20130108091644_create_terminal_profile_promotions.rb +10 -0
  199. data/db/schema.rb +489 -0
  200. data/db/seeds/receipt_templates/payment.txt +19 -0
  201. data/db/seeds/receipt_templates/system/balance.txt +13 -0
  202. data/db/seeds/receipt_templates/system/collection.txt +17 -0
  203. data/db/seeds/receipt_templates/system/touchtest.txt +15 -0
  204. data/db/seeds.rb +18 -0
  205. data/doc/README_FOR_APP +2 -0
  206. data/init.rb +1 -0
  207. data/lib/active_admin/cancan_integration.rb +81 -0
  208. data/lib/active_admin/form_builder_fix.rb +76 -0
  209. data/lib/active_admin/inputs/filter_date_range_input_fix.rb +24 -0
  210. data/lib/active_admin/inputs/filter_multiple_select_input.rb +18 -0
  211. data/lib/active_admin/inputs/filter_numeric_range_input.rb +31 -0
  212. data/lib/active_admin/resource_controller_fix.rb +23 -0
  213. data/lib/active_admin/views/pages/base_fix.rb +13 -0
  214. data/lib/assets/.gitkeep +0 -0
  215. data/lib/blueprints.rb +79 -0
  216. data/lib/date_expander.rb +38 -0
  217. data/lib/dav4rack/build_resource.rb +59 -0
  218. data/lib/formtastic/inputs/selectable_check_boxes.rb +39 -0
  219. data/lib/paper_trail/version_fix.rb +3 -0
  220. data/lib/report_builder.rb +88 -0
  221. data/lib/seeder.rb +103 -0
  222. data/lib/smartkiosk/server/version.rb +5 -0
  223. data/lib/smartkiosk/server.rb +35 -0
  224. data/lib/string_file.rb +12 -0
  225. data/lib/tasks/.gitkeep +0 -0
  226. data/lib/tasks/db.rake +27 -0
  227. data/lib/tasks/dump.rake +53 -0
  228. data/lib/tasks/matrioshka.rake +16 -0
  229. data/log/.gitkeep +0 -0
  230. data/log/gateways/.gitkeep +0 -0
  231. data/public/404.html +26 -0
  232. data/public/422.html +26 -0
  233. data/public/500.html +25 -0
  234. data/public/robots.txt +5 -0
  235. data/script/rails +6 -0
  236. data/smartkiosk-server.gemspec +23 -0
  237. data/spec/controllers/collections_controller_spec.rb +32 -0
  238. data/spec/controllers/payments_controller_spec.rb +123 -0
  239. data/spec/controllers/system_receipt_templates_controller_spec.rb +5 -0
  240. data/spec/controllers/terminal_builds_controller_spec.rb +5 -0
  241. data/spec/controllers/terminal_orders_controller_spec.rb +32 -0
  242. data/spec/controllers/terminal_pings_controller_spec.rb +31 -0
  243. data/spec/spec_helper.rb +66 -0
  244. data/vendor/assets/javascripts/.gitkeep +0 -0
  245. data/vendor/assets/javascripts/chosen.jquery.js +1026 -0
  246. data/vendor/assets/javascripts/datepicker-ru.jquery.js +21 -0
  247. data/vendor/assets/javascripts/nestedSortable.jquery.js +429 -0
  248. data/vendor/assets/javascripts/qtip.jquery.js +3403 -0
  249. data/vendor/assets/stylesheets/.gitkeep +0 -0
  250. data/vendor/assets/stylesheets/chosen.jquery.css +397 -0
  251. data/vendor/assets/stylesheets/modules/PIE.htc +96 -0
  252. data/vendor/assets/stylesheets/qtip.jquery.css.scss +604 -0
  253. data/vendor/plugins/.gitkeep +0 -0
  254. metadata +333 -0
@@ -0,0 +1,99 @@
1
+ class Gateway < ActiveRecord::Base
2
+
3
+ has_paper_trail
4
+
5
+ #
6
+ # RELATIONS
7
+ #
8
+ has_many :provider_gateways
9
+ has_many :providers, :through => :provider_gateways
10
+ has_many :payments, :order => 'id DESC'
11
+ has_many :gateway_settings
12
+ has_many :gateway_attachments
13
+ has_many :gateway_switches
14
+ has_many :rebates
15
+
16
+ accepts_nested_attributes_for :gateway_settings
17
+ accepts_nested_attributes_for :gateway_attachments
18
+ accepts_nested_attributes_for :gateway_switches
19
+
20
+ scope :enabled, where(:enabled => true)
21
+
22
+ #
23
+ # METHODS
24
+ #
25
+ def librarize(instantiate=true)
26
+ klass = ("Payzilla::Gateways::"+payzilla.camelize).constantize
27
+ return instantiate ? klass.new(self) : klass
28
+ end
29
+
30
+ def available_settings
31
+ librarize(false)::available_settings
32
+ end
33
+
34
+ def available_attachments
35
+ librarize(false)::available_attachments
36
+ end
37
+
38
+ def available_switches
39
+ librarize(false)::available_switches
40
+ end
41
+
42
+ def serialize_options
43
+ options = {}
44
+ sources = {
45
+ "setting" => available_settings,
46
+ "attachment" => available_attachments,
47
+ "switch" => available_switches
48
+ }
49
+
50
+ sources.each do |prefix, source|
51
+ source.each do |element|
52
+ keyword = "#{prefix}_#{element}"
53
+ options[keyword] = send keyword
54
+ end
55
+ end
56
+
57
+ options
58
+ end
59
+
60
+ def respond_to?(key, include_private=false)
61
+ return true if key.to_s.starts_with?('setting_') || key.to_s.starts_with?('attachment_') || key.to_s.starts_with?('switch_')
62
+ super(key, include_private)
63
+ end
64
+
65
+ def method_missing(name, *args, &block)
66
+ assign = name[-1] == '='
67
+ name = name[0, name.length-1] if assign
68
+
69
+ if name.to_s.starts_with?('setting_')
70
+ source = gateway_settings
71
+ klass = GatewaySetting
72
+ name = name.to_s.gsub('setting_', '')
73
+ elsif name.to_s.starts_with?('attachment_')
74
+ source = gateway_attachments
75
+ klass = GatewayAttachment
76
+ name = name.to_s.gsub('attachment_', '')
77
+ elsif name.to_s.starts_with?('switch_')
78
+ source = gateway_switches
79
+ klass = GatewaySwitch
80
+ name = name.to_s.gsub('switch_', '')
81
+ else
82
+ return super
83
+ end
84
+
85
+ if assign
86
+ data = source.select{|x| x.keyword == name}.first
87
+
88
+ if data.blank?
89
+ source << klass.new(:keyword => name, :gateway_id => id, :value => args[0])
90
+ else
91
+ data.value = args[0]
92
+ end
93
+ else
94
+ result = source.select{|x| x.keyword == name}.first.try(:value)
95
+ result = false if result.blank? && klass == GatewaySwitch
96
+ result
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,9 @@
1
+ class GatewayAttachment < ActiveRecord::Base
2
+
3
+ #
4
+ # RELATIONS
5
+ #
6
+ belongs_to :gateway
7
+
8
+ mount_uploader :value, FileUploader
9
+ end
@@ -0,0 +1,7 @@
1
+ class GatewaySetting < ActiveRecord::Base
2
+
3
+ #
4
+ # RELATIONS
5
+ #
6
+ belongs_to :gateway
7
+ end
@@ -0,0 +1,7 @@
1
+ class GatewaySwitch < ActiveRecord::Base
2
+
3
+ #
4
+ # RELATIONS
5
+ #
6
+ belongs_to :gateway
7
+ end
@@ -0,0 +1,77 @@
1
+ class Limit < ActiveRecord::Base
2
+
3
+ has_paper_trail
4
+
5
+ #
6
+ # RELATIONS
7
+ #
8
+ belongs_to :provider_profile
9
+ has_many :providers, :through => :provider_profile
10
+ has_many :limit_sections, :inverse_of => :limit
11
+
12
+ accepts_nested_attributes_for :limit_sections, :allow_destroy => true
13
+
14
+ default_scope includes(:limit_sections)
15
+
16
+ scope :actual, lambda{
17
+ where(arel_table[:start].lteq Date.today).
18
+ where(arel_table[:finish].gteq Date.today)
19
+ }
20
+
21
+ #
22
+ # VALIDATIONS
23
+ #
24
+ validates :provider_profile, :presence => true
25
+ validates :start, :presence => true
26
+ validates :finish, :presence => true
27
+
28
+ validate do
29
+ return if start.blank? || finish.blank?
30
+
31
+ if start > finish
32
+ errors.add(:start, :too_large)
33
+ return
34
+ end
35
+
36
+ # Conditions intersections
37
+ neighbors = self.class.where(:provider_profile_id => provider_profile_id)
38
+ neighbors = neighbors.where("id != ?", id) unless id.blank?
39
+
40
+ # Ranges intersections
41
+ neighbors = neighbors.to_a
42
+
43
+ neighbors.select! do |x|
44
+ x.start.between?(start, finish) ||
45
+ x.finish.between?(start, finish) ||
46
+ start.between?(x.start, x.finish) ||
47
+ finish.between?(x.start, x.finish)
48
+ end
49
+
50
+ if neighbors.count > 0
51
+ errors[:base] << I18n.t('activerecord.errors.models.limit.conditions_intersect')
52
+ end
53
+ end
54
+
55
+ #
56
+ # METHODS
57
+ #
58
+ def self.for(payment, filter_amount=true)
59
+ limit = payment.provider.limits.actual.first
60
+ return [] if limit.blank?
61
+
62
+ rates = limit.limit_sections.
63
+ by_terminal_profile_and_agent_ids(payment.terminal.terminal_profile_id, payment.terminal.agent_id).
64
+ by_payment_type(payment.payment_type)
65
+
66
+ rates.select!{|x|
67
+ x.min <= payment.paid_amount &&
68
+ x.max >= payment.paid_amount
69
+ } if filter_amount
70
+
71
+ rates.sort_by(&:weight).reverse
72
+ end
73
+
74
+ def title
75
+ "##{id}"
76
+ end
77
+ end
@@ -0,0 +1,58 @@
1
+ class LimitSection < ActiveRecord::Base
2
+
3
+ #
4
+ # RELATIONS
5
+ #
6
+ belongs_to :limit, :inverse_of => :limit_sections
7
+ belongs_to :agent
8
+ belongs_to :terminal_profile
9
+
10
+ scope :by_terminal_profile_and_agent_ids, lambda { |p, a|
11
+ conditions = [
12
+ '(terminal_profile_id IS NULL AND agent_id IS NULL)',
13
+ '(agent_id = ? AND terminal_profile_id IS NULL)',
14
+ 'terminal_profile_id = ?'
15
+ ]
16
+ where(
17
+ conditions.join(' OR '),
18
+ a,
19
+ p
20
+ )
21
+ }
22
+ scope :by_payment_type, lambda { |x|
23
+ where("payment_type IS NULL OR payment_type = ?", x)
24
+ }
25
+
26
+ #
27
+ # VALIDATIONS
28
+ #
29
+ validates :min, :presence => true
30
+ validates :max, :presence => true
31
+
32
+ validate do
33
+ return if min.blank? || max.blank?
34
+
35
+ if min > max
36
+ errors.add(:min, :too_large)
37
+ return
38
+ end
39
+
40
+ neighbors = limit.limit_sections.select{|x| x != self}
41
+
42
+ if neighbors.select{|x| x.payment_type.nil? != payment_type.nil?}.count > 0
43
+ errors[:base] << I18n.t('activerecord.errors.models.limit.payment_type_intersects')
44
+ end
45
+
46
+ neighbors.select!{|x| x.agent_id == agent_id && x.terminal_profile_id == terminal_profile_id}
47
+
48
+ if neighbors.count > 0
49
+ errors[:base] << I18n.t('activerecord.errors.models.limit.conditions_intersect')
50
+ end
51
+ end
52
+
53
+ def weight
54
+ return 3 unless terminal_profile_id.blank?
55
+ return 2 unless agent_id.blank?
56
+ return 1
57
+ end
58
+ end
@@ -0,0 +1,322 @@
1
+ class Payment < ActiveRecord::Base
2
+ include DateExpander
3
+ include Stateflow
4
+
5
+ SOURCE_INNER = 0
6
+ SOURCE_MANUAL = 1
7
+ SOURCE_IMPORT = 2
8
+
9
+ TYPE_CASH = 0
10
+ TYPE_INNER_CARD = 1
11
+ TYPE_FOREIGN_CARD = 2
12
+ TYPE_IBANK = 3
13
+ TYPE_MBANK = 4
14
+ TYPE_PURSE = 5
15
+ TYPE_ACCOUNT = 6
16
+
17
+ #
18
+ # STATEFLOW
19
+ #
20
+ stateflow do
21
+ state :new, :checked, :declined, :queue, :paid, :error, :manual
22
+
23
+ event :check do
24
+ transitions :from => :new, :to => [:checked, :declined], :decide => :check?
25
+ end
26
+
27
+ event :enqueue do
28
+ transitions :from => [:error, :checked], :to => :queue
29
+ end
30
+
31
+ event :pay do
32
+ transitions :from => [:checked, :queue], :to => [:paid, :error], :decide => :pay?
33
+ end
34
+
35
+ event :pay_offline do
36
+ transitions :from => :new, :to => [:paid, :error], :decide => :pay_offline?
37
+ end
38
+
39
+ event :pay_manually do
40
+ transitions :from => :error, :to => :manual
41
+ end
42
+
43
+ event :requeue do
44
+ transitions :from => :error, :to => :queue
45
+ end
46
+ end
47
+
48
+ def pay_manually!(user)
49
+ pay_manually
50
+ save!
51
+
52
+ Version.create!(
53
+ :item_type => self.class.to_s,
54
+ :item_id => self.id,
55
+ :event => "payment.paid_manually",
56
+ :whodunnit => user.id
57
+ )
58
+ end
59
+
60
+ def requeue!(user)
61
+ requeue
62
+ save!
63
+
64
+ PayWorker.perform_async(self.id)
65
+ Version.create!(
66
+ :item_type => self.class.to_s,
67
+ :item_id => self.id,
68
+ :event => "payment.requeued",
69
+ :whodunnit => user.id
70
+ )
71
+ end
72
+
73
+ def enqueue!(attributes={})
74
+ [ :paid_amount, :receipt_number, :card_track1, :card_track2 ].each do |key|
75
+ if attributes.include? key
76
+ write_attribute key, attributes[key]
77
+ end
78
+ end
79
+
80
+ enqueue
81
+ save!
82
+ PayWorker.perform_async(id)
83
+ end
84
+
85
+ #
86
+ # RELATIONS
87
+ #
88
+ belongs_to :agent
89
+ belongs_to :terminal
90
+ belongs_to :provider
91
+ belongs_to :gateway
92
+ belongs_to :user
93
+ belongs_to :corrected_payment, :class_name => 'Payment'
94
+ has_one :corrected_by, :foreign_key => 'corrected_payment_id', :class_name => 'Payment'
95
+
96
+ scope :queued, where(:state => 'queue')
97
+ scope :error, where(:state => 'error')
98
+ scope :recent, order('created_at DESC')
99
+
100
+ #
101
+ # VALIDATIONS
102
+ #
103
+ validates :gateway, :presence => true
104
+ validates :provider, :presence => true, :if => lambda{|x| x.source == SOURCE_INNER}
105
+ validates :terminal, :presence => true, :if => lambda{|x| x.source == SOURCE_INNER}
106
+ validates :agent, :presence => true, :if => lambda{|x| x.source == SOURCE_INNER}
107
+ validates :commission_amount, :presence => true, :if => lambda{|x| x.source == SOURCE_MANUAL}
108
+ validates :enrolled_amount, :presence => true, :if => lambda{|x| x.source == SOURCE_MANUAL}
109
+ validates :session_id, :uniqueness => {:scope => :terminal_id}, :unless => lambda{|x| x.terminal.blank?}
110
+ validates :user, :presence => true, :if => lambda{|x| x.source == SOURCE_MANUAL}
111
+ validates :payment_type, :presence => true
112
+
113
+ #
114
+ # MODIFICATIONS
115
+ #
116
+ before_validation do
117
+ self.meta = {} unless self.meta.is_a?(Hash)
118
+ self.agent = self.terminal.agent unless self.terminal.blank?
119
+ end
120
+
121
+ before_save do
122
+ if !self.paid_amount.nil? && (self.enrolled_amount.nil? || self.commission_amount.nil?)
123
+ self.commission_amount = Commission.for(self).first.try(:fee, paid_amount) || 0
124
+ self.enrolled_amount = self.paid_amount - self.commission_amount
125
+ end
126
+
127
+ if self.paid_amount.nil? && !self.enrolled_amount.nil? && !self.commission_amount.nil?
128
+ self.paid_amount = self.enrolled_amount + self.commission_amount
129
+ end
130
+
131
+ if !self.paid_amount.nil? && !self.commission_amount.nil? && self.rebate_amount.nil?
132
+ rebate = Rebate.for(self)
133
+ self.rebate_amount = rebate.try(:fee, paid_amount) || 0
134
+ end
135
+ end
136
+
137
+ after_create do
138
+ if source == SOURCE_MANUAL
139
+ Version.create!(
140
+ :item_type => self.class.to_s,
141
+ :item_id => self.id,
142
+ :event => "create",
143
+ :whodunnit => user.id
144
+ )
145
+ end
146
+ end
147
+
148
+ serialize :fields
149
+ serialize :raw_fields
150
+ serialize :meta
151
+
152
+ #
153
+ # METHODS
154
+ #
155
+ def self.acquirer(payment_type)
156
+ unless @acquiring_settings
157
+ @acquiring_settings = YAML::load File.read(Rails.root.join 'config/acquiring.yml')
158
+ @acquiring_settings.each do |x|
159
+ x['type'] = x['type'].split(',').map do |t|
160
+ Payment.const_get "TYPE_#{t.strip.upcase}"
161
+ end
162
+ x['class'] = x['class'].constantize
163
+ end
164
+ end
165
+
166
+ acquirer = @acquiring_settings.find{|x| x['type'].include?(payment_type)}
167
+ raise "unsupported payment type: #{payment_type}" unless acquirer
168
+
169
+ acquirer['class'].new(acquirer)
170
+ end
171
+
172
+ def self.plogger
173
+ return @plogger if @plogger
174
+
175
+ @plogger ||= Logger.new(Rails.root.join('log/payments.log'), 10, 1024000)
176
+
177
+ separator = ' | '
178
+
179
+ @plogger.formatter = proc { |severity, datetime, data, message|
180
+ data ||= {}
181
+
182
+ header = "~~ " + [
183
+ severity,
184
+ datetime.iso8601(12),
185
+ data[:progname],
186
+ data[:payment_id],
187
+ data[:payment_state],
188
+ data[:session_id],
189
+ data[:terminal_id],
190
+ data[:gateway_id],
191
+ message
192
+ ].join(separator) + "\n"
193
+ }
194
+
195
+ @plogger
196
+ end
197
+
198
+ def self.plog(severity, progname, message, data={})
199
+ data[:progname] = progname
200
+
201
+ unless block_given?
202
+ plogger.send(severity, data){ message }
203
+ else
204
+ begin
205
+ yield
206
+ rescue Exception => e
207
+ plogger.error(data){ e }
208
+ raise e
209
+ else
210
+ plogger.send(severity, data){ message }
211
+ end
212
+ end
213
+ end
214
+
215
+ def plog(severity, progname, message, &block)
216
+ data = {
217
+ :payment_id => self.id,
218
+ :payment_state => self.state,
219
+ :session_id => self.session_id,
220
+ :terminal_id => self.terminal_id,
221
+ :gateway_id => self.gateway_id
222
+ }
223
+
224
+ self.class.plog(severity, progname, message, data, &block)
225
+ end
226
+
227
+ def manual?
228
+ source == SOURCE_MANUAL
229
+ end
230
+
231
+ def complete?
232
+ %w(paid manual).include? state
233
+ end
234
+
235
+ def cash?
236
+ payment_type == TYPE_CASH
237
+ end
238
+
239
+ def cashless?
240
+ !cash?
241
+ end
242
+
243
+ def self.build!(terminal, provider, attributes)
244
+ payment = new(attributes)
245
+ provider_gateway = provider.provider_gateways.enabled.order(:priority).first
246
+
247
+ return false if provider_gateway.blank?
248
+
249
+ payment.terminal = terminal
250
+ payment.provider_gateway = provider_gateway
251
+ payment.raw_fields = payment.fields
252
+ payment.fields = provider_gateway.map(payment.account, payment.fields)
253
+
254
+ payment.save!
255
+ payment
256
+ end
257
+
258
+ def provider_gateway=(pg)
259
+ self.gateway = pg.gateway
260
+ self.provider = pg.provider
261
+ self.gateway_provider_id = pg.gateway_provider_id
262
+ end
263
+
264
+ def title
265
+ "##{id}: #{provider.try(:title)} (#{account || '--'})"
266
+ end
267
+
268
+ def human_fields=(value)
269
+ self.fields = value.gsub("\r", '').split("\n").map{|x| x.split('=')}
270
+ self.fields = Hash[*self.fields.select{|x| x.length > 1}.flatten]
271
+ end
272
+
273
+ def human_fields
274
+ return '' if self.fields.blank?
275
+ self.fields.collect{|k,v| "#{k}=#{v}"}.join("\n")
276
+ end
277
+
278
+ def check?
279
+ result = self.gateway.librarize.check(self)
280
+
281
+ if result[:success]
282
+ self.gateway_error = nil
283
+ self.gateway_payment_id = result[:gateway_payment_id] unless result[:gateway_payment_id].blank?
284
+ self.save!
285
+ return :checked
286
+ else
287
+ self.update_attribute(:gateway_error, result[:error])
288
+ return :declined
289
+ end
290
+ end
291
+
292
+ def pay?
293
+ acquirer = Payment.acquirer(self.payment_type)
294
+ authorization = acquirer.authorize(self)
295
+
296
+ if authorization.success?
297
+ result = self.gateway.librarize.pay(self)
298
+
299
+ if result[:success]
300
+ self.gateway_error = nil
301
+ self.gateway_payment_id = result[:gateway_payment_id] unless result[:gateway_payment_id].blank?
302
+ self.paid_at = DateTime.now
303
+ self.meta[:gateway] = self.gateway.serialize_options
304
+
305
+ self.save!
306
+ authorization.confirm
307
+ return :paid
308
+ else
309
+ self.update_attribute(:gateway_error, result[:error])
310
+ authorization.reverse
311
+ return :error
312
+ end
313
+ else
314
+ self.update_attribute(:gateway_error, authorization.error)
315
+ return :error
316
+ end
317
+ end
318
+
319
+ def approved?
320
+ !['new', 'declined'].include?(state)
321
+ end
322
+ end
@@ -0,0 +1,59 @@
1
+ class Provider < ActiveRecord::Base
2
+ include Redis::Objects::RMap
3
+
4
+ value :timestamp, :global => true, :marshal => true
5
+
6
+ has_rmap({:id => lambda{|x| x.to_s}}, :title)
7
+ has_paper_trail
8
+
9
+ mount_uploader :icon, IconUploader
10
+
11
+ after_save do
12
+ self.class.timestamp = updated_at
13
+ end
14
+
15
+ after_destroy do
16
+ self.class.timestamp = DateTime.now
17
+ end
18
+
19
+ #
20
+ # RELATIONS
21
+ #
22
+ belongs_to :provider_profile
23
+ belongs_to :provider_group
24
+ belongs_to :provider_receipt_template
25
+ has_many :provider_gateways
26
+ has_many :gateways, :through => :provider_gateways
27
+ has_many :payments, :order => 'id DESC'
28
+ has_many :commissions, :through => :provider_profile
29
+ has_many :limits, :through => :provider_profile
30
+ has_many :provider_fields, :dependent => :destroy, :order => :priority
31
+ has_many :terminal_profile_providers, :dependent => :destroy, :order => :priority
32
+ has_many :terminal_profile_promotions, :dependent => :destroy, :order => :priority
33
+
34
+ accepts_nested_attributes_for :provider_gateways, :allow_destroy => true
35
+ accepts_nested_attributes_for :provider_fields, :allow_destroy => true
36
+
37
+ scope :gateway_ids_eq, lambda{|x| includes(:gateways).where(:gateways => {:id => x})}
38
+ search_method :gateway_ids_eq
39
+
40
+ scope :after, lambda{|x|
41
+ x.blank? ? scoped
42
+ : where(arel_table[:updated_at].gt x)
43
+ }
44
+
45
+ #
46
+ # VALIDATIONS
47
+ #
48
+ validates :provider_profile, :presence => true
49
+ validates :provider_group, :presence => true
50
+ validates :keyword, :presence => true
51
+ validates :keyword, :uniqueness => true
52
+
53
+ #
54
+ # METHODS
55
+ #
56
+ def fields_dump
57
+ provider_fields.as_json(:only => [:keyword, :title, :kind, :mask, :values, :priority])
58
+ end
59
+ end
@@ -0,0 +1,7 @@
1
+ class ProviderField < ActiveRecord::Base
2
+ belongs_to :provider
3
+
4
+ validates :title, :presence => true
5
+ validates :kind, :presence => true
6
+ validates :values, :presence => true, :if => lambda{|x| x.kind == 'select'}
7
+ end
@@ -0,0 +1,47 @@
1
+ class ProviderGateway < ActiveRecord::Base
2
+ #
3
+ # RELATIONS
4
+ #
5
+ belongs_to :provider, :counter_cache => true
6
+ belongs_to :gateway
7
+
8
+ scope :enabled, includes(:gateway).where(:gateways => {:enabled => true})
9
+
10
+ #
11
+ # MODIFICATIONS
12
+ #
13
+ serialize :fields_mapping
14
+
15
+ #
16
+ # METHODS
17
+ #
18
+ def human_fields_mapping=(value)
19
+ self.fields_mapping = value.gsub("\r", '').split("\n").map{|x| x.split('=')}
20
+ self.fields_mapping = Hash[*self.fields_mapping.select{|x| x.length > 1}.flatten]
21
+ end
22
+
23
+ def human_fields_mapping
24
+ return '' if self.fields_mapping.blank?
25
+ self.fields_mapping.collect{|k,v| "#{k}=#{v}"}.join("\n")
26
+ end
27
+
28
+ def map(account, raw_fields)
29
+ fields = {}
30
+
31
+ if !account.blank? && !account_mapping.blank?
32
+ fields[account_mapping] = account
33
+ end
34
+
35
+ unless raw_fields.blank?
36
+ unless fields_mapping.blank?
37
+ fields_mapping.each do |k, v|
38
+ fields[v] = raw_fields[k] unless raw_fields[k].blank?
39
+ end
40
+ else
41
+ fields.merge!(raw_fields)
42
+ end
43
+ end
44
+
45
+ fields
46
+ end
47
+ end