* Import|Export: Add ability to set filters for export definitions. Currently available for Infolog.

This commit is contained in:
Nathan Gray 2013-01-09 16:38:19 +00:00
commit 0180124753
25 changed files with 984 additions and 79 deletions

View File

@ -150,7 +150,7 @@ class customfields_widget
}
}
// check if name refers to a single custom field --> show only that
if (($pos=strpos($cell['name'],$this->prefix)) !== false && // allow the prefixed name to be an array index too
if (($pos=@strpos($cell['name'],$this->prefix)) !== false && // allow the prefixed name to be an array index too
preg_match("/$this->prefix([^\]]+)/",$cell['name'],$matches) && isset($fields[$name=$matches[1]]))
{
$fields = array($name => $fields[$name]);
@ -258,6 +258,7 @@ class customfields_widget
$input =& etemplate::empty_cell('select',$this->prefix.$lname,array(
'sel_options' => $field['values'],
'size' => $field['rows'],
'enhance' => $field['enhance'],
'no_lang' => True,
));
if($this->advanced_search)

View File

@ -124,6 +124,11 @@ function selectbox_add_option(id,label,value,do_onchange)
selectBox.options[selectBox.length] = new Option(label,value,false,true);
}
if (selectBox.onchange && do_onchange) selectBox.onchange();
// If chosen is loaded, trigger update
if(selectBox && $j().chosen) {
$j(selectBox).trigger("liszt:updated");
}
}
/* toggles all checkboxes named name in form form, to be used as custom javascript in onclick of a button/image */

View File

@ -0,0 +1,257 @@
<?php
/**
* Widget for setting filters
*
* @author Nathan Gray
* @version $Id$
*/
/**
* Extend custom fields and make an general advanced filter
*
* Much of this is copied from customfields_widget and adapted.
* We assume that the app can handle pretty much any field => value combination
* we send via col_filter, but the plugin gets a chance to interpret the filter
* settings.
*
* Selectboxes are easy, we just turn them into multi-selects.
*
* For dates we either use a relative date selection, or a literal date selection.
* Relative date options are in importexport_helper_functions::$relative_dates
*
* Most text fields are ignored.
*/
class filter_widget extends customfields_widget
{
public $prefix = '';
public $human_name = array(
'filter' => 'Import|Export filter'
);
public function __construct($ui, $appname = null)
{
$this->advanced_search = true;
parent::__construct($ui, $appname);
}
/**
* pre-processing of the extension
*
* This function is called before the extension gets rendered
*
* @param string $form_name form-name of the control
* @param mixed &$value value / existing content, can be modified
* @param array &$cell array with the widget, can be modified for ui-independent widgets
* @param array &$readonlys names of widgets as key, to be made readonly
* @param mixed &$extension_data data the extension can store persisten between pre- and post-process
* @param etemplate &$tmpl reference to the template we belong too
* @return boolean true if extra label is allowed, false otherwise
*/
public function pre_process($form_name,&$value,&$cell,&$readonlys,&$extension_data,$tmpl)
{
$fields = $value['fields'];
unset($value['fields']);
list($relative_dates) = explode(',',$cell['size']);
if($cell['relative_dates']) $relative_dates = true;
// Fallback, so there's something there...
if(!is_array($fields))
{
$cell['type'] = 'label';
$cell['label'] = 'No fields';
return True;
}
// making the cell an empty grid
$cell['type'] = 'grid';
$cell['data'] = array(array());
$cell['rows'] = $cell['cols'] = 0;
$cell['size'] = '';
$n = 1;
foreach($fields as $lname => $field)
{
$new_row = null; boetemplate::add_child($cell,$new_row);
$row_class = 'row';
boetemplate::add_child($cell,$label =& boetemplate::empty_cell('label','',array(
'label' => $field['label'],
'no_lang' => substr(lang($field['label']),-1) == '*' ? 2 : 0,
'span' => $field['type'] === 'label' ? '2' : '',
)));
switch($field['type'])
{
case 'date':
case 'date-time':
// Need a range here
$options = '';
if($relative_dates)
{
$input = self::do_relative_date($lname, $value, $options, $readonly);
}
else
{
$input = self::do_absolute_date($lname, $value, $options, $readonly);
}
break;
case 'ajax_select' :
// Set some reasonable defaults for the widget
$options = array(
'get_title' => 'etemplate.ajax_select_widget.array_title',
'get_rows' => 'etemplate.ajax_select_widget.array_rows',
'id_field' => ajax_select_widget::ARRAY_KEY,
);
if($field['rows']) {
$options['num_rows'] = $field['rows'];
}
// If you specify an option known to the AJAX Select widget, it will be pulled from the list of values
// and used as such. All unknown values will be used for selection, not passed through to the query
if (isset($field['values']['@']))
{
$options['values'] = $this->_get_options_from_file($field['values']['@']);
unset($field['values']['@']);
} else {
$options['values'] = array_diff_key($field['values'], array_flip(ajax_select_widget::$known_options));
}
$options = array_merge($options, array_intersect_key($field['values'], array_flip(ajax_select_widget::$known_options)));
$input = boetemplate::empty_cell('ajax_select', $lname, array(
'readonly' => $readonly,
'no_lang' => True,
'size' => $options
));
break;
case 'link-entry':
$input =& boetemplate::empty_cell('link-entry',$this->prefix.$lname,array(
'size' => $field['type'] == 'link-entry' ? '' : $field['type'],
));
// register post-processing of link widget to get eg. needed/required validation
etemplate_old::$request->set_to_process(etemplate_old::form_name($form_name,$this->prefix.$lname), 'ext-link');
break;
case 'select':
default:
if(strpos($field['type'],'select') === 0)
{
if (count($field['values']) == 1 && isset($field['values']['@']))
{
$field['values'] = $this->_get_options_from_file($field['values']['@']);
}
foreach((array)$field['values'] as $key => $val)
{
if (substr($val = lang($val),-1) != '*')
{
$field['values'][$key] = $val;
}
}
$input =& boetemplate::empty_cell($field['type'],$lname,array(
'sel_options' => $field['values'],
'size' => $field['rows'],
'enhance' => true,
'no_lang' => True,
));
}
elseif (in_array($field['type'], array_keys(egw_link::app_list())))
{
// Link entry to a specific app
$input =& boetemplate::empty_cell('link-entry',$lname,array(
'size' => $field['type'] == 'link-entry' ? '' : $field['type'],
));
// register post-processing of link widget to get eg. needed/required validation
etemplate_old::$request->set_to_process(etemplate_old::form_name($form_name,$lname), 'ext-link');
} else {
error_log('Trying to filter with unsupported field type: ' . $field['type']);
$input =& boetemplate::empty_cell($field['type'],$lname,array(
'sel_options' => $field['values'],
'size' => $field['rows'],
'no_lang' => True,
));
}
}
$cell['data'][0]['c'.$n++] = $row_class.',top';
if (!is_null($input))
{
if ($readonly) $input['readonly'] = true;
$input['needed'] = $cell['needed'] || $field['needed'];
if (!empty($field['help']) && $row_class != 'th')
{
$input['help'] = $field['help'];
$input['no_lang'] = substr(lang($help),-1) == '*' ? 2 : 0;
}
boetemplate::add_child($cell,$input);
unset($input);
}
unset($label);
}
return false;
}
/**
* Create widgets to select a relative date range
*
* @param $lname Field name
* @param $options
* @param $readonly
*
* @return Array of widget info
*/
protected static function do_relative_date($lname, Array &$value, $options, $readonly)
{
// Maybe this could be moved to date widget
$input = boetemplate::empty_cell('select',$lname, array(
'readonly' => $readonly,
'no_lang' => true,
'options' => $options,
'sel_options' => array('' => lang('all'))
));
foreach(importexport_helper_functions::$relative_dates as $label => $values)
{
$input['sel_options'][$label] = lang($label);
}
return $input;
}
/**
* Create widgets to select an absolute date range
*
* @param $lname Field name
* @param $options
* @param $readonly
*
* @return Array of widget info
*/
protected static function do_absolute_date($lname, Array &$value, $options, $readonly)
{
$input = boetemplate::empty_cell('hbox',$lname);
$type = 'date';
$from = boetemplate::empty_cell($type, $lname.'[from]',array(
'readonly' => $readonly,
'no_lang' => True,
'size' => $options
));
$to = boetemplate::empty_cell($type, $lname.'[to]', array(
'readonly' => $readonly,
'no_lang' => True,
'size' => $options
));
boetemplate::add_child($input, $from);
boetemplate::add_child($input,boetemplate::empty_cell('label','',array(
'label' => lang('to'),
'no_lang' => true
)));
boetemplate::add_child($input, $to);
return $input;
}
}

