summaryrefslogtreecommitdiff
path: root/LedgerSMB
diff options
context:
space:
mode:
Diffstat (limited to 'LedgerSMB')
-rw-r--r--LedgerSMB/Form.pm8
-rw-r--r--LedgerSMB/IS.pm112
-rwxr-xr-xLedgerSMB/Session/DB.pm71
-rw-r--r--LedgerSMB/Sysconfig.pm22
-rw-r--r--LedgerSMB/User.pm100
5 files changed, 148 insertions, 165 deletions
diff --git a/LedgerSMB/Form.pm b/LedgerSMB/Form.pm
index a98eb0d0..4d055497 100644
--- a/LedgerSMB/Form.pm
+++ b/LedgerSMB/Form.pm
@@ -1113,9 +1113,17 @@ autocommit disabled.
sub db_init {
my ( $self, $myconfig ) = @_;
+
+ # Handling of HTTP Basic Auth headers
+ my $auth = $ENV{'HTTP_AUTHORIZATION'};
+ $auth =~ s/Basic //i; # strip out basic authentication preface
+ $auth = MIME::Base64::decode($auth);
+ my ($login, $password) = split(/:/, $auth);
+
$self->{dbh} = $self->dbconnect_noauto($myconfig) || $self->dberror();
my %date_query = (
'mm/dd/yy' => 'set DateStyle to \'SQL, US\'',
+
'mm-dd-yy' => 'set DateStyle to \'POSTGRES, US\'',
'dd/mm/yy' => 'set DateStyle to \'SQL, EUROPEAN\'',
'dd-mm-yy' => 'set DateStyle to \'POSTGRES, EUROPEAN\'',
diff --git a/LedgerSMB/IS.pm b/LedgerSMB/IS.pm
index 264fbd29..d494eb48 100644
--- a/LedgerSMB/IS.pm
+++ b/LedgerSMB/IS.pm
@@ -1527,6 +1527,12 @@ sub process_assembly {
}
sub cogs {
+ # This is nearly entirely rewritten since 1.2.8 based in part on the works
+ # of Victor Sterpu and Dieter Simader (see CONTRIBUTORS for more
+ # information). However, there are a number of areas where I have
+ # substantially rewritten the logic. This function is heavily annotated
+ # largely because COGS/invoices are still scheduled to be re-engineered in
+ # 1.4 so it is a good idea to have records of opinions in the code.-- CT
my ( $dbh2, $form, $id, $totalqty, $project_id, $sellprice) = @_;
my $dbh = $form->{dbh};
my $query;
@@ -1606,13 +1612,13 @@ sub cogs {
# will throw an error until we have an understanding of other workflows
# that need to be supported. -- CT
$query = qq|
- SELECT i.id, i.qty, i.allocated, a.transdate
- i.qty - i.allocated AS available,
+ SELECT i.id, i.qty, i.allocated, a.transdate,
+ -1 * (i.allocated + i.qty) AS available,
p.expense_accno_id, p.inventory_accno_id
FROM invoice i
JOIN parts p ON (p.id = i.parts_id)
JOIN ar a ON (a.id = i.trans_id)
- WHERE i.parts_id = ? AND (i.qty + i.allocated) > 0
+ WHERE i.parts_id = ? AND (i.qty + i.allocated) > 0
AND i.sellprice = ?
ORDER BY transdate
|;
@@ -1621,7 +1627,7 @@ sub cogs {
my $qty;
while ( my $ref = $sth->fetchrow_hashref(NAME_lc) ) {
$form->db_parse_numeric(sth=>$sth, hashref => $ref);
- if ($totalqty > $ref->{available}){
+ if ($totalqty < $ref->{available}){
$qty = $ref->{available};
} else {
$qty = $totalqty;
@@ -1629,44 +1635,86 @@ sub cogs {
# update allocated for sold item
$form->update_balance(
$dbh, "invoice", "allocated",
- qq|id = $ref->{id}|, $qty * -1
+ qq|id = $ref->{id}|, $qty
);
- $allocated += $qty;
- my $linetotal = $qty*$ref->{sellprice};
- $query = qq|
- INSERT INTO acc_trans
- (trans_id, chart_id, amount,
- transdate, project_id, invoice_id)
- VALUES (?, ?, ?, ?, ?, ?)|;
-
- my $sth1 = $dbh->prepare($query);
- $sth1->execute(
- $form->{id}, $ref->{"expense_accno_id"},
- $linetotal, $form->{transdate},
- $project_id, $ref->{id}
- ) || $form->dberror($query);
- $query = qq|
- INSERT INTO acc_trans
- (trans_id, chart_id, amount, transdate,
- project_id, invoice_id)
- VALUES (?, ?, ?, ?, ?, ?)|;
-
- $sth1 = $dbh->prepare($query);
- $sth1->execute(
- $form->{id}, $ref->{"inventory_accno_id"},
- -$linetotal, $form->{transdate},
- $project_id, $ref->{id}
- ) || $form->dberror($query);
+ # Note: No COGS calculations on reversed short sale invoices.
+ # This merely prevents COGS calculations in the future agaisnt
+ # such short invoices. -- CT
$totalqty -= $qty;
+ $allocated -= $qty;
last if $totalqty == 0;
}
+ # If the total quantity is still less than zero, we must assume that
+ # this is just an invoice which has been voided or products returns
+ # but is not merely representing a voided short sale, and therefore
+ # we need to unallocate the items from AP. There has been some debate
+ # as to how to approach this, and I think it is safest to unallocate
+ # the most recently allocated AP items of the same type regardless of
+ # the relevant dates of the invoices. I can see cases where this
+ # might require adjustments, however. -- CT
+
+ if ($totalqty < 0){
+ $query = qq|
+ SELECT i.allocated, i.sellprice, p.inventory_accno_id,
+ p.expense_accno_id, i.id
+ FROM invoice i
+ JOIN parts p ON (i.parts_id = p.id)
+ JOIN ap a ON (i.trans_id = a.id)
+ WHERE (i.allocated + i.qty) < 0
+ AND i.parts_id = ?
+ ORDER BY a.transdate DESC, a.id DESC
+ |;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute($id);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)){
+ my $qty = $ref->{allocated} * -1;
+
+ $qty = ($qty < $totalqty) ? $totalqty : $qty;
+
+ my $linetotal = $qty*$ref->{sellprice};
+ push @{ $form->{acc_trans}{lineitems} },
+ {
+ chart_id => $ref->{expense_accno_id},
+ amount => $linetotal,
+ project_id => $project_id,
+ invoice_id => $ref->{id}
+ };
+
+ push @{ $form->{acc_trans}{lineitems} },
+ {
+ chart_id => $ref->{inventory_accno_id},
+ amount => -$linetotal,
+ project_id => $project_id,
+ invoice_id => $ref->{id}
+ };
+ $form->update_balance(
+ $dbh, "invoice", "allocated",
+ qq|id = $ref->{id}|, $qty
+ );
+
+ $totalqty -= $qty;
+ $allocated -= $qty;
+
+ last if $totalqty == 0;
+ }
+ }
+
+ # If we still have less than 0 total quantity, this is not a return
+ # or a void. Throw an error. If there are valid workflows that throw
+ # this error, they will require more work to address and will not work
+ # safely with the current system. -- CT
if ($totalqty < 0){
$form->error("Too many reversed items on an invoice");
}
+ elsif ($totalqty > 0){
+ $form->error("Unexpected and invalid quantity allocated.".
+ " Aborting.");
+ }
}
-
return $allocated;
}
diff --git a/LedgerSMB/Session/DB.pm b/LedgerSMB/Session/DB.pm
index 872dd419..145e1476 100755
--- a/LedgerSMB/Session/DB.pm
+++ b/LedgerSMB/Session/DB.pm
@@ -28,16 +28,21 @@
# (ver. < 1.2) and the md5 one (ver. >= 1.2)
#====================================================================
package Session;
+use MIME::Base64;
+use strict;
sub session_check {
use Time::HiRes qw(gettimeofday);
my ( $cookie, $form ) = @_;
- my ( $sessionID, $transactionID, $token ) = split /:/, $cookie;
+ if ($cookie eq 'Login'){
+ return session_create($form);
+ }
+ my $timeout;
- # use the central database handle
- my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
+
+ my $dbh = $form->{dbh};
my $checkQuery = $dbh->prepare(
"SELECT u.username, s.transaction_id
@@ -54,6 +59,10 @@ sub session_check {
WHERE session_id = ?;"
);
+ my ($sessionID, $transactionID, $company) = split(/:/, $cookie);
+
+ $form->{company} ||= $company;
+
#must be an integer
$sessionID =~ s/[^0-9]//g;
$sessionID = int $sessionID;
@@ -61,15 +70,11 @@ sub session_check {
$transactionID =~ s/[^0-9]//g;
$transactionID = int $transactionID;
- #must be 32 chars long and contain hex chars
- $token =~ s/[^0-9a-f]//g;
- $token = substr( $token, 0, 32 );
-
- if ( !$myconfig{timeout} ) {
+ if ( !$form->{timeout} ) {
$timeout = "1 day";
}
else {
- $timeout = "$myconfig{timeout} seconds";
+ $timeout = "$form->{timeout} seconds";
}
$checkQuery->execute( $sessionID, $timeout )
@@ -99,8 +104,8 @@ sub session_check {
|| $form->dberror(
__FILE__ . ':' . __LINE__ . ': Updating session age: ' );
- $newCookieValue =
- $sessionID . ':' . $newTransactionID . ':' . $token;
+ my $newCookieValue =
+ $sessionID . ':' . $newTransactionID . ':' . $form->{company};
#now update the cookie in the browser
print qq|Set-Cookie: LedgerSMB=$newCookieValue; path=/;\n|;
@@ -129,6 +134,8 @@ sub session_check {
}
sub session_create {
+ my ($lsmb) = @_;
+ my $lsmb;
use Time::HiRes qw(gettimeofday);
@@ -136,7 +143,6 @@ sub session_create {
my ( $ignore, $newTransactionID ) = gettimeofday();
$newTransactionID = int $newTransactionID;
- my ($form) = @_;
if ( !$ENV{HTTP_HOST} ) {
@@ -145,7 +151,7 @@ sub session_create {
}
# use the central database handle
- my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
+ my $dbh = $lsmb->{dbh};
# TODO Change this to use %myconfig
my $deleteExisting = $dbh->prepare(
@@ -167,43 +173,56 @@ sub session_create {
WHERE username = ?), ?, ?);"
);
-# this is assuming that $form->{login} is safe, which might be a bad assumption
-# so, I'm going to remove some chars, which might make previously valid logins invalid
- my $login = $form->{login};
+# this is assuming that the login is safe, which might be a bad assumption
+# so, I'm going to remove some chars, which might make previously valid
+# logins invalid --CM
+
+# I am changing this to use HTTP Basic Auth credentials for now. -- CT
+
+ my $auth = $ENV{HTTP_AUTHORIZATION};
+ $auth =~ s/^Basic //i;
+ my ($login, undef) = split(/:/, MIME::Base64::decode($auth));
$login =~ s/[^a-zA-Z0-9._+\@'-]//g;
#delete any existing stale sessions with this login if they exist
- if ( !$myconfig{timeout} ) {
- $myconfig{timeout} = 86400;
+ if ( $lsmb->{timeout} ) {
+ $lsmb->{timeout} = 86400;
}
- $deleteExisting->execute( $login, "$myconfig{timeout} seconds" )
- || $form->dberror(
+ $deleteExisting->execute( $login, "$lsmb->{timeout} seconds" )
+ || $lsmb->dberror(
__FILE__ . ':' . __LINE__ . ': Delete from session: ' );
#doing the random stuff in the db so that LedgerSMB won't
-#require a good random generator - maybe this should be reviewed, pgsql's isn't great either
+#require a good random generator - maybe this should be reviewed,
+#pgsql's isn't great either -CM
+#
+#I think we should be OK. The random number generator is only a small part
+#of the credentials in 1.3.x, and for people that need greater security, there
+#is always Kerberos.... -- CT
$fetchSequence->execute()
- || $form->dberror( __FILE__ . ':' . __LINE__ . ': Fetch sequence id: ' );
+ || $lsmb->dberror( __FILE__ . ':' . __LINE__ . ': Fetch sequence id: ' );
my ( $newSessionID, $newToken ) = $fetchSequence->fetchrow_array;
#create a new session
$createNew->execute( $newSessionID, $login, $newToken, $newTransactionID )
- || $form->dberror( __FILE__ . ':' . __LINE__ . ': Create new session: ' );
+ || $lsmb->dberror( __FILE__ . ':' . __LINE__ . ': Create new session: ' );
#reseed the random number generator
my $randomSeed = 1.0 * ( '0.' . ( time() ^ ( $$ + ( $$ << 15 ) ) ) );
$seedRandom->execute($randomSeed)
- || $form->dberror(
+ || $lsmb->dberror(
__FILE__ . ':' . __LINE__ . ': Reseed random generator: ' );
- $newCookieValue = $newSessionID . ':' . $newTransactionID . ':' . $newToken;
+
+ my $newCookieValue = $newSessionID . ':' . $newTransactionID . ':'
+ . $lsmb->{company};
#now set the cookie in the browser
#TODO set domain from ENV, also set path to install path
print qq|Set-Cookie: LedgerSMB=$newCookieValue; path=/;\n|;
- $form->{LedgerSMB} = $newCookieValue;
+ $lsmb->{LedgerSMB} = $newCookieValue;
}
sub session_destroy {
diff --git a/LedgerSMB/Sysconfig.pm b/LedgerSMB/Sysconfig.pm
index e01618cc..b62651a6 100644
--- a/LedgerSMB/Sysconfig.pm
+++ b/LedgerSMB/Sysconfig.pm
@@ -116,17 +116,17 @@ for $var (qw(DBhost DBport DBname DBUserName DBPassword)) {
}
#putting this in an if clause for now so not to break other devel users
-if ( $config{globaldb}{DBname} ) {
- my $dbconnect = "dbi:Pg:dbname=$globalDBname host=$globalDBhost
- port=$globalDBport user=$globalDBUserName
- password=$globalDBPassword"; # for easier debugging
- $GLOBALDBH = DBI->connect($dbconnect);
- if ( !$GLOBALDBH ) {
- $form = new Form;
- $form->error("No GlobalDBH Configured or Could not Connect");
- }
- $GLOBALDBH->{pg_enable_utf8} = 1;
-}
+#if ( $config{globaldb}{DBname} ) {
+# my $dbconnect = "dbi:Pg:dbname=$globalDBname host=$globalDBhost
+# port=$globalDBport user=$globalDBUserName
+# password=$globalDBPassword"; # for easier debugging
+# $GLOBALDBH = DBI->connect($dbconnect);
+# if ( !$GLOBALDBH ) {
+# $form = new Form;
+# $form->error("No GlobalDBH Configured or Could not Connect");
+# }
+# $GLOBALDBH->{pg_enable_utf8} = 1;
+#}
# These lines prevent other apps in mod_perl from seeing the global db
# connection info
diff --git a/LedgerSMB/User.pm b/LedgerSMB/User.pm
index 89033ed1..41aa0dcd 100644
--- a/LedgerSMB/User.pm
+++ b/LedgerSMB/User.pm
@@ -165,14 +165,15 @@ sub fetch_config {
#I'm hoping that this function will go and is a temporary bridge
#until we get rid of %myconfig elsewhere in the code
- my ( $self, $login ) = @_;
+ my ( $self, $lsmb ) = @_;
+
+ my $login = $lsmb->{login};
+ my $dbh = $lsmb->{dbh};
if ( !$login ) {
&error( $self, "Access Denied" );
}
- # use central db
- my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
# for now, this is querying the table directly... ugly
# my $fetchUserPrefs = $dbh->prepare(
@@ -230,99 +231,6 @@ sub fetch_config {
return \%myconfig;
}
-=item $user->login($form);
-
-Disused auth function.
-
-=cut
-
-sub login {
-
- my ( $self, $form ) = @_;
-
- my $rc = -1;
-
- if ( $self->{login} ne "" ) {
- if (
- !Session::password_check(
- $form, $form->{login}, $form->{password}
- )
- )
- {
- return -1;
- }
-
- #this is really dumb, but %myconfig will have to stay until 1.3
- while ( my ( $key, $value ) = each( %{$self} ) ) {
- $myconfig{$key} = $value;
- }
-
- # check if database is down
- my $dbh =
- DBI->connect( $myconfig{dbconnect}, $myconfig{dbuser},
- $myconfig{dbpasswd} )
- or $self->error( __FILE__ . ':' . __LINE__ . ': ' . $DBI::errstr );
- $dbh->{pg_enable_utf8} = 1;
-
- # we got a connection, check the version
- my $query = qq|
- SELECT value FROM defaults
- WHERE setting_key = 'version'|;
- my $sth = $dbh->prepare($query);
- $sth->execute || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
-
- my ($dbversion) = $sth->fetchrow_array;
- $sth->finish;
-
- # add login to employee table if it does not exist
- # no error check for employee table, ignore if it does not exist
- my $login = $self->{login};
- $login =~ s/@.*//;
- $query = qq|SELECT entity_id FROM employee WHERE login = ?|;
- $sth = $dbh->prepare($query);
- $sth->execute($login);
-
- my ($id) = $sth->fetchrow_array;
- $sth->finish;
-
- if ( !$id ) {
- my ($employeenumber) =
- $form->update_defaults( \%myconfig, "employeenumber", $dbh );
-
- $query = qq|
- INSERT INTO employee
- (login, employeenumber, name,
- workphone, role)
- VALUES (?, ?, ?, ?, ?)|;
- $sth = $dbh->prepare($query);
- $sth->execute(
- $login, $employeenumber, $myconfig{name},
- $myconfig{tel}, $myconfig{role}
- );
- }
- $dbh->disconnect;
-
- $rc = 0;
-
- if ( $form->{dbversion} ne $dbversion ) {
- $rc = -3;
- $dbupdate =
- ( calc_version($dbversion) < calc_version( $form->{dbversion} ) );
- }
-
- if ($dbupdate) {
- $rc = -4;
-
- # if DB2 bale out
- if ( $myconfig{dbdriver} eq 'DB2' ) {
- $rc = -2;
- }
- }
- }
-
- $rc;
-
-}
=item LedgerSMB::User->check_recurring($form);