use Rose::Object::MakeMethods::Generic
(
- scalar => [ qw(type profile file all_profiles all_charsets sep_char all_sep_chars quote_char all_quote_chars escape_char all_escape_chars all_buchungsgruppen all_units
- import_status errors headers raw_data_headers info_headers data num_imported num_importable displayable_columns) ],
+ scalar => [ qw(type profile file all_profiles all_charsets sep_char all_sep_chars quote_char all_quote_chars escape_char all_escape_chars all_buchungsgruppen all_units
+ import_status errors headers raw_data_headers info_headers data num_imported num_importable displayable_columns file) ],
+ 'scalar --get_set_init' => [ qw(worker) ]
);
__PACKAGE__->run_before('check_auth');
return $self->action_new;
}
- my $worker = $self->create_worker($file);
+ $self->file($file);
+
+ my $worker = $self->worker();
+
$worker->run;
$self->num_imported(0);
return "csv-import-" . $self->type . ".csv";
}
-sub create_worker {
- my ($self, $file) = @_;
+sub init_worker {
+ my $self = shift;
+
+ my @args = (controller => $self);
+
+ if ( $self->file() ) {
+ push(@args, file => $self->file());
+ }
- return $self->{type} eq 'customers_vendors' ? SL::Controller::CsvImport::CustomerVendor->new(controller => $self, file => $file)
- : $self->{type} eq 'contacts' ? SL::Controller::CsvImport::Contact->new( controller => $self, file => $file)
- : $self->{type} eq 'addresses' ? SL::Controller::CsvImport::Shipto->new( controller => $self, file => $file)
- : $self->{type} eq 'parts' ? SL::Controller::CsvImport::Part->new( controller => $self, file => $file)
- : $self->{type} eq 'projects' ? SL::Controller::CsvImport::Project->new( controller => $self, file => $file)
+ return $self->{type} eq 'customers_vendors' ? SL::Controller::CsvImport::CustomerVendor->new(@args)
+ : $self->{type} eq 'contacts' ? SL::Controller::CsvImport::Contact->new(@args)
+ : $self->{type} eq 'addresses' ? SL::Controller::CsvImport::Shipto->new(@args)
+ : $self->{type} eq 'parts' ? SL::Controller::CsvImport::Part->new(@args)
+ : $self->{type} eq 'projects' ? SL::Controller::CsvImport::Project->new(@args)
: die "Program logic error";
}
sub setup_help {
my ($self) = @_;
- $self->create_worker->setup_displayable_columns;
+ $self->worker->setup_displayable_columns;
}
$self->controller->errors([ $self->csv->errors ]) if $self->csv->errors;
- return unless $self->csv->header;
+ return if ( !$self->csv->header || $self->csv->errors );
my $headers = { headers => [ grep { $profile->{$_} } @{ $self->csv->header } ] };
$headers->{methods} = [ map { $profile->{$_} } @{ $headers->{headers} } ];
$self->controller->data([ pairwise { { object => $a, raw_data => $b, errors => [], information => [], info_data => {} } } @objects, @raw_data ]);
$self->check_objects;
- $self->check_duplicates if $self->controller->profile->get('duplicates', 'no_check') ne 'no_check';
+ if ( $self->controller->profile->get('duplicates', 'no_check') ne 'no_check' ) {
+ $self->check_std_duplicates();
+ $self->check_duplicates();
+ }
$self->fix_field_lengths;
$::myconfig{numberformat} = $old_numberformat;
sub check_duplicates {
}
+sub check_std_duplicates {
+ my $self = shift;
+
+ my $duplicates = {};
+
+ my $all_fields = $self->get_duplicate_check_fields();
+
+ foreach my $key (keys(%{ $all_fields })) {
+ if ( $self->controller->profile->get('duplicates_'. $key) && (!exists($all_fields->{$key}->{std_check}) || $all_fields->{$key}->{std_check} ) ) {
+ $duplicates->{$key} = {};
+ }
+ }
+
+ my @duplicates_keys = keys(%{ $duplicates });
+
+ if ( !scalar(@duplicates_keys) ) {
+ return;
+ }
+
+ if ( $self->controller->profile->get('duplicates') eq 'check_db' ) {
+ foreach my $object (@{ $self->existing_objects }) {
+ foreach my $key (@duplicates_keys) {
+ my $value = exists($all_fields->{$key}->{maker}) ? $all_fields->{$key}->{maker}->($object, $self) : $object->$key;
+ $duplicates->{$key}->{$value} = 'db';
+ }
+ }
+ }
+
+ foreach my $entry (@{ $self->controller->data }) {
+ if ( @{ $entry->{errors} } ) {
+ next;
+ }
+
+ my $object = $entry->{object};
+
+ foreach my $key (@duplicates_keys) {
+ my $value = exists($all_fields->{$key}->{maker}) ? $all_fields->{$key}->{maker}->($object, $self) : $object->$key;
+
+ if ( exists($duplicates->{$key}->{$value}) ) {
+ push(@{ $entry->{errors} }, $duplicates->{$key}->{$value} eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file'));
+ last;
+ } else {
+ $duplicates->{$key}->{$value} = 'csv';
+ }
+
+ }
+ }
+
+}
+
+sub get_duplicate_check_fields {
+ return {};
+}
+
sub check_payment {
my ($self, $entry) = @_;
}
1;
+
push @{ $entry->{errors} }, $::locale->text('Error: Gender (cp_gender) missing or invalid') if ($entry->{object}->cp_gender ne 'm') && ($entry->{object}->cp_gender ne 'f');
}
-sub check_duplicates {
- my ($self, %params) = @_;
-
- my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; };
-
- my %by_id_and_name;
- if ('check_db' eq $self->controller->profile->get('duplicates')) {
- foreach my $type (qw(customers vendors)) {
- foreach my $vc (@{ $self->all_vc->{$type} }) {
- $by_id_and_name{ $vc->id } = { map { ( $normalizer->($_->cp_name) => 'db' ) } @{ $vc->contacts } };
+sub get_duplicate_check_fields {
+ return {
+ cp_name => {
+ label => $::locale->text('Name'),
+ default => 1,
+ maker => sub {
+ my $o = shift;
+ return join(
+ '--',
+ $o->cp_cv_id,
+ map(
+ { s/[\s,\.\-]//g; $_ }
+ $o->cp_name
+ )
+ );
}
- }
- }
-
- foreach my $entry (@{ $self->controller->data }) {
- next if @{ $entry->{errors} };
-
- my $name = $normalizer->($entry->{object}->cp_name);
-
- $by_id_and_name{ $entry->{vc}->id } ||= { };
- if (!$by_id_and_name{ $entry->{vc}->id }->{ $name }) {
- $by_id_and_name{ $entry->{vc}->id }->{ $name } = 'csv';
-
- } else {
- push @{ $entry->{errors} }, $by_id_and_name{ $entry->{vc}->id }->{ $name } eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file');
- }
- }
+ },
+ };
}
sub field_lengths {
);
}
-1;
+1;
\ No newline at end of file
$self->add_cvar_raw_data_columns;
}
-sub check_duplicates {
- my ($self, %params) = @_;
-
- my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; };
-
- my %by_name;
- if ('check_db' eq $self->controller->profile->get('duplicates')) {
- %by_name = map { ( $normalizer->($_->name) => 'db' ) } @{ $self->existing_objects };
- }
-
- foreach my $entry (@{ $self->controller->data }) {
- next if @{ $entry->{errors} };
-
- my $name = $normalizer->($entry->{object}->name);
- if (!$by_name{$name}) {
- $by_name{$name} = 'csv';
-
- } else {
- push @{ $entry->{errors} }, $by_name{$name} eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file');
- }
- }
+sub get_duplicate_check_fields {
+ return {
+ name => {
+ label => $::locale->text('Customer Name'),
+ default => 1,
+ maker => sub {
+ my $name = shift->name;
+ $name =~ s/[\s,\.\-]//g;
+ return $name;
+ }
+ },
+ };
}
sub check_name {
# TODO:
# salesman_id -- Kunden mit Typ 'Verkäufer', falls Vertreter-Modus an ist, ansonsten Employees
-1;
+1;
\ No newline at end of file
map { $self->add_raw_data_columns("make_${_}", "model_${_}", "lastcost_${_}") } sort { $a <=> $b } keys %{ $self->makemodel_columns };
}
-sub check_duplicates {
- my ($self, %params) = @_;
-
- my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; };
- my $name_maker = sub { return $normalizer->($_[0]->description) };
-
- my %by_name;
- if ('check_db' eq $self->controller->profile->get('duplicates')) {
- %by_name = map { ( $name_maker->($_) => 'db' ) } @{ $self->existing_objects };
- }
-
- foreach my $entry (@{ $self->controller->data }) {
- next if @{ $entry->{errors} };
-
- my $name = $name_maker->($entry->{object});
-
- if (!$by_name{ $name }) {
- $by_name{ $name } = 'csv';
-
- } else {
- push @{ $entry->{errors} }, $by_name{ $name } eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file');
- }
- }
+sub get_duplicate_check_fields {
+ return {
+ partnumber => {
+ label => $::locale->text('Part Number'),
+ default => 0
+ },
+
+ description => {
+ label => $::locale->text('Description'),
+ default => 1,
+ maker => sub {
+ my $desc = shift->description;
+ $desc =~ s/[\s,\.\-]//g;
+ return $desc;
+ }
+ },
+ };
}
sub check_buchungsgruppe {
}
}
-1;
+1;
\ No newline at end of file
$self->add_cvar_raw_data_columns;
}
-sub check_duplicates {
- my $self = shift;
-
- my %duplicates_by_number;
-
- if ( $self->controller->profile->get('duplicates') eq 'check_db' ) {
- foreach my $object (@{$self->existing_objects}) {
- $duplicates_by_number{$object->{projectnumber}} = 'db';
- }
- }
-
- foreach my $entry (@{ $self->controller->data }) {
-
- my $object = $entry->{object};
-
- if ( $duplicates_by_number{$object->projectnumber()} )
- {
- push( @{$entry->{errors}},
- $duplicates_by_number{$object->projectnumber()} eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file')
- );
- } else {
- $duplicates_by_number{$object->projectnumber()} = 'csv';
- }
-
- }
+sub get_duplicate_check_fields {
+ return {
+ projectnumber => {
+ label => $::locale->text('Project Number'),
+ default => 1,
+ std_check => 1
+ },
+ };
}
sub setup_displayable_columns {
);
}
-1;
+1;
\ No newline at end of file
$self->add_info_columns({ header => $::locale->text('Customer/Vendor'), method => 'vc_name' });
}
-sub check_duplicates {
- my ($self, %params) = @_;
-
- my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; };
- my $name_maker = sub { return $normalizer->($_[0]->shiptoname) . '--' . $normalizer->($_[0]->shiptostreet) };
-
- my %by_id_and_name;
- if ('check_db' eq $self->controller->profile->get('duplicates')) {
- foreach my $type (qw(customers vendors)) {
- foreach my $vc (@{ $self->all_vc->{$type} }) {
- $by_id_and_name{ $vc->id } = { map { ( $name_maker->($_) => 'db' ) } @{ $vc->shipto } };
+sub get_duplicate_check_fields {
+ return {
+ shiptoname_and_shiptostreet => {
+ label => $::locale->text('Name and Street'),
+ default => 1,
+ maker => sub {
+ my $o = shift;
+ return join(
+ '--',
+ $o->trans_id,
+ map(
+ { s/[\s,\.\-]//g; $_ }
+ $o->shiptoname,
+ $o->shiptostreet
+ )
+ );
}
- }
- }
-
- foreach my $entry (@{ $self->controller->data }) {
- next if @{ $entry->{errors} };
-
- my $name = $name_maker->($entry->{object});
-
- $by_id_and_name{ $entry->{vc}->id } ||= { };
- if (!$by_id_and_name{ $entry->{vc}->id }->{ $name }) {
- $by_id_and_name{ $entry->{vc}->id }->{ $name } = 'csv';
-
- } else {
- push @{ $entry->{errors} }, $by_id_and_name{ $entry->{vc}->id }->{ $name } eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file');
- }
- }
+ },
+
+ shiptoname => {
+ label => $::locale->text('Name'),
+ default => 1,
+ maker => sub {
+ my $o = shift;
+ return join(
+ '--',
+ $o->trans_id,
+ map(
+ { s/[\s,\.\-]//g; $_ }
+ $o->shiptoname
+ )
+ );
+ }
+ },
+
+ shiptostreet => {
+ label => $::locale->text('Street'),
+ default => 1,
+ maker => sub {
+ my $o = shift;
+ return join(
+ '--',
+ $o->trans_id,
+ map(
+ { s/[\s,\.\-]//g; $_ }
+ $o->shiptostreet
+ )
+ );
+ }
+ },
+ };
}
sub field_lengths {
);
}
-1;
+1;
\ No newline at end of file
{ name => "Digest::SHA", url => "http://search.cpan.org/~mshelor/", debian => 'libdigest-sha-perl' },
{ name => "IO::Socket::SSL", url => "http://search.cpan.org/~sullr/", debian => 'libio-socket-ssl-perl' },
{ name => "Net::LDAP", url => "http://search.cpan.org/~gbarr/", debian => 'libnet-ldap-perl' },
+ # Net::LDAP is core since 5.7.3
+ { name => "Net::SMTP::SSL", version => '1.01', url => "http://search.cpan.org/~cwest/", debian => 'libnet-smtp-ssl-perl' },
+ { name => "Net::SMTP::TLS", version => '0.12', url => "http://search.cpan.org/~awestholm/", debian => 'libnet-smtp-tls-perl' },
);
@developer_modules = (
1. KONSISTENZ DES PROGRAMMS
===========================
+* Testlauf t/test.sh
+
+ - Im Moment sind 4 Fehler optimal (die sind noch nicht angegangen):
+ o bin/mozilla/ar.pl contains at least 190 html tags.
+ o bin/mozilla/ic.pl contains at least 130 html tags.
+ o bin/mozilla/ap.pl contains at least 183 html tags.
+ o bin/mozilla/admin.pl DOES NOT use proper system or exec calls
+ - Einige Tests setzen eine korrekt aufgesetzte Datenbank für tests voraus.
+ TODO: diese Tests korrekt skippen wenn keine DB gefunden wurde.
+ TODO: Dokumeniteren wie der Releasemanager sich so eine DB baut, die
+ sollten vor einem Release zumindest durchlaufen.
+ TODO: Evtl eine Klasse von Releasetests einführen)
+
+* Testinstallation aus dem git mit neuer auth Datenbank.
+
+ - Änderungen die die auth Systeme betreffen zerreissen gerne mal die initiale
+ Installation.
+
+* Testupgrade auf einer Vorversion.
+
+ - Dito nur mit Upgradescripten. Fehlerhafte Abhängigkeiten können dazu
+ führen, dass Upgradescripte nicht in der richtigen Reihenfolge ausgeführt
+ werden, was bei inkrementellem Testen nicht auffällt.
+
* Freeze auf der Mailingliste ansagen.
- Featurefreeze für beta
t/test.sh
- - Im Moment sind 4 Fehler optimal (die sind noch nicht angegangen):
- o bin/mozilla/ar.pl contains at least 190 html tags.
- o bin/mozilla/ic.pl contains at least 130 html tags.
- o bin/mozilla/ap.pl contains at least 183 html tags.
- o bin/mozilla/admin.pl DOES NOT use proper system or exec calls
- - Einige Tests setzen eine korrekt aufgesetzte Datenbank für tests voraus.
- TODO: diese Tests korrekt skippen wenn keine DB gefunden wurde.
- TODO: Dokumeniteren wie der Releasemanager sich so eine DB baut, die
- sollten vor einem Release zumindest durchlaufen.
- TODO: Evtl eine Klasse von Releasetests einführen)
+ Siehe oben für mögliche Ergebnisse.
* Alle Änderungen einchecken.
'Multibyte Encoding' => 'Zeichenkodierung',
'MwSt. inkl.' => 'MwSt. inkl.',
'Name' => 'Name',
+ 'Name and Street' => 'Name und Straße',
'Name missing!' => 'Name fehlt!',
'National' => 'Inand',
'National Expenses' => 'Aufwand Inland',
-[% USE HTML %][% USE LxERP %][% USE L %]
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+[%- USE T8 %]
<body>
<div class="listtop">[% FORM.title %]</div>
[%- INCLUDE 'common/flash.html' %]
<form method="post" action="controller.pl" enctype="multipart/form-data">
+ [% L.hidden_tag('form_sent', '1') %]
[% L.hidden_tag('action', 'CsvImport/dispatch') %]
[% L.hidden_tag('profile.type', SELF.profile.type) %]
</td>
</tr>
- <tr>
- <th align="right">[%- LxERP.t8('Check for duplicates') %]:</th>
- <td colspan="10">
- [% opts = [ [ 'no_check', LxERP.t8('Do not check for duplicates') ],
- [ 'check_csv', LxERP.t8('Discard duplicate entries in CSV file') ],
- [ 'check_db', LxERP.t8('Discard entries with duplicates in database or CSV file') ] ] %]
- [% L.select_tag('settings.duplicates', L.options_for_select(opts, default => SELF.profile.get('duplicates')), style => 'width: 300px') %]
- </td>
- </tr>
+ [% duplicate_fields = SELF.worker.get_duplicate_check_fields() %]
+ [% IF ( duplicate_fields.size ) %]
+ <tr>
+ <th align="right">[%- LxERP.t8('Check for duplicates') %]:</th>
+
+ <td colspan=10>
+ [% FOREACH key = duplicate_fields.keys %]
+ <input type="checkbox" name="settings.duplicates_[% key | html %]" id="settings.duplicates_[% key | html %]" value="1"[% IF ( SELF.profile.get('duplicates_'_ key) || (duplicate_fields.$key.default && !FORM.form_sent ) ) %] checked="checked"[% END %]\>
+ <label for="settings.duplicates_[% key | html %]">[% duplicate_fields.$key.label | html %]</label>
+ [% END %]
+ </td>
+ </tr>
+
+ <tr>
+ <th align="right"></th>
+
+ <td colspan=10>
+ [% opts = [ [ 'no_check', LxERP.t8('Do not check for duplicates') ],
+ [ 'check_csv', LxERP.t8('Discard duplicate entries in CSV file') ],
+ [ 'check_db', LxERP.t8('Discard entries with duplicates in database or CSV file') ] ] %]
+ [% L.select_tag('settings.duplicates', L.options_for_select(opts, default => SELF.profile.get('duplicates')), style => 'width: 300px') %]
+ </td>
+ </tr>
+ [% END %]
[%- IF SELF.type == 'parts' %]
[%- INCLUDE 'csv_import/_form_parts.html' %]
-->
</script>
</body>
-</html>
+</html>
\ No newline at end of file