allow null serial and mac, RT#31388
[freeside.git] / bin / customer-faker
1 #!/usr/bin/perl
2
3 use strict;
4 use Getopt::Std;
5 use Data::Faker;
6 use Business::CreditCard;
7 use FS::UID qw(adminsuidsetup);
8 use FS::Record qw(qsearch);
9 use FS::cust_main;
10 use FS::cust_pkg;
11 use FS::svc_acct;
12 use FS::svc_phone;
13 use FS::svc_domain;
14 use FS::svc_broadband;
15 use FS::state;
16 use Data::Dumper;
17 use strict;
18
19 my $refnum = 1;
20
21 #my @pkgs = ( 4, 5, 6 );
22
23 use vars qw( $opt_p $opt_a $opt_k );
24 getopts('p:a:k:');
25
26 my $agentnum = $opt_a || 1;
27
28 my @pkgs = split(/,\s*/, $opt_k);
29 @pkgs or die &usage;
30
31 my $user = shift or die &usage;
32 my $num = shift or die &usage;
33 adminsuidsetup($user);
34
35 my $onum = $num;
36 my $start = time;
37
38 our $faker = Data::Faker->new;
39 our @states = map { $_->get('state') } qsearch('state', { country => 'US' });
40
41 sub location {
42   # yeah, produces cities/states/zip codes that don't match up;
43   # a future version of this might check for that
44   my $tries = 5;
45   my $error;
46   while ($tries--) {
47     # Data::Faker sometimes returns stupid results that don't pass our data
48     # checks. keep trying until it gets it right.
49     my $location = FS::cust_location->new({
50       'address1' => $faker->street_address,
51       'address2' => (rand() < 0.2 ?
52         ($faker->secondary_unit_designator . ' ' . $faker->secondary_unit_number)
53         : ''
54       ),
55       'city'     => $faker->city,
56       'state'    => $states[ int(rand($#states)) ],
57       'zip'      => $faker->us_zip_code,
58       'country'  => 'US',
59       'custnum'  => 1, # just so we can check it
60     });
61     $error = $location->check;
62     if (!$error) {
63       $location->custnum('');
64       return $location;
65     }
66   }
67   die "couldn't create a valid location: $error\n";
68 }
69
70 for ( my $num = 0; $num < $onum; $num++ ) {
71
72   print "$num\n";
73   my $cust_main = new FS::cust_main {
74     'agentnum' => $agentnum,
75     'refnum'   => $refnum,
76     'first'    => $faker->first_name,
77     'last'     => $faker->last_name,
78     'company'  => ( $num % 2 ? $faker->company : '' ), #half with companies..
79     'daytime'  => $faker->phone_number,
80     'night'    => $faker->phone_number,
81     'payby'    => '',
82     'payip'    => $faker->ip_address,
83   };
84   $cust_main->set('bill_location', location());
85   if ( $num % 10 == 0 ) {
86     $cust_main->set('ship_location', location());
87   } else {
88     $cust_main->set('ship_location', $cust_main->get('bill_location'));
89   }
90
91   if ( $num % 3 > 0 ) {
92     $cust_main->payby('CARD');
93     my $cardnum = '4123'. sprintf('%011u', int(rand(100000000000)) );
94     $cust_main->payinfo( $cardnum. generate_last_digit($cardnum) );
95     $cust_main->paydate( '2020-05-01' );
96   } else {
97     $cust_main->payby('CHEK');
98     my $payinfo = sprintf('%7u@%09u', int(rand(10000000)), int(rand(1000000000)) ); 
99     $cust_main->payinfo($payinfo);
100     $cust_main->payname( 'Bank of Testing' );
101   }
102
103   my $error = $cust_main->insert;
104   die Dumper($cust_main)."\ninserting cust_main:\n$error\n" if $error;
105
106   # scatter start dates within the first 6 months
107   my $now = time;
108   my $period = 60*60*24*180;
109   my $start = $now + int(rand($period));
110
111   # give each customer half of the specified set of packages
112   for (my $i = 0; $i <= scalar(@pkgs)/2; $i++) {
113
114     my $pkgpart = $pkgs[ ($num + $i) % scalar(@pkgs) ],
115     my @svcs;
116     my $cust_pkg = new FS::cust_pkg {
117       'pkgpart'    => $pkgpart,
118       'start_date' => $start,
119     };
120     foreach my $pkg_svc (qsearch('pkg_svc', { pkgpart => $pkgpart,
121                                               quantity => {op => '>', value => 0},
122                                             }))
123     {
124       my $part_svc = $pkg_svc->part_svc;
125       my $svc;
126       if ( $part_svc->svcdb eq 'svc_acct' ) {
127         $svc = new FS::svc_acct {
128           'username' => $faker->username,
129         };
130         $svc->set_password;
131
132         while ( FS::svc_acct->count('username = ?', $svc->username) ) {
133           my $username = $svc->username;
134           $username++;
135           $svc->username($username);
136         }
137       } elsif ( $part_svc->svcdb eq 'svc_broadband' ) {
138         $svc = new FS::svc_broadband {
139           'ip_addr' => sprintf('10.%u.%u.%u',
140             int(rand(255)),
141             int(rand(255)),
142             int(rand(255))
143           ),
144           'mac_addr' => sprintf('00:00:%02x:%02x:%02x:%02x',
145             int(rand(255)),
146             int(rand(255)),
147             int(rand(255)),
148             int(rand(255))
149           ),
150         };
151       } elsif ( $part_svc->svcdb eq 'svc_phone' ) {
152         my $phonenum = $faker->phone_number;
153         $phonenum =~ s/\D//g;
154         $svc = new FS::svc_phone {
155           'phonenum'  => $phonenum,
156           'pin'       => sprintf('%05u', int(rand(100000))),
157         };
158       } elsif ( $part_svc->svcdb eq 'svc_domain' ) {
159         my $domain;
160         do {
161           $domain = $faker->domain_word . '.com';
162         } until FS::svc_domain->count('domain = ?', $domain) == 0;
163         $svc = new FS::svc_domain {
164           domain => $domain
165         };
166       } else {
167         # unsupported svc_x; do nothing
168         next;
169       }
170       $svc->set('svcpart', $part_svc->svcpart);
171       push @svcs, $svc;
172     } # foreach $pkg_svc
173
174     $error = $cust_main->order_pkg(
175       cust_pkg  => $cust_pkg,
176       svcs      => \@svcs,
177     );
178     die Dumper($cust_pkg) . "\ninserting cust_pkg:\n$error\n" if $error;
179   } # package
180
181 } # customer
182
183 my $end = time;
184
185 my $sec = $end-$start;
186 $sec=1 if $sec==0;
187 my $persec = $onum / $sec;
188 print "$onum customers inserted in $sec seconds ($persec customers/sec)\n";
189
190 #---
191
192 sub usage {
193   die "Usage:\n\n  customer-faker [ -a agentnum ] [ -k pkgpart,pkgpart,pkgpart... ] user num_fakes\n";
194 }