diff options
Diffstat (limited to 'FS')
55 files changed, 3985 insertions, 252 deletions
@@ -3,7 +3,7 @@ package FS; use strict; use vars qw($VERSION); -$VERSION = '3.0'; +$VERSION = '3.1git'; #find missing entries in this file with: # for a in `ls *pm | cut -d. -f1`; do grep 'L<FS::'$a'>' ../FS.pm >/dev/null || echo "missing $a" ; done @@ -231,6 +231,8 @@ L<FS::pkg_class> - Package class class L<FS::part_pkg> - Package definition class +L<FS::part_pkg_msgcat> - Package definition localization class + L<FS::part_pkg_link> - Package definition link class L<FS::part_pkg_taxclass> - Tax class class diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index a60d033d6..bfb39b4ad 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -305,6 +305,8 @@ tie my %rights, 'Tie::IxHash', 'Usage: Call Detail Records (CDRs)', 'Usage: Unrateable CDRs', 'Usage: Time worked', + { rightname=>'Employees: Commission Report', global=>1 }, + { rightname=>'Employees: Audit Report', global=>1 }, #{ rightname => 'List customers of all agents', global=>1 }, ], diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 08e506cf1..01e0ebc33 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -50,7 +50,7 @@ $me = '[FS::ClientAPI::MyAccount]'; use vars qw( @cust_main_editable_fields @location_editable_fields ); @cust_main_editable_fields = qw( - first last daytime night fax mobile + first last company daytime night fax mobile locale payby payinfo payname paystart_month paystart_year payissue payip ss paytype paystate stateid stateid_state @@ -636,11 +636,12 @@ sub billing_history { push @history, { 'type' => 'Line item', - 'description' => $_->desc. ( $_->sdate && $_->edate - ? ' '. time2str('%d-%b-%Y', $_->sdate). - ' To '. time2str('%d-%b-%Y', $_->edate) - : '' - ), + 'description' => $_->desc( $cust_main->locale ). + ( $_->sdate && $_->edate + ? ' '. time2str('%d-%b-%Y', $_->sdate). + ' To '. time2str('%d-%b-%Y', $_->edate) + : '' + ), 'amount' => sprintf('%.2f', $_->setup + $_->recur ), 'date' => $cust_bill->_date, 'date_pretty' => time2str('%m/%d/%Y', $cust_bill->_date ), @@ -1584,7 +1585,7 @@ sub list_pkgs { my $primary_cust_svc = $_->primary_cust_svc; +{ $_->hash, $_->part_pkg->hash, - pkg_label => $_->pkg_label, + pkg_label => $_->pkg_locale, status => $_->status, part_svc => [ map { $_->hashref } @@ -1698,7 +1699,7 @@ sub list_svcs { 'svcdb' => $svcdb, 'label' => $label, 'value' => $value, - 'pkg_label' => $cust_pkg->pkg_label, + 'pkg_label' => $cust_pkg->pkg_locale, 'pkg_status' => $cust_pkg->status, 'readonly' => ($part_svc->selfservice_access eq 'readonly'), ); diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index 2fcc4b143..1dbb20bc7 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -773,13 +773,15 @@ sub new_customer { # " new customer: $bill_error" # if $bill_error; - $bill_error = $cust_main->realtime_collect( - method => FS::payby->payby2bop( $packet->{payby} ), - depend_jobnum => $placeholder->jobnum, - selfservice => 1, - ); - #warn "$me error collecting from new customer: $bill_error" - # if $bill_error; + unless ( $packet->{payby} eq 'PREPAY' ) { + $bill_error = $cust_main->realtime_collect( + method => FS::payby->payby2bop( $packet->{payby} ), + depend_jobnum => $placeholder->jobnum, + selfservice => 1, + ); + #warn "$me error collecting from new customer: $bill_error" + # if $bill_error; + } if ($bill_error && ref($bill_error) eq 'HASH') { return { 'error' => '_collect', diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index a676e66c9..6a19ff475 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -3823,6 +3823,13 @@ and customer address. Include units.', 'type' => 'checkbox', }, + { + 'key' => 'fuzzy-fuzziness', + 'section' => 'UI', + 'description' => 'Set the "fuzziness" of fuzzy searching (see the String::Approx manpage for details). Defaults to 10%', + 'type' => 'text', + }, + { 'key' => 'pkg_referral', 'section' => '', 'description' => 'Enable package-specific advertising sources.', @@ -4944,7 +4951,7 @@ and customer address. Include units.', { 'key' => 'pkg-balances', 'section' => 'billing', - 'description' => 'Enable experimental package balances. Not recommended for general use.', + 'description' => 'Enable per-package balances.', 'type' => 'checkbox', }, @@ -5198,6 +5205,13 @@ and customer address. Include units.', }, { + 'key' => 'invoice_payment_details', + 'section' => 'invoicing', + 'description' => 'When displaying payments on an invoice, show the payment method used, including the check or credit card number. Credit card numbers will be masked.', + 'type' => 'checkbox', + }, + + { 'key' => 'cust_main-status_module', 'section' => 'UI', 'description' => 'Which module to use for customer status display. The "Classic" module (the default) considers accounts with cancelled recurring packages but un-cancelled one-time charges Inactive. The "Recurring" module considers those customers Cancelled. Similarly for customers with suspended recurring packages but one-time charges.', #other differences? diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ae75539ac..1553a42df 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -77,7 +77,7 @@ if ( -e $addl_handler_use_file ) { use HTML::TableExtract qw(tree); use HTML::FormatText; use HTML::Defang; - use JSON; + use JSON::XS; # use XMLRPC::Transport::HTTP; # use XMLRPC::Lite; # for XMLRPC::Serializer use MIME::Base64; @@ -160,6 +160,7 @@ if ( -e $addl_handler_use_file ) { use FS::cust_credit; use FS::cust_credit_bill; use FS::cust_main; + use FS::h_cust_main; use FS::cust_main::Search qw(smart_search); use FS::cust_main::Import; use FS::cust_main_county; @@ -337,6 +338,7 @@ if ( -e $addl_handler_use_file ) { use FS::part_pkg_usage_class; use FS::part_pkg_usage; use FS::cdr_cust_pkg_usage; + use FS::part_pkg_msgcat; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 42af68ca5..bdf3bcf3a 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -458,7 +458,13 @@ sub qsearch { # grep defined( $record->{$_} ) && $record->{$_} ne '', @fields # ) or croak "Error executing \"$statement\": ". $sth->errstr; - $sth->execute or croak "Error executing \"$statement\": ". $sth->errstr; + my $ok = $sth->execute; + if (!$ok) { + my $error = "Error executing \"$statement\""; + $error .= ' (' . join(', ', map {"'$_'"} @value) . ')' if @value; + $error .= ': '. $sth->errstr; + croak $error; + } my $table = $stable[0]; my $pkey = ''; @@ -1788,6 +1794,8 @@ sub batch_import { last unless scalar(@buffer); my $row = shift @buffer; + &{ $asn_format->{row_callback} }( $row, $asn_header_buffer ) + if $asn_format->{row_callback}; foreach my $key ( keys %{ $asn_format->{map} } ) { $hash{$key} = &{ $asn_format->{map}{$key} }( $row, $asn_header_buffer ); } diff --git a/FS/FS/Report/FCC_477.pm b/FS/FS/Report/FCC_477.pm index 49bb8a852..fd088148b 100644 --- a/FS/FS/Report/FCC_477.pm +++ b/FS/FS/Report/FCC_477.pm @@ -22,26 +22,26 @@ Documentation. =cut @upload = qw( - <200kpbs - 200-768kpbs + <200kbps + 200-768kbps 768kbps-1.5mbps 1.5-3mpbs 3-6mbps 6-10mbps 10-25mbps 25-100mbps - >100bmps + >100mbps ); @download = qw( - 200-768kpbs + 200-768kbps 768kbps-1.5mbps - 1.5-3mpbs + 1.5-3mbps 3-6mbps 6-10mbps 10-25mbps 25-100mbps - >100bmps + >100mbps ); @technology = ( diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 29f8ea4b8..eb73ccbc8 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1080,6 +1080,7 @@ sub tables_hashref { 'locale', 'varchar', 'NULL', 16, '', '', 'calling_list_exempt', 'char', 'NULL', 1, '', '', 'invoice_noemail', 'char', 'NULL', 1, '', '', + 'message_noemail', 'char', 'NULL', 1, '', '', 'bill_locationnum', 'int', 'NULL', '', '', '', 'ship_locationnum', 'int', 'NULL', '', '', '', ], @@ -1720,6 +1721,7 @@ sub tables_hashref { 'custnum', 'int', '', '', '', '', 'pkgpart', 'int', '', '', '', '', 'pkgbatch', 'varchar', 'NULL', $char_d, '', '', + 'contactnum', 'int', 'NULL', '', '', '', 'locationnum', 'int', 'NULL', '', '', '', 'otaker', 'varchar', 'NULL', 32, '', '', 'usernum', 'int', 'NULL', '', '', '', @@ -2010,6 +2012,19 @@ sub tables_hashref { ], }, + 'part_pkg_msgcat' => { + 'columns' => [ + 'pkgpartmsgnum', 'serial', '', '', '', '', + 'pkgpart', 'int', '', '', '', '', + 'locale', 'varchar', '', 16, '', '', + 'pkg', 'varchar', '', $char_d, '', '', #longer/no limit? + 'comment', 'varchar', 'NULL', 2*$char_d, '', '', #longer/no limit? + ], + 'primary_key' => 'pkgpartmsgnum', + 'unique' => [ [ 'pkgpart', 'locale' ] ], + 'index' => [], + }, + 'part_pkg_link' => { 'columns' => [ 'pkglinknum', 'serial', '', '', '', '', @@ -2714,9 +2729,10 @@ sub tables_hashref { 'columns' => [ 'exportnum', 'serial', '', '', '', '', 'exportname', 'varchar', 'NULL', $char_d, '', '', - 'machine', 'varchar', 'NULL', $char_d, '', '', + 'machine', 'varchar', 'NULL', $char_d, '', '', 'exporttype', 'varchar', '', $char_d, '', '', 'nodomain', 'char', 'NULL', 1, '', '', + 'default_machine','int', 'NULL', '', '', '', ], 'primary_key' => 'exportnum', 'unique' => [], @@ -2893,22 +2909,28 @@ sub tables_hashref { 'svc_broadband' => { 'columns' => [ - 'svcnum', 'int', '', '', '', '', - 'description', 'varchar', 'NULL', $char_d, '', '', - 'routernum', 'int', 'NULL', '', '', '', - 'blocknum', 'int', 'NULL', '', '', '', - 'sectornum', 'int', 'NULL', '', '', '', - 'speed_up', 'int', 'NULL', '', '', '', - 'speed_down', 'int', 'NULL', '', '', '', - 'ip_addr', 'varchar', 'NULL', 15, '', '', - 'mac_addr', 'varchar', 'NULL', 12, '', '', - 'authkey', 'varchar', 'NULL', 32, '', '', - 'latitude', 'decimal', 'NULL', '10,7', '', '', - 'longitude', 'decimal', 'NULL', '10,7', '', '', - 'altitude', 'decimal', 'NULL', '', '', '', - 'vlan_profile', 'varchar', 'NULL', $char_d, '', '', - 'performance_profile', 'varchar', 'NULL', $char_d, '', '', - 'plan_id', 'varchar', 'NULL', $char_d, '', '', + 'svcnum', 'int', '', '', '', '', + 'description', 'varchar', 'NULL', $char_d, '', '', + 'routernum', 'int', 'NULL', '', '', '', + 'blocknum', 'int', 'NULL', '', '', '', + 'sectornum', 'int', 'NULL', '', '', '', + 'speed_up', 'int', 'NULL', '', '', '', + 'speed_down', 'int', 'NULL', '', '', '', + 'ip_addr', 'varchar', 'NULL', 15, '', '', + 'mac_addr', 'varchar', 'NULL', 12, '', '', + 'authkey', 'varchar', 'NULL', 32, '', '', + 'latitude', 'decimal', 'NULL', '10,7', '', '', + 'longitude', 'decimal', 'NULL', '10,7', '', '', + 'altitude', 'decimal', 'NULL', '', '', '', + 'vlan_profile', 'varchar', 'NULL', $char_d, '', '', + 'performance_profile', 'varchar', 'NULL', $char_d, '', '', + 'plan_id', 'varchar', 'NULL', $char_d, '', '', + 'radio_serialnum', 'varchar', 'NULL', $char_d, '', '', + 'radio_location', 'varchar', 'NULL', 2*$char_d, '', '', + 'poe_location', 'varchar', 'NULL', 2*$char_d, '', '', + 'rssi', 'int', 'NULL', '', '', '', + 'suid', 'int', 'NULL', '', '', '', + 'shared_svcnum', 'int', 'NULL', '', '', '', ], 'primary_key' => 'svcnum', 'unique' => [ [ 'ip_addr' ], [ 'mac_addr' ] ], diff --git a/FS/FS/TemplateItem_Mixin.pm b/FS/FS/TemplateItem_Mixin.pm index 324f05248..8b0e16a2d 100644 --- a/FS/FS/TemplateItem_Mixin.pm +++ b/FS/FS/TemplateItem_Mixin.pm @@ -52,10 +52,10 @@ line item, and for generic taxes, simply returns "Tax". =cut sub desc { - my $self = shift; + my( $self, $locale ) = @_; if ( $self->pkgnum > 0 ) { - $self->itemdesc || $self->part_pkg->pkg; + $self->itemdesc || $self->part_pkg->pkg_locale($locale); } else { my $desc = $self->itemdesc || 'Tax'; $desc .= ' '. $self->itemcomment if $self->itemcomment =~ /\S/; diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm index e3958a436..2e78f12f4 100644 --- a/FS/FS/Template_Mixin.pm +++ b/FS/FS/Template_Mixin.pm @@ -2181,6 +2181,7 @@ sub _items_cust_bill_pkg { my $cust_main = $self->cust_main;#for per-agent cust_bill-line_item-ate_style # and location labels + my $locale = $cust_main->locale; my @b = (); my ($s, $r, $u) = ( undef, undef, undef ); @@ -2225,7 +2226,7 @@ sub _items_cust_bill_pkg { my $type = $display->type; - my $desc = $cust_bill_pkg->desc; + my $desc = $cust_bill_pkg->desc( $cust_main->locale ); $desc = substr($desc, 0, $maxlength). '...' if $format eq 'latex' && length($desc) > $maxlength; diff --git a/FS/FS/UI/Web.pm b/FS/FS/UI/Web.pm index 792680876..c8ad430b2 100644 --- a/FS/FS/UI/Web.pm +++ b/FS/FS/UI/Web.pm @@ -472,23 +472,26 @@ sub cust_fields_subs { my $unlinked_warn = 0; return map { my $f = $_; - if( $unlinked_warn++ ) { + if ( $unlinked_warn++ ) { + sub { my $record = shift; - if( $record->custnum ) { - $record->$f(@_); - } - else { + if ( $record->custnum ) { + encode_entities( $record->$f(@_) ); + } else { '(unlinked)' }; - } - } - else { + }; + + } else { + sub { my $record = shift; - $record->$f(@_) if $record->custnum; - } + $record->custnum ? encode_entities( $record->$f(@_) ) : ''; + }; + } + } @cust_fields; } @@ -578,7 +581,7 @@ use vars qw($DEBUG); use Carp; use Storable qw(nfreeze); use MIME::Base64; -use JSON; +use JSON::XS; use FS::UID qw(getotaker); use FS::Record qw(qsearchs); use FS::queue; @@ -723,10 +726,7 @@ sub job_status { @return = ( 'error', $job ? $job->statustext : $jobnum ); } - #to_json(\@return); #waiting on deb 5.0 for new JSON.pm? - #silence the warning though - my $to_json = JSON->can('to_json') || JSON->can('objToJson'); - &$to_json(\@return); + encode_json \@return; } diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm index fea53a235..cda3198eb 100644 --- a/FS/FS/Upgrade.pm +++ b/FS/FS/Upgrade.pm @@ -294,6 +294,9 @@ sub upgrade_data { #insert default tower_sector if not present 'tower' => [], + #repair improperly deleted services + 'cust_svc' => [], + #routernum/blocknum 'svc_broadband' => [], diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm index 0e8bf45a9..d370ba5d1 100644 --- a/FS/FS/access_right.pm +++ b/FS/FS/access_right.pm @@ -229,7 +229,9 @@ sub _upgrade_data { # class method 'Usage: Unrateable CDRs', ], 'Provision customer service' => [ 'Edit password' ], - + 'Financial reports' => [ 'Employees: Commission Report', + 'Employees: Audit Report', + ], ; foreach my $old_acl ( keys %onetime ) { diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 9a3114442..3ebe6c420 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -644,7 +644,34 @@ sub rate_prefix { ); } + if ( $part_pkg->option_cacheable('skip_same_customer') + and ! $self->is_tollfree ) { + my ($dst_countrycode, $dst_number) = $self->parse_number( + column => 'dst', + international_prefix => $part_pkg->option_cacheable('international_prefix'), + domestic_prefix => $part_pkg->option_cacheable('domestic_prefix'), + ); + my $dst_same_cust = FS::Record->scalar_sql( + 'SELECT COUNT(svc_phone.svcnum) AS count '. + 'FROM cust_pkg ' . + 'JOIN cust_svc USING (pkgnum) ' . + 'JOIN svc_phone USING (svcnum) ' . + 'WHERE svc_phone.countrycode = ' . dbh->quote($dst_countrycode) . + ' AND svc_phone.phonenum = ' . dbh->quote($dst_number) . + ' AND cust_pkg.custnum = ' . $cust_pkg->custnum, + ); + if ( $dst_same_cust > 0 ) { + warn "not charging for CDR (same source and destination customer)\n" if $DEBUG; + return $self->set_status_and_rated_price( 'skipped', + 0, + $opt{'svcnum'}, + ); + } + } + + + ### # look up rate details based on called station id # (or calling station id for toll free calls) diff --git a/FS/FS/cdr/gsm_tap3_12.pm b/FS/FS/cdr/gsm_tap3_12.pm index b1496ac92..275e7b35c 100644 --- a/FS/FS/cdr/gsm_tap3_12.pm +++ b/FS/FS/cdr/gsm_tap3_12.pm @@ -6,6 +6,7 @@ use vars qw( %info %TZ ); use Time::Local; #use Data::Dumper; +#false laziness w/huawei_softx3000.pm %TZ = ( '+0000' => 'XXX-0', '+0100' => 'XXX-1', diff --git a/FS/FS/cdr/huawei_softx3000.pm b/FS/FS/cdr/huawei_softx3000.pm new file mode 100644 index 000000000..e66af43a9 --- /dev/null +++ b/FS/FS/cdr/huawei_softx3000.pm @@ -0,0 +1,2689 @@ +package FS::cdr::huawei_softx3000; +use base qw( FS::cdr ); + +use strict; +use vars qw( %info %TZ ); +use subs qw( ts24008_number TimeStamp ); +use Time::Local; +use FS::Record qw( qsearch ); +use FS::cdr_calltype; + +#false laziness w/gsm_tap3_12.pm +%TZ = ( + '+0000' => 'XXX-0', + '+0100' => 'XXX-1', + '+0200' => 'XXX-2', + '+0300' => 'XXX-3', + '+0400' => 'XXX-4', + '+0500' => 'XXX-5', + '+0600' => 'XXX-6', + '+0700' => 'XXX-7', + '+0800' => 'XXX-8', + '+0900' => 'XXX-9', + '+1000' => 'XXX-10', + '+1100' => 'XXX-11', + '+1200' => 'XXX-12', + '-0000' => 'XXX+0', + '-0100' => 'XXX+1', + '-0200' => 'XXX+2', + '-0300' => 'XXX+3', + '-0400' => 'XXX+4', + '-0500' => 'XXX+5', + '-0600' => 'XXX+6', + '-0700' => 'XXX+7', + '-0800' => 'XXX+8', + '-0900' => 'XXX+9', + '-1000' => 'XXX+10', + '-1100' => 'XXX+11', + '-1200' => 'XXX+12', +); + +%info = ( + 'name' => 'Huawei SoftX3000', #V100R006C05 ? + 'weight' => 160, + 'type' => 'asn.1', + 'import_fields' => [], + 'asn_format' => { + 'spec' => _asn_spec(), + 'macro' => 'CallEventDataFile', + 'header_buffer' => sub { + #my $CallEventDataFile = shift; + + my %cdr_calltype = ( map { $_->calltypename => $_->calltypenum } + qsearch('cdr_calltype', {}) + ); + + { cdr_calltype => \%cdr_calltype, + }; + + }, + 'arrayref' => sub { shift->{'callEventRecords'} }, + 'row_callback' => sub { + my( $row, $buffer ) = @_; + my @keys = keys %$row; + $buffer->{'key'} = $keys[0]; + }, + 'map' => { + 'src' => huawei_field('callingNumber', ts24008_number, ), + + 'dst' => huawei_field('calledNumber', ts24008_number, ), + + 'startdate' => huawei_field(['answerTime','deliveryTime'], TimeStamp), + 'answerdate' => huawei_field(['answerTime','deliveryTime'], TimeStamp), + 'enddate' => huawei_field('releaseTime', TimeStamp), + 'duration' => huawei_field('callDuration'), + 'billsec' => huawei_field('callDuration'), + #'disposition' => #diagnostics? + #'accountcode' + #'charged_party' => # 0 or 1, do something with this? + 'calltypenum' => sub { + my($rec, $buf) = @_; + my $key = $buf->{key}; + $buf->{'cdr_calltype'}{ $key }; + }, + #'carrierid' => + }, + + }, +); + +sub huawei_field { + my $field = shift; + my $decode = $_[0] ? shift : ''; + return sub { + my($rec, $buf) = @_; + + my $key = $buf->{key}; + + $field = ref($field) ? $field : [ $field ]; + my $value = ''; + foreach my $f (@$field) { + $value = $rec->{$key}{$f} and last; + } + + $decode + ? &{ $decode }( $value ) + : $value; + + }; +} + +sub ts24008_number { + # This type contains the binary coded decimal representation of + # a directory number e.g. calling/called/connected/translated number. + # The encoding of the octet string is in accordance with the + # the elements "Calling party BCD number", "Called party BCD number" + # and "Connected number" defined in TS 24.008. + # This encoding includes type of number and number plan information + # together with a BCD encoded digit string. + # It may also contain both a presentation and screening indicator + # (octet 3a). + # For the avoidance of doubt, this field does not include + # octets 1 and 2, the element name and length, as this would be + # redundant. + # + #type id (per TS 24.008 page 490): + # low nybble: "numbering plan identification" + # high nybble: "type of number" + # 0 unknown + # 1 international + # 2 national + # 3 network specific + # 4 dedicated access, short code + # 5 reserved + # 6 reserved + # 7 reserved for extension + # (bit 8 "extension") + return sub { + my( $type_id, $value ) = unpack 'Ch*', shift; + $value =~ s/f$//; # If the called party BCD number contains an odd number + # of digits, bits 5 to 8 of the last octet shall be + # filled with an end mark coded as "1111". + $value; + }; +} + +sub TimeStamp { + # The contents of this field are a compact form of the UTCTime format + # containing local time plus an offset to universal time. Binary coded + # decimal encoding is employed for the digits to reduce the storage and + # transmission overhead + # e.g. YYMMDDhhmmssShhmm + # where + # YY = Year 00 to 99 BCD encoded + # MM = Month 01 to 12 BCD encoded + # DD = Day 01 to 31 BCD encoded + # hh = hour 00 to 23 BCD encoded + # mm = minute 00 to 59 BCD encoded + # ss = second 00 to 59 BCD encoded + # S = Sign 0 = "+", "-" ASCII encoded + # hh = hour 00 to 23 BCD encoded + # mm = minute 00 to 59 BCD encoded + return sub { + my($year, $mon, $day, $hour, $min, $sec, $tz_sign, $tz_hour, $tz_min, $dst)= + unpack 'H2H2H2H2H2H2AH2H2C', shift; + #warn "$year/$mon/$day $hour:$min:$sec $tz_sign$tz_hour$tz_min $dst\n"; + return 0 unless $year; #y2100 bug + local($ENV{TZ}) = $TZ{ "$tz_sign$tz_hour$tz_min" }; + timelocal($sec, $min, $hour, $day, $mon-1, $year); + }; +} + +sub _asn_spec { + <<'END'; + +--DEFINITIONS IMPLICIT TAGS ::= + +--BEGIN + +-------------------------------------------------------------------------------- +-- +-- CALL AND EVENT RECORDS +-- +------------------------------------------------------------------------------ +--Font: verdana 8 + +CallEventRecord ::= CHOICE +{ + moCallRecord [0] MOCallRecord, + mtCallRecord [1] MTCallRecord, + roamingRecord [2] RoamingRecord, + incGatewayRecord [3] IncGatewayRecord, + outGatewayRecord [4] OutGatewayRecord, + transitRecord [5] TransitCallRecord, + moSMSRecord [6] MOSMSRecord, + mtSMSRecord [7] MTSMSRecord, + ssActionRecord [10] SSActionRecord, + hlrIntRecord [11] HLRIntRecord, + commonEquipRecord [14] CommonEquipRecord, + recTypeExtensions [15] ManagementExtensions, + termCAMELRecord [16] TermCAMELRecord, + mtLCSRecord [17] MTLCSRecord, + moLCSRecord [18] MOLCSRecord, + niLCSRecord [19] NILCSRecord, + forwardCallRecord [100] MOCallRecord +} + +MOCallRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedIMEI [2] IMEI OPTIONAL, + servedMSISDN [3] MSISDN OPTIONAL, + callingNumber [4] CallingNumber OPTIONAL, + calledNumber [5] CalledNumber OPTIONAL, + translatedNumber [6] TranslatedNumber OPTIONAL, + connectedNumber [7] ConnectedNumber OPTIONAL, + roamingNumber [8] RoamingNumber OPTIONAL, + recordingEntity [9] RecordingEntity OPTIONAL, + mscIncomingROUTE [10] ROUTE OPTIONAL, + mscOutgoingROUTE [11] ROUTE OPTIONAL, + location [12] LocationAreaAndCell OPTIONAL, + changeOfLocation [13] SEQUENCE OF LocationChange OPTIONAL, + basicService [14] BasicServiceCode OPTIONAL, + transparencyIndicator [15] TransparencyInd OPTIONAL, + changeOfService [16] SEQUENCE OF ChangeOfService OPTIONAL, + supplServicesUsed [17] SEQUENCE OF SuppServiceUsed OPTIONAL, + aocParameters [18] AOCParameters OPTIONAL, + changeOfAOCParms [19] SEQUENCE OF AOCParmChange OPTIONAL, + msClassmark [20] Classmark OPTIONAL, + changeOfClassmark [21] ChangeOfClassmark OPTIONAL, + seizureTime [22] TimeStamp OPTIONAL, + answerTime [23] TimeStamp OPTIONAL, + releaseTime [24] TimeStamp OPTIONAL, + callDuration [25] CallDuration OPTIONAL, + radioChanRequested [27] RadioChanRequested OPTIONAL, + radioChanUsed [28] TrafficChannel OPTIONAL, + changeOfRadioChan [29] ChangeOfRadioChannel OPTIONAL, + causeForTerm [30] CauseForTerm OPTIONAL, + diagnostics [31] Diagnostics OPTIONAL, + callReference [32] CallReference OPTIONAL, + sequenceNumber [33] SequenceNumber OPTIONAL, + additionalChgInfo [34] AdditionalChgInfo OPTIONAL, + recordExtensions [35] ManagementExtensions OPTIONAL, + gsm-SCFAddress [36] Gsm-SCFAddress OPTIONAL, + serviceKey [37] ServiceKey OPTIONAL, + networkCallReference [38] NetworkCallReference OPTIONAL, + mSCAddress [39] MSCAddress OPTIONAL, + cAMELInitCFIndicator [40] CAMELInitCFIndicator OPTIONAL, + defaultCallHandling [41] DefaultCallHandling OPTIONAL, + fnur [45] Fnur OPTIONAL, + aiurRequested [46] AiurRequested OPTIONAL, + speechVersionSupported [49] SpeechVersionIdentifier OPTIONAL, + speechVersionUsed [50] SpeechVersionIdentifier OPTIONAL, + numberOfDPEncountered [51] INTEGER OPTIONAL, + levelOfCAMELService [52] LevelOfCAMELService OPTIONAL, + freeFormatData [53] FreeFormatData OPTIONAL, + cAMELCallLegInformation [54] SEQUENCE OF CAMELInformation OPTIONAL, + freeFormatDataAppend [55] BOOLEAN OPTIONAL, + defaultCallHandling-2 [56] DefaultCallHandling OPTIONAL, + gsm-SCFAddress-2 [57] Gsm-SCFAddress OPTIONAL, + serviceKey-2 [58] ServiceKey OPTIONAL, + freeFormatData-2 [59] FreeFormatData OPTIONAL, + freeFormatDataAppend-2 [60] BOOLEAN OPTIONAL, + systemType [61] SystemType OPTIONAL, + rateIndication [62] RateIndication OPTIONAL, + partialRecordType [69] PartialRecordType OPTIONAL, + guaranteedBitRate [70] GuaranteedBitRate OPTIONAL, + maximumBitRate [71] MaximumBitRate OPTIONAL, + modemType [139] ModemType OPTIONAL, + classmark3 [140] Classmark3 OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + callingChargeAreaCode [145] ChargeAreaCode OPTIONAL, + calledChargeAreaCode [146] ChargeAreaCode OPTIONAL, + mscOutgoingCircuit [166] MSCCIC OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + callEmlppPriority [170] EmlppPriority OPTIONAL, + callerDefaultEmlppPriority [171] EmlppPriority OPTIONAL, + eaSubscriberInfo [174] EASubscriberInfo OPTIONAL, + selectedCIC [175] SelectedCIC OPTIONAL, + optimalRoutingFlag [177] NULL OPTIONAL, + optimalRoutingLateForwardFlag [178] NULL OPTIONAL, + optimalRoutingEarlyForwardFlag [179] NULL OPTIONAL, + portedflag [180] PortedFlag OPTIONAL, + calledIMSI [181] IMSI OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + changeOfglobalAreaID [189] SEQUENCE OF ChangeOfglobalAreaID OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + intermediatemccmnc [193] MCCMNC OPTIONAL, + lastmccmnc [194] MCCMNC OPTIONAL, + cUGOutgoingAccessIndicator [195] CUGOutgoingAccessIndicator OPTIONAL, + cUGInterlockCode [196] CUGInterlockCode OPTIONAL, + cUGOutgoingAccessUsed [197] CUGOutgoingAccessUsed OPTIONAL, + cUGIndex [198] CUGIndex OPTIONAL, + interactionWithIP [199] InteractionWithIP OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + setupTime [201] TimeStamp OPTIONAL, + alertingTime [202] TimeStamp OPTIONAL, + voiceIndicator [203] VoiceIndicator OPTIONAL, + bCategory [204] BCategory OPTIONAL, + callType [205] CallType OPTIONAL +} + +--at moc callingNumber is the same as served msisdn except basic msisdn != calling number such as MSP service + +MTCallRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedIMEI [2] IMEI OPTIONAL, + servedMSISDN [3] CalledNumber OPTIONAL, + callingNumber [4] CallingNumber OPTIONAL, + connectedNumber [5] ConnectedNumber OPTIONAL, + recordingEntity [6] RecordingEntity OPTIONAL, + mscIncomingROUTE [7] ROUTE OPTIONAL, + mscOutgoingROUTE [8] ROUTE OPTIONAL, + location [9] LocationAreaAndCell OPTIONAL, + changeOfLocation [10] SEQUENCE OF LocationChange OPTIONAL, + basicService [11] BasicServiceCode OPTIONAL, + transparencyIndicator [12] TransparencyInd OPTIONAL, + changeOfService [13] SEQUENCE OF ChangeOfService OPTIONAL, + supplServicesUsed [14] SEQUENCE OF SuppServiceUsed OPTIONAL, + aocParameters [15] AOCParameters OPTIONAL, + changeOfAOCParms [16] SEQUENCE OF AOCParmChange OPTIONAL, + msClassmark [17] Classmark OPTIONAL, + changeOfClassmark [18] ChangeOfClassmark OPTIONAL, + seizureTime [19] TimeStamp OPTIONAL, + answerTime [20] TimeStamp OPTIONAL, + releaseTime [21] TimeStamp OPTIONAL, + callDuration [22] CallDuration OPTIONAL, + radioChanRequested [24] RadioChanRequested OPTIONAL, + radioChanUsed [25] TrafficChannel OPTIONAL, + changeOfRadioChan [26] ChangeOfRadioChannel OPTIONAL, + causeForTerm [27] CauseForTerm OPTIONAL, + diagnostics [28] Diagnostics OPTIONAL, + callReference [29] CallReference OPTIONAL, + sequenceNumber [30] SequenceNumber OPTIONAL, + additionalChgInfo [31] AdditionalChgInfo OPTIONAL, + recordExtensions [32] ManagementExtensions OPTIONAL, + networkCallReference [33] NetworkCallReference OPTIONAL, + mSCAddress [34] MSCAddress OPTIONAL, + fnur [38] Fnur OPTIONAL, + aiurRequested [39] AiurRequested OPTIONAL, + speechVersionSupported [42] SpeechVersionIdentifier OPTIONAL, + speechVersionUsed [43] SpeechVersionIdentifier OPTIONAL, + gsm-SCFAddress [44] Gsm-SCFAddress OPTIONAL, + serviceKey [45] ServiceKey OPTIONAL, + systemType [46] SystemType OPTIONAL, + rateIndication [47] RateIndication OPTIONAL, + partialRecordType [54] PartialRecordType OPTIONAL, + guaranteedBitRate [55] GuaranteedBitRate OPTIONAL, + maximumBitRate [56] MaximumBitRate OPTIONAL, + initialCallAttemptFlag [137] NULL OPTIONAL, + ussdCallBackFlag [138] NULL OPTIONAL, + modemType [139] ModemType OPTIONAL, + classmark3 [140] Classmark3 OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + callingChargeAreaCode [145]ChargeAreaCode OPTIONAL, + calledChargeAreaCode [146]ChargeAreaCode OPTIONAL, + defaultCallHandling [150] DefaultCallHandling OPTIONAL, + freeFormatData [151] FreeFormatData OPTIONAL, + freeFormatDataAppend [152] BOOLEAN OPTIONAL, + numberOfDPEncountered [153] INTEGER OPTIONAL, + levelOfCAMELService [154] LevelOfCAMELService OPTIONAL, + roamingNumber [160] RoamingNumber OPTIONAL, + mscIncomingCircuit [166] MSCCIC OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + callEmlppPriority [170] EmlppPriority OPTIONAL, + calledDefaultEmlppPriority [171] EmlppPriority OPTIONAL, + eaSubscriberInfo [174] EASubscriberInfo OPTIONAL, + selectedCIC [175] SelectedCIC OPTIONAL, + optimalRoutingFlag [177] NULL OPTIONAL, + portedflag [180] PortedFlag OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + changeOfglobalAreaID [189] SEQUENCE OF ChangeOfglobalAreaID OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + intermediatemccmnc [193] MCCMNC OPTIONAL, + lastmccmnc [194] MCCMNC OPTIONAL, + cUGOutgoingAccessIndicator [195] CUGOutgoingAccessIndicator OPTIONAL, + cUGInterlockCode [196] CUGInterlockCode OPTIONAL, + cUGIncomingAccessUsed [197] CUGIncomingAccessUsed OPTIONAL, + cUGIndex [198] CUGIndex OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + redirectingnumber [201] RedirectingNumber OPTIONAL, + redirectingcounter [202] RedirectingCounter OPTIONAL, + setupTime [203] TimeStamp OPTIONAL, + alertingTime [204] TimeStamp OPTIONAL, + calledNumber [205] CalledNumber OPTIONAL, + voiceIndicator [206] VoiceIndicator OPTIONAL, + bCategory [207] BCategory OPTIONAL, + callType [208] CallType OPTIONAL +} + +RoamingRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedMSISDN [2] MSISDN OPTIONAL, + callingNumber [3] CallingNumber OPTIONAL, + roamingNumber [4] RoamingNumber OPTIONAL, + recordingEntity [5] RecordingEntity OPTIONAL, + mscIncomingROUTE [6] ROUTE OPTIONAL, + mscOutgoingROUTE [7] ROUTE OPTIONAL, + basicService [8] BasicServiceCode OPTIONAL, + transparencyIndicator [9] TransparencyInd OPTIONAL, + changeOfService [10] SEQUENCE OF ChangeOfService OPTIONAL, + supplServicesUsed [11] SEQUENCE OF SuppServiceUsed OPTIONAL, + seizureTime [12] TimeStamp OPTIONAL, + answerTime [13] TimeStamp OPTIONAL, + releaseTime [14] TimeStamp OPTIONAL, + callDuration [15] CallDuration OPTIONAL, + causeForTerm [17] CauseForTerm OPTIONAL, + diagnostics [18] Diagnostics OPTIONAL, + callReference [19] CallReference OPTIONAL, + sequenceNumber [20] SequenceNumber OPTIONAL, + recordExtensions [21] ManagementExtensions OPTIONAL, + networkCallReference [22] NetworkCallReference OPTIONAL, + mSCAddress [23] MSCAddress OPTIONAL, + partialRecordType [30] PartialRecordType OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + callingChargeAreaCode [145] ChargeAreaCode OPTIONAL, + calledChargeAreaCode [146] ChargeAreaCode OPTIONAL, + mscOutgoingCircuit [166] MSCCIC OPTIONAL, + mscIncomingCircuit [167] MSCCIC OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + callEmlppPriority [170] EmlppPriority OPTIONAL, + eaSubscriberInfo [174] EASubscriberInfo OPTIONAL, + selectedCIC [175] SelectedCIC OPTIONAL, + optimalRoutingFlag [177] NULL OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + cUGOutgoingAccessIndicator [195] CUGOutgoingAccessIndicator OPTIONAL, + cUGInterlockCode [196] CUGInterlockCode OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL +} + +TermCAMELRecord ::= SET +{ + recordtype [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedMSISDN [2] MSISDN OPTIONAL, + recordingEntity [3] RecordingEntity OPTIONAL, + interrogationTime [4] TimeStamp OPTIONAL, + destinationRoutingAddress [5] DestinationRoutingAddress OPTIONAL, + gsm-SCFAddress [6] Gsm-SCFAddress OPTIONAL, + serviceKey [7] ServiceKey OPTIONAL, + networkCallReference [8] NetworkCallReference OPTIONAL, + mSCAddress [9] MSCAddress OPTIONAL, + defaultCallHandling [10] DefaultCallHandling OPTIONAL, + recordExtensions [11] ManagementExtensions OPTIONAL, + calledNumber [12] CalledNumber OPTIONAL, + callingNumber [13] CallingNumber OPTIONAL, + mscIncomingROUTE [14] ROUTE OPTIONAL, + mscOutgoingROUTE [15] ROUTE OPTIONAL, + seizureTime [16] TimeStamp OPTIONAL, + answerTime [17] TimeStamp OPTIONAL, + releaseTime [18] TimeStamp OPTIONAL, + callDuration [19] CallDuration OPTIONAL, + causeForTerm [21] CauseForTerm OPTIONAL, + diagnostics [22] Diagnostics OPTIONAL, + callReference [23] CallReference OPTIONAL, + sequenceNumber [24] SequenceNumber OPTIONAL, + numberOfDPEncountered [25] INTEGER OPTIONAL, + levelOfCAMELService [26] LevelOfCAMELService OPTIONAL, + freeFormatData [27] FreeFormatData OPTIONAL, + cAMELCallLegInformation [28] SEQUENCE OF CAMELInformation OPTIONAL, + freeFormatDataAppend [29] BOOLEAN OPTIONAL, + mscServerIndication [30] BOOLEAN OPTIONAL, + defaultCallHandling-2 [31] DefaultCallHandling OPTIONAL, + gsm-SCFAddress-2 [32] Gsm-SCFAddress OPTIONAL, + serviceKey-2 [33] ServiceKey OPTIONAL, + freeFormatData-2 [34] FreeFormatData OPTIONAL, + freeFormatDataAppend-2 [35] BOOLEAN OPTIONAL, + partialRecordType [42] PartialRecordType OPTIONAL, + basicService [130] BasicServiceCode OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL +} + +IncGatewayRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + callingNumber [1] CallingNumber OPTIONAL, + calledNumber [2] CalledNumber OPTIONAL, + recordingEntity [3] RecordingEntity OPTIONAL, + mscIncomingROUTE [4] ROUTE OPTIONAL, + mscOutgoingROUTE [5] ROUTE OPTIONAL, + seizureTime [6] TimeStamp OPTIONAL, + answerTime [7] TimeStamp OPTIONAL, + releaseTime [8] TimeStamp OPTIONAL, + callDuration [9] CallDuration OPTIONAL, + causeForTerm [11] CauseForTerm OPTIONAL, + diagnostics [12] Diagnostics OPTIONAL, + callReference [13] CallReference OPTIONAL, + sequenceNumber [14] SequenceNumber OPTIONAL, + recordExtensions [15] ManagementExtensions OPTIONAL, + partialRecordType [22] PartialRecordType OPTIONAL, + iSDN-BC [23] ISDN-BC OPTIONAL, + lLC [24] LLC OPTIONAL, + hLC [25] HLC OPTIONAL, + basicService [130] BasicServiceCode OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + rateIndication [159] RateIndication OPTIONAL, + roamingNumber [160] RoamingNumber OPTIONAL, + mscIncomingCircuit [167] MSCCIC OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + callEmlppPriority [170] EmlppPriority OPTIONAL, + eaSubscriberInfo [174] EASubscriberInfo OPTIONAL, + selectedCIC [175] SelectedCIC OPTIONAL, + cUGOutgoingAccessIndicator [195] CUGOutgoingAccessIndicator OPTIONAL, + cUGInterlockCode [196] CUGInterlockCode OPTIONAL, + cUGIncomingAccessUsed [197] CUGIncomingAccessUsed OPTIONAL, + mscIncomingRouteAttribute [198] RouteAttribute OPTIONAL, + mscOutgoingRouteAttribute [199] RouteAttribute OPTIONAL, + networkCallReference [200] NetworkCallReference OPTIONAL, + setupTime [201] TimeStamp OPTIONAL, + alertingTime [202] TimeStamp OPTIONAL, + voiceIndicator [203] VoiceIndicator OPTIONAL, + bCategory [204] BCategory OPTIONAL, + callType [205] CallType OPTIONAL +} + +OutGatewayRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + callingNumber [1] CallingNumber OPTIONAL, + calledNumber [2] CalledNumber OPTIONAL, + recordingEntity [3] RecordingEntity OPTIONAL, + mscIncomingROUTE [4] ROUTE OPTIONAL, + mscOutgoingROUTE [5] ROUTE OPTIONAL, + seizureTime [6] TimeStamp OPTIONAL, + answerTime [7] TimeStamp OPTIONAL, + releaseTime [8] TimeStamp OPTIONAL, + callDuration [9] CallDuration OPTIONAL, + causeForTerm [11] CauseForTerm OPTIONAL, + diagnostics [12] Diagnostics OPTIONAL, + callReference [13] CallReference OPTIONAL, + sequenceNumber [14] SequenceNumber OPTIONAL, + recordExtensions [15] ManagementExtensions OPTIONAL, + partialRecordType [22] PartialRecordType OPTIONAL, + basicService [130] BasicServiceCode OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + rateIndication [159] RateIndication OPTIONAL, + roamingNumber [160] RoamingNumber OPTIONAL, + mscOutgoingCircuit [166] MSCCIC OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + eaSubscriberInfo [174] EASubscriberInfo OPTIONAL, + selectedCIC [175] SelectedCIC OPTIONAL, + callEmlppPriority [170] EmlppPriority OPTIONAL, + cUGOutgoingAccessIndicator [195] CUGOutgoingAccessIndicator OPTIONAL, + cUGInterlockCode [196] CUGInterlockCode OPTIONAL, + cUGIncomingAccessUsed [197] CUGIncomingAccessUsed OPTIONAL, + mscIncomingRouteAttribute [198] RouteAttribute OPTIONAL, + mscOutgoingRouteAttribute [199] RouteAttribute OPTIONAL, + networkCallReference [200] NetworkCallReference OPTIONAL, + setupTime [201] TimeStamp OPTIONAL, + alertingTime [202] TimeStamp OPTIONAL, + voiceIndicator [203] VoiceIndicator OPTIONAL, + bCategory [204] BCategory OPTIONAL, + callType [205] CallType OPTIONAL +} + +TransitCallRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + recordingEntity [1] RecordingEntity OPTIONAL, + mscIncomingROUTE [2] ROUTE OPTIONAL, + mscOutgoingROUTE [3] ROUTE OPTIONAL, + callingNumber [4] CallingNumber OPTIONAL, + calledNumber [5] CalledNumber OPTIONAL, + isdnBasicService [6] BasicService OPTIONAL, + seizureTime [7] TimeStamp OPTIONAL, + answerTime [8] TimeStamp OPTIONAL, + releaseTime [9] TimeStamp OPTIONAL, + callDuration [10] CallDuration OPTIONAL, + causeForTerm [12] CauseForTerm OPTIONAL, + diagnostics [13] Diagnostics OPTIONAL, + callReference [14] CallReference OPTIONAL, + sequenceNumber [15] SequenceNumber OPTIONAL, + recordExtensions [16] ManagementExtensions OPTIONAL, + partialRecordType [23] PartialRecordType OPTIONAL, + basicService [130] BasicServiceCode OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + originalCalledNumber [142] OriginalCalledNumber OPTIONAL, + rateIndication [159] RateIndication OPTIONAL, + mscOutgoingCircuit [166] MSCCIC OPTIONAL, + mscIncomingCircuit [167] MSCCIC OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + callEmlppPriority [170] EmlppPriority OPTIONAL, + eaSubscriberInfo [174] EASubscriberInfo OPTIONAL, + selectedCIC [175] SelectedCIC OPTIONAL, + cUGOutgoingAccessIndicator [195] CUGOutgoingAccessIndicator OPTIONAL, + cUGInterlockCode [196] CUGInterlockCode OPTIONAL, + cUGIncomingAccessUsed [197] CUGIncomingAccessUsed OPTIONAL, + mscIncomingRouteAttribute [198] RouteAttribute OPTIONAL, + mscOutgoingRouteAttribute [199] RouteAttribute OPTIONAL, + networkCallReference [200] NetworkCallReference OPTIONAL, + setupTime [201] TimeStamp OPTIONAL, + alertingTime [202] TimeStamp OPTIONAL, + voiceIndicator [203] VoiceIndicator OPTIONAL, + bCategory [204] BCategory OPTIONAL, + callType [205] CallType OPTIONAL +} + +MOSMSRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedIMEI [2] IMEI OPTIONAL, + servedMSISDN [3] MSISDN OPTIONAL, + msClassmark [4] Classmark OPTIONAL, + serviceCentre [5] AddressString OPTIONAL, + recordingEntity [6] RecordingEntity OPTIONAL, + location [7] LocationAreaAndCell OPTIONAL, + messageReference [8] MessageReference OPTIONAL, + originationTime [9] TimeStamp OPTIONAL, + smsResult [10] SMSResult OPTIONAL, + recordExtensions [11] ManagementExtensions OPTIONAL, + destinationNumber [12] SmsTpDestinationNumber OPTIONAL, + cAMELSMSInformation [13] CAMELSMSInformation OPTIONAL, + systemType [14] SystemType OPTIONAL, + basicService [130] BasicServiceCode OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + classmark3 [140] Classmark3 OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + smsUserDataType [195] SmsUserDataType OPTIONAL, + smstext [196] SMSTEXT OPTIONAL, + maximumNumberOfSMSInTheConcatenatedSMS [197] MaximumNumberOfSMSInTheConcatenatedSMS OPTIONAL, + concatenatedSMSReferenceNumber [198] ConcatenatedSMSReferenceNumber OPTIONAL, + sequenceNumberOfTheCurrentSMS [199] SequenceNumberOfTheCurrentSMS OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + callReference [201] CallReference OPTIONAL +} + +MTSMSRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + serviceCentre [1] AddressString OPTIONAL, + servedIMSI [2] IMSI OPTIONAL, + servedIMEI [3] IMEI OPTIONAL, + servedMSISDN [4] MSISDN OPTIONAL, + msClassmark [5] Classmark OPTIONAL, + recordingEntity [6] RecordingEntity OPTIONAL, + location [7] LocationAreaAndCell OPTIONAL, + deliveryTime [8] TimeStamp OPTIONAL, + smsResult [9] SMSResult OPTIONAL, + recordExtensions [10] ManagementExtensions OPTIONAL, + systemType [11] SystemType OPTIONAL, + cAMELSMSInformation [12] CAMELSMSInformation OPTIONAL, + basicService [130] BasicServiceCode OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + classmark3 [140] Classmark3 OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + smsUserDataType [195] SmsUserDataType OPTIONAL, + smstext [196] SMSTEXT OPTIONAL, + maximumNumberOfSMSInTheConcatenatedSMS [197] MaximumNumberOfSMSInTheConcatenatedSMS OPTIONAL, + concatenatedSMSReferenceNumber [198] ConcatenatedSMSReferenceNumber OPTIONAL, + sequenceNumberOfTheCurrentSMS [199] SequenceNumberOfTheCurrentSMS OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + origination [201] CallingNumber OPTIONAL, + callReference [202] CallReference OPTIONAL +} + +HLRIntRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedMSISDN [2] MSISDN OPTIONAL, + recordingEntity [3] RecordingEntity OPTIONAL, + basicService [4] BasicServiceCode OPTIONAL, + routingNumber [5] RoutingNumber OPTIONAL, + interrogationTime [6] TimeStamp OPTIONAL, + numberOfForwarding [7] NumberOfForwarding OPTIONAL, + interrogationResult [8] HLRIntResult OPTIONAL, + recordExtensions [9] ManagementExtensions OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + callReference [169] CallReference OPTIONAL +} + +SSActionRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + servedIMSI [1] IMSI OPTIONAL, + servedIMEI [2] IMEI OPTIONAL, + servedMSISDN [3] MSISDN OPTIONAL, + msClassmark [4] Classmark OPTIONAL, + recordingEntity [5] RecordingEntity OPTIONAL, + location [6] LocationAreaAndCell OPTIONAL, + basicServices [7] BasicServices OPTIONAL, + supplService [8] SS-Code OPTIONAL, + ssAction [9] SSActionType OPTIONAL, + ssActionTime [10] TimeStamp OPTIONAL, + ssParameters [11] SSParameters OPTIONAL, + ssActionResult [12] SSActionResult OPTIONAL, + callReference [13] CallReference OPTIONAL, + recordExtensions [14] ManagementExtensions OPTIONAL, + systemType [15] SystemType OPTIONAL, + ussdCodingScheme [126] UssdCodingScheme OPTIONAL, + ussdString [127] SEQUENCE OF UssdString OPTIONAL, + ussdNotifyCounter [128] UssdNotifyCounter OPTIONAL, + ussdRequestCounter [129] UssdRequestCounter OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + classmark3 [140] Classmark3 OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL +} + +CommonEquipRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + equipmentType [1] EquipmentType OPTIONAL, + equipmentId [2] EquipmentId OPTIONAL, + servedIMSI [3] IMSI OPTIONAL, + servedMSISDN [4] MSISDN OPTIONAL, + recordingEntity [5] RecordingEntity OPTIONAL, + basicService [6] BasicServiceCode OPTIONAL, + changeOfService [7] SEQUENCE OF ChangeOfService OPTIONAL, + supplServicesUsed [8] SEQUENCE OF SuppServiceUsed OPTIONAL, + seizureTime [9] TimeStamp OPTIONAL, + releaseTime [10] TimeStamp OPTIONAL, + callDuration [11] CallDuration OPTIONAL, + callReference [12] CallReference OPTIONAL, + sequenceNumber [13] SequenceNumber OPTIONAL, + recordExtensions [14] ManagementExtensions OPTIONAL, + systemType [15] SystemType OPTIONAL, + rateIndication [16] RateIndication OPTIONAL, + fnur [17] Fnur OPTIONAL, + partialRecordType [18] PartialRecordType OPTIONAL, + causeForTerm [100] CauseForTerm OPTIONAL, + diagnostics [101] Diagnostics OPTIONAL, + servedIMEI [102] IMEI OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL +} + +------------------------------------------------------------------------------ +-- +-- OBSERVED IMEI TICKETS +-- +------------------------------------------------------------------------------ + +ObservedIMEITicket ::= SET +{ + servedIMEI [0] IMEI, + imeiStatus [1] IMEIStatus, + servedIMSI [2] IMSI, + servedMSISDN [3] MSISDN OPTIONAL, + recordingEntity [4] RecordingEntity, + eventTime [5] TimeStamp, + location [6] LocationAreaAndCell, + imeiCheckEvent [7] IMEICheckEvent OPTIONAL, + callReference [8] CallReference OPTIONAL, + recordExtensions [9] ManagementExtensions OPTIONAL, + orgMSCId [168] MSCId OPTIONAL +} + + + +------------------------------------------------------------------------------ +-- +-- LOCATION SERICE TICKETS +-- +------------------------------------------------------------------------------ + +MTLCSRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + recordingEntity [1] RecordingEntity OPTIONAL, + lcsClientType [2] LCSClientType OPTIONAL, + lcsClientIdentity [3] LCSClientIdentity OPTIONAL, + servedIMSI [4] IMSI OPTIONAL, + servedMSISDN [5] MSISDN OPTIONAL, + locationType [6] LocationType OPTIONAL, + lcsQos [7] LCSQoSInfo OPTIONAL, + lcsPriority [8] LCS-Priority OPTIONAL, + mlc-Number [9] ISDN-AddressString OPTIONAL, + eventTimeStamp [10] TimeStamp OPTIONAL, + measureDuration [11] CallDuration OPTIONAL, + notificationToMSUser [12] NotificationToMSUser OPTIONAL, + privacyOverride [13] NULL OPTIONAL, + location [14] LocationAreaAndCell OPTIONAL, + locationEstimate [15] Ext-GeographicalInformation OPTIONAL, + positioningData [16] PositioningData OPTIONAL, + lcsCause [17] LCSCause OPTIONAL, + diagnostics [18] Diagnostics OPTIONAL, + systemType [19] SystemType OPTIONAL, + recordExtensions [20] ManagementExtensions OPTIONAL, + causeForTerm [21] CauseForTerm OPTIONAL, + lcsReferenceNumber [101] CallReferenceNumber OPTIONAL, + servedIMEI [102] IMEI OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + callReference [201] CallReference OPTIONAL +} + +MOLCSRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + recordingEntity [1] RecordingEntity OPTIONAL, + lcsClientType [2] LCSClientType OPTIONAL, + lcsClientIdentity [3] LCSClientIdentity OPTIONAL, + servedIMSI [4] IMSI OPTIONAL, + servedMSISDN [5] MSISDN OPTIONAL, + molr-Type [6] MOLR-Type OPTIONAL, + lcsQos [7] LCSQoSInfo OPTIONAL, + lcsPriority [8] LCS-Priority OPTIONAL, + mlc-Number [9] ISDN-AddressString OPTIONAL, + eventTimeStamp [10] TimeStamp OPTIONAL, + measureDuration [11] CallDuration OPTIONAL, + location [12] LocationAreaAndCell OPTIONAL, + locationEstimate [13] Ext-GeographicalInformation OPTIONAL, + positioningData [14] PositioningData OPTIONAL, + lcsCause [15] LCSCause OPTIONAL, + diagnostics [16] Diagnostics OPTIONAL, + systemType [17] SystemType OPTIONAL, + recordExtensions [18] ManagementExtensions OPTIONAL, + causeForTerm [19] CauseForTerm OPTIONAL, + lcsReferenceNumber [101] CallReferenceNumber OPTIONAL, + servedIMEI [102] IMEI OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + callReference [201] CallReference OPTIONAL +} + +NILCSRecord ::= SET +{ + recordType [0] CallEventRecordType OPTIONAL, + recordingEntity [1] RecordingEntity OPTIONAL, + lcsClientType [2] LCSClientType OPTIONAL, + lcsClientIdentity [3] LCSClientIdentity OPTIONAL, + servedIMSI [4] IMSI OPTIONAL, + servedMSISDN [5] MSISDN OPTIONAL, + servedIMEI [6] IMEI OPTIONAL, + emsDigits [7] ISDN-AddressString OPTIONAL, + emsKey [8] ISDN-AddressString OPTIONAL, + lcsQos [9] LCSQoSInfo OPTIONAL, + lcsPriority [10] LCS-Priority OPTIONAL, + mlc-Number [11] ISDN-AddressString OPTIONAL, + eventTimeStamp [12] TimeStamp OPTIONAL, + measureDuration [13] CallDuration OPTIONAL, + location [14] LocationAreaAndCell OPTIONAL, + locationEstimate [15] Ext-GeographicalInformation OPTIONAL, + positioningData [16] PositioningData OPTIONAL, + lcsCause [17] LCSCause OPTIONAL, + diagnostics [18] Diagnostics OPTIONAL, + systemType [19] SystemType OPTIONAL, + recordExtensions [20] ManagementExtensions OPTIONAL, + causeForTerm [21] CauseForTerm OPTIONAL, + lcsReferenceNumber [101] CallReferenceNumber OPTIONAL, + additionalChgInfo [133] AdditionalChgInfo OPTIONAL, + chargedParty [141] ChargedParty OPTIONAL, + orgRNCorBSCId [167] RNCorBSCId OPTIONAL, + orgMSCId [168] MSCId OPTIONAL, + globalAreaID [188] GAI OPTIONAL, + subscriberCategory [190] SubscriberCategory OPTIONAL, + firstmccmnc [192] MCCMNC OPTIONAL, + hotBillingTag [200] HotBillingTag OPTIONAL, + callReference [201] CallReference OPTIONAL +} + + +------------------------------------------------------------------------------ +-- +-- FTAM / FTP / TFTP FILE CONTENTS +-- +------------------------------------------------------------------------------ + +CallEventDataFile ::= SEQUENCE +{ + headerRecord [0] HeaderRecord, + callEventRecords [1] SEQUENCE OF CallEventRecord, + trailerRecord [2] TrailerRecord, + extensions [3] ManagementExtensions +} + +ObservedIMEITicketFile ::= SEQUENCE +{ + productionDateTime [0] TimeStamp, + observedIMEITickets [1] SEQUENCE OF ObservedIMEITicket, + noOfRecords [2] INTEGER, + extensions [3] ManagementExtensions +} + +HeaderRecord ::= SEQUENCE +{ + productionDateTime [0] TimeStamp, + recordingEntity [1] RecordingEntity, + extensions [2] ManagementExtensions +} + +TrailerRecord ::= SEQUENCE +{ + productionDateTime [0] TimeStamp, + recordingEntity [1] RecordingEntity, + firstCallDateTime [2] TimeStamp, + lastCallDateTime [3] TimeStamp, + noOfRecords [4] INTEGER, + extensions [5] ManagementExtensions +} + + +------------------------------------------------------------------------------ +-- +-- COMMON DATA TYPES +-- +------------------------------------------------------------------------------ + +AdditionalChgInfo ::= SEQUENCE +{ + chargeIndicator [0] ChargeIndicator OPTIONAL, + chargeParameters [1] OCTET STRING OPTIONAL +} + +AddressString ::= OCTET STRING -- (SIZE (1..maxAddressLength)) + -- This type is used to represent a number for addressing + -- purposes. It is composed of + -- a) one octet for nature of address, and numbering plan + -- indicator. + -- b) digits of an address encoded as TBCD-String. + + -- a) The first octet includes a one bit extension indicator, a + -- 3 bits nature of address indicator and a 4 bits numbering + -- plan indicator, encoded as follows: + + -- bit 8: 1 (no extension) + + -- bits 765: nature of address indicator + -- 000 unknown + -- 001 international number + -- 010 national significant number + -- 011 network specific number + -- 100 subscriber number + -- 101 reserved + -- 110 abbreviated number + -- 111 reserved for extension + + -- bits 4321: numbering plan indicator + -- 0000 unknown + -- 0001 ISDN/Telephony Numbering Plan (Rec CCITT E.164) + -- 0010 spare + -- 0011 data numbering plan (CCITT Rec X.121) + -- 0100 telex numbering plan (CCITT Rec F.69) + -- 0101 spare + -- 0110 land mobile numbering plan (CCITT Rec E.212) + -- 0111 spare + -- 1000 national numbering plan + -- 1001 private numbering plan + -- 1111 reserved for extension + + -- all other values are reserved. + + -- b) The following octets representing digits of an address + -- encoded as a TBCD-STRING. + +-- maxAddressLength INTEGER ::= 20 + +AiurRequested ::= ENUMERATED +{ + -- + -- See Bearer Capability TS 24.008 + -- (note that value "4" is intentionally missing + -- because it is not used in TS 24.008) + -- + + aiur09600BitsPerSecond (1), + aiur14400BitsPerSecond (2), + aiur19200BitsPerSecond (3), + aiur28800BitsPerSecond (5), + aiur38400BitsPerSecond (6), + aiur43200BitsPerSecond (7), + aiur57600BitsPerSecond (8), + aiur38400BitsPerSecond1 (9), + aiur38400BitsPerSecond2 (10), + aiur38400BitsPerSecond3 (11), + aiur38400BitsPerSecond4 (12) +} + +AOCParameters ::= SEQUENCE +{ + -- + -- See TS 22.024. + -- + e1 [1] EParameter OPTIONAL, + e2 [2] EParameter OPTIONAL, + e3 [3] EParameter OPTIONAL, + e4 [4] EParameter OPTIONAL, + e5 [5] EParameter OPTIONAL, + e6 [6] EParameter OPTIONAL, + e7 [7] EParameter OPTIONAL +} + +AOCParmChange ::= SEQUENCE +{ + changeTime [0] TimeStamp, + newParameters [1] AOCParameters +} + +BasicService ::= OCTET STRING -- (SIZE(1)) + +--This parameter identifies the ISDN Basic service as defined in ETSI specification ETS 300 196. +-- allServices '00'h +-- speech '01'h +-- unrestricteDigtalInfo '02'h +-- audio3k1HZ '03'h +-- unrestricteDigtalInfowithtoneandannoucement '04'h +-- telephony3k1HZ '20'h +-- teletext '21'h +-- telefaxGroup4Class1 '22'h +-- videotextSyntaxBased '23'h +-- videotelephony '24'h +-- telefaxGroup2-3 '25'h +-- telephony7kHZ '26'h + + + +BasicServices ::= SET OF BasicServiceCode + +BasicServiceCode ::= CHOICE +{ + bearerService [2] BearerServiceCode, + teleservice [3] TeleserviceCode +} + + +TeleserviceCode ::= OCTET STRING -- (SIZE (1)) + -- This type is used to represent the code identifying a single + -- teleservice, a group of teleservices, or all teleservices. The + -- services are defined in TS GSM 02.03. + -- The internal structure is defined as follows: + + -- bits 87654321: group (bits 8765) and specific service + -- (bits 4321) + +-- allTeleservices (0x00), +-- allSpeechTransmissionServices (0x10), +-- telephony (0x11), +-- emergencyCalls (0x12), +-- +-- allShortMessageServices (0x20), +-- shortMessageMT-PP (0x21), +-- shortMessageMO-PP (0x22), +-- +-- allFacsimileTransmissionServices (0x60), +-- facsimileGroup3AndAlterSpeech (0x61), +-- automaticFacsimileGroup3 (0x62), +-- facsimileGroup4 (0x63), +-- +-- The following non-hierarchical Compound Teleservice Groups +-- are defined in TS GSM 02.30: +-- allDataTeleservices (0x70), +-- covers Teleservice Groups 'allFacsimileTransmissionServices' +-- and 'allShortMessageServices' +-- allTeleservices-ExeptSMS (0x80), +-- covers Teleservice Groups 'allSpeechTransmissionServices' and +-- 'allFacsimileTransmissionServices' +-- +-- Compound Teleservice Group Codes are only used in call +-- independent supplementary service operations, i.e. they +-- are not used in InsertSubscriberData or in +-- DeleteSubscriberData messages. +-- +-- allVoiceGroupCallServices (0x90), +-- voiceGroupCall (0x91), +-- voiceBroadcastCall (0x92), +-- +-- allPLMN-specificTS (0xd0), +-- plmn-specificTS-1 (0xd1), +-- plmn-specificTS-2 (0xd2), +-- plmn-specificTS-3 (0xd3), +-- plmn-specificTS-4 (0xd4), +-- plmn-specificTS-5 (0xd5), +-- plmn-specificTS-6 (0xd6), +-- plmn-specificTS-7 (0xd7), +-- plmn-specificTS-8 (0xd8), +-- plmn-specificTS-9 (0xd9), +-- plmn-specificTS-A (0xda), +-- plmn-specificTS-B (0xdb), +-- plmn-specificTS-C (0xdc), +-- plmn-specificTS-D (0xdd), +-- plmn-specificTS-E (0xde), +-- plmn-specificTS-F (0xdf) + + +BearerServiceCode ::= OCTET STRING -- (SIZE (1)) + -- This type is used to represent the code identifying a single + -- bearer service, a group of bearer services, or all bearer + -- services. The services are defined in TS 3GPP TS 22.002 [3]. + -- The internal structure is defined as follows: + -- + -- plmn-specific bearer services: + -- bits 87654321: defined by the HPLMN operator + + -- rest of bearer services: + -- bit 8: 0 (unused) + -- bits 7654321: group (bits 7654), and rate, if applicable + -- (bits 321) + +-- allBearerServices (0x00), +-- allDataCDA-Services (0x10), +-- dataCDA-300bps (0x11), +-- dataCDA-1200bps (0x12), +-- dataCDA-1200-75bps (0x13), +-- dataCDA-2400bps (0x14), +-- dataCDA-4800bps (0x15), +-- dataCDA-9600bps (0x16), +-- general-dataCDA (0x17), +-- +-- allDataCDS-Services (0x18), +-- dataCDS-1200bps (0x1a), +-- dataCDS-2400bps (0x1c), +-- dataCDS-4800bps (0x1d), +-- dataCDS-9600bps (0x1e), +-- general-dataCDS (0x1f), +-- +-- allPadAccessCA-Services (0x20), +-- padAccessCA-300bps (0x21), +-- padAccessCA-1200bps (0x22), +-- padAccessCA-1200-75bps (0x23), +-- padAccessCA-2400bps (0x24), +-- padAccessCA-4800bps (0x25), +-- padAccessCA-9600bps (0x26), +-- general-padAccessCA (0x27), +-- +-- allDataPDS-Services (0x28), +-- dataPDS-2400bps (0x2c), +-- dataPDS-4800bps (0x2d), +-- dataPDS-9600bps (0x2e), +-- general-dataPDS (0x2f), +-- +-- allAlternateSpeech-DataCDA (0x30), +-- +-- allAlternateSpeech-DataCDS (0x38), +-- +-- allSpeechFollowedByDataCDA (0x40), +-- +-- allSpeechFollowedByDataCDS (0x48), +-- +-- The following non-hierarchical Compound Bearer Service +-- Groups are defined in TS GSM 02.30: +-- allDataCircuitAsynchronous (0x50), +-- covers "allDataCDA-Services", "allAlternateSpeech-DataCDA" and +-- "allSpeechFollowedByDataCDA" +-- allDataCircuitSynchronous (0x58), +-- covers "allDataCDS-Services", "allAlternateSpeech-DataCDS" and +-- "allSpeechFollowedByDataCDS" +-- allAsynchronousServices (0x60), +-- covers "allDataCDA-Services", "allAlternateSpeech-DataCDA", +-- "allSpeechFollowedByDataCDA" and "allPadAccessCDA-Services" +-- allSynchronousServices (0x68), +-- covers "allDataCDS-Services", "allAlternateSpeech-DataCDS", +-- "allSpeechFollowedByDataCDS" and "allDataPDS-Services" +-- +-- Compound Bearer Service Group Codes are only used in call +-- independent supplementary service operations, i.e. they +-- are not used in InsertSubscriberData or in +-- DeleteSubscriberData messages. +-- +-- allPLMN-specificBS (0xd0), +-- plmn-specificBS-1 (0xd1), +-- plmn-specificBS-2 (0xd2), +-- plmn-specificBS-3 (0xd3), +-- plmn-specificBS-4 (0xd4), +-- plmn-specificBS-5 (0xd5), +-- plmn-specificBS-6 (0xd6), +-- plmn-specificBS-7 (0xd7), +-- plmn-specificBS-8 (0xd8), +-- plmn-specificBS-9 (0xd9), +-- plmn-specificBS-A (0xda), +-- plmn-specificBS-B (0xdb), +-- plmn-specificBS-C (0xdc), +-- plmn-specificBS-D (0xdd), +-- plmn-specificBS-E (0xde), +-- plmn-specificBS-F (0xdf) + + +BCDDirectoryNumber ::= OCTET STRING + -- This type contains the binary coded decimal representation of + -- a directory number e.g. calling/called/connected/translated number. + -- The encoding of the octet string is in accordance with the + -- the elements "Calling party BCD number", "Called party BCD number" + -- and "Connected number" defined in TS 24.008. + -- This encoding includes type of number and number plan information + -- together with a BCD encoded digit string. + -- It may also contain both a presentation and screening indicator + -- (octet 3a). + -- For the avoidance of doubt, this field does not include + -- octets 1 and 2, the element name and length, as this would be + -- redundant. + +CallDuration ::= INTEGER + -- + -- The call duration in seconds. + -- For successful calls this is the chargeable duration. + -- For call attempts this is the call holding time. + -- + +CallEventRecordType ::= ENUMERATED -- INTEGER +{ + moCallRecord (0), + mtCallRecord (1), + roamingRecord (2), + incGatewayRecord (3), + outGatewayRecord (4), + transitCallRecord (5), + moSMSRecord (6), + mtSMSRecord (7), + ssActionRecord (10), + hlrIntRecord (11), + commonEquipRecord (14), + moTraceRecord (15), + mtTraceRecord (16), + termCAMELRecord (17), + mtLCSRecord (23), + moLCSRecord (24), + niLCSRecord (25), + forwardCallRecord (100) +} + +CalledNumber ::= BCDDirectoryNumber + +CallingNumber ::= BCDDirectoryNumber + +CallingPartyCategory ::= Category + +CallReference ::= OCTET STRING -- (SIZE (1..8)) + +CallReferenceNumber ::= OCTET STRING -- (SIZE (1..8)) + +CAMELDestinationNumber ::= DestinationRoutingAddress + +CAMELInformation ::= SET +{ + cAMELDestinationNumber [1] CAMELDestinationNumber OPTIONAL, + connectedNumber [2] ConnectedNumber OPTIONAL, + roamingNumber [3] RoamingNumber OPTIONAL, + mscOutgoingROUTE [4] ROUTE OPTIONAL, + seizureTime [5] TimeStamp OPTIONAL, + answerTime [6] TimeStamp OPTIONAL, + releaseTime [7] TimeStamp OPTIONAL, + callDuration [8] CallDuration OPTIONAL, + dataVolume [9] DataVolume OPTIONAL, + cAMELInitCFIndicator [10] CAMELInitCFIndicator OPTIONAL, + causeForTerm [11] CauseForTerm OPTIONAL, + cAMELModification [12] ChangedParameters OPTIONAL, + freeFormatData [13] FreeFormatData OPTIONAL, + diagnostics [14] Diagnostics OPTIONAL, + freeFormatDataAppend [15] BOOLEAN OPTIONAL, + freeFormatData-2 [16] FreeFormatData OPTIONAL, + freeFormatDataAppend-2 [17] BOOLEAN OPTIONAL +} + +CAMELSMSInformation ::= SET +{ + gsm-SCFAddress [1] Gsm-SCFAddress OPTIONAL, + serviceKey [2] ServiceKey OPTIONAL, + defaultSMSHandling [3] DefaultSMS-Handling OPTIONAL, + freeFormatData [4] FreeFormatData OPTIONAL, + callingPartyNumber [5] CallingNumber OPTIONAL, + destinationSubscriberNumber [6] CalledNumber OPTIONAL, + cAMELSMSCAddress [7] AddressString OPTIONAL, + smsReferenceNumber [8] CallReferenceNumber OPTIONAL +} + +CAMELInitCFIndicator ::= ENUMERATED +{ + noCAMELCallForwarding (0), + cAMELCallForwarding (1) +} + +CAMELModificationParameters ::= SET + -- + -- The list contains only parameters changed due to CAMEL call + -- handling. + -- +{ + callingPartyNumber [0] CallingNumber OPTIONAL, + callingPartyCategory [1] CallingPartyCategory OPTIONAL, + originalCalledPartyNumber [2] OriginalCalledNumber OPTIONAL, + genericNumbers [3] GenericNumbers OPTIONAL, + redirectingPartyNumber [4] RedirectingNumber OPTIONAL, + redirectionCounter [5] NumberOfForwarding OPTIONAL +} + + +Category ::= OCTET STRING -- (SIZE(1)) + -- + -- The internal structure is defined in ITU-T Rec Q.763. + --see subscribe category + +CauseForTerm ::= ENUMERATED -- INTEGER + -- + -- Cause codes from 16 up to 31 are defined in TS 32.015 as 'CauseForRecClosing' + -- (cause for record closing). + -- There is no direct correlation between these two types. + -- LCS related causes belong to the MAP error causes acc. TS 29.002. + -- +{ + normalRelease (0), + partialRecord (1), + partialRecordCallReestablishment (2), + unsuccessfulCallAttempt (3), + stableCallAbnormalTermination (4), + cAMELInitCallRelease (5), + unauthorizedRequestingNetwork (52), + unauthorizedLCSClient (53), + positionMethodFailure (54), + unknownOrUnreachableLCSClient (58) +} + +CellId ::= OCTET STRING -- (SIZE(2)) + -- + -- Coded according to TS 24.008 + -- + +ChangedParameters ::= SET +{ + changeFlags [0] ChangeFlags, + changeList [1] CAMELModificationParameters OPTIONAL +} + +ChangeFlags ::= BIT STRING +-- { +-- callingPartyNumberModified (0), +-- callingPartyCategoryModified (1), +-- originalCalledPartyNumberModified (2), +-- genericNumbersModified (3), +-- redirectingPartyNumberModified (4), +-- redirectionCounterModified (5) +-- } + +ChangeOfClassmark ::= SEQUENCE +{ + classmark [0] Classmark, + changeTime [1] TimeStamp +} + +ChangeOfRadioChannel ::= SEQUENCE +{ + radioChannel [0] TrafficChannel, + changeTime [1] TimeStamp, + speechVersionUsed [2] SpeechVersionIdentifier OPTIONAL +} + +ChangeOfService ::= SEQUENCE +{ + basicService [0] BasicServiceCode, + transparencyInd [1] TransparencyInd OPTIONAL, + changeTime [2] TimeStamp, + rateIndication [3] RateIndication OPTIONAL, + fnur [4] Fnur OPTIONAL +} + +ChannelCoding ::= ENUMERATED +{ + tchF4800 (1), + tchF9600 (2), + tchF14400 (3) +} + +ChargeIndicator ::= ENUMERATED -- INTEGER +{ + noIndication (0), + noCharge (1), + charge (2) +} + +Classmark ::= OCTET STRING + -- + -- See Mobile station classmark 2 or 3 TS 24.008 + -- + +ConnectedNumber ::= BCDDirectoryNumber + +DataVolume ::= INTEGER + -- + -- The volume of data transferred in segments of 64 octets. + -- + +Day ::= INTEGER -- (1..31) + +--DayClass ::= ObjectInstance + +--DayClasses ::= SET OF DayClass + +--DayDefinition ::= SEQUENCE +--{ +-- day [0] DayOfTheWeek, +-- dayClass [1] ObjectInstance +--} + +--DayDefinitions ::= SET OF DayDefinition + +--DateDefinition ::= SEQUENCE +--{ +-- month [0] Month, +-- day [1] Day, +-- dayClass [2] ObjectInstance +--} + +--DateDefinitions ::= SET OF DateDefinition + +--DayOfTheWeek ::= ENUMERATED +--{ +-- allDays (0), +-- sunday (1), +-- monday (2), +-- tuesday (3), +-- wednesday (4), +-- thursday (5), +-- friday (6), +-- saturday (7) +--} + +DestinationRoutingAddress ::= BCDDirectoryNumber + +DefaultCallHandling ::= ENUMERATED +{ + continueCall (0), + releaseCall (1) +} + -- exception handling: + -- reception of values in range 2-31 shall be treated as "continueCall" + -- reception of values greater than 31 shall be treated as "releaseCall" + +DeferredLocationEventType ::= BIT STRING +-- { +-- msAvailable (0) +-- } (SIZE (1..16)) + + -- exception handling + -- a ProvideSubscriberLocation-Arg containing other values than listed above in + -- DeferredLocationEventType shall be rejected by the receiver with a return error cause of + -- unexpected data value. + +Diagnostics ::= CHOICE +{ + gsm0408Cause [0] INTEGER, + -- See TS 24.008 + gsm0902MapErrorValue [1] INTEGER, + -- Note: The value to be stored here corresponds to + -- the local values defined in the MAP-Errors and + -- MAP-DialogueInformation modules, for full details + -- see TS 29.002. + ccittQ767Cause [2] INTEGER, + -- See ITU-T Q.767 + networkSpecificCause [3] ManagementExtension, + -- To be defined by network operator + manufacturerSpecificCause [4] ManagementExtension + -- To be defined by manufacturer +} + +DefaultSMS-Handling ::= ENUMERATED +{ + continueTransaction (0) , + releaseTransaction (1) +} +-- exception handling: +-- reception of values in range 2-31 shall be treated as "continueTransaction" +-- reception of values greater than 31 shall be treated as "releaseTransaction" + +--Destinations ::= SET OF AE-title + +EmergencyCallIndEnable ::= BOOLEAN + +EmergencyCallIndication ::= SEQUENCE +{ + cellId [0] CellId, + callerId [1] IMSIorIMEI +} + +EParameter ::= INTEGER -- (0..1023) + -- + -- Coded according to TS 22.024 and TS 24.080 + -- + +EquipmentId ::= INTEGER + +Ext-GeographicalInformation ::= OCTET STRING -- (SIZE (1..maxExt-GeographicalInformation)) + -- Refers to geographical Information defined in 3G TS 23.032. + -- This is composed of 1 or more octets with an internal structure according to + -- 3G TS 23.032 + -- Octet 1: Type of shape, only the following shapes in 3G TS 23.032 are allowed: + -- (a) Ellipsoid point with uncertainty circle + -- (b) Ellipsoid point with uncertainty ellipse + -- (c) Ellipsoid point with altitude and uncertainty ellipsoid + -- (d) Ellipsoid Arc + -- (e) Ellipsoid Point + -- Any other value in octet 1 shall be treated as invalid + -- Octets 2 to 8 for case (a) - Ellipsoid point with uncertainty circle + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Uncertainty code 1 octet + -- Octets 2 to 11 for case (b) - Ellipsoid point with uncertainty ellipse: + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Uncertainty semi-major axis 1 octet + -- Uncertainty semi-minor axis 1 octet + -- Angle of major axis 1 octet + -- Confidence 1 octet + -- Octets 2 to 14 for case (c) - Ellipsoid point with altitude and uncertainty ellipsoid + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Altitude 2 octets + -- Uncertainty semi-major axis 1 octet + -- Uncertainty semi-minor axis 1 octet + -- Angle of major axis 1 octet + -- Uncertainty altitude 1 octet + -- Confidence 1 octet + -- Octets 2 to 13 for case (d) - Ellipsoid Arc + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- Inner radius 2 octets + -- Uncertainty radius 1 octet + -- Offset angle 1 octet + -- Included angle 1 octet + -- Confidence 1 octet + -- Octets 2 to 7 for case (e) - Ellipsoid Point + -- Degrees of Latitude 3 octets + -- Degrees of Longitude 3 octets + -- + -- An Ext-GeographicalInformation parameter comprising more than one octet and + -- containing any other shape or an incorrect number of octets or coding according + -- to 3G TS 23.032 shall be treated as invalid data by a receiver. + -- + -- An Ext-GeographicalInformation parameter comprising one octet shall be discarded + -- by the receiver if an Add-GeographicalInformation parameter is received + -- in the same message. + -- + -- An Ext-GeographicalInformation parameter comprising one octet shall be treated as + -- invalid data by the receiver if an Add-GeographicalInformation parameter is not + -- received in the same message. + +-- maxExt-GeographicalInformation INTEGER ::= 20 + -- the maximum length allows for further shapes in 3G TS 23.032 to be included in later + -- versions of 3G TS 29.002 + +EquipmentType ::= ENUMERATED -- INTEGER +{ + conferenceBridge (0) +} + +FileType ::= ENUMERATED -- INTEGER +{ + callRecords (1), + traceRecords (9), + observedIMEITicket (14) +} + +Fnur ::= ENUMERATED +{ + -- + -- See Bearer Capability TS 24.008 + -- + fnurNotApplicable (0), + fnur9600-BitsPerSecond (1), + fnur14400BitsPerSecond (2), + fnur19200BitsPerSecond (3), + fnur28800BitsPerSecond (4), + fnur38400BitsPerSecond (5), + fnur48000BitsPerSecond (6), + fnur56000BitsPerSecond (7), + fnur64000BitsPerSecond (8), + fnur33600BitsPerSecond (9), + fnur32000BitsPerSecond (10), + fnur31200BitsPerSecond (11) +} + +ForwardToNumber ::= AddressString + +FreeFormatData ::= OCTET STRING -- (SIZE(1..160)) + -- + -- Free formated data as sent in the FCI message + -- See TS 29.078 + -- + +GenericNumber ::= BCDDirectoryNumber + +GenericNumbers ::= SET OF GenericNumber + +Gsm-SCFAddress ::= ISDNAddressString + -- + -- See TS 29.002 + -- + +HLRIntResult ::= Diagnostics + +Horizontal-Accuracy ::= OCTET STRING -- (SIZE (1)) + -- bit 8 = 0 + -- bits 7-1 = 7 bit Uncertainty Code defined in 3G TS 23.032. The horizontal location + -- error should be less than the error indicated by the uncertainty code with 67% + -- confidence. + +HotBillingTag ::= ENUMERATED --INTEGER +{ + noHotBilling (0), + hotBilling (1) +} + +HSCSDParmsChange ::= SEQUENCE +{ + changeTime [0] TimeStamp, + hSCSDChanAllocated [1] NumOfHSCSDChanAllocated, + initiatingParty [2] InitiatingParty OPTIONAL, + aiurRequested [3] AiurRequested OPTIONAL, + chanCodingUsed [4] ChannelCoding, + hSCSDChanRequested [5] NumOfHSCSDChanRequested OPTIONAL +} + + +IMEI ::= TBCD-STRING -- (SIZE (8)) + -- Refers to International Mobile Station Equipment Identity + -- and Software Version Number (SVN) defined in TS GSM 03.03. + -- If the SVN is not present the last octet shall contain the + -- digit 0 and a filler. + -- If present the SVN shall be included in the last octet. + +IMSI ::= TBCD-STRING -- (SIZE (3..8)) + -- digits of MCC, MNC, MSIN are concatenated in this order. + +IMEICheckEvent ::= ENUMERATED -- INTEGER +{ + mobileOriginatedCall (0), + mobileTerminatedCall (1), + smsMobileOriginating (2), + smsMobileTerminating (3), + ssAction (4), + locationUpdate (5) +} + +IMEIStatus ::= ENUMERATED +{ + greyListedMobileEquipment (0), + blackListedMobileEquipment (1), + nonWhiteListedMobileEquipment (2) +} + +IMSIorIMEI ::= CHOICE +{ + imsi [0] IMSI, + imei [1] IMEI +} + +InitiatingParty ::= ENUMERATED +{ + network (0), + subscriber (1) +} + +ISDN-AddressString ::= AddressString -- (SIZE (1..maxISDN-AddressLength)) + -- This type is used to represent ISDN numbers. + +-- maxISDN-AddressLength INTEGER ::= 9 + +LCSCause ::= OCTET STRING -- (SIZE(1)) + -- + -- See LCS Cause Value, 3GPP TS 49.031 + -- + +LCS-Priority ::= OCTET STRING -- (SIZE (1)) + -- 0 = highest priority + -- 1 = normal priority + -- all other values treated as 1 + +LCSClientIdentity ::= SEQUENCE +{ + lcsClientExternalID [0] LCSClientExternalID OPTIONAL, + lcsClientDialedByMS [1] AddressString OPTIONAL, + lcsClientInternalID [2] LCSClientInternalID OPTIONAL +} + +LCSClientExternalID ::= SEQUENCE +{ + externalAddress [0] AddressString OPTIONAL +-- extensionContainer [1] ExtensionContainer OPTIONAL +} + +LCSClientInternalID ::= ENUMERATED +{ + broadcastService (0), + o-andM-HPLMN (1), + o-andM-VPLMN (2), + anonymousLocation (3), + targetMSsubscribedService (4) +} + -- for a CAMEL phase 3 PLMN operator client, the value targetMSsubscribedService shall be used + +LCSClientType ::= ENUMERATED +{ + emergencyServices (0), + valueAddedServices (1), + plmnOperatorServices (2), + lawfulInterceptServices (3) +} + -- exception handling: + -- unrecognized values may be ignored if the LCS client uses the privacy override + -- otherwise, an unrecognized value shall be treated as unexpected data by a receiver + -- a return error shall then be returned if received in a MAP invoke + +LCSQoSInfo ::= SEQUENCE +{ + horizontal-accuracy [0] Horizontal-Accuracy OPTIONAL, + verticalCoordinateRequest [1] NULL OPTIONAL, + vertical-accuracy [2] Vertical-Accuracy OPTIONAL, + responseTime [3] ResponseTime OPTIONAL +} + +LevelOfCAMELService ::= BIT STRING +-- { +-- basic (0), +-- callDurationSupervision (1), +-- onlineCharging (2) +-- } + +LocationAreaAndCell ::= SEQUENCE +{ + locationAreaCode [0] LocationAreaCode, + cellIdentifier [1] CellId +-- +-- For 2G the content of the Cell Identifier is defined by the Cell Id +-- refer TS 24.008 and for 3G by the Service Area Code refer TS 25.413. +-- + +} + +LocationAreaCode ::= OCTET STRING -- (SIZE(2)) + -- + -- See TS 24.008 + -- + +LocationChange ::= SEQUENCE +{ + location [0] LocationAreaAndCell, + changeTime [1] TimeStamp +} + +Location-info ::= SEQUENCE +{ + mscNumber [1] MscNo OPTIONAL, + location-area [2] LocationAreaCode, + cell-identification [3] CellId OPTIONAL +} + +LocationType ::= SEQUENCE +{ +locationEstimateType [0] LocationEstimateType, + deferredLocationEventType [1] DeferredLocationEventType OPTIONAL +} + +LocationEstimateType ::= ENUMERATED +{ + currentLocation (0), + currentOrLastKnownLocation (1), + initialLocation (2), + activateDeferredLocation (3), + cancelDeferredLocation (4) +} + -- exception handling: + -- a ProvideSubscriberLocation-Arg containing an unrecognized LocationEstimateType + -- shall be rejected by the receiver with a return error cause of unexpected data value + +LocUpdResult ::= Diagnostics + +ManagementExtensions ::= SET OF ManagementExtension + +ManagementExtension ::= SEQUENCE +{ + identifier OBJECT IDENTIFIER, + significance [1] BOOLEAN , -- DEFAULT FALSE, + information [2] OCTET STRING +} + + +MCCMNC ::= OCTET STRING -- (SIZE(3)) + -- + -- This type contains the mobile country code (MCC) and the mobile + -- network code (MNC) of a PLMN. + -- + +RateIndication ::= OCTET STRING -- (SIZE(1)) + +--0 no rate adaption +--1 V.110, I.460/X.30 +--2 ITU-T X.31 flag stuffing +--3 V.120 +--7 H.223 & H.245 +--11 PIAFS + + +MessageReference ::= OCTET STRING + +Month ::= INTEGER -- (1..12) + +MOLR-Type ::= INTEGER +--0 locationEstimate +--1 assistanceData +--2 deCipheringKeys + +MSCAddress ::= AddressString + +MscNo ::= ISDN-AddressString + -- + -- See TS 23.003 + -- + +MSISDN ::= ISDN-AddressString + -- + -- See TS 23.003 + -- + +MSPowerClasses ::= SET OF RFPowerCapability + +NetworkCallReference ::= CallReferenceNumber + -- See TS 29.002 + -- + +NetworkSpecificCode ::= INTEGER + -- + -- To be defined by network operator + -- + +NetworkSpecificServices ::= SET OF NetworkSpecificCode + +NotificationToMSUser ::= ENUMERATED +{ + notifyLocationAllowed (0), + notifyAndVerify-LocationAllowedIfNoResponse (1), + notifyAndVerify-LocationNotAllowedIfNoResponse (2), + locationNotAllowed (3) +} + -- exception handling: + -- At reception of any other value than the ones listed the receiver shall ignore + -- NotificationToMSUser. + +NumberOfForwarding ::= INTEGER -- (1..5) + +NumOfHSCSDChanRequested ::= INTEGER + +NumOfHSCSDChanAllocated ::= INTEGER + +ObservedIMEITicketEnable ::= BOOLEAN + +OriginalCalledNumber ::= BCDDirectoryNumber + +OriginDestCombinations ::= SET OF OriginDestCombination + +OriginDestCombination ::= SEQUENCE +{ + origin [0] INTEGER OPTIONAL, + destination [1] INTEGER OPTIONAL + -- + -- Note that these values correspond to the contents + -- of the attributes originId and destinationId + -- respectively. At least one of the two must be present. + -- +} + +PartialRecordTimer ::= INTEGER + +PartialRecordType ::= ENUMERATED +{ + timeLimit (0), + serviceChange (1), + locationChange (2), + classmarkChange (3), + aocParmChange (4), + radioChannelChange (5), + hSCSDParmChange (6), + changeOfCAMELDestination (7), + firstHotBill (20), + severalSSOperationBill (21) +} + +PartialRecordTypes ::= SET OF PartialRecordType + +PositioningData ::= OCTET STRING -- (SIZE(1..33)) + -- + -- See Positioning Data IE (octet 3..n), 3GPP TS 49.031 + -- + +RadioChannelsRequested ::= SET OF RadioChanRequested + +RadioChanRequested ::= ENUMERATED +{ + -- + -- See Bearer Capability TS 24.008 + -- + halfRateChannel (0), + fullRateChannel (1), + dualHalfRatePreferred (2), + dualFullRatePreferred (3) +} + +--RecordClassDestination ::= CHOICE +--{ +-- osApplication [0] AE-title, +-- fileType [1] FileType +--} + +--RecordClassDestinations ::= SET OF RecordClassDestination + +RecordingEntity ::= AddressString + +RecordingMethod ::= ENUMERATED +{ + inCallRecord (0), + inSSRecord (1) +} + +RedirectingNumber ::= BCDDirectoryNumber + +RedirectingCounter ::= INTEGER + +ResponseTime ::= SEQUENCE +{ + responseTimeCategory ResponseTimeCategory +} + -- note: an expandable SEQUENCE simplifies later addition of a numeric response time. + +ResponseTimeCategory ::= ENUMERATED +{ + lowdelay (0), + delaytolerant (1) +} + -- exception handling: + -- an unrecognized value shall be treated the same as value 1 (delaytolerant) + +RFPowerCapability ::= INTEGER + -- + -- This field contains the RF power capability of the Mobile station + -- classmark 1 and 2 of TS 24.008 expressed as an integer. + -- + +RoamingNumber ::= ISDN-AddressString + -- + -- See TS 23.003 + -- + +RoutingNumber ::= CHOICE +{ + roaming [1] RoamingNumber, + forwarded [2] ForwardToNumber +} + +Service ::= CHOICE +{ + teleservice [1] TeleserviceCode, + bearerService [2] BearerServiceCode, + supplementaryService [3] SS-Code, + networkSpecificService [4] NetworkSpecificCode +} + +ServiceDistanceDependencies ::= SET OF ServiceDistanceDependency + +ServiceDistanceDependency ::= SEQUENCE +{ + aocService [0] INTEGER, + chargingZone [1] INTEGER OPTIONAL + -- + -- Note that these values correspond to the contents + -- of the attributes aocServiceId and zoneId + -- respectively. + -- +} + +ServiceKey ::= INTEGER -- (0..2147483647) + +SimpleIntegerName ::= INTEGER + +SimpleStringName ::= GraphicString + +SMSResult ::= Diagnostics + +SmsTpDestinationNumber ::= OCTET STRING + -- + -- This type contains the binary coded decimal representation of + -- the SMS address field the encoding of the octet string is in + -- accordance with the definition of address fields in TS 23.040. + -- This encoding includes type of number and numbering plan indication + -- together with the address value range. + -- + +SpeechVersionIdentifier ::= OCTET STRING -- (SIZE(1)) +-- see GSM 08.08 + +-- 000 0001 GSM speech full rate version 1 +-- 001 0001 GSM speech full rate version 2 used for enhanced full rate +-- 010 0001 GSM speech full rate version 3 for future use +-- 000 0101 GSM speech half rate version 1 +-- 001 0101 GSM speech half rate version 2 for future use +-- 010 0101 GSM speech half rate version 3 for future use + +SSActionResult ::= Diagnostics + +SSActionType ::= ENUMERATED +{ + registration (0), + erasure (1), + activation (2), + deactivation (3), + interrogation (4), + invocation (5), + passwordRegistration (6), + ussdInvocation (7) +} + +-- ussdInvocation (7) include ussd phase 1,phase 2 + +--SS Request = SSActionType + +SS-Code ::= OCTET STRING -- (SIZE (1)) + -- This type is used to represent the code identifying a single + -- supplementary service, a group of supplementary services, or + -- all supplementary services. The services and abbreviations + -- used are defined in TS 3GPP TS 22.004 [5]. The internal structure is + -- defined as follows: + -- + -- bits 87654321: group (bits 8765), and specific service + -- (bits 4321) ussd = ff + +-- allSS (0x00), +-- reserved for possible future use +-- all SS +-- +-- allLineIdentificationSS (0x10), +-- reserved for possible future use +-- all line identification SS +-- +-- calling-line-identification-presentation (0x11), +-- calling line identification presentation +-- calling-line-identification-restriction (0x12), +-- calling line identification restriction +-- connected-line-identification-presentation (0x13), +-- connected line identification presentation +-- connected-line-identification-restriction (0x14), +-- connected line identification restriction +-- malicious-call-identification (0x15), +-- reserved for possible future use +-- malicious call identification +-- +-- allNameIdentificationSS (0x18), +-- all name identification SS +-- calling-name-presentation (0x19), +-- calling name presentation +-- +-- SS-Codes '00011010'B, to '00011111'B, are reserved for future +-- NameIdentification Supplementary Service use. +-- +-- allForwardingSS (0x20), +-- all forwarding SS +-- call-forwarding-unconditional (0x21), +-- call forwarding unconditional +-- call-deflection (0x24), +-- call deflection +-- allCondForwardingSS (0x28), +-- all conditional forwarding SS +-- call-forwarding-on-mobile-subscriber-busy (0x29), +-- call forwarding on mobile subscriber busy +-- call-forwarding-on-no-reply (0x2a), +-- call forwarding on no reply +-- call-forwarding-on-mobile-subscriber-not-reachable (0x2b), +-- call forwarding on mobile subscriber not reachable +-- +-- allCallOfferingSS (0x30), +-- reserved for possible future use +-- all call offering SS includes also all forwarding SS +-- +-- explicit-call-transfer (0x31), +-- explicit call transfer +-- mobile-access-hunting (0x32), +-- reserved for possible future use +-- mobile access hunting +-- +-- allCallCompletionSS (0x40), +-- reserved for possible future use +-- all Call completion SS +-- +-- call-waiting (0x41), +-- call waiting +-- call-hold (0x42), +-- call hold +-- completion-of-call-to-busy-subscribers-originating-side (0x43), +-- completion of call to busy subscribers, originating side +-- completion-of-call-to-busy-subscribers-destination-side (0x44), +-- completion of call to busy subscribers, destination side +-- this SS-Code is used only in InsertSubscriberData and DeleteSubscriberData +-- +-- multicall (0x45), +-- multicall +-- +-- allMultiPartySS (0x50), +-- reserved for possible future use +-- all multiparty SS +-- +-- multiPTY (0x51), +-- multiparty +-- +-- allCommunityOfInterest-SS (0x60), +-- reserved for possible future use +-- all community of interest SS +-- closed-user-group (0x61), +-- closed user group +-- +-- allChargingSS (0x70), +-- reserved for possible future use +-- all charging SS +-- advice-of-charge-information (0x71), +-- advice of charge information +-- advice-of-charge-charging (0x72), +-- advice of charge charging +-- +-- allAdditionalInfoTransferSS (0x80), +-- reserved for possible future use +-- all additional information transfer SS +-- uUS1-user-to-user-signalling (0x81), +-- UUS1 user-to-user signalling +-- uUS2-user-to-user-signalling (0x82), +-- UUS2 user-to-user signalling +-- uUS3-user-to-user-signalling (0x83), +-- UUS3 user-to-user signalling +-- +-- allBarringSS (0x90), +-- all barring SS +-- barringOfOutgoingCalls (0x91), +-- barring of outgoing calls +-- barring-of-all-outgoing-calls (0x92), +-- barring of all outgoing calls +-- barring-of-outgoing-international-calls (0x93), +-- barring of outgoing international calls +-- boicExHC (0x94), +-- barring of outgoing international calls except those directed +-- to the home PLMN +-- barringOfIncomingCalls (0x99), +-- barring of incoming calls +-- barring-of-all-incoming-calls (0x9a), +-- barring of all incoming calls +-- barring-of-incoming-calls-when-roaming-outside-home-PLMN-Country (0x9b), +-- barring of incoming calls when roaming outside home PLMN +-- Country +-- +-- allCallPrioritySS (0xa0), +-- reserved for possible future use +-- all call priority SS +-- enhanced-Multilevel-Precedence-Pre-emption-EMLPP-service (0xa1), +-- enhanced Multilevel Precedence Pre-emption 'EMLPP) service +-- +-- allLCSPrivacyException (0xb0), +-- all LCS Privacy Exception Classes +-- universal (0xb1), +-- allow location by any LCS client +-- callrelated (0xb2), +-- allow location by any value added LCS client to which a call +-- is established from the target MS +-- callunrelated (0xb3), +-- allow location by designated external value added LCS clients +-- plmnoperator (0xb4), +-- allow location by designated PLMN operator LCS clients +-- +-- allMOLR-SS (0xc0), +-- all Mobile Originating Location Request Classes +-- basicSelfLocation (0xc1), +-- allow an MS to request its own location +-- autonomousSelfLocation (0xc2), +-- allow an MS to perform self location without interaction +-- with the PLMN for a predetermined period of time +-- transferToThirdParty (0xc3), +-- allow an MS to request transfer of its location to another LCS client +-- +-- allPLMN-specificSS (0xf0), +-- plmn-specificSS-1 (0xf1), +-- plmn-specificSS-2 (0xf2), +-- plmn-specificSS-3 (0xf3), +-- plmn-specificSS-4 (0xf4), +-- plmn-specificSS-5 (0xf5), +-- plmn-specificSS-6 (0xf6), +-- plmn-specificSS-7 (0xf7), +-- plmn-specificSS-8 (0xf8), +-- plmn-specificSS-9 (0xf9), +-- plmn-specificSS-A (0xfa), +-- plmn-specificSS-B (0xfb), +-- plmn-specificSS-C (0xfc), +-- plmn-specificSS-D (0xfd), +-- plmn-specificSS-E (0xfe), +-- ussd (0xff) + + +SSParameters ::= CHOICE +{ + forwardedToNumber [0] ForwardToNumber, + unstructuredData [1] OCTET STRING +} + +SupplServices ::= SET OF SS-Code + +SuppServiceUsed ::= SEQUENCE +{ + ssCode [0] SS-Code OPTIONAL, + ssTime [1] TimeStamp OPTIONAL +} + +SwitchoverTime ::= SEQUENCE +{ + hour INTEGER , -- (0..23), + minute INTEGER , -- (0..59), + second INTEGER -- (0..59) +} + +SystemType ::= ENUMERATED + -- "unknown" is not to be used in PS domain. +{ + unknown (0), + iuUTRAN (1), + gERAN (2) +} + +TBCD-STRING ::= OCTET STRING + -- This type (Telephony Binary Coded Decimal String) is used to + -- represent several digits from 0 through 9, *, #, a, b, c, two + -- digits per octet, each digit encoded 0000 to 1001 (0 to 9), + -- 1010 (*), 1011 (#), 1100 (a), 1101 (b) or 1110 (c); 1111 used + -- as filler when there is an odd number of digits. + + -- bits 8765 of octet n encoding digit 2n + -- bits 4321 of octet n encoding digit 2(n-1) +1 + +TariffId ::= INTEGER + +TariffPeriod ::= SEQUENCE +{ + switchoverTime [0] SwitchoverTime, + tariffId [1] INTEGER + -- Note that the value of tariffId corresponds + -- to the attribute tariffId. +} + +TariffPeriods ::= SET OF TariffPeriod + +TariffSystemStatus ::= ENUMERATED +{ + available (0), -- available for modification + checked (1), -- "frozen" and checked + standby (2), -- "frozen" awaiting activation + active (3) -- "frozen" and active +} + + +TimeStamp ::= OCTET STRING -- (SIZE(9)) + -- + -- The contents of this field are a compact form of the UTCTime format + -- containing local time plus an offset to universal time. Binary coded + -- decimal encoding is employed for the digits to reduce the storage and + -- transmission overhead + -- e.g. YYMMDDhhmmssShhmm + -- where + -- YY = Year 00 to 99 BCD encoded + -- MM = Month 01 to 12 BCD encoded + -- DD = Day 01 to 31 BCD encoded + -- hh = hour 00 to 23 BCD encoded + -- mm = minute 00 to 59 BCD encoded + -- ss = second 00 to 59 BCD encoded + -- S = Sign 0 = "+", "-" ASCII encoded + -- hh = hour 00 to 23 BCD encoded + -- mm = minute 00 to 59 BCD encoded + -- + +TrafficChannel ::= ENUMERATED +{ + fullRate (0), + halfRate (1) +} + +TranslatedNumber ::= BCDDirectoryNumber + +TransparencyInd ::= ENUMERATED +{ + transparent (0), + nonTransparent (1) +} + +ROUTE ::= CHOICE +{ + rOUTENumber [0] INTEGER, + rOUTEName [1] GraphicString +} + +--rOUTEName 1 10 octet + +TSChangeover ::= SEQUENCE +{ + newActiveTS [0] INTEGER, + newStandbyTS [1] INTEGER, +-- changeoverTime [2] GeneralizedTime OPTIONAL, + authkey [3] OCTET STRING OPTIONAL, + checksum [4] OCTET STRING OPTIONAL, + versionNumber [5] OCTET STRING OPTIONAL + -- Note that if the changeover time is not + -- specified then the change is immediate. +} + +TSCheckError ::= SEQUENCE +{ + errorId [0] TSCheckErrorId + --fail [1] ANY DEFINED BY errorId OPTIONAL +} + +TSCheckErrorId ::= CHOICE +{ + globalForm [0] OBJECT IDENTIFIER, + localForm [1] INTEGER +} + +TSCheckResult ::= CHOICE +{ + success [0] NULL, + fail [1] SET OF TSCheckError +} + +TSCopyTariffSystem ::= SEQUENCE +{ + oldTS [0] INTEGER, + newTS [1] INTEGER +} + +TSNextChange ::= CHOICE +{ + noChangeover [0] NULL, + tsChangeover [1] TSChangeover +} + +TypeOfSubscribers ::= ENUMERATED +{ + home (0), -- HPLMN subscribers + visiting (1), -- roaming subscribers + all (2) +} + +TypeOfTransaction ::= ENUMERATED +{ + successful (0), + unsuccessful (1), + all (2) +} + +Vertical-Accuracy ::= OCTET STRING -- (SIZE (1)) + -- bit 8 = 0 + -- bits 7-1 = 7 bit Vertical Uncertainty Code defined in 3G TS 23.032. + -- The vertical location error should be less than the error indicated + -- by the uncertainty code with 67% confidence. + +ISDNAddressString ::= AddressString + +EmlppPriority ::= OCTET STRING -- (SIZE (1)) + +--priorityLevelA EMLPP-Priority ::= 6 +--priorityLevelB EMLPP-Priority ::= 5 +--priorityLevel0 EMLPP-Priority ::= 0 +--priorityLevel1 EMLPP-Priority ::= 1 +--priorityLevel2 EMLPP-Priority ::= 2 +--priorityLevel3 EMLPP-Priority ::= 3 +--priorityLevel4 EMLPP-Priority ::= 4 +--See 29.002 + + +EASubscriberInfo ::= OCTET STRING -- (SIZE (3)) + -- The internal structure is defined by the Carrier Identification + -- parameter in ANSI T1.113.3. Carrier codes between "000" and "999" may + -- be encoded as 3 digits using "000" to "999" or as 4 digits using + -- "0000" to "0999". Carrier codes between "1000" and "9999" are encoded + -- using 4 digits. + +SelectedCIC ::= OCTET STRING -- (SIZE (3)) + +PortedFlag ::= ENUMERATED +{ + numberNotPorted (0), + numberPorted (1) +} + +SubscriberCategory ::= OCTET STRING -- (SIZE (1)) +-- unknownuser = 0x00, +-- frenchuser = 0x01, +-- englishuser = 0x02, +-- germanuser = 0x03, +-- russianuser = 0x04, +-- spanishuser = 0x05, +-- specialuser = 0x06, +-- reserveuser = 0x09, +-- commonuser = 0x0a, +-- superioruser = 0x0b, +-- datacalluser = 0x0c, +-- testcalluser = 0x0d, +-- spareuser = 0x0e, +-- payphoneuser = 0x0f, +-- coinuser = 0x20, +-- isup224 = 0xe0 + + +CUGOutgoingAccessIndicator ::= ENUMERATED +{ + notCUGCall (0), + cUGCall (1) +} + +CUGInterlockCode ::= OCTET STRING -- (SIZE (4)) + +-- + +CUGOutgoingAccessUsed ::= ENUMERATED +{ + callInTheSameCUGGroup (0), + callNotInTheSameCUGGroup (1) +} + +SMSTEXT ::= OCTET STRING + +MSCCIC ::= INTEGER -- (0..65535) + +RNCorBSCId ::= OCTET STRING -- (SIZE (3)) +--octet order is the same as RANAP/BSSAP signaling +--if spc is coded as 14bit, then OCTET STRING1 will filled with 00 ,for example rnc id = 123 will be coded as 00 01 23 +--OCTET STRING1 +--OCTET STRING2 +--OCTET STRING3 + +MSCId ::= OCTET STRING -- (SIZE (3)) +--National network format , octet order is the same as ISUP signaling +--if spc is coded as 14bit, then OCTET STRING1 will filled with 00,,for example rnc id = 123 will be coded as 00 01 23 +--OCTET STRING1 +--OCTET STRING2 +--OCTET STRING3 + +EmergencyCallFlag ::= ENUMERATED +{ + notEmergencyCall (0), + emergencyCall (1) +} + +CUGIncomingAccessUsed ::= ENUMERATED +{ + callInTheSameCUGGroup (0), + callNotInTheSameCUGGroup (1) +} + +SmsUserDataType ::= OCTET STRING -- (SIZE (1)) +-- +--00 concatenated-short-messages-8-bit-reference-number +--01 special-sms-message-indication +--02 reserved +--03 Value not used to avoid misinterpretation as <LF> +--04 characterapplication-port-addressing-scheme-8-bit-address +--05 application-port-addressing-scheme-16-bit-address +--06 smsc-control-parameters +--07 udh-source-indicator +--08 concatenated-short-message-16-bit-reference-number +--09 wireless-control-message-protocol +--0A text-formatting +--0B predefined-sound +--0C user-defined-sound-imelody-max-128-bytes +--0D predefined-animation +--0E large-animation-16-16-times-4-32-4-128-bytes +--0F small-animation-8-8-times-4-8-4-32-bytes +--10 large-picture-32-32-128-bytes +--11 small-picture-16-16-32-bytes +--12 variable-picture +--13 User prompt indicator +--14 Extended Object +--15 Reused Extended Object +--16 Compression Control +--17 Object Distribution Indicator +--18 Standard WVG object +--19 Character Size WVG object +--1A Extended Object Data Request Command +--1B-1F Reserved for future EMS features (see subclause 3.10) +--20 RFC 822 E-Mail Header +--21 Hyperlink format element +--22 Reply Address Element +--23 - 6F Reserved for future use +--70 - 7F (U)SIM Toolkit Security Headers +--80 - 9F SME to SME specific use +--A0 - BF Reserved for future use +--C0 - DF SC specific use +--E0 - FE Reserved for future use +--FF normal SMS + +ConcatenatedSMSReferenceNumber ::= INTEGER -- (0..65535) + +MaximumNumberOfSMSInTheConcatenatedSMS ::= INTEGER -- (0..255) + +SequenceNumberOfTheCurrentSMS ::= INTEGER -- (0..255) + +SequenceNumber ::= INTEGER + +--(1... ) +-- + +DisconnectParty ::= ENUMERATED +{ + callingPartyRelease (0), + calledPartyRelease (1), + networkRelease (2) +} + +ChargedParty ::= ENUMERATED +{ + callingParty (0), + calledParty (1) +} + +ChargeAreaCode ::= OCTET STRING -- (SIZE (1..3)) + +CUGIndex ::= OCTET STRING -- (SIZE (2)) + +GuaranteedBitRate ::= ENUMERATED +{ + gBR14400BitsPerSecond (1), -- BS20 non-transparent + gBR28800BitsPerSecond (2), -- BS20 non-transparent and transparent, + -- BS30 transparent and multimedia + gBR32000BitsPerSecond (3), -- BS30 multimedia + gBR33600BitsPerSecond (4), -- BS30 multimedia + gBR56000BitsPerSecond (5), -- BS30 transparent and multimedia + gBR57600BitsPerSecond (6), -- BS20 non-transparent + gBR64000BitsPerSecond (7), -- BS30 transparent and multimedia + + gBR12200BitsPerSecond (106), -- AMR speech + gBR10200BitsPerSecond (107), -- AMR speech + gBR7950BitsPerSecond (108), -- AMR speech + gBR7400BitsPerSecond (109), -- AMR speech + gBR6700BitsPerSecond (110), -- AMR speech + gBR5900BitsPerSecond (111), -- AMR speech + gBR5150BitsPerSecond (112), -- AMR speech + gBR4750BitsPerSecond (113) -- AMR speech +} + +MaximumBitRate ::= ENUMERATED +{ + mBR14400BitsPerSecond (1), -- BS20 non-transparent + mBR28800BitsPerSecond (2), -- BS20 non-transparent and transparent, + -- BS30 transparent and multimedia + mBR32000BitsPerSecond (3), -- BS30 multimedia + mBR33600BitsPerSecond (4), -- BS30 multimedia + mBR56000BitsPerSecond (5), -- BS30 transparent and multimedia + mBR57600BitsPerSecond (6), -- BS20 non-transparent + mBR64000BitsPerSecond (7), -- BS30 transparent and multimedia + + mBR12200BitsPerSecond (106), -- AMR speech + mBR10200BitsPerSecond (107), -- AMR speech + mBR7950BitsPerSecond (108), -- AMR speech + mBR7400BitsPerSecond (109), -- AMR speech + mBR6700BitsPerSecond (110), -- AMR speech + mBR5900BitsPerSecond (111), -- AMR speech + mBR5150BitsPerSecond (112), -- AMR speech + mBR4750BitsPerSecond (113) -- AMR speech +} + + +HLC ::= OCTET STRING + +-- this parameter is a 1:1 copy of the contents (i.e. starting with octet 3) of the "high layer compatibility" parameter of ITU-T Q.931 [35]. + +LLC ::= OCTET STRING + +-- this parameter is a 1:1 copy of the contents (i.e. starting with octet 3) of the "low layer compatibility" parameter of ITU-T Q.931 [35]. + + +ISDN-BC ::= OCTET STRING + +-- this parameter is a 1:1 copy of the contents (i.e. starting with octet 3) of the "bearer capability" parameter of ITU-T Q.931 [35]. + +ModemType ::= ENUMERATED +{ + none-modem (0), + modem-v21 (1), + modem-v22 (2), + modem-v22-bis (3), + modem-v23 (4), + modem-v26-ter (5), + modem-v32 (6), + modem-undef-interface (7), + modem-autobauding1 (8), + no-other-modem-type (31), + modem-v34 (33) +} + +UssdCodingScheme ::= OCTET STRING + +UssdString ::= OCTET STRING + +UssdNotifyCounter ::= INTEGER -- (0..255) + +UssdRequestCounter ::= INTEGER -- (0..255) + +Classmark3 ::= OCTET STRING -- (SIZE(2)) + +OptimalRoutingDestAddress ::= BCDDirectoryNumber + +GAI ::= OCTET STRING -- (SIZE(7)) +--such as 64 F0 00 00 ABCD 1234 + +ChangeOfglobalAreaID ::= SEQUENCE +{ + location [0] GAI, + changeTime [1] TimeStamp +} + +InteractionWithIP ::= NULL + +RouteAttribute ::= ENUMERATED +{ + cas (0), + tup (1), + isup (2), + pra (3), + bicc (4), + sip (5), + others (255) +} + +VoiceIndicator ::= ENUMERATED +{ + sendToneByLocalMsc (0) , + sendToneByOtherMsc (1), + voiceNoIndication (3) +} + +BCategory ::= ENUMERATED +{ + subscriberFree (0), + subscriberBusy (1), + subscriberNoIndication (3) +} + +CallType ::= ENUMERATED +{ + unknown (0), + internal (1), + incoming (2), + outgoing (3), + tandem (4) +} + +-- END +END +} + +1; + diff --git a/FS/FS/contact_Mixin.pm b/FS/FS/contact_Mixin.pm new file mode 100644 index 000000000..6e8f315b9 --- /dev/null +++ b/FS/FS/contact_Mixin.pm @@ -0,0 +1,19 @@ +package FS::contact_Mixin; + +use strict; +use FS::Record qw( qsearchs ); +use FS::contact; + +=item contact_obj + +Returns the contact object, if any (see L<FS::contact>). + +=cut + +sub contact_obj { + my $self = shift; + return '' unless $self->contactnum; + qsearchs( 'contact', { 'contactnum' => $self->contactnum } ); +} + +1; diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 41124bc36..8b156c642 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -2130,10 +2130,13 @@ sub print_csv { $previous_balance = sprintf('%.2f', $previous_balance); my $totaldue = sprintf('%.2f', $self->owed + $previous_balance); my @items = map { - ($_->{pkgnum} || ''), - $_->{description}, - $_->{amount} - } $self->_items_pkg; + $_->{pkgnum}, + $_->{description}, + $_->{amount} + } + $self->_items_pkg, #_items_nontax? no sections or anything + # with this format + $self->_items_tax; $csv->combine( $cust_main->agentnum, @@ -3134,11 +3137,16 @@ sub _items_payments { #something more elaborate if $_->amount ne ->cust_pay->paid ? + my $desc = $self->mt('Payment received').' '. + time2str($date_format,$_->cust_pay->_date ); + $desc .= $self->mt(' via ' . $_->cust_pay->payby_payinfo_pretty) + if ( $self->conf->exists('invoice_payment_details') ); + push @b, { - 'description' => $self->mt('Payment received').' '. - time2str($date_format,$_->cust_pay->_date ), + 'description' => $desc, 'amount' => sprintf("%.2f", $_->amount ) }; + } @b; diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index 716c0983e..d8cbf5915 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -1104,8 +1104,7 @@ sub upgrade_tax_location { delete @hash{qw(censustract censusyear latitude longitude coord_auto)}; $hash{custnum} = $h_cust_main->custnum; - my $tax_loc = qsearchs('cust_location', \%hash) # unlikely - || FS::cust_location->new({ %hash }); + my $tax_loc = FS::cust_location->new_or_existing(\%hash); if ( !$tax_loc->locationnum ) { $tax_loc->disabled('Y'); my $error = $tax_loc->insert; diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm index b25163f36..b12a161db 100644 --- a/FS/FS/cust_location.pm +++ b/FS/FS/cust_location.pm @@ -5,7 +5,7 @@ use strict; use vars qw( $import ); use Locale::Country; use FS::UID qw( dbh driver_name ); -use FS::Record qw( qsearch ); #qsearchs ); +use FS::Record qw( qsearch qsearchs ); use FS::Conf; use FS::prospect_main; use FS::cust_main; @@ -104,6 +104,35 @@ points to. You can ask the object for a copy with the I<hash> method. sub table { 'cust_location'; } +=item new_or_existing HASHREF + +Returns an existing location matching the customer and address fields in +HASHREF, if one exists; otherwise returns a new location containing those +fields. The following fields must match: address1, address2, city, county, +state, zip, country, geocode, disabled. Other fields are only required +to match if they're specified in HASHREF. + +The new location will not be inserted; the calling code must call C<insert> +(or a method such as C<move_to>) to insert it, and check for errors at that +point. + +=cut + +sub new_or_existing { + my $class = shift; + my %hash = ref($_[0]) ? %{$_[0]} : @_; + # if coords are empty, then it doesn't matter if they're auto or not + if ( !$hash{'latitude'} and !$hash{'longitude'} ) { + delete $hash{'coord_auto'}; + } + foreach ( qw(address1 address2 city county state zip country geocode + disabled ) ) { + # empty fields match only empty fields + $hash{$_} = '' if !defined($hash{$_}); + } + return qsearchs('cust_location', \%hash) || $class->new(\%hash); +} + =item insert Adds this record to the database. If there is an error, returns the error, diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 3e5d4c137..2a4602e19 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1778,9 +1778,10 @@ sub check { || $self->ut_floatn('credit_limit') || $self->ut_numbern('billday') || $self->ut_numbern('prorate_day') - || $self->ut_enum('edit_subject', [ '', 'Y' ] ) - || $self->ut_enum('calling_list_exempt', [ '', 'Y' ] ) - || $self->ut_enum('invoice_noemail', [ '', 'Y' ] ) + || $self->ut_flag('edit_subject') + || $self->ut_flag('calling_list_exempt') + || $self->ut_flag('invoice_noemail') + || $self->ut_flag('message_noemail') || $self->ut_enum('locale', [ '', FS::Locales->locales ]) ; diff --git a/FS/FS/cust_main/Packages.pm b/FS/FS/cust_main/Packages.pm index 588f8a19f..f83bce915 100644 --- a/FS/FS/cust_main/Packages.pm +++ b/FS/FS/cust_main/Packages.pm @@ -87,7 +87,7 @@ sub order_pkg { if exists($opt->{'depend_jobnum'}) && $opt->{'depend_jobnum'}; my %insert_params = map { $opt->{$_} ? ( $_ => $opt->{$_} ) : () } - qw( ticket_subject ticket_queue ); + qw( ticket_subject ticket_queue allow_pkgpart ); local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -100,17 +100,48 @@ sub order_pkg { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - if ( $opt->{'cust_location'} && - ( ! $cust_pkg->locationnum || $cust_pkg->locationnum == -1 ) ) { - my $error = $opt->{'cust_location'}->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return "inserting cust_location (transaction rolled back): $error"; + if ( $opt->{'contactnum'} and $opt->{'contactnum'} != -1 ) { + + $cust_pkg->contactnum($opt->{'contactnum'}); + + } elsif ( $opt->{'contact'} ) { + + if ( ! $opt->{'contact'}->contactnum ) { + # not inserted yet + my $error = $opt->{'contact'}->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "inserting contact (transaction rolled back): $error"; + } } - $cust_pkg->locationnum($opt->{'cust_location'}->locationnum); + $cust_pkg->contactnum($opt->{'contact'}->contactnum); + + #} else { + # + # $cust_pkg->contactnum(); + } - else { + + if ( $opt->{'locationnum'} and $opt->{'locationnum'} != -1 ) { + + $cust_pkg->locationnum($opt->{'locationnum'}); + + } elsif ( $opt->{'cust_location'} ) { + + if ( ! $opt->{'cust_location'}->locationnum ) { + # not inserted yet + my $error = $opt->{'cust_location'}->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "inserting cust_location (transaction rolled back): $error"; + } + } + $cust_pkg->locationnum($opt->{'cust_location'}->locationnum); + + } else { + $cust_pkg->locationnum($self->ship_locationnum); + } $cust_pkg->custnum( $self->custnum ); @@ -164,6 +195,7 @@ sub order_pkg { 'refnum' => $cust_pkg->refnum, 'discountnum' => $cust_pkg->discountnum, 'waive_setup' => $cust_pkg->waive_setup, + 'allow_pkgpart' => $opt->{'allow_pkgpart'}, }); $error = $self->order_pkg('cust_pkg' => $pkg); if ( $error ) { diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index 2c7c04669..7dbb7a859 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -646,6 +646,16 @@ sub search { if $params->{'with_email'}; ## + # "with postal mail invoices" checkbox + ## + + push @where, + "EXISTS ( SELECT 1 FROM cust_main_invoice + WHERE cust_main_invoice.custnum = cust_main.custnum + AND dest = 'POST' )" + if $params->{'POST'}; + + ## # "without postal mail invoices" checkbox ## @@ -794,11 +804,19 @@ sub search { @tagnums = grep /^(\d+)$/, @tagnums; if ( @tagnums ) { + if ( $params->{'all_tags'} ) { + foreach ( @tagnums ) { + push @where, 'exists(select 1 from cust_tag where '. + 'cust_tag.custnum = cust_main.custnum and tagnum = '. + $_ . ')'; + } + } else { # matching any tag, not all my $tags_where = "0 < (select count(1) from cust_tag where " . " cust_tag.custnum = cust_main.custnum and tagnum in (" . join(',', @tagnums) . "))"; push @where, $tags_where; + } } } @@ -839,7 +857,8 @@ sub search { if ($params->{'flattened_pkgs'}) { #my $pkg_join = ''; - $addl_from .= ' LEFT JOIN cust_pkg USING ( custnum ) '; + $addl_from .= + ' LEFT JOIN cust_pkg ON ( cust_main.custnum = cust_pkg.custnum ) '; if ($dbh->{Driver}->{Name} eq 'Pg') { @@ -935,6 +954,11 @@ sub fuzzy_search { my @cust_main = (); + my @fuzzy_mod = 'i'; + my $conf = new FS::Conf; + my $fuzziness = $conf->config('fuzzy-fuzziness'); + push @fuzzy_mod, $fuzziness if $fuzziness; + check_and_rebuild_fuzzyfiles(); foreach my $field ( keys %$fuzzy ) { @@ -942,7 +966,7 @@ sub fuzzy_search { next unless scalar(@$all); my %match = (); - $match{$_}=1 foreach ( amatch( $fuzzy->{$field}, ['i'], @$all ) ); + $match{$_}=1 foreach ( amatch( $fuzzy->{$field}, \@fuzzy_mod, @$all ) ); next if !keys(%match); my $in_matches = 'IN (' . diff --git a/FS/FS/cust_main_county.pm b/FS/FS/cust_main_county.pm index 9a4990a9d..a61d67e11 100644 --- a/FS/FS/cust_main_county.pm +++ b/FS/FS/cust_main_county.pm @@ -147,13 +147,10 @@ If the taxname field is set, it will look like If the taxclass is set, then it will be "Anytown, Alameda County, CA, US (International)". -Currently it will not contain the district, even if the city+county+state -is not unique. - -OPTIONS may contain "no_taxclass" (hides taxclass) and/or "no_city" -(hides city). It may also contain "out", in which case, if this -region (district+city+county+state+country) contains no non-zero -taxes, the label will read "Out of taxable region(s)". +OPTIONS may contain "with_taxclass", "with_city", and "with_district" to show +those fields. It may also contain "out", in which case, if this region +(district+city+county+state+country) contains no non-zero taxes, the label +will read "Out of taxable region(s)". =cut @@ -175,12 +172,15 @@ sub label { my $label = $self->country; $label = $self->state.", $label" if $self->state; $label = $self->county." County, $label" if $self->county; - if (!$opt{no_city}) { + if ($opt{with_city}) { $label = $self->city.", $label" if $self->city; + if ($opt{with_district} and $self->district) { + $label = $self->district . ", $label"; + } } # ugly labels when taxclass and taxname are both non-null... # but this is how the tax report does it - if (!$opt{no_taxclass}) { + if ($opt{with_taxclass}) { $label = "$label (".$self->taxclass.')' if $self->taxclass; } $label = $self->taxname." ($label)" if $self->taxname; diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index fa5672cdd..0e9e8a716 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -1033,13 +1033,17 @@ sub _upgrade_data { #class method # not only cust_pay, but also voided and refunded payments if (!FS::upgrade_journal->is_done('cust_pay__parse_paybatch_1')) { + local $FS::Record::nowarn_classload=1; # really inefficient, but again, only has to run once foreach my $table (qw(cust_pay cust_pay_void cust_refund)) { + my $and_batchnum_is_null = + ( $table =~ /^cust_pay/ ? ' AND batchnum IS NULL' : '' ); foreach my $object ( qsearch({ table => $table, extra_sql => "WHERE payby IN('CARD','CHEK') ". "AND (paybatch IS NOT NULL ". - "OR (paybatch IS NULL AND auth IS NULL) )", + "OR (paybatch IS NULL AND auth IS NULL + $and_batchnum_is_null ) )", }) ) { if ( $object->paybatch eq '' ) { @@ -1059,6 +1063,8 @@ sub _upgrade_data { #class method warn "couldn't find paybatch history record for $table ".$object->$pkey."\n"; next; } + # if the paybatch didn't have an auth string, then it's fine + $h->paybatch =~ /:(\w+):/ or next; # set paybatch to what it was in that record $object->set('paybatch', $h->paybatch) # and then upgrade it like the old records @@ -1076,7 +1082,7 @@ sub _upgrade_data { #class method } } #$object } #$table - FS::upgrade_journal->set_done('cust_pay__parse_paybatch'); + FS::upgrade_journal->set_done('cust_pay__parse_paybatch_1'); } } diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 87acf0e52..741d440fa 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1,7 +1,8 @@ package FS::cust_pkg; use strict; -use base qw( FS::otaker_Mixin FS::cust_main_Mixin FS::location_Mixin +use base qw( FS::otaker_Mixin FS::cust_main_Mixin + FS::contact_Mixin FS::location_Mixin FS::m2m_Common FS::option_Common ); use vars qw($disable_agentcheck $DEBUG $me); use Carp qw(cluck); @@ -17,6 +18,7 @@ use FS::CurrentUser; use FS::cust_svc; use FS::part_pkg; use FS::cust_main; +use FS::contact; use FS::cust_location; use FS::pkg_svc; use FS::cust_bill_pkg; @@ -225,7 +227,7 @@ Create a new billing item. To add the item to the database, see L<"insert">. =cut sub table { 'cust_pkg'; } -sub cust_linked { $_[0]->cust_main_custnum; } +sub cust_linked { $_[0]->cust_main_custnum || $_[0]->custnum } sub cust_unlinked_msg { my $self = shift; "WARNING: can't find cust_main.custnum ". $self->custnum. @@ -267,6 +269,12 @@ a ticket will be added to this customer with this subject an optional queue name for ticket additions +=item allow_pkgpart + +Don't check the legality of the package definition. This should be used +when performing a package change that doesn't change the pkgpart (i.e. +a location change). + =back =cut @@ -274,7 +282,8 @@ an optional queue name for ticket additions sub insert { my( $self, %options ) = @_; - my $error = $self->check_pkgpart; + my $error; + $error = $self->check_pkgpart unless $options{'allow_pkgpart'}; return $error if $error; my $part_pkg = $self->part_pkg; @@ -613,7 +622,7 @@ sub check { $self->ut_numbern('pkgnum') || $self->ut_foreign_key('custnum', 'cust_main', 'custnum') || $self->ut_numbern('pkgpart') - || $self->check_pkgpart + || $self->ut_foreign_keyn('contactnum', 'contact', 'contactnum' ) || $self->ut_foreign_keyn('locationnum', 'cust_location', 'locationnum') || $self->ut_numbern('start_date') || $self->ut_numbern('setup') @@ -654,14 +663,19 @@ sub check { =item check_pkgpart +Check the pkgpart to make sure it's allowed with the reg_code and/or +promo_code of the package (if present) and with the customer's agent. +Called from C<insert>, unless we are doing a package change that doesn't +affect pkgpart. + =cut sub check_pkgpart { my $self = shift; - my $error = $self->ut_numbern('pkgpart'); - return $error if $error; + # my $error = $self->ut_numbern('pkgpart'); # already done + my $error; if ( $self->reg_code ) { unless ( grep { $self->pkgpart == $_->pkgpart } @@ -981,6 +995,7 @@ sub uncancel { my $error = $cust_pkg->insert( 'change' => 1, #supresses any referral credit to a referring customer + 'allow_pkgpart' => 1, # allow this even if the package def is disabled ); if ($error) { $dbh->rollback if $oldAutoCommit; @@ -1749,12 +1764,23 @@ sub change { if ( $opt->{'cust_location'} && ( ! $opt->{'locationnum'} || $opt->{'locationnum'} == -1 ) ) { - $error = $opt->{'cust_location'}->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return "inserting cust_location (transaction rolled back): $error"; + + if ( ! $opt->{'cust_location'}->locationnum ) { + # not inserted yet + $error = $opt->{'cust_location'}->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "inserting cust_location (transaction rolled back): $error"; + } } $opt->{'locationnum'} = $opt->{'cust_location'}->locationnum; + + } + + # whether to override pkgpart checking on the new package + my $same_pkgpart = 1; + if ( $opt->{'pkgpart'} and ( $opt->{'pkgpart'} != $self->pkgpart ) ) { + $same_pkgpart = 0; } my $unused_credit = 0; @@ -1781,6 +1807,12 @@ sub change { # (i.e. customer default location) $opt->{'locationnum'} = $self->locationnum if !exists($opt->{'locationnum'}); + # usually this doesn't matter. the two cases where it does are: + # 1. unused_credit_change + pkgpart change + setup fee on the new package + # and + # 2. (more importantly) changing a package before it's billed + $hash{'waive_setup'} = $self->waive_setup; + # Create the new package. my $cust_pkg = new FS::cust_pkg { custnum => $self->custnum, @@ -1789,7 +1821,8 @@ sub change { locationnum => ( $opt->{'locationnum'} ), %hash, }; - $error = $cust_pkg->insert( 'change' => 1 ); + $error = $cust_pkg->insert( 'change' => 1, + 'allow_pkgpart' => $same_pkgpart ); if ($error) { $dbh->rollback if $oldAutoCommit; return $error; @@ -1847,6 +1880,23 @@ sub change { } } + # transfer discounts, if we're not changing pkgpart + if ( $same_pkgpart ) { + foreach my $old_discount ($self->cust_pkg_discount_active) { + # don't remove the old discount, we may still need to bill that package. + my $new_discount = new FS::cust_pkg_discount { + 'pkgnum' => $cust_pkg->pkgnum, + 'discountnum' => $old_discount->discountnum, + 'months_used' => $old_discount->months_used, + }; + $error = $new_discount->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error transferring discounts: $error"; + } + } + } + # Order any supplemental packages. my $part_pkg = $cust_pkg->part_pkg; my @old_supp_pkgs = $self->supplemental_pkgs; @@ -1874,14 +1924,14 @@ sub change { contract_end => $cust_pkg->contract_end, refnum => $cust_pkg->refnum, discountnum => $cust_pkg->discountnum, - waive_setup => $cust_pkg->waive_setup + waive_setup => $cust_pkg->waive_setup, }); if ( $old and $opt->{'keep_dates'} ) { foreach (qw(setup bill last_bill)) { $new->set($_, $old->get($_)); } } - $error = $new->insert; + $error = $new->insert( allow_pkgpart => $same_pkgpart ); # transfer services if ( $old ) { $error ||= $old->transfer($new); @@ -1931,6 +1981,24 @@ sub change { } +=item set_quantity QUANTITY + +Change the package's quantity field. This is the one package property +that can safely be changed without canceling and reordering the package +(because it doesn't affect tax eligibility). Returns an error or an +empty string. + +=cut + +sub set_quantity { + my $self = shift; + $self = $self->replace_old; # just to make sure + my $qty = shift; + ($qty =~ /^\d+$/ and $qty > 0) or return "bad package quantity $qty"; + $self->set('quantity' => $qty); + $self->replace; +} + use Storable 'thaw'; use MIME::Base64; sub process_bulk_cust_pkg { @@ -2621,7 +2689,7 @@ sub statuscolor { =item pkg_label Returns a label for this package. (Currently "pkgnum: pkg - comment" or -"pkg-comment" depending on user preference). +"pkg - comment" depending on user preference). =cut @@ -2648,6 +2716,17 @@ sub pkg_label_long { $label; } +=item pkg_locale + +Returns a customer-localized label for this package. + +=cut + +sub pkg_locale { + my $self = shift; + $self->part_pkg->pkg_locale( $self->cust_main->locale ); +} + =item primary_cust_svc Returns a primary service (as FS::cust_svc object) if one can be identified. diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index bbf4eedf8..165384048 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -895,6 +895,48 @@ sub smart_search_param { ); } +sub _upgrade_data { + my $class = shift; + + # fix missing (deleted by mistake) svc_x records + warn "searching for missing svc_x records...\n"; + my %search = ( + 'table' => 'cust_svc', + 'select' => 'cust_svc.*', + 'addl_from' => ' LEFT JOIN ( ' . + join(' UNION ', + map { "SELECT svcnum FROM $_" } + FS::part_svc->svc_tables + ) . ' ) AS svc_all ON cust_svc.svcnum = svc_all.svcnum', + 'extra_sql' => ' WHERE svc_all.svcnum IS NULL', + ); + my @svcs = qsearch(\%search); + warn "found ".scalar(@svcs)."\n"; + + local $FS::Record::nowarn_classload = 1; # for h_svc_ + local $FS::svc_Common::noexport_hack = 1; # because we're inserting services + + my %h_search = ( + 'hashref' => { history_action => 'delete' }, + 'order_by' => ' ORDER BY history_date DESC LIMIT 1', + ); + foreach my $cust_svc (@svcs) { + my $svcnum = $cust_svc->svcnum; + my $svcdb = $cust_svc->part_svc->svcdb; + $h_search{'hashref'}{'svcnum'} = $svcnum; + $h_search{'table'} = "h_$svcdb"; + my $h_svc_x = qsearchs(\%h_search) + or next; + my $class = "FS::$svcdb"; + my $new_svc_x = $class->new({ $h_svc_x->hash }); + my $error = $new_svc_x->insert; + warn "error repairing svcnum $svcnum ($svcdb) from history:\n$error\n" + if $error; + } + + ''; +} + =back =head1 BUGS diff --git a/FS/FS/export_svc.pm b/FS/FS/export_svc.pm index 0370f5f0b..b08f8f7c3 100644 --- a/FS/FS/export_svc.pm +++ b/FS/FS/export_svc.pm @@ -5,6 +5,7 @@ use vars qw( @ISA ); use FS::Record qw( qsearch qsearchs dbh ); use FS::part_export; use FS::part_svc; +use FS::svc_export_machine; @ISA = qw(FS::Record); @@ -209,6 +210,19 @@ sub insert { } #end of duplicate check, whew $error = $self->SUPER::insert; + + my $part_export = $self->part_export; + if ( !$error and $part_export->default_machine ) { + foreach my $cust_svc ( $self->part_svc->cust_svc ) { + my $svc_export_machine = FS::svc_export_machine->new({ + 'exportnum' => $self->exportnum, + 'svcnum' => $cust_svc->svcnum, + 'machinenum' => $part_export->default_machine, + }); + $error ||= $svc_export_machine->insert; + } + } + if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -251,7 +265,23 @@ Delete this record from the database. =cut -# the delete method can be inherited from FS::Record +sub delete { + my $self = shift; + my $dbh = dbh; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + + my $error = $self->SUPER::delete; + foreach ($self->svc_export_machine) { + $error ||= $_->delete; + } + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; +} + =item replace OLD_RECORD @@ -307,6 +337,24 @@ sub part_svc { qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } ); } +=item svc_export_machine + +Returns all export hostname records (L<FS::svc_export_machine>) for this +combination of svcpart and exportnum. + +=cut + +sub svc_export_machine { + my $self = shift; + qsearch({ + 'table' => 'svc_export_machine', + 'select' => 'svc_export_machine.*', + 'addl_from' => 'JOIN cust_svc USING (svcnum)', + 'hashref' => { 'exportnum' => $self->exportnum }, + 'extra_sql' => ' AND cust_svc.svcpart = '.$self->svcpart, + }); +} + =back =head1 BUGS diff --git a/FS/FS/part_event/Condition/cust_bill_owed_percent.pm b/FS/FS/part_event/Condition/cust_bill_owed_percent.pm new file mode 100644 index 000000000..e06b511ef --- /dev/null +++ b/FS/FS/part_event/Condition/cust_bill_owed_percent.pm @@ -0,0 +1,50 @@ +package FS::part_event::Condition::cust_bill_owed_percent; + +use strict; +use FS::cust_bill; + +use base qw( FS::part_event::Condition ); + +sub description { + 'Percentage owed on specific invoice'; +} + +sub eventtable_hashref { + { 'cust_main' => 0, + 'cust_bill' => 1, + 'cust_pkg' => 0, + }; +} + +sub option_fields { + ( + 'owed' => { 'label' => 'Percentage of invoice owed over', + 'type' => 'percentage', + 'value' => '0', #default + }, + ); +} + +sub condition { + #my($self, $cust_bill, %opt) = @_; + my($self, $cust_bill) = @_; + + my $percent = $self->option('owed') || 0; + my $over = sprintf('%.2f', + $cust_bill->charged * $percent / 100); + + $cust_bill->owed > $over; +} + +sub condition_sql { + my( $class, $table ) = @_; + + # forces the option to be an integer--do we care? + my $percent = $class->condition_sql_option_integer('owed'); + + my $owed_sql = FS::cust_bill->owed_sql; + + "$owed_sql > CAST( cust_bill.charged * $percent / 100 AS DECIMAL(10,2) )"; +} + +1; diff --git a/FS/FS/part_event/Condition/message_email.pm b/FS/FS/part_event/Condition/message_email.pm new file mode 100644 index 000000000..7cceba697 --- /dev/null +++ b/FS/FS/part_event/Condition/message_email.pm @@ -0,0 +1,22 @@ +package FS::part_event::Condition::message_email; +use base qw( FS::part_event::Condition ); +use strict; + +sub description { + 'Customer allows email notices' +} + +sub condition { + my( $self, $object ) = @_; + my $cust_main = $self->cust_main($object); + + $cust_main->message_noemail ? 0 : 1; +} + +sub condition_sql { + my( $self, $table ) = @_; + + "cust_main.message_noemail IS NULL" +} + +1; diff --git a/FS/FS/part_event/Condition/once_perinv.pm b/FS/FS/part_event/Condition/once_perinv.pm index f85a05665..1ee53b812 100644 --- a/FS/FS/part_event/Condition/once_perinv.pm +++ b/FS/FS/part_event/Condition/once_perinv.pm @@ -12,6 +12,15 @@ sub description { "Run only once for each time the package has been billed"; } # Run the event, at most, a number of times equal to the number of # distinct invoices that contain line items from this package. +sub option_fields { + ( + 'paid' => { 'label' => 'Only count paid bills', + 'type' => 'checkbox', + 'value' => 'Y', + }, + ) +} + sub eventtable_hashref { { 'cust_main' => 0, 'cust_bill' => 0, @@ -22,9 +31,15 @@ sub eventtable_hashref { sub condition { my($self, $cust_pkg, %opt) = @_; - my %invnum; - $invnum{$_->invnum} = 1 - foreach ( qsearch('cust_bill_pkg', { 'pkgnum' => $cust_pkg->pkgnum }) ); + my @cust_bill_pkg = qsearch('cust_bill_pkg', { pkgnum=>$cust_pkg->pkgnum }); + + @cust_bill_pkg = grep { ($_->owed_setup + $_->owed_recur) == 0 } + @cust_bill_pkg + if $self->option('paid'); + + my %invnum = (); + $invnum{$_->invnum} = 1 foreach @cust_bill_pkg; + my @events = qsearch( { 'table' => 'cust_event', 'hashref' => { 'eventpart' => $self->eventpart, @@ -40,6 +55,9 @@ sub condition { sub condition_sql { my( $self, $table ) = @_; + #paid flag not yet implemented here, but that's okay, a partial optimization + # is better than none + "( ( SELECT COUNT(distinct(invnum)) FROM cust_bill_pkg diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 3eee37f71..28cb1419d 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -125,31 +125,14 @@ sub insert { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - my $error = $self->SUPER::insert(@_); + my $error = $self->SUPER::insert(@_) + || $self->replace; + # use replace to do all the part_export_machine and default_machine stuff if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; } - #kinda false laziness with process_m2name - my @machines = map { $_ =~ s/^\s+//; $_ =~ s/\s+$//; $_ } - grep /\S/, - split /[\n\r]{1,2}/, - $self->part_export_machine_textarea; - - foreach my $machine ( @machines ) { - - my $part_export_machine = new FS::part_export_machine { - 'exportnum' => $self->exportnum, - 'machine' => $machine, - }; - $error = $part_export_machine->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; - } - } - $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; } @@ -217,6 +200,7 @@ or modified. sub replace { my $self = shift; + my $old = $self->replace_old; local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -228,12 +212,7 @@ sub replace { my $oldAutoCommit = $FS::UID::AutoCommit; local $FS::UID::AutoCommit = 0; my $dbh = dbh; - - my $error = $self->SUPER::replace(@_); - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; - } + my $error; if ( $self->part_export_machine_textarea ) { @@ -258,6 +237,10 @@ sub replace { } } + if ( $self->default_machine_name eq $machine ) { + $self->default_machine( $part_export_machine{$machine}->machinenum ); + } + delete $part_export_machine{$machine}; #so we don't disable it below } else { @@ -272,11 +255,13 @@ sub replace { return $error; } + if ( $self->default_machine_name eq $machine ) { + $self->default_machine( $part_export_machine->machinenum ); + } } } - foreach my $part_export_machine ( values %part_export_machine ) { $part_export_machine->disabled('Y'); $error = $part_export_machine->replace; @@ -286,6 +271,48 @@ sub replace { } } + if ( $old->machine ne '_SVC_MACHINE' ) { + # then set up the default for any already-attached export_svcs + foreach my $export_svc ( $self->export_svc ) { + my @svcs = qsearch('cust_svc', { 'svcpart' => $export_svc->svcpart }); + foreach my $cust_svc ( @svcs ) { + my $svc_export_machine = FS::svc_export_machine->new({ + 'exportnum' => $self->exportnum, + 'svcnum' => $cust_svc->svcnum, + 'machinenum' => $self->default_machine, + }); + $error ||= $svc_export_machine->insert; + } + } + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } # if switching to selectable hosts + + } elsif ( $old->machine eq '_SVC_MACHINE' ) { + # then we're switching from selectable to non-selectable + foreach my $svc_export_machine ( + qsearch('svc_export_machine', { 'exportnum' => $self->exportnum }) + ) { + $error ||= $svc_export_machine->delete; + } + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + } + + $error = $self->SUPER::replace(@_); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + if ( $self->machine eq '_SVC_MACHINE' and ! $self->default_machine ) { + $dbh->rollback if $oldAutoCommit; + return "no default export host selected"; } $dbh->commit or die $dbh->errstr if $oldAutoCommit; @@ -308,6 +335,13 @@ sub check { || $self->ut_domainn('machine') || $self->ut_alpha('exporttype') ; + + if ( $self->machine eq '_SVC_MACHINE' ) { + $error ||= $self->ut_numbern('default_machine') + } else { + $self->set('default_machine', ''); + } + return $error if $error; $self->nodomain =~ /^(Y?)$/ or return "Illegal nodomain: ". $self->nodomain; @@ -471,7 +505,9 @@ sub _rebless { $self; } -=item svc_machine +=item svc_machine SVC_X + +Return the export hostname for SVC_X. =cut @@ -483,14 +519,33 @@ sub svc_machine { my $svc_export_machine = qsearchs('svc_export_machine', { 'svcnum' => $svc_x->svcnum, 'exportnum' => $self->exportnum, - }) - #would only happen if you add this export to existing services without a - #machine set then try to run exports without setting it... right? - or die "No hostname selected for ".($self->exportname || $self->exporttype); + }); + + if (!$svc_export_machine) { + warn "No hostname selected for ".($self->exportname || $self->exporttype); + return $self->default_export_machine->machine; + } return $svc_export_machine->part_export_machine->machine; } +=item default_export_machine + +Return the default export hostname for this export. + +=cut + +sub default_export_machine { + my $self = shift; + my $machinenum = $self->default_machine; + if ( $machinenum ) { + my $default_machine = FS::part_export_machine->by_key($machinenum); + return $default_machine->machine if $default_machine; + } + # this should not happen + die "no default export hostname for export ".$self->exportnum; +} + #these should probably all go away, just let the subclasses define em =item export_insert SVC_OBJECT @@ -601,6 +656,17 @@ DEFAULTSREF is a hashref with the same keys where true values indicate the setting is a default (and thus can be displayed in the UI with less emphasis, or hidden by default). +=item actions + +Adds one or more "action" links to the export's display in +browse/part_export.cgi. Should return pairs of values. The first is +the link label; the second is the Mason path to a document to load. +The document will show in a popup. + +=cut + +sub actions { } + =cut =item weight @@ -692,6 +758,55 @@ sub _upgrade_data { #class method $error = $opt->replace; die $error if $error; } + # for exports that have selectable hostnames, make sure all services + # have a hostname selected + foreach my $part_export ( + qsearch('part_export', { 'machine' => '_SVC_MACHINE' }) + ) { + + my $exportnum = $part_export->exportnum; + my $machinenum = $part_export->default_machine; + if (!$machinenum) { + my ($first) = $part_export->part_export_machine; + if (!$first) { + # user intervention really is required. + die "Export $exportnum has no hostname options defined.\n". + "You must correct this before upgrading.\n"; + } + # warn about this, because we might not choose the right one + warn "Export $exportnum (". $part_export->exporttype. + ") has no default hostname. Setting to ".$first->machine."\n"; + $machinenum = $first->machinenum; + $part_export->set('default_machine', $machinenum); + my $error = $part_export->replace; + die $error if $error; + } + + # the service belongs to a service def that uses this export + # and there is not a hostname selected for this export for that service + my $join = ' JOIN export_svc USING ( svcpart )'. + ' LEFT JOIN svc_export_machine'. + ' ON ( cust_svc.svcnum = svc_export_machine.svcnum'. + ' AND export_svc.exportnum = svc_export_machine.exportnum )'; + + my @svcs = qsearch( { + 'select' => 'cust_svc.*', + 'table' => 'cust_svc', + 'addl_from' => $join, + 'extra_sql' => ' WHERE svcexportmachinenum IS NULL'. + ' AND export_svc.exportnum = '.$part_export->exportnum, + } ); + foreach my $cust_svc (@svcs) { + my $svc_export_machine = FS::svc_export_machine->new({ + 'exportnum' => $exportnum, + 'machinenum' => $machinenum, + 'svcnum' => $cust_svc->svcnum, + }); + my $error = $svc_export_machine->insert; + die $error if $error; + } + } + # pass downstream my %exports_in_use; $exports_in_use{ref $_} = 1 foreach qsearch('part_export', {}); diff --git a/FS/FS/part_export/huawei_hlr.pm b/FS/FS/part_export/huawei_hlr.pm index d231567c1..007981880 100644 --- a/FS/FS/part_export/huawei_hlr.pm +++ b/FS/FS/part_export/huawei_hlr.pm @@ -5,8 +5,12 @@ use Tie::IxHash; use FS::Record qw(qsearch qsearchs dbh); use FS::part_export; use FS::svc_phone; +use FS::inventory_class; +use FS::inventory_item; use IO::Socket::INET; use Data::Dumper; +use MIME::Base64 qw(decode_base64); +use Storable qw(thaw); use strict; @@ -18,6 +22,20 @@ tie my %options, 'Tie::IxHash', 'pwd' => { label=>'Operator password' }, 'tplid' => { label=>'Template number' }, 'hlrsn' => { label=>'HLR serial number' }, + 'k4sno' => { label=>'K4 serial number' }, + 'cardtype' => { label => 'Card type', + type => 'select', + options=> ['SIM', 'USIM'] + }, + 'alg' => { label => 'Authentication algorithm', + type => 'select', + options=> ['COMP128_1', + 'COMP128_2', + 'COMP128_3', + 'MILENAGE' ], + }, + 'opcvalue' => { label=>'OPC value (for MILENAGE only)' }, + 'opsno' => { label=>'OP serial number (for MILENAGE only)' }, 'timeout' => { label=>'Timeout (seconds)', default => 120 }, 'debug' => { label=>'Enable debugging', type=>'checkbox' }, ; @@ -33,6 +51,10 @@ set on the service, and the template must exist. END ); +sub actions { + 'Import SIMs' => 'misc/part_export/huawei_hlr-import_sim.html' +} + sub _export_insert { my( $self, $svc_phone ) = (shift, shift); # svc_phone::check should ensure phonenum and sim_imsi are numeric @@ -227,4 +249,92 @@ sub command { \%return; } +sub process_import_sim { + my $job = shift; + my $param = thaw(decode_base64(shift)); + $param->{'job'} = $job; + my $exportnum = delete $param->{'exportnum'}; + my $export = __PACKAGE__->by_key($exportnum); + my $file = delete $param->{'uploaded_files'}; + $file =~ s/^file://; + my $dir = $FS::UID::cache_dir .'/cache.'. $FS::UID::datasrc; + open( $param->{'filehandle'}, '<', "$dir/$file" ) + or die "unable to open '$file'.\n"; + my $error = $export->import_sim($param); +} + +sub import_sim { + # import a SIM list + local $FS::UID::AutoCommit = 1; # yes, 1 + my $self = shift; + my $param = shift; + my $job = $param->{'job'}; + my $fh = $param->{'filehandle'}; + my @lines = $fh->getlines; + + my @command = 'ADD KI'; + push @command, ('HLRSN', $self->option('hlrsn')) if $self->option('hlrsn'); + + my @args = ('OPERTYPE', 'ADD'); + push @args, ('K4SNO', $self->option('k4sno')) if $self->option('k4sno'); + push @args, ('CARDTYPE', $self->option('cardtype'), + 'ALG', $self->option('alg')); + push @args, ('OPCVALUE', $self->option('opcvalue'), + 'OPSNO', $self->option('opsno')) + if $self->option('alg') eq 'MILENAGE'; + + my $agentnum = $param->{'agentnum'}; + my $classnum = $param->{'classnum'}; + my $class = FS::inventory_class->by_key($classnum) + or die "bad inventory class $classnum\n"; + my %existing = map { $_->item, 1 } + qsearch('inventory_item', { 'classnum' => $classnum }); + + my $socket = $self->login; + my $num=0; + my $total = scalar(@lines); + foreach my $line (@lines) { + $num++; + $job->update_statustext(int(100*$num/$total).',Provisioning IMSIs...') + if $job; + + chomp $line; + my ($imsi, $iccid, $pin1, $puk1, $pin2, $puk2, $acc, $ki) = + split(' ', $line); + # the only fields we really care about are the IMSI and KI. + if ($imsi !~ /^\d{15}$/ or $ki !~ /^[0-9A-Z]{32}$/) { + warn "misspelled line in SIM file: $line\n"; + next; + } + if ($existing{$imsi}) { + warn "IMSI $imsi already in inventory, skipped\n"; + next; + } + + # push IMSI/KI to the HLR + my $return = $self->command($socket, + @command, + 'IMSI', $imsi, + 'KIVALUE', $ki, + @args + ); + if ( $return->{success} ) { + # add to inventory + my $item = FS::inventory_item->new({ + 'classnum' => $classnum, + 'agentnum' => $agentnum, + 'item' => $imsi, + }); + my $error = $item->insert; + if ( $error ) { + die "IMSI $imsi added to HLR, but not to inventory:\n$error\n"; + } + } else { + die "IMSI $imsi could not be added to HLR:\n".$return->{error}."\n"; + } + } #foreach $line + $self->logout($socket); + return; +} + 1; diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index f964af31c..9408d1454 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -243,12 +243,12 @@ sub _export_command { ${$_} = $svc_acct->getfield($_) foreach $svc_acct->fields; # snarfs are unused at this point? - my $count = 1; - foreach my $acct_snarf ( $svc_acct->acct_snarf ) { - ${"snarf_$_$count"} = shell_quote( $acct_snarf->get($_) ) - foreach qw( machine username _password ); - $count++; - } + # my $count = 1; + # foreach my $acct_snarf ( $svc_acct->acct_snarf ) { + # ${"snarf_$_$count"} = shell_quote( $acct_snarf->get($_) ) + # foreach qw( machine username _password ); + # $count++; + # } } my $cust_pkg = $svc_acct->cust_svc->cust_pkg; diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm index 18ee30488..833dd9a1d 100644 --- a/FS/FS/part_export/sqlradius.pm +++ b/FS/FS/part_export/sqlradius.pm @@ -597,7 +597,8 @@ New-style: pass a hashref with the following keys: =item stoptime_end - Upper bound for AcctStopTime, as a UNIX timestamp -=item open_sessions - Only show records with no AcctStopTime (typically used without stoptime_* options and with starttime_* options instead) +=item session_status - 'closed' to only show records with AcctStopTime, +'open' to only show records I<without> AcctStopTime, empty to show both. =item starttime_start - Lower bound for AcctStartTime, as a UNIX timestamp @@ -727,20 +728,26 @@ sub usage_sessions { push @where, " CalledStationID LIKE 'sip:$prefix\%'"; } - if ( $opt->{open_sessions} ) { - push @where, 'AcctStopTime IS NULL'; - } else { - + my $acctstoptime = ''; + if ( $opt->{session_status} ne 'open' ) { if ( $start ) { - push @where, "$str2time AcctStopTime ) >= ?"; + $acctstoptime .= "$str2time AcctStopTime ) >= ?"; push @param, $start; + $acctstoptime .= ' AND ' if $end; } if ( $end ) { - push @where, "$str2time AcctStopTime ) <= ?"; + $acctstoptime .= "$str2time AcctStopTime ) <= ?"; push @param, $end; } - } + if ( $opt->{session_status} ne 'closed' ) { + if ( $acctstoptime ) { + $acctstoptime = "( ( $acctstoptime ) OR AcctStopTime IS NULL )"; + } else { + $acctstoptime = 'AcctStopTime IS NULL'; + } + } + push @where, $acctstoptime; if ( $opt->{starttime_start} ) { push @where, "$str2time AcctStartTime ) >= ?"; diff --git a/FS/FS/part_export/test.pm b/FS/FS/part_export/test.pm new file mode 100644 index 000000000..126897c0b --- /dev/null +++ b/FS/FS/part_export/test.pm @@ -0,0 +1,75 @@ +package FS::part_export::test; + +use strict; +use vars qw(%options %info); +use Tie::IxHash; +use base qw(FS::part_export); + +tie %options, 'Tie::IxHash', + 'result' => { label => 'Result', + type => 'select', + options => [ 'success', 'failure', 'exception' ], + default => 'success', + }, + 'errormsg'=> { label => 'Error message', + default => 'Test export' }, + 'insert' => { label => 'Insert', type => 'checkbox', default => 1, }, + 'delete' => { label => 'Delete', type => 'checkbox', default => 1, }, + 'replace' => { label => 'Replace',type => 'checkbox', default => 1, }, + 'suspend' => { label => 'Suspend',type => 'checkbox', default => 1, }, + 'unsuspend'=>{ label => 'Unsuspend', type => 'checkbox', default => 1, }, +; + +%info = ( + 'svc' => [ qw(svc_acct svc_broadband svc_phone svc_domain) ], + 'desc' => 'Test export for development', + 'options' => \%options, + 'notes' => <<END, +<P>Test export. Do not use this in production systems.</P> +<P>This export either always succeeds, always fails (returning an error), +or always dies, according to the "Result" option. It does nothing else; the +purpose is purely to simulate success or failure within an export module.</P> +<P>The checkbox options can be used to turn the export off for certain +actions, if this is needed.</P> +END +); + +sub export_insert { + my $self = shift; + $self->run(@_) if $self->option('insert'); +} + +sub export_delete { + my $self = shift; + $self->run(@_) if $self->option('delete'); +} + +sub export_replace { + my $self = shift; + $self->run(@_) if $self->option('replace'); +} + +sub export_suspend { + my $self = shift; + $self->run(@_) if $self->option('suspend'); +} + +sub export_unsuspend { + my $self = shift; + $self->run(@_) if $self->option('unsuspend'); +} + +sub run { + my $self = shift; + my $svc_x = shift; + my $result = $self->option('result'); + if ( $result eq 'failure' ) { + return $self->option('errormsg'); + } elsif ( $result eq 'exception' ) { + die $self->option('errormsg'); + } else { + return ''; + } +} + +1; diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index 856a693dd..e788269f7 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -1,7 +1,8 @@ package FS::part_pkg; +use base qw( FS::m2m_Common FS::o2m_Common FS::option_Common ); use strict; -use vars qw( @ISA %plans $DEBUG $setup_hack $skip_pkg_svc_hack ); +use vars qw( %plans $DEBUG $setup_hack $skip_pkg_svc_hack ); use Carp qw(carp cluck confess); use Scalar::Util qw( blessed ); use Time::Local qw( timelocal_nocheck ); @@ -16,6 +17,7 @@ use FS::type_pkgs; use FS::part_pkg_option; use FS::pkg_class; use FS::agent; +use FS::part_pkg_msgcat; use FS::part_pkg_taxrate; use FS::part_pkg_taxoverride; use FS::part_pkg_taxproduct; @@ -24,7 +26,6 @@ use FS::part_pkg_discount; use FS::part_pkg_usage; use FS::part_pkg_vendor; -@ISA = qw( FS::m2m_Common FS::option_Common ); $DEBUG = 0; $setup_hack = 0; $skip_pkg_svc_hack = 0; @@ -715,6 +716,35 @@ sub propagate { join("\n", @error); } +=item pkg_locale LOCALE + +Returns a customer-viewable string representing this package for the given +locale, from the part_pkg_msgcat table. If the given locale is empty or no +localized string is found, returns the base pkg field. + +=cut + +sub pkg_locale { + my( $self, $locale ) = @_; + return $self->pkg unless $locale; + my $part_pkg_msgcat = $self->part_pkg_msgcat($locale) or return $self->pkg; + $part_pkg_msgcat->pkg; +} + +=item part_pkg_msgcat LOCALE + +Like pkg_locale, but returns the FS::part_pkg_msgcat object itself. + +=cut + +sub part_pkg_msgcat { + my( $self, $locale ) = @_; + qsearchs( 'part_pkg_msgcat', { + pkgpart => $self->pkgpart, + locale => $locale, + }); +} + =item pkg_comment [ OPTION => VALUE... ] Returns an (internal) string representing this package. Currently, diff --git a/FS/FS/part_pkg/prorate_Mixin.pm b/FS/FS/part_pkg/prorate_Mixin.pm index 153ed56cd..9efc7e89d 100644 --- a/FS/FS/part_pkg/prorate_Mixin.pm +++ b/FS/FS/part_pkg/prorate_Mixin.pm @@ -67,11 +67,11 @@ the base price per billing cycle. Options: - add_full_period: Bill for the time up to the prorate day plus one full -billing period after that. + billing period after that. - prorate_round_day: Round the current time to the nearest full day, -instead of using the exact time. + instead of using the exact time. - prorate_defer_bill: Don't bill the prorate interval until the prorate -day arrives. + day arrives. - prorate_verbose: Generate details to explain the prorate calculations. =cut @@ -104,7 +104,7 @@ sub calc_prorate { $add_period = 1; } - # if the customer alreqady has a billing day-of-month established, + # if the customer already has a billing day-of-month established, # and it's a valid cutoff day, try to respect it my $next_bill_day; if ( my $next_bill = $cust_pkg->cust_main->next_bill_date ) { @@ -123,31 +123,46 @@ sub calc_prorate { my $permonth = $charge / $self->freq; my $months = ( ( $self->freq - 1 ) + ($mend-$mnow) / ($mend-$mstart) ); - - if ( $self->option('prorate_verbose',1) - and $months > 0 and $months < $self->freq ) { - push @$details, - 'Prorated (' . time2str('%b %d', $mnow) . - ' - ' . time2str('%b %d', $mend) . '): ' . $money_char . - sprintf('%.2f', $permonth * $months + 0.00000001 ); - } + # after this, $self->freq - 1 < $months <= $self->freq # add a full period if currently billing for a partial period # or periods up to freq_override if billing for an override interval if ( ($param->{'freq_override'} || 0) > 1 ) { $months += $param->{'freq_override'} - 1; - } - elsif ( $add_period && $months < $self->freq) { + # freq_override - 1 correct here? + # (probably only if freq == 1, yes?) + } elsif ( $add_period && $months < $self->freq ) { + + # 'add_period' is a misnomer. + # we add enough to make the total at least a full period + $months++; + $$sdate = $self->add_freq($mstart, 1); + # now $self->freq <= $months <= $self->freq + 1 + # (note that this only happens if $months < $self->freq to begin with) - if ( $self->option('prorate_verbose',1) ) { - # calculate the prorated and add'l period charges + } + + if ( $self->option('prorate_verbose',1) and $months > 0 ) { + if ( $months < $self->freq ) { + # we are billing a fractional period only + # # (though maybe not a fractional month) + my $period_end = $self->add_freq($mstart); + push @$details, + 'Prorated (' . time2str('%b %d', $mnow) . + ' - ' . time2str('%b %d', $period_end) . '): ' . $money_char . + sprintf('%.2f', $permonth * $months + 0.00000001 ); + + } elsif ( $months > $self->freq ) { + # we are billing MORE than a full period push @$details, - 'First full month: ' . $money_char . - sprintf('%.2f', $permonth); - } - $months += $self->freq; - $$sdate = $self->add_freq($mstart); + 'Prorated (' . time2str('%b %d', $mnow) . + ' - ' . time2str('%b %d', $mend) . '): ' . $money_char . + sprintf('%.2f', $permonth * ($months - $self->freq + 0.0000001)), + + 'First full period: ' . $money_char . + sprintf('%.2f', $permonth * $self->freq); + } # else $months == $self->freq, and no prorating has happened } $param->{'months'} = $months; diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index 67ddfb5e9..21c6a8a2c 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -157,10 +157,16 @@ tie my %detail_formats, 'Tie::IxHash', 'use_carrierid' => { 'name' => 'Only charge for CDRs where the Carrier ID is set to any of these (comma-separated) values: ', }, - 'use_cdrtypenum' => { 'name' => 'Only charge for CDRs where the CDR Type is set to: ', + 'use_cdrtypenum' => { 'name' => 'Only charge for CDRs where the CDR Type is set to this cdrtypenum: ', }, - 'ignore_cdrtypenum' => { 'name' => 'Do not charge for CDRs where the CDR Type is set to: ', + 'ignore_cdrtypenum' => { 'name' => 'Do not charge for CDRs where the CDR Type is set to this cdrtypenum: ', + }, + + 'use_calltypenum' => { 'name' => 'Only charge for CDRs where the CDR Call Type is set to this calltypenum: ', + }, + + 'ignore_calltypenum' => { 'name' => 'Do not charge for CDRs where the CDR Call Type is set to this calltypenum: ', }, 'ignore_disposition' => { 'name' => 'Do not charge for CDRs where the Disposition is set to any of these (comma-separated) values: ', @@ -208,6 +214,11 @@ tie my %detail_formats, 'Tie::IxHash', 'skip_max_callers' => { 'name' => 'Do not charge for CDRs where max_callers is less than or equal to this value: ', }, + 'skip_same_customer' => { + 'name' => 'Do not charge for calls between numbers belonging to the same customer', + 'type' => 'checkbox', + }, + 'use_duration' => { 'name' => 'Calculate usage based on the duration field instead of the billsec field', 'type' => 'checkbox', }, @@ -304,6 +315,7 @@ tie my %detail_formats, 'Tie::IxHash', use_amaflags use_carrierid use_cdrtypenum ignore_cdrtypenum + use_calltypenum ignore_calltypenum ignore_disposition disposition_in skip_dcontext skip_dst_prefix skip_dstchannel_prefix skip_src_length_more @@ -313,6 +325,7 @@ tie my %detail_formats, 'Tie::IxHash', noskip_dst_length_accountcode_tollfree skip_lastapp skip_max_callers + skip_same_customer use_duration 411_rewrite output_format @@ -414,6 +427,7 @@ sub calc_usage { 'disable_src' => $self->option('disable_src'), 'default_prefix' => $self->option('default_prefix'), 'cdrtypenum' => $self->option('use_cdrtypenum'), + 'calltypenum' => $self->option('use_calltypenum'), 'status' => '', 'for_update' => 1, ); # $last_bill, $$sdate ) @@ -481,6 +495,7 @@ sub calc_usage { } #returns a reason why not to rate this CDR, or false if the CDR is chargeable +# lots of false laziness w/voip_inbound sub check_chargable { my( $self, $cdr, %flags ) = @_; @@ -514,6 +529,15 @@ sub check_chargable { if length($self->option_cacheable('ignore_cdrtypenum')) && $cdr->cdrtypenum eq $self->option_cacheable('ignore_cdrtypenum'); #eq otherwise 0 matches '' + # unlike everything else, use_calltypenum is applied in FS::svc_x::get_cdrs. + return "calltypenum != ". $self->option_cacheable('use_calltypenum') + if length($self->option_cacheable('use_calltypenum')) + && $cdr->calltypenum ne $self->option_cacheable('use_calltypenum'); #ne otherwise 0 matches '' + + return "calltypenum == ". $self->option_cacheable('ignore_calltypenum') + if length($self->option_cacheable('ignore_calltypenum')) + && $cdr->calltypenum eq $self->option_cacheable('ignore_calltypenum'); #eq otherwise 0 matches '' + return "dcontext IN ( ". $self->option_cacheable('skip_dcontext'). " )" if $self->option_cacheable('skip_dcontext') =~ /\S/ && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $self->option_cacheable('skip_dcontext')); diff --git a/FS/FS/part_pkg/voip_inbound.pm b/FS/FS/part_pkg/voip_inbound.pm index 9054f7b99..525db804d 100644 --- a/FS/FS/part_pkg/voip_inbound.pm +++ b/FS/FS/part_pkg/voip_inbound.pm @@ -60,15 +60,21 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); 'type' => 'checkbox', }, - 'use_carrierid' => { 'name' => 'Only charge for CDRs where the Carrier ID is set to: ', + 'use_carrierid' => { 'name' => 'Only charge for CDRs where the Carrier ID is set to any of these (comma-separated) values: ', }, - 'use_cdrtypenum' => { 'name' => 'Only charge for CDRs where the CDR Type is set to: ', + 'use_cdrtypenum' => { 'name' => 'Only charge for CDRs where the CDR Type is set to this cdrtypenum: ', }, - 'ignore_cdrtypenum' => { 'name' => 'Do not charge for CDRs where the CDR Type is set to: ', + 'ignore_cdrtypenum' => { 'name' => 'Do not charge for CDRs where the CDR Type is set to this cdrtypenum: ', }, + 'use_calltypenum' => { 'name' => 'Only charge for CDRs where the CDR Call Type is set to this cdrtypenum: ', + }, + + 'ignore_calltypenum' => { 'name' => 'Do not charge for CDRs where the CDR Call Type is set to this cdrtypenum: ', + }, + 'ignore_disposition' => { 'name' => 'Do not charge for CDRs where the Disposition is set to any of these (comma-separated) values: ', }, @@ -147,6 +153,7 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); use_amaflags use_carrierid use_cdrtypenum ignore_cdrtypenum + use_calltypenum ignore_calltypenum ignore_disposition disposition_in skip_dcontext skip_dstchannel_prefix skip_dst_length_less skip_lastapp @@ -329,67 +336,58 @@ sub calc_usage { } #returns a reason why not to rate this CDR, or false if the CDR is chargeable +# lots of false laziness w/voip_cdr... sub check_chargable { my( $self, $cdr, %flags ) = @_; - #should have some better way of checking these options from a hash - #or something - - my @opt = qw( - use_amaflags - use_carrierid - use_cdrtypenum - ignore_cdrtypenum - disposition_in - ignore_disposition - skip_dcontext - skip_dstchannel_prefix - skip_dst_length_less - skip_lastapp - ); - foreach my $opt (grep !exists($flags{option_cache}->{$_}), @opt ) { - $flags{option_cache}->{$opt} = $self->option($opt, 1); - } - my %opt = %{ $flags{option_cache} }; - return 'amaflags != 2' - if $opt{'use_amaflags'} && $cdr->amaflags != 2; - - return "disposition NOT IN ( $opt{'disposition_in'} )" - if $opt{'disposition_in'} =~ /\S/ - && !grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $opt{'disposition_in'}); - - return "disposition IN ( $opt{'ignore_disposition'} )" - if $opt{'ignore_disposition'} =~ /\S/ - && grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $opt{'ignore_disposition'}); - - return "carrierid != $opt{'use_carrierid'}" - if length($opt{'use_carrierid'}) - && $cdr->carrierid ne $opt{'use_carrierid'}; #ne otherwise 0 matches '' + if $self->option_cacheable('use_amaflags') && $cdr->amaflags != 2; - return "cdrtypenum != $opt{'use_cdrtypenum'}" - if length($opt{'use_cdrtypenum'}) - && $cdr->cdrtypenum ne $opt{'use_cdrtypenum'}; #ne otherwise 0 matches '' - - return "cdrtypenum == $opt{'ignore_cdrtypenum'}" - if length($opt{'ignore_cdrtypenum'}) - && $cdr->cdrtypenum eq $opt{'ignore_cdrtypenum'}; #eq otherwise 0 matches '' + return "disposition NOT IN ( ". $self->option_cacheable('disposition_in')." )" + if $self->option_cacheable('disposition_in') =~ /\S/ + && !grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $self->option_cacheable('disposition_in')); + + return "disposition IN ( ". $self->option_cacheable('ignore_disposition')." )" + if $self->option_cacheable('ignore_disposition') =~ /\S/ + && grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $self->option_cacheable('ignore_disposition')); + + return "carrierid NOT IN ( ". $self->option_cacheable('use_carrierid'). " )" + if $self->option_cacheable('use_carrierid') =~ /\S/ + && !grep { $cdr->carrierid eq $_ } split(/\s*,\s*/, $self->option_cacheable('use_carrierid')); #eq otherwise 0 matches '' + + # unlike everything else, use_cdrtypenum is applied in FS::svc_x::get_cdrs. + return "cdrtypenum != ". $self->option_cacheable('use_cdrtypenum') + if length($self->option_cacheable('use_cdrtypenum')) + && $cdr->cdrtypenum ne $self->option_cacheable('use_cdrtypenum'); #ne otherwise 0 matches '' + + return "cdrtypenum == ". $self->option_cacheable('ignore_cdrtypenum') + if length($self->option_cacheable('ignore_cdrtypenum')) + && $cdr->cdrtypenum eq $self->option_cacheable('ignore_cdrtypenum'); #eq otherwise 0 matches '' + + # unlike everything else, use_calltypenum is applied in FS::svc_x::get_cdrs. + return "calltypenum != ". $self->option_cacheable('use_calltypenum') + if length($self->option_cacheable('use_calltypenum')) + && $cdr->calltypenum ne $self->option_cacheable('use_calltypenum'); #ne otherwise 0 matches '' + + return "calltypenum == ". $self->option_cacheable('ignore_calltypenum') + if length($self->option_cacheable('ignore_calltypenum')) + && $cdr->calltypenum eq $self->option_cacheable('ignore_calltypenum'); #eq otherwise 0 matches '' - return "dcontext IN ( $opt{'skip_dcontext'} )" - if $opt{'skip_dcontext'} =~ /\S/ - && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $opt{'skip_dcontext'}); + return "dcontext IN ( ". $self->option_cacheable('skip_dcontext'). " )" + if $self->option_cacheable('skip_dcontext') =~ /\S/ + && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $self->option_cacheable('skip_dcontext')); - my $len_prefix = length($opt{'skip_dstchannel_prefix'}); - return "dstchannel starts with $opt{'skip_dstchannel_prefix'}" + my $len_prefix = length($self->option_cacheable('skip_dstchannel_prefix')); + return "dstchannel starts with ". $self->option_cacheable('skip_dstchannel_prefix') if $len_prefix - && substr($cdr->dstchannel,0,$len_prefix) eq $opt{'skip_dstchannel_prefix'}; + && substr($cdr->dstchannel,0,$len_prefix) eq $self->option_cacheable('skip_dstchannel_prefix'); - my $dst_length = $opt{'skip_dst_length_less'}; + my $dst_length = $self->option_cacheable('skip_dst_length_less'); return "destination less than $dst_length digits" if $dst_length && length($cdr->dst) < $dst_length; - return "lastapp is $opt{'skip_lastapp'}" - if length($opt{'skip_lastapp'}) && $cdr->lastapp eq $opt{'skip_lastapp'}; + return "lastapp is ". $self->option_cacheable('skip_lastapp') + if length($self->option_cacheable('skip_lastapp')) && $cdr->lastapp eq $self->option_cacheable('skip_lastapp'); #all right then, rate it ''; diff --git a/FS/FS/part_pkg_msgcat.pm b/FS/FS/part_pkg_msgcat.pm new file mode 100644 index 000000000..7c00c26ac --- /dev/null +++ b/FS/FS/part_pkg_msgcat.pm @@ -0,0 +1,138 @@ +package FS::part_pkg_msgcat; + +use strict; +use base qw( FS::Record ); +use FS::Locales; +#use FS::Record qw( qsearch qsearchs ); +use FS::part_pkg; + +=head1 NAME + +FS::part_pkg_msgcat - Object methods for part_pkg_msgcat records + +=head1 SYNOPSIS + + use FS::part_pkg_msgcat; + + $record = new FS::part_pkg_msgcat \%hash; + $record = new FS::part_pkg_msgcat { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::part_pkg_msgcat object represents localized labels of a package +definition. FS::part_pkg_msgcat inherits from FS::Record. The following +fields are currently supported: + +=over 4 + +=item pkgpartmsgnum + +primary key + +=item pkgpart + +Package definition + +=item locale + +locale + +=item pkg + +Localized package name (customer-viewable) + +=item comment + +Localized package comment (non-customer-viewable), optional + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new record. To add the record to the database, see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I<hash> method. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'part_pkg_msgcat'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +# the insert method can be inherited from FS::Record + +=item delete + +Delete this record from the database. + +=cut + +# the delete method can be inherited from FS::Record + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +# the replace method can be inherited from FS::Record + +=item check + +Checks all fields to make sure this is a valid record. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('pkgpartmsgnum') + || $self->ut_foreign_key('pkgpart', 'part_pkg', 'pkgpart') + || $self->ut_enum('locale', [ FS::Locales->locales ] ) + || $self->ut_text('pkg') + || $self->ut_textn('comment') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/pay_batch/nacha.pm b/FS/FS/pay_batch/nacha.pm index d0758f4b6..c069082c7 100644 --- a/FS/FS/pay_batch/nacha.pm +++ b/FS/FS/pay_batch/nacha.pm @@ -47,7 +47,7 @@ $DEBUG = 0; my $origin = $1; my $company = $conf->config('company_name', $pay_batch->agentnum); - $company = substr($company. (' 'x23), 0, 23); + $company = substr(uc($company). (' 'x23), 0, 23); my $now = time; diff --git a/FS/FS/payinfo_transaction_Mixin.pm b/FS/FS/payinfo_transaction_Mixin.pm index 093891e93..50659ac1e 100644 --- a/FS/FS/payinfo_transaction_Mixin.pm +++ b/FS/FS/payinfo_transaction_Mixin.pm @@ -73,10 +73,7 @@ sub _parse_paybatch { my $payment_gateway = qsearchs('payment_gateway', { 'gatewaynum' => $gatewaynum } ); - die "payment gateway $gatewaynum not found" #? - unless $payment_gateway; - - $processor = $payment_gateway->gateway_module; + $processor = $payment_gateway->gateway_module if $payment_gateway; } diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index e36dbbd69..26d6e5b72 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1895,12 +1895,14 @@ sub email { $self->username. '@'. $self->domain(@_); } + =item acct_snarf Returns an array of FS::acct_snarf records associated with the account. =cut +# unused as originally intended, but now by Communigate Pro "RPOP" sub acct_snarf { my $self = shift; qsearch({ diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index 01495ca39..002aa55ce 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -103,10 +103,10 @@ sub table_info { 'ip_field' => 'ip_addr', 'fields' => { 'svcnum' => 'Service', - 'description' => 'Descriptive label for this particular device', - 'speed_down' => 'Maximum download speed for this service in Kbps. 0 denotes unlimited.', - 'speed_up' => 'Maximum upload speed for this service in Kbps. 0 denotes unlimited.', - 'ip_addr' => 'IP address. Leave blank for automatic assignment.', + 'description' => 'Descriptive label', + 'speed_down' => 'Download speed (Kbps)', + 'speed_up' => 'Upload speed (Kbps)', + 'ip_addr' => 'IP address', 'blocknum' => { 'label' => 'Address block', 'type' => 'select', @@ -134,6 +134,15 @@ sub table_info { disable_inventory => 1, multiple => 1, }, + 'radio_serialnum' => 'Radio Serial Number', + 'radio_location' => 'Radio Location', + 'poe_location' => 'POE Location', + 'rssi' => 'RSSI', + 'suid' => 'SUID', + 'shared_svcnum' => { label => 'Shared Service', + type => 'search-svc_broadband', + disable_inventory => 1, + }, }, }; } @@ -225,15 +234,31 @@ sub search_sql { my( $class, $string ) = @_; if ( $string =~ /^(\d{1,3}\.){3}\d{1,3}$/ ) { $class->search_sql_field('ip_addr', $string ); - }elsif ( $string =~ /^([a-fA-F0-9]{12})$/ ) { + } elsif ( $string =~ /^([a-fA-F0-9]{12})$/ ) { $class->search_sql_field('mac_addr', uc($string)); - }elsif ( $string =~ /^(([a-fA-F0-9]{1,2}:){5}([a-fA-F0-9]{1,2}))$/ ) { + } elsif ( $string =~ /^(([a-fA-F0-9]{1,2}:){5}([a-fA-F0-9]{1,2}))$/ ) { $class->search_sql_field('mac_addr', uc("$2$3$4$5$6$7") ); + } elsif ( $string =~ /^(\d+)$/ ) { + my $table = $class->table; + "$table.svcnum = $1"; } else { '1 = 0'; #false } } +=item smart_search STRING + +=cut + +sub smart_search { + my( $class, $string ) = @_; + qsearch({ + 'table' => $class->table, #'svc_broadband', + 'hashref' => {}, + 'extra_sql' => 'WHERE '. $class->search_sql($string), + }); +} + =item label Returns the IP address. @@ -330,6 +355,12 @@ sub check { || $self->ut_sfloatn('altitude') || $self->ut_textn('vlan_profile') || $self->ut_textn('plan_id') + || $self->ut_alphan('radio_serialnum') + || $self->ut_textn('radio_location') + || $self->ut_textn('poe_location') + || $self->ut_snumbern('rssi') + || $self->ut_numbern('suid') + || $self->ut_foreign_keyn('shared_svcnum', 'svc_broadband', 'svcnum') ; return $error if $error; diff --git a/FS/FS/svc_export_machine.pm b/FS/FS/svc_export_machine.pm index 10f7b6821..7ca20ccb6 100644 --- a/FS/FS/svc_export_machine.pm +++ b/FS/FS/svc_export_machine.pm @@ -40,6 +40,10 @@ fields are currently supported: primary key +=item exportnum + +Export definition, see L<FS::part_export> + =item svcnum Customer service, see L<FS::cust_svc> diff --git a/FS/FS/svc_hardware.pm b/FS/FS/svc_hardware.pm index 96502e41e..b28cc9ef5 100644 --- a/FS/FS/svc_hardware.pm +++ b/FS/FS/svc_hardware.pm @@ -105,9 +105,13 @@ sub search_sql { my ($class, $string) = @_; my @where = (); - my $ip = NetAddr::IP->new($string); - if ( $ip ) { - push @where, $class->search_sql_field('ip_addr', $ip->addr); + if ( $string =~ /^[\d\.:]+$/ ) { + # if the string isn't an IP address, this will waste several seconds + # attempting a DNS lookup. so try to filter those out. + my $ip = NetAddr::IP->new($string); + if ( $ip ) { + push @where, $class->search_sql_field('ip_addr', $ip->addr); + } } if ( $string =~ /^(\w+)$/ ) { diff --git a/FS/FS/svc_pbx.pm b/FS/FS/svc_pbx.pm index 4182a1315..66e51da71 100644 --- a/FS/FS/svc_pbx.pm +++ b/FS/FS/svc_pbx.pm @@ -292,7 +292,9 @@ to allow title to indicate a range of IP addresses. =item begin, end: Start and end of date range, as unix timestamp. -=item cdrtypenum: Only return CDRs with this type number. +=item cdrtypenum: Only return CDRs with this type. + +=item calltypenum: Only return CDRs with this call type. =back @@ -310,6 +312,9 @@ sub psearch_cdrs { if ($options{'cdrtypenum'}) { $hash{'cdrtypenum'} = $options{'cdrtypenum'}; } + if ($options{'calltypenum'}) { + $hash{'calltypenum'} = $options{'calltypenum'}; + } my $for_update = $options{'for_update'} ? 'FOR UPDATE' : ''; diff --git a/FS/FS/svc_phone.pm b/FS/FS/svc_phone.pm index f28002cc4..3cc1adc66 100644 --- a/FS/FS/svc_phone.pm +++ b/FS/FS/svc_phone.pm @@ -684,7 +684,9 @@ with the chosen prefix. =item begin, end: Start and end of a date range, as unix timestamp. -=item cdrtypenum: Only return CDRs with this type number. +=item cdrtypenum: Only return CDRs with this type. + +=item calltypenum: Only return CDRs with this call type. =item disable_src => 1: Only match on "charged_party", not "src". @@ -735,6 +737,9 @@ sub psearch_cdrs { if ($options{'cdrtypenum'}) { $hash{'cdrtypenum'} = $options{'cdrtypenum'}; } + if ($options{'calltypenum'}) { + $hash{'calltypenum'} = $options{'calltypenum'}; + } my $for_update = $options{'for_update'} ? 'FOR UPDATE' : ''; diff --git a/FS/MANIFEST b/FS/MANIFEST index 95b11f8e5..94232905e 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -490,6 +490,8 @@ FS/phone_type.pm t/phone_type.t FS/contact_email.pm t/contact_email.t +FS/contact_Mixin.pm +t/contact_Mixin.t FS/prospect_main.pm t/prospect_main.t FS/o2m_Common.pm @@ -686,3 +688,5 @@ FS/part_pkg_usage.pm t/part_pkg_usage.t FS/cdr_cust_pkg_usage.pm t/cdr_cust_pkg_usage.t +FS/part_pkg_msgcat.pm +t/part_pkg_msgcat.t diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued index 2fd80255e..dcc6ac4ba 100644 --- a/FS/bin/freeside-queued +++ b/FS/bin/freeside-queued @@ -212,8 +212,10 @@ while (1) { # don't put @args in the log, may expose passwords $log->info('starting job ('.$ljob->job.')'); warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG; + local $FS::UID::AutoCommit = 0; # so that we can clean up failures eval $eval; #throw away return value? suppose so if ( $@ ) { + dbh->rollback; my %hash = $ljob->hash; $hash{'statustext'} = $@; if ( $hash{'statustext'} =~ /\/misc\/queued_report/ ) { #use return? @@ -225,8 +227,10 @@ while (1) { my $fjob = new FS::queue( \%hash ); my $error = $fjob->replace($ljob); die $error if $error; + dbh->commit; # for the status change only } else { $ljob->delete; + dbh->commit; # for the job itself } if ( UNIVERSAL::can(dbh, 'sprintProfile') ) { diff --git a/FS/bin/freeside-upgrade b/FS/bin/freeside-upgrade index b08a8401f..3d1c2e072 100755 --- a/FS/bin/freeside-upgrade +++ b/FS/bin/freeside-upgrade @@ -123,6 +123,8 @@ my $cf; while ( $cf = $cfsth->fetchrow_hashref ) { my $tbl = $cf->{'dbtable'}; my $name = $cf->{'name'}; + $name = lc($name) unless driver_name =~ /^mysql/i; + @statements = grep { $_ !~ /^\s*ALTER\s+TABLE\s+(h_|)$tbl\s+DROP\s+COLUMN\s+cf_$name\s*$/i } @statements; push @statements, diff --git a/FS/t/contact_Mixin.t b/FS/t/contact_Mixin.t new file mode 100644 index 000000000..89dcc37c5 --- /dev/null +++ b/FS/t/contact_Mixin.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::contact_Mixin; +$loaded=1; +print "ok 1\n"; diff --git a/FS/t/part_pkg_msgcat.t b/FS/t/part_pkg_msgcat.t new file mode 100644 index 000000000..541c16799 --- /dev/null +++ b/FS/t/part_pkg_msgcat.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::part_pkg_msgcat; +$loaded=1; +print "ok 1\n"; |