Permalink
Browse files

Make all specs pass, fix the csv scrubber

  • Loading branch information...
1 parent 2f40cfe commit 6c36281f03afc197a530b63004286bff1887b215 @manveru manveru committed Feb 25, 2012
View
1 .gems
@@ -11,6 +11,7 @@ name_parse -v0.0.5
nokogiri -v1.5.0
pg -v0.12.2
rack -v1.4.1
+rack-test -v0.6.1
rake -v0.9.2.2
ramaze -v2011.12.28
sequel -v3.31.0
View
24 app.rb
@@ -2,19 +2,15 @@
require 'ramaze'
require_relative 'options'
+require_relative 'model/init'
require_relative 'lib/tiny_dialer'
-
-module TinyDialer
- require MODEL_ROOT/:init
- require LIBROOT/:tiny_dialer/:csv_scrub
- require LIBROOT/:tiny_dialer/:zip_scrub
- require LIBROOT/:tiny_dialer/:state_scrub
- require LIBROOT/:tiny_dialer/:dialer
- require LIBROOT/:tiny_dialer/:hopper
- require LIBROOT/:tiny_dialer/:phone_number
- require LIBROOT/:tiny_dialer/:tcc_helper if TinyDialer.options.direct_listener.tcc_root
-end
-
+require_relative 'lib/tiny_dialer/lead_scrub'
+require_relative 'lib/tiny_dialer/state_scrub'
+require_relative 'lib/tiny_dialer/zip_scrub'
+require_relative 'lib/tiny_dialer/dialer'
+require_relative 'lib/tiny_dialer/hopper'
+require_relative 'lib/tiny_dialer/phone_number'
+require_relative 'lib/tiny_dialer/tcc_helper' if TinyDialer.options.direct_listener.tcc_root
require_relative 'controller/init'
Ramaze::Response.options.headers.merge!(
@@ -25,6 +21,4 @@ module TinyDialer
FSR.load_all_commands
-if $0 == __FILE__
- Ramaze.start port: 7575
-end
+Ramaze.start port: 7575 if $0 == __FILE__
View
@@ -18,7 +18,8 @@ def upload_csv
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'wb+'){|out| out.print(upload[:tempfile].read) }
- CsvScrubber.new(path, clear_leads).scrub_csv
+ TinyDialer::Lead.destroy if request[:clear_leads]
+ LeadScrubber.import_leads(path)
flash[:INFO] = "Loaded #{filename} : #{upload[:tempfile].size} bytes"
redirect_referrer
@@ -1,44 +0,0 @@
-require_relative '../tiny_dialer'
-require 'csv'
-require 'name_parse'
-
-module TinyDialer
- class CsvScrubber
- attr_reader :path, :db, :records, :clear_leads
-
- def initialize(path, clear_leads = false)
- @path = path
- @db = TinyDialer.db
- @clear_leads = clear_leads
- end
-
- def read_csv
- @records ||= CSV.read(path)
- Log.info "Records loaded: #{records.size}"
- end
-
- def load_db
- records.each_with_index do |record, index|
- next if index == 0
- Log.info "Loading record ##{index} #{record}"
- n = NameParse[record[1]]
- TinyDialer::Lead.create(:reference_number => record[0], :first_name => n.first, :last_name => n.last, :suffix => n.suffix, :prefix => n.prefix, :phone => record[5], :balance => record[4], :status => 'NEW', :zip => record[7], :state => record[6])
- end
- Log.info "DB loaded"
- end
-
- def clear_previous_leads
- TinyDialer::Lead.all.each {|x| x.destroy}
- Log.info "Cleared Leads from DB"
- end
-
- def scrub_csv
- if clear_leads
- clear_previous_leads
- end
- read_csv
- load_db
- end
-
- end
-end
@@ -0,0 +1,47 @@
+require_relative '../tiny_dialer'
+require 'csv'
+require 'name_parse'
+
+module TinyDialer
+ module LeadScrubber
+ MAP = {
+ balance: 'BALANCE',
+ fullname: 'NAME1',
+ phone: 'RES-PHONE',
+ reference_number: 'REFNUMBER',
+ state: 'STATE',
+ zip: 'ZIP',
+ }
+
+ module_function
+
+ def each_lead(res)
+ return to_enum(__method__, res) unless block_given?
+
+ CSV.open res, headers: true do |csv|
+ csv.each do |entry|
+ yield(entry)
+ end
+ end
+ end
+
+ def import_leads(res)
+ each_lead res do |lead|
+ hash = lead.to_hash
+ name = NameParse[hash.fetch('NAME1')]
+ TinyDialer::Lead.create(
+ first_name: name.first,
+ last_name: name.last,
+ suffix: name.suffix,
+ prefix: name.prefix,
+ balance: hash.fetch('INIT-BALANCE'),
+ phone: hash.fetch('RES-PHONE'),
+ reference_number: hash.fetch('REFNUMBER'),
+ state: hash.fetch('STATE'),
+ status: 'NEW',
+ zip: hash.fetch('ZIP'),
+ )
+ end
+ end
+ end
+end
@@ -25,23 +25,23 @@ def session_initiated
def play_message
lead.update(:status => 'ANSWER', :timestamp => Time.now)
- @record = TinyDialer::Record.create(:timestamp => Time.now, :status => "CALLING", :debtor_id => lead.debtor_id.to_s, :first_name => lead.first_name.to_s, :last_name => lead.last_name.to_s, :phone => lead.phone.to_s, :zip => lead.zip.to_s)
+ @record = TinyDialer::Record.create(:timestamp => Time.now, :status => "CALLING", :reference_number => lead.reference_number.to_s, :first_name => lead.first_name.to_s, :last_name => lead.last_name.to_s, :phone => lead.phone.to_s, :zip => lead.zip.to_s)
playback(WELCOME_WAV) do
update_session do
- Log.info "#{Time.now} - #{session.headers[:variable_amd_status].to_s} answered (#{session.headers[:variable_amd_result]}) - #{lead.first_name} #{lead.last_name} #{lead.debtor_id}"
+ Log.info "#{Time.now} - #{session.headers[:variable_amd_status].to_s} answered (#{session.headers[:variable_amd_result]}) - #{lead.first_name} #{lead.last_name} #{lead.reference_number}"
if session.headers[:variable_amd_status].to_s != "machine"
@record.update(:status => "ANSWERED")
- Log.info "A person answered, playing initial first/last name question: #{lead.first_name} #{lead.last_name} #{lead.debtor_id}"
+ Log.info "A person answered, playing initial first/last name question: #{lead.first_name} #{lead.last_name} #{lead.reference_number}"
speak("#{lead.first_name.to_s} #{lead.last_name.to_s}", {:voice => 'diane', :engine => 'cepstral'}) do
- Log.info "getting input: #{lead.first_name} #{lead.last_name} #{lead.debtor_id}"
+ Log.info "getting input: #{lead.first_name} #{lead.last_name} #{lead.reference_number}"
get_input
end
else
@record.update(:status => "MACHINE_ANSWERED")
set("first_name", "#{lead.first_name}") do
set("last_name", "#{lead.last_name}") do
- set("debtor_id", "#{lead.debtor_id.to_s.split(%r{\s*}).join(' ')}") do
- Log.info "#{Time.now} - Leaving a message for #{lead.first_name} #{lead.last_name} #{lead.debtor_id}"
+ set("reference_number", "#{lead.reference_number.to_s.split(%r{\s*}).join(' ')}") do
+ Log.info "#{Time.now} - Leaving a message for #{lead.first_name} #{lead.last_name} #{lead.reference_number}"
lead.update(:status => 'ANS_MACH_LMTC', :timestamp => Time.now)
@record.update(:status => 'ANS_MACH_LMTC')
lead.write_status
@@ -96,12 +96,12 @@ def case_input(input)
end
def direct_xfer
- Log.info "#{Time.now} - ##{lead.debtor_id} #{lead.first_name} #{lead.last_name} transfered to queue"
+ Log.info "#{Time.now} - ##{lead.reference_number} #{lead.first_name} #{lead.last_name} transfered to queue"
timestamp = Time.now
lead.update(:status => 'DIRECT_XFER', :timestamp => timestamp)
@record.update(:status => 'DIRECT_XFER')
lead.write_status
- set("effective_caller_id_number", "Acct#{lead.debtor_id}") do
+ set("effective_caller_id_number", "Acct#{lead.reference_number}") do
set("effective_caller_id_name", "#{@lead.first_name} #{@lead.last_name}") do
transfer("9999 XML default") { close_connection }
end
@@ -116,7 +116,7 @@ def leave_msg
lead.write_status
set("first_name", "#{lead.first_name}") do
set("last_name", "#{lead.last_name}") do
- set("debtor_id", "#{lead.debtor_id.to_s.split(%r{\s*}).join(' ')}") do
+ set("reference_number", "#{lead.reference_number.to_s.split(%r{\s*}).join(' ')}") do
lead.write_status
transfer("7001 XML default") { close_connection }
end
View
@@ -3,18 +3,21 @@
class TinyDialer::Lead < Sequel::Model
set_dataset :leads
- attr_reader :rej
def phone_num
phone.gsub('-', '') # Return phone number without hyphens, i.e. "-"
end
def write_status
- File.open(File.join(TinyDialer::ROOT, "results", "#{self.debtor_id}.tsv"), 'wb', 0664) do |f|
- f.puts "#{self.debtor_id}\t#{self.status}\t#{self.phone}\t#{self.timestamp.year}-#{self.timestamp.month}-#{self.timestamp.day}\t#{self.timestamp.hour}:#{self.timestamp.min}\tBD_IC"
+ File.open write_status_path, 'wb+', 0664 do |f|
+ f.puts [reference_number, status, phone, timestamp.strftime("%Y-%m-%d\t%H:%M"), 'BD_IC'].join("\t")
end
end
+ def write_status_path
+ "#{TinyDialer::ROOT}/results/#{reference_number}.tsv"
+ end
+
def postal
@zip ||= TinyDialer::Zip[:zip => zip[0..4]] if zip
@zip
@@ -35,48 +38,47 @@ def timezone
#
# Resorted to using postgres for the time comparison, because it Just Works
def call?
- if rejection_reason
- TinyDialer::Log.info "Rejected #{phone}: #{rejection_reason}"
- return
+ if reason = rejection_reason
+ TinyDialer::Log.info "Rejected #{phone}: #{reason}"
+ return false
end
+
# Make sure (now, now) overlaps (start, stop)
now = (Time.now.utc + (3600*(timezone)).to_i).strftime('%H:%M')
- unless TinyDialer.db.fetch("select ('#{now}'::text::time, '#{now}'::text::time) OVERLAPS ('#{state.start}'::text::time, '#{state.stop}'::text::time)").first[:overlaps]
+ if TinyDialer.db.fetch("select ('#{now}'::text::time, '#{now}'::text::time) OVERLAPS ('#{state.start}'::text::time, '#{state.stop}'::text::time)").first[:overlaps]
+ return true
+ else
TinyDialer::Log.info "Rejected #{phone}: Outside of calling times #{state.start} and #{state.stop}"
return false
end
- true
rescue => e
TinyDialer::Log.error e
- return
+ false
end
def dnc?
- TinyDialer::Dnc[:number => self.phone_num]
+ TinyDialer::Dnc[number: phone_num]
end
def called_today?
- return unless timestamp
- begin
- Time.now.to_date == timestamp.to_date
- rescue => e
- TinyDialer::Log.error e
- return
- end
+ timestamp && Date.today == timestamp.to_date
+ rescue => e
+ TinyDialer::Log.error e
+ false
end
private
+
def rejection_reason
- return @rej = :no_zip unless zip
- return @rej = :no_state unless state
- #return @rej = :called_today if called_today?
- return @rej = :do_not_call if dnc?
- @rej = false
+ return :no_zip unless zip
+ return :no_state unless state
+ return :called_today if called_today?
+ return :do_not_call if dnc?
+ false
end
def before_create
self[:created_at] = DateTime.now
self[:status] ||= "NEW"
end
-
end
View
No changes.
View
@@ -0,0 +1,14 @@
+"REFNUMBER","NAME1","NAME2","INIT-BALANCE","BALANCE","RES-PHONE","STATE","ZIP"
+1819039,"Vanderpoel, Tj","",320.0,320.0,"4719395828","CA","95202"
+1234567,"Blank, Paul",,320.0,320.0,"8123955950","TX","75202"
+1234568,"Smith, Yolandia",,320.0,320.0,"8123766817","NY","05202"
+1234569,"Dempsey, Rita",,320.0,320.0,"8124040546","TX","75202"
+1234570,"Bacon, Dennis",,320.0,320.0,"8128860850","TX","75202"
+1234571,"Harper, Tonya",,320.0,320.0,"8127247873","TX","75202"
+1234572,"Rogers, Sudeshna",,320.0,320.0,"2878310431","TX","75202"
+1234573,"Tate, Ronnie",,320.0,320.0,"2875693801","TX","75202"
+1234574,"Gibson, Gary",,320.0,320.0,"2875791072","TX","75202"
+1234575,"Tyler, Steve",,320.0,320.0,"8725406060","TX","75202"
+1234576,"Hanks, Candace",,320.0,320.0,"2879647478","TX","75202"
+1234577,"Berry, Thunder",,320.0,320.0,"8123340088","TX","75202"
+1234578,"Wayne, Roy",,320.0,320.0,"8122052049","TX","75202"
View
@@ -3,9 +3,9 @@
describe 'TinyDialer::Lead' do
before do
- @u = TinyDialer::Lead.create(:first_name => "jayson", :last_name => "vaughn",
- :phone => "817-690-7937", :status => "NEW",
- :debtor_id => '1234567', :zip => '75202')
+ @u = TinyDialer::Lead.create(:first_name => "jayson", :last_name => "vaughn",
+ :phone => "817-690-7937", :status => "NEW",
+ :reference_number => '1234567', :zip => '75202')
@tz = TinyDialer::Zip.create(:zip => '75202', :gmt => '-6.0', :state => 'TX')
@state = TinyDialer::State.create(:state => 'TX', :start => "09:00", :stop => "21:00")
end
@@ -18,21 +18,19 @@
it 'should allow creation of a lead' do
@u.id.should.not == nil
- @u.debtor_id.should == "1234567"
+ @u.reference_number.should == "1234567"
@u.phone.should == "817-690-7937"
@u.first_name.should == "jayson"
end
it 'should write lead status to a file in /tmp' do
- @u.update(:status => 'LTMC', :timestamp => Time.now)
+ @u.update(:status => 'LTMC', :timestamp => Time.at(1330205728))
@u.write_status
- status_file = File.join(TinyDialer::ROOT, "results", "#{@u.debtor_id}.tsv")
- File.exists?(status_file).should == true
- file = File.open(status_file).each do |record|
- entry = record.strip.split("\t")
- entry[0].should == "1234567"
- entry[1].should == "LTMC"
- entry[2].should == "817-690-7937"
+
+ File.open @u.write_status_path do |file|
+ file.each_line do |record|
+ record.scan(/[^\t]+/).first(3).should == %w[1234567 LTMC 817-690-7937]
+ end
end
end
@@ -61,11 +59,11 @@
end
it 'should not allow a call to be placed twice in the same day' do
- @state.update(:start => '00:00', :stop => '23:59') # So the first spec will always pass
- @u.update(:timestamp => Time.now - 36000)
- @u.call?.should == true
- @u.update(:timestamp => Time.now, :status => 'ANSWERED')
- @u.call?.should != true
+ @state.update(start: '00:00', stop: '23:59') # So the first spec will always pass
+ @u.update(status: 'NEW', timestamp: Date.today - 1)
+ @u.timestamp.to_date.should.not == Date.today
+ @u.should.be.call
+ @u.update(status: 'ANSWERED', timestamp: Time.now)
+ @u.should.not.be.call
end
-
end
@@ -1,16 +0,0 @@
-require_relative '../db_helper'
-
-describe 'TinyDialer::CsvScrubber' do
-
- after do
- TinyDialer::Lead.all.each {|x| x.destroy}
- end
-
- it 'be able to read a csv and load into the DB' do
- scrubber = TinyDialer::CsvScrubber.new(File.join(TinyDialer::ROOT, "spec", "csv_test.csv"))
- scrubber.read_csv.should == 5
- scrubber.load_db
- TinyDialer::Lead.all.size.should == 4
- end
-
-end
Oops, something went wrong.

0 comments on commit 6c36281

Please sign in to comment.