diff options
author | Mitch Jackson <mitch@freeside.biz> | 2018-01-11 20:05:34 -0600 |
---|---|---|
committer | Mitch Jackson <mitch@freeside.biz> | 2018-01-11 20:05:34 -0600 |
commit | 69e481a4a9191b9912d6bb8202627a5dc75f74ce (patch) | |
tree | 85604b29a5ce712824472778f488e69d0b0be1c5 /FS | |
parent | 77daf007ef522ae71041d9b094643cf868d8ecce (diff) |
rt# 74031 implement svc_realestate
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/Mason.pm | 3 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 90 | ||||
-rw-r--r-- | FS/FS/h_svc_realestate.pm | 31 | ||||
-rw-r--r-- | FS/FS/realestate_location.pm | 177 | ||||
-rw-r--r-- | FS/FS/realestate_unit.pm | 163 | ||||
-rw-r--r-- | FS/FS/svc_Common.pm | 10 | ||||
-rw-r--r-- | FS/FS/svc_realestate.pm | 172 | ||||
-rw-r--r-- | FS/t/realestate_location.t | 5 | ||||
-rw-r--r-- | FS/t/realestate_unit.t | 5 | ||||
-rw-r--r-- | FS/t/svc_realestate.t | 5 |
10 files changed, 658 insertions, 3 deletions
diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 7bdb6059e..7f883dec1 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -418,6 +418,9 @@ if ( -e $addl_handler_use_file ) { use FS::part_svc_msgcat; use FS::commission_schedule; use FS::commission_rate; + use FS::realestate_location; + use FS::realestate_unit; + use FS::svc_realestate; use FS::saved_search; use FS::sector_coverage; # Sammath Naur diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 6d7520bd9..f7ac973be 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -495,8 +495,44 @@ sub tables_hashref { my $username_len = 64; #usernamemax config file - # name type nullability length default local + # Return a hashref defining the entire application database schema + # Each key of the hashref contains a structure describing a database table + # + # table_name => { + # columns => [...], + # primary_key => 'column', + # unique => [column,column,...], + # index => [[column],[column,column],...], + # foreign_keys => [{...},{...},...], + # } + # + # + # columns => [ + # + # 'column_name', + # + # 'column_type', + # + # 'NULL' or '', # 'NULL' : Allow null values + # # '' : Disallow null values + # + # 'length', # Column size value. eg: + # # 40 : VARCHAR(40) + # # '10,2' : FLOAT(10,2) + # + # 'default', # Default column value for a new record + # # (Unclear if setting this to '' results in a default + # # value of NULL or empty string?) + # + # '', # local ? + # + # name, type, nullability, length, default, local, + # name, type, nullability, length, default, local, + # ... + # + # ], + # name type nullability length default local return { 'agent' => { @@ -7601,6 +7637,57 @@ sub tables_hashref { 'foreign_keys' => [], }, + 'realestate_unit' => { + 'columns' => [ + 'realestatenum', 'serial', '', '', '', '', + 'realestatelocnum', 'int', '', '', '', '', + 'agentnum', 'int', 'NULL', '', '', '', + 'unit_title', 'varchar', '', $char_d, '', '', + 'disabled', 'char', 'NULL', 1, '', '', + ], + 'primary_key' => 'realestatenum', + 'unique' => [ ['unit_title'] ], + 'index' => [ + ['agentnum'], + ['realestatelocnum'], + ['disabled'], + ['unit_title'], + ], + 'foreign_keys' => [ + {columns => ['agentnum'], table => 'agent'}, + {columns => ['realestatelocnum'] => table => 'realestate_location'}, + ], + }, + + realestate_location => { + 'columns' => [ + 'realestatelocnum', 'serial', '', '', '', '', + 'agentnum', 'int', 'NULL', '', '', '', + 'location_title', 'varchar', '', $char_d, '', '', + 'address1', 'varchar', 'NULL', $char_d, '', '', + 'address2', 'varchar', 'NULL', $char_d, '', '', + 'city', 'varchar', 'NULL', $char_d, '', '', + 'state', 'varchar', 'NULL', $char_d, '', '', + 'zip', 'char', 'NULL', 5, '', '', + 'disabled', 'char', 'NULL', 1, '', '', + ], + primary_key => 'realestatelocnum', + 'unique' => [ ['location_title'] ], + 'index' => [ ['agentnum'], ['disabled'] ], + 'foreign_keys' => [ + {columns => ['agentnum'], table => 'agent'}, + ], + }, + + svc_realestate => { + columns => [ + 'svcnum', 'serial', '', '', '', '', + 'realestatenum', 'int', 'NULL', '', '', '', + ], + primary_key => 'svcnum', + index => [], + }, + # name type nullability length default local #'new_table' => { @@ -7627,4 +7714,3 @@ L<DBIx::DBSchema> =cut 1; - diff --git a/FS/FS/h_svc_realestate.pm b/FS/FS/h_svc_realestate.pm new file mode 100644 index 000000000..2fdd291d1 --- /dev/null +++ b/FS/FS/h_svc_realestate.pm @@ -0,0 +1,31 @@ +package FS::h_svc_realestate; + +use strict; +use vars qw( @ISA ); +use FS::h_Common; + + +@ISA = qw( FS::h_Common ); + +sub table { 'h_svc_realestate' }; + +=head1 NAME + +FS::h_svc_circuit - Historical realestate service objects + +=head1 SYNOPSIS + +=head1 DESCRIPTION + +An FS::h_svc_realestate object + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::h_Common>, L<FS::svc_realestate>, L<FS::Record>, schema.html from the base +documentation. + +=cut + +1; diff --git a/FS/FS/realestate_location.pm b/FS/FS/realestate_location.pm new file mode 100644 index 000000000..d9cd76a58 --- /dev/null +++ b/FS/FS/realestate_location.pm @@ -0,0 +1,177 @@ +package FS::realestate_location; +use strict; +use warnings; +use Carp qw(croak); + +use base 'FS::Record'; + +use FS::Record qw(qsearchs qsearch); + +=head1 NAME + +FS::realestate_location - Object representing a realestate_location record + +=head1 SYNOPSIS + + use FS::realestate_location; + + $location = new FS::realestate_location \%values; + $location = new FS::realestate_location { + agentnum => 1, + location_title => 'Superdome', + address1 => '1500 Sugar Bowl Dr', + city => 'New Orleans', + state => 'LA', + zip => '70112', + }; + + $error = $location->insert; + $error = $new_loc->replace($location); + $error = $record->check; + + $error = $location->add_unit('Box Seat No. 42'); + @units = $location->units; + +=head1 DESCRIPTION + +An FS::realestate_location object represents a location for one or more +FS::realestate_unit objects. Expected to contain at least one unit, as only +realestate_unit objects are assignable to packages via +L<FS::svc_realestate>. + +FS::realestate_location inherits from FS::Record. + +The following fields are currently supported: + +=over 4 + +=item realestatelocnum + +=item agentnum + +=item location_title + +=item address1 (optional) + +=item address2 (optional) + +=item city (optional) + +=item state (optional) + +=item zip (optional) + +=item disabled + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF (see L<FS::Record>) + +=cut + +sub table {'realestate_location';} + +=item insert (see L<FS::Record>) + +=item delete + + FS::realestate_location records should never be deleted, only disabled + +=cut + +sub delete { + # Once this record has been associated with a customer in any way, it + # should not be deleted. todo perhaps, add a is_deletable function that + # checks if the record has ever actually been used, and allows deletion + # if it hasn't. (entered in error, etc). + croak "FS::realestate_location records should never be deleted"; +} + +=item replace OLD_RECORD (see L<FS::Record>) + +=item check (see L<FS::Record>) + +=item agent + +Returns the associated agent + +=cut + +sub agent { + my $self = shift; + return undef unless $self->agentnum; + return exists $self->{agent} + ? $self->{agent} + : $self->{agent} = qsearchs('agent', {agentnum => $self->agentnum} ); +} + + +=item add_unit UNIT_TITLE + +Create an associated L<FS::realestate_unit> record + +=cut + +sub add_unit { + my ($self, $unit_title) = @_; + croak "add_unit() requires a \$unit_title parameter" unless $unit_title; + + if ( + qsearchs('realestate_unit',{ + realestatelocnum => $self->realestatelocnum, + unit_title => $unit_title, + }) + ) { + return "Unit Title ($unit_title) has already been used for location (". + $self->location_title.")"; + } + + my $unit = FS::realestate_unit->new({ + realestatelocnum => $self->realestatelocnum, + agentnum => $self->agentnum, + unit_title => $unit_title, + }); + my $err = $unit->insert; + die "Error creating FS::realestate_new record: $err" if $err; + + return; +} + + +=item units + +Returns all units associated with this location + +=cut + +sub units { + my $self = shift; + return qsearch( + 'realestate_unit', + {realestatelocnum => $self->realestatelocnum} + ); +} + + +=head1 SUBROUTINES + +=over 4 + +=cut + + + + +=back + +=head1 SEE ALSO + +L<FS::record>, L<FS::realestate_unit>, L<FS::svc_realestate> + +=cut + +1; diff --git a/FS/FS/realestate_unit.pm b/FS/FS/realestate_unit.pm new file mode 100644 index 000000000..d1d1f7fda --- /dev/null +++ b/FS/FS/realestate_unit.pm @@ -0,0 +1,163 @@ +package FS::realestate_unit; +use strict; +use warnings; +use Carp qw(croak); + +use base 'FS::Record'; +use FS::Record qw(qsearch qsearchs); + +=head1 NAME + +FS::realestate_unit - Object representing a realestate_unit record + +=head1 SYNOPSIS + + use FS::realestate_unit; + + $record = new FS:realestate_unit \%values; + $record = new FS::realestate_unit { + realestatelocnum => 42, + agentnum => 1, + unit_title => 'Ste 404', + }; + + $error = $record->insert; + $error = $new_rec->replace($record) + $error = $record->check; + + $location = $record->location; + +=head1 DESCRIPTION + +An FS::realestate_unit object represents an invoicable unit of real estate. +Object may represent a single property, such as a rental house. It may also +represent a group of properties sharing a common address or identifier, such +as a shopping mall, apartment complex, or office building, concert hall. + +A FS::realestate_unit object must be associated with a FS::realestate_location + +FS::realestate_unit inherits from FS::Record. + +The following fields are currently supported: + +=over 4 + +=item realestatenum + +=item realestatelocnum + +=item agentnum + +=item unit_title + +=item disabled + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF (see L<FS::Record>) + +=cut + +sub table {'realestate_unit';} + +=item insert (see L<FS::Record>) + +=item delete + + FS::realestate_unit records should never be deleted, only disabled + +=cut + +sub delete { + # Once this record has been associated with a customer in any way, it + # should not be deleted. todo perhaps, add a is_deletable function that + # checks if the record has ever actually been used, and allows deletion + # if it hasn't. (entered in error, etc). + croak "FS::realestate_unit records should never be deleted"; +} + + +=item replace OLD_RECORD (see L<FS::Record>) + +=item check (see L<FS::Record>) + +=item agent + +Returns the associated agent, if any, for this object + +=cut + +sub agent { + my $self = shift; + return undef unless $self->agentnum; + return qsearchs('agent', {agentnum => $self->agentnum} ); +} + +=item location + + Return the associated FS::realestate_location object + +=cut + +sub location { + my $self = shift; + return $self->{location} if exists $self->{location}; + return $self->{location} = qsearchs( + 'realestate_location', + {realestatelocnum => $self->realestatelocnum} + ); +} + +=back + +=item custnum + +Pull the assigned custnum for this unit, if provisioned + +=cut + +sub custnum { + my $self = shift; + return $self->{custnum} + if $self->{custnum}; + + # select cust_pkg.custnum + # from svc_realestate + # LEFT JOIN cust_svc ON svc_realestate.svcnum = cust_svc.svcnum + # LEFT JOIN cust_pkg ON cust_svc.pkgnum = cust_pkg.pkgnum + # WHERE svc_realestate.realestatenum = $realestatenum + + my $row = qsearchs({ + select => 'cust_pkg.custnum', + table => 'svc_realestate', + addl_from => 'LEFT JOIN cust_svc ON svc_realestate.svcnum = cust_svc.svcnum ' + . 'LEFT JOIN cust_pkg ON cust_svc.pkgnum = cust_pkg.pkgnum ', + extra_sql => 'WHERE svc_realestate.realestatenum = '.$self->realestatenum, + }); + + return + unless $row && $row->custnum; + + return $self->{custnum} = $row->custnum; +} + +=head1 SUBROUTINES + +=over 4 + +=cut + + +=back + +=head1 SEE ALSO + +L<FS::record>, L<FS::realestate_location>, L<FS::svc_realestate> + +=cut + +1; diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm index f2456a56f..afd5db64f 100644 --- a/FS/FS/svc_Common.pm +++ b/FS/FS/svc_Common.pm @@ -122,6 +122,15 @@ sub virtual_fields { =item label +Returns a label to identify a record of this service. +Label may be displayed on freeside screens, and within customer bills. + +For example, $obj->label may return: + + - A provisioned phone number for svc_phone + - The mailing list name and e-mail address for svc_mailinglist + - The address of a rental property svc_realestate + svc_Common provides a fallback label subroutine that just returns the svcnum. =cut @@ -1586,4 +1595,3 @@ from the base documentation. =cut 1; - diff --git a/FS/FS/svc_realestate.pm b/FS/FS/svc_realestate.pm new file mode 100644 index 000000000..a7512eef8 --- /dev/null +++ b/FS/FS/svc_realestate.pm @@ -0,0 +1,172 @@ +package FS::svc_realestate; +use base qw(FS::svc_Common); + +use strict; +use warnings; +use vars qw($conf); + +use FS::Record qw(qsearchs qsearch dbh); +use Tie::IxHash; + +$FS::UID::callback{'FS::svc_realestate'} = sub { + $conf = new FS::Conf; +}; + +=head1 NAME + +FS::svc_realestate - Object methods for svc_realestate records + +=head1 SYNOPSIS + + {...} TODO + +=head1 DESCRIPTION + +A FS::svc_realestate object represents a billable real estate trasnaction, +such as renting a home or office. + +FS::svc_realestate inherits from FS::svc_Common. The following fields are +currently supported: + +=over 4 + +=item svcnum - primary key + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Instantiates a new svc_realestate object. + +=cut + +sub table_info { + tie my %fields, 'Tie::IxHash', + svcnum => 'Service', + realestatenum => { + type => 'select-realestate_unit', + label => 'Real estate unit', + }; + + { + name => 'Real estate', + name_plural => 'Real estate services', + longname_plural => 'Real estate services', + display_weight => 100, + cancel_weight => 100, + fields => \%fields, + }; +} + +sub table {'svc_realestate'} + +=item label + +Returns a label formatted as: + <location_title> <unit_title> + +=cut + +sub label { + my $self = shift; + my $unit = $self->realestate_unit; + my $location = $self->realestate_location; + + return $location->location_title.' '.$unit->unit_title + if $unit && $location; + + return $self->svcnum; # shouldn't happen +} + + +=item realestate_unit + +Returns associated L<FS::realestate_unit> + +=cut + +sub realestate_unit { + my $self = shift; + + return $self->get('_realestate_unit') + if $self->get('_realestate_unit'); + + return unless $self->realestatenum; + + my $realestate_unit = qsearchs( + 'realestate_unit', + {realestatenum => $self->realestatenum} + ); + + $self->set('_realestate_unit', $realestate_unit); + $realestate_unit; +} + +=item realestate_location + +Returns associated L<FS::realestate_location> + +=cut + +sub realestate_location { + my $self = shift; + + my $realestate_unit = $self->realestate_unit; + return unless $realestate_unit; + + $realestate_unit->location; +} + +=item cust_svc + +Returns associated L<FS::cust_svc> + +=cut + +sub cust_svc { + qsearchs('cust_svc', { 'svcnum' => $_[0]->svcnum } ); +} + +=item search_sql + +I have an unfounded suspicion this method serves no purpose in this context + +=cut + +# sub search_sql {die "search_sql called on FS::svc_realestate"} + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=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. + +=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. + +=back 4 + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; diff --git a/FS/t/realestate_location.t b/FS/t/realestate_location.t new file mode 100644 index 000000000..ecb1d8be9 --- /dev/null +++ b/FS/t/realestate_location.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::realestate_location; +$loaded=1; +print "ok 1\n"; diff --git a/FS/t/realestate_unit.t b/FS/t/realestate_unit.t new file mode 100644 index 000000000..bbecc1a4c --- /dev/null +++ b/FS/t/realestate_unit.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::realestate_unit; +$loaded=1; +print "ok 1\n"; diff --git a/FS/t/svc_realestate.t b/FS/t/svc_realestate.t new file mode 100644 index 000000000..4145d8b52 --- /dev/null +++ b/FS/t/svc_realestate.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::svc_realestate; +$loaded=1; +print "ok 1\n"; |