Revision 280cbfe9
Von Thomas Heck vor etwa 12 Jahren hinzugefügt
SL/Controller/CsvImport/Base.pm | ||
---|---|---|
39 | 39 |
|
40 | 40 |
$self->controller->errors([ $self->csv->errors ]) if $self->csv->errors; |
41 | 41 |
|
42 |
return if ( !$self->csv->header || $self->csv->errors ) ;
|
|
42 |
return if ( !$self->csv->header || $self->csv->errors ); |
|
43 | 43 |
|
44 | 44 |
my $headers = { headers => [ grep { $profile->{$_} } @{ $self->csv->header } ] }; |
45 | 45 |
$headers->{methods} = [ map { $profile->{$_} } @{ $headers->{headers} } ]; |
... | ... | |
53 | 53 |
$self->controller->data([ pairwise { { object => $a, raw_data => $b, errors => [], information => [], info_data => {} } } @objects, @raw_data ]); |
54 | 54 |
|
55 | 55 |
$self->check_objects; |
56 |
$self->check_duplicates if $self->controller->profile->get('duplicates', 'no_check') ne 'no_check'; |
|
56 |
if ( $self->controller->profile->get('duplicates', 'no_check') ne 'no_check' ) { |
|
57 |
$self->check_std_duplicates(); |
|
58 |
$self->check_duplicates(); |
|
59 |
} |
|
57 | 60 |
$self->fix_field_lengths; |
58 | 61 |
|
59 | 62 |
$::myconfig{numberformat} = $old_numberformat; |
... | ... | |
269 | 272 |
sub check_duplicates { |
270 | 273 |
} |
271 | 274 |
|
275 |
sub check_std_duplicates { |
|
276 |
my $self = shift; |
|
277 |
|
|
278 |
my $duplicates = {}; |
|
279 |
|
|
280 |
my $all_fields = $self->get_duplicate_check_fields(); |
|
281 |
|
|
282 |
foreach my $key (keys(%{ $all_fields })) { |
|
283 |
if ( $self->controller->profile->get('duplicates_'. $key) && (!exists($all_fields->{$key}->{std_check}) || $all_fields->{$key}->{std_check} ) ) { |
|
284 |
$duplicates->{$key} = {}; |
|
285 |
} |
|
286 |
} |
|
287 |
|
|
288 |
my @duplicates_keys = keys(%{ $duplicates }); |
|
289 |
|
|
290 |
if ( !scalar(@duplicates_keys) ) { |
|
291 |
return; |
|
292 |
} |
|
293 |
|
|
294 |
if ( $self->controller->profile->get('duplicates') eq 'check_db' ) { |
|
295 |
foreach my $object (@{ $self->existing_objects }) { |
|
296 |
foreach my $key (@duplicates_keys) { |
|
297 |
my $value = exists($all_fields->{$key}->{maker}) ? $all_fields->{$key}->{maker}->($object, $self) : $object->$key; |
|
298 |
$duplicates->{$key}->{$value} = 'db'; |
|
299 |
} |
|
300 |
} |
|
301 |
} |
|
302 |
|
|
303 |
foreach my $entry (@{ $self->controller->data }) { |
|
304 |
if ( @{ $entry->{errors} } ) { |
|
305 |
next; |
|
306 |
} |
|
307 |
|
|
308 |
my $object = $entry->{object}; |
|
309 |
|
|
310 |
foreach my $key (@duplicates_keys) { |
|
311 |
my $value = exists($all_fields->{$key}->{maker}) ? $all_fields->{$key}->{maker}->($object, $self) : $object->$key; |
|
312 |
|
|
313 |
if ( exists($duplicates->{$key}->{$value}) ) { |
|
314 |
push(@{ $entry->{errors} }, $duplicates->{$key}->{$value} eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file')); |
|
315 |
last; |
|
316 |
} else { |
|
317 |
$duplicates->{$key}->{$value} = 'csv'; |
|
318 |
} |
|
319 |
|
|
320 |
} |
|
321 |
} |
|
322 |
|
|
323 |
} |
|
324 |
|
|
325 |
sub get_duplicate_check_fields { |
|
326 |
return {}; |
|
327 |
} |
|
328 |
|
|
272 | 329 |
sub check_payment { |
273 | 330 |
my ($self, $entry) = @_; |
274 | 331 |
|
... | ... | |
329 | 386 |
|
330 | 387 |
1; |
331 | 388 |
|
332 |
|
SL/Controller/CsvImport/Contact.pm | ||
---|---|---|
54 | 54 |
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'); |
55 | 55 |
} |
56 | 56 |
|
57 |
sub check_duplicates { |
|
58 |
my ($self, %params) = @_; |
|
59 |
|
|
60 |
my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; }; |
|
61 |
|
|
62 |
my %by_id_and_name; |
|
63 |
if ('check_db' eq $self->controller->profile->get('duplicates')) { |
|
64 |
foreach my $type (qw(customers vendors)) { |
|
65 |
foreach my $vc (@{ $self->all_vc->{$type} }) { |
|
66 |
$by_id_and_name{ $vc->id } = { map { ( $normalizer->($_->cp_name) => 'db' ) } @{ $vc->contacts } }; |
|
57 |
sub get_duplicate_check_fields { |
|
58 |
return { |
|
59 |
cp_name => { |
|
60 |
label => $::locale->text('Name'), |
|
61 |
default => 1, |
|
62 |
maker => sub { |
|
63 |
my $o = shift; |
|
64 |
return join( |
|
65 |
'--', |
|
66 |
$o->cp_cv_id, |
|
67 |
map( |
|
68 |
{ s/[\s,\.\-]//g; $_ } |
|
69 |
$o->cp_name |
|
70 |
) |
|
71 |
); |
|
67 | 72 |
} |
68 |
} |
|
69 |
} |
|
70 |
|
|
71 |
foreach my $entry (@{ $self->controller->data }) { |
|
72 |
next if @{ $entry->{errors} }; |
|
73 |
|
|
74 |
my $name = $normalizer->($entry->{object}->cp_name); |
|
75 |
|
|
76 |
$by_id_and_name{ $entry->{vc}->id } ||= { }; |
|
77 |
if (!$by_id_and_name{ $entry->{vc}->id }->{ $name }) { |
|
78 |
$by_id_and_name{ $entry->{vc}->id }->{ $name } = 'csv'; |
|
79 |
|
|
80 |
} else { |
|
81 |
push @{ $entry->{errors} }, $by_id_and_name{ $entry->{vc}->id }->{ $name } eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file'); |
|
82 |
} |
|
83 |
} |
|
73 |
}, |
|
74 |
}; |
|
84 | 75 |
} |
85 | 76 |
|
86 | 77 |
sub field_lengths { |
... | ... | |
125 | 116 |
); |
126 | 117 |
} |
127 | 118 |
|
128 |
1; |
|
119 |
1; |
SL/Controller/CsvImport/CustomerVendor.pm | ||
---|---|---|
72 | 72 |
$self->add_cvar_raw_data_columns; |
73 | 73 |
} |
74 | 74 |
|
75 |
sub check_duplicates { |
|
76 |
my ($self, %params) = @_; |
|
77 |
|
|
78 |
my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; }; |
|
79 |
|
|
80 |
my %by_name; |
|
81 |
if ('check_db' eq $self->controller->profile->get('duplicates')) { |
|
82 |
%by_name = map { ( $normalizer->($_->name) => 'db' ) } @{ $self->existing_objects }; |
|
83 |
} |
|
84 |
|
|
85 |
foreach my $entry (@{ $self->controller->data }) { |
|
86 |
next if @{ $entry->{errors} }; |
|
87 |
|
|
88 |
my $name = $normalizer->($entry->{object}->name); |
|
89 |
if (!$by_name{$name}) { |
|
90 |
$by_name{$name} = 'csv'; |
|
91 |
|
|
92 |
} else { |
|
93 |
push @{ $entry->{errors} }, $by_name{$name} eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file'); |
|
94 |
} |
|
95 |
} |
|
75 |
sub get_duplicate_check_fields { |
|
76 |
return { |
|
77 |
name => { |
|
78 |
label => $::locale->text('Customer Name'), |
|
79 |
default => 1, |
|
80 |
maker => sub { |
|
81 |
my $name = shift->name; |
|
82 |
$name =~ s/[\s,\.\-]//g; |
|
83 |
return $name; |
|
84 |
} |
|
85 |
}, |
|
86 |
}; |
|
96 | 87 |
} |
97 | 88 |
|
98 | 89 |
sub check_name { |
... | ... | |
265 | 256 |
# TODO: |
266 | 257 |
# salesman_id -- Kunden mit Typ 'Verkäufer', falls Vertreter-Modus an ist, ansonsten Employees |
267 | 258 |
|
268 |
1; |
|
259 |
1; |
SL/Controller/CsvImport/Part.pm | ||
---|---|---|
132 | 132 |
map { $self->add_raw_data_columns("make_${_}", "model_${_}", "lastcost_${_}") } sort { $a <=> $b } keys %{ $self->makemodel_columns }; |
133 | 133 |
} |
134 | 134 |
|
135 |
sub check_duplicates { |
|
136 |
my ($self, %params) = @_; |
|
137 |
|
|
138 |
my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; }; |
|
139 |
my $name_maker = sub { return $normalizer->($_[0]->description) }; |
|
140 |
|
|
141 |
my %by_name; |
|
142 |
if ('check_db' eq $self->controller->profile->get('duplicates')) { |
|
143 |
%by_name = map { ( $name_maker->($_) => 'db' ) } @{ $self->existing_objects }; |
|
144 |
} |
|
145 |
|
|
146 |
foreach my $entry (@{ $self->controller->data }) { |
|
147 |
next if @{ $entry->{errors} }; |
|
148 |
|
|
149 |
my $name = $name_maker->($entry->{object}); |
|
150 |
|
|
151 |
if (!$by_name{ $name }) { |
|
152 |
$by_name{ $name } = 'csv'; |
|
153 |
|
|
154 |
} else { |
|
155 |
push @{ $entry->{errors} }, $by_name{ $name } eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file'); |
|
156 |
} |
|
157 |
} |
|
135 |
sub get_duplicate_check_fields { |
|
136 |
return { |
|
137 |
partnumber => { |
|
138 |
label => $::locale->text('Part Number'), |
|
139 |
default => 0 |
|
140 |
}, |
|
141 |
|
|
142 |
description => { |
|
143 |
label => $::locale->text('Description'), |
|
144 |
default => 1, |
|
145 |
maker => sub { |
|
146 |
my $desc = shift->description; |
|
147 |
$desc =~ s/[\s,\.\-]//g; |
|
148 |
return $desc; |
|
149 |
} |
|
150 |
}, |
|
151 |
}; |
|
158 | 152 |
} |
159 | 153 |
|
160 | 154 |
sub check_buchungsgruppe { |
... | ... | |
502 | 496 |
} |
503 | 497 |
} |
504 | 498 |
|
505 |
1; |
|
499 |
1; |
SL/Controller/CsvImport/Project.pm | ||
---|---|---|
34 | 34 |
$self->add_cvar_raw_data_columns; |
35 | 35 |
} |
36 | 36 |
|
37 |
sub check_duplicates { |
|
38 |
my $self = shift; |
|
39 |
|
|
40 |
my %duplicates_by_number; |
|
41 |
|
|
42 |
if ( $self->controller->profile->get('duplicates') eq 'check_db' ) { |
|
43 |
foreach my $object (@{$self->existing_objects}) { |
|
44 |
$duplicates_by_number{$object->{projectnumber}} = 'db'; |
|
45 |
} |
|
46 |
} |
|
47 |
|
|
48 |
foreach my $entry (@{ $self->controller->data }) { |
|
49 |
|
|
50 |
my $object = $entry->{object}; |
|
51 |
|
|
52 |
if ( $duplicates_by_number{$object->projectnumber()} ) |
|
53 |
{ |
|
54 |
push( @{$entry->{errors}}, |
|
55 |
$duplicates_by_number{$object->projectnumber()} eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file') |
|
56 |
); |
|
57 |
} else { |
|
58 |
$duplicates_by_number{$object->projectnumber()} = 'csv'; |
|
59 |
} |
|
60 |
|
|
61 |
} |
|
37 |
sub get_duplicate_check_fields { |
|
38 |
return { |
|
39 |
projectnumber => { |
|
40 |
label => $::locale->text('Project Number'), |
|
41 |
default => 1, |
|
42 |
std_check => 1 |
|
43 |
}, |
|
44 |
}; |
|
62 | 45 |
} |
63 | 46 |
|
64 | 47 |
sub setup_displayable_columns { |
... | ... | |
73 | 56 |
); |
74 | 57 |
} |
75 | 58 |
|
76 |
1; |
|
59 |
1; |
SL/Controller/CsvImport/Shipto.pm | ||
---|---|---|
27 | 27 |
$self->add_info_columns({ header => $::locale->text('Customer/Vendor'), method => 'vc_name' }); |
28 | 28 |
} |
29 | 29 |
|
30 |
sub check_duplicates { |
|
31 |
my ($self, %params) = @_; |
|
32 |
|
|
33 |
my $normalizer = sub { my $name = $_[0]; $name =~ s/[\s,\.\-]//g; return $name; }; |
|
34 |
my $name_maker = sub { return $normalizer->($_[0]->shiptoname) . '--' . $normalizer->($_[0]->shiptostreet) }; |
|
35 |
|
|
36 |
my %by_id_and_name; |
|
37 |
if ('check_db' eq $self->controller->profile->get('duplicates')) { |
|
38 |
foreach my $type (qw(customers vendors)) { |
|
39 |
foreach my $vc (@{ $self->all_vc->{$type} }) { |
|
40 |
$by_id_and_name{ $vc->id } = { map { ( $name_maker->($_) => 'db' ) } @{ $vc->shipto } }; |
|
30 |
sub get_duplicate_check_fields { |
|
31 |
return { |
|
32 |
shiptoname_and_shiptostreet => { |
|
33 |
label => $::locale->text('Name and Street'), |
|
34 |
default => 1, |
|
35 |
maker => sub { |
|
36 |
my $o = shift; |
|
37 |
return join( |
|
38 |
'--', |
|
39 |
$o->trans_id, |
|
40 |
map( |
|
41 |
{ s/[\s,\.\-]//g; $_ } |
|
42 |
$o->shiptoname, |
|
43 |
$o->shiptostreet |
|
44 |
) |
|
45 |
); |
|
41 | 46 |
} |
42 |
} |
|
43 |
} |
|
44 |
|
|
45 |
foreach my $entry (@{ $self->controller->data }) { |
|
46 |
next if @{ $entry->{errors} }; |
|
47 |
|
|
48 |
my $name = $name_maker->($entry->{object}); |
|
49 |
|
|
50 |
$by_id_and_name{ $entry->{vc}->id } ||= { }; |
|
51 |
if (!$by_id_and_name{ $entry->{vc}->id }->{ $name }) { |
|
52 |
$by_id_and_name{ $entry->{vc}->id }->{ $name } = 'csv'; |
|
53 |
|
|
54 |
} else { |
|
55 |
push @{ $entry->{errors} }, $by_id_and_name{ $entry->{vc}->id }->{ $name } eq 'db' ? $::locale->text('Duplicate in database') : $::locale->text('Duplicate in CSV file'); |
|
56 |
} |
|
57 |
} |
|
47 |
}, |
|
48 |
|
|
49 |
shiptoname => { |
|
50 |
label => $::locale->text('Name'), |
|
51 |
default => 1, |
|
52 |
maker => sub { |
|
53 |
my $o = shift; |
|
54 |
return join( |
|
55 |
'--', |
|
56 |
$o->trans_id, |
|
57 |
map( |
|
58 |
{ s/[\s,\.\-]//g; $_ } |
|
59 |
$o->shiptoname |
|
60 |
) |
|
61 |
); |
|
62 |
} |
|
63 |
}, |
|
64 |
|
|
65 |
shiptostreet => { |
|
66 |
label => $::locale->text('Street'), |
|
67 |
default => 1, |
|
68 |
maker => sub { |
|
69 |
my $o = shift; |
|
70 |
return join( |
|
71 |
'--', |
|
72 |
$o->trans_id, |
|
73 |
map( |
|
74 |
{ s/[\s,\.\-]//g; $_ } |
|
75 |
$o->shiptostreet |
|
76 |
) |
|
77 |
); |
|
78 |
} |
|
79 |
}, |
|
80 |
}; |
|
58 | 81 |
} |
59 | 82 |
|
60 | 83 |
sub field_lengths { |
... | ... | |
104 | 127 |
); |
105 | 128 |
} |
106 | 129 |
|
107 |
1; |
|
130 |
1; |
locale/de/all | ||
---|---|---|
1174 | 1174 |
'Multibyte Encoding' => 'Zeichenkodierung', |
1175 | 1175 |
'MwSt. inkl.' => 'MwSt. inkl.', |
1176 | 1176 |
'Name' => 'Name', |
1177 |
'Name and Street' => 'Name und Straße', |
|
1177 | 1178 |
'Name missing!' => 'Name fehlt!', |
1178 | 1179 |
'National' => 'Inand', |
1179 | 1180 |
'National Expenses' => 'Aufwand Inland', |
templates/webpages/csv_import/form.html | ||
---|---|---|
1 |
[% USE HTML %][% USE LxERP %][% USE L %] |
|
1 |
[%- USE HTML %] |
|
2 |
[%- USE LxERP %] |
|
3 |
[%- USE L %] |
|
4 |
[%- USE T8 %] |
|
2 | 5 |
<body> |
3 | 6 |
|
4 | 7 |
<div class="listtop">[% FORM.title %]</div> |
... | ... | |
6 | 9 |
[%- INCLUDE 'common/flash.html' %] |
7 | 10 |
|
8 | 11 |
<form method="post" action="controller.pl" enctype="multipart/form-data"> |
12 |
[% L.hidden_tag('form_sent', '1') %] |
|
9 | 13 |
[% L.hidden_tag('action', 'CsvImport/dispatch') %] |
10 | 14 |
[% L.hidden_tag('profile.type', SELF.profile.type) %] |
11 | 15 |
|
... | ... | |
157 | 161 |
</td> |
158 | 162 |
</tr> |
159 | 163 |
|
160 |
<tr> |
|
161 |
<th align="right">[%- LxERP.t8('Check for duplicates') %]:</th> |
|
162 |
<td colspan="10"> |
|
163 |
[% opts = [ [ 'no_check', LxERP.t8('Do not check for duplicates') ], |
|
164 |
[ 'check_csv', LxERP.t8('Discard duplicate entries in CSV file') ], |
|
165 |
[ 'check_db', LxERP.t8('Discard entries with duplicates in database or CSV file') ] ] %] |
|
166 |
[% L.select_tag('settings.duplicates', L.options_for_select(opts, default => SELF.profile.get('duplicates')), style => 'width: 300px') %] |
|
167 |
</td> |
|
168 |
</tr> |
|
164 |
[% duplicate_fields = SELF.worker.get_duplicate_check_fields() %] |
|
165 |
[% IF ( duplicate_fields.size ) %] |
|
166 |
<tr> |
|
167 |
<th align="right">[%- LxERP.t8('Check for duplicates') %]:</th> |
|
168 |
|
|
169 |
<td colspan=10> |
|
170 |
[% FOREACH key = duplicate_fields.keys %] |
|
171 |
<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 %]\> |
|
172 |
<label for="settings.duplicates_[% key | html %]">[% duplicate_fields.$key.label | html %]</label> |
|
173 |
[% END %] |
|
174 |
</td> |
|
175 |
</tr> |
|
176 |
|
|
177 |
<tr> |
|
178 |
<th align="right"></th> |
|
179 |
|
|
180 |
<td colspan=10> |
|
181 |
[% opts = [ [ 'no_check', LxERP.t8('Do not check for duplicates') ], |
|
182 |
[ 'check_csv', LxERP.t8('Discard duplicate entries in CSV file') ], |
|
183 |
[ 'check_db', LxERP.t8('Discard entries with duplicates in database or CSV file') ] ] %] |
|
184 |
[% L.select_tag('settings.duplicates', L.options_for_select(opts, default => SELF.profile.get('duplicates')), style => 'width: 300px') %] |
|
185 |
</td> |
|
186 |
</tr> |
|
187 |
[% END %] |
|
169 | 188 |
|
170 | 189 |
[%- IF SELF.type == 'parts' %] |
171 | 190 |
[%- INCLUDE 'csv_import/_form_parts.html' %] |
... | ... | |
225 | 244 |
--> |
226 | 245 |
</script> |
227 | 246 |
</body> |
228 |
</html> |
|
247 |
</html> |
Auch abrufbar als: Unified diff
CSV-Import: Auswahl der Felder für die Duplikat-Prüfung
fixt 1964