Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 315 lines (278 sloc) 10.09 kb
#! /usr/bin/env ruby
# encoding: utf-8
# create passwords file named passwords-santander.rb in the same directory with:
# {:dni=>"mydni", :numeric_password=>"4 digit pwd",
# :password=>"your password",
# :transfer_card=>["51", "25", "11", "60".......]}
# encrypt the file with gpg -c --cipher-algo BLOWFISH passwords-santander.rb
# delete the original file
require 'watir-webdriver'
require 'headless'
def login(b, dni, numeric_password, password)
b.goto 'https://www.personas.santanderrio.com.ar'
b.text_field(:name => "dni").set dni
b.text_field(:name => "clave").set numeric_password
b.text_field(:name => "usuario").set password
b.input(:type => "image").click
end
def login_company(b, cuit, numeric_password)
b.goto 'https://www.emp.santanderrio.com.ar/nb/'
b.text_field(:name => "cuit").set cuit
b.text_field(:name => "password").set numeric_password
b.input(:type => "button").click
end
def load_user_data(path)
puts "Ingrese la clave para desbloquear el archivo de secretos"
data = `gpg -d #{path} 2> /dev/null`
eval(data)
end
def find_menu(b, name)
b.frame(:name => "frame1").link(:text => name)
end
def find_company_menu(b, name)
b.frame(:name => "frameMenu").link(:text => name)
end
def find_company_submenu(b, name)
company_submenu_frame(b).link(:text => name)
end
def company_submenu_frame(b)
b.frame(:name => "frame2").frame(:name => "frameOperaciones")
end
def find_company_submenu_by_index(b, index)
company_submenu_frame(b).link(:index => index)
end
def within_company_main_frame(b, &block)
yield b.frame(:name => "frame2").frame(:name => "frameTrabajo")
end
def make_browser(download_directory, headless = false)
if headless && !@headless_instance
@headless_instance = Headless.new
@headless_instance.start
end
Dir.mkdir download_directory rescue nil
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.folderList'] = 2 # custom location
profile['browser.download.dir'] = download_directory
profile['browser.helperApps.neverAsk.saveToDisk'] = "text/csv,application/pdf,application/vnd.ms-excel,application/msexcel,application/x-msexcel,application/x-ms-excel,application/vnd.ms-excel,application/x-excel,application/x-dos_ms_excel,application/xls"
Watir::Browser.new :firefox, :profile => profile
end
def main_frame(b)
b.frame(:name => 'frame2')
end
def submenu(b)
main_frame(b).frame(:name => "rowOperaciones")
end
def productos(b)
main_frame(b).frame(:name => "rowProductos")
end
def wait_and_click(b, link)
b.wait_until {|w| link.exists?}
link.click
end
def within_operation_area(b, &block)
yield(main_frame(b).frame(:name => 'rowWorkingArea'))
end
def show_message(title, msg)
system(%Q[zenity --info --title="#{title}" --text="#{msg}"])
end
def confirmation(title, msg)
system(%Q[zenity --question --title="#{title}" --text="#{msg}"])
$? == 0
end
def get_coord(c, coords_array)
col = c.downcase[0].ord - "a".ord
row = c[1].ord - "1".ord
coords_array[col + 9*row]
end
def transfer(b, to_account, user_data)
wait_and_click(b, find_menu(b, "PAGOS Y TRANSFERENCIAS"))
wait_and_click(b, submenu(b).link(:text => "Transferencias"))
within_operation_area(b) do |w|
if to_account
combo = w.select(:name => "selCtaDest")
accounts = combo.options.map(&:text)
reg = Regexp.new(".*#{to_account.downcase}.*")
if match = accounts.find {|acc| reg.match(acc.downcase)}
combo.select match
end
w.div(:class => "btnPanelCuentas").a.click
end
show_message "Transferencia", "Ingrese los datos de la transferencia en el browser y luego aprete OK aquí"
w.input(:value => "CONTINUAR").click
if w.th(:class => "aviso").exists? #show schedule warning?
w.input(:name => "Continuar").click
end
coords = w.form(:id => "fBotones").td(:align => "center").text
coords = coords.split
coords = coords.map {|c| get_coord(c, user_data[:coord_card])}
w.text_field(:name => "incoord1").set(coords[0])
w.text_field(:name => "incoord2").set(coords[1])
if confirmation("Transferencia", "Seguro que desea realizar esta transferencia?")
w.input(:value => "CONTINUAR").click
end
end
end
def operations(b, downloads_path)
wait_and_click(b, find_menu(b, "CUENTAS"))
wait_and_click(b, submenu(b).link(:text => "Últimos movimientos"))
within_operation_area(b) do |w|
w.select(:name => "cantDias").select("Últimos 60 días")
w.input(:value => "Generar archivo excel").click
end
puts "Movimientos de cuenta salvado en #{downloads_path}"
wait_and_click(b, find_menu(b, "TARJETAS"))
for prod in ["prod0", "prod1"]
wait_and_click(b, productos(b).span(:id => prod).link)
wait_and_click(b, submenu(b).link(:text => "Último Resumen"))
within_operation_area(b) do |w|
b.wait_until {|_| w.div(:id => "template_data_div").exists?}
File.open(File.join(downloads_path, "resumen-#{prod}.txt"), "w") do |f|
f.write w.div(:id => "template_data_div").text
puts "Resumen de #{prod} salvado en #{f.path}"
end
end
wait_and_click(b, submenu(b).link(:text => "Últimos Consumos"))
within_operation_area(b) do |w|
b.wait_until {|_| w.div(:id => "template_data_div").exists?}
File.open(File.join(downloads_path, "ultimos-movimientos-#{prod}.txt"), "w") do |f|
f.write w.div(:id => "template_data_div").text
puts "Últimos movimientos de #{prod} salvado en #{f.path}"
end
end
end
end
def balance(b)
b.wait_until {|_| main_frame(b).th(:text => "Cuenta").exists?}
accounts_table = main_frame(b).th(:text, "Cuenta").parent.parent.parent
accounts_table.tbody.strings.each do |row|
puts "#{row[0]}\t#{row[1]}"
end
end
def statements(b)
wait_and_click(b, find_menu(b, "CUENTAS"))
wait_and_click(b, submenu(b).link(:text => "Resumen de cuenta online"))
within_operation_area(b) do |w|
combo = w.select(:name => "resumenes")
dates = combo.options.map(&:text)
dates.shift #drop prompt
for res in dates
puts "Bajando resumen #{res}"
combo.select(res)
w.input(:value => "verresumen").click
end
end
end
def close_company_popups_and_keep_main(b)
puts "Intentando cerrar popups..."
# close initial window, main window is a popup
b.window(:index => 0).close rescue puts("No pude cerrar la ventana inicial")
# close 'Opere seguro' popup
begin
w = b.window(:title => "Opere seguro")
w.wait_until_present(10)
w.close
rescue
puts "No pude cerrar el popup 'Opere seguro'"
end
puts "Popups cerrados"
end
def company_operations_between_dates(b, from, to)
wait_and_click(b, find_company_menu(b, "Cuentas"))
wait_and_click(b, find_company_submenu(b, "Extracto y Movimientos del día"))
within_company_main_frame(b) do |f|
f.input(:value => "Búsqueda Avanzada").click
f.input(:name, "fechaDde").wait_until_present
format = "%d/%m/%Y"
f.text_field(:name, "fechaDde").set(from.strftime(format))
f.text_field(:name, "fechaHta").set(to.strftime(format))
f.input(:type => "radio", :name => "formato", :index => 1).click
f.input(:type => "button", :value => "Buscar").click
f.b(:text => "La descarga a archivo ha finalizado").wait_until_present
puts "El archivo ha sido descargado"
end
end
def company_operations_last_month(b)
today = Date.today
date_start = (today << 1) - today.day + 1
date_end = today - today.day
company_operations_between_dates(b, date_start, date_end)
end
def company_operations_this_month(b)
company_operations_between_dates(b, Date.today - Date.today.day + 1, Date.today - 1)
end
def company_balance(b)
wait_and_click(b, find_company_menu(b, "Cuentas"))
balance_detail_link = find_company_submenu_by_index(b, 1)
wait_and_click(b, balance_detail_link)
within_company_main_frame(b) do |f|
f.table(:id => "mainTablaResumen").strings.each do |row|
puts "#{row[0]}\t#{row[1]}"
end
end
end
def usage
puts "santander op [args]"
puts "op = login | transfer | operations | balance | statements | login_company | company_operations_last_month | company_operations_this_month | company_balance"
puts "args ="
puts " for transfer: account-name (optional)"
exit 1
end
COMPANY_SECRETS_PATH = File.join(File.dirname(__FILE__), "passwords-santander-company.rb.gpg")
SECRETS_PATH = File.join(File.dirname(__FILE__), "passwords-santander.rb.gpg")
DOWNLOADS_PATH = "/tmp/santander-downloads"
def start_browser_and_login(type, headless)
if type == :person
user_data = load_user_data(SECRETS_PATH)
b = make_browser DOWNLOADS_PATH, headless
login(b, user_data[:dni], user_data[:numeric_password], user_data[:password])
else
user_data = load_user_data(COMPANY_SECRETS_PATH)
b = make_browser DOWNLOADS_PATH, headless
login_company(b, user_data[:cuit], user_data[:numeric_password])
close_company_popups_and_keep_main b unless headless
end
b
end
def with_logged_in_browser(type = :person, close=true, headless = false)
b = start_browser_and_login type, headless
yield b
ensure
b.close rescue nil if close
@headless_instance.destroy rescue nil if @headless_instance
end
case ARGV[0]
when "login" then
with_logged_in_browser(:person, false) {|_|}
when "transfer" then
with_logged_in_browser do |b|
transfer b, ARGV[1], user_data
end
when "operations" then
with_logged_in_browser do |b|
operations b, DOWNLOADS_PATH
end
when "statements" then
with_logged_in_browser do |b|
statements b
end
when "balance" then
with_logged_in_browser do |b|
balance b
end
when "login_company" then
with_logged_in_browser(:company, false) {}
when "company_operations_last_month" then
with_logged_in_browser(:company, true, true) do |b|
company_operations_last_month b
end
when "company_operations_this_month" then
with_logged_in_browser(:company, true, true) do |b|
company_operations_this_month b
end
when "company_balance" then
with_logged_in_browser(:company, true, true) do |b|
company_balance b
end
else
usage
end
Jump to Line
Something went wrong with that request. Please try again.