File Coverage

blib/lib/WWW/Salesforce/Report.pm
Criterion Covered Total %
statement 190 359 52.9
branch 84 304 27.6
condition 19 54 35.1
subroutine 23 29 79.3
pod 13 13 100.0
total 329 759 43.3


line stmt bran cond sub pod time code
1             # $Id$
2             # Copyright 2010 Pedro Paixao (paixaop at gmail dot com)
3             #
4             package WWW::Salesforce::Report;
5              
6 3     3   148959 use warnings;
  3         8  
  3         113  
7 3     3   17 use strict;
  3         7  
  3         96  
8              
9             # CPAN and external modules
10 3     3   2863 use HTTP::Cookies;
  3         53824  
  3         103  
11 3     3   3757 use HTTP::Headers;
  3         35978  
  3         179  
12 3     3   3410 use HTTP::Request::Common;
  3         89118  
  3         293  
13 3     3   6504 use LWP::UserAgent;
  3         107714  
  3         110  
14 3     3   33 use Digest::MD5;
  3         5  
  3         160  
15 3     3   4744 use IO::Compress::Zip qw(zip $ZipError :constants);
  3         291977  
  3         1283  
16 3     3   8028 use DBI;
  3         43031  
  3         184  
17 3     3   50 use Carp;
  3         5  
  3         17124  
