Langtext-Dialog: Größe prozentual zum Hauptfenster einstellbar pro Benutzer
[kivitendo-erp.git] / templates / webpages / csv_import / form.html
1 [%- USE HTML %]
2 [%- USE LxERP %]
3 [%- USE L %]
4 [%- USE T8 %]
5  <h1>[% FORM.title %]</h1>
6
7  [%- INCLUDE 'common/flash.html' %]
8
9  <form method="post" action="controller.pl" enctype="multipart/form-data" id="form">
10   [% L.hidden_tag('form_sent', '1') %]
11   [% L.hidden_tag('action', 'CsvImport/dispatch') %]
12   [% L.hidden_tag('profile.type', SELF.profile.type) %]
13   [% L.hidden_tag('tmp_profile_id', SELF.profile.id) %]
14
15  [%- IF SELF.profile.get('dont_edit_profile') %]
16   [% L.hidden_tag('force_profile', 1) %]
17   [% L.hidden_tag('profile.id', SELF.profile.id) %]
18  [%- ELSE %][%# IF SELF.profile.get('dont_edit_profile') %]
19   <h2>[%- LxERP.t8('Import profiles') %]</h2>
20
21   <table>
22    [%- IF SELF.profile.id %]
23     <tr>
24      <th align="right">[%- LxERP.t8('Current profile') %]:</th>
25      <td>[%- HTML.escape(SELF.profile.name) %]</td>
26     </tr>
27    [%- END %][%# IF SELF.profile.id %]
28
29    [%- IF SELF.all_profiles.size %]
30     <tr>
31      <th align="right">[%- LxERP.t8('Existing profiles') %]:</th>
32      <td>
33       [% L.select_tag('profile.id', SELF.all_profiles, title_key = 'name', default = SELF.profile.id, style = 'width: 300px') %]
34      </td>
35      <td>
36       [% L.submit_tag('action_new', LxERP.t8('Load profile')) %]
37       [% L.submit_tag('action_destroy', LxERP.t8('Delete profile'), confirm => LxERP.t8('Do you really want to delete this object?')) %]
38      </td>
39     </tr>
40    [%- END %][%# IF SELF.all_profiles.size %]
41
42    <tr>
43     <th align="right" valign="top">[%- LxERP.t8('Save settings as') %]:</th>
44     <td valign="top">
45      [% L.input_tag('profile.name', '', style => 'width: 300px') %]
46      <br>
47      [% L.checkbox_tag('profile.is_default', label => LxERP.t8('Make default profile')) %]
48     </td>
49     <td valign="top">[% L.submit_tag('action_save', LxERP.t8('Save profile')) %]</td>
50    </tr>
51   </table>
52
53   <hr>
54
55   <h2>[%- LxERP.t8('Help on column names') %]</h2>
56
57   <div class="help_toggle">
58    <a href="#" onClick="javascript:$('.help_toggle').toggle()">[% LxERP.t8("Show help text") %]</a>
59   </div>
60
61   <div class="help_toggle" style="display:none">
62    <p><a href="#" onClick="javascript:$('.help_toggle').toggle()">[% LxERP.t8("Hide help text") %]</a></p>
63
64    [%- IF SELF.worker.is_multiplexed %]
65      <table>
66        <tr class="listheading">
67          [%- FOREACH p = SELF.worker.profile %]
68            <th>[%- p.row_ident %]</th>
69          [%- END %][%# FOREACH SELF.worker.profile %]
70        </tr>
71        <tr style="vertical-align:top">
72          [%- FOREACH p = SELF.worker.profile %]
73            [% SET ri = p.row_ident %]
74          <td>
75            <table>
76              <tr class="listheading">
77                <th>[%- LxERP.t8('Column name') %]</th>
78                <th>[%- LxERP.t8('Meaning') %]</th>
79              </tr>
80
81              [%- FOREACH row = SELF.displayable_columns.$ri %]
82              <tr class="listrow[% loop.count % 2 %]">
83                <td>[%- HTML.escape(row.name) %]</td>
84                <td>[%- HTML.escape(row.description) %]</td>
85              </tr>
86              [%- END %][%# FOREACH SELF.displayable_columns.$ri %]
87            </table>
88          </td>
89          [%- END %][%# FOREACH SELF.worker.profile %]
90        </tr>
91      </table>
92    [%- ELSE %][%# IF SELF.worker.is_multiplexed %]
93      <table>
94        <tr class="listheading">
95          <th>[%- LxERP.t8('Column name') %]</th>
96          <th>[%- LxERP.t8('Meaning') %]</th>
97        </tr>
98
99        [%- FOREACH row = SELF.displayable_columns %]
100        <tr class="listrow[% loop.count % 2 %]">
101          <td>[%- HTML.escape(row.name) %]</td>
102          <td>[%- HTML.escape(row.description) %]</td>
103        </tr>
104        [%- END %][%# FOREACH SELF.displayable_columns %]
105      </table>
106    [%- END %][%# SELF.worker.is_multiplexed %]
107
108 [%- IF SELF.type == 'contacts' %]
109    <p>
110     [%- LxERP.t8("You can update existing contacts by providing the 'cp_id' column with their database IDs. Otherwise: ") %]
111     [%- LxERP.t8('At least one of the columns #1, customer, customernumber, customer_gln, vendor, vendornumber, vendor_gln (depending on the target table) is required for matching the entry to an existing customer or vendor.', 'cp_cv_id') %]
112    </p>
113
114 [%- ELSIF SELF.type == 'addresses' %]
115    <p>
116     [%- LxERP.t8('At least one of the columns #1, customer, customernumber, customer_gln, vendor, vendornumber, vendor_gln (depending on the target table) is required for matching the entry to an existing customer or vendor.', 'trans_id') %]
117    </p>
118
119 [%- ELSIF SELF.type == 'parts' %]
120    <p>
121     [1]:
122     [% LxERP.t8('The three columns "make_X", "model_X" and "lastcost_X" with the same number "X" are used to import vendor part numbers and vendor prices.') %]
123     [% LxERP.t8('The column triplets can occur multiple times with different numbers "X" each time (e.g. "make_1", "model_1", "lastcost_1", "make_2", "model_2", "lastcost_2", "make_3", "model_3", "lastcost_3" etc).') %]
124     [% LxERP.t8('The items are imported accoring do their number "X" regardless of the column order inside the file.') %]
125     [% LxERP.t8('The column "make_X" can contain either a vendor\'s database ID, a vendor number or a vendor\'s name.') %]
126    </p>
127     <p>
128     [2]:
129     [% LxERP.t8('Onhand only sets the quantity in master data, not in inventory. This is only a legacy info field and will be overwritten as soon as a inventory transfer happens.') %]
130    </p>
131    <p>
132     [3]:
133     [% LxERP.t8("If the article type is set to 'mixed' then a column called 'part_type' or called 'pclass' must be present.") %]
134     [% LxERP.t8("Type can be either 'part', 'service' or 'assembly'.") %]
135     [%- LxERP.t8("If column 'pclass' is present the article type is then irrelevant or used as default ") %]
136     [% LxERP.t8("The 'pclass' column has the same abbreviation like a part export. The first letter is for the type Part,Assembly or Service, the second(and third) for Part Classification") %]
137    </p>
138
139 [%- ELSIF SELF.type == 'inventories' %]
140    <p>
141     [%- LxERP.t8('One of the columns "qty" or "target_qty" must be given. If "target_qty" is given, the quantity to transfer for each transfer will be calculate, so that the quantity for this part, warehouse and bin will result in the given "target_qty" after each transfer.') %]
142    </p>
143
144 [%- ELSIF SELF.type == 'orders' OR SELF.type == 'delivery_orders' OR SELF.type == 'ar_transactions' %]
145    <p>
146     [1]:
147     [% LxERP.t8('The column "datatype" must be present and must be at the same position / column in each data set. The values must be the row names (see settings) for order and item data respectively.') %]
148    </p>
149    [%- IF SELF.type == 'orders' OR SELF.type == 'ar_transactions' %]
150     <p>
151      [2]:
152      [%- LxERP.t8('Amount and net amount are calculated by kivitendo. "verify_amount" and "verify_netamount" can be used for sanity checks.') %]<br>
153      [%- LxERP.t8('If amounts differ more than "Maximal amount difference" (see settings), this item is marked as invalid.') %]<br>
154     </p>
155    [%- END %]
156 [%- END %][%# IF SELF.type == … %]
157   </div>
158
159   <div>
160     <p>
161       [%- L.submit_tag('action_download_sample', LxERP.t8('Download sample file')) %]
162     </p>
163   </div>
164
165   <hr>
166
167   <h2>[%- LxERP.t8('Settings') %]</h2>
168
169   <div class="settings_toggle"[% UNLESS SELF.deferred || SELF.import_status %] style="display:none"[% END %]>
170    <a href="#" onClick="javascript:$('.settings_toggle').toggle()">[% LxERP.t8("Show settings") %]</a>
171   </div>
172
173   <div class="settings_toggle"[% IF SELF.deferred || SELF.import_status %] style="display:none"[% END %]>
174    <p><a href="#" onClick="javascript:$('.settings_toggle').toggle()">[% LxERP.t8("Hide settings") %]</a></p>
175
176   <table>
177    <tr>
178     <th align="right">[%- LxERP.t8('Number Format') %]:</th>
179     <td colspan="10">
180      [% L.select_tag('settings.numberformat', ['1.000,00', '1000,00', '1,000.00', '1000.00', "1'000.00"], default = SELF.profile.get('numberformat'), style = 'width: 300px') %]
181     </td>
182    </tr>
183
184    <tr>
185     <th align="right">[%- LxERP.t8('Date Format') %]:</th>
186     <td colspan="10">
187      [% L.select_tag('settings.dateformat', ['dd.mm.yyyy', 'yyyy-mm-dd', 'dd/mm/yyyy', 'mm/dd/yyyy' ], default = SELF.profile.get('dateformat'), style = 'width: 300px') %]
188     </td>
189    </tr>
190
191    <tr>
192     <th align="right">[%- LxERP.t8('Charset') %]:</th>
193     <td colspan="10">[% L.select_tag('settings.charset', SELF.all_charsets, default = SELF.profile.get('charset'), style = 'width: 300px') %]</td>
194    </tr>
195
196    <tr>
197     <th align="right">[%- LxERP.t8('Separator') %]:</th>
198     [% SET custom_sep_char = SELF.sep_char %]
199     [% FOREACH entry = SELF.all_sep_chars %]
200      <td>
201       [% IF SELF.sep_char == entry.first %] [% SET custom_sep_char = '' %] [%- END %]
202       [% L.radio_button_tag('sep_char', value => entry.first, label => entry.last, checked => SELF.sep_char == entry.first) %]
203      </td>
204     [%- END %][%# FOREACH SELF.all_sep_chars %]
205
206     <td>
207      [% L.radio_button_tag('sep_char', value => 'custom', checked => custom_sep_char != '') %]
208      [% L.input_tag('custom_sep_char', custom_sep_char, size => 3, maxlength => 1) %]
209     </td>
210    </tr>
211
212    <tr>
213     <th align="right">[%- LxERP.t8('Quote character') %]:</th>
214     [% SET custom_quote_char = SELF.quote_char %]
215     [% FOREACH entry = SELF.all_quote_chars %]
216      <td>
217       [% IF SELF.quote_char == entry.first %] [% SET custom_quote_char = '' %] [%- END %]
218       [% L.radio_button_tag('quote_char', value => entry.first, label => entry.last, checked => SELF.quote_char == entry.first) %]
219      </td>
220     [%- END %][%# FOREACH SELF.all_quote_chars %]
221
222     <td>
223      [% L.radio_button_tag('quote_char', value => 'custom', checked => custom_quote_char != '') %]
224      [% L.input_tag('custom_quote_char', custom_quote_char, size => 3, maxlength => 1) %]
225     </td>
226    </tr>
227
228    <tr>
229     <th align="right">[%- LxERP.t8('Escape character') %]:</th>
230     [% SET custom_escape_char = SELF.escape_char %]
231     [% FOREACH entry = SELF.all_escape_chars %]
232      <td>
233       [% IF SELF.escape_char == entry.first %] [% SET custom_escape_char = '' %] [%- END %]
234       [% L.radio_button_tag('escape_char', value => entry.first, label => entry.last, checked => SELF.escape_char == entry.first) %]
235      </td>
236     [%- END %][%# FOREACH SELF.all_escape_chars %]
237
238     <td>
239      [% L.radio_button_tag('escape_char', value => 'custom', checked => custom_escape_char != '') %]
240      [% L.input_tag('custom_escape_char', custom_escape_char, size => 3, maxlength => 1) %]
241     </td>
242    </tr>
243
244    [% duplicate_fields = SELF.worker.get_duplicate_check_fields() %]
245    [% IF ( duplicate_fields.size ) %]
246      <tr>
247        <th align="right">[%- LxERP.t8('Check for duplicates') %]:</th>
248
249        <td colspan=10>
250          [% FOREACH key = duplicate_fields.keys %]
251            <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 %]>
252            <label for="settings.duplicates_[% key | html %]">[% duplicate_fields.$key.label | html %]</label>
253          [% END %][%# FOREACH duplicate_fields.keys %]
254        </td>
255      </tr>
256
257      <tr>
258        <th align="right"></th>
259
260        <td colspan=10>
261          [% opts = [ [ 'no_check',  LxERP.t8('Do not check for duplicates') ],
262                      [ 'check_csv', LxERP.t8('Discard duplicate entries in CSV file') ],
263                      [ 'check_db',  LxERP.t8('Discard entries with duplicates in database or CSV file') ] ] %]
264          [% L.select_tag('settings.duplicates', opts, default = SELF.profile.get('duplicates'), style = 'width: 300px') %]
265        </td>
266      </tr>
267    [% END %][%# IF duplicate_fields.size %]
268
269 [%- IF SELF.type == 'parts' %]
270  [%- INCLUDE 'csv_import/_form_parts.html' %]
271 [%- ELSIF SELF.type == 'customers_vendors' %]
272  [%- INCLUDE 'csv_import/_form_customers_vendors.html' %]
273 [%- ELSIF SELF.type == 'contacts' %]
274  [%- INCLUDE 'csv_import/_form_contacts.html' %]
275 [%- ELSIF SELF.type == 'inventories' %]
276  [%- INCLUDE 'csv_import/_form_inventories.html' %]
277 [%- ELSIF SELF.type == 'orders' %]
278  [%- INCLUDE 'csv_import/_form_orders.html' %]
279 [%- ELSIF SELF.type == 'delivery_orders' %]
280  [%- INCLUDE 'csv_import/_form_delivery_orders.html' %]
281 [%- ELSIF SELF.type == 'ar_transactions' %]
282  [%- INCLUDE 'csv_import/_form_artransactions.html' %]
283 [%- ELSIF SELF.type == 'bank_transactions' %]
284  [%- INCLUDE 'csv_import/_form_banktransactions.html' %]
285 [%- END %]
286
287    <tr>
288     <th align="right">[%- LxERP.t8('Preview Mode') %]:</th>
289     <td colspan="10">
290       [% L.radio_button_tag('settings.full_preview', value=0, checked=!SELF.profile.get('full_preview'),   label=LxERP.t8('Full Preview')) %]
291       [% L.radio_button_tag('settings.full_preview', value=1, checked=SELF.profile.get('full_preview')==1, label=LxERP.t8('Only Lines with Notes or Errors')) %]
292       [% L.radio_button_tag('settings.full_preview', value=2, checked=SELF.profile.get('full_preview')==2, label=LxERP.t8('First 20 Lines')) %]
293     </td>
294    </tr>
295
296    <tr>
297     <th align="right">[%- LxERP.t8('Import file') %]:</th>
298     <td colspan="10">[% L.input_tag('file', '', type => 'file', accept => '*') %]</td>
299    </tr>
300
301    [%- IF SELF.file.exists %]
302     <tr>
303      <th align="right">[%- LxERP.t8('Existing file on server') %]:</th>
304      <td colspan="10">[%- LxERP.t8('Uploaded on #1, size #2 kB', SELF.file.displayable_mtime, LxERP.format_amount(SELF.file.size / 1024, 2)) %]</td>
305     </tr>
306    [%- END %][%# IF SELF.file.exists %]
307
308   </table>
309
310   </div>
311   <hr>
312
313 [%- UNLESS SELF.worker.is_multiplexed %]
314   <h2>[% 'Mappings (csv_import)' | $T8 %]</h2>
315
316   <div class="mappings_toggle"[% UNLESS SELF.deferred || SELF.import_status %] style="display:none"[% END %]>
317    <a href="#" onClick="javascript:$('.mappings_toggle').toggle()">[% LxERP.t8("Show mappings (csv_import)") %]</a>
318   </div>
319   <div class="mappings_toggle"[% IF SELF.deferred || SELF.import_status %] style="display:none"[% END %]>
320    <p><a href="#" onClick="javascript:$('.mappings_toggle').toggle()">[% LxERP.t8("Hide mappings (csv_import)") %]</a></p>
321
322     <p>[% 'These mappings can be used to map heading from non standard csv files to known columns. These will also be saved in profiles, so you can save profiles for every source of formats.' | $T8 %]</p>
323
324   <table id="csv_import_mappings">
325    <tr class=listheading>
326     <th></th>
327     <th>[% 'Text in CSV File' | $T8 %]</th>
328     <th>[% 'Known Column' | $T8 %]</th>
329    </tr>
330    <tr id='mapping_empty' style='display:none'>
331     <td colspan=3>[% 'There is nothing here yet (csv_import)' | $T8 %]</td>
332    </tr>
333 [%- FOREACH row = SELF.mappings %]
334    [% PROCESS 'csv_import/_mapping_item.html', item=row IF row.from %]
335 [%- END %][%# FOREACH SELF.mappings %]
336    [% PROCESS 'csv_import/_mapping_item.html', item={} %]
337   </table>
338
339   <input type=button id='add_empty_mapping_line' value='[% 'Add empty line (csv_import)' | $T8 %]'>
340   <input type=button id='add_mapping_from_upload' value='[% 'Add headers from last uploaded file (csv_import)' | $T8 %]'>
341
342   </div>
343   <hr>
344 [%- END %][%# UNLESS SELF.worker.is_multiplexed %]
345 [%- END %][%# IF SELF.profile.get('dont_edit_profile') %]
346  </form>
347
348  <div id='results'>
349  [%- IF SELF.deferred %]
350    [%- PROCESS 'csv_import/_deferred_results.html' %]
351  [%- END %][%# IF SELF.deferred %]
352  </div>
353
354
355  <script type="text/javascript">
356   <!--
357     $(document).ready(function() {
358       $('#action_save').click(function() {
359         if ($('#profile_name').val() != '')
360           return true;
361         alert('[% LxERP.t8('Please enter a profile name.') %]');
362         return false;
363       });
364       $('#add_empty_mapping_line').click(function(){
365         $.get('controller.pl', { action: 'CsvImport/add_empty_mapping_line', 'profile.type': $('#profile_type').val() }, kivi.eval_json_result);
366       });
367       $('#add_mapping_from_upload').click(function(){
368         $.get('controller.pl?action_add_mapping_from_upload=1', $('form').serialize() , kivi.eval_json_result);
369       });
370       $('#csv_import_mappings').on('click', '.remove_line', function(){ $(this).closest('tr').remove(); if (1==$('#csv_import_mappings tr:visible').length) $('#mapping_empty').show() });
371     });
372     -->
373  </script>