View File

@ -31,6 +31,7 @@ class importexport_definition implements importexport_iface_egw_record {
'type' => 'string',
'allowed_users' => 'array',
'plugin_options' => 'array',
'filter' => 'array',
'owner' => 'int',
'description' => 'string',
'modified' => 'timestamp'
@ -86,6 +87,8 @@ class importexport_definition implements importexport_iface_egw_record {
{
error_log($e->getMessage());
}
if($this->definition['filter']) $filter = importexport_arrayxml::xml2array( $this->definition['filter'] );
$this->definition['filter'] = $filter['root'];
}
}
@ -117,6 +120,8 @@ class importexport_definition implements importexport_iface_egw_record {
return $this->get_allowed_users();
case 'plugin_options' :
return $this->get_options();
case 'filter':
return $this->get_filter();
default :
return $this->definition[$_attribute_name];
}
@ -131,6 +136,8 @@ class importexport_definition implements importexport_iface_egw_record {
return $this->set_allowed_users($_data);
case 'plugin_options' :
return $this->set_options($_data);
case 'filter':
return $this->set_filter((Array)$_data);
default :
$this->definition[$_attribute_name] = $_data;
return;
@ -173,6 +180,24 @@ class importexport_definition implements importexport_iface_egw_record {
$this->definition['plugin_options'] = $_plugin_options;
}
/**
* Get stored data filter
*
* @return array
*/
private function get_filter() {
return $this->definition['filter'];
}
/**
* Set stored data filter
*
* @param filter array of field => settings
*/
private function set_filter(Array $filter) {
$this->definition['filter'] = $filter;
}
/**
* converts this object to array.
* @abstract We need such a function cause PHP5
@ -185,6 +210,7 @@ class importexport_definition implements importexport_iface_egw_record {
$definition = $this->definition;
$definition['allowed_users'] = $this->get_allowed_users();
$definition['plugin_options'] = $this->get_options();
$definition['filter'] = $this->get_filter();
return $definition;
}
@ -218,6 +244,7 @@ class importexport_definition implements importexport_iface_egw_record {
// convert plugin_options into internal representation
$this->set_allowed_users( $this->definition['allowed_users'] );
$this->set_options( $this->definition['plugin_options'] ? $this->definition['plugin_options'] : array());
$this->set_filter( $this->definition['filter'] ? $this->definition['filter'] : array());
}
/**
@ -242,6 +269,7 @@ class importexport_definition implements importexport_iface_egw_record {
$this->so_sql->data = $this->definition;
$this->so_sql->data['plugin_options'] = importexport_arrayxml::array2xml( $this->definition['plugin_options'] );
$this->so_sql->data['filter'] = importexport_arrayxml::array2xml( $this->definition['filter'] );
$this->so_sql->data['modified'] = time();
if ($this->so_sql->save( array( 'definition_id' => $_dst_identifier ))) {
throw new Exception('Error: so_sql was not able to save definition: '.$this->get_identifier());

View File

@ -610,6 +610,7 @@ class importexport_definitions_ui
{
$this->response = new xajaxResponse();
egw_framework::include_css_js_response();
if ($content['closewindow'])
{
$this->response->addScript("opener.location.reload();");
@ -637,6 +638,7 @@ class importexport_definitions_ui
{
$GLOBALS['egw']->js->set_onload("document.getElementById('picturebox').style.display = 'none';");
egw_framework::validate_file('.', 'etemplate', 'etemplate');
egw_framework::validate_file('.', 'etemplate', 'etemplate');
common::egw_header();
echo '<div id="divMain">'."\n";
echo '<div><h3>{Im|Ex}port Wizard</h3></div>';

View File

@ -29,10 +29,15 @@ class importexport_export_csv implements importexport_iface_export_record
*/
protected $conversion = array();
/**
* @var Current record being processed
*/
public $record;
/**
* @var array holding the current record
*/
protected $record = array();
protected $record_array = array();
/**
* @var translation holds (charset) translation object
@ -145,7 +150,8 @@ class importexport_export_csv implements importexport_iface_export_record
* @return bool
*/
public function export_record( importexport_iface_egw_record $_record ) {
$this->record = $_record->get_record_array();
$this->record = $_record;
$this->record_array = $_record->get_record_array();
// begin with fieldnames ?
if ($this->num_of_records == 0 && $this->csv_options['begin_with_fieldnames'] ) {
@ -175,7 +181,7 @@ class importexport_export_csv implements importexport_iface_export_record
}
}
}
$mapping = ! empty( $this->mapping ) ? $this->mapping : array_keys ( $this->record );
$mapping = ! empty( $this->mapping ) ? $this->mapping : array_keys ( $this->record_array );
self::fputcsv( $this->handle ,$mapping ,$this->csv_options['delimiter'], $this->csv_options['enclosure'] );
}
@ -186,19 +192,19 @@ class importexport_export_csv implements importexport_iface_export_record
// do conversions
if ( !empty( $this->conversion )) {
$this->record = importexport_helper_functions::conversion( $this->record, $this->conversion );
$this->record_array = importexport_helper_functions::conversion( $this->record_array, $this->conversion );
}
// do fieldmapping
if ( !empty( $this->mapping ) ) {
$record_data = $this->record;
$this->record = array();
$record_data = $this->record_array;
$this->record_array = array();
foreach ($this->mapping as $egw_field => $csv_field) {
$this->record[$csv_field] = $record_data[$egw_field];
$this->record_array[$csv_field] = $record_data[$egw_field];
}
}
self::fputcsv( $this->handle, $this->record, $this->csv_options['delimiter'], $this->csv_options['enclosure'] );
self::fputcsv( $this->handle, $this->record_array, $this->csv_options['delimiter'], $this->csv_options['enclosure'] );
$this->num_of_records++;
}

View File

