File Coverage

blib/lib/Net/SugarCRM.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Net::SugarCRM;
2              
3 1     1   29811 use Moose;
  0            
  0            
4             use Log::Log4perl qw(:easy);
5             use LWP::UserAgent;
6             use DateTime;
7             use Time::HiRes;
8             use JSON;
9             use Data::Dumper;
10             use Readonly;
11             use Try::Tiny;
12             use HTTP::Request::Common;
13             use DBI;
14             use Carp qw(croak);
15             use Data::Dumper;
16             use Net::SugarCRM::Entry;
17              
18             BEGIN {
19             if(!(Log::Log4perl->initialized())) {
20             Log::Log4perl->easy_init($ERROR);
21             }
22             }
23              
24             Readonly our $LEADS => 'Leads';
25             Readonly our $NOTES => 'Notes';
26             Readonly our $ACCOUNTS => 'Accounts';
27             Readonly our $CONTACTS => 'Contacts';
28             Readonly our $OPPORTUNITIES => 'Opportunities';
29             Readonly our $CAMPAIGNS => 'Campaigns';
30             Readonly our $PROSPECTLISTS => 'ProspectLists';
31             Readonly our $EMAILMARKETINGS => 'EmailMarketing'; # email templates association
32             Readonly our $USERS => 'Users';
33             Readonly our $CURRENCIES => 'Currencies';
34              
35             =head1 NAME
36              
37             Net::SugarCRM - A simple module to access SugarCRM via Rest services
38              
39             =head1 VERSION
40              
41             Version $Revision: 23143 $
42              
43             =cut
44              
45             our $VERSION = sprintf "3.%05d", q$Revision: 23143 $ =~ /(\d+)/xg;
46              
47             =head1 DESCRIPTION
48              
49             This is a simple module to provision entries in SugarCRM via REST methods.
50              
51             This is for example to be able to provision contacts, leads, accounts via web services
52             and be able to integrate Sugar with other applications.
53              
54             See the Sugar Developer Guide for more info:
55              
56             http://developers.sugarcrm.com/docs/OS/6.2/-docs-Developer_Guides-Sugar_Developer_Guide_6.2.0-Sugar_Developer_Guide_6.2.1_ht
57             ml.html#9000412
58              
59             Most of the attributes values that you can use, you need to get them from the description
60             of the mysql tables leads, accounts, contacts, ...
61              
62             See also L<Net::SugarCRM::Tutorial>
63              
64              
65             =head2 Examples
66              
67             # Sometimes the encryption parameter seems necessary
68             # my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> md5_hex($Test::pass));
69             # or you have to encode the password as md5_hex
70             # my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
71             #
72            
73             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
74             my $lead_entry = {
75             email1 => 'batman@justiceleague.org',
76             salutation => 'Mr',
77             first_name => 'Bruce',
78             last_name => 'Wayne',
79             title => 'Detective',
80             account_name => 'Justice League of America',
81             department => 'Gotham city dep',
82             phone_work => '+1123123123',
83             website => 'http://justiceleagueofamerica.org',
84             };
85             my $leadid = $s->create_lead($lead_entry);
86             ...
87             my $account_entry = {
88             email1 => 'dc@dc.neverland',
89             name => 'DC Comics',
90             description => 'DC Comics is special...',
91             website => 'http://dccomics.neverland',
92             annual_revenue => '12345',
93             phone_office => '1123123124',
94             };
95             my $accountid = $s->create_account($account_entry);
96             my $account_entries_from_mail = $s->get_accounts_from_mail('dc@dc.neverland');
97             # this method croaks if you've got more the email more than once
98             my $accountid = $s->get_unique_account_id_from_mail($mail);
99             my $phone_office = $s->get_account_attribute($accountid, 'phone_office');
100             ...
101             my $mail = 'superman@justiceleague.org';
102             my $contact_entry = {
103             email1 => $mail,
104             salutation => 'Mr',
105             first_name => 'Clark',
106             last_name => 'Kent123',
107             title => 'SuperHero',
108             department => 'Metropolis dep',
109             phone_work => '+1123123124',
110             };
111             my $contactid = $s->create_contact($contact_entry);
112             my $opportunity_entry = {
113             name => 'My incredible opportunity',
114             description => 'This is the former DC Comics is special...',
115             amount => '12345',
116             sales_stage => 'Prospecting',
117             date_closed => '2011-12-31',
118             account_id => $accountid,
119             };
120             my $opportunityid = $s->create_opportunity($opportunity_entry);
121             my $query = 'opportunities.name = "My incredible opportunity"';
122             my $opid2 = $s->get_unique_opportunity_id($query);
123             ...
124             # Now try to send a campaign email bypassing previous sent emails
125             # For this you need to have access to the SugarCRM database to
126             # manipulate the campaign_log
127             $s->dsn('DBI:mysql:database=sugarcrm;host=localhost');
128             $s->dbuser($Test::testdbuser);
129             $s->dbpassword($Test::testdbpass);
130             # You need to have created the campaign, target list (prospect_list), and email_marketing
131             # entry and mail template
132             my $attrs = {
133             campaign_name => 'My Demo Campaign',
134             emailmarketing_name => 'Demo users send greetings',
135             prospectlist_name => 'Demo users',
136             related_type => 'Leads',
137             related_id => $leadid,
138             email => 'batman@justiceleague.org',
139             };
140              
141              
142              
143             =head1 ATTRIBUTES
144              
145             =cut
146              
147             =head2 url
148              
149             The default url to access, if not defined http://localhost/sugarcrm/service/v4/rest.php
150              
151             =cut
152              
153             has 'url' => ( is => 'rw', default => sub { 'http://localhost/sugarcrm/service/v4/rest.php' });
154              
155             =head2 restuser
156              
157             the username for login in the rest method
158              
159             =cut
160              
161             has 'restuser' => (is => 'rw', default => sub { '' });
162              
163             =head2 restpasswd
164              
165             the password for login in the rest method
166              
167             Sometimes the encryption parameter seems to be necessary to use plain password (See https://rt.cpan.org/Ticket/Display.html?id=93696), or you can manually encode the password as md5_hex, that is.
168              
169             $self->restpasswd(md5_hex('mypass'))
170              
171             =cut
172              
173             has 'restpasswd' => (is => 'rw', default => sub { '' });
174              
175             =head2 globalua
176              
177             The default useragent
178              
179             =cut
180              
181             has 'globalua' => ( is => 'rw', builder => '_buildUa');
182              
183             sub _buildUa {
184             my $self = shift;
185             my $globalua = LWP::UserAgent->new(
186             agent => "Net-SugarCRM/$VERSION",
187             keep_alive => 1,
188             );
189             $globalua->default_header('Accept' => 'application/json');
190             return $globalua;
191             }
192              
193             =head2 application
194              
195             The application name to be used for the rest method in sugar
196              
197             =cut
198              
199             has 'application' => ( is => 'rw', default => sub { 'net_sugarcrm' } );
200              
201             =head2 email_attr
202              
203             The SugarCRM attribute name for email
204              
205             =cut
206              
207             has 'email_attr' => (is => 'rw', default => sub { 'email1' });
208              
209             =head2 required_attr
210              
211             Hash reference to the required attrs for a lead, contact, account
212              
213             =cut
214              
215             has 'required_attr' =>
216             ( is => 'rw', default =>
217             sub {
218             my $ret_val = {
219             $LEADS => ['last_name', 'email1'],
220             $NOTES => ['name', 'description', 'parent_id', 'parent_type'],
221             $ACCOUNTS => ['name'],
222             $CONTACTS => ['last_name', 'email1'],
223             $OPPORTUNITIES => ['name', 'amount', 'sales_stage', 'account_id', 'date_closed'],
224             };
225             return $ret_val;
226             });
227              
228             has '_module_id_for_mail_search' =>
229             ( is => 'rw', default =>
230             sub {
231             my $ret_val = {
232             $LEADS => 'leads.id',
233             $ACCOUNTS => 'accounts.id',
234             $CONTACTS => 'contacts.id',
235             };
236             return $ret_val;
237             });
238             has '_module_id_for_prospect_list' =>
239             ( is => 'rw', default =>
240             sub {
241             my $ret_val = {
242             $LEADS => 'leads.id',
243             $CONTACTS => 'contacts.id',
244             $ACCOUNTS => 'accounts.id',
245             };
246             return $ret_val;
247             });
248              
249             has '_module_id_for_search' =>
250             ( is => 'rw', default =>
251             sub {
252             my $ret_val = {
253             $LEADS => 'leads.id',
254             $NOTES => 'notes.id',
255             $ACCOUNTS => 'accounts.id',
256             $CONTACTS => 'contacts.id',
257             $OPPORTUNITIES => 'opportunities.id',
258             $CAMPAIGNS => 'campaigns.id',
259             $PROSPECTLISTS => 'prospect_lists.id',
260             $EMAILMARKETINGS => 'email_marketing.id',
261             };
262             return $ret_val;
263             });
264              
265              
266             =head2 dsn
267              
268             Datasource Name: the configuration string for the database. For example:
269              
270             DBI:mysql:database=qvd;host=localhost
271              
272             =cut
273              
274             has 'dsn' => (is => 'rw', default => sub { 'DBI:mysql:database=theqvdsugarcrm;host=localhost' });
275              
276             =head2 dbuser
277              
278             the user to connect to the database
279              
280             =cut
281             has 'dbuser' => (is => 'rw', default => sub { '' } );
282              
283             =head2 dbpassword
284              
285             the password of user to connect to the database
286              
287             =cut
288             has 'dbpassword' => (is => 'rw', default => sub { '' } );
289              
290             =head2 dbh
291              
292             the database handler
293              
294             =cut
295             has 'dbh' => (is => 'rw', lazy => 1, builder => '_buildDbh');
296              
297             sub _buildDbh {
298             my $self = shift;
299             my $dbh = DBI->connect($self->dsn, $self->dbuser, $self->dbpassword, {RaiseError=>1});
300             return $dbh;
301             }
302              
303             has '_delete_sth' => (is => 'rw', lazy => 1, default => sub { my $self = shift; return $self->dbh->prepare('DELETE FROM campaign_log WHERE id = ?'); } );
304              
305             =head2 sessionid
306              
307             Returns the sessionid after the login. If it is not defined, it tries to do a login.
308              
309             =cut
310             has '_sessionid' => (is => 'rw');
311              
312             sub sessionid {
313             my ($self) = @_;
314             $self->login
315             if (!defined($self->_sessionid));
316             return $self->_sessionid;
317             }
318              
319             # Logger with a known, fixed category
320             has 'log' => (
321             is => 'rw',
322             lazy => 1,
323             default => sub { Log::Log4perl->get_logger },
324             );
325              
326             =head2 max_results
327              
328             The maximum number of results a get_entry_list returns. By default it is 1000
329              
330             =cut
331              
332             has 'max_results' => ( is => 'rw', default => sub { 1000 } );
333              
334             =head1 METHODS
335              
336              
337             =cut
338              
339              
340             # Input the method, and the rest_data
341             # Output response entry
342              
343             sub _rest_request {
344             my ($self, $method, $rest_data) = @_;
345              
346             my $res = $self->_rest_request_no_json($method, $rest_data);
347             my ($response, $msg) = try {
348             return(JSON->new->decode($res->content), 0);
349             } catch {
350             return({}, "SugarCRM internal error: ".$res->content);
351             };
352             if ($msg or (exists($$response{number}) && exists($$response{name}) &&
353             exists($$response{description}))) {
354             $msg = "Error getting id <".$res->status_line."> fetching ".Dumper($res->content)
355             unless $msg;
356             $self->log->logconfess($msg);
357             }
358             $self->log->debug("Success rest method <$method>\n");
359             return $response;
360             }
361              
362             sub _rest_request_no_json {
363             my ($self, $method, $rest_data) = @_;
364             my $req = POST($self->url, Accept=>'application/json', Content => [
365             method => $method,
366             input_type => 'json',
367             response_type => 'json',
368             rest_data => $rest_data
369             ]);
370              
371             my $res = $self->globalua->request($req);
372             if ($res->is_error) {
373             $self->log->logconfess("Error <".$res->status_line."> fetching ".Dumper($res->request));
374             }
375             return $res;
376             }
377              
378             =head2 Login/logout
379              
380             =head3 login
381              
382             login
383              
384             it uses the object attributes url, restuser and restpasswd for the login.
385             It returns the sessionid. And it also stores the sessionid in the object.
386             Normally you don't need to call this method it is implicitly called
387              
388             On some SugarCRM PRO it seems that it is needed to set $self->encryption('PLAIN')
389              
390             The code would be something like
391              
392             my $sugar = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
393             $sugar->encryption('PLAIN');
394             $sugar->login
395              
396             On error the method croaks
397              
398             =cut
399              
400             sub login {
401             my ($self) = @_;
402              
403             my $application = $self->application;
404             my $user_auth = {
405             user_name => $self->restuser,
406             password => $self->restpasswd
407             };
408              
409             $user_auth->{encryption} = $self->encryption if ($self->encryption);
410              
411             my $rest_data = encode_json({
412             user_auth => $user_auth,
413             application => $application});
414              
415             use Data::Dumper;
416             print STDERR Dumper($rest_data);
417              
418             my $response = $self->_rest_request('login', $rest_data);
419             my $sessionid=$response->{id};
420             $self->log->debug( "Successfully logged in for user ".$self->restuser."x with session id $sessionid");
421             $self->_sessionid($sessionid);
422             return $sessionid;
423             }
424              
425              
426             =head3 encryption
427              
428             encryption if set it will add the "encryption" parameter to the login service
429             REST message.
430              
431             The valid values currently are "PLAIN", although this is not enforced.
432             If it is undef, the parameter is not passed in the login method.
433              
434             =cut
435              
436             has encryption => ( is => 'rw', default => sub { undef } );
437              
438             =head3 logout
439              
440             Input: session id
441              
442             On error the method croaks. Normally you don't need to invoke this method it is implicitly called.
443              
444             =cut
445              
446             sub logout {
447             my ($self) = @_;
448              
449             if (!defined($self->_sessionid)) {
450             $self->log->error("logging out for user ".$self->restuser." which was not logged in, not doing anything");
451             return;
452             }
453             my $rest_data = encode_json({
454             session => $self->_sessionid,
455             });
456             my $res = try {
457             $self->_rest_request_no_json('logout', $rest_data);
458             } catch {
459             $self->log->error("Error in SugarCRM: method returned invalid JSON: $rest_data. $_");
460             };
461              
462             try {
463             if ($res->content ne 'null') {
464             $self->log->error("Error logging out user ".$self->restuser." <".$res->status_line."> fetching ".Dumper($res->content)) ;
465             } else {
466             # On DEMOLISH sometimes it does not exist
467             $self->log->debug( "Successfully logged out user ".$self->restuser." with session id ".$self->_sessionid);
468             $self->_sessionid(undef);
469             }
470             } catch {
471             $self->log->error("Error logging out user logout result is not defined:".Dumper($res)) ;
472             };
473              
474             return;
475             }
476              
477             =head2 Modules
478              
479             =head3 get_available_modules
480              
481             Input:
482              
483             * session id
484              
485             Output:
486              
487             * ref to an array of modules. On error the method croaks
488              
489             =cut
490              
491             sub get_available_modules {
492             my ($self) = @_;
493             my $rest_data = encode_json({
494             session => $self->sessionid,
495             });
496              
497             my $response = $self->_rest_request('get_available_modules', $rest_data);
498             return $response;
499             }
500              
501             =head3 get_module_fields
502              
503             Input:
504              
505             * Module names
506              
507             Output:
508             * ref to an array of modules. On error the method croaks
509              
510             =cut
511              
512             sub get_module_fields {
513             my ($self, $module_name) = @_;
514             my $rest_data = '{ "session": "'.$self->sessionid.'", "module_name": "'.$module_name.'" }';
515             my $response = $self->_rest_request('get_module_fields', $rest_data);
516             return $response;
517             }
518              
519              
520             =head2 Generic module methods
521              
522             =head3 create_module_entry
523              
524             Input:
525              
526             * Module name: Contacts, Accounts, Notes, Leads
527             * A hash reference of attributes for the entry. Valid values depend on the module name, ...
528              
529             Output:
530              
531             * The created id for the module entry. On error the method croaks
532              
533             =cut
534             sub create_module_entry {
535             my ($self, $module, $attributes) = @_;
536              
537             foreach my $required_attr (@{$self->required_attr->{$module}}) {
538             $self->log->logconfess("No $required_attr attribute. Not creating entry in $module for: ".Dumper($attributes))
539             if (!exists($$attributes{$required_attr}) ||
540             !defined($$attributes{$required_attr}) ||
541             $$attributes{$required_attr} eq '');
542             }
543              
544             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "name_value_list": '.
545             encode_json($attributes).
546             ',"track_view": "false" }';
547              
548             my $response = $self->_rest_request('set_entry', $rest_data);
549             $self->log->info( "Successfully created module entry $module <".encode_json($attributes)."> entry with sessionid ".$self->sessionid."\n");
550             $self->log->debug("Entry created in module $module was:".Dumper($response));
551             return $response->{id};
552             }
553              
554             =head3 get_module_entries
555              
556             Returns the entries for a given module, searching for an attribute
557              
558             Input:
559             * query string. This must be one of the valid attributes in the module or module_cstm table, for example for Leads these would be the leads or leads_cstm table. Examples (Note email1 does not work as a valid attribute although it works for create_lead):
560             "salutation = 'Mr'"
561             "first_name = 'Bruce'"
562             "last_name = 'Wayne'"
563             "title => 'Detective'"
564             "account_name = 'Justice League of America'"
565             "department = 'Gotham city dep'"
566             "phone_work = '+1123123123'"
567             "website = 'http://justiceleagueofamerica.org'"
568              
569             Output:
570              
571             * A reference to a an array of module entries,
572             [] if none found, and
573             confess on error
574            
575             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
576             my $lead_entries_from_mail = $s->get_module_entries('Leads', 'website = "http://justiceleagueofamerica.org"');
577             for my $l (@$lead_entries_from_mail) {
578             print Dumper($l);
579             }
580              
581             =cut
582              
583             sub get_module_entries {
584             my ($self, $module, $query) = @_;
585             $query =~ s/"/\\"/xg;
586             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "query": "'.$query.'", "order_by": "", "offset": "", "select_fields": "", "link_name_to_fields_array": "", "max_results": "'.$self->max_results.'" } ';
587             my $response = $self->_rest_request('get_entry_list', $rest_data);
588             $self->log->debug("Module entry for module $module with query <$query> found was:".Dumper($response));
589             if ($response->{total_count} == 0) {
590             $self->log->debug( "No entries found for module $module and query $query and sessionid ".$self->sessionid."\n");
591             return [];
592             }
593             $self->log->trace( "Successfully found entry for module $module for query $query and sessionid ".$self->sessionid."\n");
594              
595             return [map { Net::SugarCRM::Entry->new($_) } @{$response->{entry_list}}];
596             }
597              
598             =head3 get_module_ids
599              
600             Returns an array of module ids, searching for query see L<get_module_entries> for more info.
601              
602             Input:
603             * query
604             * module
605              
606             Output:
607              
608             * A reference to an array of module ids, and confess on error
609              
610             =cut
611              
612             sub get_module_ids {
613             my ($self, $module, $query) = @_;
614             my $entries = $self->get_module_entries($module, $query);
615             my @entriesids = map { $_->{id} } @$entries;
616             return \@entriesids;
617             }
618              
619             =head3 get_unique_module_id
620              
621             Returns the module id, searching for query $query
622             If none is found undef is returned, and if more than one is found
623             an error is issued.
624              
625             This method should only be used if you can garantee that you have only one
626             module entry for the given query
627              
628             Input:
629             * query (see L<get_module_entries> for more info)
630              
631             Output:
632              
633             * entry id found, 0 if none is found, and confess on error or if more than
634             one leadid is found.
635            
636              
637             =cut
638              
639             sub get_unique_module_id {
640             my ($self, $module, $query) = @_;
641             my $entries = $self->get_module_ids($module, $query);
642             return () if ($#$entries == -1);
643             $self->log->logconfess("More than one module entry is found for module $module searching for query $query")
644             if ($#$entries > 0);
645             return $entries->[0];
646             }
647              
648              
649             =head3 get_module_entry
650              
651             Returns the module entry, given a module name and a module id
652              
653             Input:
654             * module name
655             * id
656              
657             Output:
658              
659             * A module entry,
660             undef if none found, and
661             confess on error
662            
663             =cut
664              
665             sub get_module_entry {
666             my ($self, $module, $id) = @_;
667             if (!exists($self->_module_id_for_search->{$module})) {
668             $self->log->logconfess("The module $module cannot be used to search by ID");
669             }
670             $self->log->logconfess("ID is required") unless defined $id;
671             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "query": "'.$self->_module_id_for_search->{$module}.' = \"'.$id.'\"" } ';
672             my $response = $self->_rest_request('get_entry_list', $rest_data);
673             $self->log->debug("Module entry for module $module and id $id found was:".Dumper($response));
674             if ($response->{total_count} == 0) {
675             $self->log->debug( "No entries found found for id $id in module $module and sessionid ".$self->sessionid."\n");
676             return ();
677             }
678             $self->log->trace("Successfully found entry with for id $id in module $module and sessionid ".$self->sessionid."\n");
679              
680             return Net::SugarCRM::Entry->new($response->{entry_list}->[0]);
681             }
682              
683             =head3 get_module_attribute
684              
685             Returns the value of the attribute for a given module and module id,
686             If the attribute or module id is not found undef is returned.
687             On error the method confess
688              
689             Input:
690             * module name
691             * module id
692             * attribute name
693              
694             Output:
695              
696             * attribute value or undef (if the leadid is not found, the attribute does not exists)
697            
698             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
699             try {
700             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
701             if (!defined($lead_entry)) {
702             print "Not found\n";
703             } else {
704             print $s->get_module_attribute('Leads', $lead_entry, 'last_name');
705             }
706             } catch {
707             print "Error or more than one entry was found: $@";
708             }
709              
710             =cut
711              
712             sub get_module_attribute {
713             my ($self, $module, $id, $attribute) = @_;
714             my $entry = $self->get_module_entry($module, $id);
715             if (defined $entry && exists($entry->{name_value_list}{$attribute})) {
716             return $entry->{name_value_list}{$attribute}{value};
717             }
718             return ();
719             }
720              
721             =head3 get_module_entries_from_mail
722              
723             Returns the module ids, searching for mail
724              
725             Input:
726             * module name
727             * email address
728              
729             Output:
730              
731             * A reference to a an array of module entries,
732             [] if none found, and
733             confess on error, or the module does not searching by mail address
734              
735             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
736             my $lead_entries_from_mail = $s->get_module_entries_from_mail('Leads', 'batman@justiceleague.org');
737             for my $l (@$lead_entries_from_mail) {
738             print Dumper($l);
739             }
740              
741             =cut
742              
743             sub get_module_entries_from_mail {
744             my ($self, $module, $mail) = @_;
745             my $umail = uc $mail;
746             if (!exists($self->_module_id_for_mail_search->{$module})) {
747             $self->log->logconfess("The module $module cannot be used to search by mail address");
748             }
749             my $query = $self->_module_id_for_mail_search->{$module}.' in ( SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address_caps = "'.$umail.'")';
750             return $self->get_module_entries($module, $query);
751             }
752              
753             =head3 get_module_ids_from_mail
754              
755             Returns an array of module id, searching for mail
756              
757             Input:
758             * email address
759              
760             Output:
761              
762             * A reference to an array of module id, and confess on error
763              
764             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
765             my $lead_entries_from_mail = $s->get_module_ids_from_mail('Leads', 'batman@justiceleague.org');
766             for my $l (@$lead_entries_from_mail) {
767             print Dumper($l);
768             }
769            
770              
771             =cut
772              
773             sub get_module_ids_from_mail {
774             my ($self, $module, $mail) = @_;
775             my $entries = $self->get_module_entries_from_mail($module, $mail);
776             my @entriesids = map { $_->{id} } @$entries;
777             return \@entriesids;
778             }
779              
780             =head3 get_unique_module_id_from_mail
781              
782             Returns the module id, searching for mail
783             If none is found undef is returned, and if more than one is found
784             an error is issued.
785              
786             This method should only be used if you can garantee that you have only one
787             module entry with the same email address
788              
789             Input:
790             * email address
791              
792             Output:
793              
794             * module id found, 0 if none is found, and confess on error or if more than
795             one leadid is found.
796            
797             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
798             try {
799             my $lead_entry = $s->get_unique_module_id_from_mail('Leads', 'batman@justiceleague.org');
800             if (!defined($lead_entry)) {
801             print "Not found\n";
802             } else {
803             print "$lead_entry\n";
804             }
805             } catch {
806             print "Error or more than one entry was found: $@";
807             }
808              
809             =cut
810              
811             sub get_unique_module_id_from_mail {
812             my ($self, $module, $mail) = @_;
813             my $entries = $self->get_module_ids_from_mail($module, $mail);
814             return ()
815             if ($#$entries == -1);
816             $self->log->logconfess("More than one module entry is found searching for mail $mail and module $module")
817             if ($#$entries > 0);
818             return $entries->[0];
819             }
820              
821             =head3 delete_module_entry_by_id
822              
823             Deletes the module entry indicated by id
824              
825             Input:
826             * module name
827             * entry id
828              
829             Output:
830              
831             * 1 if the module id was modified, 0 if the id was not found and confess on error
832              
833             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
834             try {
835             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
836             if (!defined($lead_entry)) {
837             print "Not found\n";
838             } else {
839             $s->delete_module_entry_by_id('Leads', $lead_entry);
840             print "$lead_entry\n";
841             }
842             } catch {
843             print "Error or more than one entry was found: $@";
844             }
845              
846             =cut
847              
848             sub delete_module_entry_by_id {
849             my ($self, $module, $id) = @_;
850             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "name_value_list": { "id" : "'.$id.'", "deleted" : "1" } } ';
851             my $response = $self->_rest_request('set_entry', $rest_data);
852             $self->log->debug("Module entry in module $module deleted was:".Dumper($response));
853             if ($response->{id} ne $id) {
854             $self->log->info( "No entries updated found for module id $id module $module and sessionid ".$self->sessionid."\n");
855             return ();
856             }
857             $self->log->info( "Successfully deleted entry in module $module and id $id and sessionid ".$self->sessionid."\n");
858              
859             return 1;
860            
861             }
862              
863             =head3 get_module_link_ids
864              
865             Returns related ids for a given module, searching for an id
866              
867             Input:
868              
869             * module name
870             * link_field_name
871             * module id
872             * query (which might be empty)
873             * related_fields (which might be empty and if not it should be a reference to an array of fields). By default this is ["id"]
874              
875             Output:
876              
877             * A reference to an array of related ids
878              
879             Example: Get all the opportunity ids of account id $accountid
880              
881             my $ids = $s->get_module_link_ids("Accounts", "opportunities", $accountid);
882             print Dumper($ids);
883              
884              
885             =cut
886              
887             sub get_module_link_ids {
888             my ($self, $module, $link, $id, $query, $relatedfields) = @_;
889            
890             $query = '' if (!$query);
891             $relatedfields = [ 'id' ] if (ref $relatedfields ne 'ARRAY');
892             my $relatedfieldsjson;
893             {
894             local $Data::Dumper::Indent = 0;
895             local $Data::Dumper::Useqq = 1;
896             local $Data::Dumper::Terse = 1;
897             $relatedfieldsjson = Dumper($relatedfields);
898             }
899              
900             my $sessionid = $self->sessionid;
901             my $rest_data = qq({"session":"$sessionid","module_name":"$module","module_id":"$id","link_field_name":"$link","related_module_query":"$query","related_fields":$relatedfieldsjson});
902              
903             my $response = $self->_rest_request('get_relationships', $rest_data);
904             $self->log->debug("Module entry for module $module with id <$id> found was:".Dumper($response));
905              
906             my @entriesids = map { $_->{id} } @{$response->{entry_list}};
907             return \@entriesids;
908             }
909              
910             =head3 update_module_entry
911              
912             Updates the module entry attributes
913              
914             Input:
915             * module name
916             * module id
917             * A hash reference of attribute pairs. Example { website => 'http://newsite.org'}
918              
919             Output:
920              
921             * 1 if the id was modified, 0 if the id was not found and confess on error
922              
923             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
924             try {
925             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
926             if (!defined($lead_entry)) {
927             print "Not found\n";
928             } else {
929             $s->update_module_entry('Leads', $lead_entry, { website => 'http://newsite.org' });
930             print "$lead_entry\n";
931             }
932             } catch {
933             print "Error or more than one entry was found: $@";
934             }
935              
936             =cut
937              
938             sub update_module_entry {
939             my ($self, $module, $id, $attributes) = @_;
940             $$attributes{id} = $id;
941             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "name_value_list": '.
942             encode_json($attributes).
943             ' } ';
944             my $response = $self->_rest_request('set_entry', $rest_data);
945             $self->log->debug("Module entry updated for module $module was:".Dumper($response));
946             if ($response->{id} ne $id) {
947             $self->log->info( "No entries updated found for in module $module and id $id and sessionid ".$self->sessionid."\n");
948             return ();
949             }
950             $self->log->info( "Successfully updated entry in module $module with id $id and sessionid ".$self->sessionid.". Attributes: ".join(",", (%$attributes))."\n");
951              
952             return 1;
953            
954             }
955              
956             =head2 Lead
957              
958             Leads methods
959              
960             =head3 create_lead
961              
962             Input:
963              
964             * A hash reference of attributes for the Lead. Valid values are first_name, last_name, email1, account_name, title, department, phone_work, website, ...
965              
966             Output:
967              
968             * The created id for the lead
969              
970             On error the method confess
971              
972             Example:
973              
974             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
975             my $lead_entry = {
976             email1 => 'batman@justiceleague.org',
977             salutation => 'Mr',
978             first_name => 'Bruce',
979             last_name => 'Wayne',
980             title => 'Detective',
981             account_name => 'Justice League of America',
982             department => 'Gotham city dep',
983             phone_work => '+1123123123',
984             website => 'http://justiceleagueofamerica.org',
985             };
986            
987             my $leadid = $s->create_lead($lead_entry);
988              
989              
990             =cut
991              
992             sub create_lead {
993             my ($self, $attributes) = @_;
994              
995             return $self->create_module_entry($LEADS, $attributes);
996             }
997              
998              
999              
1000              
1001             =head3 get_leads
1002              
1003             Returns the lead entry, searching for an attribute
1004              
1005             Input:
1006             * query string. This must be one of the valid attributes in the leads or leads_cstm table. Examples (Note email1 does not work as a valid attribute although it works for create_lead):
1007             "salutation = 'Mr'"
1008             "first_name = 'Bruce'"
1009             "last_name = 'Wayne'"
1010             "title => 'Detective'"
1011             "account_name = 'Justice League of America'"
1012             "department = 'Gotham city dep'"
1013             "phone_work = '+1123123123'"
1014             "website = 'http://justiceleagueofamerica.org'"
1015              
1016             Output:
1017              
1018             * A reference to a an array of lead entries,
1019             [] if none found, and
1020             confess on error
1021            
1022             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1023             my $lead_entries_from_mail = $s->get_leads('website = "http://justiceleagueofamerica.org"');
1024             for my $l (@$lead_entries_from_mail) {
1025             print Dumper($l);
1026             }
1027              
1028             =cut
1029              
1030             sub get_leads {
1031             my ($self, $query) = @_;
1032             return $self->get_module_entries($LEADS, $query);
1033             }
1034              
1035              
1036             =head3 get_lead_ids
1037              
1038             Returns an array of lead id, searching for query see L<get_leads> for more info.
1039              
1040             Input:
1041             * query
1042              
1043             Output:
1044              
1045             * A reference to an array of lead id, and confess on error
1046              
1047             =cut
1048              
1049             sub get_lead_ids {
1050             my ($self, $query) = @_;
1051             return $self->get_module_ids($LEADS, $query);
1052             }
1053              
1054             =head3 get_unique_lead_id
1055              
1056             Returns the lead id, searching for query $query
1057             If none is found undef is returned, and if more than one is found
1058             an error is issued.
1059              
1060             This method should only be used if you can garantee that you have only one
1061             lead with the same email address
1062              
1063             Input:
1064             * query (see L<get_leads> for more info)
1065              
1066             Output:
1067              
1068             * leadid found, 0 if none is found, and confess on error or if more than
1069             one leadid is found.
1070            
1071              
1072             =cut
1073              
1074             sub get_unique_lead_id {
1075             my ($self, $query) = @_;
1076             return $self->get_unique_module_id($LEADS, $query);
1077             }
1078              
1079             =head3 get_lead
1080              
1081             Returns the lead entry, given an leadid
1082              
1083             Input:
1084             * leadid
1085              
1086             Output:
1087              
1088             * A lead entry,
1089             undef if none found, and
1090             confess on error
1091            
1092             =cut
1093              
1094             sub get_lead {
1095             my ($self, $leadid) = @_;
1096             return $self->get_module_entry($LEADS, $leadid);
1097             }
1098              
1099              
1100             =head3 get_lead_attribute
1101              
1102             Returns the value of the attribute for a given lead id,
1103             If the attribute or lead id is not found undef is returned.
1104              
1105             Input:
1106             * leadid
1107             * attribute name
1108              
1109             Output:
1110              
1111             * attribute value or undef (if the leadid is not found, the attribute does not exists)
1112            
1113             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1114             try {
1115             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
1116             if (!defined($lead_entry)) {
1117             print "Not found\n";
1118             } else {
1119             print $s->get_lead_attribute($lead_entry, 'last_name');
1120             }
1121             } catch {
1122             print "Error or more than one entry was found: $@";
1123             }
1124              
1125             =cut
1126              
1127             sub get_lead_attribute {
1128             my ($self, $leadid, $attribute) = @_;
1129             return $self->get_module_attribute($LEADS, $leadid, $attribute);
1130             }
1131              
1132             =head3 get_leads_from_mail
1133              
1134             Returns the lead id, searching for mail
1135              
1136             Input:
1137             * email address
1138              
1139             Output:
1140              
1141             * A reference to a an array of lead entries,
1142             [] if none found, and
1143             confess on error
1144            
1145             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1146             my $lead_entries_from_mail = $s->get_leads_from_mail('batman@justiceleague.org');
1147             for my $l (@$lead_entries_from_mail) {
1148             print Dumper($l);
1149             }
1150              
1151             =cut
1152              
1153             sub get_leads_from_mail {
1154             my ($self, $mail) = @_;
1155              
1156             return $self->get_module_entries_from_mail($LEADS, $mail);
1157             # my $umail = uc $mail;
1158             # my $query = 'leads.id in ( SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address_caps = "'.$umail.'")';
1159             # return $self->get_leads($query);
1160             }
1161              
1162             =head3 get_lead_ids_from_mail
1163              
1164             Returns an array of lead id, searching for mail
1165              
1166             Input:
1167             * email address
1168              
1169             Output:
1170              
1171             * A reference to an array of lead id, and confess on error
1172              
1173             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1174             my $lead_entries_from_mail = $s->get_lead_ids_from_mail('batman@justiceleague.org');
1175             for my $l (@$lead_entries_from_mail) {
1176             print Dumper($l);
1177             }
1178            
1179              
1180             =cut
1181              
1182             sub get_lead_ids_from_mail {
1183             my ($self, $mail) = @_;
1184             my $entries = $self->get_leads_from_mail($mail);
1185             my @entriesids = map { $_->{id} } @$entries;
1186             return \@entriesids;
1187             }
1188              
1189             =head3 get_unique_lead_id_from_mail
1190              
1191             Returns the lead id, searching for mail
1192             If none is found undef is returned, and if more than one is found
1193             an error is issued.
1194              
1195             This method should only be used if you can garantee that you have only one
1196             lead with the same email address
1197              
1198             Input:
1199             * email address
1200              
1201             Output:
1202              
1203             * leadid found, undef if none is found, and confess on error or if more than
1204             one leadid is found.
1205            
1206             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1207             try {
1208             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
1209             if (!defined($lead_entry)) {
1210             print "Not found\n";
1211             } else {
1212             print "$lead_entry\n";
1213             }
1214             } catch {
1215             print "Error or more than one entry was found: $@";
1216             }
1217              
1218             =cut
1219              
1220             sub get_unique_lead_id_from_mail {
1221             my ($self, $mail) = @_;
1222             return $self->get_unique_module_id_from_mail($LEADS, $mail);
1223             }
1224              
1225             =head3 delete_lead_by_id
1226              
1227             Deletes the leadid indicated by $id
1228              
1229             Input:
1230             * leadid
1231              
1232             Output:
1233              
1234             * 1 if the leadid was modified, 0 if no leadid was found and confess on error
1235              
1236             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1237             try {
1238             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
1239             if (!defined($lead_entry)) {
1240             print "Not found\n";
1241             } else {
1242             $s->delete_lead_by_id($lead_entry);
1243             print "$lead_entry\n";
1244             }
1245             } catch {
1246             print "Error or more than one entry was found: $@";
1247             }
1248              
1249             =cut
1250              
1251             sub delete_lead_by_id {
1252             my ($self, $leadid) = @_;
1253             return $self->delete_module_entry_by_id($LEADS, $leadid);
1254             }
1255              
1256             =head3 update_lead
1257              
1258             Updates the lead attributes
1259              
1260             Input:
1261             * leadid
1262             * A hash reference of attribute pairs. Example { website => 'http://newsite.org'}
1263              
1264             Output:
1265              
1266             * 1 if the leadid was modified, 0 if no leadid was found and confess on error
1267              
1268             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1269             try {
1270             my $lead_entry = $s->get_unique_lead_id_from_mail('batman@justiceleague.org');
1271             if (!defined($lead_entry)) {
1272             print "Not found\n";
1273             } else {
1274             $s->update_lead($lead_entry, { website => 'http://newsite.org' });
1275             print "$lead_entry\n";
1276             }
1277             } catch {
1278             print "Error or more than one entry was found: $@";
1279             }
1280              
1281             =cut
1282              
1283             sub update_lead {
1284             my ($self, $leadid, $attributes) = @_;
1285             return $self->update_module_entry($LEADS, $leadid, $attributes);
1286             }
1287              
1288              
1289             =head2 Contacts
1290              
1291             Contacts methods
1292              
1293             =head3 create_contact
1294              
1295             Input:
1296              
1297             * A hash reference of attributes for the Contact. Valid values are first_name, last_name, email1, ...
1298              
1299             To reference it to an account include the attribute "account_id" pointing it to an account.
1300              
1301             Output:
1302              
1303             * The created id for the contact
1304              
1305             On error the method confess
1306              
1307             =cut
1308              
1309             sub create_contact {
1310             my ($self, $attributes) = @_;
1311             return $self->create_module_entry($CONTACTS, $attributes);
1312             }
1313              
1314             =head3 get_contacts
1315              
1316             Returns the contact entry, searching for an attribute
1317              
1318             Input:
1319             * query string. This must be one of the valid attributes in the contacts or contacts_cstm table. Examples (Note email1 does not work as a valid attribute although it works for create_contact):
1320             "salutation = 'Mr'"
1321             "first_name = 'Bruce'"
1322             "last_name = 'Wayne'"
1323             "title => 'Detective'"
1324             "account_name = 'Justice League of America'"
1325             "department = 'Gotham city dep'"
1326             "phone_work = '+1123123123'"
1327             "website = 'http://justiceleagueofamerica.org'"
1328              
1329             Output:
1330              
1331             * A reference to a an array of contact entries,
1332             [] if none found, and
1333             confess on error
1334            
1335             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1336             my $contact_entries_from_mail = $s->get_contacts('website = "http://justiceleagueofamerica.org"');
1337             for my $l (@$contact_entries_from_mail) {
1338             print Dumper($l);
1339             }
1340              
1341             =cut
1342              
1343             sub get_contacts {
1344             my ($self, $query) = @_;
1345             return $self->get_module_entries($CONTACTS, $query);
1346             }
1347              
1348              
1349             =head3 get_contact_ids
1350              
1351             Returns an array of contact id, searching for query see L<get_contacts> for more info.
1352              
1353             Input:
1354             * query
1355              
1356             Output:
1357              
1358             * A reference to an array of contact id, and confess on error
1359              
1360             =cut
1361              
1362             sub get_contact_ids {
1363             my ($self, $query) = @_;
1364             return $self->get_module_ids($CONTACTS, $query);
1365             }
1366              
1367             =head3 get_unique_contact_id
1368              
1369             Returns the contact id, searching for query $query
1370             If none is found undef is returned, and if more than one is found
1371             an error is issued.
1372              
1373             This method should only be used if you can garantee that you have only one
1374             contact with the same email address
1375              
1376             Input:
1377             * query (see L<get_contacts> for more info)
1378              
1379             Output:
1380              
1381             * contactid found, 0 if none is found, and confess on error or if more than
1382             one contactid is found.
1383            
1384              
1385             =cut
1386              
1387             sub get_unique_contact_id {
1388             my ($self, $query) = @_;
1389             return $self->get_unique_module_id($CONTACTS, $query);
1390             }
1391              
1392             =head3 get_contact
1393              
1394             Returns the contact entry, given an contactid
1395              
1396             Input:
1397             * contactid
1398              
1399             Output:
1400              
1401             * A contact entry,
1402             undef if none found, and
1403             confess on error
1404            
1405             =cut
1406              
1407             sub get_contact {
1408             my ($self, $contactid) = @_;
1409             return $self->get_module_entry($CONTACTS, $contactid);
1410             }
1411              
1412              
1413             =head3 get_contact_attribute
1414              
1415             Returns the value of the attribute for a given contact id,
1416             If the attribute or contact id is not found undef is returned.
1417              
1418             Input:
1419             * contactid
1420             * attribute name
1421              
1422             Output:
1423              
1424             * attribute value or undef (if the contactid is not found, the attribute does not exists)
1425            
1426             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1427             try {
1428             my $contact_entry = $s->get_unique_contact_id_from_mail('batman@justiceleague.org');
1429             if (!defined($contact_entry)) {
1430             print "Not found\n";
1431             } else {
1432             print $s->get_contact_attribute($contact_entry, 'last_name');
1433             }
1434             } catch {
1435             print "Error or more than one entry was found: $@";
1436             }
1437              
1438             =cut
1439              
1440             sub get_contact_attribute {
1441             my ($self, $contactid, $attribute) = @_;
1442             return $self->get_module_attribute($CONTACTS, $contactid, $attribute);
1443             }
1444              
1445             =head3 get_contacts_from_mail
1446              
1447             Returns the contact id, searching for mail
1448              
1449             Input:
1450             * email address
1451              
1452             Output:
1453              
1454             * A reference to a an array of contact entries,
1455             [] if none found, and
1456             confess on error
1457            
1458             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1459             my $contact_entries_from_mail = $s->get_contacts_from_mail('batman@justiceleague.org');
1460             for my $l (@$contact_entries_from_mail) {
1461             print Dumper($l);
1462             }
1463              
1464             =cut
1465              
1466             sub get_contacts_from_mail {
1467             my ($self, $mail) = @_;
1468              
1469             return $self->get_module_entries_from_mail($CONTACTS, $mail);
1470             # my $umail = uc $mail;
1471             # my $query = 'contacts.id in ( SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address_caps = "'.$umail.'")';
1472             # return $self->get_contacts($query);
1473             }
1474              
1475             =head3 get_contact_ids_from_mail
1476              
1477             Returns an array of contact id, searching for mail
1478              
1479             Input:
1480             * email address
1481              
1482             Output:
1483              
1484             * A reference to an array of contact id, and confess on error
1485              
1486             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1487             my $contact_entries_from_mail = $s->get_contact_ids_from_mail('batman@justiceleague.org');
1488             for my $l (@$contact_entries_from_mail) {
1489             print Dumper($l);
1490             }
1491            
1492              
1493             =cut
1494              
1495             sub get_contact_ids_from_mail {
1496             my ($self, $mail) = @_;
1497             my $entries = $self->get_contacts_from_mail($mail);
1498             my @entriesids = map { $_->{id} } @$entries;
1499             return \@entriesids;
1500             }
1501              
1502             =head3 get_unique_contact_id_from_mail
1503              
1504             Returns the contact id, searching for mail
1505             If none is found undef is returned, and if more than one is found
1506             an error is issued.
1507              
1508             This method should only be used if you can garantee that you have only one
1509             contact with the same email address
1510              
1511             Input:
1512             * email address
1513              
1514             Output:
1515              
1516             * contactid found, 0 if none is found, and confess on error or if more than
1517             one contactid is found.
1518            
1519             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1520             try {
1521             my $contact_entry = $s->get_unique_contact_id_from_mail('batman@justiceleague.org');
1522             if (!defined($contact_entry)) {
1523             print "Not found\n";
1524             } else {
1525             print "$contact_entry\n";
1526             }
1527             } catch {
1528             print "Error or more than one entry was found: $@";
1529             }
1530              
1531             =cut
1532              
1533             sub get_unique_contact_id_from_mail {
1534             my ($self, $mail) = @_;
1535             return $self->get_unique_module_id_from_mail($CONTACTS, $mail);
1536             }
1537              
1538             =head3 get_contact_account_ids
1539              
1540             Find all accounts associated with the specified contact
1541              
1542             Input:
1543              
1544             * contactid
1545              
1546             Output:
1547              
1548             * A reference to an array of account ids
1549              
1550             =cut
1551              
1552             sub get_contact_account_ids {
1553             my ($self, $id) = @_;
1554             return $self->get_module_link_ids($CONTACTS, 'accounts', $id);
1555             }
1556              
1557              
1558             =head3 delete_contact_by_id
1559              
1560             Deletes the contactid indicated by $id
1561              
1562             Input:
1563             * contactid
1564              
1565             Output:
1566              
1567             * 1 if the contactid was modified, 0 if no contactid was found and confess on error
1568              
1569             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1570             try {
1571             my $contact_entry = $s->get_unique_contact_id_from_mail('batman@justiceleague.org');
1572             if (!defined($contact_entry)) {
1573             print "Not found\n";
1574             } else {
1575             $s->delete_contact_by_id($contact_entry);
1576             print "$contact_entry\n";
1577             }
1578             } catch {
1579             print "Error or more than one entry was found: $@";
1580             }
1581              
1582             =cut
1583              
1584             sub delete_contact_by_id {
1585             my ($self, $contactid) = @_;
1586             return $self->delete_module_entry_by_id($CONTACTS, $contactid);
1587             }
1588              
1589             =head3 update_contact
1590              
1591             Updates the contact attributes
1592              
1593             Input:
1594             * contactid
1595             * A hash reference of attribute pairs. Example { website => 'http://newsite.org'}
1596              
1597             Output:
1598              
1599             * 1 if the contactid was modified, 0 if no contactid was found and confess on error
1600              
1601             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1602             try {
1603             my $contact_entry = $s->get_unique_contact_id_from_mail('batman@justiceleague.org');
1604             if (!defined($contact_entry)) {
1605             print "Not found\n";
1606             } else {
1607             $s->update_contact($contact_entry, { website => 'http://newsite.org' });
1608             print "$contact_entry\n";
1609             }
1610             } catch {
1611             print "Error or more than one entry was found: $@";
1612             }
1613              
1614             =cut
1615              
1616             sub update_contact {
1617             my ($self, $contactid, $attributes) = @_;
1618             return $self->update_module_entry($CONTACTS, $contactid, $attributes);
1619             }
1620              
1621              
1622             =head2 Accounts
1623              
1624             Accounts methods
1625              
1626             =head3 create_account
1627              
1628             Input:
1629              
1630             * A hash reference of attributes for the Account. Valid values are first_name, last_name, email1, ...
1631              
1632             To reference it to an account include the attribute "account_id" pointing it to an account.
1633              
1634             Output:
1635              
1636             * The created id for the account
1637              
1638             On error the method confess
1639              
1640             =cut
1641              
1642             sub create_account {
1643             my ($self, $attributes) = @_;
1644             return $self->create_module_entry($ACCOUNTS, $attributes);
1645             }
1646              
1647             =head3 get_accounts
1648              
1649             Returns the account entry, searching for an attribute
1650              
1651             Input:
1652             * query string. This must be one of the valid attributes in the accounts or accounts_cstm table. Examples (Note email1 does not work as a valid attribute although it works for create_account):
1653             "salutation = 'Mr'"
1654             "first_name = 'Bruce'"
1655             "last_name = 'Wayne'"
1656             "title => 'Detective'"
1657             "account_name = 'Justice League of America'"
1658             "department = 'Gotham city dep'"
1659             "phone_work = '+1123123123'"
1660             "website = 'http://justiceleagueofamerica.org'"
1661              
1662             Output:
1663              
1664             * A reference to a an array of account entries,
1665             [] if none found, and
1666             confess on error
1667            
1668             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1669             my $account_entries_from_mail = $s->get_accounts('website = "http://justiceleagueofamerica.org"');
1670             for my $l (@$account_entries_from_mail) {
1671             print Dumper($l);
1672             }
1673              
1674             =cut
1675              
1676             sub get_accounts {
1677             my ($self, $query) = @_;
1678             return $self->get_module_entries($ACCOUNTS, $query);
1679             }
1680              
1681              
1682             =head3 get_account_ids
1683              
1684             Returns an array of account id, searching for query see L<get_accounts> for more info.
1685              
1686             Input:
1687             * query
1688              
1689             Output:
1690              
1691             * A reference to an array of account id, and confess on error
1692              
1693             =cut
1694              
1695             sub get_account_ids {
1696             my ($self, $query) = @_;
1697             return $self->get_module_ids($ACCOUNTS, $query);
1698             }
1699              
1700             =head3 get_unique_account_id
1701              
1702             Returns the account id, searching for query $query
1703             If none is found undef is returned, and if more than one is found
1704             an error is issued.
1705              
1706             This method should only be used if you can garantee that you have only one
1707             account with the same email address
1708              
1709             Input:
1710             * query (see L<get_accounts> for more info)
1711              
1712             Output:
1713              
1714             * accountid found, 0 if none is found, and confess on error or if more than
1715             one accountid is found.
1716            
1717              
1718             =cut
1719              
1720             sub get_unique_account_id {
1721             my ($self, $query) = @_;
1722             return $self->get_unique_module_id($ACCOUNTS, $query);
1723             }
1724              
1725             =head3 get_account
1726              
1727             Returns the account entry, given an accountid
1728              
1729             Input:
1730             * accountid
1731              
1732             Output:
1733              
1734             * A account entry,
1735             undef if none found, and
1736             confess on error
1737            
1738             =cut
1739              
1740             sub get_account {
1741             my ($self, $accountid) = @_;
1742             return $self->get_module_entry($ACCOUNTS, $accountid);
1743             }
1744              
1745              
1746             =head3 get_account_attribute
1747              
1748             Returns the value of the attribute for a given account id,
1749             If the attribute or account id is not found undef is returned.
1750              
1751             Input:
1752             * accountid
1753             * attribute name
1754              
1755             Output:
1756              
1757             * attribute value or undef (if the accountid is not found, the attribute does not exists)
1758            
1759             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1760             try {
1761             my $account_entry = $s->get_unique_account_id_from_mail('batman@justiceleague.org');
1762             if (!defined($account_entry)) {
1763             print "Not found\n";
1764             } else {
1765             print $s->get_account_attribute($account_entry, 'last_name');
1766             }
1767             } catch {
1768             print "Error or more than one entry was found: $@";
1769             }
1770              
1771             =cut
1772              
1773             sub get_account_attribute {
1774             my ($self, $accountid, $attribute) = @_;
1775             return $self->get_module_attribute($ACCOUNTS, $accountid, $attribute);
1776             }
1777              
1778             =head3 get_accounts_from_mail
1779              
1780             Returns the account id, searching for mail
1781              
1782             Input:
1783             * email address
1784              
1785             Output:
1786              
1787             * A reference to a an array of account entries,
1788             [] if none found, and
1789             confess on error
1790            
1791             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1792             my $account_entries_from_mail = $s->get_accounts_from_mail('batman@justiceleague.org');
1793             for my $l (@$account_entries_from_mail) {
1794             print Dumper($l);
1795             }
1796              
1797             =cut
1798              
1799             sub get_accounts_from_mail {
1800             my ($self, $mail) = @_;
1801              
1802             return $self->get_module_entries_from_mail($ACCOUNTS, $mail);
1803             # my $umail = uc $mail;
1804             # my $query = 'accounts.id in ( SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address_caps = "'.$umail.'")';
1805             # return $self->get_accounts($query);
1806             }
1807              
1808             =head3 get_account_ids_from_mail
1809              
1810             Returns an array of account id, searching for mail
1811              
1812             Input:
1813             * email address
1814              
1815             Output:
1816              
1817             * A reference to an array of account id, and confess on error
1818              
1819             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1820             my $account_entries_from_mail = $s->get_account_ids_from_mail('batman@justiceleague.org');
1821             for my $l (@$account_entries_from_mail) {
1822             print Dumper($l);
1823             }
1824            
1825              
1826             =cut
1827              
1828             sub get_account_ids_from_mail {
1829             my ($self, $mail) = @_;
1830             my $entries = $self->get_accounts_from_mail($mail);
1831             my @entriesids = map { $_->{id} } @$entries;
1832             return \@entriesids;
1833             }
1834              
1835             =head3 get_unique_account_id_from_mail
1836              
1837             Returns the account id, searching for mail
1838             If none is found undef is returned, and if more than one is found
1839             an error is issued.
1840              
1841             This method should only be used if you can garantee that you have only one
1842             account with the same email address
1843              
1844             Input:
1845             * email address
1846              
1847             Output:
1848              
1849             * accountid found, 0 if none is found, and confess on error or if more than
1850             one accountid is found.
1851            
1852             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1853             try {
1854             my $account_entry = $s->get_unique_account_id_from_mail('batman@justiceleague.org');
1855             if (!defined($account_entry)) {
1856             print "Not found\n";
1857             } else {
1858             print "$account_entry\n";
1859             }
1860             } catch {
1861             print "Error or more than one entry was found: $@";
1862             }
1863              
1864             =cut
1865              
1866             sub get_unique_account_id_from_mail {
1867             my ($self, $mail) = @_;
1868             return $self->get_unique_module_id_from_mail($ACCOUNTS, $mail);
1869             }
1870              
1871             =head3 get_account_contact_ids
1872              
1873             Find all contacts associated with the specified account
1874              
1875             Input:
1876              
1877             * accountid
1878              
1879             Output:
1880              
1881             * A reference to an array of contact ids
1882              
1883             =cut
1884              
1885             sub get_account_contact_ids {
1886             my ($self, $id) = @_;
1887             return $self->get_module_link_ids($ACCOUNTS, 'contacts', $id);
1888             }
1889              
1890             =head3 delete_account_by_id
1891              
1892             Deletes the accountid indicated by $id
1893              
1894             Input:
1895             * accountid
1896              
1897             Output:
1898              
1899             * 1 if the accountid was modified, 0 if no accountid was found and confess on error
1900              
1901             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1902             try {
1903             my $account_entry = $s->get_unique_account_id_from_mail('batman@justiceleague.org');
1904             if (!defined($account_entry)) {
1905             print "Not found\n";
1906             } else {
1907             $s->delete_account_by_id($account_entry);
1908             print "$account_entry\n";
1909             }
1910             } catch {
1911             print "Error or more than one entry was found: $@";
1912             }
1913              
1914             =cut
1915              
1916             sub delete_account_by_id {
1917             my ($self, $accountid) = @_;
1918             return $self->delete_module_entry_by_id($ACCOUNTS, $accountid);
1919             }
1920              
1921             =head3 update_account
1922              
1923             Updates the account attributes
1924              
1925             Input:
1926             * accountid
1927             * A hash reference of attribute pairs. Example { website => 'http://newsite.org'}
1928              
1929             Output:
1930              
1931             * 1 if the accountid was modified, 0 if no accountid was found and confess on error
1932              
1933             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
1934             try {
1935             my $account_entry = $s->get_unique_account_id_from_mail('batman@justiceleague.org');
1936             if (!defined($account_entry)) {
1937             print "Not found\n";
1938             } else {
1939             $s->update_account($account_entry, { website => 'http://newsite.org' });
1940             print "$account_entry\n";
1941             }
1942             } catch {
1943             print "Error or more than one entry was found: $@";
1944             }
1945              
1946             =cut
1947              
1948             sub update_account {
1949             my ($self, $accountid, $attributes) = @_;
1950             return $self->update_module_entry($ACCOUNTS, $accountid, $attributes);
1951             }
1952              
1953              
1954             =head2 Currency
1955              
1956             Currency methods
1957              
1958             =head3 create_currency
1959              
1960             Input:
1961              
1962             * A hash reference of attributes for the Currency. Valid values are name, symbol, iso4217, conversion_rate
1963              
1964             Output:
1965              
1966             * The created id for the currency
1967              
1968              
1969             =cut
1970              
1971             sub create_currency {
1972             my ($self, $attributes) = @_;
1973             return $self->create_module_entry($CURRENCIES, $attributes);
1974             }
1975              
1976              
1977             =head3 get_currencies
1978              
1979             Returns the currency entry, searching for an attribute
1980              
1981             Input:
1982             * query string. This must be one of the valid attributes in the currencies or currencies_cstm table.
1983             Output:
1984              
1985             * A reference to a an array of currency entries,
1986             [] if none found, and
1987             confess on error
1988            
1989              
1990             =cut
1991              
1992             sub get_currencies {
1993             my ($self, $query) = @_;
1994             return $self->get_module_entries($CURRENCIES, $query);
1995             }
1996              
1997              
1998             =head3 get_currency_ids
1999              
2000             Returns an array of currency id, searching for query see L<get_currencies> for more info.
2001              
2002             Input:
2003             * query
2004              
2005             Output:
2006              
2007             * A reference to an array of currency id, and confess on error
2008              
2009             =cut
2010              
2011             sub get_currency_ids {
2012             my ($self, $query) = @_;
2013             return $self->get_module_ids($CURRENCIES, $query);
2014             }
2015              
2016             =head3 get_unique_currency_id
2017              
2018             Returns the currency id, searching for query $query
2019             If none is found undef is returned, and if more than one is found
2020             an error is issued.
2021              
2022             This method should only be used if you can garantee that you have only one
2023             currency with the same email address
2024              
2025             Input:
2026             * query (see L<get_currencies> for more info)
2027              
2028             Output:
2029              
2030             * currencyid found, 0 if none is found, and confess on error or if more than
2031             one currencyid is found.
2032            
2033              
2034             =cut
2035              
2036             sub get_unique_currency_id {
2037             my ($self, $query) = @_;
2038             return $self->get_unique_module_id($CURRENCIES, $query);
2039             }
2040              
2041             =head3 get_currency
2042              
2043             Returns the currency entry, given an currencyid
2044              
2045             Input:
2046             * currencyid
2047              
2048             Output:
2049              
2050             * A currency entry,
2051             undef if none found, and
2052             confess on error
2053            
2054             =cut
2055              
2056             sub get_currency {
2057             my ($self, $currencyid) = @_;
2058             return $self->get_module_entry($CURRENCIES, $currencyid);
2059             }
2060              
2061              
2062             =head3 get_currency_attribute
2063              
2064             Returns the value of the attribute for a given currency id,
2065             If the attribute or currency id is not found undef is returned.
2066              
2067             Input:
2068             * currencyid
2069             * attribute name
2070              
2071             Output:
2072              
2073             * attribute value or undef (if the currencyid is not found, the attribute does not exists)
2074            
2075              
2076             =cut
2077              
2078             sub get_currency_attribute {
2079             my ($self, $currencyid, $attribute) = @_;
2080             return $self->get_module_attribute($CURRENCIES, $currencyid, $attribute);
2081             }
2082              
2083             =head3 delete_currency_by_id
2084              
2085             Deletes the currencyid indicated by $id
2086              
2087             Input:
2088             * currencyid
2089              
2090             Output:
2091              
2092             * 1 if the currencyid was modified, 0 if no currencyid was found and confess on error
2093              
2094             =cut
2095              
2096             sub delete_currency_by_id {
2097             my ($self, $currencyid) = @_;
2098             return $self->delete_module_entry_by_id($CURRENCIES, $currencyid);
2099             }
2100              
2101             =head3 update_currency
2102              
2103             Updates the currency attributes
2104              
2105             Input:
2106             * currencyid
2107             * A hash reference of attribute pairs. Example { website => 'http://newsite.org'}
2108              
2109             Output:
2110              
2111             * 1 if the currencyid was modified, 0 if no currencyid was found and confess on error
2112              
2113             =cut
2114              
2115             sub update_currency {
2116             my ($self, $currencyid, $attributes) = @_;
2117             return $self->update_module_entry($CURRENCIES, $currencyid, $attributes);
2118             }
2119              
2120              
2121              
2122              
2123              
2124             =head2 Opportunity
2125              
2126             Opportunity methods
2127              
2128             =head3 create_opportunity
2129              
2130             Input:
2131              
2132             * A hash reference of attributes for the Opportunity. Valid values are first_name, last_name, email1, ...
2133              
2134             To reference it to an opportunity include the attribute "opportunity_id" pointing it to an opportunity.
2135              
2136             Output:
2137              
2138             * The created id for the opportunity
2139              
2140             On error the method confess
2141              
2142             my $opportunity_entry = {
2143             name => 'My incredible opportunity',
2144             description => 'This is the former DC Comics is special...',
2145             amount => '12345',
2146             sales_stage => 'Prospecting',
2147             date_closed => '2011-12-31',
2148             account_id => $accountid,
2149             };
2150             my $opportunityid2 = $s->create_opportunity($opportunity_entry);
2151              
2152             =cut
2153              
2154             sub create_opportunity {
2155             my ($self, $attributes) = @_;
2156             return $self->create_module_entry($OPPORTUNITIES, $attributes);
2157             }
2158              
2159             =head3 get_opportunities
2160              
2161             Returns the opportunity entry, searching for an attribute
2162              
2163             Input:
2164             * query string. This must be one of the valid attributes in the opportunities or opportunities_cstm table. Examples (Note email1 does not work as a valid attribute although it works for create_opportunity):
2165             "salutation = 'Mr'"
2166             "first_name = 'Bruce'"
2167             "last_name = 'Wayne'"
2168             "title => 'Detective'"
2169             "opportunity_name = 'Justice League of America'"
2170             "department = 'Gotham city dep'"
2171             "phone_work = '+1123123123'"
2172             "website = 'http://justiceleagueofamerica.org'"
2173              
2174             Output:
2175              
2176             * A reference to a an array of opportunity entries,
2177             [] if none found, and
2178             confess on error
2179            
2180             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2181             my $opportunity_entries_from_mail = $s->get_opportunities('website = "http://justiceleagueofamerica.org"');
2182             for my $l (@$opportunity_entries_from_mail) {
2183             print Dumper($l);
2184             }
2185              
2186             =cut
2187              
2188             sub get_opportunities {
2189             my ($self, $query) = @_;
2190             return $self->get_module_entries($OPPORTUNITIES, $query);
2191             }
2192              
2193              
2194             =head3 get_opportunity_ids
2195              
2196             Returns an array of opportunity id, searching for query see L<get_opportunities> for more info.
2197              
2198             Input:
2199             * query
2200              
2201             Output:
2202              
2203             * A reference to an array of opportunity id, and confess on error
2204              
2205             =cut
2206              
2207             sub get_opportunity_ids {
2208             my ($self, $query) = @_;
2209             return $self->get_module_ids($OPPORTUNITIES, $query);
2210             }
2211              
2212             =head3 get_unique_opportunity_id
2213              
2214             Returns the opportunity id, searching for query $query
2215             If none is found undef is returned, and if more than one is found
2216             an error is issued.
2217              
2218             This method should only be used if you can garantee that you have only one
2219             opportunity with the same email address
2220              
2221             Input:
2222             * query (see L<get_opportunities> for more info)
2223              
2224             Output:
2225              
2226             * opportunityid found, 0 if none is found, and confess on error or if more than
2227             one opportunityid is found.
2228            
2229              
2230             =cut
2231              
2232             sub get_unique_opportunity_id {
2233             my ($self, $query) = @_;
2234             return $self->get_unique_module_id($OPPORTUNITIES, $query);
2235             }
2236              
2237             =head3 get_opportunity
2238              
2239             Returns the opportunity entry, given an opportunityid
2240              
2241             Input:
2242             * opportunityid
2243              
2244             Output:
2245              
2246             * A opportunity entry,
2247             undef if none found, and
2248             confess on error
2249            
2250             =cut
2251              
2252             sub get_opportunity {
2253             my ($self, $opportunityid) = @_;
2254             return $self->get_module_entry($OPPORTUNITIES, $opportunityid);
2255             }
2256              
2257              
2258             =head3 get_opportunity_attribute
2259              
2260             Returns the value of the attribute for a given opportunity id,
2261             If the attribute or opportunity id is not found undef is returned.
2262              
2263             Input:
2264             * opportunityid
2265             * attribute name
2266              
2267             Output:
2268              
2269             * attribute value or undef (if the opportunityid is not found, the attribute does not exists)
2270            
2271             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2272             try {
2273             my $opportunity_entry = $s->get_unique_opportunity_id_from_mail('batman@justiceleague.org');
2274             if (!defined($opportunity_entry)) {
2275             print "Not found\n";
2276             } else {
2277             print $s->get_opportunity_attribute($opportunity_entry, 'last_name');
2278             }
2279             } catch {
2280             print "Error or more than one entry was found: $@";
2281             }
2282              
2283             =cut
2284              
2285             sub get_opportunity_attribute {
2286             my ($self, $opportunityid, $attribute) = @_;
2287             return $self->get_module_attribute($OPPORTUNITIES, $opportunityid, $attribute);
2288             }
2289              
2290             =head3 get_opportunities_from_mail
2291              
2292             Returns the opportunity id, searching for mail
2293              
2294             Input:
2295             * email address
2296              
2297             Output:
2298              
2299             * A reference to a an array of opportunity entries,
2300             [] if none found, and
2301             confess on error
2302            
2303             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2304             my $opportunity_entries_from_mail = $s->get_opportunities_from_mail('batman@justiceleague.org');
2305             for my $l (@$opportunity_entries_from_mail) {
2306             print Dumper($l);
2307             }
2308              
2309             =cut
2310              
2311             sub get_opportunities_from_mail {
2312             my ($self, $mail) = @_;
2313              
2314             return $self->get_module_entries_from_mail($OPPORTUNITIES, $mail);
2315             # my $umail = uc $mail;
2316             # my $query = 'opportunities.id in ( SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address_caps = "'.$umail.'")';
2317             # return $self->get_opportunities($query);
2318             }
2319              
2320             =head3 get_opportunity_ids_from_mail
2321              
2322             Returns an array of opportunity id, searching for mail
2323              
2324             Input:
2325             * email address
2326              
2327             Output:
2328              
2329             * A reference to an array of opportunity id, and confess on error
2330              
2331             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2332             my $opportunity_entries_from_mail = $s->get_opportunity_ids_from_mail('batman@justiceleague.org');
2333             for my $l (@$opportunity_entries_from_mail) {
2334             print Dumper($l);
2335             }
2336            
2337              
2338             =cut
2339              
2340             sub get_opportunity_ids_from_mail {
2341             my ($self, $mail) = @_;
2342             my $entries = $self->get_opportunities_from_mail($mail);
2343             my @entriesids = map { $_->{id} } @$entries;
2344             return \@entriesids;
2345             }
2346              
2347             =head3 get_unique_opportunity_id_from_mail
2348              
2349             Returns the opportunity id, searching for mail
2350             If none is found undef is returned, and if more than one is found
2351             an error is issued.
2352              
2353             This method should only be used if you can garantee that you have only one
2354             opportunity with the same email address
2355              
2356             Input:
2357             * email address
2358              
2359             Output:
2360              
2361             * opportunityid found, 0 if none is found, and confess on error or if more than
2362             one opportunityid is found.
2363            
2364             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2365             try {
2366             my $opportunity_entry = $s->get_unique_opportunity_id_from_mail('batman@justiceleague.org');
2367             if (!defined($opportunity_entry)) {
2368             print "Not found\n";
2369             } else {
2370             print "$opportunity_entry\n";
2371             }
2372             } catch {
2373             print "Error or more than one entry was found: $@";
2374             }
2375              
2376             =cut
2377              
2378             sub get_unique_opportunity_id_from_mail {
2379             my ($self, $mail) = @_;
2380             return $self->get_unique_module_id_from_mail($OPPORTUNITIES, $mail);
2381             }
2382              
2383             =head3 delete_opportunity_by_id
2384              
2385             Deletes the opportunityid indicated by $id
2386              
2387             Input:
2388             * opportunityid
2389              
2390             Output:
2391              
2392             * 1 if the opportunityid was modified, 0 if no opportunityid was found and confess on error
2393              
2394             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2395             try {
2396             my $opportunity_entry = $s->get_unique_opportunity_id_from_mail('batman@justiceleague.org');
2397             if (!defined($opportunity_entry)) {
2398             print "Not found\n";
2399             } else {
2400             $s->delete_opportunity_by_id($opportunity_entry);
2401             print "$opportunity_entry\n";
2402             }
2403             } catch {
2404             print "Error or more than one entry was found: $@";
2405             }
2406              
2407             =cut
2408              
2409             sub delete_opportunity_by_id {
2410             my ($self, $opportunityid) = @_;
2411             return $self->delete_module_entry_by_id($OPPORTUNITIES, $opportunityid);
2412             }
2413              
2414             =head3 update_opportunity
2415              
2416             Updates the opportunity attributes
2417              
2418             Input:
2419             * opportunityid
2420             * A hash reference of attribute pairs. Example { website => 'http://newsite.org'}
2421              
2422             Output:
2423              
2424             * 1 if the opportunityid was modified, 0 if no opportunityid was found and confess on error
2425              
2426             my $s = Net::SugarCRM->new(url=>$Test::url, restuser=>$Test::login, restpasswd=> $Test::pass);
2427             try {
2428             my $opportunity_entry = $s->get_unique_opportunity_id_from_mail('batman@justiceleague.org');
2429             if (!defined($opportunity_entry)) {
2430             print "Not found\n";
2431             } else {
2432             $s->update_opportunity($opportunity_entry, { website => 'http://newsite.org' });
2433             print "$opportunity_entry\n";
2434             }
2435             } catch {
2436             print "Error or more than one entry was found: $@";
2437             }
2438              
2439             =cut
2440              
2441             sub update_opportunity {
2442             my ($self, $opportunityid, $attributes) = @_;
2443             return $self->update_module_entry($OPPORTUNITIES, $opportunityid, $attributes);
2444             }
2445              
2446              
2447              
2448             =head2 Mail
2449              
2450             mail methods
2451              
2452             =head3 get_mail_entry
2453              
2454             Returns the EmailAddress entry, searching for mail address
2455              
2456             Input:
2457             * email address
2458              
2459             Output:
2460              
2461             * the EmailAddress entry, undef if none found, and confess on error
2462              
2463             =cut
2464              
2465             sub get_mail_entry {
2466             my ($self, $mail) = @_;
2467             my $umail = uc $mail;
2468             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "EmailAddresses", "query": "email_address_caps = \"'.$umail.'\"" }';
2469             my $response = $self->_rest_request('get_entry_list', $rest_data);
2470             $self->log->debug("Email found was:".Dumper($response));
2471             if ($response->{total_count} > 1) {
2472             $self->log->logconfess("Found more than one entry with for mail $mail and sessionid $self->sessionid:".Dumper($response));
2473             }
2474             if ($response->{total_count} == 0) {
2475             $self->log->debug( "No entries found found for mail $mail and sessionid ".$self->sessionid."\n");
2476             return;
2477             }
2478             $self->log->trace( "Successfully found entry with for mail $mail and sessionid ".$self->sessionid."\n");
2479             return $response->{entry_list}->[0];
2480             }
2481              
2482             =head3 get_mail_entry_id
2483              
2484             Returns the emailaddress id, searching for mail
2485             Adds the lead identified by id to the specified to the outgoing email
2486              
2487             Input:
2488             * email address
2489              
2490             Output:
2491              
2492             * the contact id, undef if none found, and confess on error
2493              
2494             =cut
2495             sub get_mail_entry_id {
2496             my ($self, $mail) = @_;
2497             my $entry = $self->get_mail_entry($mail);
2498             return (ref($entry) eq 'HASH') ? $entry->{id} : undef;
2499             }
2500              
2501             =head2 Note
2502              
2503             Notes methods
2504              
2505             =head3 create_note
2506              
2507             contact_id, description, name =subject
2508              
2509             parent_type -> Accounts, Opportunities
2510             parent_id -> account_id or opportunity_id
2511              
2512             =cut
2513             sub create_note {
2514             my ($self, $attributes) = @_;
2515              
2516             return $self->create_module_entry($NOTES, $attributes);
2517             }
2518              
2519             =head3 get_note
2520              
2521             Returns the note entry, given an noteid
2522              
2523             Input:
2524             * noteid
2525              
2526             Output:
2527              
2528             * A Note entry,
2529             undef if none found, and
2530             confess on error
2531            
2532             =cut
2533              
2534             sub get_note {
2535             my ($self, $noteid) = @_;
2536             return $self->get_module_entry($NOTES, $noteid);
2537             }
2538              
2539              
2540             =head3 get_note_attribute
2541              
2542             Returns the value of the attribute for a given note id,
2543             If the attribute or note id is not found undef is returned.
2544              
2545             Input:
2546             * noteid
2547             * attribute name
2548              
2549             Output:
2550              
2551             * attribute value or undef (if the noteid is not found, the attribute does not exists)
2552            
2553              
2554             =cut
2555              
2556             sub get_note_attribute {
2557             my ($self, $noteid, $attribute) = @_;
2558             return $self->get_module_attribute($NOTES, $noteid, $attribute);
2559             }
2560              
2561              
2562             =head3 delete_note_by_id
2563              
2564             Deletes the note indicated by $id
2565              
2566             Input:
2567             * noteid
2568              
2569             Output:
2570              
2571             * 1 if the opportunityid was modified, 0 if no opportunityid was found and confess on error
2572              
2573             =cut
2574              
2575             sub delete_note_by_id {
2576             my ($self, $noteid) = @_;
2577             return $self->delete_module_entry_by_id($OPPORTUNITIES, $noteid);
2578             }
2579              
2580              
2581             =head2 Campaigns
2582              
2583             =head3 get_campaignid_by_name
2584              
2585             Returns a campaign id searching for the campaign name,
2586              
2587             Input:
2588              
2589             * Campaign name
2590              
2591             Output:
2592              
2593             * if duplicate names exists
2594             an error is thrown (confess), if not found undef is returned and if found the campaign id
2595             is returned
2596             =cut
2597             sub get_campaignid_by_name {
2598             my ($self, $name) = @_;
2599             my $query = 'campaigns.name = "'.$name.'"';
2600             return $self->get_unique_module_id($CAMPAIGNS, $query);
2601             }
2602              
2603             =head3 get_campaign
2604              
2605             Returns the campaign entry, given a campaign id
2606              
2607             Input:
2608             * campaignid
2609              
2610             Output:
2611              
2612             * A campaign entry,
2613             undef if none found, and
2614             confess on error
2615            
2616             =cut
2617              
2618             sub get_campaign {
2619             my ($self, $campaignid) = @_;
2620             return $self->get_module_entry($CAMPAIGNS, $campaignid);
2621             }
2622              
2623             =head3 get_campaign_attribute
2624              
2625             Returns the value of the attribute for a given campaing id,
2626             If the attribute or campaing id is not found undef is returned.
2627              
2628             Input:
2629             * campaignid
2630             * attribute name
2631              
2632             Output:
2633              
2634             * attribute value or undef (if the leadid is not found, the attribute does not exists)
2635            
2636              
2637             =cut
2638              
2639             sub get_campaign_attribute {
2640             my ($self, $campaignid, $attribute) = @_;
2641             return $self->get_module_attribute($CAMPAIGNS, $campaignid, $attribute);
2642             }
2643              
2644              
2645             =head2 Prospectlists
2646              
2647             =head3 get_prospectlistid_by_name
2648              
2649             Returns a prospectlist id searching for the prospectlist name,
2650              
2651             Input:
2652              
2653             * Prospectlist name
2654              
2655             Output:
2656              
2657             * if duplicate names exists
2658             an error is thrown (confess), if not found undef is returned and if found the prospectlist id
2659             is returned
2660             =cut
2661             sub get_prospectlistid_by_name {
2662             my ($self, $name) = @_;
2663             my $query = 'prospect_lists.name = "'.$name.'"';
2664             return $self->get_unique_module_id($PROSPECTLISTS, $query);
2665             }
2666              
2667             =head3 get_prospectlist
2668              
2669             Returns the prospectlist entry, given a prospectlist id
2670              
2671             Input:
2672             * prospectlistid
2673              
2674             Output:
2675              
2676             * A prospectlist entry,
2677             undef if none found, and
2678             confess on error
2679            
2680             =cut
2681              
2682             sub get_prospectlist {
2683             my ($self, $prospectlistid) = @_;
2684             return $self->get_module_entry($PROSPECTLISTS, $prospectlistid);
2685             }
2686              
2687             =head3 get_prospectlist_attribute
2688              
2689             Returns the value of the attribute for a given campaing id,
2690             If the attribute or campaing id is not found undef is returned.
2691              
2692             Input:
2693             * prospectlistid
2694             * attribute name
2695              
2696             Output:
2697              
2698             * attribute value or undef (if the leadid is not found, the attribute does not exists)
2699            
2700              
2701             =cut
2702              
2703             sub get_prospectlist_attribute {
2704             my ($self, $prospectlistid, $attribute) = @_;
2705             return $self->get_module_attribute($PROSPECTLISTS, $prospectlistid, $attribute);
2706             }
2707              
2708             =head2 EmailMarketing
2709              
2710             =head3 get_emailmarketingid_by_name
2711              
2712             Returns a emailmarketing id searching for the emailmarketing name,
2713              
2714             Input:
2715              
2716             * Emailmarketing name
2717              
2718             Output:
2719              
2720             * if duplicate names exists
2721             an error is thrown (confess), if not found undef is returned and if found the emailmarketing id
2722             is returned
2723             =cut
2724             sub get_emailmarketingid_by_name {
2725             my ($self, $name) = @_;
2726             my $query = 'email_marketing.name = "'.$name.'"';
2727             return $self->get_unique_module_id($EMAILMARKETINGS, $query);
2728             }
2729              
2730             =head3 get_emailmarketing
2731              
2732             Returns the emailmarketing entry, given a emailmarketing id
2733              
2734             Input:
2735             * emailmarketingid
2736              
2737             Output:
2738              
2739             * A emailmarketing entry,
2740             undef if none found, and
2741             confess on error
2742            
2743             =cut
2744              
2745             sub get_emailmarketing {
2746             my ($self, $emailmarketingid) = @_;
2747             return $self->get_module_entry($EMAILMARKETINGS, $emailmarketingid);
2748             }
2749              
2750             =head3 get_emailmarketing_attribute
2751              
2752             Returns the value of the attribute for a given campaing id,
2753             If the attribute or campaing id is not found undef is returned.
2754              
2755             Input:
2756             * emailmarketingid
2757             * attribute name
2758              
2759             Output:
2760              
2761             * attribute value or undef (if the leadid is not found, the attribute does not exists)
2762            
2763              
2764             =cut
2765              
2766             sub get_emailmarketing_attribute {
2767             my ($self, $emailmarketingid, $attribute) = @_;
2768             return $self->get_module_attribute($EMAILMARKETINGS, $emailmarketingid, $attribute);
2769             }
2770              
2771             =head2 Prospect Lists
2772              
2773             =head3 add_module_id_to_prospect_list
2774              
2775             Adds the lead identified by id to the specified target list
2776              
2777             Input:
2778             * Module (currently only Contacts and Leads are supported)
2779             * Lead id or contact id
2780             * Target list id
2781              
2782             Output:
2783              
2784             * Returns 1 on success and undef if the entry was not created
2785             confess on error
2786            
2787              
2788             =cut
2789              
2790             sub add_module_id_to_prospect_list {
2791             my ($self, $module, $id, $prospect_list) = @_;
2792             $self->log->logconfess("Module $module cannot be added to a target list")
2793             if (!exists($self->_module_id_for_prospect_list->{$module}));
2794              
2795             if (!defined($self->get_module_entry($module, $id))) {
2796             $self->log->logconfess("Not found module $module and id $id. Check that the id is valid");
2797             }
2798             if (!defined($self->get_module_entry($PROSPECTLISTS, $prospect_list))) {
2799             $self->log->logconfess("Not found module $module and id $id. Check that the id is valid");
2800             }
2801             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "module_id": "'.$id.'", "link_field_name": "prospect_lists", "related_ids": '.
2802             '"'.$prospect_list.'" }';
2803             my $response = $self->_rest_request('set_relationship', $rest_data);
2804             $self->log->info( "Successfully created link from module \"$module\" and "
2805             ."id \"$id\" to target list \"$prospect_list\" entry with sessionid "
2806             ."\"".$self->sessionid."\"");
2807             $self->log->debug("Module id $id in module $module linked was:".Dumper($response));
2808             return ($response->{created} == 1) ? 1 : undef;
2809              
2810             }
2811              
2812             =head3 delete_module_id_from_prospect_list
2813              
2814             Gets the leads and contacts ids from the specified target list
2815              
2816             Input:
2817             * Target list id
2818              
2819             Output:
2820              
2821             * A reference to a hash with the entries ,confess on error
2822            
2823              
2824             =cut
2825              
2826             sub delete_module_id_from_prospect_list {
2827             my ($self, $module, $id, $prospect_list) = @_;
2828             $self->log->logconfess("Module $module cannot be added to a target list")
2829             if (!exists($self->_module_id_for_prospect_list->{$module}));
2830              
2831             # Need to set both deleted and delete, if not it doesn't work in 6.2.1 at least...
2832             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "'.$module.'", "module_id": "'.$id.'", "link_field_name": "prospect_lists", "related_ids": '.
2833             ' "'.$prospect_list.'" , "deleted" : "1", "delete" : "1" }';
2834              
2835             my $response = $self->_rest_request('set_relationship', $rest_data);
2836             $self->log->info( "Successfully deleted link from module $module and $id to target list <".$prospect_list.."> entry with sessionid ".$self->sessionid."\n");
2837             $self->log->debug("Module id $id in module $module linked was:".Dumper($response));
2838             return ($response->{deleted} == 1) ? 1 : undef;
2839              
2840             }
2841              
2842              
2843             =head3 add_lead_id_to_prospect_list
2844              
2845             Adds the lead identified by id to the specified target list
2846              
2847             Input:
2848             * Lead id
2849             * Target list id
2850              
2851             Output:
2852              
2853             * 1 if the lead was added undef if not
2854             confess on error
2855            
2856              
2857             =cut
2858              
2859             sub add_lead_id_to_prospect_list {
2860             my ($self, $id, $prospect_list) = @_;
2861             return $self->add_module_id_to_prospect_list($LEADS, $id, $prospect_list);
2862             }
2863              
2864             =head3 add_contact_id_to_prospect_list
2865              
2866             Adds the contact identified by id to the specified target list
2867              
2868             Input:
2869             * Contact id
2870             * Target list id
2871              
2872             Output:
2873              
2874             * 1 if the lead was added undef if not
2875             confess on error
2876            
2877              
2878             =cut
2879              
2880             sub add_contact_id_to_prospect_list {
2881             my ($self, $id, $prospect_list) = @_;
2882             return $self->add_module_id_to_prospect_list($CONTACTS, $id, $prospect_list);
2883             }
2884              
2885             =head3 delete_lead_id_from_prospect_list
2886              
2887             Note: This method does not seem to work
2888              
2889             Deletes the lead identified by id from the specified target list
2890              
2891             Input:
2892             * Lead id
2893             * Target list id
2894              
2895             Output:
2896              
2897             * 1 if the lead was added undef if not
2898             confess on error
2899            
2900              
2901             =cut
2902              
2903             sub delete_lead_id_from_prospect_list {
2904             my ($self, $id, $prospect_list) = @_;
2905             return $self->delete_module_id_from_prospect_list($LEADS, $id, $prospect_list);
2906             }
2907              
2908             =head3 delete_contact_id_from_prospect_list
2909              
2910             Note: This method does not seem to work
2911              
2912             Deletes the contact identified by id from the specified target list
2913              
2914             Input:
2915             * Contact id
2916             * Target list id
2917              
2918             Output:
2919              
2920             * 1 if the lead was added undef if not
2921             confess on error
2922            
2923              
2924             =cut
2925              
2926             sub delete_contact_id_from_prospect_list {
2927             my ($self, $id, $prospect_list) = @_;
2928             return $self->delete_module_id_from_prospect_list($CONTACTS, $id, $prospect_list);
2929             }
2930              
2931              
2932             =head2 Campaign emails
2933              
2934             These methods are to send emails out.
2935              
2936             =head3 send_prospectlist_marketing_email_force
2937              
2938             Note: Be careful you might resend emails that were already sent, this function overrides that.
2939              
2940             This method gets as input:
2941             * Hash array:
2942             * campaign_name: campaign name,
2943             * emailmarketing_name: marketing name (this is the name of the name that holds the email template)
2944             * prospectlist_name: Prospect list, where the contact or lead is going to be added
2945             * related_name: Can be one of two values Leads or Contacts
2946             * related_id: The leadid or contactid
2947             * email: The email of the contact
2948              
2949             Output:
2950              
2951             * undef if the email was not put in the outbound queue, confess in case of error.
2952              
2953             this method is a facility method to add contact to a prospect_list, delete all the relevant entries in the campaign log, and put the email in the outbound queue (emailman)
2954            
2955             =cut
2956              
2957             # Verifies params and returns mail
2958             sub _send_prospectlist_marketing_email_force_verify_params {
2959             my ($self, $attrs) = @_;
2960             $self->log->logconfess("campaign_name not specified:".Dumper($attrs))
2961             if (!defined($$attrs{campaign_name}));
2962             $self->log->logconfess("emailmarketing_name not specified:".Dumper($attrs))
2963             if (!defined($$attrs{emailmarketing_name}));
2964             $self->log->logconfess("prospectlist_name not specified:".Dumper($attrs))
2965             if (!defined($$attrs{prospectlist_name}));
2966             $self->log->logconfess("related_type not specified:".Dumper($attrs))
2967             if (!defined($$attrs{related_type}));
2968             $self->log->logconfess("email not specified:".Dumper($attrs))
2969             if (!defined($$attrs{email}));
2970             $self->log->logconfess("related_type is not $CONTACTS, $LEADS, or $ACCOUNTS:".Dumper($attrs))
2971             if ($$attrs{related_type} ne $CONTACTS && $$attrs{related_type} ne $LEADS &&
2972             $$attrs{related_type} ne $ACCOUNTS);
2973             $self->log->logconfess("related_id not specified:".Dumper($attrs))
2974             if (!defined($$attrs{related_id}));
2975             # Just verify that the related_id and related_type exists
2976             my $mail = $self->get_module_attribute($$attrs{related_type}, $$attrs{related_id}, 'email1');
2977             $self->log->logconfess("No email1 attribute for module and id ".$$attrs{related_type}." ".$$attrs{related_id}."")
2978             if (!$mail);
2979             # TODO verify $mail = $$attrs{email}
2980             return $mail;
2981             }
2982              
2983             sub send_prospectlist_marketing_email_force {
2984             my ($self, $attrs) = @_;
2985              
2986             # Verify parameters
2987             my $mail = $self->_send_prospectlist_marketing_email_force_verify_params($attrs);
2988              
2989             # Get parameters
2990             my $campaignid = $self->get_campaignid_by_name($$attrs{campaign_name})
2991             or $self->log->logcroak("Campaign \"$$attrs{campaign_name}\" not found");
2992             my $marketingid = $self->get_emailmarketingid_by_name($$attrs{emailmarketing_name})
2993             or $self->log->logcroak("Email marketing \"$$attrs{emailmarketing_name}\" not found");
2994             my $prospectlistid = $self->get_prospectlistid_by_name($$attrs{prospectlist_name})
2995             or $self->log->logcroak("Prospect list \"$$attrs{prospectlist_name}\" not found");
2996             my $userid = $self->get_unique_module_id($USERS, 'users.sugar_login = "'.$self->restuser.'"');
2997             # Delete existing emails sent either leads or contacts which have the
2998             # email address
2999             my $existing_leadid = $self->get_unique_lead_id_from_mail($mail);
3000             if (!$existing_leadid) {
3001             $self->log->debug("Previous email for leadid not found, forcing leadid to a non existen value -1 to allow searching also for non existent lead and existent email");
3002             $existing_leadid = '-1';
3003             }
3004             my $attrs_campaign_leads = {
3005             campaign_id => $campaignid,
3006             target_id => $existing_leadid,
3007             target_type => $LEADS,
3008             list_id => $prospectlistid,
3009             marketing_id => $marketingid,
3010             email => $mail,
3011             };
3012             $self->log->debug("Getting campaignlog id with params".Dumper($attrs_campaign_leads));
3013             my $ids = $self->get_ids_from_campaignlog($attrs_campaign_leads);
3014             $self->delete_ids_from_campaignlog($ids);
3015              
3016             my $existing_contactid = $self->get_unique_contact_id_from_mail($mail);
3017             if (!$existing_contactid) {
3018             $self->log->debug("Previous email for contactid not found, forcing contactid to a non existen value -1 to allow searching also for non existent contact and existent email");
3019             $existing_contactid = '-1';
3020             }
3021             my $attrs_campaign_contacts = {
3022             campaign_id => $campaignid,
3023             target_id => $existing_contactid,
3024             target_type => $CONTACTS,
3025             list_id => $prospectlistid,
3026             marketing_id => $marketingid,
3027             email => $mail,
3028             };
3029             $self->log->debug("Getting campaignlog id with params".Dumper($attrs_campaign_contacts));
3030             $ids = $self->get_ids_from_campaignlog($attrs_campaign_contacts);
3031             $self->delete_ids_from_campaignlog($ids);
3032              
3033             # Add the contact or lead to a distribution list
3034             $self->add_module_id_to_prospect_list($$attrs{related_type}, $$attrs{related_id}, $prospectlistid);
3035             $self->log->debug("Adding to list $prospectlistid module and id ".$$attrs{related_type}." ".$$attrs{related_id});
3036              
3037             # queue the mail outgoing
3038             my $emailman_attrs = {
3039             campaign_id => $campaignid,
3040             marketing_id => $marketingid,
3041             list_id => $prospectlistid,
3042             related_id => $$attrs{related_id},
3043             related_type => $$attrs{related_type},
3044             user_id => $userid,
3045             modified_user_id => $userid,
3046             };
3047             $self->add_to_emailman($emailman_attrs);
3048              
3049             return 1;
3050             }
3051              
3052             =head3 add_to_emailman
3053              
3054             Adds the module entry identified by some attributes to the specified to the outgoing email.
3055              
3056             This method puts in the outbound queue the mail specified by marketing_id, related_id and list_id (to resend a previous sent email you need to specifically delete the entries in the campaign log, see L<delete_ids_from_campaignlog>
3057              
3058              
3059             Input:
3060             * A hash with the following elements at least
3061             * campaign_id e6c3a792-9d03-c063-3601-4e2ad8991061
3062             * marketing_id e6c3a792-9d03-c063-3601-4e2ad8991061
3063             * list_id 55308e7d-1d97-9a8f-dc30-4e2ad69623af
3064             * related_id, new id created,
3065             * related_type, Leads or Contacts
3066              
3067             Output:
3068              
3069             * the hash created,confess on error
3070            
3071             Side effect the way we generate the ids, there should be at least a millisecond between
3072             each insert...
3073              
3074             my $emailman_attrs = {
3075             campaign_id => $campaignid,
3076             marketing_id => $emailmarketingid,
3077             list_id => $prospectlistid,
3078             related_id => $leadid,
3079             related_type => 'Leads',
3080             user_id => 'f2347eb8-b5ed-b324-a316-4e26c9558337',
3081             modified_user_id => 'f2347eb8-b5ed-b324-a316-4e26c9558337',
3082             };
3083             ok($s->add_to_emailman($emailman_attrs), "Added mails to emailman");
3084              
3085             =cut
3086              
3087             sub add_to_emailman {
3088             my ($self, $attributes) = @_;
3089              
3090             my $now = DateTime->now->strftime("%Y-%m-%d %T");;
3091             my $id = int(Time::HiRes::time * 10**2) % (2**31);
3092             $$attributes{id} = $id;
3093             $$attributes{new_with_id} = 1;
3094             $$attributes{send_date_time} = $now;
3095             $$attributes{in_queue_date} = $now;
3096              
3097             # my $attributes = {
3098             # id=>$id,
3099             # If you don't specify this then new_with_id will just not work...
3100             # new_with_id=>1,
3101             # campaign_id => $campaign_id,
3102             # marketing_id => $marketing_id,
3103             # list_id => $list_id,
3104             # related_id => $lead_id,
3105             # user_id => $user_id,
3106             # related_type => 'Leads',
3107             # modified_user_id => $user_id,
3108             # send_date_time => "$now",
3109             # in_queue_date => "$now",
3110             # };
3111             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "EmailMan", "name_value_list": '.
3112             encode_json($attributes).
3113             ',"track_view": "false" }';
3114              
3115             my $response = $self->_rest_request('set_entry', $rest_data);
3116             $self->log->info( "Successfully created emailman entry entry with sessionid ".$self->sessionid."\n");
3117             $self->log->debug("Module entry created was:".Dumper($response));
3118             return $response;
3119              
3120             }
3121              
3122              
3123             =head3 get_ids_from_campaignlog
3124              
3125             Returns the id, searching for campaign_id, target_id, target_type, list_id, marketing_id
3126              
3127             Input:
3128             * hash with
3129             * campaign_id
3130             * target_id
3131             * target_type
3132             * list_id
3133             * marketing_id
3134             * email
3135              
3136             Output:
3137              
3138             * an array ref with the campaign logs id, if none found an empty hash array, and confess on error
3139            
3140             =cut
3141              
3142             sub get_ids_from_campaignlog {
3143             my ($self, $attributes) = @_;
3144             my @required_keys = ('campaign_id', 'target_id', 'target_type', 'list_id', 'marketing_id', 'email');
3145             foreach (@required_keys) {
3146             $self->log->logconfess("key $_ not found in attributes: ".Dumper($attributes))
3147             unless defined $$attributes{$_};
3148             }
3149             my $query = "( campaign_log.campaign_id = '".$$attributes{'campaign_id'}.
3150             "' AND campaign_log.target_id = '".$$attributes{'target_id'}.
3151             "' AND campaign_log.target_type = '".$$attributes{'target_type'}.
3152             "' AND campaign_log.list_id = '".$$attributes{'list_id'}.
3153             "' AND campaign_log.marketing_id = '".$$attributes{'marketing_id'}.
3154             "' ) OR campaign_log.more_information = '".$$attributes{'email'}."'";
3155              
3156              
3157             my $rest_data = '{"session": "'.$self->sessionid.'", "module_name": "CampaignLog", "query": "'.$query.'" } ';
3158             my $response = $self->_rest_request('get_entry_list', $rest_data);
3159             $self->log->debug("Campaign log ids for found was:".Dumper($query, $attributes,$response));
3160              
3161             my @ids = map { $_->{id} } @{$response->{entry_list}};
3162              
3163             return \@ids;;
3164             }
3165              
3166             =head3 delete_ids_from_campaignlog
3167              
3168             Returns the id, searching for campaign_id, target_id, target_type, list_id, marketing_id
3169             Adds the lead identified by id to the specified to the outgoing email
3170              
3171             For this method to work you need to get the database configuration set up see sttributes dsn, dbuser and dbpassword
3172              
3173             Input:
3174             * reference to an array with campaign log ids to be deleted
3175              
3176             Output:
3177              
3178             * None, confess on error
3179              
3180             my $attrs = {
3181             campaign_id => $campaignid,
3182             target_id => $contactid,
3183             target_type => 'Contacts',
3184             list_id => $prospectlistid,
3185             marketing_id => $emailmarketingid,
3186             };
3187             my $ids = $s->get_ids_from_campaignlog($attrs);
3188             $s->delete_ids_from_campaignlog($ids);
3189              
3190            
3191             =cut
3192              
3193             sub delete_ids_from_campaignlog {
3194             my ($self, $ids) = @_;
3195              
3196             $self->log->debug("delete_ids_from_campaignlog".Dumper($ids));
3197              
3198             foreach my $id (@$ids) {
3199             $self->_delete_sth->execute($id);
3200             $self->log->info("Deleted from campaignlog id $id");
3201             }
3202              
3203             return;
3204             }
3205              
3206             # =head2 convertlead
3207              
3208             # Input:
3209              
3210             # * leadid
3211             # * Opportunity attrs. As defined in L<create_opportunity>. If this is empty no opportunity is created
3212              
3213             # Output:
3214             # * a hash with
3215             # * contactid (created, or existent if the email exists as contact)
3216             # * accountid (created or existent if the name exists as account)
3217             # * opportunityid (created with the attributes specified)
3218              
3219             # =cut
3220              
3221             # sub _create_account_from_leadentry {
3222             # my ($self, $leadentry) = @_;
3223             # my $accountid = 1;
3224             # return $accountid;
3225             # }
3226              
3227             # sub _create_account_from_leadentry {
3228             # my ($self, $leadentry) = @_;
3229             # my $leadid = 1;
3230             # return $leadid;
3231             # }
3232              
3233             # sub convertlead {
3234             # my ($self, $leadid, $opportunity_args) = @_;
3235              
3236             # my $leadentry = $self->get_lead($leadid);
3237             # confess "No leadid found with leadid $leadid"
3238             # if (!defined($leadentry));
3239             # confess "Found leadentry with id $leadid, but no email attribute email1 defined... ".Dumper($leadentry)
3240             # if (!exists($leadentry->{name_value_list}->{email1}->{value}));
3241             # my $leademail = $leadentry->{name_value_list}->{email1}->{value};
3242            
3243             # my ($accountid, $newaccountid);
3244             # $accountid = $self->get_unique_account_id('accounts.name = "'.$leadentry->{account_name}.'"');
3245             # if (!defined($accountid)) {
3246             # $accountid = $self->_create_account_from_leadentry();
3247             # $newaccountid = $accountid;
3248             # }
3249             # # On error it sends an exception
3250             # # Check if accountid was empty
3251             # # check contact by mail
3252             # my ($contactid, $newcontactid);
3253             # try {
3254             # $contactid = $self->get_unique_contact_id_from_mail($leademail); #
3255             # if (!defined($contactid)) {
3256             # $contactid = $self->_create_contact_from_leadentry($leadentry);
3257             # $newcontactid = $contactid;
3258             # }
3259             # } catch {
3260             # $self->delete_account_by_id($accountid) if (defined(e$newaccountid));
3261             # confess "Error creating contact, removing account $accountid from lead entry: $@. Entry: ".Dumper($leadentry);
3262             # };
3263              
3264            
3265             # # leads
3266              
3267             # #| id | char(36) | NO | PRI | NULL | |
3268             # #| date_entered | datetime | YES | | NULL | |
3269             # #| date_modified | datetime | YES | | NULL | |
3270             # #| modified_user_id | char(36) | YES | | NULL | |
3271             # #| created_by | char(36) | YES | | NULL | |
3272             # #| description | text | YES | | NULL | |
3273             # #| deleted | tinyint(1) | YES | MUL | 0 | |
3274             # #| assigned_user_id | char(36) | YES | MUL | NULL | |
3275             # #| salutation | varchar(255) | YES | | NULL | |
3276             # #| first_name | varchar(100) | YES | | NULL | |
3277             # #| last_name | varchar(100) | YES | MUL | NULL | |
3278             # #| title | varchar(100) | YES | | NULL | |
3279             # #| department | varchar(100) | YES | | NULL | |
3280             # #| do_not_call | tinyint(1) | YES | | 0 | |
3281             # #| phone_home | varchar(100) | YES | | NULL | |
3282             # #| phone_mobile | varchar(100) | YES | | NULL | |
3283             # #| phone_work | varchar(100) | YES | | NULL | |
3284             # #| phone_other | varchar(100) | YES | | NULL | |
3285             # #| phone_fax | varchar(100) | YES | | NULL | |
3286             # #| primary_address_street | varchar(150) | YES | | NULL | |
3287             # #| primary_address_city | varchar(100) | YES | | NULL | |
3288             # #| primary_address_state | varchar(100) | YES | | NULL | |
3289             # #| primary_address_postalcode | varchar(20) | YES | | NULL | |
3290             # #| primary_address_country | varchar(255) | YES | | NULL | |
3291             # #| alt_address_street | varchar(150) | YES | | NULL | |
3292             # #| alt_address_city | varchar(100) | YES | | NULL | |
3293             # #| alt_address_state | varchar(100) | YES | | NULL | |
3294             # #| alt_address_postalcode | varchar(20) | YES | | NULL | |
3295             # #| alt_address_country | varchar(255) | YES | | NULL | |
3296             # #| assistant | varchar(75) | YES | | NULL | |
3297             # #| assistant_phone | varchar(100) | YES | | NULL | |
3298             # #| converted | tinyint(1) | YES | | 0 | |
3299             # #| refered_by | varchar(100) | YES | | NULL | |
3300             # #| lead_source | varchar(100) | YES | | NULL | |
3301             # #| lead_source_description | text | YES | | NULL | |
3302             # #| status | varchar(100) | YES | | NULL | |
3303             # #| status_description | text | YES | | NULL | |
3304             # #| reports_to_id | char(36) | YES | MUL | NULL | |
3305             # #| account_name | varchar(255) | YES | MUL | NULL | |
3306             # #| account_description | text | YES | | NULL | |
3307             # #| contact_id | char(36) | YES | MUL | NULL | |
3308             # #| account_id | char(36) | YES | MUL | NULL | |
3309             # #| opportunity_id | char(36) | YES | MUL | NULL | |
3310             # #| opportunity_name | varchar(255) | YES | | NULL | |
3311             # #| opportunity_amount | varchar(50) | YES | | NULL | |
3312             # #| campaign_id | char(36) | YES | | NULL | |
3313             # #| birthdate | date | YES | | NULL | |
3314             # #| portal_name | varchar(255) | YES | | NULL | |
3315             # #| portal_app | varchar(255) | YES | | NULL | |
3316             # #| website | varchar(255) | YES | | NULL | |
3317             # #
3318             # #mysql> describe accounts;
3319             # #+-----------------------------+--------------+------+-----+---------+-------+
3320             # #| Field | Type | Null | Key | Default | Extra |
3321             # #+-----------------------------+--------------+------+-----+---------+-------+
3322             # #| id | char(36) | NO | PRI | NULL | |
3323             # #| name | varchar(150) | YES | MUL | NULL | |
3324             # #| date_entered | datetime | YES | | NULL | |
3325             # #| date_modified | datetime | YES | | NULL | |
3326             # #| modified_user_id | char(36) | YES | | NULL | |
3327             # #| created_by | char(36) | YES | | NULL | |
3328             # #| description | text | YES | | NULL | |
3329             # #| deleted | tinyint(1) | YES | MUL | 0 | |
3330             # #| assigned_user_id | char(36) | YES | | NULL | |
3331             # #| account_type | varchar(50) | YES | | NULL | |
3332             # #| industry | varchar(50) | YES | | NULL | |
3333             # #| annual_revenue | varchar(100) | YES | | NULL | |
3334             # #| phone_fax | varchar(100) | YES | | NULL | |
3335             # #| billing_address_street | varchar(150) | YES | | NULL | |
3336             # #| billing_address_city | varchar(100) | YES | | NULL | |
3337             # #| billing_address_state | varchar(100) | YES | | NULL | |
3338             # #| billing_address_postalcode | varchar(20) | YES | | NULL | |
3339             # #| billing_address_country | varchar(255) | YES | | NULL | |
3340             # #| rating | varchar(100) | YES | | NULL | |
3341             # #| phone_office | varchar(100) | YES | | NULL | |
3342             # #| phone_alternate | varchar(100) | YES | | NULL | |
3343             # #| website | varchar(255) | YES | | NULL | |
3344             # #| ownership | varchar(100) | YES | | NULL | |
3345             # #| employees | varchar(10) | YES | | NULL | |
3346             # #| ticker_symbol | varchar(10) | YES | | NULL | |
3347             # #| shipping_address_street | varchar(150) | YES | | NULL | |
3348             # #| shipping_address_city | varchar(100) | YES | | NULL | |
3349             # #| shipping_address_state | varchar(100) | YES | | NULL | |
3350             # #| shipping_address_postalcode | varchar(20) | YES | | NULL | |
3351             # #| shipping_address_country | varchar(255) | YES | | NULL | |
3352             # #| parent_id | char(36) | YES | MUL | NULL | |
3353             # #| sic_code | varchar(10) | YES | | NULL | |
3354             # #| campaign_id | char(36) | YES | | NULL | |
3355             # #+-----------------------------+--------------+------+-----+---------+-------+
3356             # #33 rows in set (0.01 sec)
3357             # #
3358             # #mysql> describe opportunities;
3359             # #+------------------+--------------+------+-----+---------+-------+
3360             # #| Field | Type | Null | Key | Default | Extra |
3361             # #+------------------+--------------+------+-----+---------+-------+
3362             # #| id | char(36) | NO | PRI | NULL | |
3363             # #| name | varchar(50) | YES | MUL | NULL | |
3364             # #| date_entered | datetime | YES | | NULL | |
3365             # #| date_modified | datetime | YES | | NULL | |
3366             # #| modified_user_id | char(36) | YES | | NULL | |
3367             # #| created_by | char(36) | YES | | NULL | |
3368             # #| description | text | YES | | NULL | |
3369             # #| deleted | tinyint(1) | YES | | 0 | |
3370             # #| assigned_user_id | char(36) | YES | MUL | NULL | |
3371             # #| opportunity_type | varchar(255) | YES | | NULL | |
3372             # #| campaign_id | char(36) | YES | | NULL | |
3373             # #| lead_source | varchar(50) | YES | | NULL | |
3374             # #| amount | double | YES | | NULL | |
3375             # #| amount_usdollar | double | YES | | NULL | |
3376             # #| currency_id | char(36) | YES | | NULL | |
3377             # #| date_closed | date | YES | | NULL | |
3378             # #| next_step | varchar(100) | YES | | NULL | |
3379             # #| sales_stage | varchar(255) | YES | | NULL | |
3380             # #| probability | double | YES | | NULL | |
3381             # #+------------------+--------------+------+-----+---------+-------+
3382             # #19 rows in set (0.00 sec)
3383             # #
3384             # #mysql> describe contacts;
3385             # #+----------------------------+--------------+------+-----+---------+-------+
3386             # #| Field | Type | Null | Key | Default | Extra |
3387             # #+----------------------------+--------------+------+-----+---------+-------+
3388             # #| id | char(36) | NO | PRI | NULL | |
3389             # #| date_entered | datetime | YES | | NULL | |
3390             # #| date_modified | datetime | YES | | NULL | |
3391             # #| modified_user_id | char(36) | YES | | NULL | |
3392             # #| created_by | char(36) | YES | | NULL | |
3393             # #| description | text | YES | | NULL | |
3394             # #| deleted | tinyint(1) | YES | MUL | 0 | |
3395             # #| assigned_user_id | char(36) | YES | MUL | NULL | |
3396             # #| salutation | varchar(255) | YES | | NULL | |
3397             # #| first_name | varchar(100) | YES | | NULL | |
3398             # #| last_name | varchar(100) | YES | MUL | NULL | |
3399             # #| title | varchar(100) | YES | | NULL | |
3400             # #| department | varchar(255) | YES | | NULL | |
3401             # #| do_not_call | tinyint(1) | YES | | 0 | |
3402             # #| phone_home | varchar(100) | YES | | NULL | |
3403             # #| phone_mobile | varchar(100) | YES | | NULL | |
3404             # #| phone_work | varchar(100) | YES | | NULL | |
3405             # #| phone_other | varchar(100) | YES | | NULL | |
3406             # #| phone_fax | varchar(100) | YES | | NULL | |
3407             # #| primary_address_street | varchar(150) | YES | | NULL | |
3408             # #| primary_address_city | varchar(100) | YES | | NULL | |
3409             # #| primary_address_state | varchar(100) | YES | | NULL | |
3410             # #| primary_address_postalcode | varchar(20) | YES | | NULL | |
3411             # #| primary_address_country | varchar(255) | YES | | NULL | |
3412             # #| alt_address_street | varchar(150) | YES | | NULL | |
3413             # #| alt_address_city | varchar(100) | YES | | NULL | |
3414             # #| alt_address_state | varchar(100) | YES | | NULL | |
3415             # #| alt_address_postalcode | varchar(20) | YES | | NULL | |
3416             # #| alt_address_country | varchar(255) | YES | | NULL | |
3417             # #| assistant | varchar(75) | YES | | NULL | |
3418             # #| assistant_phone | varchar(100) | YES | | NULL | |
3419             # #| lead_source | varchar(255) | YES | | NULL | |
3420             # #| reports_to_id | char(36) | YES | MUL | NULL | |
3421             # #| birthdate | date | YES | | NULL | |
3422             # #| campaign_id | char(36) | YES | | NULL | |
3423             # #+----------------------------+--------------+------+-----+---------+-------+
3424             # #35 rows in set (0.00 sec)
3425             # #
3426             # #mysql> describe opportunities;
3427             # #+------------------+--------------+------+-----+---------+-------+
3428             # #| Field | Type | Null | Key | Default | Extra |
3429             # #+------------------+--------------+------+-----+---------+-------+
3430             # #| id | char(36) | NO | PRI | NULL | |
3431             # #| name | varchar(50) | YES | MUL | NULL | |
3432             # #| date_entered | datetime | YES | | NULL | |
3433             # #| date_modified | datetime | YES | | NULL | |
3434             # #| modified_user_id | char(36) | YES | | NULL | |
3435             # #| created_by | char(36) | YES | | NULL | |
3436             # #| description | text | YES | | NULL | |
3437             # #| deleted | tinyint(1) | YES | | 0 | |
3438             # #| assigned_user_id | char(36) | YES | MUL | NULL | |
3439             # #| opportunity_type | varchar(255) | YES | | NULL | |
3440             # #| campaign_id | char(36) | YES | | NULL | |
3441             # #| lead_source | varchar(50) | YES | | NULL | |
3442             # #| amount | double | YES | | NULL | |
3443             # #| amount_usdollar | double | YES | | NULL | |
3444             # #| currency_id | char(36) | YES | | NULL | |
3445             # #| date_closed | date | YES | | NULL | |
3446             # #| next_step | varchar(100) | YES | | NULL | |
3447             # #| sales_stage | varchar(255) | YES | | NULL | |
3448             # #| probability | double | YES | | NULL | |
3449             # #+------------------+--------------+------+-----+---------+-------+
3450             # #19 rows in set (0.00 sec)
3451             # #
3452             # #mysql>
3453              
3454             # #mysql> select * from leads where last_name = "sainz"
3455             # # -> ;
3456             # #+--------------------------------------+---------------------+---------------------+--------------------------------------+--------------------------------------+-------------+---------+------------------+------------+------------+-----------+----------+---------------+-------------+------------+--------------+--------------+-------------+-----------+------------------------+----------------------+-----------------------+----------------------------+-------------------------+--------------------+------------------+-------------------+------------------------+---------------------+-----------+-----------------+-----------+------------+-------------+-------------------------+--------+--------------------+---------------+--------------+---------------------+------------+------------+----------------+------------------+--------------------+-------------+-----------+-------------+------------+---------+
3457             # #| id | date_entered | date_modified | modified_user_id | created_by | description | deleted | assigned_user_id | salutation | first_name | last_name | title | department | do_not_call | phone_home | phone_mobile | phone_work | phone_other | phone_fax | primary_address_street | primary_address_city | primary_address_state | primary_address_postalcode | primary_address_country | alt_address_street | alt_address_city | alt_address_state | alt_address_postalcode | alt_address_country | assistant | assistant_phone | converted | refered_by | lead_source | lead_source_description | status | status_description | reports_to_id | account_name | account_description | contact_id | account_id | opportunity_id | opportunity_name | opportunity_amount | campaign_id | birthdate | portal_name | portal_app | website |
3458             # #+--------------------------------------+---------------------+---------------------+--------------------------------------+--------------------------------------+-------------+---------+------------------+------------+------------+-----------+----------+---------------+-------------+------------+--------------+--------------+-------------+-----------+------------------------+----------------------+-----------------------+----------------------------+-------------------------+--------------------+------------------+-------------------+------------------------+---------------------+-----------+-----------------+-----------+------------+-------------+-------------------------+--------+--------------------+---------------+--------------+---------------------+------------+------------+----------------+------------------+--------------------+-------------+-----------+-------------+------------+---------+
3459             # #| 55002180-ee48-b7b9-4ec8-4e5c5a3b9ed7 | 2011-08-30 03:34:52 | 2011-08-30 03:34:52 | f2347eb8-b5ed-b324-a316-4e26c9558337 | f2347eb8-b5ed-b324-a316-4e26c9558337 | NULL | 0 | NULL | Mr | Jorge | Sainz | Puto amo | Uno muy bueno | 0 | NULL | NULL | 34600000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 0 | NULL | Online Demo | NULL | New | NULL | NULL | Qindel | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
3460             # # After lead conversion
3461             # #| 55002180-ee48-b7b9-4ec8-4e5c5a3b9ed7 | 2011-08-30 03:34:52 | 2011-10-28 10:31:42 | 1 | f2347eb8-b5ed-b324-a316-4e26c9558337 | NULL | 0 | NULL | Mr | Jorge | Sainz | Puto amo | Uno muy bueno | 0 | NULL | NULL | 34600000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 1 | NULL | Online Demo | NULL | Converted | NULL | NULL | Qindel | NULL | b960509e-085f-76d2-6186-4eaa84c22c59 | c6a57a6d-6aab-8829-0058-4eaa849b236c | d15428f7-ddd8-9cd7-08e2-4eaa84b175c4 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
3462              
3463             # #1 row in set (0.01 sec)
3464             # #
3465             # #mysql>
3466              
3467              
3468             # }
3469              
3470             =head2 DESTROY
3471              
3472             if the object is dereferenced and the sessionid is defined a logout is issued
3473              
3474             =cut
3475             sub DESTROY {
3476             my ($self) = @_;
3477             $self->logout;
3478             return;
3479             }
3480              
3481             =head2 update
3482              
3483             Save the values of a Net::SugarCRM::Entry
3484              
3485             =cut
3486              
3487             sub update {
3488             # Update Net::SugarCRM::Entry in CRM
3489             my ($self, $entry) = @_;
3490             return $self->update_module_entry(
3491             $entry->{module_name},
3492             $entry->{id},
3493             $entry->{name_value_list});
3494             }
3495              
3496             =head1 TODO
3497              
3498             =over 4
3499              
3500             =item * convert lead
3501              
3502             =back
3503              
3504             =head1 AUTHOR
3505              
3506             Nito Martinez, C<< <Nito at Qindel.ES> >>
3507              
3508             =head1 BUGS
3509              
3510             Please report any bugs or feature requests to C<bug-sugarcrm-client-rest at rt.cpan.org>, or through
3511             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-SugarCRM>. I will be notified, and then you'll
3512             automatically be notified of progress on your bug as I make changes.
3513              
3514              
3515             =head1 SUPPORT
3516              
3517             You can find documentation for this module with the perldoc command.
3518              
3519             perldoc Net::SugarCRM
3520              
3521             perldoc Net::SugarCRM::Tutorial
3522              
3523             You can also look for information at:
3524              
3525             =over 4
3526              
3527             =item * RT: CPAN's request tracker
3528              
3529             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-SugarCRM>
3530              
3531             =item * AnnoCPAN: Annotated CPAN documentation
3532              
3533             L<http://annocpan.org/dist/Net-SugarCRM>
3534              
3535             =item * CPAN Ratings
3536              
3537             L<http://cpanratings.perl.org/d/Net-SugarCRM>
3538              
3539             =item * Search CPAN
3540              
3541             L<http://search.cpan.org/dist/Net-SugarCRM/>
3542              
3543             =back
3544              
3545              
3546             =head1 ACKNOWLEDGEMENTS
3547              
3548             =over 4
3549              
3550             =item * Thanks to Phil Hallows Globe Microsystems L<www.globemicro.com> for contributing with get_module_link_ids and get_contact_account_ids the methods
3551              
3552             =back
3553              
3554             =head1 LICENSE AND COPYRIGHT
3555              
3556             Copyright 2011 Nito Martinez.
3557              
3558             This program is free software; you can redistribute it and/or modify
3559             it under the terms of the GNU General Public License as published by
3560             the Free Software Foundation; version 2 dated June, 1991 or at your option
3561             any later version.
3562              
3563             This program is distributed in the hope that it will be useful,
3564             but WITHOUT ANY WARRANTY; without even the implied warranty of
3565             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3566             GNU General Public License for more details.
3567              
3568             A copy of the GNU General Public License is available in the source tree;
3569             if not, write to the Free Software Foundation, Inc.,
3570             59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3571              
3572             =cut
3573             1; # End of Net::SugarCRM