Files
pmgr/scripts/sitelink2pmgr.pl
abijah fc30dfa2e8 Another snapshot. I think I'll be taking the CREDIT/DEBIT reconcile functionality out.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@353 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-07-20 02:17:54 +00:00

1489 lines
53 KiB
Perl

#perl -w
use strict;
use DBI;
use Data::Dumper;
use File::Copy;
my $use_invoice = 0;
my $use_receipt = 1;
# Internally adjust all numbers coming from the database to
# be in inches. Not necessary to go to this detail, but the
# actual units used is irrelevant, provided everything is to
# scale, and this factor ensures that any fractional units
# become whole (e.g. 7.5 "feet" becomes 90 "units")
my $internal_adjustment_factor = 12;
my $schema_file = shift || die("Must specify schema file\n");
my $slink_file = shift || die("Must specify sitelink file\n");
my $slink_file = ";Data Source=$slink_file";
my $slink_pass = ";Jet OLEDB:Database Password=2web";
my $sdsn="Provider=Microsoft.Jet.OLEDB.4.0$slink_pass$slink_file";
my $sdbh = DBI->connect("dbi:ADO:$sdsn", undef, undef, {PrintError => 1,
RaiseError => 1});
# Connect to the database.
my($hostname, $database, $user, $password) = ('localhost',
'property_manager',
'pmgr', 'pmgruser');
$database = shift if @ARGV;
$user = shift if @ARGV;
$password = shift if @ARGV;
print "Connecting to $database as $user\n";
my $db_handle = DBI->connect("DBI:mysql:database=$database;host=$hostname",
$user, $password,
{'PrintError' => 1,
'RaiseError' => 0});
$SIG{__DIE__} = \&Die;
my ($query, $result, $nrows, $row);
my (%newdb) = ( 'schema' => [],
'tables' => {},
'ids' => {},
'lookup' => {'state' => { 1=>'AK', 14=>'ID', 48=>'WA' }} );
######################################################################
######################################################################
## Die
sub Die {
my @text = @_;
warn "----------------------------------------------------------\n";
warn "FATAL ERROR: @text\n";
my $count = 0;
{
my ($package, $filename, $line, $sub) = caller($count);
last unless defined $line;
warn sprintf("%02i %5i %-35s %-20s\n", $count++, $line, $sub,
$filename);
redo;
}
exit 1;
}
######################################################################
######################################################################
## addRow
sub addRow {
my ($table, $cols, $noid) = @_;
die unless $table;
die unless ref($cols) eq 'HASH';
die "Table `$table` is unknown!"
unless defined $newdb{'tables'}{$table};
my $id;
if ($noid) {
$id = $cols->{'id'};
}
if (!defined $id) {
$id = ++$newdb{'tables'}{$table}{'autoid'};
}
$cols->{'id'} = $id
unless ($noid);
# For debug purposes
my $line = (caller())[2];
$cols->{'--LINE--'} = "addRow called from line: $line";
$newdb{'tables'}{$table}{'rows'}[$id] = $cols;
return $id;
}
######################################################################
######################################################################
## updateRow
sub updateRow {
my ($table, $id, $cols) = @_;
die unless $table;
die unless $id;
die unless ref($cols) eq 'HASH';
die "Table `$table` is unknown!"
unless defined $newdb{'tables'}{$table};
die "Table `$table` : ID `$id` does not exist!"
unless $newdb{'tables'}{$table}{'rows'}[$id];
# For debug purposes
my $line = (caller())[2];
$cols->{'--UPDATE-LINE--'} = [] unless $cols->{'--UPDATE-LINE--'};
push(@{$cols->{'--UPDATE-LINE--'}}, "updateRow called from line: $line");
#$newdb{'tables'}{$table}{'rows'}[$id] = $cols;
return $id;
}
######################################################################
######################################################################
## query
sub query {
my ($dbh, $sql, $data, $ignore) = @_;
#print("$sql\n\n"); #return [ { 'id' => 7 } ];
#print("$sql\n\n") if $sql =~ /^\s*UPDATE/i;
#return 1 unless $sql =~ /^\s*SELECT/i;
my ($sth, $result);
if ($sql =~ /^\s*SELECT/i) {
$sth = $dbh->prepare($sql);
$sth->execute();
$result = $sth->fetchall_arrayref({});
} else {
$result = $dbh->do($sql);
}
if (!$result && !$ignore) {
print STDERR "SQL Query FAILED:\n";
print STDERR "$sql\n\n";
print STDERR Dumper $data
if defined $data;
die;
}
return ($sth, $result);
}
######################################################################
######################################################################
## executeSchema
sub executeSchema {
foreach (@{$newdb{'schema'}}) {
query($db_handle, $_);
}
foreach my $table (values %{$newdb{'tables'}}) {
foreach (@{$table->{'schema'}}) {
query($db_handle, $_);
}
}
}
######################################################################
######################################################################
## buildTables
sub buildTables {
foreach my $table_name (sort keys %{$newdb{'tables'}}) {
my $table = $newdb{'tables'}{$table_name};
my $count = 0;
foreach (@{$table->{'rows'}}) {
next unless defined $_;
++$count;
}
printf("%-30s : %d rows\n", $table->{'name'}, $count);
foreach (@{$table->{'rows'}}) {
next unless defined $_;
my %row = %$_;
delete $row{'--LINE--'};
my $query;
$query = "INSERT INTO " . $table->{'name'};
$query .= " (" . join(", ", map({"`$_`"} keys(%row))) . ")";
$query .= " VALUES (" . join(", ", map({s/'/''/g if defined $_;
defined $_
? (/^\w+\(.*\)$/
? $_
: "'$_'" )
: "NULL" }
values(%row))) . ")";
query($db_handle, $query, $_);
}
}
}
######################################################################
######################################################################
## helper functions
sub sizeCode {
my ($width, $depth) = @_;
return "YARD"
if ($width == 12 && $depth == 40);
return "APARTMENT"
if ($width == 20 && $depth == 30);
return sprintf("%02dx%02d", $width, $depth);
}
sub datefmt {
my ($dt) = @_;
return undef unless $dt;
my @dt = split(/\/|\s/, $dt);
#print("$dt : " . sprintf("%04d-%02d-%02d", $dt[2], $dt[0], $dt[1]) . "\n");
return sprintf("%04d-%02d-%02d%s", $dt[2], $dt[0], $dt[1], $dt[3] ? ' '.$dt[3] : "");
}
sub dates {
my ($type, $dt, $dt_end, $comment, $ledger_id) = @_;
# Nothing should be stamped before possession
my $stamp = $dt;
if ($stamp =~ m%^0?[12]/% || ($stamp =~ m%^0?3/(\d+)/% && $1 <= 25)) {
$stamp = "3/25/2009 16:00";
}
my $effective_dt = $dt;
my $through_dt = $dt_end;
# Use different dates for security deposits
if ($type eq 'charge' && $comment eq 'Security Deposit') {
$effective_dt = $newdb{'lookup'}{'ledger'}{$ledger_id}{'lease_date'};
$through_dt = undef;
}
# REVISIT <AP>: 20090708
# Do we want to have effective dates on invoices?
# Do we want to have effective dates for payments?
# The Receipt already has an effective date.
if ($type eq 'invoice' || $type eq 'payment') {
$effective_dt = undef;
$through_dt = undef;
}
return (datefmt($stamp), datefmt($effective_dt), datefmt($through_dt));
}
######################################################################
######################################################################
######################################################################
######################################################################
## BUILD THE DATABASE
open(SCHEMA, "<$schema_file") || die ("Can't open schema ($!)\n");
my $schema_query = "";
my $table;
while (<SCHEMA>) {
next if /^\s*--/;
if (/DROP\s+TABLE\s.*`?(pmgr_(\w+))/i) {
$table = $2;
$newdb{'tables'}{$table} = { 'name' => $1,
'schema' => [],
'autoid' => 0,
'rows' => [] };
}
$schema_query .= $_;
if (/;\s*$/) {
$schema_query =~ s/^\s+//;
$schema_query =~ s/\s*;\s*$//;
if (!$table) {
push(@{$newdb{'schema'}}, $schema_query);
} else {
push(@{$newdb{'tables'}{$table}{'schema'}}, $schema_query);
}
$schema_query = "";
}
}
close(SCHEMA);
executeSchema();
#################################################################
## Test Contact
addRow('contacts',
{ 'first_name' => 'Abijah',
# 'middle_name' => 'M',
'last_name' => 'Perkins' });
addRow('contact_addresses',
{ 'address' => '1324 N Liberty Lake Rd\nPMB 263',
'city' => 'Liberty Lake',
'state' => 'WA',
'postcode' => '99019',
'country' => 'USA' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_addresses'}{'autoid'},
'method' => 'ADDRESS',
'type' => 'MAIN',
'preference' => 'PRIMARY' },
1);
addRow('contact_addresses',
{ 'address' => '5221 W Myrtlewood Ct',
'city' => 'Spokane',
'state' => 'WA',
'postcode' => '99208',
'country' => 'USA' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_addresses'}{'autoid'},
'method' => 'ADDRESS',
'type' => 'HOME',
'preference' => 'ALTERNATE' },
1);
# addRow('contact_addresses',
# { 'address' => 'PO Box 69',
# 'city' => 'Granger',
# 'state' => 'WA',
# 'postcode' => '98932',
# 'country' => 'USA' });
# addRow('contacts_methods',
# { 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
# 'method_id' => $newdb{'tables'}{'contact_addresses'}{'autoid'},
# 'method' => 'ADDRESS',
# 'type' => 'HOME',
# 'preference' => 'ALTERNATE' },
# 1);
addRow('contact_phones',
{ 'type' => 'MOBILE',
'phone' => '5098445573' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'MAIN',
'preference' => 'PRIMARY' },
1);
addRow('contact_phones',
{ 'type' => 'MOBILE',
'phone' => '5098445973' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'MAIN',
'preference' => 'ALTERNATE' },
1);
addRow('contact_phones',
{ 'type' => 'VIRTUAL',
'phone' => '5095901112' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'BUSINESS',
'preference' => 'WORK' },
1);
# addRow('contact_phones',
# { 'type' => 'LANDLINE',
# 'phone' => '5098541491' });
# addRow('contacts_methods',
# { 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
# 'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
# 'method' => 'PHONE',
# 'type' => 'HOME',
# 'preference' => 'ALTERNATE' },
# 1);
addRow('contact_phones',
{ 'type' => 'VIRTUAL',
'phone' => '8774488664' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'BUSINESS',
'preference' => 'WORK' },
1);
addRow('contact_phones',
{ 'type' => 'FAX',
'phone' => '8662960131' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'BUSINESS',
'preference' => 'WORK' },
1);
addRow('contact_emails',
{ 'email' => 'abijah\@PerkinsHouse.com' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_emails'}{'autoid'},
'method' => 'EMAIL',
'type' => 'HOME',
'preference' => 'PRIMARY' },
1);
addRow('contact_emails',
{ 'email' => 'abijah\@PerkinsREI.com' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_emails'}{'autoid'},
'method' => 'EMAIL',
'type' => 'HOME',
'preference' => 'WORK' },
1);
addRow('contact_emails',
{ 'email' => 'abijah\@ValleyStorage.info' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'},
'method_id' => $newdb{'tables'}{'contact_emails'}{'autoid'},
'method' => 'EMAIL',
'type' => 'BUSINESS',
'preference' => 'WORK' },
1);
#################################################################
## GROUPS
addRow('groups',
{ 'code' => 'Owner',
'name' => 'Owner Group' });
addRow('group_permissions',
{ 'group_id' => $newdb{'tables'}{'groups'}{'autoid'},
'name' => 'EVERYTHING',
'access' => 'FORCED' },
1);
#################################################################
## USERS
addRow('users',
{ 'code' => 'AP',
'login' => 'abijah',
'contact_id' => $newdb{'tables'}{'contacts'}{'autoid'} });
#################################################################
## SITES
addRow('sites',
{ 'code' => 'VSS',
'name' => 'Valley Storage' });
addRow('site_memberships',
{ 'site_id' => $newdb{'tables'}{'sites'}{'autoid'},
'user_id' => $newdb{'tables'}{'users'}{'autoid'},
'group_id' => $newdb{'tables'}{'groups'}{'autoid'} },
1);
addRow('site_areas',
{ 'site_id' => $newdb{'tables'}{'sites'}{'autoid'},
'code' => 'Main',
'name' => 'Main Facility Area' });
#################################################################
## LEASES
addRow('lease_types',
{ 'code' => 'SL',
'name' => 'Storage Lease' });
#################################################################
## LEDGERS
$newdb{'lookup'}{'account'} = {};
$query = "SELECT * FROM pmgr_accounts";
$result = query($db_handle, $query);
foreach $row (@$result) {
addRow('ledgers',
{ 'account_id' => $row->{'id'},
'comment' => undef });
$newdb{'lookup'}{'account'}{$row->{'name'}}
= {'account_id' => $row->{'id'},
'tillable' => $row->{'tillable'},
'ledger_id' => $newdb{'tables'}{'ledgers'}{'autoid'} };
if ((!defined $newdb{'tables'}{'accounts'}{'autoid'}) ||
$row->{'id'} > $newdb{'tables'}{'accounts'}{'autoid'}) {
$newdb{'tables'}{'accounts'}{'autoid'} = $row->{'id'};
}
}
# For compatibility, while deciding on account names
if (!defined $newdb{'lookup'}{'account'}{'Cash'}) {
$newdb{'lookup'}{'account'}{'Cash'}
= $newdb{'lookup'}{'account'}{'Till'};
}
$newdb{'lookup'}{'charge_type'} = {};
$newdb{'lookup'}{'charge_type'}{'Rent'} =
$newdb{'lookup'}{'account'}{'Rent'};
$newdb{'lookup'}{'charge_type'}{'Late Fee'} =
$newdb{'lookup'}{'account'}{'Late Charge'};
$newdb{'lookup'}{'charge_type'}{'Security Deposit'} =
$newdb{'lookup'}{'account'}{'Security Deposit'};
#################################################################
## MONETARY
$newdb{'lookup'}{'payment_type'} = {};
$newdb{'lookup'}{'payment_type'}{1}
= { 'name' => 'Cash', 'account_name' => 'Cash' };
$newdb{'lookup'}{'payment_type'}{2}
= { 'name' => 'Check', 'account_name' => 'Check' };
$newdb{'lookup'}{'payment_type'}{3}
= { 'name' => 'Money Order', 'account_name' => 'Money Order' };
$newdb{'lookup'}{'payment_type'}{4}
= { 'name' => 'ACH', 'account_name' => 'Bank' };
$newdb{'lookup'}{'payment_type'}{12}
= { 'name' => 'Concession', 'account_name' => 'Concession' };
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
##
## UNITS
##
my @unit_sort_order =
qw(
A01 A02 A03 A04 A05 A06
B01 B02 B03 B04 B05 B06 B07
C01 C02 C03 C04 C05 C06 C07 C08 C09
10 11 12 13 14 15 16 17 18 19 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
D01 D02 D03 D04 D05 D06 D07 D08 D09 D10 D11
APT
Y01 Y02 Y03 Y04 Y05 Y06 Y07 Y08 Y09 Y10
);
my $unit_sort_order = 0;
my %unit_sort_order;
foreach (@unit_sort_order) {
$unit_sort_order += 1; # use 100 for later insertion
$unit_sort_order{$_} = $unit_sort_order;
}
my @unit_walk_order =
qw(
19 18 17 16 15 14 13 12 11 10
C01 C02 C03 C04 C05 C06 C07 C08 C09
APT
38 37 36 35 34 33 32 31 30 29 28
B01 B02 B03 B04 B05 B06 B07
A01 A02 A03 A04 A05 A06
27 26 25 24 23 22
D11 D10 D09 D08 D07 D06 D05 D04 D03 D02 D01
45 44 43 42 41 40 39
Y01 Y02 Y03 Y04 Y05 Y06 Y07 Y08 Y09 Y10
);
my $unit_walk_order = 0;
my %unit_walk_order;
foreach (@unit_walk_order) {
$unit_walk_order += 1; # use 100 for later insertion
$unit_walk_order{$_} = $unit_walk_order;
}
######################################################################
## Unit Types
$newdb{'lookup'}{'unit_type'} = {};
$query = "SELECT * FROM UnitType ORDER BY TypeID";
foreach $row (@{query($sdbh, $query)}) {
addRow('unit_types',
{ 'code' => 'xxx',
'name' => $row->{'UnitType'} });
$newdb{'lookup'}{'unit_type'}{$row->{'TypeID'}} =
$newdb{'tables'}{'unit_types'}{'autoid'};
}
######################################################################
## Unit Sizes
$newdb{'lookup'}{'unit_size'} = {};
$query = "SELECT * FROM UnitInfo WHERE UnitID <> 'POS\$' ORDER BY UnitID";
foreach $row (@{query($sdbh, $query)}) {
my $sz = sizeCode($row->{'Width'}, $row->{'Depth'});
next if defined $newdb{'lookup'}{'unit_size'}{$sz};
addRow('unit_sizes',
{ 'unit_type_id' => $row->{'Type'},
'code' => $sz,
'name' => $sz,
'width' => $internal_adjustment_factor * $row->{'Width'},
'depth' => $internal_adjustment_factor * $row->{'Depth'},
'deposit' => $row->{'StdSecDep'},
'rent' => $row->{'StdRent'} });
$newdb{'lookup'}{'unit_size'}{$sz}
= { 'id' => $newdb{'tables'}{'unit_sizes'}{'autoid'},
'rent' => $row->{'StdRent'},
'dep' => $row->{'StdSecDep'} };
}
######################################################################
## Units
$newdb{'lookup'}{'unit'} = {};
foreach $row (@{query($sdbh, $query)}) {
my $sz = sizeCode($row->{'Width'}, $row->{'Depth'});
my $szid = $newdb{'lookup'}{'unit_size'}{$sz}{'id'};
addRow('units',
{ 'unit_size_id' => $szid,
'code' => $row->{'UnitID'},
'name' => $row->{'UnitID'},
'status' => $row->{'Rented'} ?'OCCUPIED' :($row->{'Rentable'} ?'VACANT' :'UNAVAILABLE'),
'sort_order' => $unit_sort_order{$row->{'UnitID'}},
'walk_order' => $unit_walk_order{$row->{'UnitID'}},
'deposit' => $row->{'StdSecDep'},
'rent' => $row->{'StdRent'} });
$newdb{'lookup'}{'unit'}{$row->{'UnitID'}}
= { 'id' => $newdb{'tables'}{'units'}{'autoid'} };
}
######################################################################
## Map
my %info = ('extents' => {}, 'units' => {});
# Get the overall site limits
$query = "SELECT MIN(M.Top) AS mintop, MIN(M.Left) AS minlft,";
$query .= " MAX(M.Top + IIF(M.reverseWL, U.Width, U.Depth)) AS bot,";
$query .= " MAX(M.Left + IIF(M.reverseWL, U.Depth, U.Width)) AS rgt";
$query .= ' FROM UnitInfo U INNER JOIN mapUnitsV2 M ON M.unitID = U.UnitID';
$result = query($sdbh, $query);
# Fetch and verify the result
my $row = shift(@$result);
die("MIN query failed!") unless $row;
# Compute the actual boundaries, adjusting for a (0,0) origin
my $top_adjustment = 0 - $row->{'mintop'};
my $left_adjustment = 0 - $row->{'minlft'};
$info{'extents'}{'top'} = 0;
$info{'extents'}{'left'} = 0;
$info{'extents'}{'bottom'} = $internal_adjustment_factor * ($top_adjustment + $row->{'bot'} + 0);
$info{'extents'}{'right'} = $internal_adjustment_factor * ($left_adjustment + $row->{'rgt'} + 0);
addRow('maps',
{ 'name' => 'Main Facility Map',
'site_area_id' => $newdb{'tables'}{'site_areas'}{'autoid'},
'width' => $info{'extents'}{'right'} - $info{'extents'}{'left'},
'depth' => $info{'extents'}{'bottom'} - $info{'extents'}{'top'} });
# Get list of units and positions
$query = "SELECT U.UnitID, U.UnitID as name,";
$query .= " ($top_adjustment + M.Top) AS pt_t,";
$query .= " ($left_adjustment + M.Left) AS pt_l,";
$query .= " IIF(M.reverseWL, U.Depth, U.Width) AS Width,";
$query .= " IIF(M.reverseWL, U.Width, U.Depth) AS Depth,";
$query .= " M.reverseWL, U.Rented, U.Rentable";
$query .= " FROM UnitInfo U INNER JOIN mapUnitsV2 M ON M.unitID = U.UnitID";
# Go through each one, calculating the map location
foreach $row (@{query($sdbh, $query)}) {
addRow('maps_units',
{ 'map_id' => $newdb{'tables'}{'maps'}{'autoid'},
'unit_id' => $newdb{'lookup'}{'unit'}{$row->{'UnitID'}}{'id'},
'pt_top' => $internal_adjustment_factor * ($row->{'pt_t'}),
'pt_left' => $internal_adjustment_factor * ($row->{'pt_l'}),
'transpose' => $row->{'reverseWL'} });
}
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
##
## TENANTS
##
######################################################################
## Tenants
$newdb{'lookup'}{'tenant'} = {};
$query = "SELECT * FROM TenantInfo WHERE FirstName <> 'POS' ORDER BY TenantID";
foreach $row (@{query($sdbh, $query)}) {
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}
= { 'name' => "$row->{'LastName'}, $row->{'FirstName'}" };
addRow('contacts',
{ 'first_name' => $row->{'FirstName'},
'middle_name' => $row->{'MiddleName'},
'last_name' => $row->{'LastName'},
'id_local' => $row->{'IDNum'} || undef,
'id_local_state' => $row->{'IDNum'} ? $newdb{'lookup'}{'state'}{$row->{'DLStateID'}} : undef });
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'} =
$newdb{'tables'}{'contacts'}{'autoid'};
addRow('customers',
{ 'name' => "$row->{'LastName'}, $row->{'FirstName'}",
'primary_contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
});
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'} =
$newdb{'tables'}{'customers'}{'autoid'};
addRow('contacts_customers',
{ 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
'type' => 'TENANT' },
1);
if ($row->{'City'}) {
addRow('contact_addresses',
{ 'address' => $row->{'HomeAddress'} . ($row->{'HomeAddr2'} ? "\n".$row->{'HomeAddr2'} : "") || undef,
'city' => $row->{'City'},
'state' => $newdb{'lookup'}{'state'}{$row->{'StateID'}},
'postcode' => $row->{'Zip'} || undef,
'country' => 'USA' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
'method_id' => $newdb{'tables'}{'contact_addresses'}{'autoid'},
'method' => 'ADDRESS',
'type' => 'HOME',
'preference' => 'PRIMARY' },
1);
}
foreach ({'type' => 'LANDLINE', 'preference' => 'PRIMARY', 'phone' => $row->{'Phone'}},
{'type' => 'LANDLINE', 'preference' => 'WORK',
'phone' => $row->{'BusinessPhone'}, 'ext' => $row->{'BusinessExt'}},
{'type' => 'FAX', 'preference' => 'PRIMARY', 'phone' => $row->{'FAX'}},
{'type' => 'PAGER', 'preference' => 'PRIMARY', 'phone' => $row->{'Pager'}},
{'type' => 'MOBILE', 'preference' => 'ALTERNATE', 'phone' => $row->{'CellPhone'}})
{
if ($_->{'phone'}) {
addRow('contact_phones',
{ 'type' => $_->{'type'},
'phone' => $_->{'phone'},
'ext' => $_->{'ext'} });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'MAIN',
'preference' => $_->{'preference'} },
1);
}
}
if ($row->{'Email'}) {
addRow('contact_emails',
{ 'email' => $row->{'Email'} });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
'method_id' => $newdb{'tables'}{'contact_emails'}{'autoid'},
'method' => 'EMAIL',
'type' => 'MAIN',
'preference' => 'PRIMARY' },
1);
}
next unless $row->{'AltFirstName'} || $row->{'AltLastName'} || $row->{'AltAddress'} || $row->{'AltPhone'};
addRow('contacts',
{ 'first_name' => $row->{'AltFirstName'} || undef,
'middle_name' => $row->{'AltMI'} || undef,
'last_name' => $row->{'AltLastName'} || undef });
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'alt'} =
$newdb{'tables'}{'contacts'}{'autoid'};
addRow('contacts_customers',
{ 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'alt'},
'type' => 'ALTERNATE' },
1);
if ($row->{'AltCity'}) {
addRow('contact_addresses',
{ 'address' => $row->{'AltAddress'} . ($row->{'AltAddr2'} ? "\n".$row->{'AltAddr2'} : ""),
'city' => $row->{'AltCity'},
'state' => $newdb{'lookup'}{'state'}{$row->{'AltStateID'}},
'postcode' => $row->{'AltZip'},
'country' => 'USA' });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'alt'},
'method_id' => $newdb{'tables'}{'contact_addresses'}{'autoid'},
'method' => 'ADDRESS',
'type' => 'MAIN',
'preference' => 'PRIMARY' },
1);
}
if ($row->{'AltPhone'}) {
addRow('contact_phones',
{ 'type' => 'LANDLINE',
'phone' => $row->{'AltPhone'},
'ext' => undef });
addRow('contacts_methods',
{ 'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'alt'},
'method_id' => $newdb{'tables'}{'contact_phones'}{'autoid'},
'method' => 'PHONE',
'type' => 'MAIN',
'preference' => 'PRIMARY' },
1);
}
}
######################################################################
## Tenant Leases
$newdb{'lookup'}{'ledger'} = {};
$query = "SELECT L.*, A.TenantID FROM TenantLedger L LEFT JOIN `Access` A ON A.LedgerID = L.LedgerID WHERE L.UnitID <> 'POS\$' ORDER BY L.DateIn";
foreach $row (@{query($sdbh, $query)}) {
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}
= { 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'lease_date' => $row->{'DateIn'},
};
addRow('leases',
{ 'number' => $newdb{'tables'}{'leases'}{'autoid'}+1,
#'number' => $row->{'LedgerID'},
'lease_type_id' => $newdb{'tables'}{'lease_types'}{'autoid'},
'unit_id' => $newdb{'lookup'}{'unit'}{$row->{'UnitID'}}{'id'},
'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'lease_date' => datefmt($row->{'DateIn'}),
'movein_date' => datefmt($row->{'DateIn'}),
'moveout_date' => datefmt($row->{'DateOut'}),
'close_date' => datefmt($row->{'DateClosed'}),
'rent' => $row->{'Rent'},
'comment' => "LedgerID: $row->{'LedgerID'}",
});
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_id'} =
$newdb{'tables'}{'leases'}{'autoid'};
}
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
##
## INVOICES
##
######################################################################
## Invoices
$newdb{'lookup'}{'charge'} = {};
$query = "SELECT *, ChargeAmount+TaxAmount AS InvoiceAmount FROM Charges ORDER BY ChargeID";
foreach $row (@{query($sdbh, $query)}) {
my ($stamp, $effective_date, $through_date) =
dates('invoice', $row->{'ChargeDate'}, $row->{'EndDate'},
$row->{'ChargeDescription'}, $row->{'LedgerID'});
addRow('transactions',
{ 'type' => 'INVOICE',
'stamp' => $stamp,
#'amount' => $row->{'InvoiceAmount'},
#'comment' => "Invoice Transaction",
});
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}
= { 'invoice' => {'id' => $newdb{'tables'}{'transactions'}{'autoid'},
'amount' => $row->{'InvoiceAmount'} },
};
# Charges are the only way we have to figure out security
# deposit requirements for a lease. So, if we encounter
# a security deposit charge, update the lease to reflect.
if ($row->{'ChargeDescription'} eq 'Security Deposit') {
$newdb{'tables'}{'leases'}{'rows'}[
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_id'}
]{'deposit'} = $row->{'ChargeAmount'};
}
}
######################################################################
## Charges
$query = "SELECT * FROM Charges ORDER BY ChargeID";
foreach $row (@{query($sdbh, $query)}) {
my (undef, $effective_date, $through_date) =
dates('charge', $row->{'ChargeDate'}, $row->{'EndDate'},
$row->{'ChargeDescription'}, $row->{'LedgerID'});
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'amount'}
= $row->{'ChargeAmount'};
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_id'}
= $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'customer_id'},
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_id'}
= $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_id'};
# Charge must credit the Charge ledger...
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'credit_account_id'}
= $newdb{'lookup'}{'charge_type'}{$row->{'ChargeDescription'}}{'account_id'};
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'credit_ledger_id'}
= $newdb{'lookup'}{'charge_type'}{$row->{'ChargeDescription'}}{'ledger_id'};
# ...and debit the A/R ledger.
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'debit_account_id'}
= $newdb{'lookup'}{'account'}{'A/R'}{'account_id'};
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'debit_ledger_id'}
= $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'};
# debit: A/R credit: Rent/LateCharge/Etc
addRow('double_entries',
{ 'transaction_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'invoice'}{'id'},
'effective_date' => $effective_date,
'customer_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_id'},
'lease_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_id'},
'debit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'debit_ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'credit_ledger_id'},
'amount' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'amount'},
'comment' => "Double Entry: $row->{'ChargeID'}; Ledger: $row->{'LedgerID'}",
});
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'double_entry_id'}
= $newdb{'tables'}{'double_entries'}{'autoid'};
# Add the Charge Entry
addRow('entries',
{ 'type' => 'CHARGE',
'through_date' => $through_date,
'double_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'double_entry_id'},
'account_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'credit_account_id'},
'ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'credit_ledger_id'},
'crdr' => 'CREDIT',
'comment' => "Charge: $row->{'ChargeID'}; Ledger: $row->{'LedgerID'}",
});
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'entry_id'}
= $newdb{'tables'}{'entries'}{'autoid'};
# Add the A/R entry
addRow('entries',
{ 'type' => 'TRANSFER',
'double_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'double_entry_id'},
'account_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'debit_account_id'},
'ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'debit_ledger_id'},
'crdr' => 'DEBIT',
'comment' => "Charge A/R: $row->{'ChargeID'}; Ledger: $row->{'LedgerID'}",
});
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ar_entry_id'}
= $newdb{'tables'}{'entries'}{'autoid'};
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'amount'}
= $row->{'ChargeAmount'};
next unless $row->{'TaxAmount'};
# # Add the tax charge entry
# # debit: Invoice credit: Tax
# addRow('ledger_entries',
# { 'effective_date' => $effective_date,
# 'through_date' => $through_date,
# 'transaction_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'invoice'}{'id'},
# 'debit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'debit_ledger_id'},
# 'credit_ledger_id' => $newdb{'lookup'}{'account'}{'Tax'}{'ledger_id'},
# 'amount' => $row->{'TaxAmount'},
# #'comment' => "Tax for ChargeID:$row->{'ChargeID'}",
# });
# $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'tax_ledger_entry_id'}
# = $newdb{'tables'}{'ledger_entries'}{'autoid'};
}
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
##
## RECEIPTS
##
######################################################################
## Receipts
$newdb{'lookup'}{'receipt'} = {};
############################################################
############################################################
############################################################
# REVISIT <AP> 20090630
# Handling of receipts is all backwards. The way things
# _should_ look if someone provides Cash and Check to pay
# rent & tax for two units (50 on UnitA and 40 UnitB):
#
# RENT TAX INVOICE A/R RECEIPT CASH CHECK
# ------- ------- ------- ------- ------- ------- -------
# |50 | 50| | | | |
# | | 5 5| | | | |
# | | |55 55| | | |
# |40 | 40| | | | |
# | | 4 4| | | | |
# | | |44 44| | | |
# | | | | |79 | 79|
# | | | | |20 20| |
# | | | |99 99| | |
# | | | | | | |
#
# HOWEVER,
# Our current implementation MUST match LedgerEntry to
# LedgerEntry for reconcile purposes. Thus, although there
# is a way to reconcile that $50 was received, there is no
# way to flag the payment as being for UnitA, unless we
# either rely on the charge to determine the fact (a
# solution that has proven very messy), or we add it to
# the reconciliations table. The hope, for simplicity's
# sake, was to ensure there was a single ledger entry in
# A/R for each payment that could correspond to a lease/unit,
# so that no A/R ledger entry ever represented payment for
# more than one lease. However, to do so, our ledgers
# appear like this instead:
#
# RENT TAX INVOICE A/R RECEIPT CASH CHECK
# ------- ------- ------- ------- ------- ------- -------
# |50 | 50| | | | | t1a
# | | 5 5| | | | | t1a
# | | |55 55| | | | t1b
# |40 | 40| | | | | t2a
# | | 4 4| | | | | t2a
# | | |44 44| | | | t2b
# | | | | |79 | 79| t3a
# | | | | |20 20| | t3a
# | | | |50 50| | | t3b
# | | | | 5 5| | | t3b
# | | | |40 40| | | t3b
# | | | | 4 4| | | t3b
# | | | | | | |
#
# There is another possible solution, although it is
# very probably ledger overkill (even invoice/receipt
# already fall into the overkill category).
#
# RENT TAX INVOICE A/R MERGE RECEIPT CASH CHECK
# ------- ------- ------- ------- ------- ------- ------- -------
# |50 | 50| | | | | |
# | | 5 5| | | | | |
# | | |55 55| | | | |
# |40 | 40| | | | | |
# | | 4 4| | | | | |
# | | |44 44| | | | |
# | | | | | |79 | 79|
# | | | | | |20 20| |
# | | | | |50 50| | |
# | | | | | 5 5| | |
# | | | | |40 40| | |
# | | | | | 4 4| | |
# | | | |99 99| | | |
# | | | | | | | |
#
# I might opt for this last option, but ultimately, none
# of these are really correct. We need a better solution.
# Until then, I'll go with the easiest.
############################################################
############################################################
############################################################
# Sitelink splits one physical payment into multiple "payments" to match each charge.
# The solution here is kludgy, but for our cases at least, it brings those pseudo-payments
# back into a single one. This presumes there is only one PaymentType per receipt.
$query =
"SELECT R.ReceiptNum, R.ReceiptDate, P.PaymentType, P.CheckNum, SUM(P.PaymentAmount) AS ReceiptAmount" .
" FROM Receipts R, Payments P" .
" WHERE P.ReceiptNum = R.ReceiptNum" .
" GROUP BY R.ReceiptNum, R.ReceiptDate, P.PaymentType, P.CheckNum" .
" ORDER BY R.ReceiptNum, P.PaymentType";
# print Dumper query($sdbh, $query);
# exit;
foreach $row (@{query($sdbh, $query)}) {
# if ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'}) {
# next;
# }
my ($stamp, $effective_date, $through_date) =
dates('receipt', $row->{'ReceiptDate'}, undef);
if ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}) {
print Dumper $newdb{'lookup'}{'receipt'};
print Dumper $row;
die "REALLY?";
}
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}
= { 'date' => $stamp,
'amount' => $row->{'ReceiptAmount'},
};
if ($row->{'ReceiptDate'} =~ m%3/25/2009%) {
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'name'}
= 'Closing';
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'account_name'}
= 'Bank';
}
else {
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'name'}
= $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'name'};
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'type'}
= $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'account_name'};
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'account_name'}
= $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'account_name'};
if ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'name'} eq 'Check') {
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'name'}
= 'Check #' . $row->{'CheckNum'};
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'data1'}
= $row->{'CheckNum'};
}
}
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'type'} = undef
if ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'type'}
== 'Concession');
addRow('transactions',
{ 'type' => 'RECEIPT',
'stamp' => $stamp,
});
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'receipt_id'}
= $newdb{'tables'}{'transactions'}{'autoid'};
# Receipt must debit the "money" asset (bank, cash, check, etc)...
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'debit_account_id'}
= $newdb{'lookup'}{'account'}{
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'account_name'}
}{'account_id'};
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'debit_ledger_id'}
= $newdb{'lookup'}{'account'}{
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'account_name'}
}{'ledger_id'};
# ...and credit the A/R ledger
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'credit_account_id'}
= $newdb{'lookup'}{'account'}{'A/R'}{'account_id'};
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'credit_ledger_id'}
= $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'};
# debit: Cash/Check/Etc credit: A/R
addRow('double_entries',
{ 'transaction_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'receipt_id'},
'effective_date' => $effective_date,
'customer_id' => undef, # This is set later...
'debit_ledger_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'debit_ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'credit_ledger_id'},
'amount' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'amount'},
'comment' => "Double Entry Receipt: $row->{'ReceiptNum'}; Type: $row->{'PaymentType'}",
});
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'double_entry_id'}
= $newdb{'tables'}{'double_entries'}{'autoid'};
# Add the Payment Entry
addRow('entries',
{ 'type' => 'PAYMENT',
'account_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'debit_account_id'},
'ledger_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'debit_ledger_id'},
'crdr' => 'DEBIT',
'double_entry_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'double_entry_id'},
'name' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'name'},
'monetary_type' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'type'},
'data1' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'data1'},
'comment' => "Receipt: $row->{'ReceiptNum'}; Type: $row->{'PaymentType'}",
});
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'entry_id'}
= $newdb{'tables'}{'entries'}{'autoid'};
# Add the A/R Entry
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'credit_account_id'},
'ledger_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'credit_ledger_id'},
'crdr' => 'CREDIT',
'double_entry_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'double_entry_id'},
'comment' => "Receipt A/R: $row->{'ReceiptNum'}; Type: $row->{'PaymentType'}",
});
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ar_entry_id'}
= $newdb{'tables'}{'entries'}{'autoid'};
}
######################################################################
## Payments to Charges assignments
$newdb{'lookup'}{'payment'} = {};
$query = "SELECT * FROM Payments ORDER BY PaymentID";
foreach $row (@{query($sdbh, $query)})
{
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}
= { 'receipt_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'receipt_id'},
'ar_entry_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ar_entry_id'},
'entry_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'entry_id'},
'amount' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'amount'},
};
# Ensure Payment has the right customer
$newdb{'tables'}{'double_entries'}{'rows'}[
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'double_entry_id'}
]{'customer_id'} = $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_id'};
next
if ($newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'reconciled'});
# Figure out how much of the charge can be reconciled
my $charge_amount = $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'amount'};
my $payment_amount = $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'amount'};
my $reconcile_amount = ($charge_amount < $payment_amount) ? $charge_amount : $payment_amount;
# Reconcile the A/R Account
addRow('reconciliations',
{ 'debit_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ar_entry_id'},
'credit_entry_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'ar_entry_id'},
'amount' => $reconcile_amount,
});
# Reconcile the payment to the charge
addRow('charges_payments',
{ 'charge_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'entry_id'},
'payment_entry_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'entry_id'},
'amount' => $reconcile_amount,
});
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'reconciled'} = 1;
# Update the transaction to use the memo from this payment
if ($row->{'Memo'}) {
my $id = $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'entry_id'};
$newdb{'tables'}{'entries'}{'rows'}[$id]{'comment'} = $row->{'Memo'};
}
}
######################################################################
## Special cases - Fix sitelink Brenda Harmon bug
# print("Special Cases - Fix Brenda Harmon...\n");
# $query =
# "UPDATE pmgr_contacts" .
# " SET first_name = 'Krystan'" .
# " WHERE first_name = 'Kristan' AND last_name = 'Mancini'";
# query($db_handle, $query);
######################################################################
## Special case - Equities / Loans / Petty Cash
my ($stamp, $effective_date, $through_date);
print("Set up Petty Cash...\n");
# Add the first loan
# debit: Equity credit: Loan
addRow('transactions',
{ 'type' => 'TRANSFER',
'stamp' => datefmt('03/25/2009 16:00'),
});
addRow('double_entries',
{ 'transaction_id' => $newdb{'tables'}{'transactions'}{'autoid'},
'effective_date' => $effective_date,
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'Equity'}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{'Loan'}{'ledger_id'},
'amount' => 5000,
'comment' => "HTP Loan #1",
});
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'account'}{'Equity'}{'account_id'},
'ledger_id' => $newdb{'lookup'}{'account'}{'Equity'}{'ledger_id'},
'crdr' => 'DEBIT',
'double_entry_id' => $newdb{'tables'}{'double_entries'}{'autoid'},
'comment' => "Equity: HTP Loan #1",
});
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'account'}{'Loan'}{'account_id'},
'ledger_id' => $newdb{'lookup'}{'account'}{'Loan'}{'ledger_id'},
'crdr' => 'CREDIT',
'double_entry_id' => $newdb{'tables'}{'double_entries'}{'autoid'},
'comment' => "Loan: HTP Loan #1",
});
# Add the second loan
# debit: Equity credit: Loan
addRow('transactions',
{ 'type' => 'TRANSFER',
'stamp' => datefmt('04/01/2009 16:00'),
});
addRow('double_entries',
{ 'transaction_id' => $newdb{'tables'}{'transactions'}{'autoid'},
'effective_date' => $effective_date,
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'Equity'}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{'Loan'}{'ledger_id'},
'amount' => 1000,
'comment' => "HTP Loan #2",
});
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'account'}{'Equity'}{'account_id'},
'ledger_id' => $newdb{'lookup'}{'account'}{'Equity'}{'ledger_id'},
'crdr' => 'DEBIT',
'double_entry_id' => $newdb{'tables'}{'double_entries'}{'autoid'},
'comment' => "Equity: HTP Loan #2",
});
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'account'}{'Loan'}{'account_id'},
'ledger_id' => $newdb{'lookup'}{'account'}{'Loan'}{'ledger_id'},
'crdr' => 'CREDIT',
'double_entry_id' => $newdb{'tables'}{'double_entries'}{'autoid'},
'comment' => "Loan: HTP Loan #2",
});
# Cheat for now, using equity for Petty Cash
# debit: Petty Cash credit: Equity
addRow('transactions',
{ 'type' => 'TRANSFER',
'stamp' => datefmt('03/25/2009 16:00'),
});
addRow('double_entries',
{ 'transaction_id' => $newdb{'tables'}{'transactions'}{'autoid'},
'effective_date' => $effective_date,
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'Petty Cash'}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{'Equity'}{'ledger_id'},
'amount' => 750,
'comment' => "Petty Cash Funding",
});
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'account'}{'Petty Cash'}{'account_id'},
'ledger_id' => $newdb{'lookup'}{'account'}{'Petty Cash'}{'ledger_id'},
'crdr' => 'DEBIT',
'double_entry_id' => $newdb{'tables'}{'double_entries'}{'autoid'},
'comment' => "Petty Cash: Petty Cash Funding",
});
addRow('entries',
{ 'type' => 'TRANSFER',
'account_id' => $newdb{'lookup'}{'account'}{'Equity'}{'account_id'},
'ledger_id' => $newdb{'lookup'}{'account'}{'Equity'}{'ledger_id'},
'crdr' => 'CREDIT',
'double_entry_id' => $newdb{'tables'}{'double_entries'}{'autoid'},
'comment' => "Equity: Petty Cash Funding",
});
######################################################################
## Build the Database
$Data::Dumper::Sortkeys = 1;
# print Dumper \%newdb;
# exit;
buildTables();
######################################################################
## Special cases - Name corrections
print("Special Cases...\n");
$query =
"UPDATE pmgr_contacts" .
" SET first_name = 'Krystan'" .
" WHERE first_name = 'Kristan' AND last_name = 'Mancini'";
query($db_handle, $query);
$query =
"UPDATE pmgr_customers" .
" SET name = 'Mancini, Krystan'" .
" WHERE name = 'Mancini, Kristan'";
query($db_handle, $query);
$query =
"UPDATE pmgr_contacts" .
" SET first_name = NULL, last_name = NULL, company_name = 'Valley Bible Church'" .
" WHERE first_name = 'VBC' AND last_name = 'Tenant'";
query($db_handle, $query);
$query =
"UPDATE pmgr_customers" .
" SET name = 'Valley Bible Church'" .
" WHERE name = 'Tenant, VBC'";
query($db_handle, $query);
######################################################################
## Contact Display Names
print("Set Contact Display Names...\n");
$query =
"UPDATE pmgr_contacts".
" SET display_name =" .
" IF(first_name IS NOT NULL AND last_name IS NOT NULL," .
" CONCAT(last_name, ', ', first_name)," .
" IF(first_name IS NOT NULL, first_name, last_name))";
query($db_handle, $query);
######################################################################
## Unit Lease Assignments
print("Set Current Leases...\n");
$query = "UPDATE pmgr_units U, pmgr_leases L
SET U.`current_lease_id` = L.id
WHERE L.unit_id = U.id AND L.close_date IS NULL";
query($db_handle, $query);
######################################################################
## Invoice/Receipt totals
print("Set Invoice/Receipt Totals...\n");
$query = "UPDATE pmgr_transactions T, pmgr_double_entries DE
SET T.`amount` = COALESCE(T.`amount`,0) + DE.amount
WHERE DE.transaction_id = T.id";
query($db_handle, $query);