18              
19             =pod
20              
21             =head1 NAME
22              
23             WWW::Salesforce::Report - The poor man's Salesforce report API in Perl!
24              
25             =head1 VERSION
26              
27             Version 0.02
28              
29             =cut
30              
31             our $VERSION = '0.03';
32              
33             =head1 SYNOPSIS
34              
35             Create a rough API for Salesforce.com reports. Reports are downloaded in CSV
36             format from Salesforce and can then be cached locally in a SQLite database.
37             Regular SQL queries can then be ran on the data.
38              
39             The reports can also be downloaded in Excel format, which will not be
40             cache in a local database but can be sent as an attachment to users for example.
41              
42             Perhaps a little code snippet.
43              
44             use WWW::Salesforce::Report;
45              
46             my $sfr = WWW::Salesforce::Report->new(
47             id=> "000000068AxXd",
48             user=> "myuser",
49             password => "mypassword" );
50            
51             $sfr->login();
52             $sfr->get_report();
53            
54             my @data = $sfr->query( query => "select * from report" );
55              
56             Save a report to an Excel file
57              
58             use WWW::Salesforce::Report;
59              
60             $sfr = WWW::Salesforce::Report->new(
61             id=> "000000068AxXd",
62             user=> "myuser",
63             password => "mypassword" );
64            
65             $sfr->login();
66             my $xls_data = $sfr->get_report(format => "xls");
67             my $name = $sfr->write(file=> "report.xls", compress => 0);
68              
69             Attach a compressed version of the Excel report to an email and send it to a
70             user or group of users:
71              
72             use WWW::Salesforce::Report;
73             use Net::SMTP::TLS;
74             use Mime::Lite;
75            
76             $sfr = WWW::Salesforce::Report->new(
77             id=> "000000068AxXd",
78             user=> "myuser",
79             password => "mypassword" );
80            
81             $sfr->login();
82             my $xls_data = $sfr->get_report(format => "xls");
83             my $name = $sfr->write(file=> "report.xls");
84            
85             # using TLS to send the e-mail
86             my $mailer = new Net::SMTP::TLS(
87             "mail.domain.com",
88             Hello => "mail.domain.com",
89             Port => 25,
90             User => "my_user_name",
91             Password=> "my_password");
92            
93             # email of the sender
94             $mailer->mail("reports@domain.com");
95            
96             # email of the recipient
97             $mailer->to("user@domain.com");
98            
99             $mailer->data;
100            
101             my $message = MIME::Lite->new(
102             From => "reports@domain.com",
103             To => "user@domain.com",
104             Subject => "REPORT: Quarter Forecast by Region",
105             Type =>'multipart/mixed'
106             );
107            
108             # Message body
109             $message->attach(
110             Type => "TEXT",
111             Data => "Here are the latest forecast numbers.",
112             );
113            
114             # Attach the zip file
115             $message->attach(
116             Type => "application/zip",
117             Filename => $name,
118             Path => $name,
119             Encoding => "base64",
120             Disposition => 'attachment',
121             );
122            
123             $mailer->datasend($message->as_string);
124            
125             $mailer->dataend;
126             $mailer->quit;
127              
128             =head1 DEPENDS
129              
130             The WWW::Salesforce::Report depends on the following CPAN modules
131              
132             =begin HTML
133              
134            
135            
  • HTTP::Cookies
  • 136            
  • HTTP::Headers
  • 137            
  • HTTP::Request::Common
  • 138            
  • LWP::UserAgent
  • 139            
  • Digest::MD5
  • 140            
  • DBI
  • 141            
  • Carp
  • 142            
    143              
    144             =end HTML
    145              
    146             =head1 METHODS
    147              
    148             =head2 PUBLIC METHODS
    149              
    150             This module uses a named paramter convetion. That means that all methods expect
    151             to be called like
    152              
    153             $obj->method( param_name => value, param2_name => value_2 );
    154            
    155             and not like
    156              
    157             $obj->method( value_1, value_2 );
    158              
    159             =over
    160              
    161             =item new( OPTIONS )
    162              
    163             Class constructor. You must call new() before using the object, and manipulating
    164             report data.
    165              
    166             C are passed in a hash like fashion, using key and value pairs.
    167             Possible options are:
    168              
    169             B
    170              
    171             B => user_name
    172              
    173             B => password
    174              
    175             User name and password to login to Salesforce.com.
    176              
    177             B
    178              
    179             B => salesforce_id
    180              
    181             Salesforce.com Id of the report you want to download. Please make sure this is a
    182             valid report Id from Salesforce.com otherwise this module will fail.
    183             You can get the Id from the Salesfoce.com URL that points to the report you want
    184             to use with the script.
    185             Although you can set the report ID using report_id() it is a best practice to set it
    186             in the object constructor, and if you need to work with multiple reports create
    187             different objects for each one.
    188              
    189             B => "csv"| "xls"
    190              
    191             See L
    192              
    193             B => 0 | 1
    194              
    195             If true a "lot" of debug or tracing messages will be printed.
    196             Enabled by default.
    197              
    198             B => 0 | 1
    199              
    200             If true convert dates from Salesforce.com format to SQLite format. Enabled by
    201             default.
    202              
    203             B => URL
    204              
    205             This must be a Salesforce.com direct login URL. See L.
    206             Defaults to:
    207              
    208             login_url => https://login.salesforce.com/?un=USER&pw=PASS
    209              
    210             B => URL
    211              
    212             Url to export the desired report as a CSV file.
    213             Defaults to:
    214              
    215             csv_report_url => https://SERVER.salesforce.com/REPORTID?export=1&enc=UTF-8&xf=csv
    216              
    217             B => URL
    218              
    219             Url to export the desired report as a CSV file.
    220             Defaults to:
    221              
    222             csv_report_url => https://SERVER.salesforce.com/REPORTID?export=1&enc=UTF-8&xf=xls
    223              
    224             In the above URLs the words SERVER, USER and PASS represent the Salesforce.com
    225             login server, user name and password.
    226              
    227             Generally you do not need to supply your own URLs, these parameters are here
    228             just to ensure future compatibility if Salesfroce.com changes them.
    229              
    230             B => 0 | 1
    231              
    232             If true the database file will be deleted and recreated anew. Defaults to 1.
    233              
    234             B => 0 | 1
    235              
    236             If true the database will allow duplicate records. For every report line a
    237             new field is added which equals the MD5 hash of said report line.
    238             This is done because not all Salesforce reports may contain Salesforce.com IDs.
    239             If you do not want duplicates in your database a UNIQUE index will be created on
    240             the __hash field.
    241             Defaults to 1, to allow duplicates.
    242              
    243             B => sqlite_type
    244              
    245             The type of the primary key. This must be a valid SQLite type. Defaults to TEXT.
    246              
    247             B => name_of_primary_key
    248              
    249             The name of the primary key. Defaults to __id
    250              
    251             B => 0 | 1
    252              
    253             If true erase the reports table. Defaults to 1.
    254             If the database already exists, it will not be created but you have the
    255             opportunity of erasing all data in the reports table.
    256              
    257             B => 0 | 1
    258              
    259             If true erase the notifications table. Defaults to 0.
    260             If the database already exists, it will not be created but you have the
    261             opportunity of erasing all data in the notifications table.
    262              
    263             B => 0 | 1
    264              
    265             If true clean up local files when destroying object. Defauts to true (1)
    266              
    267             =cut
    268              
    269             sub new {
    270 6     6 1 2507 my ($class, %options) = @_;
    271            
    272 6         14 my $self = {} ;
    273 6   33     977 $class = ref($class) || $class;
    274 6         15 bless ($self, $class);
    275            
    276 6         47 $self->{ ua } = LWP::UserAgent->new; # HTTP User Agent
    277 6         10824 $self->{ cookie_jar } = HTTP::Cookies->new; # Prepare the cookies
    278            
    279             # Let's fake a Internet Explorer Browser on Windows XP ;)
    280 6         131 $self->{ ua }->agent('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)');
    281              
    282             # Should module pring verbose messages?
    283 6         908 $self->{ verbose } = 0;
    284             $self->{ verbose } = $options{ verbose }
    285 6 50       63 if( defined($options{ verbose }) );
    286            
    287             # Should Salesforce.com dates be converted to SQLite format?
    288 6         13 $self->{ convert_dates } = 1;
    289             $self->{ convert_dates } = $options{ convert_dates }
    290 6 50       21 if( defined($options{ convert_dates }) );
    291            
    292             # User provided a different login URL?
    293 6 50       19 if( defined($options{ login_url }) ) {
    294 0         0 $self->{ login_url } = $options{ login_url };
    295             } else {
    296 6         15 $self->{ login_url } = "https://login.salesforce.com/?un=USER&pw=PASS";
    297             }
    298            
    299             # User provided a different URL for the CSV format reports?
    300 6 50       12 if( defined($options{ csv_report_url }) ) {
    301 0         0 $self->{ csv_report_url } = $options{ csv_report_url };
    302             } else {
    303             $self->{ csv_report_url } =
    304 6         16 "https://SERVER.salesforce.com/REPORTID?export=1&enc=UTF-8&xf=csv";
    305             }
    306            
    307             # User provided a different URL for the XLS format reports?
    308 6 50       14 if( defined($options{ xls_report_url }) ) {
    309 0         0 $self->{ xls_report_url } = $options{ xls_report_url };
    310             } else {
    311             $self->{ xls_report_url } =
    312 6         10 "https://SERVER.salesforce.com/REPORTID?export=1&enc=UTF-8&xf=xls";
    313             }
    314            
    315 6         20 $self->{ id } = "";
    316 6         12 $self->{ file } = "";
    317            
    318             # File directive to read from a local file overrides the salesforce Id
    319 6 100       15 if( defined($options{ file }) ) {
    320              
    321             croak "Local file $options{ file } does not exist"
    322 2 50       81 if( !-e $options{ file } );
    323              
    324 2         6 $self->{ file } = $options{ file };
    325              
    326             }
    327             else {
    328            
    329 4 100       11 if( defined($options{ id }) ) {
    330 3         7 $self->{ id } = $options{ id };
    331             }
    332             else {
    333 1         423 croak 'You need to pass a "file" or "id" parameter to WWW::Salesforce::Report->new()';
    334             }
    335              
    336 3 100       9 if( defined($options{ user }) ) {
    337 2         5 $self->{ user } = $options{ user };
    338             } else {
    339 1         114 croak 'You need to pass a "user" parameter to WWW::Salesforce::Report->new()';
    340             }
    341            
    342 2 100       7 if( defined($options{ password }) ) {
    343 1         39 $self->{ password } = $options{ password };
    344             } else {
    345 1         154 croak 'You need to pass a "password" parameter to WWW::Salesforce::Report->new()';
    346             }
    347            
    348             }
    349            
    350             # Set default format to CSV, and do not update name
    351 3         12 $self->format( format => "csv" );
    352 3 50       10 if( defined($options{ format }) ) {
    353 0         0 $self->format( format => $options{ format } );
    354             }
    355            
    356 3         7 $self->{ cache } = 1;
    357 3 50       9 if( defined($options{ cache }) ) {
    358 0         0 $self->{ cache } = $options{ cache };
    359             }
    360            
    361 3         7 $self->{ pre_import_query } = "";
    362 3 50       8 if( defined($options{ pre_import_query }) ) {
    363 0         0 $self->{ pre_import_query } = $options{ pre_import_query };
    364             }
    365            
    366 3         9 $self->{ post_import_query } = "";
    367 3 50       14 if( defined($options{ post_import_query }) ) {
    368 0         0 $self->{ post_import_query } = $options{ post_import_query };
    369             }
    370            
    371             $self->{ erase_db } = 1
    372 3 50       10 if( !defined($self->{ erase_db }) );
    373            
    374             $self->{ allow_duplicates } = 1
    375 3 50       9 if( !defined($self->{ allow_duplicates }) );
    376            
    377 3 50       19 $self->{ primary_key_type } = "TEXT"
    378             if( !defined($self->{primary_key_type}) );
    379            
    380 3 50       12 $self->{ primary_key } = "__id"
    381             if( !defined($self->{primary_key}) );
    382            
    383             $self->{ erase_reports_table } = 1
    384 3 50       15 if( !defined($self->{ erase_reports_table }) );
    385            
    386             $self->{ erase_notifications_table } = 0
    387 3 50       9 if( !defined($self->{ erase_reports_table }) );
    388            
    389             $self->{ clean_on_destroy } = 1
    390 3 50       10 if( !defined($self->{ clean_on_destroy }) );
    391            
    392             croak "new() failed, neither file, id, or name were initialized"
    393 3 0 66     16 if( !$self->{ file } && !$self->{ id } && !$self->name );
          33        
    394              
    395 3         14 return $self;
    396             }
    397              
    398             =item login ( )
    399              
    400             Login to Salesforce.com via the URL method, which includes the user's
    401             credentials in a URL instead of the login form the user usually sees.
    402              
    403             If successful returns 1, otherwise triggers an error.
    404              
    405             The URL method of login is sort of a hack since it does not use an approved API
    406             call. Unfortunately the fact that Salesforce.com does not have a report API
    407             available we must use this method to get the report data.
    408              
    409             As of this witting you can login to Salesforce.com directly, i.e.,
    410             not using the Login page, by using the following URL:
    411              
    412             https://login.salesforce.com/?un=USER&pw=PASS
    413              
    414             where C is the user name, and C the user's password.
    415              
    416             =cut
    417              
    418             sub login {
    419 1     1 1 3 my ($self) = @_;
    420            
    421 1 50       6 croak "Please call new() before using the object\n" if( !$self );
    422            
    423 1 50       4 if( $self->{ file } ) {
    424            
    425             print "Reading report from local file. Salesforce.com login not needed\n"
    426 1 50       4 if( $self->{ verbose } );
    427              
    428 1         4 return 0;
    429            
    430             }
    431            
    432 0         0 my $usr_login = $self->{ login_url };
    433 0         0 $usr_login =~ s/USER/$self->{ user }/g;
    434 0         0 $usr_login =~ s/PASS/$self->{ password }/g;
    435            
    436             print "Attempt Salesforce.com login with: $self->{ user }\n"
    437 0 0       0 if( $self->{ verbose } );
    438            
    439             # Get the login page with user and password information
    440 0         0 my $res = $self->{ ua }->request(GET $usr_login);
    441            
    442             # Exit if we can't connect
    443 0 0       0 croak "Cannot get login page" if(!$res->is_success);
    444            
    445             # Check if we got the Activation page and inform the user
    446             # This is not a permanent error. All that needs to be done is access
    447             # Salesforce.com from a browser in the computer where the script is installed
    448             # and follow the Salesforce.com activation procedure
    449 0 0       0 if( $res->content =~/Challenge User/ ) {
    450            
    451             # we got the Challenge User page asking the user to verify the computer
    452 0         0 croak "This computer is not activated to access Salesforce.com.\n" .
    453             "Login to Salesforce.com from a browser on this computer " .
    454             "before using this script\n";
    455              
    456             }
    457            
    458             # Check if we got the login page again...
    459 0 0       0 croak "Cannot Login with user $self->{ user }\n"
    460             if( $res->content =~ /Login Page/ );
    461            
    462             # Extract the cookie information from the server response, and
    463             # save it in our "cookie jar"
    464 0         0 $self->{ cookie_jar }->extract_cookies($res);
    465            
    466             # Determine which server did we login to by checking the cookies
    467             # Replace the server name in the report urls so we can download them later
    468 0         0 foreach my $server (keys %{ $self->{ cookie_jar }->{ COOKIES } }) {
      0         0  
    469            
    470 0 0       0 if( $server =~ /(.+?)\.salesforce\.com/ ) {
    471            
    472 0         0 $server = $1;
    473 0         0 $self->{ csv_report_url } =~ s/SERVER/$server/g;
    474 0         0 $self->{ xls_report_url } =~ s/SERVER/$server/g;
    475 0         0 $self->{ url } =~ s/SERVER/$server/g;
    476            
    477             print "Login Successful on " . $server . ".salesforce.com\n"
    478 0 0       0 if( $self->{ verbose } );
    479            
    480 0         0 last;
    481             }
    482            
    483             }
    484            
    485 0         0 return 1;
    486             }
    487              
    488             =item login_server ( )
    489              
    490             If the login was successful return the server to which the user logged on,
    491             otherwise return 0.
    492              
    493             my $server;
    494             if( $sforce->login() ) {
    495             $server = $sforce->login_server();
    496             }
    497            
    498             print "Logged to : $server \n";
    499              
    500             =cut
    501              
    502             sub login_server {
    503 1     1 1 3 my ($self) = @_;
    504            
    505             # Sanity checks
    506 1 50       5 croak "Please call new() before using the object\n" if( !$self );
    507            
    508 1 50       12 if( !$self->{ file } ) {
    509            
    510 0         0 foreach my $server (keys %{ $self->{ cookie_jar }->{ COOKIES } }) {
      0         0  
    511 0 0       0 if( $server =~ /(.+?)\.salesforce\.com/ ) {
    512 0         0 return $1;
    513             }
    514             }
    515            
    516             }
    517            
    518             print "Reading report from local file. Salesforce.com login_server not set.\n"
    519 1 50       4 if( $self->{ verbose } );
    520            
    521 1         4 return 0;
    522             }
    523              
    524             =item report_id( [id => salesforce_id] )
    525              
    526             Set or get the Salesforce.com Id of report you want to download.
    527              
    528             $sforce->report_id() # return the current Salesforce.com Id.
    529             $sforce->report_id( id=> salesforce_id ) # set the current Salesforce.com Id.
    530              
    531             =cut
    532              
    533             sub report_id {
    534 0     0 1 0 my ($self, %options) = @_;
    535            
    536 0 0       0 $options{ delete } = 1 if( !defined($options{ delete }) );
    537            
    538 0 0       0 if( $options{ id } ) {
    539            
    540             # If the id does not change just return and do nothing
    541             return $self->{ id }
    542 0 0       0 if( $self->{ id } eq $options{ id } );
    543            
    544 0         0 $self->{ id } = $options{ id };
    545            
    546 0         0 $self->_set_name( delete => $options{ delete } );
    547            
    548             }
    549            
    550 0         0 return $self->{ id };
    551             }
    552              
    553              
    554             =item name ( )
    555              
    556             Get the name of the local cache file or database.
    557              
    558             =cut
    559              
    560             sub name {
    561 7     7 1 7786 my ($self) = @_;
    562            
    563             # Sanity checks
    564 7 50       24 croak "Please call new() before using the object\n" if( !$self );
    565            
    566             croak "Please pass a Salesforce.com Report Id, or local file,"
    567             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    568 7 50 66     45 if( !$self->{ id } && !$self->{ file } );
    569            
    570 7         62 return $self->{ name };
    571             }
    572              
    573             =item format( format => "csv" | "xls" )
    574              
    575             Get or set the report format
    576              
    577             B => "csv"| "xls"
    578              
    579             The report format. Possible values are C<"csv">, or C<"xls">.
    580             As of this writing Salesforce.com only supports CSV and XLS formats
    581             for exported reports.
    582             Comma Separated Value (CSV) is the only format that can be cached to a local
    583             SQLite database. If you set the local file, via the C parameter to new(),
    584             a local CSV file will be read from disk instead of downloading the report data
    585             from Salesforce.com. The local file must be in CSV format.
    586              
    587             To return the current format:
    588              
    589             my $format = $sforce->format();
    590              
    591             To set the current format:
    592              
    593             $sforce->format( format=> "csv" );
    594              
    595             =cut
    596              
    597             sub format {
    598 11     11 1 634 my ($self, %options) = @_;
    599            
    600             # Sanity checks
    601 11 50       30 croak "Please call new() before using the object\n" if( !$self );
    602            
    603             croak "Please pass a Salesforce.com Report Id, or local file,"
    604             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    605 11 50 66     62 if( !$self->{ id } && !$self->{ file } );
    606            
    607 11 100       73 return $self->{ format } if( !defined($options{ format }) );
    608            
    609 5         10 $self->{ format } = $options{ format };
    610            
    611 5 100       60 if( $self->{ format }=~ /csv/i ) {
        50          
    612            
    613 4         10 $self->{ url } = $self->{ csv_report_url };
    614            
    615             print "Report format set to CSV.\n"
    616 4 50       12 if( $self->{ verbose } );
    617            
    618             }
    619             elsif( $self->{ format } =~ /xls/i ) {
    620            
    621             croak 'Format cannot be set to "xls" when reading from local file'
    622 1 50       192 if( $self->{ file } );
    623            
    624 0         0 $self->{ url } = $self->{ xls_report_url };
    625            
    626             # XLS reports cannot be cached localy
    627 0         0 $self->cache( cache => 0 );
    628            
    629             print "Report format set to XLS. Caching disabled\n"
    630 0 0       0 if( $self->{ verbose } );
    631            
    632             }
    633             else {
    634            
    635 0         0 croak "Unknonw report type ($self->{ format }). Supported formats are"
    636             . ' "csv", or "xls"';
    637             }
    638            
    639 4         13 $self->_set_name();
    640 4         10 return $self->{ format };
    641              
    642             }
    643              
    644             =item cache( cache => 0 | 1 )
    645              
    646             Get or set the local cache flag
    647              
    648             To return the current format:
    649              
    650             my $cache = $sforce->cache();
    651              
    652             To set the current format:
    653              
    654             $sforce->cache( cache => 0 );
    655              
    656             =cut
    657              
    658             sub cache {
    659 4     4 1 12 my ($self, %options) = @_;
    660            
    661             $self->{ cache } = $options{ cache }
    662 4 100       14 if( defined($options{ cache }) );
    663            
    664 4         26 return $self->{ cache };
    665              
    666             }
    667              
    668             =item primary_key( key => field )
    669              
    670             Get the primary key field of the database. Defaults to '__id'
    671              
    672             =cut
    673              
    674             sub primary_key {
    675 1     1 1 3 my ($self) = @_;
    676            
    677 1         6 return $self->{ primary_key };
    678             }
    679              
    680              
    681             =item clean ( )
    682              
    683             Clean the local cache and report data. This method will delete the local
    684             cache file (SQLite database) if it exists.
    685             Downloaded report data will also be erased from memory.
    686              
    687             =cut
    688              
    689             sub clean {
    690 6     6 1 12 my ($self, %options ) = @_;
    691            
    692             # Check if the local cache database exists and remove it
    693             # So we do not leave garbage behind.
    694 6 50 66     126 if( $self->{ name } &&
          66        
    695             $self->{ format } =~ /csv|xls/i &&
    696             -e $self->{ name } ) {
    697              
    698             unlink $self->{ name } or
    699 0 0       0 croak "Could not erase local cache $self->{ name }\n";
    700              
    701             }
    702            
    703 6         41 $self->{ data } = "";
    704             }
    705              
    706             =item get_report ( format => string, cache => 0 | 1, force => 0 | 1 )
    707              
    708             Download a report from Salesforce.com or read it from a local file
    709             Returns a string with the report data.
    710              
    711             C are passed in a hash like fashion, using key and value pairs.
    712             Possible options are:
    713              
    714             B => "csv"| "xls"
    715              
    716             The report format. Possible values are csv, or xls
    717             As of this writing Salesforce.com only supports CSV and XLS formats
    718             for exported reports.
    719             Comma Separated Value (CSV) is the only format that can be cached to a local
    720             SQLite database. If you set the local file, via the C parameter to new(),
    721             a local CSV file will be read from disk instead of downloading the report data
    722             from Salesforce.com. The local file must be in CSV format.
    723              
    724             B => 0 | 1
    725              
    726             If true create a local cache for the report data, using a SQLite
    727             database. B is on by default but only used if report B is C or
    728             C. The database name is the report Id, with a 'db3' extension. Or local
    729             C in case of C format.
    730              
    731             B => 0 | 1
    732              
    733             If called multiple times C will return the cached data without
    734             downloading it again, and again. If you want to re-download the data from
    735             Salesforce.com, or re-read the local file, set C to 1.
    736             By default C is 0.
    737              
    738             Example:
    739              
    740             my $report = $sf->get_report( id => "000006889AAD", format => "xls");
    741              
    742             =cut
    743              
    744             sub get_report {
    745 1     1 1 3 my ($self, %options ) =@_;
    746            
    747             # Sanity checks
    748 1 50       7 croak "Please call new() before using the object\n" if( !$self );
    749            
    750             croak "Please pass a Salesforce.com Report Id, or local file,"
    751             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    752 1 50 33     24 if( !$self->{ id } && !$self->{ file } );
    753            
    754 1 50       8 $options{ force } = 0 if( !defined($options{ force }) );
    755            
    756 1 50 33     6 if( $self->{ data } &&
    757             !$options{ force } ) {
    758            
    759             print "Report content already in memory. Return without downloading\n"
    760 0 0       0 if( $self->{ verbose } );
    761            
    762 0         0 return $self->{ data };
    763             }
    764            
    765 1 50       4 if( $options{ format } ) {
    766            
    767 0         0 $self->format( format => $options{ format } );
    768 0         0 $self->_set_name( delete => $options{ force } );
    769              
    770             }
    771            
    772             # Replace the report Id in the report URL
    773 1         12 $self->{ url } =~ s/REPORTID/$self->{ id }/g;
    774            
    775 1         2 my $res;
    776 1 50       4 if( !$self->{ file } ) {
    777            
    778             # Not a local report so get it from Salesfoce.com
    779             print "Getting report $self->{ id } data.\n"
    780 0 0       0 if( $self->{ verbose } );
    781            
    782 0         0 $res = $self->_request($self->{ url });
    783            
    784             }
    785             else {
    786            
    787             print "Get Report from local file: $self->{ file }\n"
    788 1 50       4 if( $self->{ verbose } );
    789            
    790             open my $fh,"<", $self->{ file } or
    791 1 50       92 croak "Could not open $self->{ file } : $!";
    792            
    793 1         3 $res = "";
    794 1         26 while( <$fh> ) {
    795 3         16 $res .= $_;
    796             }
    797            
    798 1         16 close $fh;
    799             }
    800              
    801 1 50       8 if( $self->{ format } =~ /csv/i ) {
    802             # Remove the text in the end of the report results. Something like:
    803             #
    804             # "This is the report name"
    805             # "Copyright (c) 2000-2007 salesforce.com, inc. All rights reserved."
    806             # "Confidential Information - Do Not Distribute"
    807             # "Generated By: username 2/4/2008 3:54 AM"
    808             # "Company"
    809             #
    810 1         4 $res =~ s/"(?:\n){2}.*$/"/s;
    811            
    812 1         6 $res =~ s/"\n/"___/g; # safeguard the "true" new lines
    813 1         3 $res =~ s/\n/ /g; # replace all "in-field" new lines with \s
    814 1         4 $res =~ s/___/\n/g; # restore "true" end of lines
    815             }
    816            
    817 1         2 $self->{ data } = $res;
    818            
    819             # Cache report to local database, if caching is enabled
    820 1 50       6 $self->_cache_report_to_sqlite()
    821             if( $self->cache() );
    822            
    823             print "Caching disabled. Report data not imported into local database\n"
    824 0 0 0     0 if( !$self->cache() && $self->{ verbose } );
    825            
    826 0         0 return $res;
    827             }
    828              
    829             =item write( file => file_name, compress => 0 | 1 )
    830              
    831             Write report data to local file. If C is 1 create a Zip file, with the
    832             compressed contents of the downloaded report. This is the default.
    833              
    834             If a specific file name is not passed via C the report data will be saved
    835             to the default name returned by name().
    836              
    837             Example:
    838              
    839             Write report data to a Zipped Excel file
    840              
    841             use PMP::Salesforce;
    842              
    843             $sf = PMP::Salesforce->new(
    844             id=> "000000068AxXd",
    845             format => "xls",
    846             user=> "myuser",
    847             password => "mypassword" );
    848            
    849             $sf->login();
    850             $sf->get_report();
    851             my $name = $sf->write();
    852              
    853             =cut
    854              
    855             sub write {
    856 0     0 1 0 my ($self, %options) = @_;
    857            
    858             # Sanity checks
    859 0 0       0 croak "Please call new() before using the object\n" if( !$self );
    860              
    861             croak "Please pass a Salesforce.com Report Id, or local file,"
    862             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    863 0 0 0     0 if( !$self->{ id } && !$self->{ file } );
    864            
    865             croak "Call get_report() before calling write()"
    866 0 0       0 if( !$self->{ data } );
    867            
    868 0         0 my $name;
    869 0 0       0 if( $options{ file } ) {
        0          
        0          
    870 0         0 $name = $options{ file };
    871             }
    872             elsif( $self->{ file } ) {
    873 0         0 $name = $self->{ file };
    874             }
    875             elsif( $self->{ id } ) {
    876            
    877 0         0 $name = $self->{ id } . ".csv";
    878             }
    879             else {
    880 0         0 croak "File name not set";
    881             }
    882            
    883 0 0       0 $options{ compress } = 1 if( !defined($options{ compress }) );
    884            
    885 0 0       0 if( !$options{ compress } ) {
    886 0 0       0 open my $fh, ">", $name or
    887             croak "Could not create file $name for writing\n";
    888            
    889 0         0 print $fh $self->{ data };
    890 0         0 close $fh;
    891            
    892             print "Report data written to file $name\n"
    893 0 0       0 if( $self->{ verbose } );
    894            
    895 0         0 return $name;
    896             }
    897             else {
    898             # Compress the file?
    899            
    900             # remove the .db3 that may exist in the file's name
    901 0         0 $name =~ s/\.db3$//;
    902 0         0 my $zip_name = $name;
    903            
    904 0 0       0 if( $name =~ /\..+/ ) {
    905            
    906             # Replace the file extention with .zip
    907 0         0 $zip_name =~ s/\..*$/\.zip/;
    908            
    909             }
    910             else {
    911            
    912             # File had no extention just add a .zip
    913 0         0 $zip_name .= ".zip";
    914            
    915             }
    916            
    917 0 0       0 my $z = IO::Compress::Zip->new(
    918             $zip_name,
    919             name => $name,
    920             ExtAttr => 0666 << 16,
    921             AutoClose => 1 )
    922             or die "IO::Compress::Zip(1) failed: $ZipError\n";
    923            
    924 0         0 print $z $self->{ data };
    925            
    926             print "Report data written to zip file $zip_name\n"
    927 0 0       0 if( $self->{ verbose } );
    928            
    929 0         0 return $zip_name;
    930             }
    931              
    932             }
    933              
    934             =item query( query => sqlite_query, hash => 0 | 1 )
    935              
    936             Run query on the cached report database. This method can only be called on
    937             CSV and local report formats that have been cached locally. If the database
    938             does not exist the mothod will fail and croak.
    939              
    940             B => sqlite_query
    941              
    942             Mandatory SQLite query string to execute.
    943              
    944             B => 0 | 1
    945              
    946             Optional parameter that defaulst to 1, and controls how data is returned.
    947             If hash => 1 query result is returned as an array
    948             of hash references. If hash => 0 query result is returned as an array
    949             of array references. See DBI module documentation for fetchrow_hashref(), and
    950             fetchrow_arrayref().
    951              
    952             Example:
    953              
    954             $sf = PMP::Salesforce->new( user=> "myuser", password => "mypassword" );
    955             $sf->login();
    956             $sf->report_id(id=> "000000068AxXd");
    957             $sf->get_report();
    958             my @data = $sf->query(query => "select * from reports");
    959              
    960             =cut
    961              
    962             sub query {
    963 0     0 1 0 my ($self, %options ) = @_;
    964            
    965             # Sanity checks
    966 0 0       0 croak "Please call new() before using the object\n" if( !$self );
    967            
    968             croak "Please pass a Salesforce.com Report Id, or local file,"
    969             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    970 0 0 0     0 if( !$self->{ id } && !$self->{ file } );
    971            
    972             croak "You need to cache a report locally before you can call query()\n"
    973 0 0       0 if( !-e $self->{ name } );
    974            
    975             croak "Please pass a SQLite query string to query()\n"
    976 0 0       0 if( !defined($options{ query }) );
    977            
    978 0 0       0 croak "Please enable the local cache in new() before you can run queries"
    979             if( !$self->cache() );
    980            
    981 0 0       0 $options{ hash } = 1 if( !defined( $options{ hash }) );
    982            
    983             $self->{ dbh } =
    984 0 0       0 DBI->connect("dbi:SQLite:dbname=". $self->{ name },"","") or
    985             croak "Database connection not made: $DBI::errstr";
    986              
    987 0         0 my $sth;
    988 0 0       0 $sth = $self->{ dbh }->prepare( $options{ query } ) or
    989             croak "Couldn't prepare statement: " . $sth->errstr;
    990            
    991             print "Running query: $options{ query }\n"
    992 0 0       0 if( $self->{ verbose } );
    993            
    994 0 0       0 $sth->execute() or
    995             croak "Couldn't execute statement: " . $sth->errstr;
    996            
    997             #TODO: This is not optimal from a memory consumption perspective and should
    998             # be changed into calling a sub ref.
    999 0         0 my %ret_hash;
    1000              
    1001 0         0 $ret_hash{ num_fields } = $sth->{NUM_OF_FIELDS};
    1002              
    1003             # TODO: this is a bug for sure
    1004 0         0 push @{ $ret_hash{ fields } }, @{ $sth->{ NAME } };
      0         0  
      0         0  
    1005            
    1006 0 0       0 if( $options{ hash } ) {
    1007 0         0 $ret_hash{ format } = "array_of_hashes";
    1008            
    1009 0         0 while( my $data = $sth->fetchrow_hashref() ) {
    1010 0         0 push @{ $ret_hash{ data } }, $data ;
      0         0  
    1011             }
    1012              
    1013             }
    1014             else {
    1015 0         0 $ret_hash{ format } = "array_of_array";
    1016 0         0 while( my $data = $sth->fetchrow_arrayref() ) {
    1017 0         0 push @{ $ret_hash{ data } }, ( $data );
      0         0  
    1018             }
    1019            
    1020             }
    1021            
    1022 0         0 return %ret_hash;
    1023             }
    1024              
    1025             =item dbh ( )
    1026              
    1027             Returns the DBI handle of the cached report database. Use this method if you
    1028             need direct access to the local database DBI handle.
    1029              
    1030             my $dbh = $sforce->dbh();
    1031             my $sth = $dbh->prepare( "select * from reports ) or
    1032             croak "Couldn't prepare statement: " . $sth->errstr;
    1033              
    1034             Just like you're accessing SQLite through DBI, a bit low level but allows you
    1035             to manipulate the report data in a very flexible way.
    1036              
    1037             =cut
    1038              
    1039             sub dbh {
    1040 0     0 1 0 my ($self, %options ) = @_;
    1041            
    1042             # Sanity checks
    1043 0 0       0 croak "Please call new() before using the object\n" if( !$self );
    1044            
    1045             croak "Please pass a Salesforce.com Report Id, or local file,"
    1046             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    1047 0 0 0     0 if( !$self->{ id } && !$self->{ file } );
    1048            
    1049             croak "You need to download the report and cache it locally before you can call get_dbh()\n"
    1050 0 0       0 if( !defined($self->{ dbh } ) );
    1051            
    1052 0         0 return $self->{ dbh };
    1053             }
    1054              
    1055             =back
    1056              
    1057             =head2 PRIVATE METHODS
    1058              
    1059             Internal methods are not to be used directly in your code. Documented in
    1060             case you need to hack this module...
    1061              
    1062             =over
    1063              
    1064             =item _request( URL )
    1065              
    1066             Request Salesforce.com URL after the user has already been authenticated
    1067             Returns the page content as a string.
    1068             Can be used to get any URL
    1069              
    1070             =cut
    1071              
    1072             sub _request {
    1073 0     0   0 my ($self, $url) = @_;
    1074            
    1075             # Sanity checks
    1076 0 0       0 die "Please pass a url to _request" if(!defined($url) );
    1077 0 0       0 croak "Please call new() before using the object\n" if( !$self );
    1078            
    1079 0 0       0 croak "Please login() before doing any other operations"
    1080             if( !$self->login_server() );
    1081            
    1082 0         0 my $request = HTTP::Request->new(GET => $url);
    1083              
    1084             # Place the saved cookie on the request HTTP Header
    1085 0         0 $self->{ cookie_jar }->add_cookie_header($request);
    1086              
    1087             # Actually send the request to the server
    1088 0         0 my $res = $self->{ ua }->request($request);
    1089            
    1090 0 0       0 croak "Cannot get $url"
    1091             if(!$res->is_success);
    1092            
    1093 0         0 return($res->content);
    1094             }
    1095              
    1096             =item _db_check_create( fields => fields_str )
    1097              
    1098             Check if the database exists and if it needs to be deleted/created before the
    1099             report is imported to the database.
    1100              
    1101             If the database file does not exist a new one is created and the two tables are
    1102             created within it.
    1103              
    1104             B => list_of_field_names
    1105              
    1106             String with the list of all the report fields (comma separated).
    1107              
    1108             B
    1109              
    1110             This is the table where all the report data will be stored. The fields of the
    1111             table are the same as the ones used in the Salesforce.com report, but with all
    1112             the characters that do not match 0-9, a-z or A-Z removed.
    1113             The database will have two tables (report and notifications) and optionally
    1114             an index (__report_index).
    1115              
    1116             B
    1117              
    1118             Table to store all report data. Fields are determined by the C parameter
    1119             all the types are C.
    1120             A C<__hash> fields is always added to the C table. This field will store
    1121             a MD5 hash of each report line, and can be used to create a C index if
    1122             you do not want repeated report lines in your local database.
    1123              
    1124             B
    1125              
    1126             Table to store notification data, for instance emails sent to users notifying
    1127             them about report data.
    1128              
    1129             B
    1130              
    1131             If C is false then an index will be created on the __hash
    1132             field of the reports table in order to guarantee no duplicate report line data
    1133             is stored in the database.
    1134              
    1135             Example:
    1136              
    1137             $self->_db_check_create( fields => "OpportunityOwner, Amount, Probability" );
    1138              
    1139             =cut
    1140              
    1141             sub _db_check_create {
    1142 1     1   3 my ($self, %options) = @_;
    1143            
    1144             # Sanity checks
    1145 1 50       4 croak "Please call new() before using the object\n" if( !$self );
    1146            
    1147             croak "Please pass a Salesforce.com Report Id, or local file,"
    1148             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    1149 1 50 33     8 if( !$self->{ id } && !$self->{ file } );
    1150            
    1151             croak "Please pass a list of fields to _db_check_create()\n"
    1152 1 50       3 if( !$options{ fields } );
    1153            
    1154 1 50       2 die 'Local cache only supports "csv" format, in _db_check_create()'
    1155             if( $self->format() !~ /csv/i);
    1156            
    1157             # Store the first line for data insertion
    1158 1         3 my $sql_fields = "__hash," . $options{ fields };
    1159            
    1160 1         9 my $db_name = $self->name();
    1161            
    1162             # Check if the user wants to erase the database each time we run
    1163 1 50 33     25 if( $self->{ erase_db } &&
    1164             -e $db_name) {
    1165            
    1166 0 0       0 unlink($db_name) or
    1167             die "Could not delete database: $db_name\n";
    1168            
    1169             print "Database $db_name deleted\n"
    1170 0 0       0 if( $self->{ verbose } );
    1171            
    1172             }
    1173            
    1174 1 50       16 if( !( -e $db_name) ) {
    1175             # Create the database if it does not exist
    1176            
    1177             # Create DB Table
    1178             # All data types are TEXT
    1179 1         3 $options{ fields } =~ s/"//g;
    1180 1         5 my @fields = split(/,/, $options{ fields });
    1181            
    1182 1         2 my $report_table = "CREATE TABLE report (__hash TEXT,";
    1183 1         2 my $notify_table = "CREATE TABLE notifications (";
    1184            
    1185 1 50       4 if( $self->{ primary_key } eq "__id" ) {
    1186 1         2 $report_table .= "__id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ";
    1187 1         2 $notify_table .= "__id INTEGER,timestamp TEXT, action TEXT,subject TEXT,note TEXT,sender TEXT,rcpt TEXT)";
    1188             }
    1189             else {
    1190            
    1191             # Check if the user primary key exists in the fields
    1192             croak "Bad primary key:$self->{ primary_key }, " .
    1193             "possilbe values are: $options{ fields }"
    1194 0 0       0 if( $options{ fields } !~ /$self->{ primary_key }/ );
    1195            
    1196             $notify_table .=
    1197             $self->{ primary_key } . " " .
    1198 0         0 $self->{ primary_key_type } . "," .
    1199             "timestamp TEXT, action TEXT,subject TEXT,note TEXT," .
    1200             "sender TEXT,rcpt TEXT)";
    1201              
    1202             }
    1203            
    1204             # append the report fields
    1205 1         45 foreach my $field ( @fields ) {
    1206 4 50       11 if( $field eq $self->{ primary_key } ) {
    1207 0         0 $report_table .=
    1208             "$field $self->{ primary_key_type } NOT NULL PRIMARY KEY,";
    1209             } else {
    1210 4         10 $report_table .= " $field TEXT,"
    1211             }
    1212             }
    1213            
    1214 1         3 chop($report_table);
    1215 1         1 $report_table .= ")";
    1216            
    1217             # Connect/Create the DB and create the table to store the report
    1218 1 0       13 my $dbh = DBI->connect("dbi:SQLite:dbname=$db_name","","") or
    1219             die "Database connection not made: $DBI::errstr";
    1220            
    1221 0 0       0 $dbh->do( $report_table ) or
    1222             die "Could not create database table reports: $DBI::errstr";
    1223            
    1224 0 0       0 $dbh->do( $notify_table ) or
    1225             die "Could not create database table notifications: $DBI::errstr";
    1226            
    1227             # Check if the user wants to allow duplicates in the db.
    1228             # If not create a unique index for the hash value
    1229 0 0       0 if( !$self->{ allow_duplicates } ) {
    1230            
    1231             print "Duplicates not allowed. Creating Unique index\n"
    1232 0 0       0 if( $self->{ verbose } );
    1233            
    1234 0         0 my $index;
    1235 0 0       0 if( $self->{ primary_key } eq "__id" ) {
    1236 0         0 $index = "CREATE UNIQUE INDEX __hash_index ON reports (__hash)";
    1237             }
    1238             else {
    1239 0         0 $index = "CREATE UNIQUE INDEX __report_index ON reports ($self->{ primary_key })";
    1240             }
    1241 0 0       0 $dbh->do( $index ) or
    1242             die "Could not create database index :$DBI::errstr";
    1243              
    1244             }
    1245            
    1246 0 0       0 $dbh->disconnect() or
    1247             die "Could not disconnect from database: $DBI::errstr";
    1248            
    1249             }
    1250            
    1251 0 0 0     0 if( $self->{ erase_reports_table } ||
    1252             $self->{ erase_notifications_table } ) {
    1253            
    1254 0 0       0 my $dbh = DBI->connect("dbi:SQLite:dbname=$db_name","","") or
    1255             die "Database connection not made: $DBI::errstr";
    1256            
    1257 0 0       0 if( $self->{ erase_reports_table } ) {
    1258            
    1259             print "All data in reports table deleted\n"
    1260 0 0       0 if( $self->{ verbose } );
    1261            
    1262 0 0       0 $dbh->do("DELETE FROM report") or
    1263             die "Could not delete data in the report table: $DBI::errstr";
    1264             }
    1265            
    1266 0 0       0 if( $self->{ erase_notifications_table } ) {
    1267            
    1268             print "All data in notifications table deleted\n"
    1269 0 0       0 if( $self->{ verbose } );
    1270            
    1271 0 0       0 $dbh->do("DELETE FROM notifications") or
    1272             die "Could not delete data in the notifications table: $DBI::errstr";
    1273             }
    1274            
    1275 0 0       0 $dbh->disconnect() or
    1276             die "Could not disconnect from database: $DBI::errstr";
    1277             }
    1278             }
    1279              
    1280             =item _dd($self, $mon, $day, $year)
    1281              
    1282             Convert the dates from mm/dd/yyyy to yyyy-mm-dd
    1283              
    1284             =cut
    1285              
    1286             sub _dd {
    1287 0     0   0 my ($s1, $s2, $s3) = @_;
    1288 0         0 return sprintf("%04d-%02d-%02d",$s3,$s1,$s2);
    1289             }
    1290              
    1291             =item _cache_report_to_sqlite( $data )
    1292              
    1293             Take the CSV formated $data and import it into the SQLite database.
    1294             The CSV must have all the fields in the first line of the file, be comma separated
    1295             data and all fields should be quoted with "
    1296              
    1297             Report data is imported into the C table in the database.
    1298              
    1299             =cut
    1300              
    1301             sub _cache_report_to_sqlite {
    1302 1     1   3 my ($self) =@_;
    1303            
    1304             # Sanity checks
    1305 1 50       4 croak "Please call new() before using the object\n" if( !$self );
    1306            
    1307             croak "Please pass a Salesforce.com Report Id, or local file,"
    1308             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    1309 1 50 33     8 if( !$self->{ id } && !$self->{ file } );
    1310            
    1311 1 50       4 die 'Local cache only supports "csv" format, in _db_check_create()'
    1312             if( $self->format() !~ /csv/i);
    1313            
    1314             croak "Call get_report() before calling _cache_report_to_sqlite"
    1315 1 50       4 if( !$self->{ data } );
    1316            
    1317             print "Writing report data to database\n"
    1318 1 50       5 if( $self->{ verbose } );
    1319            
    1320             print "Importing data.\n"
    1321 1 50       4 if( $self->{ verbose } );
    1322            
    1323 1         2 my $res = $self->{ data };
    1324            
    1325             #The first line has the field names lets fix them
    1326 1         4 $res =~ s/^[\s\t]+\n/_/sg; # replace spaces and tabs with '_'
    1327            
    1328             # get first line
    1329 1         3 $res =~ /(.*)/m;
    1330 1         4 my $first_line = $1;
    1331 1         5 $res =~ s/.*\n//m;
    1332              
    1333             # if the report is empty then there is only the first line, which has
    1334             # all the field names and no data.
    1335 1 50       4 if( $res eq $first_line ) {
    1336            
    1337             print "No new data to add to database\n"
    1338 0 0       0 if( $self->{ verbose } );
    1339 0         0 return 0;
    1340            
    1341             }
    1342              
    1343             # Convert the Field names so they only have letters and Numbers and no spaces
    1344 1         44 $first_line =~ s/[^,a-zA-Z0-9]*//g;
    1345            
    1346 1         6 my @fields = split(/,/,$first_line);
    1347 1         2 my $num_fields = $#fields;
    1348              
    1349             # Store the first line for data insertion
    1350 1         4 my $sql_fields = "__hash," . $first_line;
    1351            
    1352             # Create the DB and create the table to store the report
    1353 1         5 $self->_db_check_create( fields => $first_line );
    1354            
    1355             # Connect to the database
    1356            
    1357             $self->{ dbh } =
    1358 0 0       0 DBI->connect("dbi:SQLite:dbname=" . $self->{ name }, "", "")
    1359             or die "Database connection not made: $DBI::errstr";
    1360            
    1361             $self->query(query => $self->{ pre_import_query })
    1362 0 0       0 if( $self->{ pre_import_query } );
    1363            
    1364 0         0 my $sql = "INSERT INTO report (" . $sql_fields . ") VALUES (__MYVALUES__)";
    1365              
    1366             # Loop all the data lines
    1367 0         0 while( $res =~ /(.*)/gm) {
    1368             # in SFDC CSV exports all fields are quoted with " and separated with ,
    1369             # but the fields can have LF chars in them
    1370 0         0 my $line = $1;
    1371            
    1372 0 0       0 next if( $line eq "" );
    1373            
    1374 0 0       0 if( $self->{ convert_dates } ) {
    1375 0         0 $line =~ s/(\d{1,2})\/(\d{1,2})\/(\d{4})/$self->_dd($1,$2,$3)/ge;
      0         0  
    1376             }
    1377            
    1378             # hash the data so we don't do repeats
    1379 0         0 my $md5 = Digest::MD5->new;
    1380 0         0 $md5->add($line);
    1381 0         0 $line = "\"". $md5->hexdigest . "\"," . $line;
    1382            
    1383 0         0 my $tsql = $sql;
    1384 0         0 $tsql =~ s/__MYVALUES__/$line/;
    1385            
    1386 0 0       0 $self->{ dbh }->do($tsql) or
    1387             croak "Could not insert data into reports table>: $DBI::errstr\n";
    1388              
    1389             }
    1390              
    1391 0 0       0 $self->{ dbh }->disconnect() or
    1392             croak "Could not disconnect from Database: $DBI::errstr";
    1393            
    1394             print "Data imported into the reports table of " . $self->{ name } . "\n"
    1395 0 0       0 if( $self->{ verbose });
    1396            
    1397             $self->query(query => $self->{ post_import_query })
    1398 0 0       0 if( $self->{ post_import_query } );
    1399            
    1400 0         0 return 1;
    1401             }
    1402              
    1403             =item _set_name ( name => file_name, delete => 0 | 1)
    1404              
    1405             Set the name of the local cache database or file to which the report
    1406             data is saved.
    1407              
    1408             Optional Parameters:
    1409              
    1410             B => file_name
    1411              
    1412             Name of file to use. If C is not given the file's name is determined by
    1413             using the current report C, and local C, or C that were passed
    1414             to C.
    1415              
    1416             As in other methods the C option takes precedence over Salesforce.com
    1417             report C. Teh name is constructed by appending and extension to either the
    1418             C or C as follows
    1419              
    1420             Extensions and formats:
    1421             CSV -> name.db3
    1422             XLS -> name.xls
    1423              
    1424             B => 0 | 1
    1425              
    1426             If C is true the report data, and local cache file will be deleted
    1427             before the name change. Otherwise the file is left on disk. Default is true (1).
    1428              
    1429             =cut
    1430              
    1431             sub _set_name {
    1432 4     4   9 my($self, %options) = @_;
    1433            
    1434             # Sanity checks
    1435 4 50       10 croak "Please call new() before using the object\n" if( !$self );
    1436            
    1437             croak "Please pass a Salesforce.com Report Id, or local file,"
    1438             . "to WWW::Salesforce::Report->new() or by calling the report_id() method.\n"
    1439 4 50 66     23 if( !$self->{ id } && !$self->{ file } );
    1440            
    1441             # Delete the local fiel and report data?
    1442             $options{ delete } =1
    1443 4 50       15 if( !defined( $options{ delete }) );
    1444 4 50       10 if( $options{ delete } ) {
    1445            
    1446 4         12 $self->clean();
    1447            
    1448             }
    1449            
    1450             $options{ name } = ""
    1451 4 50       14 if( !defined( $options{ name }) );
    1452            
    1453 4 50       11 if( !$options{ name } ) {
    1454             # Calculate name from current report format and local file or
    1455             # Salesforce.com report id
    1456            
    1457             # Update local chache name
    1458 4 100       11 if( $self->{ file } ) {
        50          
    1459            
    1460             # local file must be in CSV
    1461 3         11 $self->{ name } = $self->{ file } . ".db3";
    1462            
    1463             }
    1464             elsif( $self->{ id } ) {
    1465            
    1466 1 50       6 if( $self->format() =~ /csv/i ) {
        0          
    1467 1         4 $self->{ name } = $self->{ id } . ".db3";
    1468             }
    1469             elsif( $self->format() =~ /xls/i ) {
    1470 0         0 $self->{ name } = $self->{ id } . ".xls";
    1471             }
    1472             else {
    1473 0         0 croak 'Bad file format. Format can only be "csv" or "xls".';
    1474             }
    1475              
    1476             }
    1477             else {
    1478            
    1479             croak 'Unkown report format: ' . $self->{ format } .
    1480 0         0 'Must be "csv" or "xls".\n';
    1481              
    1482             }
    1483            
    1484             }
    1485             else {
    1486 0         0 $self->{name} = $options{ name };
    1487             }
    1488            
    1489             die "Name was not set new()"
    1490 4 50       11 if( !$self->{ name } );
    1491            
    1492 4         15 return $self->{ name };
    1493             }
    1494              
    1495              
    1496             =item Destructor
    1497              
    1498             Object destructor will clean the local cache files format is CSV or XLS.
    1499              
    1500             =back
    1501              
    1502             =cut
    1503              
    1504             sub DESTROY {
    1505 5     5   3141 my $self = shift;
    1506            
    1507 5 50       21 return if( !$self );
    1508            
    1509 5 100       94 $self->clean() if( $self->{ clean_on_destroy } );
    1510             }
    1511              
    1512             =head1 AUTHOR
    1513              
    1514             Pedro Paixao, C<< >>
    1515              
    1516             =head1 BUGS
    1517              
    1518             Please report any bugs or feature requests to C, or through
    1519             the web interface at L. I will be notified, and then you'll
    1520             automatically be notified of progress on your bug as I make changes.
    1521              
    1522             =head1 SEE ALSO
    1523              
    1524             L
    1525              
    1526             =head1 SUPPORT
    1527              
    1528             You can find documentation for this module with the perldoc command.
    1529              
    1530             perldoc WWW::Salesforce::Report
    1531              
    1532              
    1533             You can also look for information at:
    1534              
    1535             =over 4
    1536              
    1537             =item * RT: CPAN's request tracker
    1538              
    1539             L
    1540              
    1541             =item * AnnoCPAN: Annotated CPAN documentation
    1542              
    1543             L
    1544              
    1545             =item * CPAN Ratings
    1546              
    1547             L
    1548              
    1549             =item * Search CPAN
    1550              
    1551             L
    1552              
    1553             =back
    1554              
    1555              
    1556             =head1 ACKNOWLEDGEMENTS
    1557              
    1558              
    1559             =head1 LICENSE AND COPYRIGHT
    1560              
    1561             Copyright 2010 Pedro Paixao.
    1562              
    1563             This program is free software; you can redistribute it and/or modify it
    1564             under the terms of either: the GNU General Public License as published
    1565             by the Free Software Foundation; or the Artistic License.
    1566              
    1567             See http://dev.perl.org/licenses/ for more information.
    1568              
    1569              
    1570             =cut
    1571              
    1572             1; # End of WWW::Salesforce::Report