summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorMitch Jackson <mitch@freeside.biz>2017-11-27 19:13:40 +0000
committerMitch Jackson <mitch@freeside.biz>2017-11-27 19:13:40 +0000
commit95144265eeb3ecd13b16708dbdd75dd3701f92ad (patch)
tree9b3ab3585bc33dd47db620e8fb85ef42287bc0b1 /FS
parent437042190fc83f5c2ed91386f44460d194278c84 (diff)
Added option for Credit Report to include Voided Credits RT#73200
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/Record.pm165
1 files changed, 99 insertions, 66 deletions
diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm
index 479f9b1..21fef73 100644
--- a/FS/FS/Record.pm
+++ b/FS/FS/Record.pm
@@ -67,7 +67,7 @@ FS::UID->install_callback( sub {
eval "use FS::Conf;";
die $@ if $@;
- $conf = FS::Conf->new;
+ $conf = FS::Conf->new;
$conf_encryption = $conf->exists('encryption');
$conf_encryptionmodule = $conf->config('encryptionmodule');
$conf_encryptionpublickey = join("\n",$conf->config('encryptionpublickey'));
@@ -104,7 +104,7 @@ FS::Record - Database record objects
$record = qsearchs FS::Record 'table', \%hash;
$record = qsearchs FS::Record 'table', { 'column' => 'value', ... };
- @records = qsearch FS::Record 'table', \%hash;
+ @records = qsearch FS::Record 'table', \%hash;
@records = qsearch FS::Record 'table', { 'column' => 'value', ... };
$table = $record->table;
@@ -174,14 +174,14 @@ Creates a new record. It doesn't store it in the database, though. See
L<"insert"> for that.
Note that the object stores this hash reference, not a distinct copy of the
-hash it points to. You can ask the object for a copy with the I<hash>
+hash it points to. You can ask the object for a copy with the I<hash>
method.
TABLE can only be omitted when a dervived class overrides the table method.
=cut
-sub new {
+sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
@@ -192,10 +192,10 @@ sub new {
carp "warning: FS::Record::new called with table name ". $self->{'Table'}
unless $nowarn_classload;
}
-
+
$self->{'Hash'} = shift;
- foreach my $field ( grep !defined($self->{'Hash'}{$_}), $self->fields ) {
+ foreach my $field ( grep !defined($self->{'Hash'}{$_}), $self->fields ) {
$self->{'Hash'}{$field}='';
}
@@ -489,6 +489,26 @@ sub qsearch {
croak $error;
}
+
+ # Determine how to format rows returned form a union query:
+ #
+ # * When all queries involved in the union are from the same table:
+ # Return an array of FS::$table_name objects
+ #
+ # * When union query is performed on multiple tables,
+ # Return an array of FS::Record objects
+ # ! Note: As far as I can tell, this functionality was broken, and
+ # ! actually results in a crash. Behavior is left intact
+ # ! as-is, in case the results are in use somewhere
+ #
+ # * Union query is performed on multiple table,
+ # and $union_options{classname_from_column} = 1
+ # Return an array of FS::$classname objects, where $classname is
+ # derived for each row from a static field inserted each returned
+ # row of data.
+ # e.g.: SELECT custnum,first,last,'cust_main' AS `__classname`'.
+
+
my $table = $stable[0];
my $pkey = '';
$table = '' if grep { $_ ne $table } @stable;
@@ -508,7 +528,21 @@ sub qsearch {
#below was refactored out to _from_hashref, this should use it at some point
my @return;
- if ( eval 'scalar(@FS::'. $table. '::ISA);' ) {
+ if ($union_options{classname_from_column}) {
+
+ # todo
+ # I'm not implementing the cache for this use case, at least not yet
+ # -mjackson
+
+ for my $row (@stuff) {
+ my $table_class = $row->{__classname}
+ or die "`__classname` column must be set when ".
+ "using \$union_options{classname_from_column}";
+ push @return, new("FS::$table_class",$row);
+ }
+
+ }
+ elsif ( eval 'scalar(@FS::'. $table. '::ISA);' ) {
if ( eval 'FS::'. $table. '->can(\'new\')' eq \&new ) {
#derivied class didn't override new method, so this optimization is safe
if ( $cache ) {
@@ -531,12 +565,12 @@ sub qsearch {
# Check for encrypted fields and decrypt them.
## only in the local copy, not the cached object
no warnings 'deprecated'; # XXX silence the warning for now
- if ( $conf_encryption
+ if ( $conf_encryption
&& eval '@FS::'. $table . '::encrypted_fields' ) {
foreach my $record (@return) {
foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
- next if $field eq 'payinfo'
- && ($record->isa('FS::payinfo_transaction_Mixin')
+ next if $field eq 'payinfo'
+ && ($record->isa('FS::payinfo_transaction_Mixin')
|| $record->isa('FS::payinfo_Mixin') )
&& $record->payby
&& !grep { $record->payby eq $_ } @encrypt_payby;
@@ -657,7 +691,7 @@ sub _query {
push @statement, $statement;
warn "[debug]$me $statement\n" if $DEBUG > 1 || $debug;
-
+
foreach my $field (
grep defined( $record->{$_} ) && $record->{$_} ne '', @real_fields
@@ -740,12 +774,12 @@ sub _from_hashref {
# Check for encrypted fields and decrypt them.
## only in the local copy, not the cached object
- if ( $conf_encryption
+ if ( $conf_encryption
&& eval '@FS::'. $table . '::encrypted_fields' ) {
foreach my $record (@return) {
foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
- next if $field eq 'payinfo'
- && ($record->isa('FS::payinfo_transaction_Mixin')
+ next if $field eq 'payinfo'
+ && ($record->isa('FS::payinfo_transaction_Mixin')
|| $record->isa('FS::payinfo_Mixin') )
&& $record->payby
&& !grep { $record->payby eq $_ } @encrypt_payby;
@@ -772,7 +806,7 @@ sub get_real_fields {
$alias_main ||= $table;
## could be optimized more for readability
- return (
+ return (
map {
my $op = '=';
@@ -833,7 +867,7 @@ sub get_real_fields {
}
} @{ $real_fields }
- );
+ );
}
=item by_key PRIMARY_KEY_VALUE
@@ -871,7 +905,7 @@ single SELECT spanning multiple tables, and cache the results for subsequent
method calls. Interface will almost definately change in an incompatible
fashion.
-Arguments:
+Arguments:
=cut
@@ -955,7 +989,7 @@ sub get {
# to avoid "Use of unitialized value" errors
if ( defined ( $self->{Hash}->{$field} ) ) {
$self->{Hash}->{$field};
- } else {
+ } else {
'';
}
}
@@ -970,7 +1004,7 @@ Sets the value of the column/field/key COLUMN to VALUE. Returns VALUE.
=cut
-sub set {
+sub set {
my($self,$field,$value) = @_;
$self->{'modified'} = 1;
$self->{'Hash'}->{$field} = $value;
@@ -1029,7 +1063,7 @@ sub AUTOLOAD {
my %search = ( $foreign_column => $pkey_value );
# FS::Record->$method() ? they're actually just subs :/
- if ( $method eq 'qsearchs' ) {
+ if ( $method eq 'qsearchs' ) {
return $pkey_value ? qsearchs( $table, \%search ) : '';
} elsif ( $method eq 'qsearch' ) {
return $pkey_value ? qsearch( $table, \%search ) : ();
@@ -1043,7 +1077,7 @@ sub AUTOLOAD {
$self->setfield($field,$value);
} else {
$self->getfield($field);
- }
+ }
}
# efficient (also, old, doesn't support FK stuff)
@@ -1054,7 +1088,7 @@ sub AUTOLOAD {
# $_[0]->setfield($field, $_[1]);
# } else {
# $_[0]->getfield($field);
-# }
+# }
#}
# get_fk_method(TABLE, FIELD)
@@ -1175,7 +1209,7 @@ sub hash {
my($self) = @_;
confess $self. ' -> hash: Hash attribute is undefined'
unless defined($self->{'Hash'});
- %{ $self->{'Hash'} };
+ %{ $self->{'Hash'} };
}
=item hashref
@@ -1331,14 +1365,14 @@ sub insert {
}
my $table = $self->table;
-
+
# Encrypt before the database
if ( scalar( eval '@FS::'. $table . '::encrypted_fields')
&& $conf_encryption
) {
foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
- next if $field eq 'payinfo'
- && ($self->isa('FS::payinfo_transaction_Mixin')
+ next if $field eq 'payinfo'
+ && ($self->isa('FS::payinfo_transaction_Mixin')
|| $self->isa('FS::payinfo_Mixin') )
&& $self->payby
&& !grep { $self->payby eq $_ } @encrypt_payby;
@@ -1361,7 +1395,7 @@ sub insert {
$statement .= 'DEFAULT VALUES';
} else {
-
+
if ( $use_placeholders ) {
@bind_values = map $self->getfield($_), @real_fields;
@@ -1395,7 +1429,7 @@ sub insert {
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
- local $SIG{QUIT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
@@ -1405,7 +1439,7 @@ sub insert {
# get inserted id from the database, if applicable & needed
if ( $db_seq && ! $self->getfield($primary_key) ) {
warn "[debug]$me retreiving sequence from database\n" if $DEBUG;
-
+
my $insertid = '';
if ( driver_name eq 'Pg' ) {
@@ -1454,7 +1488,7 @@ sub insert {
} else {
dbh->rollback if $FS::UID::AutoCommit;
- return "don't know how to retreive inserted ids from ". driver_name.
+ return "don't know how to retreive inserted ids from ". driver_name.
", try using counterfiles (maybe run dbdef-create?)";
}
@@ -1478,7 +1512,7 @@ sub insert {
dbh->commit or croak dbh->errstr if $FS::UID::AutoCommit;
- # Now that it has been saved, reset the encrypted fields so that $new
+ # Now that it has been saved, reset the encrypted fields so that $new
# can still be used.
foreach my $field (keys %{$saved}) {
$self->setfield($field, $saved->{$field});
@@ -1537,7 +1571,7 @@ sub delete {
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
- local $SIG{QUIT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
@@ -1545,7 +1579,7 @@ sub delete {
my $rc = $sth->execute or return $sth->errstr;
#not portable #return "Record not found, statement:\n$statement" if $rc eq "0E0";
$h_sth->execute or return $h_sth->errstr if $h_sth;
-
+
dbh->commit or croak dbh->errstr if $FS::UID::AutoCommit;
#no need to needlessly destoy the data either (causes problems actually)
@@ -1595,15 +1629,15 @@ sub replace {
my $error = $new->check;
return $error if $error;
-
+
# Encrypt for replace
my $saved = {};
if ( scalar( eval '@FS::'. $new->table . '::encrypted_fields')
&& $conf_encryption
) {
foreach my $field (eval '@FS::'. $new->table . '::encrypted_fields') {
- next if $field eq 'payinfo'
- && ($new->isa('FS::payinfo_transaction_Mixin')
+ next if $field eq 'payinfo'
+ && ($new->isa('FS::payinfo_transaction_Mixin')
|| $new->isa('FS::payinfo_Mixin') )
&& $new->payby
&& !grep { $new->payby eq $_ } @encrypt_payby;
@@ -1615,7 +1649,7 @@ sub replace {
#my @diff = grep $new->getfield($_) ne $old->getfield($_), $old->fields;
my %diff = map { ($new->getfield($_) ne $old->getfield($_))
? ($_, $new->getfield($_)) : () } $old->fields;
-
+
unless (keys(%diff) || $no_update_diff ) {
carp "[warning]$me ". ref($new)."->replace ".
( $primary_key ? "$primary_key ".$new->get($primary_key) : '' ).
@@ -1626,7 +1660,7 @@ sub replace {
my $statement = "UPDATE ". $old->table. " SET ". join(', ',
map {
- "$_ = ". _quote($new->getfield($_),$old->table,$_)
+ "$_ = ". _quote($new->getfield($_),$old->table,$_)
} real_fields($old->table)
). ' WHERE '.
join(' AND ',
@@ -1676,7 +1710,7 @@ sub replace {
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
- local $SIG{QUIT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
local $SIG{PIPE} = 'IGNORE';
@@ -1688,7 +1722,7 @@ sub replace {
dbh->commit or croak dbh->errstr if $FS::UID::AutoCommit;
- # Now that it has been saved, reset the encrypted fields so that $new
+ # Now that it has been saved, reset the encrypted fields so that $new
# can still be used.
foreach my $field (keys %{$saved}) {
$new->setfield($field, $saved->{$field});
@@ -1732,7 +1766,7 @@ non-custom fields, etc., and call this method via $self->SUPER::check.
=cut
-sub check {
+sub check {
my $self = shift;
foreach my $field ($self->virtual_fields) {
my $error = $self->ut_textn($field);
@@ -1743,7 +1777,7 @@ sub check {
=item virtual_fields [ TABLE ]
-Returns a list of virtual fields defined for the table. This should not
+Returns a list of virtual fields defined for the table. This should not
be exported, and should only be called as an instance or class method.
=cut
@@ -1837,8 +1871,8 @@ format_types).
=back
-PARAMS is a hashref (or base64-encoded Storable hashref) containing the
-POSTed data. It must contain the field "uploaded files", generated by
+PARAMS is a hashref (or base64-encoded Storable hashref) containing the
+POSTed data. It must contain the field "uploaded files", generated by
/elements/file-upload.html and containing the list of uploaded files.
Currently only supports a single file named "file".
@@ -1853,7 +1887,7 @@ sub process_batch_import {
my %formats = %{ $opt->{formats} };
warn Dumper($param) if $DEBUG;
-
+
my $files = $param->{'uploaded_files'}
or die "No files provided.\n";
@@ -2193,7 +2227,7 @@ sub batch_import {
next if $line =~ /^\s*$/; #skip empty lines
$line = &{$row_callback}($line) if $row_callback;
-
+
next if $line =~ /^\s*$/; #skip empty lines
$parser->parse($line) or do {
@@ -2246,7 +2280,7 @@ sub batch_import {
foreach my $field ( @fields ) {
my $value = shift @columns;
-
+
if ( ref($field) eq 'CODE' ) {
#&{$field}(\%hash, $value);
push @later, $field, $value;
@@ -2371,7 +2405,7 @@ sub _h_statement {
=item unique COLUMN
-B<Warning>: External use is B<deprecated>.
+B<Warning>: External use is B<deprecated>.
Replaces COLUMN in record with a unique number, using counters in the
filesystem. Used by the B<insert> method on single-field unique columns
@@ -2542,7 +2576,7 @@ sub ut_numbern {
=item ut_decimal COLUMN[, DIGITS]
-Check/untaint decimal numbers (up to DIGITS decimal places. If there is an
+Check/untaint decimal numbers (up to DIGITS decimal places. If there is an
error, returns the error, otherwise returns false.
=item ut_decimaln COLUMN[, DIGITS]
@@ -2707,7 +2741,7 @@ error, returns the error, otherwise returns false.
sub ut_alphan {
my($self,$field)=@_;
- $self->getfield($field) =~ /^(\w*)$/
+ $self->getfield($field) =~ /^(\w*)$/
or return "Illegal (alphanumeric) $field: ". $self->getfield($field);
$self->setfield($field,$1);
'';
@@ -2722,7 +2756,7 @@ an error, returns the error, otherwise returns false.
sub ut_alphasn {
my($self,$field)=@_;
- $self->getfield($field) =~ /^([\w ]*)$/
+ $self->getfield($field) =~ /^([\w ]*)$/
or return "Illegal (alphanumeric) $field: ". $self->getfield($field);
$self->setfield($field,$1);
'';
@@ -3041,8 +3075,8 @@ sub ut_name {
$self->getfield($field) =~ /^([\p{Word} \,\.\-\']+)$/
or return gettext('illegal_name'). " $field: ". $self->getfield($field);
my $name = $1;
- $name =~ s/^\s+//;
- $name =~ s/\s+$//;
+ $name =~ s/^\s+//;
+ $name =~ s/\s+$//;
$name =~ s/\s+/ /g;
$self->setfield($field, $name);
'';
@@ -3123,7 +3157,7 @@ see L<Locale::Country>.
sub ut_country {
my( $self, $field ) = @_;
unless ( $self->getfield($field) =~ /^(\w\w)$/ ) {
- if ( $self->getfield($field) =~ /^([\w \,\.\(\)\']+)$/
+ if ( $self->getfield($field) =~ /^([\w \,\.\(\)\']+)$/
&& country2code($1) ) {
$self->setfield($field,uc(country2code($1)));
}
@@ -3379,7 +3413,7 @@ sub loadRSA {
if ($conf_encryptionpublickey && $conf_encryptionpublickey ne '') {
$rsa_encrypt = $rsa_module->new_public_key($conf_encryptionpublickey);
}
-
+
# Intitalize Decryption
if ($conf_encryptionprivatekey && $conf_encryptionprivatekey ne '') {
$rsa_decrypt = $rsa_module->new_private_key($conf_encryptionprivatekey);
@@ -3447,8 +3481,8 @@ sub scalar_sql {
=item count [ WHERE [, PLACEHOLDER ...] ]
-Convenience method for the common case of "SELECT COUNT(*) FROM table",
-with optional WHERE. Must be called as method on a class with an
+Convenience method for the common case of "SELECT COUNT(*) FROM table",
+with optional WHERE. Must be called as method on a class with an
associated table.
=cut
@@ -3485,7 +3519,7 @@ sub row_exists {
=item real_fields [ TABLE ]
-Returns a list of the real columns in the specified table. Called only by
+Returns a list of the real columns in the specified table. Called only by
fields() and other subroutines elsewhere in FS::Record.
=cut
@@ -3500,7 +3534,7 @@ sub real_fields {
=item pvf FIELD_NAME
-Returns the FS::part_virtual_field object corresponding to a field in the
+Returns the FS::part_virtual_field object corresponding to a field in the
record (specified by FIELD_NAME).
=cut
@@ -3513,7 +3547,7 @@ sub pvf {
my $concat = [ "'cf_'", "name" ];
return qsearchs({ table => 'part_virtual_field',
hashref => { dbtable => $self->table,
- name => $name
+ name => $name
},
select => 'vfieldpart, dbtable, length, label, '.concat_sql($concat).' as name',
});
@@ -3547,7 +3581,7 @@ sub _quote {
cluck "WARNING: Attempting to set non-null integer $table.$column null; ".
"using 0 instead";
0;
- } elsif ( $value =~ /^\d+(\.\d+)?$/ &&
+ } elsif ( $value =~ /^\d+(\.\d+)?$/ &&
! $column_type =~ /(char|binary|text)$/i ) {
$value;
} elsif (( $column_type =~ /^bytea$/i || $column_type =~ /(blob|varbinary)/i )
@@ -3611,7 +3645,7 @@ the current database.
=cut
-sub str2time_sql {
+sub str2time_sql {
my $driver = shift || driver_name;
return 'UNIX_TIMESTAMP(' if $driver =~ /^mysql/i;
@@ -3634,7 +3668,7 @@ the current database.
=cut
-sub str2time_sql_closing {
+sub str2time_sql_closing {
my $driver = shift || driver_name;
return ' )::INTEGER ' if $driver =~ /^Pg/i;
@@ -3708,7 +3742,7 @@ sub concat_sql {
=item group_concat_sql COLUMN, DELIMITER
-Returns an SQL expression to concatenate an aggregate column, using
+Returns an SQL expression to concatenate an aggregate column, using
GROUP_CONCAT() for mysql and array_to_string() and array_agg() for Pg.
=cut
@@ -3726,7 +3760,7 @@ sub group_concat_sql {
=item midnight_sql DATE
-Returns an SQL expression to convert DATE (a unix timestamp) to midnight
+Returns an SQL expression to convert DATE (a unix timestamp) to midnight
on that day in the system timezone, using the default driver name.
=cut
@@ -3798,4 +3832,3 @@ http://poop.sf.net/
=cut
1;
-