summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorivan <ivan>2006-05-14 16:47:31 +0000
committerivan <ivan>2006-05-14 16:47:31 +0000
commit2c757d7db4cb6a7b9655de13206fcc84fb7ce61f (patch)
treef01088bb60d49ee0dd3dd796d57abe219c321f7b /FS
parentc46235292c6bf929615ac28fc48c1d5609ce4590 (diff)
first part of ACL and re-skinning work and some other small stuff
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/AccessRight.pm77
-rw-r--r--FS/FS/CGI.pm5
-rw-r--r--FS/FS/Schema.pm87
-rw-r--r--FS/FS/UI/Web.pm14
-rw-r--r--FS/FS/access_group.pm121
-rw-r--r--FS/FS/access_groupagent.pm124
-rw-r--r--FS/FS/access_right.pm127
-rw-r--r--FS/FS/access_user.pm167
-rw-r--r--FS/FS/access_user_pref.pm127
-rw-r--r--FS/FS/access_usergroup.pm144
-rw-r--r--FS/FS/agent_type.pm3
-rw-r--r--FS/FS/cust_bill.pm5
-rw-r--r--FS/FS/m2m_Common.pm110
-rw-r--r--FS/FS/part_pkg/billoneday.pm48
-rw-r--r--FS/FS/payby.pm3
-rw-r--r--FS/FS/svc_domain.pm6
-rw-r--r--FS/MANIFEST1
-rw-r--r--FS/bin/freeside-addoutsourceuser4
-rw-r--r--FS/t/AccessRight.t5
-rw-r--r--FS/t/access_group.t5
-rw-r--r--FS/t/access_groupagent.t5
-rw-r--r--FS/t/access_right.t5
-rw-r--r--FS/t/access_user.t5
-rw-r--r--FS/t/access_user_pref.t5
-rw-r--r--FS/t/access_usergroup.t5
25 files changed, 1150 insertions, 58 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm
new file mode 100644
index 000000000..01d63e35d
--- /dev/null
+++ b/FS/FS/AccessRight.pm
@@ -0,0 +1,77 @@
+package FS::AccessRight;
+
+use strict;
+user vars qw(@rights %rights);
+use Tie::IxHash;
+
+=head1 NAME
+
+FS::AccessRight - Access control rights.
+
+=head1 SYNOPSIS
+
+ use FS::AccessRight;
+
+=head1 DESCRIPTION
+
+Access control rights - Permission to perform specific actions that can be
+assigned to users and/or groups.
+
+=cut
+
+@rights = (
+ 'Reports' => [
+ '_desc' => 'Access to high-level reporting',
+ ],
+ 'Configuration' => [
+ '_desc' => 'Access to configuration',
+
+ 'Settings' => {},
+
+ 'agent' => [
+ '_desc' => 'Master access to reseller configuration',
+ 'agent_type' => {},
+ 'agent' => {},
+ ],
+
+ 'export_svc_pkg' => [
+ '_desc' => 'Access to export, service and package configuration',
+ 'part_export' => {},
+ 'part_svc' => {},
+ 'part_pkg' => {},
+ 'pkg_class' => {},
+ ],
+
+ 'billing' => [
+ '_desc' => 'Access to billing configuration',
+ 'payment_gateway' => {},
+ 'part_bill_event' => {},
+ 'prepay_credit' => {},
+ 'rate' => {},
+ 'cust_main_county' => {},
+ ],
+
+ 'dialup' => [
+ '_desc' => 'Access to dialup configuraiton',
+ 'svc_acct_pop' => {},
+ ],
+
+ 'broadband' => [
+ '_desc' => 'Access to broadband configuration',
+ 'router' => {},
+ 'addr_block' => {},
+ ],
+
+ 'misc' => [
+ 'part_referral' => {},
+ 'part_virtual_field' => {},
+ 'msgcat' => {},
+ 'inventory_class' => {},
+ ],
+
+ },
+
+);
+
+#turn it into a more hash-like structure, but ordered via IxHash
+
diff --git a/FS/FS/CGI.pm b/FS/FS/CGI.pm
index f1f2a3dca..d598f5218 100644
--- a/FS/FS/CGI.pm
+++ b/FS/FS/CGI.pm
@@ -62,9 +62,9 @@ sub header {
</HEAD>
<BODY BGCOLOR="#e8e8e8"$etc>
<FONT SIZE=6>
- $title
+ <CENTER>$title</CENTER>
</FONT>
- <BR><BR>
+ <BR><!--<BR>-->
END
$x .= $menubar. "<BR><BR>" if $menubar;
$x;
@@ -115,6 +115,7 @@ sub menubar { #$menubar=menubar('Main Menu', '../', 'Item', 'url', ... );
my($item,$url,@html);
while (@_) {
($item,$url)=splice(@_,0,2);
+ next if $item =~ /^\s*Main\s+Menu\s*$/i;
push @html, qq!<A HREF="$url">$item</A>!;
}
join(' | ',@html);
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 9125758d0..e81185666 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -244,6 +244,8 @@ sub tables_hashref {
my $username_len = 32; #usernamemax config file
+ # name type nullability length default local
+
return {
'agent' => {
@@ -445,6 +447,9 @@ sub tables_hashref {
'index' => [ ['last'], [ 'company' ], [ 'referral_custnum' ],
[ 'daytime' ], [ 'night' ], [ 'fax' ], [ 'refnum' ],
[ 'county' ], [ 'state' ], [ 'country' ], [ 'zip' ],
+ [ 'ship_last' ], [ 'ship_company' ],
+ [ 'payby' ], [ 'paydate' ],
+
],
},
@@ -1444,16 +1449,94 @@ sub tables_hashref {
'inventory_class' => {
'columns' => [
- 'classnum', 'serial', '', '', '', '',
- 'classname', 'varchar', $char_d, '', '', '',
+ 'classnum', 'serial', '', '', '', '',
+ 'classname', 'varchar', '', $char_d, '', '',
],
'primary_key' => 'classnum',
'unique' => [],
'index' => [],
},
+ 'access_user' => {
+ 'columns' => [
+ 'usernum', 'serial', '', '', '', '',
+ 'username', 'varchar', '', $char_d, '', '',
+ '_password', 'varchar', '', $char_d, '', '',
+ 'last', 'varchar', '', $char_d, '', '',
+ 'first', 'varchar', '', $char_d, '', '',
+ ],
+ 'primary_key' => 'usernum',
+ 'unique' => [ [ 'username' ] ],
+ 'index' => [],
+ },
+
+ 'access_user_pref' => {
+ 'columns' => [
+ 'prefnum', 'serial', '', '', '', '',
+ 'usernum', 'int', '', '', '', '',
+ 'prefname', 'varchar', '', $char_d, '', '',
+ 'prefvalue', 'text', 'NULL', '', '', '',
+ ],
+ 'primary_key' => 'prefnum',
+ 'unique' => [],
+ 'index' => [ [ 'usernum' ] ],
+ },
+
+ 'access_group' => {
+ 'columns' => [
+ 'groupnum', 'serial', '', '', '', '',
+ 'groupname', 'varchar', '', $char_d, '', '',
+ ],
+ 'primary_key' => 'groupnum',
+ 'unique' => [ [ 'groupname' ] ],
+ 'index' => [],
+ },
+
+ 'access_usergroup' => {
+ 'columns' => [
+ 'usergroupnum', 'serial', '', '', '', '',
+ 'usernum', 'int', '', '', '', '',
+ 'groupnum', 'int', '', '', '', '',
+ ],
+ 'primary_key' => 'usergroupnum',
+ 'unique' => [ [ 'usernum', 'groupnum' ] ],
+ 'index' => [ [ 'usernum' ] ],
+ },
+
+ 'access_groupagent' => {
+ 'columns' => [
+ 'groupagentnum', 'serial', '', '', '', '',
+ 'groupnum', 'int', '', '', '', '',
+ 'agentnum', 'int', '', '', '', '',
+ ],
+ 'primary_key' => 'groupagentnum',
+ 'unique' => [ [ 'groupnum', 'agentnum' ] ],
+ 'index' => [ [ 'groupnum' ] ],
+ },
+
+ 'access_right' => {
+ 'columns' => [
+ 'rightnum', 'serial', '', '', '', '',
+ 'righttype', 'varchar', '', $char_d, '', '',
+ 'rightobjnum', 'int', '', '', '', '',
+ 'rightname', 'varchar', '', '', '', '',
+ ],
+ 'primary_key' => 'rightnum',
+ 'unique' => [ [ 'righttype', 'rightobjnum', 'rightname' ] ],
+ 'index' => [],
+ },
+
};
+ #'new_table' => {
+ # 'columns' => [
+ # 'num', 'serial', '', '', '', '',
+ # ],
+ # 'primary_key' => 'num',
+ # 'unique' => [],
+ # 'index' => [],
+ #},
+
}
=back
diff --git a/FS/FS/UI/Web.pm b/FS/FS/UI/Web.pm
index dc45e0188..10ddbf33f 100644
--- a/FS/FS/UI/Web.pm
+++ b/FS/FS/UI/Web.pm
@@ -184,6 +184,10 @@ sub process {
$self->job_status(@args);
+ } else {
+
+ die "unknown sub $sub";
+
}
}
@@ -228,11 +232,19 @@ sub start_job {
my $error = $job->insert( '_JOB', encode_base64(nfreeze(\%param)) );
if ( $error ) {
+
+ warn "job not inserted: $error\n"
+ if $DEBUG;
+
$error; #this doesn't seem to be handled well,
# will trigger "illegal jobnum" below?
# (should never be an error inserting the job, though, only thing
# would be Pg f%*kage)
} else {
+
+ warn "job inserted successfully with jobnum ". $job->jobnum. "\n"
+ if $DEBUG;
+
$job->jobnum;
}
@@ -253,7 +265,7 @@ sub job_status {
my @return;
if ( $job && $job->status ne 'failed' ) {
@return = ( 'progress', $job->statustext );
- } elsif ( !$job ) { #handle job gone case : job sucessful
+ } elsif ( !$job ) { #handle job gone case : job successful
# so close popup, redirect parent window...
@return = ( 'complete' );
} else {
diff --git a/FS/FS/access_group.pm b/FS/FS/access_group.pm
new file mode 100644
index 000000000..9d870e57f
--- /dev/null
+++ b/FS/FS/access_group.pm
@@ -0,0 +1,121 @@
+package FS::access_group;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::access_group - Object methods for access_group records
+
+=head1 SYNOPSIS
+
+ use FS::access_group;
+
+ $record = new FS::access_group \%hash;
+ $record = new FS::access_group { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_group object represents an example. FS::access_group inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item groupnum - primary key
+
+=item groupname -
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example 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 { 'access_group'; }
+
+=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 example. 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('groupnum')
+ || $self->ut_text('groupname')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/access_groupagent.pm b/FS/FS/access_groupagent.pm
new file mode 100644
index 000000000..6b5def1a3
--- /dev/null
+++ b/FS/FS/access_groupagent.pm
@@ -0,0 +1,124 @@
+package FS::access_groupagent;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::access_groupagent - Object methods for access_groupagent records
+
+=head1 SYNOPSIS
+
+ use FS::access_groupagent;
+
+ $record = new FS::access_groupagent \%hash;
+ $record = new FS::access_groupagent { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_groupagent object represents an example. FS::access_groupagent inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item groupagentnum - primary key
+
+=item groupnum -
+
+=item agentnum -
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example 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 { 'access_groupagent'; }
+
+=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 example. 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('groupagentnum')
+ || $self->ut_number('groupnum')
+ || $self->ut_number('agentnum')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm
new file mode 100644
index 000000000..67200f245
--- /dev/null
+++ b/FS/FS/access_right.pm
@@ -0,0 +1,127 @@
+package FS::access_right;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::access_right - Object methods for access_right records
+
+=head1 SYNOPSIS
+
+ use FS::access_right;
+
+ $record = new FS::access_right \%hash;
+ $record = new FS::access_right { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_right object represents an example. FS::access_right inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item rightnum - primary key
+
+=item righttype -
+
+=item rightobjnum -
+
+=item rightname -
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example 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 { 'access_right'; }
+
+=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 example. 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('rightnum')
+ || $self->ut_text('righttype')
+ || $self->ut_text('rightobjnum')
+ || $self->ut_text('rightname')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/access_user.pm b/FS/FS/access_user.pm
new file mode 100644
index 000000000..ca311d3b8
--- /dev/null
+++ b/FS/FS/access_user.pm
@@ -0,0 +1,167 @@
+package FS::access_user;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::m2m_Common;
+use FS::access_usergroup;
+
+@ISA = qw( FS::m2m_Common FS::Record );
+
+=head1 NAME
+
+FS::access_user - Object methods for access_user records
+
+=head1 SYNOPSIS
+
+ use FS::access_user;
+
+ $record = new FS::access_user \%hash;
+ $record = new FS::access_user { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_user object represents an example. FS::access_user inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item usernum - primary key
+
+=item username -
+
+=item _password -
+
+=item last -
+
+=item first -
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example 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 { 'access_user'; }
+
+=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 example. 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('usernum')
+ || $self->ut_text('username')
+ || $self->ut_text('_password')
+ || $self->ut_text('last')
+ || $self->ut_text('first')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=item name
+
+Returns a name string for this user: "Last, First".
+
+=cut
+
+sub name {
+ my $self = shift;
+ $self->get('last'). ', '. $self->first;
+}
+
+=item access_usergroup
+
+=cut
+
+sub access_usergroup {
+ my $self = shift;
+ qsearch( 'access_usergroup', { 'usernum' => $self->usernum } );
+}
+
+#=item access_groups
+#
+#=cut
+#
+#sub access_groups {
+#
+#}
+#
+#=item access_groupnames
+#
+#=cut
+#
+#sub access_groupnames {
+#
+#}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/access_user_pref.pm b/FS/FS/access_user_pref.pm
new file mode 100644
index 000000000..ff957f2a1
--- /dev/null
+++ b/FS/FS/access_user_pref.pm
@@ -0,0 +1,127 @@
+package FS::access_user_pref;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::access_user_pref - Object methods for access_user_pref records
+
+=head1 SYNOPSIS
+
+ use FS::access_user_pref;
+
+ $record = new FS::access_user_pref \%hash;
+ $record = new FS::access_user_pref { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_user_pref object represents an example. FS::access_user_pref inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item prefnum - primary key
+
+=item usernum -
+
+=item prefname -
+
+=item prefvalue -
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example 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 { 'access_user_pref'; }
+
+=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 example. 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('prefnum')
+ || $self->ut_number('usernum')
+ || $self->ut_text('prefname')
+ || $self->ut_textn('prefvalue')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/access_usergroup.pm b/FS/FS/access_usergroup.pm
new file mode 100644
index 000000000..4d8836c15
--- /dev/null
+++ b/FS/FS/access_usergroup.pm
@@ -0,0 +1,144 @@
+package FS::access_usergroup;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::access_user;
+use FS::access_group;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::access_usergroup - Object methods for access_usergroup records
+
+=head1 SYNOPSIS
+
+ use FS::access_usergroup;
+
+ $record = new FS::access_usergroup \%hash;
+ $record = new FS::access_usergroup { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::access_usergroup object represents an example. FS::access_usergroup inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item usergroupnum - primary key
+
+=item usernum -
+
+=item groupnum -
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example 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 { 'access_usergroup'; }
+
+=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 example. 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('usergroupnum')
+ || $self->ut_number('usernum')
+ || $self->ut_number('groupnum')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=item access_user
+
+=cut
+
+sub access_user {
+ my $self = shift;
+ qsearchs( 'access_user', { 'usernum' => $self->usernum } );
+}
+
+=item access_group
+
+=cut
+
+sub access_group {
+ my $self = shift;
+ qsearchs( 'access_group', { 'groupnum' => $self->groupnum } );
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/agent_type.pm b/FS/FS/agent_type.pm
index 968b3b72e..b28c57285 100644
--- a/FS/FS/agent_type.pm
+++ b/FS/FS/agent_type.pm
@@ -3,10 +3,11 @@ package FS::agent_type;
use strict;
use vars qw( @ISA );
use FS::Record qw( qsearch );
+use FS::m2m_Common;
use FS::agent;
use FS::type_pkgs;
-@ISA = qw( FS::Record );
+@ISA = qw( FS::m2m_Common FS::Record );
=head1 NAME
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index cce028b2c..bcae4d646 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -2463,6 +2463,7 @@ use Data::Dumper;
use MIME::Base64;
sub process_re_X {
my( $method, $job ) = ( shift, shift );
+ warn "process_re_X $method for job $job\n" if $DEBUG;
my $param = thaw(decode_base64(shift));
warn Dumper($param) if $DEBUG;
@@ -2478,6 +2479,10 @@ sub process_re_X {
sub re_X {
my($method, $job, %param ) = @_;
# [ 'begin', 'end', 'agentnum', 'open', 'days', 'newest_percust' ],
+ if ( $DEBUG ) {
+ warn "re_X $method for job $job with param:\n".
+ join( '', map { " $_ => ". $param{$_}. "\n" } keys %param );
+ }
#some false laziness w/search/cust_bill.html
my $distinct = '';
diff --git a/FS/FS/m2m_Common.pm b/FS/FS/m2m_Common.pm
new file mode 100644
index 000000000..fd8700a2d
--- /dev/null
+++ b/FS/FS/m2m_Common.pm
@@ -0,0 +1,110 @@
+package FS::m2m_Common;
+
+use strict;
+use vars qw( @ISA $DEBUG );
+use FS::Schema qw( dbdef );
+use FS::Record qw( qsearch qsearchs ); #dbh );
+
+@ISA = qw( FS::Record );
+
+$DEBUG = 0;
+
+=head1 NAME
+
+FS::m2m_Common - Base class for classes in a many-to-many relationship
+
+=head1 SYNOPSIS
+
+use FS::m2m_Common;
+
+@ISA = qw( FS::m2m_Common );
+
+=head1 DESCRIPTION
+
+FS::m2m_Common is intended as a base class for classes which have a
+many-to-many relationship with another table (via a linking table).
+
+Note: It is currently assumed that the link table contains two fields
+named the same as the primary keys of ths base and target tables.
+
+=head1 METHODS
+
+=over 4
+
+=item process_m2m
+
+=cut
+
+sub process_m2m {
+ my( $self, %opt ) = @_;
+
+ my $self_pkey = $self->dbdef_table->primary_key;
+
+ my $link_table = $self->_load_table($opt{'link_table'});
+
+ my $target_table = $self->_load_table($opt{'target_table'});
+ my $target_pkey = dbdef->table($target_table)->primary_key;
+
+ foreach my $target_obj ( qsearch($target_table, {} ) ) {
+
+ my $targetnum = $target_obj->$target_pkey();
+
+ my $link_obj = qsearchs( $link_table, {
+ $self_pkey => $self->$self_pkey(),
+ $target_pkey => $targetnum,
+ });
+
+ if ( $link_obj && ! $opt{'params'}->{"$target_pkey$targetnum"} ) {
+
+ my $d_link_obj = $link_obj; #need to save $link_obj for below.
+ my $error = $d_link_obj->delete;
+ die $error if $error;
+
+ } elsif ( $opt{'params'}->{"$target_pkey$targetnum"} && ! $link_obj ) {
+
+ #ok to clobber it now (but bad form nonetheless?)
+ #$link_obj = new "FS::$link_table" ( {
+ $link_obj = "FS::$link_table"->new( {
+ $self_pkey => $self->$self_pkey(),
+ $target_pkey => $targetnum,
+ });
+ my $error = $link_obj->insert;
+ die $error if $error;
+ }
+
+ }
+
+ '';
+}
+
+sub _load_table {
+ my( $self, $table ) = @_;
+ eval "use FS::$table";
+ die $@ if $@;
+ $table;
+}
+
+#=item target_table
+#
+#=cut
+#
+#sub target_table {
+# my $self = shift;
+# my $target_table = $self->_target_table;
+# eval "use FS::$target_table";
+# die $@ if $@;
+# $target_table;
+#}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_pkg/billoneday.pm b/FS/FS/part_pkg/billoneday.pm
deleted file mode 100644
index 8740547a3..000000000
--- a/FS/FS/part_pkg/billoneday.pm
+++ /dev/null
@@ -1,48 +0,0 @@
-package FS::part_pkg::billoneday;
-
-use strict;
-use vars qw(@ISA %info);
-use Time::Local qw(timelocal);
-#use FS::Record qw(qsearch qsearchs);
-use FS::part_pkg::flat;
-
-@ISA = qw(FS::part_pkg::flat);
-
-%info = (
- 'name' => 'charge a full month every (selectable) billing day',
- 'fields' => {
- 'setup_fee' => { 'name' => 'Setup fee for this package',
- 'default' => 0,
- },
- 'recur_fee' => { 'name' => 'Recurring fee for this package',
- 'default' => 0,
- },
- 'cutoff_day' => { 'name' => 'billing day',
- 'default' => 1,
- },
-
- },
- 'fieldorder' => [ 'setup_fee', 'recur_fee','cutoff_day'],
- #'setup' => 'what.setup_fee.value',
- #'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; $sdate = timelocal(0,0,0,$self->option('cutoff_day'),$mon,$year); \' + what.recur_fee.value',
- 'freq' => 'm',
- 'weight' => 30,
-);
-
-sub calc_recur {
- my($self, $cust_pkg, $sdate ) = @_;
-
- my $mnow = $$sdate;
- my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($mnow) )[0,1,2,3,4,5];
- my $mstart = timelocal(0,0,0,$self->option('cutoff_day'),$mon,$year);
- my $mend = timelocal(0,0,0,$self->option('cutoff_day'), $mon == 11 ? 0 : $mon+1, $year+($mon==11));
-
- if($mday > $self->option('cutoff_date') and $mstart != $mnow ) {
- $$sdate = timelocal(0,0,0,$self->option('cutoff_day'), $mon == 11 ? 0 : $mon+1, $year+($mon==11));
- }
- else{
- $$sdate = timelocal(0,0,0,$self->option('cutoff_day'), $mon, $year);
- }
- $self->option('recur_fee');
-}
-1;
diff --git a/FS/FS/payby.pm b/FS/FS/payby.pm
index 4425df040..9f8b68918 100644
--- a/FS/FS/payby.pm
+++ b/FS/FS/payby.pm
@@ -115,7 +115,8 @@ sub cust_payby2longname {
=head1 BUGS
-This should eventually be an actual database table.
+This should eventually be an actual database table, and all tables that
+currently have a char payby field should have a foreign key into here instead.
=head1 SEE ALSO
diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm
index 191d85604..bdaf79b2f 100644
--- a/FS/FS/svc_domain.pm
+++ b/FS/FS/svc_domain.pm
@@ -230,7 +230,11 @@ sub delete {
my $error = $domain_record->delete;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
- return $error;
+ return "can't delete DNS entry: ".
+ join(' ', map $domain_record->$_(),
+ qw( reczone recaf rectype recdata )
+ ).
+ ":$error";
}
}
diff --git a/FS/MANIFEST b/FS/MANIFEST
index c309251ff..bd810a8db 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -339,3 +339,4 @@ FS/access_groupagent.pm
t/access_groupagent.t
FS/access_right.pm
t/access_right.t
+FS/m2m_Common.pm
diff --git a/FS/bin/freeside-addoutsourceuser b/FS/bin/freeside-addoutsourceuser
index cad07f1fd..02a435141 100644
--- a/FS/bin/freeside-addoutsourceuser
+++ b/FS/bin/freeside-addoutsourceuser
@@ -3,6 +3,7 @@
username=$1
domain=$2
password=$3
+realdomain=$4
freeside-adduser -h /usr/local/etc/freeside/htpasswd \
-s conf.DBI:Pg:dbname=$domain/secrets \
@@ -10,6 +11,5 @@ freeside-adduser -h /usr/local/etc/freeside/htpasswd \
$username $password 2>/dev/null
[ -e /usr/local/etc/freeside/dbdef.DBI:Pg:dbname=$domain ] \
- || ( freeside-setup -s $username 2>/dev/null; \
- /home/ivan/freeside/bin/populate-msgcat $username 2>/dev/null )
+ || ( freeside-setup -d $realdomain $username 2>/dev/null )
diff --git a/FS/t/AccessRight.t b/FS/t/AccessRight.t
new file mode 100644
index 000000000..a96684224
--- /dev/null
+++ b/FS/t/AccessRight.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::AccessRight;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/access_group.t b/FS/t/access_group.t
new file mode 100644
index 000000000..be141099b
--- /dev/null
+++ b/FS/t/access_group.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_group;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/access_groupagent.t b/FS/t/access_groupagent.t
new file mode 100644
index 000000000..aff1f2524
--- /dev/null
+++ b/FS/t/access_groupagent.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_groupagent;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/access_right.t b/FS/t/access_right.t
new file mode 100644
index 000000000..66cd362e8
--- /dev/null
+++ b/FS/t/access_right.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_right;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/access_user.t b/FS/t/access_user.t
new file mode 100644
index 000000000..cab679d8d
--- /dev/null
+++ b/FS/t/access_user.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_user;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/access_user_pref.t b/FS/t/access_user_pref.t
new file mode 100644
index 000000000..282209830
--- /dev/null
+++ b/FS/t/access_user_pref.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_user_pref;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/access_usergroup.t b/FS/t/access_usergroup.t
new file mode 100644
index 000000000..383a7cf9c
--- /dev/null
+++ b/FS/t/access_usergroup.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::access_usergroup;
+$loaded=1;
+print "ok 1\n";