Rose-Model Wiederkehrende Rechnungen: Foreign Key "order" nennen, nicht "oe"
[kivitendo-erp.git] / scripts / rose_auto_create_model.pl
index 6b6db0a..7aab083 100755 (executable)
@@ -31,7 +31,6 @@ my %blacklist     = SL::DB::Helper::Mappings->get_blacklist;
 my %package_names = SL::DB::Helper::Mappings->get_package_names;
 
 our $form;
-our $cgi;
 our $auth;
 our %lx_office_conf;
 
@@ -45,6 +44,18 @@ our $meta_path = "SL/DB/MetaSetup";
 
 my %config;
 
+our %foreign_key_name_map = (
+  oe                   => { payment => 'payment_terms', },
+  ar                   => { payment => 'payment_terms', },
+  ap                   => { payment => 'payment_terms', },
+
+  orderitems           => { parts => 'part', trans => 'order', },
+  delivery_order_items => { parts => 'part' },
+  invoice              => { parts => 'part' },
+
+  periodic_invoices_configs => { oe => 'order' },
+);
+
 sub setup {
 
   SL::LxOfficeConf->read;
@@ -56,13 +67,13 @@ sub setup {
     usage();
   }
 
-  $::lxdebug    = LXDebug->new();
+  $::lxdebug      = LXDebug->new();
   $::locale       = Locale->new("de");
   $::form         = new Form;
-  $::cgi          = new CGI('');
   $::auth         = SL::Auth->new();
-  $::user         = User->new($login);
-  %::myconfig     = $auth->read_user($login);
+  $::user         = User->new(login => $login);
+  %::myconfig     = $auth->read_user(login => $login);
+  $::request      = { cgi => CGI->new({}) };
   $form->{script} = 'rose_meta_data.pl';
   $form->{login}  = $login;
 
@@ -104,6 +115,11 @@ CODE
   }
 
   $definition =~ s/::AUTO::/::/g;
