smartkiosk-server 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/.rspec +1 -0
- data/Capfile +4 -0
- data/Gemfile +71 -0
- data/Gemfile.lock +439 -0
- data/Guardfile +25 -0
- data/LICENSE +287 -0
- data/README.md +13 -0
- data/Rakefile +5 -0
- data/app/acquirers/cards_mkb_acquirer.rb +87 -0
- data/app/acquirers/cash_acquirer.rb +22 -0
- data/app/admin/agents.rb +108 -0
- data/app/admin/collections.rb +62 -0
- data/app/admin/commissions.rb +87 -0
- data/app/admin/gateways.rb +183 -0
- data/app/admin/limits.rb +82 -0
- data/app/admin/payments.rb +246 -0
- data/app/admin/provider_groups.rb +60 -0
- data/app/admin/provider_profiles.rb +11 -0
- data/app/admin/provider_receipt_templates.rb +82 -0
- data/app/admin/providers.rb +201 -0
- data/app/admin/rebates.rb +83 -0
- data/app/admin/report_results.rb +66 -0
- data/app/admin/report_templates.rb +209 -0
- data/app/admin/reports.rb +158 -0
- data/app/admin/revisions.rb +120 -0
- data/app/admin/system_receipt_templates.rb +76 -0
- data/app/admin/terminal_builds.rb +39 -0
- data/app/admin/terminal_profiles.rb +123 -0
- data/app/admin/terminals.rb +388 -0
- data/app/admin/users.rb +117 -0
- data/app/admin/versions.rb +131 -0
- data/app/admin/welcome.rb +64 -0
- data/app/assets/fonts/PT_Sans-Web-Bold.eot +0 -0
- data/app/assets/fonts/PT_Sans-Web-Bold.svg +6386 -0
- data/app/assets/fonts/PT_Sans-Web-Bold.ttf +0 -0
- data/app/assets/fonts/PT_Sans-Web-Bold.woff +0 -0
- data/app/assets/fonts/PT_Sans-Web-Regular.eot +0 -0
- data/app/assets/fonts/PT_Sans-Web-Regular.svg +5650 -0
- data/app/assets/fonts/PT_Sans-Web-Regular.ttf +0 -0
- data/app/assets/fonts/PT_Sans-Web-Regular.woff +0 -0
- data/app/assets/images/chosen-sprite.png +0 -0
- data/app/assets/javascripts/active_admin/chosen.js.erb.coffee +12 -0
- data/app/assets/javascripts/active_admin/qtip.js.coffee +22 -0
- data/app/assets/javascripts/active_admin/sortable_forms.js.coffee +14 -0
- data/app/assets/javascripts/active_admin.js.coffee +9 -0
- data/app/assets/javascripts/application.js +15 -0
- data/app/assets/javascripts/report_templates.js.coffee +10 -0
- data/app/assets/javascripts/terminals.js.coffee +12 -0
- data/app/assets/stylesheets/active_admin/PIE.css.scss +18 -0
- data/app/assets/stylesheets/active_admin/filter_numeric_range.css.scss +14 -0
- data/app/assets/stylesheets/active_admin/selectable_check_boxes.css.scss +12 -0
- data/app/assets/stylesheets/active_admin/sortable_forms.css.scss +11 -0
- data/app/assets/stylesheets/active_admin.css.scss +705 -0
- data/app/assets/stylesheets/fonts.css.scss +14 -0
- data/app/assets/stylesheets/provider_groups.css.scss +12 -0
- data/app/assets/stylesheets/provider_receipt_templates.css.scss +12 -0
- data/app/assets/stylesheets/terminals.css.scss +9 -0
- data/app/controllers/application_controller.rb +12 -0
- data/app/controllers/collections_controller.rb +10 -0
- data/app/controllers/payments_controller.rb +73 -0
- data/app/controllers/system_receipt_templates_controller.rb +10 -0
- data/app/controllers/terminal_builds_controller.rb +5 -0
- data/app/controllers/terminal_orders_controller.rb +25 -0
- data/app/controllers/terminal_pings_controller.rb +45 -0
- data/app/controllers/welcome_controller.rb +5 -0
- data/app/helpers/active_admin/report_templates_helper.rb +56 -0
- data/app/helpers/active_admin/views_helper.rb +20 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/mailers/.gitkeep +0 -0
- data/app/models/.gitkeep +0 -0
- data/app/models/ability.rb +30 -0
- data/app/models/agent.rb +24 -0
- data/app/models/collection.rb +65 -0
- data/app/models/commission.rb +77 -0
- data/app/models/commission_section.rb +75 -0
- data/app/models/gateway.rb +99 -0
- data/app/models/gateway_attachment.rb +9 -0
- data/app/models/gateway_setting.rb +7 -0
- data/app/models/gateway_switch.rb +7 -0
- data/app/models/limit.rb +77 -0
- data/app/models/limit_section.rb +58 -0
- data/app/models/payment.rb +322 -0
- data/app/models/provider.rb +59 -0
- data/app/models/provider_field.rb +7 -0
- data/app/models/provider_gateway.rb +47 -0
- data/app/models/provider_group.rb +45 -0
- data/app/models/provider_profile.rb +9 -0
- data/app/models/provider_rebate.rb +69 -0
- data/app/models/provider_receipt_template.rb +85 -0
- data/app/models/rebate.rb +84 -0
- data/app/models/report.rb +71 -0
- data/app/models/report_result.rb +11 -0
- data/app/models/report_template.rb +56 -0
- data/app/models/revision.rb +104 -0
- data/app/models/role.rb +48 -0
- data/app/models/system_receipt_template.rb +13 -0
- data/app/models/terminal.rb +126 -0
- data/app/models/terminal_build.rb +62 -0
- data/app/models/terminal_order.rb +42 -0
- data/app/models/terminal_ping.rb +120 -0
- data/app/models/terminal_profile.rb +51 -0
- data/app/models/terminal_profile_promotion.rb +18 -0
- data/app/models/terminal_profile_provider.rb +11 -0
- data/app/models/terminal_profile_provider_group.rb +19 -0
- data/app/models/user.rb +38 -0
- data/app/models/user_role.rb +45 -0
- data/app/reports/agents_report.rb +81 -0
- data/app/reports/collections_report.rb +151 -0
- data/app/reports/payments_report.rb +189 -0
- data/app/reports/terminals_report.rb +123 -0
- data/app/uploaders/file_uploader.rb +53 -0
- data/app/uploaders/icon_uploader.rb +15 -0
- data/app/uploaders/zip_uploader.rb +53 -0
- data/app/views/admin/gateways/providers.html.arb +10 -0
- data/app/views/admin/revisions/payments.html.arb +28 -0
- data/app/views/admin/terminal_profiles/_tree.html.haml +35 -0
- data/app/views/admin/terminal_profiles/sort.html.haml +21 -0
- data/app/views/admin/terminals/pings.html.arb +55 -0
- data/app/views/admin/terminals/upgrade_build.html.arb +30 -0
- data/app/views/layouts/application.html.erb +1 -0
- data/app/views/welcome/index.html.erb +25 -0
- data/app/workers/pay_worker.rb +11 -0
- data/app/workers/report_worker.rb +7 -0
- data/app/workers/revise_worker.rb +7 -0
- data/config/acquiring.yml +13 -0
- data/config/application.rb +75 -0
- data/config/boot.rb +6 -0
- data/config/database.yml +17 -0
- data/config/deploy/roundlake-passenger.rb +3 -0
- data/config/deploy/roundlake-trinidad.rb +3 -0
- data/config/deploy.rb +37 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +39 -0
- data/config/environments/production.rb +67 -0
- data/config/environments/test.rb +37 -0
- data/config/initializers/active_admin.rb +31 -0
- data/config/initializers/backtrace_silencers.rb +7 -0
- data/config/initializers/devise.rb +232 -0
- data/config/initializers/inflections.rb +15 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/money.rb +6 -0
- data/config/initializers/redis.rb +4 -0
- data/config/initializers/secret_token.rb +7 -0
- data/config/initializers/session_store.rb +8 -0
- data/config/initializers/setup_rack.rb +1 -0
- data/config/initializers/wrap_parameters.rb +14 -0
- data/config/locales/active_admin.ru.yml +71 -0
- data/config/locales/activerecord.ru.yml +645 -0
- data/config/locales/devise.ru.yml +57 -0
- data/config/locales/ru.yml +33 -0
- data/config/locales/smartkiosk.gateways.ru.yml +241 -0
- data/config/locales/smartkiosk.hardware.ru.yml +38 -0
- data/config/locales/smartkiosk.reports.ru.yml +56 -0
- data/config/locales/smartkiosk.ru.yml +163 -0
- data/config/nginx.conf +9 -0
- data/config/redis.yml +9 -0
- data/config/routes.rb +48 -0
- data/config/schedule.rb +13 -0
- data/config/sidekiq.yml +5 -0
- data/config/trinidad.yml +6 -0
- data/config.ru +4 -0
- data/db/migrate/20120825083035_create_terminals.rb +47 -0
- data/db/migrate/20120825083305_create_payments.rb +51 -0
- data/db/migrate/20120827062618_devise_create_users.rb +50 -0
- data/db/migrate/20120827132621_create_admin_notes.rb +17 -0
- data/db/migrate/20120827132622_move_admin_notes_to_comments.rb +25 -0
- data/db/migrate/20120903193346_create_providers.rb +24 -0
- data/db/migrate/20120922075345_create_collections.rb +26 -0
- data/db/migrate/20120922080440_create_agents.rb +29 -0
- data/db/migrate/20120922081104_create_commissions.rb +10 -0
- data/db/migrate/20120927035841_create_gateways.rb +13 -0
- data/db/migrate/20120927040626_create_provider_gateways.rb +13 -0
- data/db/migrate/20120927091849_create_limits.rb +10 -0
- data/db/migrate/20120927164647_create_roles.rb +14 -0
- data/db/migrate/20121003131522_create_report_templates.rb +18 -0
- data/db/migrate/20121007135652_create_reports.rb +13 -0
- data/db/migrate/20121008073905_create_report_results.rb +10 -0
- data/db/migrate/20121017114538_create_gateway_settings.rb +12 -0
- data/db/migrate/20121017114556_create_gateway_attachments.rb +10 -0
- data/db/migrate/20121019132606_create_revisions.rb +19 -0
- data/db/migrate/20121023073501_create_gateway_switches.rb +10 -0
- data/db/migrate/20121112142743_create_terminal_orders.rb +13 -0
- data/db/migrate/20121118191553_create_versions.rb +19 -0
- data/db/migrate/20121125093414_create_system_receipt_templates.rb +9 -0
- data/db/migrate/20121127192257_create_terminal_builds.rb +10 -0
- data/db/migrate/20121212053441_create_rebates.rb +15 -0
- data/db/migrate/20121216143855_create_provider_receipt_templates.rb +9 -0
- data/db/migrate/20130101091100_create_terminal_profiles.rb +13 -0
- data/db/migrate/20130101091734_create_provider_rebates.rb +21 -0
- data/db/migrate/20130102164447_create_limit_sections.rb +14 -0
- data/db/migrate/20130102164503_create_commission_sections.rb +17 -0
- data/db/migrate/20130102171743_create_provider_profiles.rb +10 -0
- data/db/migrate/20130103152507_create_provider_fields.rb +17 -0
- data/db/migrate/20130103154526_create_provider_groups.rb +10 -0
- data/db/migrate/20130104063628_create_terminal_profile_providers.rb +11 -0
- data/db/migrate/20130104090957_create_terminal_profile_provider_groups.rb +11 -0
- data/db/migrate/20130108091644_create_terminal_profile_promotions.rb +10 -0
- data/db/schema.rb +489 -0
- data/db/seeds/receipt_templates/payment.txt +19 -0
- data/db/seeds/receipt_templates/system/balance.txt +13 -0
- data/db/seeds/receipt_templates/system/collection.txt +17 -0
- data/db/seeds/receipt_templates/system/touchtest.txt +15 -0
- data/db/seeds.rb +18 -0
- data/doc/README_FOR_APP +2 -0
- data/init.rb +1 -0
- data/lib/active_admin/cancan_integration.rb +81 -0
- data/lib/active_admin/form_builder_fix.rb +76 -0
- data/lib/active_admin/inputs/filter_date_range_input_fix.rb +24 -0
- data/lib/active_admin/inputs/filter_multiple_select_input.rb +18 -0
- data/lib/active_admin/inputs/filter_numeric_range_input.rb +31 -0
- data/lib/active_admin/resource_controller_fix.rb +23 -0
- data/lib/active_admin/views/pages/base_fix.rb +13 -0
- data/lib/assets/.gitkeep +0 -0
- data/lib/blueprints.rb +79 -0
- data/lib/date_expander.rb +38 -0
- data/lib/dav4rack/build_resource.rb +59 -0
- data/lib/formtastic/inputs/selectable_check_boxes.rb +39 -0
- data/lib/paper_trail/version_fix.rb +3 -0
- data/lib/report_builder.rb +88 -0
- data/lib/seeder.rb +103 -0
- data/lib/smartkiosk/server/version.rb +5 -0
- data/lib/smartkiosk/server.rb +35 -0
- data/lib/string_file.rb +12 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/db.rake +27 -0
- data/lib/tasks/dump.rake +53 -0
- data/lib/tasks/matrioshka.rake +16 -0
- data/log/.gitkeep +0 -0
- data/log/gateways/.gitkeep +0 -0
- data/public/404.html +26 -0
- data/public/422.html +26 -0
- data/public/500.html +25 -0
- data/public/robots.txt +5 -0
- data/script/rails +6 -0
- data/smartkiosk-server.gemspec +23 -0
- data/spec/controllers/collections_controller_spec.rb +32 -0
- data/spec/controllers/payments_controller_spec.rb +123 -0
- data/spec/controllers/system_receipt_templates_controller_spec.rb +5 -0
- data/spec/controllers/terminal_builds_controller_spec.rb +5 -0
- data/spec/controllers/terminal_orders_controller_spec.rb +32 -0
- data/spec/controllers/terminal_pings_controller_spec.rb +31 -0
- data/spec/spec_helper.rb +66 -0
- data/vendor/assets/javascripts/.gitkeep +0 -0
- data/vendor/assets/javascripts/chosen.jquery.js +1026 -0
- data/vendor/assets/javascripts/datepicker-ru.jquery.js +21 -0
- data/vendor/assets/javascripts/nestedSortable.jquery.js +429 -0
- data/vendor/assets/javascripts/qtip.jquery.js +3403 -0
- data/vendor/assets/stylesheets/.gitkeep +0 -0
- data/vendor/assets/stylesheets/chosen.jquery.css +397 -0
- data/vendor/assets/stylesheets/modules/PIE.htc +96 -0
- data/vendor/assets/stylesheets/qtip.jquery.css.scss +604 -0
- data/vendor/plugins/.gitkeep +0 -0
- 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
|
data/app/models/limit.rb
ADDED
@@ -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,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
|