]> wagnertech.de Git - mfinanz.git/blob - templates/design40_webpages/csv_import/form.html
date error in mapping
[mfinanz.git] / templates / design40_webpages / csv_import / form.html
1 [% USE HTML %]
2 [% USE LxERP %]
3 [% USE L %]
4 [% USE T8 %]
5
6 <h1>[% FORM.title %]</h1>
7
8 [% INCLUDE 'common/flash.html' %]
9
10 <form method="post" action="controller.pl" enctype="multipart/form-data" id="form">
11 [% L.hidden_tag('form_sent', '1') %]
12 [% L.hidden_tag('action', 'CsvImport/dispatch') %]
13 [% L.hidden_tag('profile.type', SELF.profile.type) %]
14 [% L.hidden_tag('tmp_profile_id', SELF.profile.id) %]
15
16 [% IF SELF.profile.get('dont_edit_profile') %]
17   [% L.hidden_tag('force_profile', 1) %]
18   [% L.hidden_tag('profile.id', SELF.profile.id) %]
19
20 [% ELSE %]
21
22 <div class="wrapper">
23
24 <table class="tbl-horizontal">
25   <caption>[% LxERP.t8('Import profiles') %]</caption>
26   <colgroup><col class="wi-mediumsmall"><col class="wi-wide"></colgroup>
27   <tbody>
28     [% IF SELF.profile.id %]
29     <tr>
30       <th>[% LxERP.t8('Current profile') %]:</th>
31       <td><h3>[% HTML.escape(SELF.profile.name) %]</h3></td>
32     </tr>
33     [% END %]
34     [% IF SELF.all_profiles.size %]
35     <tr>
36       <th>[% LxERP.t8('Existing profiles') %]:</th>
37       <td>
38         [% L.select_tag('profile.id', SELF.all_profiles, title_key = 'name', default = SELF.profile.id, class='wi-wide') %]
39         <div class="buttons below">
40           [% L.submit_tag('action_new', LxERP.t8('Load profile')) %]
41           [% L.submit_tag('action_destroy', LxERP.t8('Delete profile'), confirm => LxERP.t8('Do you really want to delete this object?')) %]
42         </div>
43       </td>
44     </tr>
45     [% END %]
46     <tr>
47       <th>[% LxERP.t8('Save settings as') %]:</th>
48       <td>
49         [% L.input_tag('profile.name', '', class='wi-wide') %]
50         <div class="below">
51           [% L.checkbox_tag('profile.is_default', label => LxERP.t8('Make default profile'), class='below') %]
52         </div>
53         <div class="buttons below">
54           [% L.submit_tag('action_save', LxERP.t8('Save profile')) %]
55         </div>
56       </td>
57     </tr>
58   </tbody>
59 </table>
60
61 </div><!-- /.wrapper -->
62
63 <div class="wrapper">
64
65 <div class="col wi-verywide">
66
67 <h3 class="caption">[% LxERP.t8('Settings') %]</h3>
68
69 [% BLOCK panel_1 %]
70 <table class="tbl-horizontal">
71   <colgroup><col class="wi-mediumsmall"><col class="wi-wide"></colgroup>
72   <tbody>
73     <tr>
74       <th>[% LxERP.t8('Number Format') %]:</th>
75       <td>[% L.select_tag('settings.numberformat', ['1.000,00', '1000,00', '1,000.00', '1000.00', "1'000.00"], default = SELF.profile.get('numberformat'), class='wi-normal') %]</td>
76     </tr>
77     <tr>
78      <th>[% LxERP.t8('Date Format') %]:</th>
79      <td>[% L.select_tag('settings.dateformat', ['dd.mm.yyyy', 'yyyy-mm-dd', 'dd/mm/yyyy', 'mm/dd/yyyy' ], default = SELF.profile.get('dateformat'), class='wi-normal') %]</td>
80     </tr>
81     <tr>
82       <th>[% LxERP.t8('Charset') %]:</th>
83       <td>[% L.select_tag('settings.charset', SELF.all_charsets, default = SELF.profile.get('charset'), class='wi-normal') %]</td>
84     </tr>
85     <tr>
86       <th>[% LxERP.t8('Separator') %]:</th>
87       <td>
88         [% SET custom_sep_char = SELF.sep_char %]
89         [% FOREACH entry = SELF.all_sep_chars %]
90           [% IF SELF.sep_char == entry.first %] [% SET custom_sep_char = '' %] [% END %]
91           [% L.radio_button_tag('sep_char', value => entry.first, label => entry.last, checked => SELF.sep_char == entry.first) %]<br>
92         [% END %]
93         [% L.radio_button_tag('sep_char', value => 'custom', checked => custom_sep_char != '') %]
94         [% L.input_tag('custom_sep_char', custom_sep_char, size => 3, maxlength => 1) %]
95       </td>
96     </tr>
97     <tr>
98       <th>[% LxERP.t8('Quote character') %]:</th>
99       <td>
100         [% SET custom_quote_char = SELF.quote_char %]
101         [% FOREACH entry = SELF.all_quote_chars %]
102           [% IF SELF.quote_char == entry.first %] [% SET custom_quote_char = '' %] [% END %]
103           [% L.radio_button_tag('quote_char', value => entry.first, label => entry.last, checked => SELF.quote_char == entry.first) %]<br>
104         [% END %]
105         [% L.radio_button_tag('quote_char', value => 'custom', checked => custom_quote_char != '') %]
106         [% L.input_tag('custom_quote_char', custom_quote_char, size => 3, maxlength => 1) %]
107       </td>
108     </tr>
109     <tr>
110       <th>[% LxERP.t8('Escape character') %]:</th>
111       <td>
112         [% SET custom_escape_char = SELF.escape_char %]
113         [% FOREACH entry = SELF.all_escape_chars %]
114           [% IF SELF.escape_char == entry.first %] [% SET custom_escape_char = '' %] [% END %]
115           [% L.radio_button_tag('escape_char', value => entry.first, label => entry.last, checked => SELF.escape_char == entry.first) %]<br>
116         [% END %]
117         [% L.radio_button_tag('escape_char', value => 'custom', checked => custom_escape_char != '') %]
118         [% L.input_tag('custom_escape_char', custom_escape_char, size => 3, maxlength => 1) %]
119       </td>
120     </tr>
121     [% duplicate_fields = SELF.worker.get_duplicate_check_fields() %]
122     [% IF ( duplicate_fields.size ) %]
123       <tr>
124         <th>[% LxERP.t8('Check for duplicates') %]:</th>
125         <td>
126         [% FOREACH key = duplicate_fields.keys %]
127           [% IF (SELF.profile.get('duplicates_'_ key) || (duplicate_fields.$key.default && !FORM.form_sent)) %] [% SET chckd=' checked' %]
128           [% ELSE %] [% SET chckd='' %]
129           [% END %]
130           <input type="checkbox" name="settings.duplicates_[% key | html %]" id="settings.duplicates_[% key | html %]" value="1"[% chckd %]>
131           <label for="settings.duplicates_[% key | html %]">[% duplicate_fields.$key.label | html %]</label><br>
132         [% END %]
133         </td>
134       </tr>
135       <tr>
136         <th></th>
137         <td>
138           [% opts = [ [ 'no_check',  LxERP.t8('Do not check for duplicates') ],
139                       [ 'check_csv', LxERP.t8('Discard duplicate entries in CSV file') ],
140                       [ 'check_db',  LxERP.t8('Discard entries with duplicates in database or CSV file') ] ] %]
141           [% L.select_tag('settings.duplicates', opts, default = SELF.profile.get('duplicates'), class='wi-wide') %]
142         </td>
143       </tr>
144     [% END %]
145     [% IF SELF.type == 'parts' %]
146       [% INCLUDE 'csv_import/_form_parts.html' %]
147     [% ELSIF SELF.type == 'customers_vendors' %]
148       [% INCLUDE 'csv_import/_form_customers_vendors.html' %]
149     [% ELSIF SELF.type == 'contacts' %]
150       [% INCLUDE 'csv_import/_form_contacts.html' %]
151     [% ELSIF SELF.type == 'inventories' %]
152       [% INCLUDE 'csv_import/_form_inventories.html' %]
153     [% ELSIF SELF.type == 'orders' %]
154       [% INCLUDE 'csv_import/_form_orders.html' %]
155     [% ELSIF SELF.type == 'delivery_orders' %]
156       [% INCLUDE 'csv_import/_form_delivery_orders.html' %]
157     [% ELSIF SELF.type == 'ar_transactions' %]
158       [% INCLUDE 'csv_import/_form_artransactions.html' %]
159     [% ELSIF SELF.type == 'ap_transactions' %]
160       [% INCLUDE 'csv_import/_form_aptransactions.html' %]
161     [% ELSIF SELF.type == 'bank_transactions' %]
162       [% INCLUDE 'csv_import/_form_banktransactions.html' %]
163     [% END %]
164     <tr>
165       <th>[% LxERP.t8('Preview Mode') %]:</th>
166       <td>
167         [% L.radio_button_tag('settings.full_preview', value=0, checked=!SELF.profile.get('full_preview'), label=LxERP.t8('Full Preview')) %]
168         [% 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')) %]
169         [% L.radio_button_tag('settings.full_preview', value=2, checked=SELF.profile.get('full_preview')==2,   label=LxERP.t8('First 20 Lines')) %]
170       </td>
171     </tr>
172     <tr>
173       <th>[% LxERP.t8('Import file') %]:</th>
174       <td>[% L.input_tag('file', '', type => 'file', accept => '*') %]</td>
175     </tr>
176     [% IF SELF.file.exists %]
177       <tr>
178         <th>[% LxERP.t8('Existing file on server') %]:</th>
179         <td>[% LxERP.t8('Uploaded on #1, size #2 kB', SELF.file.displayable_mtime, LxERP.format_amount(SELF.file.size / 1024, 2)) %]</td>
180       </tr>
181     [% END %]
182   </tbody>
183 </table>
184 [% END # panel_1 %]
185
186 [%
187   INCLUDE 'common/toggle_panel.html'
188   block_name     = 'panel_1'
189   toggle_class   = 'toggle_panel_1'
190   display_status = 'open'
191   button_closed  = LxERP.t8("Show settings")
192   button_open    = LxERP.t8("Hide settings")
193 %]
194
195 </div><!-- /.col -->
196
197 [% UNLESS SELF.worker.is_multiplexed %]
198
199 <div class="col wi-verywide">
200
201 <h3>[% 'Mappings (csv_import)' | $T8 %]</h3>
202
203 [% BLOCK panel_2 %]
204 <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>
205 <table id="csv_import_mappings" class="tbl-list">
206   <thead>
207     <tr>
208       <th>[% 'Action' | $T8 %]</th>
209       <th>[% 'Text in CSV File' | $T8 %]</th>
210       <th>[% 'Known Column' | $T8 %]</th>
211     </tr>
212   </thead>
213   <tbody>
214     <tr id="mapping_empty" style="display:none">
215       <td colspan="3">[% 'There is nothing here yet (csv_import)' | $T8 %]</td>
216     </tr>
217     [% FOREACH row = SELF.mappings %]
218       [% PROCESS 'csv_import/_mapping_item.html', item=row IF row.from %]
219     [% END %]
220     [% PROCESS 'csv_import/_mapping_item.html', item={} %]
221   </tbody>
222 </table>
223 <div class="button">
224   <input type="button" id="add_empty_mapping_line" value="[% 'Add empty line (csv_import)' | $T8 %]">
225   <input type="button" id="add_mapping_from_upload" value="[% 'Add headers from last uploaded file (csv_import)' | $T8 %]">
226 </div>
227 [% END # panel_2 %]
228
229 [%
230   INCLUDE 'common/toggle_panel.html'
231   block_name     = 'panel_2'
232   toggle_class   = 'toggle_panel_2'
233   display_status = 'open'
234   button_closed  = LxERP.t8("Show mappings (csv_import)")
235   button_open    = LxERP.t8("Hide mappings (csv_import)")
236 %]
237
238 </div><!-- /.col -->
239
240 [% END # UNLESS SELF.worker.is_multiplexed %]
241
242 [% IF SELF.deferred %]
243   <div id="results" class="horizontal-scroll-wrapper">
244     [% PROCESS 'csv_import/_deferred_results.html' %]
245   </div>
246 [% END %]
247
248 <div class="col wi-verywide">
249
250 <h3 class="caption">[% LxERP.t8('Help on column names') %]</h3>
251
252 [% BLOCK panel_3 %]
253   <div class="horizontal-scroll-wrapper">
254   [% IF SELF.worker.is_multiplexed %]
255     <table>
256       <tbody>
257         <tr>
258           [% FOREACH p = SELF.worker.profile %]
259             <th>[% p.row_ident %]</th>
260           [% END %]
261         </tr>
262         <tr>
263           [% FOREACH p = SELF.worker.profile %]
264             [% SET ri = p.row_ident %]
265             <td>
266               <table class="tbl-list">
267                 <thead>
268                   <tr>
269                     <th>[% LxERP.t8('Column name') %]</th>
270                     <th>[% LxERP.t8('Meaning') %]</th>
271                   </tr>
272                 </thead>
273                 <tbody>
274                   [% FOREACH row = SELF.displayable_columns.$ri %]
275                     <tr>
276                       <td>[% HTML.escape(row.name) %]</td>
277                       <td>[% HTML.escape(row.description) %]</td>
278                     </tr>
279                   [% END %]
280                 </tbody>
281               </table>
282             </td>
283           [% END %]
284         </tr>
285       </tbody>
286     </table>
287   [% ELSE %]
288     <table class="tbl-list">
289       <thead>
290         <tr>
291           <th>[% LxERP.t8('Column name') %]</th>
292           <th>[% LxERP.t8('Meaning') %]</th>
293         </tr>
294       </thead>
295       <tbody>
296         [% FOREACH row = SELF.displayable_columns %]
297         <tr>
298           <td>[% HTML.escape(row.name) %]</td>
299           <td>[% HTML.escape(row.description) %]</td>
300         </tr>
301         [% END %]
302       </tbody>
303     </table>
304   [% END %]
305   </div><!-- /.horizontal-scroll-wrapper -->
306   [% IF SELF.type == 'contacts' %]
307     <p>
308       [% LxERP.t8("You can update existing contacts by providing the 'cp_id' column with their database IDs. Otherwise: ") %]
309       [% 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') %]
310     </p>
311   [% ELSIF SELF.type == 'addresses' %]
312     <p>[% 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') %]</p>
313   [% ELSIF SELF.type == 'parts' %]
314     <p>
315       [1]:
316       [% 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.') %]
317       [% 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).') %]
318       [% LxERP.t8('The items are imported accoring do their number "X" regardless of the column order inside the file.') %]
319       [% LxERP.t8('The column "make_X" can contain either a vendor\'s database ID, a vendor number or a vendor\'s name.') %]
320     </p>
321     <p>
322       [2]:
323       [% 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.') %]
324     </p>
325     <p>
326       [3]:
327       [% LxERP.t8("If the article type is set to 'mixed' then a column called 'part_type' or called 'pclass' must be present.") %]
328       [% LxERP.t8("Type can be either 'part', 'service' or 'assembly'.") %]
329       [% LxERP.t8("If column 'pclass' is present the article type is then irrelevant or used as default ") %]
330       [% 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") %]
331     </p>
332   [% ELSIF SELF.type == 'inventories' %]
333     <p>[% 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.') %]</p>
334   [% ELSIF SELF.type == 'orders' OR SELF.type == 'delivery_orders' OR SELF.type == 'ar_transactions' %]
335     <p>
336       [1]:
337       [% 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.') %]
338     </p>
339     <p>
340     [% IF SELF.type == 'orders' OR SELF.type == 'ar_transactions' %]
341       <p>
342         [2]:
343         [% LxERP.t8('Amount and net amount are calculated by kivitendo. "verify_amount" and "verify_netamount" can be used for sanity checks.') %]<br>
344         [% LxERP.t8('If amounts differ more than "Maximal amount difference" (see settings), this item is marked as invalid.') %]<br>
345       </p>
346     [% END %]
347   [% END %][%# IF SELF.type == … %]
348   <p>[% L.submit_tag('action_download_sample', LxERP.t8('Download sample file')) %]</p>
349 [% END # panel_3 %]
350
351 [%
352   INCLUDE 'common/toggle_panel.html'
353   block_name    = 'panel_3'
354   toggle_class  = 'toggle_panel_3'
355   button_closed = LxERP.t8("Show help text")
356   button_open   = LxERP.t8("Hide help text")
357 %]
358
359
360 </div><!-- /.col -->
361
362 [% END %]<!-- # /ELSE SELF.profile.get('dont_edit_profile') -->
363
364
365
366 </form>
367
368 <div class="col wi-wide">
369
370
371
372
373 </div><!-- /.col -->
374
375 </div><!-- /.wrapper -->
376
377
378 <script type="text/javascript">
379   $(document).ready(function() {
380     $('#action_save').click(function() {
381       if ($('#profile_name').val() != '')
382         return true;
383       alert('[% LxERP.t8('Please enter a profile name.') %]');
384       return false;
385     });
386     $('#add_empty_mapping_line').click(function(){
387       $.get('controller.pl', { action: 'CsvImport/add_empty_mapping_line', 'profile.type': $('#profile_type').val() }, kivi.eval_json_result);
388     });
389     $('#add_mapping_from_upload').click(function(){
390       $.get('controller.pl?action_add_mapping_from_upload=1', $('form').serialize() , kivi.eval_json_result);
391     });
392     $('#csv_import_mappings').on('click', '.remove_line', function(){ $(this).closest('tr').remove(); if (1==$('#csv_import_mappings tr:visible').length) $('#mapping_empty').show() });
393   });
394 </script>