PriceRule: Korrektes Matching von Nulls
authorSven Schöling <s.schoeling@linet-services.de>
Thu, 11 Sep 2014 16:14:13 +0000 (18:14 +0200)
committerSven Schöling <s.schoeling@linet-services.de>
Thu, 18 Dec 2014 15:18:50 +0000 (16:18 +0100)
SL/DB/Manager/PriceRule.pm
SL/DB/Manager/PriceRuleItem.pm

index a3eeaff..e94fd15 100644 (file)
@@ -27,8 +27,7 @@ sub get_matching_filter {
   my $type = $params{record}->is_sales ? 'customer' : 'vendor';
 
   # plan: 1. search all rule_items that do NOT match this record/record item combo
-  my ($sub_where, @value_subs) = SL::DB::Manager::PriceRuleItem->not_matching_sql_and_values(type => $type);
-  my @values = map { $_->($params{record}, $params{record_item}) } @value_subs;
+  my ($sub_where, @values) = SL::DB::Manager::PriceRuleItem->not_matching_sql_and_values(type => $type, %params);
 
   # now union all NOT matching, invert ids, load these
   my $matching_rule_ids = <<SQL;
index ef6cc9c..6842d5b 100644 (file)
@@ -26,10 +26,10 @@ my %ops = (
 my %types = (
   'customer'            => { description => t8('Customer'),           customer => 1, vendor => 0, data_type => 'int',  data => sub { $_[0]->customer->id }, },
   'vendor'              => { description => t8('Vendor'),             customer => 0, vendor => 1, data_type => 'int',  data => sub { $_[0]->vendor->id }, },
-  'business'            => { description => t8('Type of Business'),   customer => 1, vendor => 1, data_type => 'int',  data => sub { $_[0]->customervendor->business_id }, },
+  'business'            => { description => t8('Type of Business'),   customer => 1, vendor => 1, data_type => 'int',  data => sub { $_[0]->customervendor->business_id }, exclude_nulls => 1 },
   'reqdate'             => { description => t8('Reqdate'),            customer => 1, vendor => 1, data_type => 'date', data => sub { $_[0]->reqdate }, ops => 'date' },
-  'pricegroup'          => { description => t8('Pricegroup'),         customer => 1, vendor => 1, data_type => 'int',  data => sub { $_[1]->pricegroup_id }, },
-  'partsgroup'          => { description => t8('Group'),              customer => 1, vendor => 1, data_type => 'int',  data => sub { $_[1]->part->partsgroup_id }, },
+  'pricegroup'          => { description => t8('Pricegroup'),         customer => 1, vendor => 1, data_type => 'int',  data => sub { $_[1]->pricegroup_id }, exclude_nulls => 1 },
+  'partsgroup'          => { description => t8('Group'),              customer => 1, vendor => 1, data_type => 'int',  data => sub { $_[1]->part->partsgroup_id }, exclude_nulls => 1 },
   'qty'                 => { description => t8('Qty'),                customer => 1, vendor => 1, data_type => 'num',  data => sub { $_[1]->qty }, ops => 'num' },
 );
 
@@ -37,6 +37,7 @@ sub not_matching_sql_and_values {
   my ($class, %params) = @_;
 
   die 'must be called with a customer/vendor type' unless $params{type};
+  my @args = @params{'record', 'record_item'};
 
   my (@tokens, @values);
 
@@ -44,19 +45,25 @@ sub not_matching_sql_and_values {
     my $def = $types{$type};
     next unless $def->{$params{type}};
 
-    if ($def->{ops}) {
-      my $ops = $ops{$def->{ops}};
+    my $value = $def->{data}->(@args);
 
+    if ($def->{exclude_nulls} && !defined $value) {
+      push @tokens, "type = '$type'";
+    } else {
       my @sub_tokens;
-      for (keys %$ops) {
-        push @sub_tokens, "op = '$_' AND NOT value_$def->{data_type} $ops->{$_} ?";
-        push @values, $def->{data};
+      if ($def->{ops}) {
+        my $ops = $ops{$def->{ops}};
+
+        for (keys %$ops) {
+          push @sub_tokens, "op = '$_' AND NOT value_$def->{data_type} $ops->{$_} ?";
+          push @values, $value;
+        }
+      } else {
+        push @sub_tokens, "NOT value_$def->{data_type} = ?";
+        push @values, $value;
       }
 
       push @tokens, "type = '$type' AND " . join ' OR ', map "($_)", @sub_tokens;
-    } else {
-      push @tokens, "type = '$type' AND NOT value_$def->{data_type} = ?";
-      push @values, $def->{data};
     }
   }