| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Parse::SAMGov::Entity; |
|
2
|
|
|
|
|
|
|
$Parse::SAMGov::Entity::VERSION = '0.202'; |
|
3
|
5
|
|
|
5
|
|
310833
|
use strict; |
|
|
5
|
|
|
|
|
29
|
|
|
|
5
|
|
|
|
|
216
|
|
|
4
|
5
|
|
|
5
|
|
25
|
use warnings; |
|
|
5
|
|
|
|
|
10
|
|
|
|
5
|
|
|
|
|
303
|
|
|
5
|
5
|
|
|
5
|
|
85
|
use 5.010; |
|
|
5
|
|
|
|
|
17
|
|
|
6
|
5
|
|
|
5
|
|
1264
|
use Data::Dumper; |
|
|
5
|
|
|
|
|
16077
|
|
|
|
5
|
|
|
|
|
411
|
|
|
7
|
5
|
|
|
5
|
|
2042
|
use Parse::SAMGov::Mo; |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
40
|
|
|
8
|
5
|
|
|
5
|
|
3320
|
use URI; |
|
|
5
|
|
|
|
|
28888
|
|
|
|
5
|
|
|
|
|
174
|
|
|
9
|
5
|
|
|
5
|
|
5011
|
use DateTime; |
|
|
5
|
|
|
|
|
2979543
|
|
|
|
5
|
|
|
|
|
359
|
|
|
10
|
5
|
|
|
5
|
|
3895
|
use DateTime::Format::Strptime; |
|
|
5
|
|
|
|
|
307573
|
|
|
|
5
|
|
|
|
|
28
|
|
|
11
|
5
|
|
|
5
|
|
3273
|
use Parse::SAMGov::Entity::Address; |
|
|
5
|
|
|
|
|
16
|
|
|
|
5
|
|
|
|
|
173
|
|
|
12
|
5
|
|
|
5
|
|
2153
|
use Parse::SAMGov::Entity::PointOfContact; |
|
|
5
|
|
|
|
|
47
|
|
|
|
5
|
|
|
|
|
502
|
|
|
13
|
5
|
|
|
5
|
|
49
|
use Carp; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
3464
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
#ABSTRACT: Object to denote each Entity in SAM |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use overload fallback => 1, |
|
18
|
|
|
|
|
|
|
'""' => sub { |
|
19
|
8
|
|
|
8
|
|
17784
|
my $self = $_[0]; |
|
20
|
8
|
|
|
|
|
21
|
my $str = ''; |
|
21
|
8
|
100
|
|
|
|
34
|
$str .= $self->name if $self->name; |
|
22
|
8
|
100
|
|
|
|
30
|
$str .= ' dba ' . $self->dba_name if $self->dba_name; |
|
23
|
8
|
100
|
|
|
|
32
|
$str .= "\nUEI: " . $self->UEI if $self->UEI; |
|
24
|
8
|
100
|
|
|
|
29
|
$str .= "\nDUNS: " . $self->DUNS if $self->DUNS; |
|
25
|
8
|
50
|
66
|
|
|
29
|
$str .= '+' . $self->DUNSplus4 if $self->DUNS and $self->DUNSplus4 ne '0000'; |
|
26
|
8
|
100
|
|
|
|
27
|
$str .= '\nEntity EFT Indicator: ' . $self->EEFTI if defined $self->EEFTI; |
|
27
|
8
|
50
|
|
|
|
28
|
$str .= "\nCAGE: " . $self->CAGE if $self->CAGE; |
|
28
|
8
|
100
|
|
|
|
31
|
$str .= "\nDODAAC: " . $self->DODAAC if $self->DODAAC; |
|
29
|
8
|
50
|
|
|
|
26
|
$str .= "\nStatus: " . $self->extract_code if $self->extract_code; |
|
30
|
8
|
100
|
|
|
|
62
|
$str .= "\nUpdated: Yes" if $self->updated; |
|
31
|
8
|
50
|
|
|
|
56
|
$str .= "\nRegistration Purpose: " . $self->regn_purpose if $self->regn_purpose; |
|
32
|
8
|
100
|
|
|
|
26
|
$str .= "\nRegistration Date: " . $self->regn_date->ymd('-') if $self->regn_date; |
|
33
|
8
|
100
|
|
|
|
238
|
$str .= "\nExpiry Date: " . $self->expiry_date->ymd('-') if $self->expiry_date; |
|
34
|
8
|
100
|
|
|
|
102
|
$str .= "\nLast Update Date: " . $self->lastupdate_date->ymd('-') if $self->lastupdate_date; |
|
35
|
8
|
100
|
|
|
|
116
|
$str .= "\nActivation Date: " . $self->activation_date->ymd('-') if $self->activation_date; |
|
36
|
8
|
100
|
|
|
|
113
|
$str .= "\nCompany Division: " . $self->company_division if $self->company_division; |
|
37
|
8
|
50
|
|
|
|
28
|
$str .= "\nDivision No.: " . $self->division_no if $self->division_no; |
|
38
|
8
|
100
|
|
|
|
25
|
$str .= "\nPhysical Address: " . $self->physical_address if $self->physical_address; |
|
39
|
8
|
100
|
|
|
|
29
|
$str .= "\nBusiness Start Date: " . $self->start_date->ymd('-') if $self->start_date; |
|
40
|
8
|
100
|
|
|
|
137
|
$str .= sprintf "\nFiscal Year End: %02d-%02d", $self->fiscalyear_date->month, $self->fiscalyear_date->day |
|
41
|
|
|
|
|
|
|
if $self->fiscalyear_date; |
|
42
|
8
|
100
|
|
|
|
72
|
$str .= "\nCorporate URL: " . $self->url if $self->url; |
|
43
|
8
|
|
|
|
|
84
|
$str .= "\nBusiness Types: [" . join(',', @{$self->biztype}) . "]"; |
|
|
8
|
|
|
|
|
30
|
|
|
44
|
8
|
|
|
|
|
33
|
$str .= "\nNAICS Codes: [" . join(',', keys %{$self->NAICS}) . "]"; |
|
|
8
|
|
|
|
|
24
|
|
|
45
|
8
|
100
|
|
|
|
31
|
$str .= "\nSmall Business: " . ($self->is_smallbiz() ? 'Yes' : 'No'); |
|
46
|
|
|
|
|
|
|
{ |
|
47
|
8
|
|
|
|
|
16
|
local $Data::Dumper::Indent = 1; |
|
|
8
|
|
|
|
|
36
|
|
|
48
|
8
|
|
|
|
|
20
|
local $Data::Dumper::Terse = 1; |
|
49
|
8
|
|
|
|
|
22
|
$str .= "\nNAICS Details: " . Dumper($self->NAICS); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
8
|
|
|
|
|
1517
|
$str .= "\nPSC Codes: [" . join(',', @{$self->PSC}) . "]"; |
|
|
8
|
|
|
|
|
40
|
|
|
52
|
8
|
100
|
|
|
|
27
|
$str .= "\nMailing Address: " . $self->mailing_address if $self->mailing_address; |
|
53
|
8
|
100
|
|
|
|
29
|
$str .= "\nGovt Business POC: " . $self->POC_gov if $self->POC_gov; |
|
54
|
8
|
100
|
|
|
|
37
|
$str .= "\nGovt Business POC (alternate): " . $self->POC_gov_alt if $self->POC_gov_alt; |
|
55
|
8
|
100
|
|
|
|
54
|
$str .= "\nPast Performance POC: " . $self->POC_pastperf if $self->POC_pastperf; |
|
56
|
8
|
100
|
|
|
|
28
|
$str .= "\nPast Performance POC (alternate): " . $self->POC_pastperf_alt if $self->POC_pastperf_alt; |
|
57
|
8
|
100
|
|
|
|
46
|
$str .= "\nElectronic POC: " . $self->POC_elec if $self->POC_elec; |
|
58
|
8
|
100
|
|
|
|
36
|
$str .= "\nElectronic POC (alternate): " . $self->POC_elec_alt if $self->POC_elec_alt; |
|
59
|
8
|
50
|
|
|
|
35
|
$str .= "\nDelinquent Federal Debt: " . ($self->delinquent_fed_debt ? 'Yes' : 'No'); |
|
60
|
8
|
50
|
|
|
|
23
|
$str .= "\nExclusion Status: " . $self->exclusion_status if $self->exclusion_status; |
|
61
|
|
|
|
|
|
|
{ |
|
62
|
8
|
|
|
|
|
24
|
local $Data::Dumper::Indent = 0; |
|
63
|
8
|
|
|
|
|
16
|
local $Data::Dumper::Terse = 1; |
|
64
|
8
|
|
|
|
|
25
|
$str .= "\nSBA Business Type: " . Dumper($self->SBA); |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
{ |
|
67
|
8
|
|
|
|
|
36
|
local $Data::Dumper::Indent = 0; |
|
|
8
|
|
|
|
|
554
|
|
|
|
8
|
|
|
|
|
17
|
|
|
68
|
8
|
|
|
|
|
14
|
local $Data::Dumper::Terse = 1; |
|
69
|
8
|
|
|
|
|
33
|
$str .= "\nDisaster Response Type: " . Dumper($self->disaster_response); |
|
70
|
|
|
|
|
|
|
} |
|
71
|
8
|
100
|
|
|
|
383
|
$str .= "\nIs Private Listing: " . ($self->is_private ? 'Yes' : 'No'); |
|
72
|
8
|
100
|
|
|
|
23
|
$str .= "\nD&B Open Data Flag: " . $self->dnb_open_data if defined $self->dnb_open_data; |
|
73
|
8
|
|
|
|
|
134
|
return $str; |
|
74
|
5
|
|
|
5
|
|
39
|
}; |
|
|
5
|
|
|
|
|
1496
|
|
|
|
5
|
|
|
|
|
410
|
|
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
has 'UEI'; |
|
78
|
|
|
|
|
|
|
has 'DUNS'; |
|
79
|
|
|
|
|
|
|
has DUNSplus4 => default => sub { '0000' }; |
|
80
|
|
|
|
|
|
|
has 'EEFTI'; |
|
81
|
|
|
|
|
|
|
has 'CAGE'; |
|
82
|
|
|
|
|
|
|
has 'DODAAC'; |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
has 'extract_code'; |
|
86
|
|
|
|
|
|
|
has 'updated'; |
|
87
|
|
|
|
|
|
|
has 'regn_purpose' => coerce => sub { |
|
88
|
|
|
|
|
|
|
my $p = $_[0]; |
|
89
|
|
|
|
|
|
|
return 'Federal Assistance Awards' if $p eq 'Z1'; |
|
90
|
|
|
|
|
|
|
return 'All Awards' if $p eq 'Z2'; |
|
91
|
|
|
|
|
|
|
return 'IGT-Only' if $p eq 'Z3'; |
|
92
|
|
|
|
|
|
|
return 'Federal Assistance Awards & IGT' if $p eq 'Z4'; |
|
93
|
|
|
|
|
|
|
return 'All Awards & IGT' if $p eq 'Z5'; |
|
94
|
|
|
|
|
|
|
}; |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub _parse_yyyymmdd { |
|
97
|
102
|
50
|
|
102
|
|
231
|
if (@_) { |
|
98
|
102
|
|
|
|
|
168
|
my $d = shift; |
|
99
|
102
|
100
|
|
|
|
219
|
if (length($d) == 4) { |
|
100
|
14
|
|
|
|
|
106
|
my $y = DateTime->now->year; |
|
101
|
14
|
|
|
|
|
4947
|
$d = "$y$d"; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
102
|
|
|
|
|
224
|
state $Strp = |
|
104
|
|
|
|
|
|
|
DateTime::Format::Strptime->new(pattern => '%Y%m%d', |
|
105
|
|
|
|
|
|
|
time_zone => 'America/New_York',); |
|
106
|
102
|
|
|
|
|
83030
|
return $Strp->parse_datetime($d); |
|
107
|
|
|
|
|
|
|
} |
|
108
|
0
|
|
|
|
|
0
|
return; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
has 'regn_date' => coerce => sub { _parse_yyyymmdd $_[0] }; |
|
113
|
|
|
|
|
|
|
has 'expiry_date' => coerce => sub { _parse_yyyymmdd $_[0] }; |
|
114
|
|
|
|
|
|
|
has 'lastupdate_date' => coerce => sub { _parse_yyyymmdd $_[0] }; |
|
115
|
|
|
|
|
|
|
has 'activation_date' => coerce => sub { _parse_yyyymmdd $_[0] }; |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
has 'name'; |
|
119
|
|
|
|
|
|
|
has 'dba_name'; |
|
120
|
|
|
|
|
|
|
has 'company_division'; |
|
121
|
|
|
|
|
|
|
has 'division_no'; |
|
122
|
|
|
|
|
|
|
has 'physical_address' => default => sub { return Parse::SAMGov::Entity::Address->new; }; |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
has 'start_date' => coerce => sub { _parse_yyyymmdd $_[0] }; |
|
126
|
|
|
|
|
|
|
has 'fiscalyear_date' => coerce => sub { _parse_yyyymmdd $_[0] }; |
|
127
|
|
|
|
|
|
|
has 'url' => coerce => sub { URI->new($_[0]) }; |
|
128
|
|
|
|
|
|
|
has 'entity_structure'; |
|
129
|
|
|
|
|
|
|
has entity_structure_descriptions => default => sub { |
|
130
|
|
|
|
|
|
|
{ |
|
131
|
|
|
|
|
|
|
'2J' => 'Sole Proprietorship', |
|
132
|
|
|
|
|
|
|
'2K' => 'Partnership or Limited Liability Partnership', |
|
133
|
|
|
|
|
|
|
'2L' => 'Corporate Entity (Not Tax Exempt)', |
|
134
|
|
|
|
|
|
|
'8H' => 'Corporate Entity (Tax Exempt)', |
|
135
|
|
|
|
|
|
|
'2A' => 'U.S. Government Entity', |
|
136
|
|
|
|
|
|
|
'CY' => 'Country - Foreign Government', |
|
137
|
|
|
|
|
|
|
'X6' => 'International Organization', |
|
138
|
|
|
|
|
|
|
'ZZ' => 'Other', |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
}; |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
has 'incorporation_state'; |
|
145
|
|
|
|
|
|
|
has 'incorporation_country'; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
has 'biztype' => default => sub { [] }; |
|
150
|
|
|
|
|
|
|
has 'NAICS' => default => sub { {} }; |
|
151
|
|
|
|
|
|
|
has 'PSC' => default => sub { [] }; |
|
152
|
|
|
|
|
|
|
has 'creditcard'; |
|
153
|
|
|
|
|
|
|
has 'correspondence_type'; |
|
154
|
|
|
|
|
|
|
has 'mailing_address' => default => sub { return Parse::SAMGov::Entity::Address->new; }; |
|
155
|
|
|
|
|
|
|
has 'POC_gov' => default => sub { return |
|
156
|
|
|
|
|
|
|
Parse::SAMGov::Entity::PointOfContact->new; }; |
|
157
|
|
|
|
|
|
|
has 'POC_gov_alt' => default => sub { |
|
158
|
|
|
|
|
|
|
Parse::SAMGov::Entity::PointOfContact->new; }; |
|
159
|
|
|
|
|
|
|
has 'POC_pastperf' => default => sub { |
|
160
|
|
|
|
|
|
|
Parse::SAMGov::Entity::PointOfContact->new; }; |
|
161
|
|
|
|
|
|
|
has 'POC_pastperf_alt' => default => sub { |
|
162
|
|
|
|
|
|
|
Parse::SAMGov::Entity::PointOfContact->new; }; |
|
163
|
|
|
|
|
|
|
has 'POC_elec' => default => sub { |
|
164
|
|
|
|
|
|
|
Parse::SAMGov::Entity::PointOfContact->new; }; |
|
165
|
|
|
|
|
|
|
has 'POC_elec_alt' => default => sub { |
|
166
|
|
|
|
|
|
|
Parse::SAMGov::Entity::PointOfContact->new; }; |
|
167
|
|
|
|
|
|
|
has 'delinquent_fed_debt'; |
|
168
|
|
|
|
|
|
|
has 'exclusion_status'; |
|
169
|
|
|
|
|
|
|
has 'is_private'; |
|
170
|
|
|
|
|
|
|
has 'dnb_open_data'; |
|
171
|
|
|
|
|
|
|
has 'disaster_response' => default => sub { {} }; |
|
172
|
|
|
|
|
|
|
has 'SBA' => default => sub { {} }; |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
has 'SBA_descriptions' => default => sub { |
|
175
|
|
|
|
|
|
|
{ |
|
176
|
|
|
|
|
|
|
A4 => 'SBA Certified Small Disadvantaged Business', |
|
177
|
|
|
|
|
|
|
A6 => 'SBA Certified 8A Program Participant', |
|
178
|
|
|
|
|
|
|
JT => 'SBA Certified 8A Joint Venture', |
|
179
|
|
|
|
|
|
|
XX => 'SBA Certified HUBZone Firm', |
|
180
|
|
|
|
|
|
|
A9 => 'SBA Certified Women-Owned Small Business', |
|
181
|
|
|
|
|
|
|
A0 => 'SBA Certified Economically Disadvantaged Women-Owned Small Business', |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
}; |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub is_smallbiz { |
|
186
|
8
|
|
|
8
|
1
|
17
|
my $self = shift; |
|
187
|
8
|
|
|
|
|
16
|
my $res = 0; |
|
188
|
8
|
|
|
|
|
18
|
foreach my $k (keys %{$self->NAICS}) { |
|
|
8
|
|
|
|
|
19
|
|
|
189
|
34
|
100
|
|
|
|
60
|
$res = 1 if $self->NAICS->{$k}->{small_biz}; |
|
190
|
34
|
100
|
|
|
|
59
|
$res = 1 if $self->NAICS->{$k}->{exception}->{small_biz}; |
|
191
|
34
|
100
|
|
|
|
67
|
last if $res; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
8
|
|
|
|
|
36
|
return $res; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub _trim { |
|
197
|
|
|
|
|
|
|
# from Mojo::Util::trim |
|
198
|
720
|
|
|
720
|
|
1062
|
my $s = shift; |
|
199
|
720
|
|
|
|
|
1443
|
$s =~ s/^\s+//g; |
|
200
|
720
|
|
|
|
|
1336
|
$s =~ s/\s+$//g; |
|
201
|
720
|
|
|
|
|
2411
|
return $s; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub load { |
|
205
|
16
|
|
|
16
|
0
|
33
|
my $self = shift; |
|
206
|
16
|
|
|
|
|
38
|
my $ncols = scalar(@_); |
|
207
|
16
|
100
|
|
|
|
95
|
return $self->load_v1(@_) if $ncols eq 150; |
|
208
|
4
|
50
|
|
|
|
31
|
return $self->load_v2(@_) if $ncols eq 142; |
|
209
|
0
|
|
|
|
|
0
|
carp "Unknown version of data file found with $ncols columns"; |
|
210
|
0
|
|
|
|
|
0
|
return undef; |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub load_v1 { |
|
214
|
12
|
|
|
12
|
0
|
25
|
my $self = shift; |
|
215
|
12
|
50
|
|
|
|
35
|
return unless (scalar(@_) == 150); |
|
216
|
12
|
|
|
|
|
49
|
$self->DUNS(shift); |
|
217
|
12
|
|
50
|
|
|
78
|
$self->DUNSplus4(shift || '0000'); |
|
218
|
12
|
|
|
|
|
40
|
$self->CAGE(shift); |
|
219
|
12
|
|
|
|
|
38
|
$self->DODAAC(shift); |
|
220
|
12
|
|
|
|
|
48
|
$self->updated(0); |
|
221
|
12
|
|
|
|
|
23
|
my $code = shift; |
|
222
|
12
|
100
|
|
|
|
128
|
if ($code =~ /A|2|3/x) { |
|
|
|
50
|
|
|
|
|
|
|
223
|
10
|
|
|
|
|
31
|
$self->extract_code('active'); |
|
224
|
10
|
100
|
|
|
|
68
|
$self->updated(1) if $code eq '3'; |
|
225
|
|
|
|
|
|
|
} elsif ($code =~ /E|1|4/x) { |
|
226
|
2
|
|
|
|
|
10
|
$self->extract_code('expired'); |
|
227
|
2
|
50
|
|
|
|
12
|
$self->updated(1) if $code eq '1'; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
12
|
|
|
|
|
44
|
$self->regn_purpose(shift); |
|
230
|
12
|
|
|
|
|
54
|
$self->regn_date(shift); |
|
231
|
12
|
|
|
|
|
51
|
$self->expiry_date(shift); |
|
232
|
12
|
|
|
|
|
57
|
$self->lastupdate_date(shift); |
|
233
|
12
|
|
|
|
|
90
|
$self->activation_date(shift); |
|
234
|
12
|
|
|
|
|
42
|
$self->name(_trim(shift)); |
|
235
|
12
|
|
|
|
|
41
|
$self->dba_name(_trim(shift)); |
|
236
|
12
|
|
|
|
|
28
|
$self->company_division(_trim(shift)); |
|
237
|
12
|
|
|
|
|
28
|
$self->division_no(_trim(shift)); |
|
238
|
12
|
|
|
|
|
51
|
my $paddr = Parse::SAMGov::Entity::Address->new( |
|
239
|
|
|
|
|
|
|
# the order of shifting matters |
|
240
|
|
|
|
|
|
|
address => _trim(join(' ', shift, shift)), |
|
241
|
|
|
|
|
|
|
city => shift, |
|
242
|
|
|
|
|
|
|
state => shift, |
|
243
|
|
|
|
|
|
|
zip => sprintf("%s-%s", shift, shift), |
|
244
|
|
|
|
|
|
|
country => shift, |
|
245
|
|
|
|
|
|
|
district => shift, |
|
246
|
|
|
|
|
|
|
); |
|
247
|
12
|
|
|
|
|
48
|
$self->physical_address($paddr); |
|
248
|
12
|
|
|
|
|
37
|
$self->start_date(shift); |
|
249
|
12
|
|
|
|
|
55
|
$self->fiscalyear_date(shift); |
|
250
|
12
|
|
|
|
|
36
|
$self->url(_trim(shift)); |
|
251
|
12
|
|
|
|
|
61
|
$self->entity_structure(shift); |
|
252
|
12
|
|
|
|
|
48
|
$self->incorporation_state(shift); |
|
253
|
12
|
|
|
|
|
46
|
$self->incorporation_country(shift); |
|
254
|
12
|
|
100
|
|
|
31
|
my $count = int(_trim(shift) || 0); |
|
255
|
12
|
100
|
|
|
|
39
|
if ($count > 0) { |
|
256
|
10
|
|
|
|
|
52
|
my @biztypes = grep { length($_) > 0 } split /~/, shift; |
|
|
34
|
|
|
|
|
84
|
|
|
257
|
10
|
|
|
|
|
54
|
$self->biztype([@biztypes]); |
|
258
|
|
|
|
|
|
|
} else { |
|
259
|
2
|
|
|
|
|
4
|
shift; # ignore |
|
260
|
|
|
|
|
|
|
} |
|
261
|
12
|
|
|
|
|
31
|
my $pnaics = _trim(shift); |
|
262
|
12
|
100
|
|
|
|
74
|
$self->NAICS->{$pnaics} = { is_primary => 1 } if length($pnaics); |
|
263
|
12
|
100
|
100
|
|
|
29
|
$count = int(_trim(shift) || 0) + (length($pnaics) ? 1 : 0); |
|
264
|
12
|
100
|
|
|
|
38
|
if ($count > 0) { |
|
265
|
10
|
|
|
|
|
36
|
my @naics = grep { length($_) > 0 } split /~/, shift; |
|
|
16
|
|
|
|
|
42
|
|
|
266
|
10
|
|
|
|
|
25
|
foreach my $c (@naics) { |
|
267
|
16
|
50
|
|
|
|
107
|
if ($c =~ /(\d+)(Y|N|E)/) { |
|
268
|
16
|
100
|
|
|
|
46
|
$self->NAICS->{$1} = {} unless ref $self->NAICS->{$1} eq 'HASH'; |
|
269
|
16
|
100
|
|
|
|
68
|
$self->NAICS->{$1}->{is_primary} = 1 if $pnaics eq $1; |
|
270
|
16
|
100
|
|
|
|
64
|
$self->NAICS->{$1}->{small_biz} = 1 if $2 eq 'Y'; |
|
271
|
16
|
100
|
|
|
|
113
|
$self->NAICS->{$1}->{small_biz} = 0 if $2 eq 'N'; |
|
272
|
16
|
100
|
|
|
|
61
|
$self->NAICS->{$1}->{exception} = {} if $2 eq 'E'; |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
} else { |
|
276
|
2
|
|
|
|
|
2
|
shift; # ignore |
|
277
|
|
|
|
|
|
|
} |
|
278
|
12
|
|
100
|
|
|
34
|
$count = int(_trim(shift) || 0); |
|
279
|
12
|
100
|
|
|
|
33
|
if ($count > 0) { |
|
280
|
2
|
|
|
|
|
8
|
my @psc = grep { length ($_) > 0 } split /~/, shift; |
|
|
2
|
|
|
|
|
8
|
|
|
281
|
2
|
|
|
|
|
13
|
$self->PSC([@psc]); |
|
282
|
|
|
|
|
|
|
} else { |
|
283
|
10
|
|
|
|
|
14
|
shift; # ignore |
|
284
|
|
|
|
|
|
|
} |
|
285
|
12
|
100
|
|
|
|
65
|
$self->creditcard((shift eq 'Y') ? 1 : 0); |
|
286
|
12
|
|
|
|
|
18
|
$code = shift; # re-use variable |
|
287
|
12
|
50
|
|
|
|
41
|
$self->correspondence_type('mail') if $code eq 'M'; |
|
288
|
12
|
50
|
|
|
|
28
|
$self->correspondence_type('fax') if $code eq 'F'; |
|
289
|
12
|
50
|
|
|
|
27
|
$self->correspondence_type('email') if $code eq 'E'; |
|
290
|
12
|
|
|
|
|
62
|
my $maddr = Parse::SAMGov::Entity::Address->new( |
|
291
|
|
|
|
|
|
|
# the order of shifting matters |
|
292
|
|
|
|
|
|
|
address => _trim(join(' ', shift, shift)), |
|
293
|
|
|
|
|
|
|
city => shift, |
|
294
|
|
|
|
|
|
|
zip => sprintf("%s-%s", shift, shift), |
|
295
|
|
|
|
|
|
|
country => shift, |
|
296
|
|
|
|
|
|
|
state => shift, |
|
297
|
|
|
|
|
|
|
); |
|
298
|
12
|
|
|
|
|
51
|
$self->mailing_address($maddr); |
|
299
|
12
|
|
|
|
|
38
|
for my $i (0..5) { |
|
300
|
72
|
|
|
|
|
175
|
my $poc = Parse::SAMGov::Entity::PointOfContact->new( |
|
301
|
|
|
|
|
|
|
first => _trim(shift), |
|
302
|
|
|
|
|
|
|
middle => _trim(shift), |
|
303
|
|
|
|
|
|
|
last => _trim(shift), |
|
304
|
|
|
|
|
|
|
title => _trim(shift), |
|
305
|
|
|
|
|
|
|
address => _trim(join(' ', shift, shift)), |
|
306
|
|
|
|
|
|
|
city => shift, |
|
307
|
|
|
|
|
|
|
zip => sprintf("%s-%s", shift, shift), |
|
308
|
|
|
|
|
|
|
country => shift, |
|
309
|
|
|
|
|
|
|
state => shift, |
|
310
|
|
|
|
|
|
|
phone => shift, |
|
311
|
|
|
|
|
|
|
phone_ext => shift, |
|
312
|
|
|
|
|
|
|
phone_nonUS => shift, |
|
313
|
|
|
|
|
|
|
fax => shift, |
|
314
|
|
|
|
|
|
|
email => shift, |
|
315
|
|
|
|
|
|
|
); |
|
316
|
72
|
100
|
|
|
|
302
|
$self->POC_gov($poc) if $i == 0; |
|
317
|
72
|
100
|
|
|
|
183
|
$self->POC_gov_alt($poc) if $i == 1; |
|
318
|
72
|
100
|
|
|
|
170
|
$self->POC_pastperf($poc) if $i == 2; |
|
319
|
72
|
100
|
|
|
|
178
|
$self->POC_pastperf_alt($poc) if $i == 3; |
|
320
|
72
|
100
|
|
|
|
214
|
$self->POC_elec($poc) if $i == 4; |
|
321
|
72
|
100
|
|
|
|
227
|
$self->POC_elec_alt($poc) if $i == 5; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
12
|
|
100
|
|
|
37
|
$count = int(_trim(shift) || 0); |
|
324
|
12
|
100
|
|
|
|
43
|
if ($count > 0) { |
|
325
|
2
|
|
|
|
|
11
|
my @naics = grep { length($_) > 0 } split /~/, shift; |
|
|
4
|
|
|
|
|
17
|
|
|
326
|
2
|
|
|
|
|
8
|
foreach my $c (@naics) { |
|
327
|
4
|
50
|
|
|
|
28
|
if ($c =~ /(\d+)([YN ]*)/) { |
|
328
|
4
|
|
|
|
|
20
|
my @es = split //, $2; |
|
329
|
4
|
50
|
|
|
|
13
|
if (@es) { |
|
330
|
4
|
50
|
|
|
|
14
|
$self->NAICS->{$1}->{exception} = {} unless ref $self->NAICS->{$1}->{exception} eq 'HASH'; |
|
331
|
4
|
50
|
|
|
|
18
|
$self->NAICS->{$1}->{exception}->{small_biz} = 1 if $es[0] eq 'Y'; |
|
332
|
4
|
50
|
|
|
|
21
|
$self->NAICS->{$1}->{exception}->{small_biz} = 0 if $es[0] eq 'N'; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
} else { |
|
337
|
10
|
|
|
|
|
18
|
shift; # ignore |
|
338
|
|
|
|
|
|
|
} |
|
339
|
12
|
|
|
|
|
25
|
$code = shift; |
|
340
|
12
|
50
|
|
|
|
38
|
$self->delinquent_fed_debt(1) if $code eq 'Y'; |
|
341
|
12
|
100
|
|
|
|
52
|
$self->delinquent_fed_debt(0) if $code eq 'N'; |
|
342
|
12
|
|
|
|
|
34
|
$self->exclusion_status(_trim(shift)); |
|
343
|
12
|
|
100
|
|
|
26
|
$count = int(_trim(shift) || 0); |
|
344
|
12
|
50
|
|
|
|
34
|
if ($count > 0) { |
|
345
|
0
|
|
|
|
|
0
|
my @sba = grep { length($_) > 0 } split /~/, shift; |
|
|
0
|
|
|
|
|
0
|
|
|
346
|
0
|
|
|
|
|
0
|
foreach my $c (@sba) { |
|
347
|
0
|
0
|
|
|
|
0
|
if ($c =~ /(\w{2})(\d{8})/) { |
|
348
|
0
|
|
|
|
|
0
|
my $t = $1; |
|
349
|
0
|
0
|
|
|
|
0
|
$self->SBA->{$t} = {} unless ref $self->SBA->{$t} eq 'HASH'; |
|
350
|
0
|
|
|
|
|
0
|
$self->SBA->{$t}->{description} = $self->SBA_descriptions->{$t}; |
|
351
|
0
|
|
|
|
|
0
|
$self->SBA->{$t}->{expiration} = _parse_yyyymmdd($2); |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
} else { |
|
355
|
12
|
|
|
|
|
22
|
shift; # ignore |
|
356
|
|
|
|
|
|
|
} |
|
357
|
12
|
100
|
|
|
|
56
|
$self->is_private(length(shift) ? 1 : 0); |
|
358
|
12
|
|
100
|
|
|
24
|
$count = int(_trim(shift) || 0); |
|
359
|
12
|
50
|
|
|
|
32
|
if ($count > 0) { |
|
360
|
0
|
|
|
|
|
0
|
my @dres = grep { length($_) > 0 } split /~/, shift; |
|
|
0
|
|
|
|
|
0
|
|
|
361
|
0
|
|
|
|
|
0
|
my $h = {}; |
|
362
|
0
|
|
|
|
|
0
|
my %desc = ( |
|
363
|
|
|
|
|
|
|
ANY => 'Any area', |
|
364
|
|
|
|
|
|
|
CTY => 'County', |
|
365
|
|
|
|
|
|
|
STA => 'State', |
|
366
|
|
|
|
|
|
|
MSA => 'Metropolitan Service Area', |
|
367
|
|
|
|
|
|
|
); |
|
368
|
0
|
|
|
|
|
0
|
foreach my $c (@dres) { |
|
369
|
0
|
0
|
|
|
|
0
|
if ($c =~ /(\w{3})(\w*)/) { |
|
370
|
0
|
0
|
|
|
|
0
|
$h->{$1} = {} unless ref $h->{$1} eq 'HASH'; |
|
371
|
0
|
|
|
|
|
0
|
$h->{$1}->{description} = $desc{$1}; |
|
372
|
0
|
0
|
|
|
|
0
|
$h->{$1}->{areas} = [] unless ref $h->{$1}->{areas} eq 'HASH'; |
|
373
|
0
|
|
|
|
|
0
|
my $a = _trim($2); |
|
374
|
0
|
0
|
|
|
|
0
|
push @{$h->{$1}->{areas}}, $a if length $a; |
|
|
0
|
|
|
|
|
0
|
|
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
} |
|
377
|
0
|
|
|
|
|
0
|
$self->disaster_response($h); |
|
378
|
|
|
|
|
|
|
} else { |
|
379
|
12
|
|
|
|
|
19
|
shift; # ignore |
|
380
|
|
|
|
|
|
|
} |
|
381
|
12
|
|
|
|
|
24
|
my $eof = shift; |
|
382
|
12
|
50
|
|
|
|
38
|
carp "Invalid end of record '$eof' seen. Expected '!end'" if $eof ne '!end'; |
|
383
|
12
|
|
|
|
|
236
|
return 1; |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
sub load_v2 { |
|
387
|
4
|
|
|
4
|
0
|
6
|
my $self = shift; |
|
388
|
4
|
50
|
|
|
|
12
|
return unless (scalar(@_) == 142); |
|
389
|
4
|
|
|
|
|
17
|
$self->UEI(shift);## UEI SAM 12 chars |
|
390
|
4
|
|
|
|
|
13
|
$self->DUNS(shift);## DUNS UEI 9 chars |
|
391
|
4
|
|
|
|
|
15
|
$self->EEFTI(shift);## 4 chars |
|
392
|
4
|
|
|
|
|
13
|
$self->CAGE(shift);## 5 chars |
|
393
|
4
|
|
|
|
|
13
|
$self->DODAAC(shift);## 9 chars |
|
394
|
4
|
|
|
|
|
13
|
$self->updated(0); |
|
395
|
4
|
|
|
|
|
9
|
my $code = shift; |
|
396
|
4
|
50
|
|
|
|
24
|
if ($code =~ /A|2|3/x) { |
|
|
|
0
|
|
|
|
|
|
|
397
|
4
|
|
|
|
|
13
|
$self->extract_code('active'); |
|
398
|
4
|
50
|
|
|
|
16
|
$self->updated(1) if $code eq '3'; |
|
399
|
|
|
|
|
|
|
} elsif ($code =~ /E|1|4/x) { |
|
400
|
0
|
|
|
|
|
0
|
$self->extract_code('expired'); |
|
401
|
0
|
0
|
|
|
|
0
|
$self->updated(1) if $code eq '1'; |
|
402
|
|
|
|
|
|
|
} |
|
403
|
4
|
|
|
|
|
15
|
$self->regn_purpose(shift); |
|
404
|
4
|
|
|
|
|
13
|
$self->regn_date(shift); |
|
405
|
4
|
|
|
|
|
19
|
$self->expiry_date(shift); |
|
406
|
4
|
|
|
|
|
18
|
$self->lastupdate_date(shift); |
|
407
|
4
|
|
|
|
|
18
|
$self->activation_date(shift); |
|
408
|
4
|
|
|
|
|
15
|
$self->name(_trim(shift)); |
|
409
|
4
|
|
|
|
|
9
|
$self->dba_name(_trim(shift)); |
|
410
|
4
|
|
|
|
|
9
|
$self->company_division(_trim(shift));## entity division |
|
411
|
4
|
|
|
|
|
8
|
$self->division_no(_trim(shift)); ## entity division number |
|
412
|
4
|
|
|
|
|
18
|
my $paddr = Parse::SAMGov::Entity::Address->new( |
|
413
|
|
|
|
|
|
|
# the order of shifting matters |
|
414
|
|
|
|
|
|
|
address => _trim(join(' ', shift, shift)), |
|
415
|
|
|
|
|
|
|
city => shift, |
|
416
|
|
|
|
|
|
|
state => shift, |
|
417
|
|
|
|
|
|
|
zip => sprintf("%s-%s", shift, shift), |
|
418
|
|
|
|
|
|
|
country => shift, |
|
419
|
|
|
|
|
|
|
district => shift, |
|
420
|
|
|
|
|
|
|
); |
|
421
|
4
|
|
|
|
|
17
|
$self->physical_address($paddr); |
|
422
|
4
|
|
|
|
|
14
|
$self->dnb_open_data(shift);# D&B Open Data flag |
|
423
|
4
|
|
|
|
|
26
|
$self->start_date(shift); |
|
424
|
4
|
|
|
|
|
16
|
$self->fiscalyear_date(shift); |
|
425
|
4
|
|
|
|
|
12
|
$self->url(_trim(shift)); |
|
426
|
4
|
|
|
|
|
17
|
$self->entity_structure(shift); |
|
427
|
4
|
|
|
|
|
17
|
$self->incorporation_state(shift); |
|
428
|
4
|
|
|
|
|
11
|
$self->incorporation_country(shift); |
|
429
|
4
|
|
50
|
|
|
11
|
my $count = int(_trim(shift) || 0); |
|
430
|
4
|
50
|
|
|
|
13
|
if ($count > 0) { |
|
431
|
4
|
|
|
|
|
15
|
my @biztypes = grep { length($_) > 0 } split /~/, shift; |
|
|
6
|
|
|
|
|
43
|
|
|
432
|
4
|
|
|
|
|
17
|
$self->biztype([@biztypes]); |
|
433
|
|
|
|
|
|
|
} else { |
|
434
|
0
|
|
|
|
|
0
|
shift; # ignore |
|
435
|
|
|
|
|
|
|
} |
|
436
|
4
|
|
|
|
|
17
|
my $pnaics = _trim(shift); |
|
437
|
4
|
50
|
|
|
|
25
|
$self->NAICS->{$pnaics} = { is_primary => 1 } if length ($pnaics); |
|
438
|
4
|
50
|
50
|
|
|
9
|
$count = int(_trim(shift) || 0) + (length($pnaics) ? 1 : 0); |
|
439
|
4
|
50
|
|
|
|
9
|
if ($count > 0) { |
|
440
|
4
|
|
|
|
|
39
|
my @naics = grep { length($_) > 0 } split /~/, shift; |
|
|
62
|
|
|
|
|
131
|
|
|
441
|
4
|
|
|
|
|
15
|
foreach my $c (@naics) { |
|
442
|
62
|
100
|
|
|
|
228
|
if ($c =~ /(\d+)(Y|N|E)/) { |
|
443
|
60
|
100
|
|
|
|
122
|
$self->NAICS->{$1} = {} unless ref $self->NAICS->{$1} eq 'HASH'; |
|
444
|
60
|
100
|
|
|
|
169
|
$self->NAICS->{$1}->{is_primary} = 1 if $pnaics eq $1; |
|
445
|
60
|
50
|
|
|
|
116
|
$self->NAICS->{$1}->{small_biz} = 1 if $2 eq 'Y'; |
|
446
|
60
|
100
|
|
|
|
165
|
$self->NAICS->{$1}->{small_biz} = 0 if $2 eq 'N'; |
|
447
|
60
|
100
|
|
|
|
148
|
$self->NAICS->{$1}->{exception} = {} if $2 eq 'E'; |
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
} |
|
450
|
|
|
|
|
|
|
} else { |
|
451
|
0
|
|
|
|
|
0
|
shift; # ignore |
|
452
|
|
|
|
|
|
|
} |
|
453
|
4
|
|
50
|
|
|
11
|
$count = int(_trim(shift) || 0); |
|
454
|
4
|
50
|
|
|
|
12
|
if ($count > 0) { |
|
455
|
4
|
|
|
|
|
18
|
my @psc = grep { length ($_) > 0 } split /~/, shift; |
|
|
24
|
|
|
|
|
46
|
|
|
456
|
4
|
|
|
|
|
19
|
$self->PSC([@psc]); |
|
457
|
|
|
|
|
|
|
} else { |
|
458
|
0
|
|
|
|
|
0
|
shift; # ignore |
|
459
|
|
|
|
|
|
|
} |
|
460
|
4
|
50
|
|
|
|
18
|
$self->creditcard((shift eq 'Y') ? 1 : 0); |
|
461
|
4
|
|
|
|
|
8
|
$code = shift; # re-use variable |
|
462
|
4
|
50
|
|
|
|
36
|
$self->correspondence_type('mail') if $code eq 'M'; |
|
463
|
4
|
50
|
|
|
|
11
|
$self->correspondence_type('fax') if $code eq 'F'; |
|
464
|
4
|
50
|
|
|
|
7
|
$self->correspondence_type('email') if $code eq 'E'; |
|
465
|
4
|
|
|
|
|
18
|
my $maddr = Parse::SAMGov::Entity::Address->new( |
|
466
|
|
|
|
|
|
|
# the order of shifting matters |
|
467
|
|
|
|
|
|
|
address => _trim(join(' ', shift, shift)), |
|
468
|
|
|
|
|
|
|
city => shift, |
|
469
|
|
|
|
|
|
|
zip => sprintf("%s-%s", shift, shift), |
|
470
|
|
|
|
|
|
|
country => shift, |
|
471
|
|
|
|
|
|
|
state => shift, |
|
472
|
|
|
|
|
|
|
); |
|
473
|
4
|
|
|
|
|
17
|
$self->mailing_address($maddr); |
|
474
|
4
|
|
|
|
|
14
|
for my $i (0..5) { |
|
475
|
|
|
|
|
|
|
### V2 has no email/phone/fax |
|
476
|
24
|
|
|
|
|
55
|
my $poc = Parse::SAMGov::Entity::PointOfContact->new( |
|
477
|
|
|
|
|
|
|
first => _trim(shift), |
|
478
|
|
|
|
|
|
|
middle => _trim(shift), |
|
479
|
|
|
|
|
|
|
last => _trim(shift), |
|
480
|
|
|
|
|
|
|
title => _trim(shift), |
|
481
|
|
|
|
|
|
|
address => _trim(join(' ', shift, shift)), |
|
482
|
|
|
|
|
|
|
city => shift, |
|
483
|
|
|
|
|
|
|
zip => sprintf("%s-%s", shift, shift), |
|
484
|
|
|
|
|
|
|
country => shift, |
|
485
|
|
|
|
|
|
|
state => shift, |
|
486
|
|
|
|
|
|
|
); |
|
487
|
24
|
100
|
|
|
|
72
|
$self->POC_gov($poc) if $i == 0; |
|
488
|
24
|
100
|
|
|
|
72
|
$self->POC_gov_alt($poc) if $i == 1; |
|
489
|
24
|
100
|
|
|
|
50
|
$self->POC_pastperf($poc) if $i == 2; |
|
490
|
24
|
100
|
|
|
|
48
|
$self->POC_pastperf_alt($poc) if $i == 3; |
|
491
|
24
|
100
|
|
|
|
56
|
$self->POC_elec($poc) if $i == 4; |
|
492
|
24
|
100
|
|
|
|
64
|
$self->POC_elec_alt($poc) if $i == 5; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
4
|
|
50
|
|
|
11
|
$count = int(_trim(shift) || 0); |
|
495
|
4
|
50
|
|
|
|
12
|
if ($count > 0) { |
|
496
|
4
|
|
|
|
|
15
|
my @naics = grep { length($_) > 0 } split /~/, shift; |
|
|
12
|
|
|
|
|
27
|
|
|
497
|
4
|
|
|
|
|
9
|
foreach my $c (@naics) { |
|
498
|
12
|
50
|
|
|
|
65
|
if ($c =~ /(\d+)([YN ]*)/) { |
|
499
|
12
|
|
|
|
|
45
|
my @es = split //, $2; |
|
500
|
12
|
50
|
|
|
|
23
|
if (@es) { |
|
501
|
12
|
50
|
|
|
|
30
|
$self->NAICS->{$1}->{exception} = {} unless ref $self->NAICS->{$1}->{exception} eq 'HASH'; |
|
502
|
12
|
50
|
|
|
|
22
|
$self->NAICS->{$1}->{exception}->{small_biz} = 1 if $es[0] eq 'Y'; |
|
503
|
12
|
50
|
|
|
|
28
|
$self->NAICS->{$1}->{exception}->{small_biz} = 0 if $es[0] eq 'N'; |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
} |
|
507
|
|
|
|
|
|
|
} else { |
|
508
|
0
|
|
|
|
|
0
|
shift; # ignore |
|
509
|
|
|
|
|
|
|
} |
|
510
|
4
|
|
|
|
|
8
|
$code = shift; |
|
511
|
4
|
50
|
|
|
|
9
|
$self->delinquent_fed_debt(1) if $code eq 'Y'; |
|
512
|
4
|
50
|
|
|
|
34
|
$self->delinquent_fed_debt(0) if $code eq 'N'; |
|
513
|
4
|
|
|
|
|
11
|
$self->exclusion_status(_trim(shift)); |
|
514
|
4
|
|
50
|
|
|
9
|
$count = int(_trim(shift) || 0); |
|
515
|
4
|
50
|
|
|
|
11
|
if ($count > 0) { |
|
516
|
0
|
|
|
|
|
0
|
my @sba = grep { length($_) > 0 } split /~/, shift; |
|
|
0
|
|
|
|
|
0
|
|
|
517
|
0
|
|
|
|
|
0
|
foreach my $c (@sba) { |
|
518
|
0
|
0
|
|
|
|
0
|
if ($c =~ /(\w{2})(\d{8})/) { |
|
519
|
0
|
|
|
|
|
0
|
my $t = $1; |
|
520
|
0
|
0
|
|
|
|
0
|
$self->SBA->{$t} = {} unless ref $self->SBA->{$t} eq 'HASH'; |
|
521
|
0
|
|
|
|
|
0
|
$self->SBA->{$t}->{description} = $self->SBA_descriptions->{$t}; |
|
522
|
0
|
|
|
|
|
0
|
$self->SBA->{$t}->{expiration} = _parse_yyyymmdd($2); |
|
523
|
|
|
|
|
|
|
} |
|
524
|
|
|
|
|
|
|
} |
|
525
|
|
|
|
|
|
|
} else { |
|
526
|
4
|
|
|
|
|
7
|
shift; # ignore |
|
527
|
|
|
|
|
|
|
} |
|
528
|
4
|
50
|
|
|
|
19
|
$self->is_private(length(shift) ? 1 : 0); |
|
529
|
4
|
|
50
|
|
|
9
|
$count = int(_trim(shift) || 0); |
|
530
|
4
|
50
|
|
|
|
10
|
if ($count > 0) { |
|
531
|
0
|
|
|
|
|
0
|
my @dres = grep { length($_) > 0 } split /~/, shift; |
|
|
0
|
|
|
|
|
0
|
|
|
532
|
0
|
|
|
|
|
0
|
my $h = {}; |
|
533
|
0
|
|
|
|
|
0
|
my %desc = ( |
|
534
|
|
|
|
|
|
|
ANY => 'Any area', |
|
535
|
|
|
|
|
|
|
CTY => 'County', |
|
536
|
|
|
|
|
|
|
STA => 'State', |
|
537
|
|
|
|
|
|
|
MSA => 'Metropolitan Service Area', |
|
538
|
|
|
|
|
|
|
); |
|
539
|
0
|
|
|
|
|
0
|
foreach my $c (@dres) { |
|
540
|
0
|
0
|
|
|
|
0
|
if ($c =~ /(\w{3})(\w*)/) { |
|
541
|
0
|
0
|
|
|
|
0
|
$h->{$1} = {} unless ref $h->{$1} eq 'HASH'; |
|
542
|
0
|
|
|
|
|
0
|
$h->{$1}->{description} = $desc{$1}; |
|
543
|
0
|
0
|
|
|
|
0
|
$h->{$1}->{areas} = [] unless ref $h->{$1}->{areas} eq 'HASH'; |
|
544
|
0
|
|
|
|
|
0
|
my $a = _trim($2); |
|
545
|
0
|
0
|
|
|
|
0
|
push @{$h->{$1}->{areas}}, $a if length $a; |
|
|
0
|
|
|
|
|
0
|
|
|
546
|
|
|
|
|
|
|
} |
|
547
|
|
|
|
|
|
|
} |
|
548
|
0
|
|
|
|
|
0
|
$self->disaster_response($h); |
|
549
|
|
|
|
|
|
|
} else { |
|
550
|
4
|
|
|
|
|
6
|
shift; # ignore |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
## field 122-141 are Flex Fields with length 0 |
|
553
|
4
|
|
|
|
|
11
|
for (122 .. 141) { |
|
554
|
80
|
|
|
|
|
95
|
shift;#ignore |
|
555
|
|
|
|
|
|
|
} |
|
556
|
4
|
|
|
|
|
8
|
my $eof = shift; |
|
557
|
4
|
50
|
|
|
|
11
|
carp "Invalid end of record '$eof' seen. Expected '!end'" if $eof ne '!end'; |
|
558
|
4
|
|
|
|
|
54
|
return 1; |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
1; |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=pod |
|
564
|
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=encoding UTF-8 |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=head1 NAME |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Parse::SAMGov::Entity - Object to denote each Entity in SAM |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head1 VERSION |
|
572
|
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
version 0.202 |
|
574
|
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
### for V2 files |
|
578
|
|
|
|
|
|
|
my $e_v2 = Parse::SAMGov::Entity->new(UEI => 12345); |
|
579
|
|
|
|
|
|
|
say $e_v2; #... stringification supported ... |
|
580
|
|
|
|
|
|
|
### for V1 files |
|
581
|
|
|
|
|
|
|
my $e_v1 = Parse::SAMGov::Entity->new(DUNS => 12345); |
|
582
|
|
|
|
|
|
|
say $e_v1; #... stringification supported ... |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
=head1 METHODS |
|
585
|
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
=head2 UEI |
|
587
|
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
This holds the SAM Unique Entity Identifier (UEI) and is 12 characters long. This number is only valid for V2 files on or after 2022. |
|
589
|
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=head2 DUNS |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
This holds the unique identifier of the entity, currently the Data |
|
593
|
|
|
|
|
|
|
Universal Numbering System (DUNS) number. This has a maximum length of 9 characters. |
|
594
|
|
|
|
|
|
|
This number can be gotten from Dun & Bradstreet. This is only valid for V1 files on or before 2021. |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=head2 DUNSplus4 |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
This holds the DUNS+4 value which is of 4 characters. If an entity doesn't have |
|
599
|
|
|
|
|
|
|
this value set, it will be set as '0000'. This is only valid for V1 files on or before 2021. |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
=head2 EEFTI |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
The Entity EFT Indicator is an entity-selected Electronics Funds Transfer (EFT) Identifier used to distinguish more than one remittance location for payment. An entity can only provide an Entity EFT Indicator if they provide an additional set of EFT information. If the entity does not need to provide additional EFT information, the registration will show a value of null. CAGE codes are assigned at the Entity EFT Indicator level. |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=head2 CAGE |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
This holds the CAGE code of the Entity. |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=head2 DODAAC |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
This holds the DODAAC code of the entity. |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=head2 extract_code |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
This denotes whether the SAM entry is active or expired |
|
616
|
|
|
|
|
|
|
during extraction of the data. |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
=head2 updated |
|
619
|
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
This denotes whether the SAM entry has been updated recently. Has a boolean |
|
621
|
|
|
|
|
|
|
value of 1 if updated and 0 or undef otherwise. |
|
622
|
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=head2 regn_purpose |
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
This denotes whether the purpose of registration is Federal Assistance Awards, |
|
626
|
|
|
|
|
|
|
All Awards, IGT-only, Federal Assistance Awards & IGT or All Awards & IGT. |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head2 regn_date |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Registration date of the entity with the input in YYYYMMDD format and it returns |
|
631
|
|
|
|
|
|
|
a DateTime object. |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=head2 expiry_date |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
Expiration date of the registration of the entity. The input is in YYYYMMDD |
|
636
|
|
|
|
|
|
|
format and it returns a DateTime object. |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=head2 lastupdate_date |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
Last update date of the registration of the entity. The input is in YYYYMMDD |
|
641
|
|
|
|
|
|
|
format and it returns a DateTime object. |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head2 activation_date |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
Activation date of the registration of the entity. The input is in YYYYMMDD |
|
646
|
|
|
|
|
|
|
format and it returns a DateTime object. |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
=head2 name |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
The legal business name of the entity. |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=head2 dba_name |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
The Doing Business As (DBA) name of the entity. |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=head2 company_division |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
The company division (V1) listed in the entity. Same as Entity Division in V2. |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
=head2 division_no |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
The divison number of the company division (V1) or entity division (V2). |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=head2 physical_address |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
This is the physical address of the entity represented as a |
|
667
|
|
|
|
|
|
|
Parse::SAMGov::Entity::Address object. |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=head2 start_date |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
This denotes the business start date. It takes as input the date in YYYYMMDD |
|
672
|
|
|
|
|
|
|
format and returns a DateTime object. |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=head2 fiscalyear_date |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
This denotes the current fiscal year end close date in YYYYMMDD format and |
|
677
|
|
|
|
|
|
|
returns a DateTime object. |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=head2 url |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
The corporate URL is denoted in this method. Returns a URI object and takes a |
|
682
|
|
|
|
|
|
|
string value. |
|
683
|
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=head2 entity_structure |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
Get/Set the entity structure of the entity. This is a 2-letter code |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=head2 entity_structure_descriptions |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
Describe the 2-letter code for entity structure (V2). |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=head2 incorporation_state |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
Get/Set the two-character abbreviation of the state of incorporation. |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=head2 incorporation_country |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
Get/Set the three-character abbreviation of the country of incorporation. |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=head2 biztype |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
Get/Set the various business types that the entity holds. Requires an array |
|
703
|
|
|
|
|
|
|
reference. The full list of business type codes can be retrieved from the SAM |
|
704
|
|
|
|
|
|
|
Functional Data Dictionary. |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=head2 is_smallbiz |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
Returns 1 or 0 if the business is defined as a small business or not. |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=head2 NAICS |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
Get/Set the NAICS codes for the entity. This is a hash reference with the keys |
|
713
|
|
|
|
|
|
|
being the numeric NAICS codes and the values being a hash reference with the |
|
714
|
|
|
|
|
|
|
following keys: |
|
715
|
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
{ |
|
717
|
|
|
|
|
|
|
124567 => { |
|
718
|
|
|
|
|
|
|
small_biz => 1, |
|
719
|
|
|
|
|
|
|
exceptions => { |
|
720
|
|
|
|
|
|
|
small_biz => 0, |
|
721
|
|
|
|
|
|
|
# ... undocumented others ... |
|
722
|
|
|
|
|
|
|
}, |
|
723
|
|
|
|
|
|
|
}, |
|
724
|
|
|
|
|
|
|
# ... |
|
725
|
|
|
|
|
|
|
} |
|
726
|
|
|
|
|
|
|
whether it is a small |
|
727
|
|
|
|
|
|
|
business (value is 1) or not (value is 0) or has an exception (value is 2). |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=head2 PSC |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
Get/Set the PSC codes for the entity. This requires an array reference. |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=head2 creditcard |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
This denotes whether the entity uses a credit card. |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=head2 correspondence_type |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
This denotes whether the entity prefers correspondence by mail, fax or email. |
|
740
|
|
|
|
|
|
|
Returns a string of value 'mail', 'fax' or 'email'. |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=head2 mailing_address |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
The mailing address of the entity as a L<Parse::SAMGov::Entity::Address> object. |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=head2 POC_gov |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
This denotes the Government business Point of Contact for the entity and holds an |
|
749
|
|
|
|
|
|
|
L<Parse::SAMGov::Entity::PointOfContact> object. |
|
750
|
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
=head2 POC_gov_alt |
|
752
|
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
This denotes the alternative Government business Point of Contact for the entity and |
|
754
|
|
|
|
|
|
|
holds an L<Parse::SAMGov::Entity::PointOfContact> object. |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=head2 POC_pastperf |
|
757
|
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
This denotes the Past Performance Point of Contact for the entity and |
|
759
|
|
|
|
|
|
|
holds an L<Parse::SAMGov::Entity::PointOfContact> object. |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
=head2 POC_pastperf_alt |
|
762
|
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
This denotes the alternative Past Performance Point of Contact for the entity and |
|
764
|
|
|
|
|
|
|
holds an L<Parse::SAMGov::Entity::PointOfContact> object. |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=head2 POC_elec |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
This denotes the electronic business Point of Contact for the entity and |
|
769
|
|
|
|
|
|
|
holds an L<Parse::SAMGov::Entity::PointOfContact> object. |
|
770
|
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
=head2 POC_elec_alt |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
This denotes the alternative electronic business Point of Contact for the entity and |
|
774
|
|
|
|
|
|
|
holds an L<Parse::SAMGov::Entity::PointOfContact> object. |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=head2 delinquent_fed_debt |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
Get/Set the delinquent federal debt flag. Also known as Debt Subject to Offset Flag in V2. |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
=head2 exclusion_status |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
Get/Set the exclusion status flag. |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
=head2 is_private |
|
785
|
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
This flag denotes whether the listing is private or not. |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
=head2 dnb_open_data |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
This flag denotes whether this is a D&B Open Data or not. V2 only. |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
=head2 SBA |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
This holds a hash-ref of Small Business Administration codes such as Hubzone, |
|
795
|
|
|
|
|
|
|
8(a) certifications and the expiration dates. The structure looks like below: |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
{ |
|
798
|
|
|
|
|
|
|
A4 => { description => 'SBA Certified Small Disadvantaged Busines', |
|
799
|
|
|
|
|
|
|
expiration => '2016-12-01', #... this is a DateTime object... |
|
800
|
|
|
|
|
|
|
}, |
|
801
|
|
|
|
|
|
|
} |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=head2 disaster_response |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
This holds an array ref of disaster response (FEMA) codes that the entity falls |
|
806
|
|
|
|
|
|
|
under, if applicable. |
|
807
|
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
=head1 AUTHOR |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
Vikas N Kumar <vikas@cpan.org> |
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
This software is copyright (c) 2023 by Selective Intellect LLC. |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
817
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
=cut |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
__END__ |
|
822
|
|
|
|
|
|
|
### COPYRIGHT: Selective Intellect LLC. |
|
823
|
|
|
|
|
|
|
### AUTHOR: Vikas N Kumar <vikas@cpan.org> |