From ff1b3d334503363b3148c3b4b3a7a9b9fb603f3e Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 29 Mar 2011 21:46:54 +0000 Subject: [PATCH] Add ability to add unknown categories & statuses --- .../class.timesheet_export_openoffice.inc.php | 10 +-- .../inc/class.timesheet_import_csv.inc.php | 90 ++++++++++++++----- .../class.timesheet_wizard_import_csv.inc.php | 62 +++++++++++++ timesheet/setup/etemplates.inc.php | 4 +- 4 files changed, 140 insertions(+), 26 deletions(-) diff --git a/timesheet/inc/class.timesheet_export_openoffice.inc.php b/timesheet/inc/class.timesheet_export_openoffice.inc.php index 220e380bf6..f300ead9b4 100644 --- a/timesheet/inc/class.timesheet_export_openoffice.inc.php +++ b/timesheet/inc/class.timesheet_export_openoffice.inc.php @@ -25,7 +25,7 @@ class timesheet_export_openoffice implements importexport_iface_export_plugin { */ public function export( $_stream, importexport_definition $_definition) { - $options = $_definition->options; + $options = $_definition->plugin_options; $botimesheet = new timesheet_bo(); @@ -33,11 +33,11 @@ class timesheet_export_openoffice implements importexport_iface_export_plugin { $query = $GLOBALS['egw']->session->appsession('index',TIMESHEET_APP); - $bo_pm = CreateObject('projectmanager.boprojectmanager'); + $bo_pm = CreateObject('projectmanager.projectmanager_bo'); $childs = $bo_pm->children( $query['col_filter']['pm_id'] ); $childs[] = $query['col_filter']['pm_id']; $pmChilds = implode(",",$childs); - $botimesheet->db->select( 'egw_links','link_id, link_id1','', + $GLOBALS['egw']->db->select( 'egw_links','link_id, link_id1','', __LINE__,__FILE__,False, '',False,0, 'JOIN egw_pm_projects ON (pm_id = link_id2) @@ -189,7 +189,7 @@ class timesheet_export_openoffice implements importexport_iface_export_plugin { * @return string html */ public function get_options_etpl() { - return 'timesheet.export_openoffice_options'; + return false; } /** @@ -197,7 +197,7 @@ class timesheet_export_openoffice implements importexport_iface_export_plugin { * */ public function get_selectors_etpl() { - return 'Selectors:'; + return array('preserv' => true); } } diff --git a/timesheet/inc/class.timesheet_import_csv.inc.php b/timesheet/inc/class.timesheet_import_csv.inc.php index 30fb770155..4e6772c5bf 100644 --- a/timesheet/inc/class.timesheet_import_csv.inc.php +++ b/timesheet/inc/class.timesheet_import_csv.inc.php @@ -146,7 +146,7 @@ class timesheet_import_csv implements importexport_iface_import_plugin { // For converting human-friendly lookups $categories = new categories('timesheet'); $lookups = array( - 'ts_status' => $bo->status_labels, + 'ts_status' => $this->bo->status_labels, 'cat_id' => $categories->return_sorted_array(0,False,'','','',true) ); @@ -163,42 +163,92 @@ class timesheet_import_csv implements importexport_iface_import_plugin { // don't import empty records if( count( array_unique( $record ) ) < 2 ) continue; + // Date / time + $record['ts_start'] = strtotime($record['ts_start']); + // Automatically handle text categories without explicit translation - $record['cat_id'] = importexport_helper_functions::cat_name2id($record['cat_id']); + foreach(array('ts_status','cat_id') as $field) { + if(!is_numeric($record[$field])) { + $translate_key = 'translate'.(substr($field,0,2) == 'ts' ? substr($field,2) : '_cat_id'); + if($key = array_search($record[$field], $lookups[$field])) { + $record[$field] = $key; + } elseif(array_key_exists($translate_key, $_definition->plugin_options)) { + $t_field = $_definition->plugin_options[$translate_key]; + switch ($t_field) { + case '': + case '0': + // Skip that field + unset($record[$field]); + break; + case '~skip~': + continue 2; + default: + if(strpos($t_field, 'add') === 0) { + // Check for a parent + list($name, $parent_name) = explode('~',$t_field); + if($parent_name) { + $parent = importexport_helper_functions::cat_name2id($parent_name); + } + + if($field == 'cat_id') { + $record[$field] = importexport_helper_functions::cat_name2id($record[$field], $parent); + } elseif ($field == 'ts_status') { + end($this->bo->status_labels); + $id = key($this->bo->status_labels)+1; + $this->bo->status_labels[$id] = $record[$field]; + $this->bo->status_labels_config[$id] = array( + 'name' => $record[$field], + 'parent' => $parent, + 'admin' => false + ); + config::save_value('status_labels',$this->bo->status_labels_config,TIMESHEET_APP); + $lookups[$field][$id] = $name; + $record[$field] = $id; + } + } elseif($key = array_search($t_field, $lookups[$field])) { + $record[$field] = $key; + } else { + $record[$field] = $t_field; + } + break; + } + } + } + } // Set creator, unless it's supposed to come from CSV file - if($_definition->plugin_options['creator_from_csv']) { - if(!is_numeric($record['ts_owner'])) { + if($_definition->plugin_options['owner_from_csv'] && $record['ts_owner'] && !is_numeric($record['ts_owner'])) { + // Automatically handle text owner without explicit translation + $new_owner = importexport_helper_functions::account_name2id($record['ts_owner']); + if($new_owner == '') { $this->errors[$import_csv->get_current_position()] = lang( - 'Invalid owner ID: %1. Might be a bad field translation. Used %2 instead.', - $record['ts_owner'], - $_definition->plugin_options['creator'] + 'Unable to convert "%1" to account ID. Using plugin setting (%2) for %3.', + $record['ts_owner'], + common::grab_owner_name($_definition->plugin_options['creator']), + lang($this->bo->field2label['ts_owner']) ); $record['ts_owner'] = $_definition->plugin_options['creator']; + } else { + $record['ts_owner'] = $new_owner; } } elseif ($_definition->plugin_options['creator']) { $record['ts_owner'] = $_definition->plugin_options['creator']; } // Check account IDs - foreach(array('ts_owner','ts_modifier') as $field) { + foreach(array('ts_modifier') as $field) { if($record[$field] && !is_numeric($record[$field])) { // Try an automatic conversion - $contact_id = self::addr_id($record[$field]); - if($contact_id) { - $contact = $addressbook->read($contact_id); - $account_id = $contact['account_id']; - } else { - $accounts = $GLOBALS['egw']->accounts->search(array('type' => 'both','query'=>$record[$field])); - if($accounts) $account_id = key($accounts); - } - if($account_id && common::grab_owner_name($account_id) == $record[$field]) { + $account_id = importexport_helper_functions::account_name2id($record[$field]); + if($account_id && strtoupper(common::grab_owner_name($account_id)) == strtoupper($record[$field])) { $record[$field] = $account_id; } else { $this->errors[$import_csv->get_current_position()] = lang( - 'Invalid field: %1 = %2, it needs to be a number.', $field, $record[$field] + 'Unable to convert "%1" to account ID. Using plugin setting (%2) for %3.', + $record[$field], + common::grab_owner_name($_definition->plugin_options['creator']), + $this->bo->field2label[$field] ? lang($this->bo->field2label[$field]) : $field ); - continue 2; } } } @@ -301,7 +351,7 @@ class timesheet_import_csv implements importexport_iface_import_plugin { $this->errors[$record_num] = lang('Permissions error - %1 could not %2', $GLOBALS['egw']->accounts->id2name($_data['owner']), lang($_action) - ) . $result; + ) . ' ' . $result; } else { $this->results[$_action]++; $result = $this->bo->data['ts_id']; diff --git a/timesheet/inc/class.timesheet_wizard_import_csv.inc.php b/timesheet/inc/class.timesheet_wizard_import_csv.inc.php index 5df17fbf8e..0d7c0c688f 100644 --- a/timesheet/inc/class.timesheet_wizard_import_csv.inc.php +++ b/timesheet/inc/class.timesheet_wizard_import_csv.inc.php @@ -21,10 +21,13 @@ class timesheet_wizard_import_csv extends importexport_wizard_basic_import_csv parent::__construct(); $this->steps += array( + 'wizard_step45' => lang('Import options'), 'wizard_step50' => lang('Manage mapping'), 'wizard_step60' => lang('Choose \'creator\' of imported data'), ); + $this->step_templates['wizard_step45'] = 'timesheet.wizard_import_options'; + // Field mapping $bo = new timesheet_bo(); $this->mapping_fields = array('ts_id' => lang('Timesheet ID')) + $bo->field2label; @@ -57,6 +60,65 @@ class timesheet_wizard_import_csv extends importexport_wizard_basic_import_csv ); } + function wizard_step45(&$content, &$sel_options, &$readonlys, &$preserv) + { + if($this->debug) error_log(__METHOD__.'->$content '.print_r($content,true)); + + // return from step45 + if ($content['step'] == 'wizard_step45') + { + switch (array_search('pressed', $content['button'])) + { + case 'next': + return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1); + case 'previous' : + return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],-1); + case 'finish': + return 'wizard_finish'; + default : + return $this->wizard_step45($content,$sel_options,$readonlys,$preserv); + } + } + // init step45 + else + { + $content['message'] = $this->steps['wizard_step45']; + $content['step'] = 'wizard_step45'; + + $ui = new timesheet_ui(); + $options = array( + false => lang('Ignore'), + '~skip~' => lang('Skip record'), + 'add' => lang('Add'), + ); + $set_to = lang('Set to') . ':'; + $categories = new categories('timesheet'); + $cat_list = array(); + foreach((array)$categories->return_sorted_array(0,False,'','','',true) as $cat) { + $s = str_repeat(' ',$cat['level']) . stripslashes($cat['name']); + + if (categories::is_global($cat)) + { + $s .= ' ♦'; + } + $cat_list[$cat['id']] = empty($cat['description']) ? $s : array( + 'label' => $s, + 'title' => $cat['description'], + ); + } + $sel_options = array( + 'translate_status' => $options + array($set_to => $ui->status_labels), + 'translate_cat_id' => $options + array($set_to => $cat_list), + ); + $preserv = $content; + foreach($sel_options as $field => $options) { + if(!array_key_exists($field,$content)) $content[$field] = $content['plugin_options'][$field]; + } + unset ($preserv['button']); + return $this->step_templates['wizard_step45']; + } + } + function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv) { $result = parent::wizard_step50($content, $sel_options, $readonlys, $preserv); diff --git a/timesheet/setup/etemplates.inc.php b/timesheet/setup/etemplates.inc.php index fae057546c..73b314c3ca 100644 --- a/timesheet/setup/etemplates.inc.php +++ b/timesheet/setup/etemplates.inc.php @@ -2,7 +2,7 @@ /** * eGroupWare - eTemplates for Application timesheet * http://www.egroupware.org - * generated by soetemplate::dump4setup() 2011-02-04 11:33 + * generated by soetemplate::dump4setup() 2011-03-29 13:40 * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package timesheet @@ -71,3 +71,5 @@ $templ_data[] = array('name' => 'timesheet.index.dates','template' => '','lang' $templ_data[] = array('name' => 'timesheet.index.rows','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:9:{s:2:"c1";s:2:"th";s:2:"c2";s:16:"$row_cont[class]";s:1:"A";s:3:"15%";s:1:"B";s:3:"50%";s:1:"H";s:14:",@no_owner_col";s:1:"G";s:13:",@no_ts_total";s:1:"F";s:17:",@no_ts_unitprice";s:1:"E";s:16:",@no_ts_quantity";s:1:"I";s:14:",@no_ts_status";}i:1;a:11:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"Date";s:4:"name";s:8:"ts_start";}s:1:"B";a:7:{s:4:"type";s:4:"grid";s:7:"no_lang";s:1:"1";s:4:"data";a:5:{i:0;a:2:{s:2:"h1";s:21:",@pm_integration=full";s:2:"h2";s:22:",!@pm_integration=full";}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"size";s:12:"All projects";s:4:"name";s:10:"ts_project";s:7:"no_lang";s:1:"1";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:22:"nextmatch-customfilter";s:4:"size";s:34:"projectmanager-select,All projects";s:4:"name";s:5:"pm_id";s:8:"onchange";i:1;}}i:3;a:1:{s:1:"A";a:6:{s:4:"type";s:22:"nextmatch-customfilter";s:4:"size";s:10:"link-entry";i:1;a:5:{s:4:"type";s:10:"link-entry";s:4:"size";s:15:"infolog,infolog";s:4:"name";s:11:"nm[info_id]";s:8:"onchange";i:1;s:4:"blur";s:14:"select Infolog";}i:2;a:2:{s:4:"type";s:6:"button";s:5:"label";s:6:"submit";}s:8:"onchange";i:1;s:4:"name";s:6:"linked";}}i:4;a:1:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Title";s:4:"name";s:8:"ts_title";}}}s:4:"rows";i:4;s:4:"cols";i:1;s:4:"size";s:7:",,,,0,0";s:7:"options";a:2:{i:4;s:1:"0";i:5;s:1:"0";}}s:1:"C";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Category";s:4:"name";s:6:"cat_id";}s:1:"D";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Duration";s:4:"name";s:11:"ts_duration";}i:2;a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:8:"duration";s:4:"size";s:6:",h,,,1";s:8:"readonly";s:1:"1";}}s:1:"E";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:6:"2,,0,0";i:1;a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:8:"Quantity";s:4:"name";s:11:"ts_quantity";}i:2;a:4:{s:4:"type";s:5:"float";s:4:"name";s:8:"quantity";s:8:"readonly";s:1:"1";s:4:"size";s:4:",,,3";}}s:1:"F";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Price";s:4:"name";s:12:"ts_unitprice";}s:1:"G";a:4:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Total";s:4:"name";s:8:"ts_total";}i:2;a:4:{s:4:"type";s:5:"float";s:4:"name";s:5:"price";s:8:"readonly";s:1:"1";s:4:"size";s:4:",,,2";}}s:1:"H";a:5:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"name";s:8:"ts_owner";s:4:"size";s:4:"User";s:7:"no_lang";s:1:"1";s:4:"span";s:18:",$cont[ownerClass]";}s:1:"I";a:4:{s:4:"type";s:22:"nextmatch-filterheader";s:4:"name";s:9:"ts_status";s:8:"onchange";i:1;s:4:"size";s:10:"All status";}s:1:"J";a:2:{s:4:"type";s:22:"nextmatch-customfields";s:4:"name";s:12:"customfields";}s:1:"K";a:5:{s:4:"type";s:4:"hbox";s:4:"span";s:8:",noPrint";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:5:"label";s:7:"Actions";s:4:"span";s:8:",noPrint";s:5:"align";s:5:"right";}i:2;a:7:{s:4:"type";s:6:"button";s:5:"label";s:9:"Check all";s:4:"size";s:5:"check";s:4:"name";s:9:"check_all";s:6:"needed";s:1:"1";s:4:"help";s:9:"Check all";s:7:"onclick";s:60:"toggle_all(this.form,form::name(\'checked[]\')); return false;";}}}i:2;a:11:{s:1:"A";a:4:{s:4:"type";s:9:"date-time";s:4:"name";s:16:"${row}[ts_start]";s:8:"readonly";s:1:"1";s:4:"size";s:2:",8";}s:1:"B";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:6:"3,,0,0";i:1;a:3:{s:4:"type";s:4:"link";s:4:"name";s:15:"${row}[ts_link]";s:7:"no_lang";s:1:"1";}i:2;a:4:{s:4:"type";s:5:"label";s:4:"name";s:16:"${row}[ts_title]";s:7:"no_lang";s:1:"1";s:4:"span";s:22:",$row_cont[titleClass]";}i:3;a:3:{s:4:"type";s:5:"label";s:4:"name";s:22:"${row}[ts_description]";s:7:"no_lang";s:1:"1";}}s:1:"C";a:4:{s:4:"type";s:10:"select-cat";s:8:"readonly";s:1:"1";s:4:"name";s:14:"${row}[cat_id]";s:4:"span";s:7:",noWrap";}s:1:"D";a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:19:"${row}[ts_duration]";s:8:"readonly";s:1:"1";s:4:"size";s:6:",h,,,1";}s:1:"E";a:5:{s:4:"type";s:5:"float";s:4:"name";s:19:"${row}[ts_quantity]";s:7:"no_lang";s:1:"1";s:4:"size";s:4:",,,3";s:8:"readonly";s:1:"1";}s:1:"F";a:3:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:20:"${row}[ts_unitprice]";}s:1:"G";a:5:{s:4:"type";s:5:"float";s:7:"no_lang";s:1:"1";s:4:"name";s:16:"${row}[ts_total]";s:4:"size";s:4:",,,2";s:8:"readonly";s:1:"1";}s:1:"H";a:4:{s:4:"type";s:14:"select-account";s:4:"name";s:16:"${row}[ts_owner]";s:8:"readonly";s:1:"1";s:4:"span";s:18:",$cont[ownerClass]";}s:1:"I";a:3:{s:4:"type";s:6:"select";s:4:"name";s:17:"${row}[ts_status]";s:8:"readonly";s:1:"1";}s:1:"J";a:3:{s:4:"type";s:17:"customfields-list";s:4:"name";s:4:"$row";s:8:"readonly";s:1:"1";}s:1:"K";a:9:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"5";i:1;a:6:{s:4:"type";s:6:"button";s:4:"size";s:4:"view";s:5:"label";s:4:"View";s:4:"name";s:22:"view[$row_cont[ts_id]]";s:7:"onclick";s:187:"window.open(egw::link(\'/index.php\',\'menuaction=timesheet.timesheet_ui.view&ts_id=$row_cont[ts_id]\'),\'_blank\',\'dependent=yes,width=600,height=400,scrollbars=yes,status=yes\'); return false;";s:4:"help";s:15:"View this entry";}i:2;a:6:{s:4:"type";s:6:"button";s:4:"size";s:4:"edit";s:5:"label";s:4:"Edit";s:4:"name";s:22:"edit[$row_cont[ts_id]]";s:4:"help";s:15:"Edit this entry";s:7:"onclick";s:187:"window.open(egw::link(\'/index.php\',\'menuaction=timesheet.timesheet_ui.edit&ts_id=$row_cont[ts_id]\'),\'_blank\',\'dependent=yes,width=600,height=400,scrollbars=yes,status=yes\'); return false;";}i:3;a:5:{s:4:"type";s:6:"button";s:4:"name";s:26:"document[$row_cont[ts_id]]";s:4:"size";s:15:"etemplate/merge";s:5:"label";s:18:"Insert in document";s:4:"span";s:8:",image16";}s:4:"span";s:8:",noPrint";i:4;a:6:{s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"name";s:24:"delete[$row_cont[ts_id]]";s:4:"help";s:17:"Delete this entry";s:7:"onclick";s:36:"return confirm(\'Delete this entry\');";}s:5:"align";s:5:"right";i:5;a:4:{s:4:"type";s:8:"checkbox";s:4:"size";s:16:"$row_cont[ts_id]";s:4:"name";s:9:"checked[]";s:4:"help";s:47:"Select multiple timeshhets for a further action";}}}}s:4:"rows";i:2;s:4:"cols";i:11;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1296843833',); +$templ_data[] = array('name' => 'timesheet.wizard_import_options','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:1:{s:2:"h1";s:10:",!@message";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:11:"all,message";s:4:"name";s:7:"message";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:40:"What should be done with unknown values?";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Status";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:16:"translate_status";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:8:"Category";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:16:"translate_cat_id";}}}s:4:"rows";i:4;s:4:"cols";i:2;}}','size' => '','style' => '','modified' => '1301427589',); +