+
+  while (my ($auto_generated_name, $desired_name) = each %{ $foreign_key_name_map{$table} || {} }) {
+    $definition =~ s/( foreign_keys \s*=> \s*\[ .* ^\s+ ) ${auto_generated_name} \b/${1}${desired_name}/msx;
+  }
+
   my $full_definition = <<CODE;
 # This file has been auto-generated. Do not modify it; it will be overwritten
 # by $::script automatically.
@@ -129,13 +145,16 @@ CODE
   my $file_exists = -f $meta_file;
   if ($file_exists) {
     my $old_size    = -s $meta_file;
-    my $old_md5     = md5_hex(do { local(@ARGV, $/) = ($meta_file); <> });
+    my $orig_file   = do { local(@ARGV, $/) = ($meta_file); <> };
+    my $old_md5     = md5_hex($orig_file);
     my $new_size    = length $full_definition;
     my $new_md5     = md5_hex($full_definition);
     if ($old_size == $new_size && $old_md5 == $new_md5) {
       notice("No changes in $meta_file, skipping.") if $config{verbose};
       return;
     }
+
+    show_diff(\$orig_file, \$full_definition) if $config{show_diff};
   }
 
   if (!$config{nocommit}) {
@@ -158,19 +177,41 @@ CODE
 sub parse_args {
   my ($options) = @_;
   GetOptions(
-    'login|user=s'  => \ my $login,
-    all             => \ my $all,
-    sugar           => \ my $sugar,
-    'no-commit'     => \ my $nocommit,
-    help            => sub { pod2usage(verbose => 99, sections => 'NAME|SYNOPSIS|OPTIONS') },
-    verbose         => \ my $verbose,
+    'login|user=s'      => \ my $login,
+    all                 => \ my $all,
+    'no-commit|dry-run' => \ my $nocommit,
+    help                => sub { pod2usage(verbose => 99, sections => 'NAME|SYNOPSIS|OPTIONS') },
+    verbose             => \ my $verbose,
+    diff                => \ my $diff,
   );
 
   $options->{login}    = $login if $login;
-  $options->{sugar}    = $sugar;
   $options->{all}      = $all;
   $options->{nocommit} = $nocommit;
   $options->{verbose}  = $verbose;
+
+  if ($diff) {
+    if (eval { require Text::Diff; 1 }) {
+      $options->{show_diff} = 1;
+    } else {
+      error('Could not load Text::Diff. Sorry, no diffs for you.');
+    }
+  }
+}
+
+sub show_diff {
+   my ($text_a, $text_b) = @_;
+
+   my %colors = (
+     '+' => 'green',
+     '-' => 'red',
+   );
+
+   Text::Diff::diff($text_a, $text_b, { OUTPUT => sub {
+     for (split /\n/, $_[0]) {
+       print colored($_, $colors{substr($_, 0, 1)}), $/;
+     }
+   }});
 }
 
 sub usage {
@@ -179,17 +220,16 @@ sub usage {
 
 sub make_tables {
   my @tables;
-  if ($config{all} || $config{sugar}) {
-    my ($type, $prefix) = $config{sugar} ? ('SUGAR', 'sugar_') : ('LXOFFICE', '');
-    my $db              = SL::DB::create(undef, $type);
-    @tables             =
-      map { $package_names{$type}->{$_} ? "$_=" . $package_names{$type}->{$_} : $prefix ? "$_=$prefix$_" : $_ }
-      grep { my $table = $_; !any { $_ eq $table } @{ $blacklist{$type} } }
+  if ($config{all}) {
+    my $db  = SL::DB::create(undef, 'LXOFFICE');
+    @tables =
+      map { $package_names{LXOFFICE}->{$_} ? "$_=" . $package_names{LXOFFICE}->{$_} : $_ }
+      grep { my $table = $_; !any { $_ eq $table } @{ $blacklist{LXOFFICE} } }
       $db->list_tables;
   } elsif (@ARGV) {
     @tables = @ARGV;
   } else {
-    error("You specified neither --sugar nor --all nor any specific tables.");
+    error("You specified neither --all nor any specific tables.");
     usage();
   }
 
@@ -223,12 +263,12 @@ __END__
 
 =head1 NAME
 
-rose_auto_create_model - mana Rose::DB::Object classes for Lx-Office
+rose_auto_create_model - mana Rose::DB::Object classes for kivitendo
 
 =head1 SYNOPSIS
 
   scripts/rose_create_model.pl --login login table1[=package1] [table2[=package2] ...]
-  scripts/rose_create_model.pl --login login [--all|-a] [--sugar|-s]
+  scripts/rose_create_model.pl --login login [--all|-a]
 
   # updates all models
   scripts/rose_create_model.pl --login login --all
@@ -268,12 +308,19 @@ database connection, and the piece of mind that comes from knowing that your
 class is stable, and won't change behind your back in response to an "action at
 a distance" (i.e., a database schema update).>
 
-Unfortunately this ready easier than it is, since classes need to get in the
-right package and directory, certain stuff need to be adjusted and table names
+Unfortunately this reads easier than it is, since classes need to go into the
+right package and directory, certain stuff needs to be adjusted and table names
 need to be translated into their class names. This script will wrap all that
 behind a few simple options.
 
-In the most basic version, just give it a login and
+In the most basic version, just give it a login and a table name, and it will
+load the schema information for this table and create the appropriate class
+files, or update them if already present.
+
+Each table has two associated files. A C<SL::DB::MetaSetup::*> class, which is
+a perl version of the schema definition, and a C<SL::DB::*> class file. The
+first one will be updated if the schema changes, the second one will only be
+created if it does not exist.
 
 =head1 OPTIONS
 
@@ -291,15 +338,17 @@ C<devel/login>. If that too is not found, an error is thrown.
 Process all tables from the database. Only those that are blacklistes in
 L<SL::DB::Helper::Mappings> are excluded.
 
-=item C<--sugar, -s>
-
-Process tables in sugar schema instead of standard schema. Rarely useful unless
-you debug schema awareness of the RDBO layer.
-
 =item C<--no-commit, -n>
 
+=item C<--dry-run>
+
 Do not write back generated files. This will do everything as usual but not
-actually modify any files.
+actually modify any file.
+
+=item C<--diff>
+
+Displays diff for selected file, if file is present and newer file is
+different. Beware, does not imply C<--no-commit>.
 
 =item C<--help, -h>