RT##29285: State field not needed for New Zealand
authorJonathan Prykop <jonathan@freeside.biz>
Tue, 30 Jun 2015 08:24:08 +0000 (03:24 -0500)
committerJonathan Prykop <jonathan@freeside.biz>
Fri, 3 Jul 2015 04:53:46 +0000 (23:53 -0500)
FS/FS/Conf.pm
FS/FS/Schema.pm
FS/FS/UI/Web/small_custview.pm
FS/FS/cust_location.pm
FS/FS/cust_pay_batch.pm
httemplate/edit/cust_main/top_misc.html
httemplate/elements/city.html
httemplate/elements/location.html
httemplate/elements/standardize_locations.js

index fa612c0..4c6b1e4 100644 (file)
@@ -3397,14 +3397,6 @@ and customer address. Include units.',
   },
 
   {
   },
 
   {
-    'key'         => 'city_not_required',
-    'section'     => 'required',
-    'description' => 'Turn off requirement for a City to be entered for billing & shipping addresses',
-    'type'        => 'checkbox',
-    'per_agent'   => 1,
-  },
-
-  {
     'key'         => 'echeck-void',
     'section'     => 'deprecated',
     'description' => '<B>DEPRECATED</B>, now controlled by ACLs.  Used to enable local-only voiding of echeck payments in addition to refunds against the payment gateway',
     'key'         => 'echeck-void',
     'section'     => 'deprecated',
     'description' => '<B>DEPRECATED</B>, now controlled by ACLs.  Used to enable local-only voiding of echeck payments in addition to refunds against the payment gateway',
@@ -4561,6 +4553,13 @@ and customer address. Include units.',
   },
 
   {
   },
 
   {
+    'key'         => 'cust_main-no_city_in_address',
+    'section'     => 'UI',
+    'description' => 'Turn off City for billing & shipping addresses',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'census_year',
     'section'     => 'UI',
     'description' => 'The year to use in census tract lookups.  NOTE: you need to select 2012 or 2013 for Year 2010 Census tract codes.  A selection of 2011 provides Year 2000 Census tract codes.  Use the freeside-censustract-update tool if exisitng customers need to be changed.',
     'key'         => 'census_year',
     'section'     => 'UI',
     'description' => 'The year to use in census tract lookups.  NOTE: you need to select 2012 or 2013 for Year 2010 Census tract codes.  A selection of 2011 provides Year 2000 Census tract codes.  Use the freeside-censustract-update tool if exisitng customers need to be changed.',
index fc6d301..40c61bb 100644 (file)
@@ -1420,7 +1420,7 @@ sub tables_hashref {
         'locationname',    'varchar', 'NULL', $char_d, '', '',
         'address1',        'varchar',     '', $char_d, '', '', 
         'address2',        'varchar', 'NULL', $char_d, '', '', 
         'locationname',    'varchar', 'NULL', $char_d, '', '',
         'address1',        'varchar',     '', $char_d, '', '', 
         'address2',        'varchar', 'NULL', $char_d, '', '', 
-        'city',            'varchar',     '', $char_d, '', '', 
+        'city',            'varchar', 'NULL', $char_d, '', '', 
         'county',          'varchar', 'NULL', $char_d, '', '', 
         'state',           'varchar', 'NULL', $char_d, '', '', 
         'zip',             'varchar', 'NULL',      10, '', '', 
         'county',          'varchar', 'NULL', $char_d, '', '', 
         'state',           'varchar', 'NULL', $char_d, '', '', 
         'zip',             'varchar', 'NULL',      10, '', '', 
@@ -1868,7 +1868,7 @@ sub tables_hashref {
         'first',    'varchar', '',     $char_d, '', '', 
         'address1', 'varchar', '',     $char_d, '', '', 
         'address2', 'varchar', 'NULL', $char_d, '', '', 
         'first',    'varchar', '',     $char_d, '', '', 
         'address1', 'varchar', '',     $char_d, '', '', 
         'address2', 'varchar', 'NULL', $char_d, '', '', 
-        'city',     'varchar', '',     $char_d, '', '', 
+        'city',     'varchar', 'NULL',     $char_d, '', '', 
         'state',    'varchar', 'NULL', $char_d, '', '', 
         'zip',      'varchar', 'NULL', 10, '', '', 
         'country',  'char', '',     2, '', '', 
         'state',    'varchar', 'NULL', $char_d, '', '', 
         'zip',      'varchar', 'NULL', 10, '', '', 
         'country',  'char', '',     2, '', '', 
index b98bca0..1e9ddb1 100644 (file)
@@ -127,7 +127,9 @@ sub small_custview {
   $html .= encode_entities($cust_main->address1). '<BR>';
   $html .= encode_entities($cust_main->address2). '<BR>'
     if $cust_main->address2;
   $html .= encode_entities($cust_main->address1). '<BR>';
   $html .= encode_entities($cust_main->address2). '<BR>'
     if $cust_main->address2;
-  $html .= encode_entities($cust_main->city). ', '. $cust_main->state. '  '.
+  $html .= encode_entities($cust_main->city) . ', ' if $cust_main->city;
+  $html .= $cust_main->state. '  '.
+           $cust_main->zip. '<BR>';
            $cust_main->zip. '<BR>';
   $html .= $cust_main->country. '<BR>'
     if $cust_main->country && $cust_main->country ne $countrydefault;
            $cust_main->zip. '<BR>';
   $html .= $cust_main->country. '<BR>'
     if $cust_main->country && $cust_main->country ne $countrydefault;
@@ -156,7 +158,7 @@ sub small_custview {
       $cust_main->ship_company,
       $ship->address1,
       $ship->address2,
       $cust_main->ship_company,
       $ship->address1,
       $ship->address2,
-      ($ship->city . ', ' . $ship->state . '  ' . $ship->zip),
+      (($ship->city ? $ship->city . ', ' : '') . $ship->state . '  ' . $ship->zip),
       ($ship->country eq $countrydefault ? '' : $ship->country ),
   );
 
       ($ship->country eq $countrydefault ? '' : $ship->country ),
   );
 
index ad6d706..4f0bd9b 100644 (file)
@@ -68,7 +68,7 @@ Address line two (optional)
 
 =item city
 
 
 =item city
 
-City
+City (optional only if cust_main-no_city_in_address config is set)
 
 =item county
 
 
 =item county
 
@@ -144,9 +144,20 @@ sub find_or_insert {
 
   warn "find_or_insert:\n".Dumper($self) if $DEBUG;
 
 
   warn "find_or_insert:\n".Dumper($self) if $DEBUG;
 
-  my @essential = (qw(custnum address1 address2 city county state zip country
+  my @essential = (qw(custnum address1 address2 county state zip country
     location_number location_type location_kind disabled));
 
     location_number location_type location_kind disabled));
 
+  # Just in case this conf was accidentally/temporarily set,
+  # we'll never overwrite existing city; see city method
+  if ($conf->exists('cust_main-no_city_in_address')) {
+    warn "Warning: find_or_insert specified city when cust_main-no_city_in_address was configured"
+      if $self->get('city');
+    $self->set('city',''); # won't end up in %nonempty, hence old value is preserved
+  } else {
+    # otherwise, of course, city is essential
+    push(@essential,'city') 
+  }
+
   # I don't think this is necessary
   #if ( !$self->coord_auto and $self->latitude and $self->longitude ) {
   #  push @essential, qw(latitude longitude);
   # I don't think this is necessary
   #if ( !$self->coord_auto and $self->latitude and $self->longitude ) {
   #  push @essential, qw(latitude longitude);
@@ -202,6 +213,11 @@ otherwise returns false.
 sub insert {
   my $self = shift;
 
 sub insert {
   my $self = shift;
 
+  # Ideally, this should never happen,
+  # but throw a warning and save the value anyway, to avoid data loss
+  warn "Warning: inserting city when cust_main-no_city_in_address is configured"
+    if $conf->exists('cust_main-no_city_in_address') && $self->get('city');
+
   if ( $self->censustract ) {
     $self->set('censusyear' => $conf->config('census_year') || 2012);
   }
   if ( $self->censustract ) {
     $self->set('censusyear' => $conf->config('census_year') || 2012);
   }
@@ -266,6 +282,15 @@ sub replace {
   my $self = shift;
   my $old = shift;
   $old ||= $self->replace_old;
   my $self = shift;
   my $old = shift;
   $old ||= $self->replace_old;
+
+  # Just in case this conf was accidentally/temporarily set,
+  # we'll never overwrite existing city; see city method
+  if ($conf->exists('cust_main-no_city_in_address')) {
+    warn "Warning: replace attempted to change city when cust_main-no_city_in_address was configured"
+      if $self->get('city') && ($old->get('city') != $self->get('city'));
+    $self->set('city',$old->get('city'));
+  }
+
   # the following fields are immutable
   foreach (qw(address1 address2 city state zip country)) {
     if ( $self->$_ ne $old->$_ ) {
   # the following fields are immutable
   foreach (qw(address1 address2 city state zip country)) {
     if ( $self->$_ ne $old->$_ ) {
@@ -325,7 +350,9 @@ sub check {
     || $self->ut_textn('locationname')
     || $self->ut_text('address1')
     || $self->ut_textn('address2')
     || $self->ut_textn('locationname')
     || $self->ut_text('address1')
     || $self->ut_textn('address2')
-    || $self->ut_text('city')
+    || ($conf->exists('cust_main-no_city_in_address') 
+        ? $self->ut_textn('city') 
+        : $self->ut_text('city'))
     || $self->ut_textn('county')
     || $self->ut_textn('state')
     || $self->ut_country('country')
     || $self->ut_textn('county')
     || $self->ut_textn('state')
     || $self->ut_country('country')
@@ -386,6 +413,30 @@ sub check {
   $self->SUPER::check;
 }
 
   $self->SUPER::check;
 }
 
+=item city
+
+When the I<cust_main-no_city_in_address> config is set, the
+city method will return a blank string no matter the previously
+set value of the field.  You can still use the get method to
+access the contents of the field directly.
+
+Just in case this config was accidentally/temporarily set,
+we'll never overwrite existing city while the config is active.
+L</find_or_insert> will throw a warning if passed any true value for city,
+ignore the city field when finding, and preserve the existing value.
+L</replace> will only throw a warning if passed a true value that is 
+different than the existing value of city, and will preserve the existing value.
+L</insert> will throw a warning but still insert a true city value,
+to avoid unnecessary data loss.
+
+=cut
+
+sub city {
+  my $self = shift;
+  return '' if $conf->exists('cust_main-no_city_in_address');
+  return $self->get('city');
+}
+
 =item country_full
 
 Returns this locations's full country name
 =item country_full
 
 Returns this locations's full country name
@@ -735,25 +786,29 @@ names in order.
 
 =cut
 
 
 =cut
 
+### Is this actually used for anything anymore?  Grep doesn't show anything...
 sub in_county_sql {
   # replaces FS::cust_pkg::location_sql
   my ($class, %opt) = @_;
   my $ornull = $opt{ornull} ? ' OR ? IS NULL' : '';
   my $x = $ornull ? 3 : 2;
   my @fields = (('district') x 3,
 sub in_county_sql {
   # replaces FS::cust_pkg::location_sql
   my ($class, %opt) = @_;
   my $ornull = $opt{ornull} ? ' OR ? IS NULL' : '';
   my $x = $ornull ? 3 : 2;
   my @fields = (('district') x 3,
-                ('city') x 3,
                 ('county') x $x,
                 ('state') x $x,
                 'country');
 
                 ('county') x $x,
                 ('state') x $x,
                 'country');
 
+  unless ($conf->exists('cust_main-no_city_in_address')) {
+    push( @fields, (('city') x 3) );
+  }
+
   my $text = (driver_name =~ /^mysql/i) ? 'char' : 'text';
 
   my @where = (
     "cust_location.district = ? OR ? = '' OR CAST(? AS $text) IS NULL",
   my $text = (driver_name =~ /^mysql/i) ? 'char' : 'text';
 
   my @where = (
     "cust_location.district = ? OR ? = '' OR CAST(? AS $text) IS NULL",
-    "cust_location.city     = ? OR ? = '' OR CAST(? AS $text) IS NULL",
     "cust_location.county   = ? OR (? = '' AND cust_location.county IS NULL) $ornull",
     "cust_location.state    = ? OR (? = '' AND cust_location.state IS NULL ) $ornull",
     "cust_location.county   = ? OR (? = '' AND cust_location.county IS NULL) $ornull",
     "cust_location.state    = ? OR (? = '' AND cust_location.state IS NULL ) $ornull",
-    "cust_location.country = ?"
+    "cust_location.country = ?",
+    "cust_location.city     = ? OR ? = '' OR CAST(? AS $text) IS NULL"
   );
   my $sql = join(' AND ', map "($_)\n", @where);
   if ( $opt{param} ) {
   );
   my $sql = join(' AND ', map "($_)\n", @where);
   if ( $opt{param} ) {
index 2ab76d5..d28085c 100644 (file)
@@ -130,6 +130,8 @@ and replace methods.
 sub check {
   my $self = shift;
 
 sub check {
   my $self = shift;
 
+  my $conf = new FS::Conf;
+
   my $error = 
       $self->ut_numbern('paybatchnum')
     || $self->ut_numbern('trancode') #deprecated
   my $error = 
       $self->ut_numbern('paybatchnum')
     || $self->ut_numbern('trancode') #deprecated
@@ -138,7 +140,9 @@ sub check {
     || $self->ut_number('custnum')
     || $self->ut_text('address1')
     || $self->ut_textn('address2')
     || $self->ut_number('custnum')
     || $self->ut_text('address1')
     || $self->ut_textn('address2')
-    || $self->ut_text('city')
+    || ($conf->exists('cust_main-no_city_in_address') 
+        ? $self->ut_textn('city') 
+        : $self->ut_text('city'))
     || $self->ut_textn('state')
   ;
 
     || $self->ut_textn('state')
   ;
 
index 8f8a96a..c19f347 100644 (file)
@@ -40,7 +40,7 @@
 
   var ship_locked_agents = <% encode_json(\%ship_locked_agents) %>;
   var ship_fields = [
 
   var ship_locked_agents = <% encode_json(\%ship_locked_agents) %>;
   var ship_fields = [
-    'locationname', 'address1', 'city', 'state', 'zip', 'country', 
+    'locationname', 'address1',<% $conf->exists('cust_main-no_city_in_address') ? '' : q( 'city',) %> 'state', 'zip', 'country', 
     'latitude', 'longitude', 'district'
   ];
 
     'latitude', 'longitude', 'district'
   ];
 
@@ -276,7 +276,10 @@ foreach (qsearch('agent',{})) {
   my $agent_ship_location = $cust_main->ship_location;
   $ship_locked_agents{$agentnum} = +{
     map { $_ => $agent_ship_location->$_ }
   my $agent_ship_location = $cust_main->ship_location;
   $ship_locked_agents{$agentnum} = +{
     map { $_ => $agent_ship_location->$_ }
-    qw(locationname address1 city state zip country latitude longitude district)
+    (
+       qw(locationname address1 state zip country latitude longitude district),
+       ($conf->exists('cust_main-no_city_in_address') ? () : 'city')
+    )
   };
 }
 
   };
 }
 
index 5f4d4e0..4e9a609 100644 (file)
@@ -159,6 +159,11 @@ my $disable_select = 1 if $conf->config('tax_district_method');
 
 $opt{'disable_empty'} = 1 unless exists($opt{'disable_empty'});
 
 
 $opt{'disable_empty'} = 1 unless exists($opt{'disable_empty'});
 
+if ($conf->exists('cust_main-no_city_in_address')) {
+  $opt{'disable_text'} = 1;
+  $disable_select = 1;
+}
+
 my $text_style   = $opt{'style'} ? [ @{ $opt{'style'} } ] : [];
 my $select_style = $opt{'style'} ? [ @{ $opt{'style'} } ] : [];
 
 my $text_style   = $opt{'style'} ? [ @{ $opt{'style'} } ] : [];
 my $select_style = $opt{'style'} ? [ @{ $opt{'style'} } ] : [];
 
index 357a91d..b50509a 100644 (file)
@@ -169,15 +169,14 @@ Example:
 
 
 <TR>
 
 
 <TR>
-% if ($conf->exists('city_not_required')) {
-<input type="hidden" name="<% ($select_hash{'prefix'}) ? $select_hash{'prefix'} : '' %>city" value=" "/>
-%} else {
-  <<%$th%> ALIGN="right"><%$r%><% mt('City') |h %></<%$th%>>
+  <<%$th%> ALIGN="right">
+% unless ($conf->exists('cust_main-no_city_in_address')) {
+  <% $r %><% mt('City') |h %>
+% }
+  </<%$th%>>
   <TD WIDTH="1"><% include('/elements/city.html', %select_hash, 'text_style' => \@style ) %></TD>
   <TD WIDTH="1"><% include('/elements/city.html', %select_hash, 'text_style' => \@style ) %></TD>
-
   <<%$th%> ALIGN="right" WIDTH="1" ID="<%$pre%>countylabel" <%$county_style%>><%$r%>County</<%$th%>>
   <TD WIDTH="1"><% include('/elements/select-county.html', %select_hash ) %></TD>
   <<%$th%> ALIGN="right" WIDTH="1" ID="<%$pre%>countylabel" <%$county_style%>><%$r%>County</<%$th%>>
   <TD WIDTH="1"><% include('/elements/select-county.html', %select_hash ) %></TD>
-% }
   <<%$th%> ALIGN="right" WIDTH="1"><%$r%><% mt('State') |h %></<%$th%>>
   <TD WIDTH="1">
     <% include('/elements/select-state.html', %select_hash ) %>
   <<%$th%> ALIGN="right" WIDTH="1"><%$r%><% mt('State') |h %></<%$th%>>
   <TD WIDTH="1">
     <% include('/elements/select-state.html', %select_hash ) %>
@@ -290,7 +289,7 @@ Example:
   var clear_coords_on_change = [
     '<%$pre%>address1',
     '<%$pre%>address2',
   var clear_coords_on_change = [
     '<%$pre%>address1',
     '<%$pre%>address2',
-    '<%$pre%>city',
+    <% $conf->exists('cust_main-no_city_in_address') ? '' : qq('${pre}city',) %>
     '<%$pre%>state',
     '<%$pre%>zip',
     '<%$pre%>country'
     '<%$pre%>state',
     '<%$pre%>zip',
     '<%$pre%>country'
index f114e34..56b2be9 100644 (file)
@@ -13,7 +13,7 @@ function form_address_info() {
 % }
 % for my $pre (@prefixes) {
 %   # normal case
 % }
 % for my $pre (@prefixes) {
 %   # normal case
-%   for my $field (qw(address1 address2 city state zip country)) {
+%   for my $field (qw(address1 address2 state zip country), ($conf->exists('cust_main-no_city_in_address') ? () : 'city')) {
     returnobj['<% $pre %><% $field %>'] = cf.elements['<% $pre %><% $field %>'].value;
 %   } #for $field
 %   if ( $withcensus ) {
     returnobj['<% $pre %><% $field %>'] = cf.elements['<% $pre %><% $field %>'].value;
 %   } #for $field
 %   if ( $withcensus ) {
@@ -145,7 +145,7 @@ function replace_address() {
   var clean = newaddr['<% $pre %>addr_clean'] == 'Y';
   var error = newaddr['<% $pre %>error'];
   if ( clean ) {
   var clean = newaddr['<% $pre %>addr_clean'] == 'Y';
   var error = newaddr['<% $pre %>error'];
   if ( clean ) {
-%   foreach my $field (qw(address1 address2 city state zip addr_clean )) {
+%   foreach my $field (qw(address1 address2 state zip addr_clean ),($conf->exists('cust_main-no_city_in_address') ? () : 'city')) {
     cf.elements['<% $pre %><% $field %>'].value = newaddr['<% $pre %><% $field %>'];
 %   } #foreach $field
 
     cf.elements['<% $pre %><% $field %>'].value = newaddr['<% $pre %><% $field %>'];
 %   } #foreach $field