@ -173,13 +173,31 @@ class importexport_export_ui {
$content['plugin_options_template'] = $options;
}
}
$content['filter'] = $definition->filter;
$content['filter']['fields'] = importexport_helper_functions::get_filter_fields($_appname, $selected_plugin);
if(!$content['filter']['fields'])
{
$this->js->set_onload("\$j('input[value=\"filter\"]').parent().hide();");
$content['no_filter'] = true;
}
else
{
// Process relative dates into the current absolute date
foreach($content['filter']['fields'] as $field => $settings)
{
if($content['filter'][$field] && strpos($settings['type'],'date') === 0)
{
$content['filter'][$field] = importexport_helper_functions::date_rel2abs($content['filter'][$field]);
}
}
}
}
// fill selection tab
if($definition && $definition->plugin_options['selection'] && !$content['selection_passed']) {
if($definition && is_array($definition->plugin_options) && $definition->plugin_options['selection'] && !$content['selection_passed']) {
$_selection = $definition->plugin_options['selection'];
}
if ($_selection && ($content['old_definition'] == $content['definition'] || $content['selection_passed'])) {
$readonlys[$tabs]['selection_tab'] = true;
$content['selection'] = $_selection;
@ -209,9 +227,18 @@ class importexport_export_ui {
disable_button('exec[export]');
");
}
// Disable / hide definition filter if not selected
if($content['selection'] !== 'filter')
{
$this->js->set_onload("
\$j('div.filters').hide();
");
}
$preserv['old_definition'] = $content['definition'];
if (($prefs = $GLOBALS['egw_info']['user']['preferences']['importexport'][$definition->definition_id]) &&
($prefs = unserialize($prefs)) && !$content['selection']['plugin_override'])
($prefs = unserialize($prefs)) && is_array($content['selection']) && !$content['selection']['plugin_override'])
{
$selection = $content['selection'];
$content = array_merge_recursive($content,$prefs);
@ -260,6 +287,35 @@ class importexport_export_ui {
'mapping' => array()
);
}
// Set filter
// Note that because not all dates are DB dates, the plugin has to handle them
$filter = $definition->filter;
if(is_array($_content['filter']))
{
foreach($_content['filter'] as $key => $value)
{
// Handle multiple values
if(!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value);
$filter[$key] = $value;
// Skip empty values or empty ranges
if(!$value || is_array($value) && array_key_exists('from',$value) && !$value['from'] && !$value['to'] )
{
unset($filter[$key]);
}
// If user selects an end date, they most likely want entries including that date
if(is_array($value) && array_key_exists('to',$value) && $value['to'] )
{
// Adjust time to 23:59:59
$filter[$key]['to'] = mktime(23,59,59,date('n',$value['to']),date('j',$value['to']),date('Y',$value['to']));
}
}
}
unset($_content['filter']);
$definition->filter = $filter;
$definition->plugin_options = array_merge(
$definition->plugin_options,
$_content
@ -287,7 +343,17 @@ class importexport_export_ui {
}
}
$plugin_object = new $definition->plugin;
$plugin_object->export( $file, $definition );
$result = $plugin_object->export( $file, $definition );
if(is_object($result) && method_exists($result, 'get_num_of_records'))
{
$record_count = $result->get_num_of_records();
if($record_count == 0)
{
$response->addScript('alert("' . lang('No matching records') . '");');
return $response->getXML();
}
}
// Keep settings
$keep = array_diff_key($_content, array_flip(array('appname', 'definition', 'plugin', 'preview', 'export', $tabs)));
@ -302,7 +368,20 @@ class importexport_export_ui {
fclose($file);
$filename = pathinfo($tmpfname, PATHINFO_FILENAME);
$response->addScript("xajax_eT_wrapper();");
$response->addScript("opener.location.href='". $GLOBALS['egw']->link('/index.php','menuaction=importexport.importexport_export_ui.download&_filename='. $filename.'&_appname='. $definition->application). "&_suffix=". $plugin_object->get_filesuffix(). "&_type=".$plugin_object->get_mimetype() ."';");
$link_query = array(
'menuaction' => 'importexport.importexport_export_ui.download',
'_filename' => $filename,
'_appname' => $definition->application,
'_suffix' => $plugin_object->get_filesuffix(),
'_type' => $plugin_object->get_mimetype()
);
// Allow plugins to suggest a file name - return false if they have no suggestion
if(method_exists($plugin_object, 'get_filename') && $plugin_filename = $plugin_object->get_filename())
{
$link_query['filename'] = $plugin_filename;
}
$response->addScript("opener.location.href='". $GLOBALS['egw']->link('/index.php',$link_query)."'");
$response->addScript('window.setTimeout("window.close();", 100);');
return $response->getXML();
}
@ -329,9 +408,12 @@ class importexport_export_ui {
$GLOBALS['egw']->translation->charset()
);
if($record_count)
{
$preview = "<div class='header'>".lang('Preview') . "<span class='count'>$record_count</span></div>".$preview;
}
$response->addAssign('exec[preview-box]','innerHTML',nl2br($preview));
$response->jquery('.preview-box','show');
$response->jquery('.preview-box-buttons','show');
$response->jquery('.preview_box','show');
$response->addScript("xajax_eT_wrapper();");
return $response->getXML();
@ -494,7 +576,7 @@ class importexport_export_ui {
if (!is_readable($tmpfname)) die();
$appname = $_GET['_appname'];
$nicefname = 'egw_export_'.$appname.'-'.date('Y-m-d');
$nicefname = $_GET['filename'] ? $_GET['filename'] : 'egw_export_'.$appname.'-'.date('Y-m-d');
// Turn off all output buffering
while (@ob_end_clean());

View File

@ -26,6 +26,25 @@ class importexport_helper_functions {
*/
public static $dry_run = false;
/**
* Relative date ranges for filtering
*/
public static $relative_dates = array( // Start: year,month,day,week, End: year,month,day,week
'Today' => array(0,0,0,0, 0,0,1,0),
'Yesterday' => array(0,0,-1,0, 0,0,0,0),
'This week' => array(0,0,0,0, 0,0,0,1),
'Last week' => array(0,0,0,-1, 0,0,0,0),
'This month' => array(0,0,0,0, 0,1,0,0),
'Last month' => array(0,-1,0,0, 0,0,0,0),
'Last 3 months' => array(0,-3,0,0, 0,0,0,0),
'This quarter'=> array(0,0,0,0, 0,0,0,0), // Just a marker, needs special handling
'Last quarter'=> array(0,-4,0,0, 0,-4,0,0), // Just a marker
'This year' => array(0,0,0,0, 1,0,0,0),
'Last year' => array(-1,0,0,0, 0,0,0,0),
'2 years ago' => array(-2,0,0,0, -1,0,0,0),
'3 years ago' => array(-3,0,0,0, -2,0,0,0),
);
/**
* Files known to cause problems, and will be skipped in a plugin scan
* If you put appname => true, the whole app will be skipped.
@ -514,4 +533,181 @@ class importexport_helper_functions {
}
return $list;
}
/**
* Get a list of filterable fields, and options for those fields
*
* It tries to automatically pull filterable fields from the list of fields in the wizard,
* and sets widget properties. The plugin can edit / set the fields by implementing
* get_filter_fields(Array &$fields).
*
* Currently only supports select,select-cat,select-account,date,date-time
*
* @param $app_name String name of app
* @param $plugin_name Name of the plugin
*
* @return Array ([fieldname] => array(widget settings), ...)
*/
public static function get_filter_fields($app_name, $plugin_name, $wizard_plugin = null, $record_classname = null)
{
$fields = array();
try {
if($record_classname == null) $record_classname = $app_name . '_egw_record';
if(!class_exists($record_classname)) throw new Exception('Bad class name ' . $record_classname);
$plugin = is_object($plugin_name) ? $plugin_name : new $plugin_name();
$plugin_name = get_class($plugin);
if(!$wizard_plugin)
{
$wizard_name = $app_name . '_wizard_' . str_replace($app_name . '_', '', $plugin_name);
if(!class_exists($wizard_name)) throw new Exception('Bad wizard name ' . $wizard_name);
$wizard_plugin = new $wizard_name;
}
}
catch (Exception $e)
{
error_log($e->getMessage());
return array();
}
// Get field -> label map and initialize fields using wizard field order
$fields = $export_fields = $wizard_plugin->get_export_fields();
foreach($record_classname::$types as $type => $type_fields)
{
// Only these for now, until filter methods for others are figured out
if(!in_array($type, array('select','select-cat','select-account','date','date-time'))) continue;
foreach($type_fields as $field_name)
{
$fields[$field_name] = array(
'name' => $field_name,
'label' => $export_fields[$field_name] ? $export_fields[$field_name] : $field_name,
'type' => $type
);
}
}
// Add custom fields
$custom = config::get_customfields($app_name);
foreach($custom as $field_name => $settings)
{
$settings['name'] = '#'.$field_name;
$fields['#'.$field_name] = $settings;
}
foreach($fields as $field_name => &$settings) {
// Can't really filter on these (or at least no generic, sane way figured out yet)
if(!is_array($settings) || in_array($settings['type'], array('text','button', 'label','url','url-email','url-phone','htmlarea')))
{
unset($fields[$field_name]);
continue;
}
if($settings['type'] == 'radio') $settings['type'] = 'select';
switch($settings['type'])
{
case 'checkbox':
// This isn't quite right - there's only 2 options and you can select both
$settings['type'] = 'select-bool';
$settings['rows'] = 1;
$settings['enhance'] = true;
break;
case 'select-cat':
$settings['rows'] = "5,,,$app_name";
$settings['enhance'] = true;
break;
case 'select-account':
$settings['rows'] = '5,both';
$settings['enhance'] = true;
break;
case 'select':
$settings['rows'] = 5;
$settings['enhance'] = true;
break;
}
}
if(method_exists($plugin, 'get_filter_fields'))
{
$plugin->get_filter_fields($fields);
}
return $fields;
}
/**
* Parse a relative date (Yesterday) into absolute (2012-12-31) date
*
* @param $value String description of date matching $relative_dates
*
* @return Array([from] => timestamp, [to]=> timestamp), inclusive
*/
public static function date_rel2abs($value)
{
if(is_array($value))
{
$abs = array();
foreach($value as $key => $val)
{
$abs[$key] = self::date_rel2abs($val);
}
return $abs;
}
if($date = self::$relative_dates[$value])
{
$year = (int) date('Y');
$month = (int) date('m');
$day = (int) date('d');
$today = mktime(0,0,0,date('m'),date('d'),date('Y'));
list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) = $date;
if(stripos($value, 'quarter') !== false)
{
// Handle quarters
$start = mktime(0,0,0,((int)floor(($smonth+$month) / 3.1)) * 3 + 1, 1, $year);
$end = mktime(0,0,0,((int)floor(($emonth+$month) / 3.1)+1) * 3 + 1, 1, $year);
}
elseif ($syear || $eyear)
{
$start = mktime(0,0,0,1,1,$syear+$year);
$end = mktime(0,0,0,1,1,$eyear+$year);
}
elseif ($smonth || $emonth)
{
$start = mktime(0,0,0,$smonth+$month,1,$year);
$end = mktime(0,0,0,$emonth+$month,1,$year);
}
elseif ($sday || $eday)
{
$start = mktime(0,0,0,$month,$sday+$day,$year);
$end = mktime(0,0,0,$month,$eday+$day,$year);
}
elseif ($sweek || $eweek)
{
$wday = (int) date('w'); // 0=sun, ..., 6=sat
switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
{
case 'Sunday':
$weekstart = $today - $wday * 24*60*60;
break;
case 'Saturday':
$weekstart = $today - (6-$wday) * 24*60*60;
break;
case 'Moday':
default:
$weekstart = $today - ($wday ? $wday-1 : 6) * 24*60*60;
break;
}
$start = $weekstart + $sweek*7*24*60*60;
$end = $weekstart + $eweek*7*24*60*60;
}
$end_param = $end - 24*60*60;
// Take 1 second off end to provide an inclusive range.for filtering
$end -= 1;
//echo __METHOD__."($value,$start,$end) today=".date('l, Y-m-d H:i',$today)." ==> <br />".date('l, Y-m-d H:i:s',$start)." <= date <= ".date('l, Y-m-d H:i:s',$end)."</p>\n";
return array('from' => $start, 'to' => $end);
}
return null;
}
} // end of importexport_helper_functions

View File

@ -301,8 +301,52 @@ class importexport_import_csv implements importexport_iface_import_record { //,
}
}
foreach((array)$fields['links'] as $name) {
if($record[$name]) {
// TODO
if($record[$name] && $links[$name])
{
// Primary key to another app, not a link
// Text - search for a matching record
if(!is_numeric($record[$name]))
{
$results = egw_link::query($links[$name], $record[$name]);
if(count($results) > 1)
{
// More than 1 result. Check for exact match
$exact_count = 0;
foreach($results as $id => $title)
{
if($title == $record[$name])
{
$exact_count++;
$app_id = $id;
continue;
}
unset($results[$id]);
}
// Too many exact matches, or none good enough
if($exact_count > 1 || count($results) == 0)
{
$warnings[] = lang('Unable to link to %1 "%2"',
lang($links[$name]), $record[$name]).
' - ' .lang('too many matches');
$record[$name] = null;
continue;
}
elseif ($exact_count == 1)
{
$record[$name] = $app_id;
}
}
if (count($results) == 0)
{
$warnings[] = lang('Unable to link to %1 "%2"',
lang($links[$name]), $record[$name]).
' - ' . lang('no matches');
$record[$name] = null;
continue;
} else {
$record[$name] = key($results);
}
}
}
}
foreach((array)$fields['select-account'] as $name) {

View File

@ -460,8 +460,30 @@
if($type == 'export')
{
// Set to export all
$definition->plugin_options = array_merge($definition->plugin_options, array('selection' => 'all'));
// Set to export all or filter, if set
$selection = array('selection' => 'all');
if($definition->filter)
{
$fields = importexport_helper_functions::get_filter_fields($definition->application, $po);
$selection = array('selection' => 'filter');
$filters = array();
foreach($definition->filter as $field => $value)
{
// Handle multiple values
if(!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value);
$filters[$field] = $value;
// Process relative dates into the current absolute date
if($filters[$field] && strpos($fields[$field]['type'],'date') === 0)
{
$filters[$field] = importexport_helper_functions::date_rel2abs($value);
}
}
// Update filter to use current absolute dates
$definition->filter = $filters;
}
$definition->plugin_options = array_merge($definition->plugin_options, $selection);
}
foreach($targets as $target)

View File

@ -1,12 +1,12 @@
<?php
/**
* eGroupWare - A basic implementation of a wizard to go with the basic CSV plugin.
*
*
* To add or remove steps, change $this->steps appropriately. The key is the function, the value is the title.
* Don't go past 80, as that's where the wizard picks it back up again to finish it off.
*
*
* For the field list to work properly, you'll have to populate $export_fields with the fields available
*
*
* NB: Your wizard class must be in <appname>/inc/class.appname_wizard_<plugin_name>.inc.php
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@ -15,7 +15,7 @@
* @author Nathan Gray
*/
class importexport_wizard_basic_export_csv
class importexport_wizard_basic_export_csv
{
const TEMPLATE_MARKER = '-eTemplate-';
@ -31,6 +31,7 @@ class importexport_wizard_basic_export_csv
protected $step_templates = array(
'wizard_step30' => 'importexport.wizard_basic_export_csv.choose_fields',
'wizard_step40' => 'importexport.wizard_basic_export_csv.choosesepncharset',
'wizard_step80' => 'importexport.wizard_basic_export_csv.filter',
);
@ -58,6 +59,7 @@ class importexport_wizard_basic_export_csv
$this->steps = array(
'wizard_step30' => lang('Choose fields to export'),
'wizard_step40' => lang('Choose seperator and charset'),
'wizard_step80' => lang('Filters'),
);
list($appname, $part2) = explode('_', get_class($this));
if(!$GLOBALS['egw_info']['apps'][$appname]) $appname .= '_'.$part2; // Handle apps with _ in the name
@ -212,6 +214,73 @@ class importexport_wizard_basic_export_csv
}
/**
* Set export filters
*
* @param array $content
* @param array $sel_options
* @param array $readonlys
* @param array $preserv
* @return string template name
*/
function wizard_step80(&$content, &$sel_options, &$readonlys, &$preserv)
{
if($this->debug) error_log(get_class($this) . '::' . __METHOD__ .'->$content '.print_r($content,true));
// return from submit
if ($content['step'] == 'wizard_step80') {
// Process submitted
unset($content['filter']);
unset($content['set_filter']['fields']);
foreach($content['set_filter'] as $key => $value)
{
if($value) {
$content['filter'][$key] = $value;
}
}
unset($content['set_filter']);
// Next step
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_step80($content,$sel_options,$readonlys,$preserv);
}
} else {
// Step 50 - filters
$content['msg'] = $this->steps['wizard_step80'];
$content['step'] = 'wizard_step80';
// Find filterable fields
if(!$content['set_filter'] && $content['filter']) {
$load = true;
}
$content['set_filter']['fields'] = importexport_helper_functions::get_filter_fields(
$content['application'],$content['plugin'],$this
);
// Load existing filter from either content or definition
if($load)
{
foreach($content['set_filter']['fields'] as $field => $settings)
{
$content['set_filter'][$field] = $content['filter'][$field];
}
}
$sel_options = array();
$preserv = $content;
unset ($preserv['button']);
return $this->step_templates[$content['step']];
}
}
/**
* Expose export fields for use elsewhere
*/

View File

@ -10,5 +10,8 @@ function clear_options(id) {
for(var count = list.options.length - 1; count >= 0; count--) {
list.options[count] = null;
}
if($j().chosen && list) {
$j(list).trigger("liszt:updated");
}
}

View File

@ -68,6 +68,7 @@ load sample file importexport en Load sample file
manage mapping importexport en Manage mapping
next importexport en Next
next run importexport en Next run
no matching records importexport en No matching records
no records selected importexport en No records selected!
old fixed definition preferences en Old fixed definition
please select file to import importexport en Please select file to import

View File

@ -2,7 +2,7 @@
/**
* EGroupware - eTemplates for Application importexport
* http://www.egroupware.org
* generated by soetemplate::dump4setup() 2012-12-03 15:42
* generated by soetemplate::dump4setup() 2013-01-07 11:24
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package importexport
@ -59,26 +59,36 @@ $templ_data[] = array('name' => 'importexport.definition_index.row','template' =
cursor: pointer;
}','modified' => '1305674060',);
$templ_data[] = array('name' => 'importexport.export_dialog','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:7:{i:0;a:1:{s:2:"c3";s:15:"save_definition";}i:1;a:1:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:3:"msg";}}i:2;a:1:{s:1:"A";a:3:{s:4:"type";s:3:"tab";s:5:"label";s:25:"General|Selection|Options";s:4:"name";s:37:"general_tab|selection_tab|options_tab";}}i:3;a:1:{s:1:"A";a:3:{s:4:"type";s:8:"checkbox";s:5:"label";s:18:"Save as definition";s:4:"name";s:18:"save_as_definition";}}i:4;a:1:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";s:4:"span";s:3:"all";i:1;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Export";s:4:"name";s:6:"export";s:7:"onclick";s:36:"xajax_eT_wrapper(this);return false;";}i:2;a:4:{s:4:"type";s:6:"button";s:5:"label";s:7:"Preview";s:4:"name";s:7:"preview";s:7:"onclick";s:36:"xajax_eT_wrapper(this);return false;";}}i:2;a:5:{s:4:"type";s:6:"button";s:5:"label";s:6:"Cancel";s:5:"align";s:5:"right";s:4:"name";s:6:"cancel";s:7:"onclick";s:29:"window.close(); return false;";}}}i:5;a:1:{s:1:"A";a:6:{s:4:"type";s:3:"box";s:4:"size";s:1:"1";s:4:"name";s:11:"preview-box";s:6:"needed";s:1:"1";i:1;a:1:{s:4:"type";s:5:"label";}s:4:"span";s:12:",preview-box";}}i:6;a:1:{s:1:"A";a:7:{s:4:"type";s:3:"box";s:4:"size";s:1:"1";s:4:"span";s:20:",preview-box-buttons";s:4:"name";s:19:"preview-box-buttons";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:2:"OK";s:5:"align";s:6:"center";s:7:"onclick";s:167:"document.getElementById(form::name(\'preview-box\')).style.display=\'none\'; document.getElementById(form::name(\'preview-box-buttons\')).style.display=\'none\'; return false;";}s:6:"needed";s:1:"1";s:5:"align";s:6:"center";}}}s:4:"rows";i:6;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '.preview-box {
$templ_data[] = array('name' => 'importexport.export_dialog','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:6:{i:0;a:1:{s:2:"c3";s:15:"save_definition";}i:1;a:1:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:4:"name";s:3:"msg";}}i:2;a:1:{s:1:"A";a:3:{s:4:"type";s:3:"tab";s:5:"label";s:25:"General|Selection|Options";s:4:"name";s:37:"general_tab|selection_tab|options_tab";}}i:3;a:1:{s:1:"A";a:3:{s:4:"type";s:8:"checkbox";s:5:"label";s:18:"Save as definition";s:4:"name";s:18:"save_as_definition";}}i:4;a:1:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";s:4:"span";s:3:"all";i:1;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:6:"Export";s:4:"name";s:6:"export";s:7:"onclick";s:36:"xajax_eT_wrapper(this);return false;";}i:2;a:4:{s:4:"type";s:6:"button";s:5:"label";s:7:"Preview";s:4:"name";s:7:"preview";s:7:"onclick";s:36:"xajax_eT_wrapper(this);return false;";}}i:2;a:5:{s:4:"type";s:6:"button";s:5:"label";s:6:"Cancel";s:5:"align";s:5:"right";s:4:"name";s:6:"cancel";s:7:"onclick";s:29:"window.close(); return false;";}}}i:5;a:1:{s:1:"A";a:6:{s:4:"type";s:3:"box";s:4:"name";s:11:"preview_box";s:4:"size";s:1:"2";s:4:"span";s:15:"all,preview_box";i:1;a:6:{s:4:"type";s:3:"box";s:4:"size";s:1:"1";s:4:"name";s:11:"preview-box";s:6:"needed";s:1:"1";i:1;a:1:{s:4:"type";s:5:"label";}s:4:"span";s:8:",content";}i:2;a:6:{s:4:"type";s:3:"box";s:4:"size";s:1:"1";s:4:"span";s:20:",preview-box-buttons";s:4:"name";s:19:"preview-box-buttons";i:1;a:4:{s:4:"type";s:6:"button";s:5:"label";s:2:"OK";s:5:"align";s:6:"center";s:7:"onclick";s:86:"document.getElementById(form::name(\'preview_box\')).style.display=\'none\'; return false;";}s:5:"align";s:6:"center";}}}}s:4:"rows";i:5;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '.preview_box {
position: absolute;
top: 0px;
left: 0px;
width: 400px;
height: 360px;
overflow: scroll;
width: 97%;
height: 95%;
overflow: hidden;
background-color: white;
z-index: 999;
display: none;
border: 1px solid black;
margin: 1.5%;
}
.preview-box-buttons {
.preview_box .header {
font-size: 150%;
margin-bottom: 5px;
padding: 5px;
border-bottom: 1px outset;
}
.header .count {
float:right;
}
.preview_box>.content {
overflow: auto;
}
.preview-box-buttons {
position: absolute;
top: 365px;
left: 0px;
width: 400px;
height: 20px;
z-index: 999;
display: none;
bottom: 0px;
width: 100%;
margin-left: 50%;
}','modified' => '1296146438',);
$templ_data[] = array('name' => 'importexport.export_dialog.general_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:1:{s:2:"c1";s:4:",top";}i:1;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"image";s:4:"name";s:6:"export";}s:1:"B";a:2:{s:4:"type";s:8:"template";s:4:"name";s:46:"importexport.export_dialog.general_tab_content";}}}s:4:"rows";i:1;s:4:"cols";i:2;s:4:"size";s:6:",200px";s:7:"options";a:1:{i:1;s:5:"200px";}}}','size' => ',200px','style' => '','modified' => '1158223670',);
@ -89,7 +99,14 @@ $templ_data[] = array('name' => 'importexport.export_dialog.options_tab','templa
display: none;
}','modified' => '1286482130',);
$templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:4:",top";s:2:"h1";s:27:",@plugin_selectors_template";}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"name";s:21:"plugin_selectors_html";s:7:"no_lang";s:1:"1";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:26:"@plugin_selectors_template";}}}s:4:"rows";i:2;s:4:"cols";i:1;s:4:"size";s:6:",200px";s:7:"options";a:1:{i:1;s:5:"200px";}}}','size' => ',200px','style' => '','modified' => '1158223796',);
$templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:10:{s:2:"h3";s:30:"20,!@plugin_selectors_template";s:2:"h2";s:27:",@plugin_selectors_template";s:2:"c2";s:4:",top";s:2:"h4";s:28:",!@plugin_selectors_template";s:2:"c3";s:2:"th";s:2:"h1";s:29:"20,@plugin_selectors_template";s:2:"c1";s:2:"th";s:2:"c4";s:4:",top";s:1:"B";s:14:"300,@no_filter";s:1:"A";s:3:"150";}i:1;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Definition filter";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"name";s:21:"plugin_selectors_html";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"span";s:8:",filters";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:6:"filter";s:4:"name";s:6:"filter";}}}i:3;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Definition filter";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:26:"@plugin_selectors_template";}s:1:"B";a:5:{s:4:"type";s:3:"box";s:4:"span";s:8:",filters";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:6:"filter";s:4:"name";s:6:"filter";}s:7:"onclick";s:105:"\\$j(\'input[value=\\\'filter\\\']\').not(\':checked\').attr(\'checked\',true).parent().effect(\'highlight\',{},2000);";}}}s:4:"rows";i:4;s:4:"cols";i:2;s:4:"size";s:10:"100%,200px";s:7:"options";a:2:{i:0;s:4:"100%";i:1;s:5:"200px";}}}','size' => '100%,200px','style' => 'select[multiple] {
width: 400px;
}
.filters {
max-height: 300px;
min-height: 150px;
overflow-y: auto;
}','modified' => '1158223796',);
$templ_data[] = array('name' => 'importexport.import_definition','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:4:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:92:"Import definitions (Attension: Existing definitions with equal names will be overwritten!!!)";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:4:"file";s:4:"name";s:11:"import_file";}}i:3;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Import";s:4:"name";s:6:"import";}i:2;a:3:{s:4:"type";s:6:"button";s:4:"name";s:6:"update";s:5:"label";s:26:"Update default-definitions";}}}}s:4:"rows";i:3;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1306253183',);
@ -114,6 +131,10 @@ $templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.choosesepn
$templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.choose_fields','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:4:"name";s:3:"msg";}}i:2;a:1:{s:1:"A";a:7:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c1";s:2:"th";}i:1;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Field";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Export";}i:2;a:7:{s:4:"type";s:10:"buttononly";s:4:"size";s:5:"check";s:5:"label";s:9:"Check all";s:4:"name";s:9:"check_all";s:4:"help";s:9:"Check all";s:7:"onclick";s:98:"jQuery(\'input:checkbox\').attr(\'checked\', !jQuery(\'input:checkbox\').attr(\'checked\')); return false;";s:6:"needed";s:1:"1";}}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"name";s:12:"${row}[name]";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:8:"checkbox";s:7:"no_lang";s:1:"1";s:4:"name";s:14:"export[${row}]";s:4:"size";s:18:"{$row_cont[field]}";}}}s:4:"rows";i:2;s:4:"cols";i:2;s:4:"size";s:10:",,,,,,auto";s:4:"name";s:6:"fields";s:7:"options";a:1:{i:6;s:4:"auto";}}}}s:4:"rows";i:2;s:4:"cols";i:1;s:7:"options";a:0:{}}}','size' => '','style' => '','modified' => '1286466690',);
$templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.filter','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:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:6:"filter";s:4:"name";s:10:"set_filter";s:4:"size";s:1:"1";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => 'select {
width: 200px;
}','modified' => '1356969972',);
$templ_data[] = array('name' => 'importexport.wizard_basic_import_csv.choosesepncharset','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:7:{i:0;a:2:{s:1:"B";s:5:"180px";s:2:"h5";s:9:",@no_cats";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:3:"msg";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Fieldseperator";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:7:"no_lang";s:1:"1";s:4:"name";s:8:"fieldsep";s:4:"size";s:1:"1";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:15:"Charset of file";}s:1:"B";a:4:{s:4:"type";s:6:"select";s:7:"no_lang";s:1:"1";s:4:"name";s:7:"charset";s:4:"span";s:9:",width180";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:20:"Header lines to skip";}s:1:"B";a:3:{s:4:"type";s:3:"int";s:4:"name";s:16:"num_header_lines";s:4:"size";s:1:"0";}}i:5;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Update categories";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:11:"update_cats";}}i:6;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Import data is";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:7:"convert";}}}s:4:"rows";i:6;s:4:"cols";i:2;}}','size' => '','style' => '.width180 select { width:150px;}','modified' => '1287425796',);
$templ_data[] = array('name' => 'importexport.wizard_basic_import_csv.conditions','template' => '','lang' => '','group' => '0','version' => '1.9.002','data' => 'a:1:{i:0;a:8:{s:4:"type";s:4:"vbox";s:4:"data";a:2:{i:0;a:0:{}i:1;a:4:{s:1:"A";a:2:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[string]";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[type]";}i:2;a:2:{s:4:"type";s:4:"text";s:4:"name";s:12:"${row}[op_2]";}}s:1:"C";a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[true]";}s:1:"D";a:2:{s:4:"type";s:6:"select";s:4:"name";s:13:"${row}[false]";}}}s:4:"rows";i:1;s:4:"cols";i:4;s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:142:"How to merge with existing data? For each record, all conditions are evaluated from top to bottom, or stop. For blind insert, leave blank. ";}i:2;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c1";s:2:"th";}i:1;a:6:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Field";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:9:"Condition";}s:1:"C";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:4:"span";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:4:"span";s:1:"2";s:5:"label";s:4:"True";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,2,0";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";}i:2;a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Stop";s:5:"align";s:5:"right";}}}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:4:"span";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:4:"span";s:1:"2";s:5:"label";s:5:"False";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,2,0";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";}i:2;a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Stop";s:5:"align";s:5:"right";}}}s:1:"F";a:1:{s:4:"type";s:5:"label";}}i:2;a:6:{s:1:"A";a:4:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[string]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:3:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[type]";s:7:"no_lang";s:1:"1";}i:2;a:3:{s:4:"type";s:4:"text";s:4:"name";s:12:"${row}[op_2]";s:7:"no_lang";s:1:"1";}}s:1:"C";a:4:{s:4:"type";s:6:"select";s:4:"name";s:20:"${row}[true][action]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:8:"checkbox";s:5:"align";s:6:"center";s:4:"name";s:18:"${row}[true][stop]";}s:1:"E";a:4:{s:4:"type";s:6:"select";s:4:"name";s:21:"${row}[false][action]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"F";a:4:{s:4:"type";s:8:"checkbox";s:5:"align";s:6:"center";s:4:"name";s:19:"${row}[false][stop]";s:4:"size";s:7:"1,false";}}}s:4:"rows";i:2;s:4:"cols";i:6;s:4:"name";s:10:"conditions";s:7:"options";a:0:{}}i:3;a:5:{s:4:"type";s:6:"button";s:4:"name";s:11:"button[add]";s:5:"label";s:3:"add";s:4:"help";s:27:"Add an additional condition";s:7:"onclick";s:37:"xajax_eT_wrapper(this); return false;";}}}','size' => '','style' => '','modified' => '1320350666',);

View File

@ -10,7 +10,7 @@
*/
$setup_info['importexport']['name'] = 'importexport';
$setup_info['importexport']['version'] = '1.9.003';
$setup_info['importexport']['version'] = '1.9.004';
$setup_info['importexport']['app_order'] = 2;
$setup_info['importexport']['enable'] = 2;
$setup_info['importexport']['tables'] = array('egw_importexport_definitions');
@ -51,3 +51,4 @@ $setup_info['importexport']['check_install'] = array(
),
);

View File

@ -25,7 +25,8 @@ $phpgw_baseline = array(
'plugin_options' => array('type' => 'longtext'),
'owner' => array('type' => 'int','precision' => '20'),
'description' => array('type' => 'varchar','precision' => '255'),
'modified' => array('type' => 'timestamp')
'modified' => array('type' => 'timestamp'),
'filter' => array('type' => 'longtext')
),
'pk' => array('definition_id'),
'fk' => array(),

View File

@ -100,3 +100,13 @@ function importexport_upgrade1_9_002()
return $GLOBALS['setup_info']['importexport']['currentver'] = '1.9.003';
}
function importexport_upgrade1_9_003()
{
$GLOBALS['egw_setup']->oProc->AddColumn('egw_importexport_definitions','filter',array(
'type' => 'longtext'
));
return $GLOBALS['setup_info']['importexport']['currentver'] = '1.9.004';
}

View File

@ -52,19 +52,44 @@
</grid>
</template>
<template id="importexport.export_dialog.selection_tab" template="" lang="" group="0" version="">
<grid height="200px">
<grid width="100%" height="200px">
<columns>
<column/>
<column width="150"/>
<column width="300" disabled="@no_filter"/>
</columns>
<rows>
<row class="th" height="20" disabled="@plugin_selectors_template">
<description/>
<description value="Definition filter"/>
</row>
<row valign="top" disabled="@plugin_selectors_template">
<html id="plugin_selectors_html" no_lang="1"/>
<box class="filters">
<filter id="filter"/>
</box>
</row>
<row>
<row class="th" height="20" disabled="!@plugin_selectors_template">
<description/>
<description value="Definition filter"/>
</row>
<row valign="top" disabled="!@plugin_selectors_template">
<template id="@plugin_selectors_template"/>
<box onclick="\$j('input[value=\'filter\']').not(':checked').attr('checked',true).parent().effect('highlight',{},2000);" class="filters">
<filter id="filter"/>
</box>
</row>
</rows>
</grid>
<styles>
select[multiple] {
width: 400px;
}
.filters {
max-height: 300px;
min-height: 150px;
overflow-y: auto;
}
</styles>
</template>
<template id="importexport.export_dialog.options_tab" template="" lang="" group="0" version="">
<grid height="200px">
@ -141,38 +166,48 @@
</hbox>
</row>
<row>
<box id="preview-box" needed="1" class="preview-box">
<description/>
</box>
</row>
<row>
<box align="center" id="preview-box-buttons" needed="1" class="preview-box-buttons">
<button align="center" label="OK" onclick="document.getElementById(form::name('preview-box')).style.display='none'; document.getElementById(form::name('preview-box-buttons')).style.display='none'; return false;"/>
<box id="preview_box" span="all" class="preview_box">
<box id="preview-box" needed="1" class="content">
<description/>
</box>
<box align="center" id="preview-box-buttons" class="preview-box-buttons">
<button align="center" label="OK" onclick="document.getElementById(form::name('preview_box')).style.display='none'; return false;"/>
</box>
</box>
</row>
</rows>
</grid>
<styles>
.preview-box {
.preview_box {
position: absolute;
top: 0px;
left: 0px;
width: 400px;
height: 360px;
overflow: scroll;
width: 97%;
height: 95%;
overflow: hidden;
background-color: white;
z-index: 999;
display: none;
border: 1px solid black;
margin: 1.5%;
}
.preview-box-buttons {
.preview_box .header {
font-size: 150%;
margin-bottom: 5px;
padding: 5px;
border-bottom: 1px outset;
}
.header .count {
float:right;
}
.preview_box&gt;.content {
overflow: auto;
}
.preview-box-buttons {
position: absolute;
top: 365px;
left: 0px;
width: 400px;
height: 20px;
z-index: 999;
display: none;
bottom: 0px;
width: 100%;
margin-left: 50%;
}
</styles>
</template>

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="importexport.wizard_basic_export_csv.choose_fields" template="" lang="" group="0" version="1.9.001">
<grid>
<columns>
<column/>
</columns>
<rows>
<row>
<description id="msg" span="all"/>
</row>
<row>
<grid overflow="auto" id="fields">
<columns>
<column/>
<column/>
</columns>
<rows>
<row class="th">
<description value="Field"/>
<hbox>
<description value="Export"/>
<buttononly statustext="Check all" label="Check all" id="check_all" needed="1" onclick="jQuery('input:checkbox').attr('checked', !jQuery('input:checkbox').attr('checked')); return false;" options="check"/>
</hbox>
</row>
<row>
<description id="${row}[name]" no_lang="1"/>
<checkbox id="export[${row}]" no_lang="1" options="{$row_cont[field]}"/>
</row>
</rows>
</grid>
</row>
</rows>
</grid>
</template>
</overlay>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="importexport.wizard_basic_export_csv.filter" template="" lang="" group="0" version="1.9.001">
<grid width="100%">
<columns>
<column/>
</columns>
<rows>
<row>
<filter id="set_filter" options="1"/>
</row>
</rows>
</grid>
<styles>select {
width: 200px;
}</styles>
</template>
</overlay>

View File

@ -24,10 +24,10 @@ class infolog_egw_record implements importexport_iface_egw_record
// Used in conversions
static $types = array(
'select' => array('info_type', 'info_status', 'info_priority', 'pl_id'),
'select-cat' => array('info_cat'),
'select-account' => array('info_owner','info_responsible','modifier'),
'select' => array('info_priority', 'info_type', 'info_status','info_pricelist'),
'date-time' => array('info_startdate', 'info_enddate','info_datecompleted', 'info_datemodified','created','last_event','next_event'),
'select-cat' => array('info_cat', 'cat_id'),
'date-time' => array('info_startdate', 'info_enddate','info_datecompleted', 'info_datemodified','info_created'),
'links' => array('info_link_id'),
);

View File

@ -17,6 +17,12 @@
class infolog_export_csv implements importexport_iface_export_plugin {
public function __construct() {
translation::add_app('infolog');
$this->bo = new infolog_bo();
$this->get_selects();
}
/**
* Exports records as defined in $_definition
*
@ -25,23 +31,15 @@ class infolog_export_csv implements importexport_iface_export_plugin {
public function export( $_stream, importexport_definition $_definition) {
$options = $_definition->plugin_options;
translation::add_app('infolog');
$this->bo = new infolog_bo();
$selection = array();
$query = array();
$cf_links = array();
if(!$this->selects)
{
$this->selects['info_type'] = $this->bo->enums['type'];
$this->selects['info_priority'] = $this->bo->enums['priority'];
}
$export_object = new importexport_export_csv($_stream, (array)$options);
$export_object->set_mapping($options['mapping']);
// do we need to query the cf's
foreach($options['mapping'] as $field => $map) {
foreach($options['mapping'] + (array)$_definition->filter as $field => $map) {
if($field[0] == '#') {
$query['custom_fields'][] = $field;
@ -56,9 +54,32 @@ class infolog_export_csv implements importexport_iface_export_plugin {
switch($options['selection'])
{
case 'search':
$query = array_merge($GLOBALS['egw']->session->appsession('session_data','infolog'), $query);
$query = array_merge((array)$GLOBALS['egw']->session->appsession('session_data','infolog'), $query);
// Fall through
case 'filter':
case 'all':
if($options['selection'] == 'filter')
{
$fields = importexport_helper_functions::get_filter_fields($_definition->application, $this);
$query['col_filter'] = $_definition->filter;
// Backend expects a string
if($query['col_filter']['info_responsible'])
{
$query['col_filter']['info_responsible'] = implode(',',$query['col_filter']['info_responsible']);
}
// Handle ranges
foreach($query['col_filter'] as $field => $value)
{
if(!is_array($value) || (!$value['from'] && !$value['to'])) continue;
// Ranges are inclusive, so should be provided that way (from 2 to 10 includes 2 and 10)
if($value['from']) $query['col_filter'][] = "$field >= " . (int)$value['from'];
if($value['to']) $query['col_filter'][] = "$field <= " . (int)$value['to'];
unset($query['col_filter'][$field]);
}
}
$query['num_rows'] = 500;
$query['start'] = 0;
do {
@ -112,7 +133,7 @@ class infolog_export_csv implements importexport_iface_export_plugin {
if(!is_array($selection[$id])) break;
$selection[$id]['pm_id'] = current($links);
$selection[$id]['project'] = egw_link::title('projectmanager', $selection[$id]['pm_id']);
$this->selects['info_pricelist'] = ExecMethod('projectmanager.projectmanager_pricelist_bo.pricelist',$selection[$id]['pm_id']);
$this->selects['pl_id'] = ExecMethod('projectmanager.projectmanager_pricelist_bo.pricelist',$selection[$id]['pm_id']);
}
}
@ -202,6 +223,25 @@ class infolog_export_csv implements importexport_iface_export_plugin {
);
}
protected function get_selects()
{
$this->selects['info_type'] = $this->bo->enums['type'];
$this->selects['info_priority'] = $this->bo->enums['priority'];
$this->selects['pl_id'] = ExecMethod('projectmanager.projectmanager_pricelist_bo.pricelist',false);
$this->selects['info_status'] = $this->bo->get_status();
}
public function get_filter_fields(Array &$filters)
{
foreach($filters as $field_name => &$settings)
{
if($this->selects[$field_name]) $settings['values'] = $this->selects[$field_name];
// Infolog can't handle ranges in custom fields due to the way searching is done.
if(strpos($field_name, '#') === 0 && strpos($settings['type'],'date') === 0) unset($filters[$field_name]);
}
}
/**
* Convert some internal data to something with more meaning
*

View File

@ -18,6 +18,9 @@ class infolog_wizard_export_csv extends importexport_wizard_basic_export_csv
// Field mapping
$bo = new infolog_tracking(new infolog_bo());
$this->export_fields = array('info_id' => 'Infolog ID', 'pm_id' => 'Project ID', 'project' => 'Project Name') + $bo->field2label;
// Add in created date, in the appropriate place
$first = array_splice($this->export_fields, 0, array_search('info_datemodified',array_keys($this->export_fields)));
$this->export_fields = array_merge($first, array('info_created'=>'creation'), $this->export_fields);
// Custom fields
unset($this->export_fields['custom']); // Heading, not a real field

View File

@ -2,7 +2,7 @@
/**
* EGroupware - eTemplates for Application infolog
* http://www.egroupware.org
* generated by soetemplate::dump4setup() 2012-06-19 12:32
* generated by soetemplate::dump4setup() 2012-12-31 11:22
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package infolog
@ -57,7 +57,7 @@ $templ_data[] = array('name' => 'infolog.edit.project','template' => '','lang' =
$templ_data[] = array('name' => 'infolog.export_csv_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:4:{i:0;a:1:{s:1:"B";s:5:"180px";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:3:"msg";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Fieldseperator";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:7:"no_lang";s:1:"1";s:4:"name";s:9:"delimiter";s:4:"size";s:1:"1";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Include header";}s:1:"B";a:2:{s:4:"type";s:11:"select-bool";s:4:"name";s:21:"begin_with_fieldnames";}}}s:4:"rows";i:3;s:4:"cols";i:2;}}','size' => '','style' => '.width180 select { width:150px;}','modified' => '1289231885',);
$templ_data[] = array('name' => 'infolog.export_csv_selectors','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:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:5:"radio";s:5:"label";s:7:"Use all";s:4:"size";s:3:"all";s:4:"name";s:9:"selection";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:5:"radio";s:5:"label";s:18:"Use search results";s:4:"name";s:9:"selection";s:4:"size";s:6:"search";}}}s:4:"rows";i:2;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1289231918',);
$templ_data[] = array('name' => 'infolog.export_csv_selectors','template' => '','lang' => '','group' => '0','version' => '1.9.002','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:5:"radio";s:5:"label";s:7:"Use all";s:4:"size";s:3:"all";s:4:"name";s:9:"selection";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:5:"radio";s:5:"label";s:18:"Use search results";s:4:"name";s:9:"selection";s:4:"size";s:6:"search";}}i:3;a:1:{s:1:"A";a:5:{s:4:"type";s:5:"radio";s:5:"label";s:21:"Use definition filter";s:4:"name";s:9:"selection";s:4:"size";s:6:"filter";s:7:"onclick";s:26:"\\$j(\'div.filters\').show();";}}}s:4:"rows";i:3;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1356978125',);
$templ_data[] = array('name' => 'infolog.importexport_wizard_chooseowner','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:6:{i:0;a:1:{s:2:"h2";s:14:",@no_owner_map";}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"name";s:3:"msg";s:7:"no_lang";s:1:"1";}}i:2;a:1:{s:1:"A";a:3:{s:4:"type";s:8:"checkbox";s:5:"label";s:30:"Use field from CSV if possible";s:4:"name";s:14:"owner_from_csv";}}i:3;a:1:{s:1:"A";a:2:{s:4:"type";s:14:"select-account";s:4:"name";s:12:"record_owner";}}i:4;a:1:{s:1:"A";a:1:{s:4:"type";s:5:"label";}}i:5;a:1:{s:1:"A";a:3:{s:4:"type";s:11:"select-bool";s:5:"label";s:26:"Change owner when updating";s:4:"name";s:12:"change_owner";}}}s:4:"rows";i:5;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1286389863',);

View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="infolog.export_csv_selectors" template="" lang="" group="0" version="1.9.002">
<grid>
<columns>
<column/>
</columns>
<rows>
<row>
<radio label="Use all" id="selection" options="all"/>
</row>
<row>
<radio label="Use search results" id="selection" options="search"/>
</row>
<row>
<radio label="Use definition filter" id="selection" onclick="\$j('div.filters').show();" options="filter"/>
</row>
</rows>
</grid>
</template>
</overlay>