From 10f5a1529874b7d01c1bf93fb22816cd0a8e4d63 Mon Sep 17 00:00:00 2001 From: Ben Klang Date: Wed, 26 May 2010 14:14:33 -0400 Subject: [PATCH] Import Hermes from CVS --- hermes/LICENSE | 24 + hermes/README | 138 ++++ hermes/admin.php | 251 +++++++ hermes/config/.cvsignore | 3 + hermes/config/.htaccess | 1 + hermes/config/conf.xml | 64 ++ hermes/config/prefs.php.dist | 30 + hermes/deliverables.php | 123 ++++ hermes/docs/CHANGES | 91 +++ hermes/docs/CREDITS | 27 + hermes/docs/INSTALL | 243 +++++++ hermes/docs/RELEASE_NOTES | 47 ++ hermes/docs/TODO | 29 + hermes/entry.php | 97 +++ hermes/index.php | 20 + hermes/invoicing.php | 136 ++++ hermes/lib/Admin.php | 201 ++++++ hermes/lib/Block/tree_menu.php | 37 + hermes/lib/Block/tree_stopwatch.php | 54 ++ hermes/lib/Data/hermes_csv.php | 47 ++ hermes/lib/Data/hermes_tsv.php | 47 ++ hermes/lib/Data/hermes_xls.php | 23 + hermes/lib/Data/iif.php | 70 ++ hermes/lib/Data/qbxml.php | 20 + hermes/lib/Driver.php | 225 ++++++ hermes/lib/Driver/sql.php | 748 +++++++++++++++++++ hermes/lib/Forms/Deliverable.php | 64 ++ hermes/lib/Forms/Export.php | 59 ++ hermes/lib/Forms/Search.php | 216 ++++++ hermes/lib/Forms/Time.php | 328 +++++++++ hermes/lib/Hermes.php | 238 ++++++ hermes/lib/Table.php | 244 +++++++ hermes/lib/api.php | 453 ++++++++++++ hermes/lib/base.php | 58 ++ hermes/lib/version.php | 1 + hermes/locale/de_DE/LC_MESSAGES/hermes.mo | Bin 0 -> 168151 bytes hermes/locale/en_US/help.xml | 40 ++ hermes/locale/es_ES/LC_MESSAGES/hermes.mo | Bin 0 -> 160609 bytes hermes/locale/es_ES/help.xml | 47 ++ hermes/locale/fi_FI/LC_MESSAGES/hermes.mo | Bin 0 -> 152171 bytes hermes/locale/zh_TW/LC_MESSAGES/hermes.mo | Bin 0 -> 132806 bytes hermes/po/.cvsignore | 1 + hermes/po/README | 1 + hermes/po/de_DE.po | 760 ++++++++++++++++++++ hermes/po/es_ES.po | 747 +++++++++++++++++++ hermes/po/fi_FI.po | 541 ++++++++++++++ hermes/po/hermes.pot | 740 +++++++++++++++++++ hermes/po/zh_TW.po | 416 +++++++++++ hermes/scripts/.htaccess | 1 + hermes/scripts/Sandals.wdgt/Default.png | Bin 0 -> 843 bytes hermes/scripts/Sandals.wdgt/Icon.png | Bin 0 -> 4797 bytes hermes/scripts/Sandals.wdgt/Info.plist | 31 + .../Contents/Info.plist | 23 + .../Contents/MacOS/KeychainPlugIn | Bin 0 -> 46724 bytes .../Resources/English.lproj/InfoPlist.strings | Bin 0 -> 276 bytes hermes/scripts/Sandals.wdgt/Sandals.html | 437 +++++++++++ hermes/scripts/Sandals.wdgt/lib/Sandals.js | 794 ++++++++++++++++++++ hermes/scripts/Sandals.wdgt/lib/horde.js | 267 +++++++ hermes/scripts/Sandals.wdgt/lib/open_calendar.js | 481 +++++++++++++ hermes/scripts/Sandals.wdgt/lib/stripe.js | 97 +++ hermes/scripts/Sandals.wdgt/lib/vcXMLRPC.js | 640 +++++++++++++++++ .../Sandals.wdgt/themes/bluewhite-screen.css | 162 +++++ .../Sandals.wdgt/themes/graphics/alerts/alarm.png | Bin 0 -> 422 bytes .../Sandals.wdgt/themes/graphics/alerts/error.png | Bin 0 -> 298 bytes .../themes/graphics/alerts/message.png | Bin 0 -> 477 bytes .../themes/graphics/alerts/success.png | Bin 0 -> 360 bytes .../themes/graphics/alerts/warning.png | Bin 0 -> 227 bytes .../Sandals.wdgt/themes/graphics/calendar.png | Bin 0 -> 368 bytes .../Sandals.wdgt/themes/graphics/hermes.png | Bin 0 -> 547 bytes .../Sandals.wdgt/themes/graphics/required.png | Bin 0 -> 118 bytes .../themes/graphics/spinner-transparent.gif | Bin 0 -> 1849 bytes .../scripts/Sandals.wdgt/themes/hermes-screen.css | 40 ++ .../scripts/Sandals.wdgt/themes/sandals-screen.css | 6 + hermes/scripts/Sandals.wdgt/themes/screen.css | 795 +++++++++++++++++++++ hermes/scripts/purge.php | 27 + hermes/scripts/sql/hermes.mssql.sql | 51 ++ hermes/scripts/sql/hermes.oci8.sql | 51 ++ hermes/scripts/sql/hermes.sql | 52 ++ hermes/scripts/sql/hermes.xml | 315 ++++++++ .../scripts/upgrades/2007-04-20_drop_invoicing.sql | 5 + .../upgrades/2007-04-25_add_jobtype_rate.sql | 1 + .../upgrades/2007-10-17_add_jobtype_billable.sql | 1 + .../upgrades/2008-07-01_deliverables_index.sql | 3 + hermes/search.php | 141 ++++ hermes/start.php | 49 ++ hermes/templates/common-header.inc | 29 + hermes/templates/deliverables/list.inc | 13 + hermes/templates/menu.inc | 4 + hermes/templates/time/form.html | 6 + hermes/themes/graphics/clockout.png | Bin 0 -> 560 bytes hermes/themes/graphics/deliverable.png | Bin 0 -> 625 bytes hermes/themes/graphics/favicon.ico | Bin 0 -> 1406 bytes hermes/themes/graphics/hermes.png | Bin 0 -> 547 bytes hermes/themes/graphics/invoices.png | Bin 0 -> 533 bytes hermes/themes/graphics/newdeliverable.png | Bin 0 -> 503 bytes hermes/themes/graphics/timer-start.png | Bin 0 -> 474 bytes hermes/themes/graphics/timer-stop.png | Bin 0 -> 529 bytes hermes/themes/print/screen.css | 8 + hermes/themes/screen.css | 40 ++ hermes/time.php | 87 +++ 100 files changed, 12407 insertions(+) create mode 100644 hermes/LICENSE create mode 100644 hermes/README create mode 100644 hermes/admin.php create mode 100644 hermes/config/.cvsignore create mode 100644 hermes/config/.htaccess create mode 100644 hermes/config/conf.xml create mode 100644 hermes/config/prefs.php.dist create mode 100644 hermes/deliverables.php create mode 100644 hermes/docs/CHANGES create mode 100644 hermes/docs/CREDITS create mode 100644 hermes/docs/INSTALL create mode 100644 hermes/docs/RELEASE_NOTES create mode 100644 hermes/docs/TODO create mode 100644 hermes/entry.php create mode 100644 hermes/index.php create mode 100644 hermes/invoicing.php create mode 100644 hermes/lib/Admin.php create mode 100644 hermes/lib/Block/tree_menu.php create mode 100644 hermes/lib/Block/tree_stopwatch.php create mode 100644 hermes/lib/Data/hermes_csv.php create mode 100644 hermes/lib/Data/hermes_tsv.php create mode 100644 hermes/lib/Data/hermes_xls.php create mode 100644 hermes/lib/Data/iif.php create mode 100644 hermes/lib/Data/qbxml.php create mode 100644 hermes/lib/Driver.php create mode 100644 hermes/lib/Driver/sql.php create mode 100644 hermes/lib/Forms/Deliverable.php create mode 100644 hermes/lib/Forms/Export.php create mode 100644 hermes/lib/Forms/Search.php create mode 100644 hermes/lib/Forms/Time.php create mode 100644 hermes/lib/Hermes.php create mode 100644 hermes/lib/Table.php create mode 100644 hermes/lib/api.php create mode 100644 hermes/lib/base.php create mode 100644 hermes/lib/version.php create mode 100644 hermes/locale/de_DE/LC_MESSAGES/hermes.mo create mode 100644 hermes/locale/en_US/help.xml create mode 100644 hermes/locale/es_ES/LC_MESSAGES/hermes.mo create mode 100644 hermes/locale/es_ES/help.xml create mode 100644 hermes/locale/fi_FI/LC_MESSAGES/hermes.mo create mode 100644 hermes/locale/zh_TW/LC_MESSAGES/hermes.mo create mode 100644 hermes/po/.cvsignore create mode 100644 hermes/po/README create mode 100644 hermes/po/de_DE.po create mode 100644 hermes/po/es_ES.po create mode 100644 hermes/po/fi_FI.po create mode 100644 hermes/po/hermes.pot create mode 100644 hermes/po/zh_TW.po create mode 100644 hermes/scripts/.htaccess create mode 100644 hermes/scripts/Sandals.wdgt/Default.png create mode 100644 hermes/scripts/Sandals.wdgt/Icon.png create mode 100644 hermes/scripts/Sandals.wdgt/Info.plist create mode 100644 hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Info.plist create mode 100755 hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/MacOS/KeychainPlugIn create mode 100644 hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Resources/English.lproj/InfoPlist.strings create mode 100644 hermes/scripts/Sandals.wdgt/Sandals.html create mode 100644 hermes/scripts/Sandals.wdgt/lib/Sandals.js create mode 100644 hermes/scripts/Sandals.wdgt/lib/horde.js create mode 100644 hermes/scripts/Sandals.wdgt/lib/open_calendar.js create mode 100644 hermes/scripts/Sandals.wdgt/lib/stripe.js create mode 100644 hermes/scripts/Sandals.wdgt/lib/vcXMLRPC.js create mode 100644 hermes/scripts/Sandals.wdgt/themes/bluewhite-screen.css create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/alerts/alarm.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/alerts/error.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/alerts/message.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/alerts/success.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/alerts/warning.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/calendar.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/hermes.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/required.png create mode 100644 hermes/scripts/Sandals.wdgt/themes/graphics/spinner-transparent.gif create mode 100644 hermes/scripts/Sandals.wdgt/themes/hermes-screen.css create mode 100644 hermes/scripts/Sandals.wdgt/themes/sandals-screen.css create mode 100644 hermes/scripts/Sandals.wdgt/themes/screen.css create mode 100755 hermes/scripts/purge.php create mode 100644 hermes/scripts/sql/hermes.mssql.sql create mode 100644 hermes/scripts/sql/hermes.oci8.sql create mode 100644 hermes/scripts/sql/hermes.sql create mode 100644 hermes/scripts/sql/hermes.xml create mode 100644 hermes/scripts/upgrades/2007-04-20_drop_invoicing.sql create mode 100644 hermes/scripts/upgrades/2007-04-25_add_jobtype_rate.sql create mode 100644 hermes/scripts/upgrades/2007-10-17_add_jobtype_billable.sql create mode 100644 hermes/scripts/upgrades/2008-07-01_deliverables_index.sql create mode 100644 hermes/search.php create mode 100644 hermes/start.php create mode 100644 hermes/templates/common-header.inc create mode 100644 hermes/templates/deliverables/list.inc create mode 100644 hermes/templates/menu.inc create mode 100644 hermes/templates/time/form.html create mode 100644 hermes/themes/graphics/clockout.png create mode 100644 hermes/themes/graphics/deliverable.png create mode 100644 hermes/themes/graphics/favicon.ico create mode 100644 hermes/themes/graphics/hermes.png create mode 100644 hermes/themes/graphics/invoices.png create mode 100644 hermes/themes/graphics/newdeliverable.png create mode 100644 hermes/themes/graphics/timer-start.png create mode 100644 hermes/themes/graphics/timer-stop.png create mode 100644 hermes/themes/print/screen.css create mode 100644 hermes/themes/screen.css create mode 100644 hermes/time.php diff --git a/hermes/LICENSE b/hermes/LICENSE new file mode 100644 index 000000000..07b15e95c --- /dev/null +++ b/hermes/LICENSE @@ -0,0 +1,24 @@ +Copyright 2002-2009 The Horde Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HORDE PROJECT +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/hermes/README b/hermes/README new file mode 100644 index 000000000..5656935b7 --- /dev/null +++ b/hermes/README @@ -0,0 +1,138 @@ +What is Hermes? +=============== + +:Last update: $Date: 2008/06/30 08:26:20 $ +:Revision: $Revision: 1.10 $ + +.. contents:: Contents +.. section-numbering:: + +Hermes is a Horde time-tracking application. It ties into address books (to +retrieve clients) and task lists, bug trackers etc. (to retrieve cost +objects). It comes with a stop watch, search and reporting capabilities, a +MacOSX Dashboard widget and an invoice interface. + +This software is OSI Certified Open Source Software. OSI Certified is a +certification mark of the `Open Source Initiative`_. + +.. _`Open Source Initiative`: http://www.opensource.org/ + + +Obtaining Hermes +---------------- + +Further information on Hermes and the latest version can be obtained at + + http://www.horde.org/hermes/ + + +Documentation +------------- + +The following documentation is available in the Hermes distribution: + +:README_: This file +:LICENSE_: Copyright and license information +:`docs/CHANGES`_: Changes by release +:`docs/CREDITS`_: Project developers +:`docs/INSTALL`_: Installation instructions and notes +:`docs/TODO`_: Development TODO list + + +Installation +------------ + +Instructions for installing Hermes can be found in the file INSTALL_ in the +``docs/`` directory of the Hermes distribution. + + +Configuration +------------- + +Editing Submitted Time +~~~~~~~~~~~~~~~~~~~~~~ + +By default, users cannot edit submitted time. Specific users or groups can be +granted the ability to edit submitted (but not exported) time by granting the +"EDIT" permission for "Hermes -> Time Review Screen" (see "Permissions" from +the Administration menu for more info). This will enable them to edit +submitted time from anywhere they can see it, which right means from the +Search screen. + +This permission also gives the user the ability to mark time as exported when +downloading it. + +Cost Objects +~~~~~~~~~~~~ + +Other applications can supply cost objects to track time against. + +Currently, Whups_ (the ticket-tracking system) will export its tickets as +possible cost object. If you configure an additional attribute for your ticket +types and make its name "Estimated Time", Whups will also be able to export +estimates on the tickets, allowing Hermes to indicate the ticket's percentage +complete. The same happens automatically with tasks exported from Nag_ as cost +objects. + +.. _Whups: http://www.horde.org/whups/ +.. _Nag: http://www.horde.org/nag/ + + +Using the OS X Widget +--------------------- + +If you are running Apple's OS X version 10.4 (Tiger) or later you can use the +included widget, Sandals, to enter time directly from the Dashboard. Sandals +can be found in the scripts/ directory. The easiest way to install it is to +create a .zip of the directory and copy that to the OS X computer. After +decompressing the .zip on the Mac, double-click the widget icon and it will be +installed into your Dashboard. + +To use Sandals you must configure the Horde URL to rpc.php along with your +username and password. Horde's rpc.php can be found in the base directory of +your Horde install. Example: http://www.example.com/horde/rpc.php + +A note about security: If you are using OS X 10.5 (Leopard) your username and +password will be securely stored in your Keychain. For 10.4 the credentials +are stored in the normal Dashboard preferences unencrypted. If this is an +issue for you, you should not use Sandals on OS X 10.4. + + +Assistance +---------- + +If you encounter problems with Hermes, help is available! + +The Horde Frequently Asked Questions List (FAQ), available on the Web at + + http://www.horde.org/faq/ + +The Horde Project runs a number of mailing lists, for individual applications +and for issues relating to the project as a whole. Information, archives, and +subscription information can be found at + + http://www.horde.org/mail/ + +Lastly, Horde developers, contributors and users also make occasional +appearances on IRC, on the channel #horde on the freenode Network +(irc.freenode.net). + + +Licensing +--------- + +For licensing and copyright information, please see the file LICENSE_ in the +Hermes distribution. + +Thanks, + +The Hermes team + + +.. _README: ?f=README.html +.. _LICENSE: http://www.horde.org/licenses/asl.php +.. _docs/CHANGES: ?f=CHANGES.html +.. _docs/CREDITS: ?f=CREDITS.html +.. _INSTALL: +.. _docs/INSTALL: ?f=INSTALL.html +.. _docs/TODO: ?f=TODO.html diff --git a/hermes/admin.php b/hermes/admin.php new file mode 100644 index 000000000..840f93b9a --- /dev/null +++ b/hermes/admin.php @@ -0,0 +1,251 @@ + + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; +require_once HERMES_BASE . '/lib/Admin.php'; + +if (!Horde_Auth::isAdmin()) { + exit('forbidden.'); +} + +$r = new Horde_Form_Renderer(); +$vars = Horde_Variables::getDefaultVariables(); +$beendone = false; + +function _open() +{ + static $opened; + + if (is_null($opened)) { + global $registry, $prefs, $browser, $conf, $notification, $beendone, $title; + + $opened = true; + $beendone = true; + $title = _("Administration"); + require HERMES_TEMPLATES . '/common-header.inc'; + require HERMES_TEMPLATES . '/menu.inc'; + } +} + +if ($vars->exists('formname')) { + switch ($vars->get('formname')) { + case 'addjobtypeform': + $form = new AddJobTypeForm($vars); + $form->validate($vars); + + if ($form->isValid()) { + $form->getInfo($vars, $info); + $result = $hermes->updateJobType($info); + if (!is_a($result, 'PEAR_Error')) { + $notification->push(sprintf(_("The job type \"%s\" has been added."), $vars->get('name')), 'horde.success'); + } else { + $notification->push(sprintf(_("There was an error adding the job type: %s."), $result->getMessage()), 'horde.error'); + } + } else { + _open(); + + $form->open($r, $vars, 'admin.php', 'post'); + $r->beginActive(_("Add Job Type")); + $r->renderFormActive($form, $vars); + $r->submit(); + $r->end(); + $form->close($r); + } + break; + + case 'editjobtypestep1form': + $form1 = new EditJobTypeStep1Form($vars); + $form1->validate($vars); + + _open(); + + if ($form1->isValid()) { + switch ($vars->get('submitbutton')) { + case _("Edit Job Type"): + $form2 = new EditJobTypeStep2Form($vars); + $form2->open($r, $vars, 'admin.php', 'post'); + + // render the second stage form + $r->beginActive(_("Edit Job Type, Step 2")); + $r->renderFormActive($form2, $vars); + $r->submit(); + $r->end(); + + $form2->close($r); + break; + + case _("Delete Job Type"): + $form2 = new DeleteJobTypeForm($vars); + $form2->open($r, $vars, 'admin.php', 'post'); + + // render the deletion form + $r->beginActive(_("Delete Job Type: Confirmation")); + $r->renderFormActive($form2, $vars); + $r->submit(); + $r->end(); + + $form2->close($r); + break; + } + } else { + $form1->open($r, $vars, 'admin.php', 'post'); + $r->beginActive(_("Edit job type")); + $r->renderFormActive($form1, $vars); + $r->submit(); + $r->end(); + $form1->close($r); + } + break; + + case 'editclientstep1form': + $form1 = new EditClientStep1Form($vars); + $form1->validate($vars); + + _open(); + + if ($form1->isValid()) { + $form2 = new EditClientStep2Form($vars); + $form2->open($r, $vars, 'admin.php', 'post'); + + // render the second stage form + $r->beginActive(_("Edit Client Settings, Step 2")); + $r->renderFormActive($form2, $vars); + $r->submit(); + $r->end(); + + $form2->close($r); + } else { + $form1->open($r, $vars, 'admin.php', 'post'); + $r->beginActive(_("Edit Client Settings")); + $r->renderFormActive($form1, $vars); + $r->submit(); + $r->end(); + $form1->close($r); + } + break; + + case 'editjobtypestep2form': + $form1 = new EditJobTypeStep2Form($vars); + $form1->validate($vars); + + if ($form1->isValid()) { + // update everything. + $form1->getInfo($vars, $info); + $info['id'] = $info['jobtype']; + $result = $hermes->updateJobType($info); + if (!PEAR::isError($result)) { + $notification->push(_("The job type has been modified."), 'horde.success'); + } else { + $notification->push(sprintf(_("There was an error editing the job type: %s."), $result->getMessage()), 'horde.error'); + } + } else { + _open(); + + $form1->open($r, $vars, 'admin.php', 'post'); + $r->beginActive(_("Edit job type, Step 2")); + $r->renderFormActive($form1, $vars); + $r->submit(); + $r->end(); + $form1->close($r); + } + break; + + case 'editclientstep2form': + $form = new EditClientStep2Form($vars); + $form->validate($vars); + + if ($form->isValid()) { + $result = $hermes->updateClientSettings($vars->get('client'), + $vars->get('enterdescription') ? 1 : 0, + $vars->get('exportid')); + if (PEAR::isError($result)) { + $notification->push(sprintf(_("There was an error editing the client settings: %s."), $result->getMessage()), 'horde.error'); + } else { + $notification->push(_("The client settings have been modified."), 'horde.success'); + } + } else { + _open(); + + $form->open($r, $vars, 'admin.php', 'post'); + $r->beginActive(_("Edit Client Settings, Step 2")); + $r->renderFormActive($form, $vars); + $r->submit(); + $r->end(); + $form->close($r); + } + break; + + case 'deletejobtypeform': + $form = new DeleteJobTypeForm($vars); + $form->validate($vars); + + if ($form->isValid()) { + if ($vars->get('yesno') == 1) { + $result = $hermes->deleteJobType($vars->get('jobtype')); + if (!PEAR::isError($result)) { + $notification->push(_("The job type has been deleted."), 'horde.success'); + } else { + $notification->push(sprintf(_("There was an error deleting the job type: %s."), $result->getMessage()), 'horde.error'); + } + } else { + $notification->push(_("The job type was not deleted."), 'horde.message'); + } + } else { + _open(); + + $form->open($r, $vars, 'admin.php', 'post'); + $r->beginActive(_("Delete Job Type: Confirmation")); + $r->renderFormActive($form, $vars); + $r->submit(); + $r->end(); + $form->close($r); + } + break; + } +} + +if (!$beendone) { + $vars = new Horde_Variables(); + $form1 = new EditJobTypeStep1Form($vars); $edit1 = _("Edit Job Type"); $edit2 = _("Delete Job Type"); + $form2 = new AddJobTypeForm($vars); $add = _("Add Job Type"); + $form3 = new EditClientStep1Form($vars); $edit3 = _("Edit Client Settings"); + + _open(); + + $form1->open($r, $vars, 'admin.php', 'post'); + $r->beginActive($edit1); + $r->renderFormActive($form1, $vars); + $r->submit(array($edit1, $edit2)); + $r->end(); + $form1->close($r); + + echo '
'; + + $form2->open($r, $vars, 'admin.php', 'post'); + $r->beginActive($add); + $r->renderFormActive($form2, $vars); + $r->submit($add); + $r->end(); + $form2->close($r); + + echo '
'; + + $form3->open($r, $vars, 'admin.php', 'post'); + $r->beginActive($edit3); + $r->renderFormActive($form3, $vars); + $r->submit($edit3); + $r->end(); + $form3->close($r); +} + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/hermes/config/.cvsignore b/hermes/config/.cvsignore new file mode 100644 index 000000000..51adefac7 --- /dev/null +++ b/hermes/config/.cvsignore @@ -0,0 +1,3 @@ +conf.php +conf.bak.php +prefs.php diff --git a/hermes/config/.htaccess b/hermes/config/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/hermes/config/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/hermes/config/conf.xml b/hermes/config/conf.xml new file mode 100644 index 000000000..2e527fcde --- /dev/null +++ b/hermes/config/conf.xml @@ -0,0 +1,64 @@ + + + + + Time Tracking Settings + true + 60 + false + false + + + + Storage System Settings + sql + + sql + + + + + + + + + Clients + name + + + + Invoices + false + + + + proforma + pending + 8 + City of + Internet + + + + + + + Menu Settings + true + + + + + + + diff --git a/hermes/config/prefs.php.dist b/hermes/config/prefs.php.dist new file mode 100644 index 000000000..e27d551df --- /dev/null +++ b/hermes/config/prefs.php.dist @@ -0,0 +1,30 @@ + _("General Options"), + 'label' => _("Timer Options"), + 'desc' => _("Set preferences on the stop watch timer."), + 'members' => array('add_description') +); + +// should we add the stop watch name to the description? +$_prefs['add_description'] = array( + 'value' => true, + 'locked' => false, + 'shared' => false, + 'type' => 'checkbox', + 'desc' => _("Add stop watch name and start and end time to the description of the time entry?") +); + +// preference for holding any running timers. +$_prefs['running_timers'] = array( + 'value' => '', + 'locked' => false, + 'shared' => false, + 'type' => 'implicit' +); diff --git a/hermes/deliverables.php b/hermes/deliverables.php new file mode 100644 index 000000000..11cd6f064 --- /dev/null +++ b/hermes/deliverables.php @@ -0,0 +1,123 @@ + + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; +require_once HERMES_BASE . '/lib/Forms/Deliverable.php'; + +$vars = Horde_Variables::getDefaultVariables(); + +switch ($vars->get('formname')) { +case 'deliverableform': + $form = new DeliverableForm($vars); + $form->validate($vars); + if ($form->isValid()) { + $form->getInfo($vars, $info); + if (!empty($info['deliverable_id'])) { + $info['id'] = $info['deliverable_id']; + if (empty($info['parent'])) { + $origdeliv = $hermes->getDeliverableByID($info['id']); + if (!is_a($origdeliv, 'PEAR_Error')) { + $info['parent'] = $origdeliv['parent']; + } + } + } + $res = $hermes->updateDeliverable($info); + if (is_a($res, 'PEAR_Error')) { + $notification->push(sprintf(_("Error saving deliverable: %s"), + $res->getMessage()), + 'horde.error'); + } else { + $notification->push(_("Deliverable saved successfully."), + 'horde.success'); + $vars = new Horde_Variables(array('client_id' => $vars->get('client_id'))); + } + } + break; + +case 'deletedeliverable': + $res = $hermes->deleteDeliverable($vars->get('delete')); + if (is_a($res, 'PEAR_Error')) { + $notification->push(sprintf(_("Error deleting deliverable: %s"), + $res->getMessage()), 'horde.error'); + } else { + $notification->push(_("Deliverable successfully deleted."), + 'horde.success'); + } + break; +} + +$title = _("Deliverables"); +require HERMES_TEMPLATES . '/common-header.inc'; +require HERMES_TEMPLATES . '/menu.inc'; + +$renderer = new Horde_Form_Renderer(); + +if (!$vars->exists('deliverable_id') && !$vars->exists('new')) { + $clientSelector = new DeliverableClientSelector($vars); + $clientSelector->renderActive($renderer, $vars, 'deliverables.php', 'post'); +} + +if ($vars->exists('deliverable_id') || $vars->exists('new')) { + if ($vars->exists('deliverable_id')) { + $deliverable = $hermes->getDeliverableByID($vars->get('deliverable_id')); + if (is_a($deliverable, 'PEAR_Error')) { + Horde::fatal($deliverable, __FILE__, __LINE__); + } + + foreach ($deliverable as $name => $value) { + $vars->set($name, $value); + } + } + + $form = new DeliverableForm($vars); + $form->renderActive($renderer, $vars, 'deliverables.php', 'post'); +} elseif ($vars->exists('client_id')) { + $clients = Hermes::listClients(); + $clientname = $clients[$vars->get('client_id')]; + + $deliverables = $hermes->listDeliverables(array('client_id' => $vars->get('client_id'))); + if (is_a($deliverables, 'PEAR_Error')) { + Horde::fatal($deliverables, __FILE__, __LINE__); + } + + $tree = Horde_Tree::factory('deliverables', 'javascript'); + $tree->setOption(array('class' => 'item', + 'alternate' => true)); + + foreach ($deliverables as $deliverable) { + $params = array(); + $params['url'] = Horde::applicationUrl('deliverables.php'); + $params['url'] = Horde_Util::addParameter($params['url'], array('deliverable_id' => $deliverable['id'], 'client_id' => $vars->get('client_id'))); + $params['title'] = sprintf(_("Edit %s"), $deliverable['name']); + + $newdeliv = ' ' . Horde::link(Horde_Util::addParameter(Horde::applicationUrl('deliverables.php'), array('new' => 1, 'parent' => $deliverable['id'], 'client_id' => $vars->get('client_id'))), _("New Sub-deliverable")) . Horde::img('newdeliverable.png', _("New Sub-deliverable")) . ''; + + $deldeliv = ' ' . Horde::link(Horde_Util::addParameter(Horde::applicationUrl('deliverables.php'), array('formname' => 'deletedeliverable', 'delete' => $deliverable['id'], 'client_id' => $vars->get('client_id'))), _("Delete This Deliverable")) . Horde::img('delete.png', _("Delete This Deliverable"), '', $registry->getImageDir('horde')) . ''; + + /* Calculate the node's depth. */ + $depth = 0; + $iterator = $deliverable; + while (!empty($iterator['parent'])) { + $depth++; + $iterator = $deliverables[$iterator['parent']]; + } + + $tree->addNode($deliverable['id'], $deliverable['parent'], + $deliverable['name'], $depth, true, $params, + array($newdeliv, $deldeliv), array()); + } + + require HERMES_TEMPLATES . '/deliverables/list.inc'; +} + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/hermes/docs/CHANGES b/hermes/docs/CHANGES new file mode 100644 index 000000000..3417ffc28 --- /dev/null +++ b/hermes/docs/CHANGES @@ -0,0 +1,91 @@ +-------- +v2.0-cvs +-------- + + + + +---------- +v1.0.2-cvs +---------- + + + + +------ +v1.0.1 +------ + +[jan] Fix client list in search form if client source has numeric IDs + (manilal@ejyothi.com, Bug #7966). + + +---- +v1.0 +---- + +[jan] Go back to search results after editing time slices from there + (mail@dunix-data.de, Request #7012). +[jan] Check permissions when displaying time slice forms (mail@dunix-data.de, + Bug #7027). +[jan] Fix index for table hermes_deliverables (Bug #7001). + + +-------- +v1.0-RC1 +-------- + +[jan] Add start and end time of stop watch to entry description (Request #5585). +[jan] Update time budget of cost objects after saving an entry. +[bak] Add OS X widget for entering time +[jan] Allow to mark job types billable (Vinay Kumar , + Request #5207). +[jan] Add configuration to only include billable time when summing up for + deliverables. +[cjh] Add an initial interface for sending invoice data to Minerva + (Duck ). +[jan] Drop incomplete invoicing support. +[jan] Add configuration for address book field used for the client listings. + (Request #3816). +[jan] Add "Enter Time" item to sidebar menu. +[ben] Better support for MS-SQL. +[jan] Add subtotal tabs to the overview page. +[jan] Save used stop watch name in "Notes" field (tevans@tachometry.com, + Request #2667). +[cjh] Add subtotal tabs to the time search form + (tevans@tachometry.com, Bug #2632). +[cjh] Add cost object filtering to the time search page + (tevans@tachometry.com, Bug #2631). +[cjh] Print button for timesheets, and support for only showing some timesheet + elements when printing (Bug #2375). +[jmf] Replace support tracking time to deliverables with support for tracking + time to more general cost objects which can be provided by other + applications. Deliverables are now a type of cost object. +[jan] Add stop watch to sidebar. +[cjh] Use bind variables in SQL driver (selsky@columbia.edu, #1745). +[cjh] Use client name instead of id in exports, and allow searching on + whether or not time is billable (Tom Evans ). +[jmf] Add ability to track time to deliverables, maintain deliverables. +[jmf] Add ability to disable job types so they still exist but can no longer + be used for time entry (but can be used for searching and display). +[jan] Add Spanish translation (Manuel Perez Ayala ). +[jmf] Merge submit screen into time entry screen. +[jmf] Make time entry form "float". +[jmf] Remove concept of "current" week. +[jan] Add Finnish translation (Petteri Karttunen ). +[jan] Add Traditional Chinese translation (David Chang ). +[cjh] Add a print menu item. +[cjh] Add a script to purge old data. +[cjh] Fix adding of bogus data because of other form variables. +[jan] Add German translation. +[cjh] Add browsing to arbitrary weeks. +[cjh] Only submitted time gets exported now. +[cjh] Add submitting of time. +[cjh] Add editing of time. +[cjh] Exporting hours by date range works now. +[cjh] Initial support for exporting hours to QuickBooks. +[cjh] There is now an Options page. +[cjh] Users can now edit time that hasn't yet been sucked into a timesheet. +[cjh] Add an admin interface for Job Types. +[cjh] Initial Hermes framework. diff --git a/hermes/docs/CREDITS b/hermes/docs/CREDITS new file mode 100644 index 000000000..10d4a6ee7 --- /dev/null +++ b/hermes/docs/CREDITS @@ -0,0 +1,27 @@ +========================= + Hermes Development Team +========================= + + +Core Developers +=============== + +Chuck Hagenbuch + - Initial code, sponsored by Hawk Technologies (http://www.hawk.com/). + +Jan Schneider + - Maintenance, stuff. + +Ben Klang + - Hermes API and Dashboard Widget. + + +Localization +============ + +===================== ====================================================== +Chinese (Traditional) David Chang +Finnish Petteri Karttunen +German Jan Schneider +Spanish Manuel Perez Ayala +===================== ====================================================== diff --git a/hermes/docs/INSTALL b/hermes/docs/INSTALL new file mode 100644 index 000000000..f0fb6d40f --- /dev/null +++ b/hermes/docs/INSTALL @@ -0,0 +1,243 @@ +======================= + Installing Hermes 1.0 +======================= + +:Last update: $Date: 2008/06/29 22:03:03 $ +:Revision: $Revision: 1.13 $ + +.. contents:: Contents +.. section-numbering:: + +This document contains instructions for installing the Hermes time-tracking +application. + +For information on the capabilities and features of Hermes, see the file +README_ in the top-level directory of the Hermes distribution. + + +Obtaining Hermes +================ + +Hermes can be obtained from the Horde website and FTP server, at + + http://www.horde.org/hermes/ + + ftp://ftp.horde.org/pub/hermes/ + +Or use the mirror closest to you: + + http://www.horde.org/mirrors.php + +Bleeding-edge development versions of Hermes are available via CVS; see the +file `horde/docs/HACKING`_ in the Horde distribution, or the website +http://www.horde.org/source/, for information on accessing the Horde CVS +repository. + + +Prerequisites +============= + +To function properly, Hermes **requires** the following: + +1. A working Horde installation. + + Hermes runs within the `Horde Application Framework`_, a set of common + tools for Web applications written in PHP. You must install Horde before + installing Hermes. + + .. Important:: Hermes 1.0 requires version 3.2+ of the Horde Framework - + earlier versions of Horde will **not** work. + + .. _`Horde Application Framework`: http://www.horde.org/horde/ + + The Horde Framework can be obtained from the Horde website and FTP server, + at + + http://www.horde.org/horde/ + + ftp://ftp.horde.org/pub/horde/ + + Many of Hermes's prerequisites are also Horde prerequisites. + + .. Important:: Be sure to have completed all of the steps in the + `horde/docs/INSTALL`_ file for the Horde Framework before + installing Hermes. + +2. The following PHP capabilities: + + a. SQL support + + Hermes stores its data in an SQL database. Build PHP with whichever SQL + driver you require; see the `horde/docs/INSTALL`_ file for details. + +3. A working Turba installation. + + Hermes queries the clients API for client listings. This API is usually + provided by Turba_. It doesn't matter what type of address book is + configured for clients, but it is a good practice to create one which is + separate from the rest of your contacts, see + http://wiki.horde.org/HermesAddressBook. + + Which addressbook Hermes uses for clients is configured in Turba's setup. + + You can replace Turba with any application providing the + clients/listClients API method. Check the `Horde Wiki`_ or ask on the + `mailing list`_ for details. + +.. _Turba: http://www.horde.org/turba/ +.. _`Horde Wiki`: http://wiki.horde.org/ +.. _`mailing list`: `Obtaining Support`_ + +The following items are not required, but are recommended: + +1. Applications providing cost objects. + + Other applications can supply cost objects to track time against. + + Currently, Whups_ (the ticket-tracking system) and Nag_ (the tasklist + manager) will export their tickets as possible cost objects. If you + configure an additional attribute for your ticket types in Whups and make + its name "Estimated Time", Whups will also be able to export estimates on + the tickets, allowing Hermes to indicate the ticket's percentage + complete. Estimation times from Nag will be exported automatically too. + +.. _Whups: http://www.horde.org/whups/ +.. _Nag: http://www.horde.org/nag/ + + +Installing Hermes +=================== + +Hermes is written in PHP, and must be installed in a web-accessible +directory. The precise location of this directory will differ from system to +system. Conventionally, Hermes is installed directly underneath Horde in the +web server's document tree. + +Since Hermes is written in PHP, there is no compilation necessary; simply +expand the distribution where you want it to reside and rename the root +directory of the distribution to whatever you wish to appear in the URL. For +example, with the Apache web server's default document root of +``/usr/local/apache/htdocs``, you would type:: + + cd /usr/local/apache/htdocs/horde + tar zxvf /path/to/hermes-h3-x.y.z.tar.gz + mv hermes-h3-x.y.z hermes + +and would then find Hermes at the URL:: + + http://your-server/horde/hermes/ + + +Configuring Hermes +================== + +1. Configuring Horde for Hermes + + a. Register the application + + In ``horde/config/registry.php``, find the ``applications['hermes']`` + stanza. The default settings here should be okay, but you can change + them if desired. If you have changed the location of Hermes relative to + Horde, either in the URL, in the filesystem or both, you must update the + ``fileroot`` and ``webroot`` settings to their correct values. + +2. Creating the database tables + + The specific steps to create Hermes's database tables depend on which + database you've chosen to use. + + First, look in ``scripts/sql/`` to see if a script already exists for your + database type. If so, you should be able to simply execute that script as + superuser in your database. (Note that executing the script as the "horde" + user will probably fail when granting privileges.) + + If such a script does not exist, you'll need to build your own, using the + file ``hermes.sql`` as a starting point. If you need assistance in + creating database tables, you may wish to let us know on the Hermes mailing + list. + + You will also need to make sure that the "horde" user in your database has + table-creation privileges, so that the tables that `PEAR DB`_ uses to + provide portable sequences can be created. + + .. _`PEAR DB`: http://pear.php.net/DB + +3. Configuring Hermes + + To configure Hermes, change to the ``config/`` directory of the installed + distribution, and make copies of all of the configuration ``dist`` files + without the ``dist`` suffix:: + + cd config/ + for foo in *.dist; do cp $foo `basename $foo .dist`; done + + Or on Windows:: + + copy *.dist *. + + Documentation on the format and purpose of those files can be found in each + file. You may edit these files if you wish to customize Hermes's appearance + and behavior. + + You must login to Horde as a Horde Administrator to finish the + configuration of Hermes. Use the Horde ``Administration`` menu item to get + to the administration page, and then click on the ``Configuration`` icon to + get the configuration page. Select ``Time Tracking`` from the selection + list of applications. Fill in or change any configuration values as + needed. When done click on ``Generate Time Tracking Configuration`` to + generate the ``conf.php`` file. If your web server doesn't have write + permissions to the Hermes configuration directory or file, it will not be + able to write the file. In this case, go back to ``Configuration`` and + choose one of the other methods to create the configuration file + ``hermes/config/conf.php``. + + Note for international users: Hermes uses GNU gettext to provide local + translations of text displayed by applications; the translations are found + in the ``po/`` directory. If a translation is not yet available for your + locale (and you wish to create one), see the ``horde/po/README`` file, or + if you're having trouble using a provided translation, please see the + `horde/docs/TRANSLATIONS`_ file for instructions. + +4. Testing Hermes + + Use Hermes to enter time-tracking data. Test at least the following: + + - Adding job types as an administrator. + - Adding deliverables as an administrator. + - Creating time entries for a client, job type, and deliverable. + - Search for time entries. + - Submit time entries. + + +Obtaining Support +================= + +If you encounter problems with Hermes, help is available! + +The Horde Frequently Asked Questions List (FAQ), available on the Web at + + http://www.horde.org/faq/ + +The Horde Project runs a number of mailing lists, for individual applications +and for issues relating to the project as a whole. Information, archives, and +subscription information can be found at + + http://www.horde.org/mail/ + +Lastly, Horde developers, contributors and users may also be found on IRC, +on the channel #horde on the Freenode Network (irc.freenode.net). + +Please keep in mind that Hermes is free software written by volunteers. +For information on reasonable support expectations, please read + + http://www.horde.org/support.php + +Thanks for using Hermes! + +The Hermes team + + +.. _README: ?f=README.html +.. _`horde/docs/HACKING`: ../../horde/docs/?f=HACKING.html +.. _`horde/docs/INSTALL`: ../../horde/docs/?f=INSTALL.html +.. _`horde/docs/TRANSLATIONS`: ../../horde/docs/?f=TRANSLATIONS.html diff --git a/hermes/docs/RELEASE_NOTES b/hermes/docs/RELEASE_NOTES new file mode 100644 index 000000000..6b70a2969 --- /dev/null +++ b/hermes/docs/RELEASE_NOTES @@ -0,0 +1,47 @@ +notes['fm']['focus'] = 4; + +/* Mailing list release notes. */ +$this->notes['ml']['changes'] = <<notes['fm']['changes'] = <<notes['name'] = 'Hermes'; +$this->notes['list'] = 'horde'; +$this->notes['fm']['project'] = 'horde-hermes'; +$this->notes['fm']['branch'] = 'Default'; diff --git a/hermes/docs/TODO b/hermes/docs/TODO new file mode 100644 index 000000000..723188679 --- /dev/null +++ b/hermes/docs/TODO @@ -0,0 +1,29 @@ +============================== + Hermes Development TODO List +============================== + +:Last update: $Date: 2008/06/25 17:20:56 $ +:Revision: $Revision: 1.11 $ + +- Add support for managing "time pools" such as vacation time and sick days. + +- Add a request and approval mechanism (for some time pools, such as + vacation). + +- Add employee expenses. Allow them to be billed to clients. Add search + and export ability for them. + +- Add "Don't know" to "Billable?" options. A manager must review and decide + on all time before exporting. + +- Allow selection of which fields to display for clients. + +- Separate "review" permission into "Other People's Time" and "Submitted Time" + permissions (and "Other People's Submitted Time"?) + +- Preference to select a new entry mode where user can enter start time and + end time (instead of number of hours). + +- The client list can get quite large. Keep the last ten MRU in the drop + down box, with a sixth option being "More...". Javascript will pop open a + window with the full list (or a search window?) to cycle one into the MRU. diff --git a/hermes/entry.php b/hermes/entry.php new file mode 100644 index 000000000..d07eb1ed6 --- /dev/null +++ b/hermes/entry.php @@ -0,0 +1,97 @@ + + * @author Jan Schneider + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; +require_once HERMES_BASE . '/lib/Forms/Time.php'; + +$vars = Horde_Variables::getDefaultVariables(); + +if (!$vars->exists('id') && $vars->exists('timer')) { + $timer_id = $vars->get('timer'); + $timers = @unserialize($prefs->getValue('running_timers', false)); + if ($timers && isset($timers[$timer_id])) { + $tname = Horde_String::convertCharset($timers[$timer_id]['name'], $prefs->getCharset()); + $tformat = $prefs->getValue('twentyFour') ? 'G:i' : 'g:i a'; + $vars->set('hours', round((float)(time() - $timer_id) / 3600, 2)); + if ($prefs->getValue('add_description')) { + $vars->set('note', sprintf(_("Using the \"%s\" stop watch from %s to %s"), $tname, date($tformat, $timer_id), date($tformat, time()))); + } + $notification->push(sprintf(_("The stop watch \"%s\" has been stopped."), $tname), 'horde.success'); + unset($timers[$timer_id]); + $prefs->setValue('running_timers', serialize($timers), false); + } +} + +switch ($vars->get('formname')) { +case 'timeentryform': + $form = new TimeEntryForm($vars); + if ($form->validate($vars)) { + $form->getInfo($vars, $info); + if ($vars->exists('id')) { + $msg = _("Your time was successfully updated."); + $result = $hermes->updateTime(array($info)); + $do_redirect = true; + } else { + $msg = _("Your time was successfully entered."); + $result = $hermes->enterTime(Horde_Auth::getAuth(), $info); + $do_redirect = false; + } + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + $notification->push(sprintf(_("There was an error storing your timesheet: %s"), $result->getMessage()), 'horde.error'); + $do_redirect = false; + } else { + $notification->push($msg, 'horde.success'); + } + if ($do_redirect) { + $url = $vars->get('url'); + if (empty($url)) { + $url = Horde::applicationUrl('time.php'); + } + header('Location: ' . $url); + exit; + } + } + break; + +default: + if ($vars->exists('id')) { + // We are updating a specific entry, load it into the form variables. + $id = $vars->get('id'); + if (!Hermes::canEditTimeslice($id)) { + $notification->push(_("Access denied; user cannot modify this timeslice."), 'horde.error'); + header('Location: ' . Horde::applicationUrl('time.php')); + exit; + } + $myhours = $hermes->getHours(array('id' => $id)); + if (is_array($myhours)) { + foreach ($myhours as $item) { + if (isset($item['id']) && $item['id'] == $id) { + foreach ($item as $key => $value) { + $vars->set($key, $value); + } + } + } + } + } + $form = new TimeEntryForm($vars); + break; +} +$form->setCostObjects($vars); + +$title = $vars->exists('id') ? _("Edit Time") : _("New Time"); +require HERMES_TEMPLATES . '/common-header.inc'; +require HERMES_TEMPLATES . '/menu.inc'; +$form->renderActive(new Horde_Form_Renderer(), $vars, 'entry.php', 'post'); +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/hermes/index.php b/hermes/index.php new file mode 100644 index 000000000..55ba89325 --- /dev/null +++ b/hermes/index.php @@ -0,0 +1,20 @@ + + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; + +require_once 'Horde/Form.php'; +require_once 'Horde/Form/Renderer.php'; +require_once 'Horde/Form/Type/tableset.php'; + +$hours = $hermes->getHours(array('billable' => true, + 'submitted' => true)); +if (is_a($hours, 'PEAR_Error')) { + $notification->push($hours->getMessage(), 'horde.error'); + header('Location: ' . Horde::applicationUrl('time.php')); + exit; +} elseif (empty($hours)) { + $notification->push(_("There is no submitted billable hours."), 'horde.warning'); + header('Location: ' . Horde::applicationUrl('time.php')); + exit; +} elseif (!$registry->hasMethod('invoices/save')) { + $notification->push(_("Invoicing system is not installed."), 'horde.warning'); + header('Location: ' . Horde::applicationUrl('time.php')); + exit; +} + +$headers = array( + 'client' => _("Client"), + 'employee' => _("Employee"), + '_type_name' => _("Job Type"), + 'rate' => _("Rate"), + 'hours' => _("Hours"), + 'total' => _("Total"), + 'date' => _("Date"), + 'description' => _("Description"), + 'note' => _("Cost Object") +); + +$clients = Hermes::listClients(); +$df = $GLOBALS['prefs']->getValue('date_format'); + +$list = array(); +$client_keys = array(); +foreach ($hours as $hour) { + $id = (int)$hour['id']; + $client_keys[$id] = $hour['client']; + $list[$id] = array( + 'client' => $clients[$hour['client']], + 'employee' => $hour['employee'], + '_type_name' => $hour['_type_name'], + 'rate' => $hour['rate'], + 'hours' => $hour['hours'], + 'total' => $hour['rate'] * $hour['hours'], + 'date' => strftime($df, $hour['date']), + 'description' => $hour['description'], + '_costobject_name' => $hour['_costobject_name'], + ); +} + +$title = _("Create invoice"); +$vars = Horde_Variables::getDefaultVariables(); +$form = new Horde_Form($vars, $title, 'create_invoice'); + +$type_params = array(array(1 => _("Yes"), 0 => _("No"))); +$form->addVariable(_("Combine same clients in one invoice"), 'combine', 'enum', true, false, null, $type_params); +$v = &$form->addVariable(_("Select hours to be invoiced"), 'hours', 'tableset', true, false, false, array($list, $headers)); +$v->setDefault(array_keys($list)); + +if ($form->validate()) { + $form->getInfo(null, $info); + + $groups = array(); + if ($info['combine']) { + foreach ($info['hours'] as $id) { + $client = $client_keys[$id]; + if (isset($groups[$client])) { + $groups[$client]['hours'][] = $id; + } else { + $groups[$client] = array('client' => $client, + 'hours' => array($id)); + } + } + } else { + foreach ($info['hours'] as $id) { + $groups[] = array('client' => $hours[$id]['client'], + 'hours' => array($id)); + } + } + + foreach ($groups as $group) { + + $invoice = array(); + $invoice['client'] = array('id' => $group['client']); + $invoice['invoice'] = array('type' => $conf['invoices']['params']['type'], + 'status' => $conf['invoices']['params']['status'], + 'expire' => $conf['invoices']['params']['expire'], + 'place' => $conf['invoices']['params']['place'], + 'service' => date('Y-m-d')); + + $invoice['articles'] = array(); + foreach ($group['hours'] as $hour) { + $invoice['articles'][] = array('name' => $list[$hour]['description'], + 'price' => $list[$hour]['rate'], + 'qt' => $list[$hour]['hours'], + 'discount' => 0); + } + + $invoice_id = $registry->call('invoices/save', array($invoice)); + if (is_a($invoice_id, 'PEAR_Error')) { + $notification->push($invoice_id->getMessage(), 'horde.error'); + } else { + $msg = sprintf(_("Invoice for client %s successfuly created."), $clients[$group['client']]); + $notification->push($msg, 'horde.success'); + } + } + + header('Location: ' . Horde::applicationUrl('time.php')); + exit; +} + +require HERMES_TEMPLATES . '/common-header.inc'; +require HERMES_TEMPLATES . '/menu.inc'; + +$renderer = new Horde_Form_Renderer(array('varrenderer_driver' => 'tableset_html')); +$form->renderActive($renderer, null, Horde::applicationUrl('invoicing.php'), 'post'); + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/hermes/lib/Admin.php b/hermes/lib/Admin.php new file mode 100644 index 000000000..5ae46aa78 --- /dev/null +++ b/hermes/lib/Admin.php @@ -0,0 +1,201 @@ + + */ + +/** + * Horde_Form + */ +require_once 'Horde/Form.php'; + +/** + * @package Hermes + */ +class AddJobTypeForm extends Horde_Form { + + function AddJobTypeForm(&$vars) + { + parent::Horde_Form($vars, 'addjobtypeform'); + + $this->addVariable(_("Job Type"), 'name', 'text', true); + $var = &$this->addVariable(_("Enabled?"), 'enabled', 'boolean', false); + $var->setDefault(true); + $var = &$this->addVariable(_("Billable?"), 'billable', 'boolean', false); + $var->setDefault(true); + $this->addVariable(_("Hourly Rate"), 'rate', 'number', false); + } + +} + +/** + * @package Hermes + */ +class EditJobTypeStep1Form extends Horde_Form { + + function EditJobTypeStep1Form(&$vars) + { + global $hermes; + + parent::Horde_Form($vars, 'editjobtypestep1form'); + + $values = array(); + $jobtypes = $hermes->listJobTypes(); + if (!is_a($jobtypes, 'PEAR_Error')) { + foreach ($jobtypes as $id => $jobtype) { + $values[$id] = $jobtype['name']; + if (empty($jobtype['enabled'])) { + $values[$id] .= _(" (DISABLED)"); + } + } + } + + if ($values) { + $subtype = 'enum'; + $type_params = array($values); + } else { + $subtype = 'invalid'; + $type_params = array(_("There are no job types to edit")); + } + + $this->addVariable(_("JobType Name"), 'jobtype', $subtype, true, false, null, $type_params); + } + +} + +/** + * @package Hermes + */ +class EditJobTypeStep2Form extends Horde_Form { + + function EditJobTypeStep2Form(&$vars) + { + global $hermes; + + parent::Horde_Form($vars, 'editjobtypestep2form'); + + $jobtype = $vars->get('jobtype'); + $info = $hermes->getJobTypeByID($jobtype); + if (!$info || is_a($info, 'PEAR_Error')) { + $stype = 'invalid'; + $type_params = array(_("This is not a valid job type.")); + } else { + $stype = 'text'; + $type_params = array(); + } + + $this->addHidden('', 'jobtype', 'int', true, true); + + $sname = &$this->addVariable(_("Job Type"), 'name', $stype, true, false, null, $type_params); + if (!empty($info['name'])) { + $sname->setDefault($info['name']); + } + + $enab = &$this->addVariable(_("Enabled?"), 'enabled', 'boolean', false); + $enab->setDefault($info['enabled']); + $enab = &$this->addVariable(_("Billable?"), 'billable', 'boolean', false); + $enab->setDefault($info['billable']); + $enab = &$this->addVariable(_("Hourly Rate"), 'rate', 'number', false); + $enab->setDefault($info['rate']); + } + +} + +/** + * @package Hermes + */ +class DeleteJobTypeForm extends Horde_Form { + + function DeleteJobTypeForm(&$vars) + { + global $hermes; + + parent::Horde_Form($vars, 'deletejobtypeform'); + + $jobtype = $vars->get('jobtype'); + $info = $hermes->getJobTypeByID($jobtype); + + $yesnotype = 'enum'; + $type_params = array(array(0 => _("No"), 1 => _("Yes"))); + + $this->addHidden('', 'jobtype', 'int', true, true); + + $sname = &$this->addVariable(_("Job Type"), 'name', 'text', false, true); + $sname->setDefault($info['name']); + + $this->addVariable(_("Really delete this job type? This may cause data problems!!"), 'yesno', $yesnotype, true, false, null, $type_params); + } + +} + +/** + * @package Hermes + */ +class EditClientStep1Form extends Horde_Form { + + function EditClientStep1Form(&$vars) + { + global $hermes; + + parent::Horde_Form($vars, 'editclientstep1form'); + + $clients = Hermes::listClients(); + if (is_a($clients, 'PEAR_Error')) { + $subtype = 'invalid'; + $type_params = array($clients->getMessage()); + } elseif (count($clients)) { + $subtype = 'enum'; + $type_params = array($clients); + } else { + $subtype = 'invalid'; + $type_params = array(_("There are no clients to edit")); + } + + $this->addVariable(_("Client Name"), 'client', $subtype, true, false, null, $type_params); + } + +} + +/** + * @package Hermes + */ +class EditClientStep2Form extends Horde_Form { + + function EditClientStep2Form(&$vars) + { + global $hermes; + + parent::Horde_Form($vars, 'editclientstep2form'); + + $client = $vars->get('client'); + $info = $hermes->getClientSettings($client); + if (!$info || is_a($info, 'PEAR_Error')) { + $stype = 'invalid'; + $type_params = array(_("This is not a valid client.")); + } else { + $stype = 'text'; + $type_params = array(); + } + + $this->addHidden('', 'client', 'text', true, true); + $name = &$this->addVariable(_("Client"), 'name', $stype, false, true, false, null, $type_params); + $name->setDefault($info['name']); + + $enterdescription = &$this->addVariable(sprintf(_("Should users enter descriptions of their timeslices for this client? If not, the description will automatically be \"%s\"."), _("See Attached Timesheet")), 'enterdescription', 'boolean', true); + if (!empty($info['enterdescription'])) { + $enterdescription->setDefault($info['enterdescription']); + } + + $exportid = &$this->addVariable(_("ID for this client when exporting data, if different from the name displayed above."), 'exportid', 'text', false); + if (!empty($info['exportid'])) { + $exportid->setDefault($info['exportid']); + } + } + +} diff --git a/hermes/lib/Block/tree_menu.php b/hermes/lib/Block/tree_menu.php new file mode 100644 index 000000000..ba90b710d --- /dev/null +++ b/hermes/lib/Block/tree_menu.php @@ -0,0 +1,37 @@ +addNode($parent . '__add', + $parent, + _("Enter Time"), + $indent + 1, + false, + array('icon' => 'hermes.png', + 'icondir' => $GLOBALS['registry']->getImageDir(), + 'url' => Horde::applicationUrl('entry.php'))); + $tree->addNode($parent . '__search', + $parent, + _("Search Time"), + $indent + 1, + false, + array('icon' => 'search.png', + 'icondir' => $GLOBALS['registry']->getImageDir('horde'), + 'url' => Horde::applicationUrl('search.php'))); + } + +} diff --git a/hermes/lib/Block/tree_stopwatch.php b/hermes/lib/Block/tree_stopwatch.php new file mode 100644 index 000000000..ef8336985 --- /dev/null +++ b/hermes/lib/Block/tree_stopwatch.php @@ -0,0 +1,54 @@ +getImageDir(); + + $tree->addNode($parent . '__start', + $parent, + _("Start Watch"), + $indent + 1, + false, + array('icon' => 'timer-start.png', + 'icondir' => $icondir, + 'url' => '#', + 'onclick' => "popup('" . Horde::applicationUrl('start.php') . "', 400, 100); return false;")); + + $timers = @unserialize($prefs->getValue('running_timers', false)); + if ($timers) { + foreach ($timers as $i => $timer) { + $hours = round((float)(time() - $i) / 3600, 2); + $tname = Horde_String::convertCharset($timer['name'], $prefs->getCharset()) . sprintf(" (%s)", $hours); + $tree->addNode($parent . '__timer_' . $i, + $parent, + $tname, + $indent + 1, + false, + array('icon' => 'timer-stop.png', + 'icondir' => $icondir, + 'url' => Horde_Util::addParameter($entry, 'timer', $i), + 'target' => 'horde_main')); + } + } + } + +} diff --git a/hermes/lib/Data/hermes_csv.php b/hermes/lib/Data/hermes_csv.php new file mode 100644 index 000000000..e7ed61ce7 --- /dev/null +++ b/hermes/lib/Data/hermes_csv.php @@ -0,0 +1,47 @@ + + * @package Horde_Data + */ +class Horde_Data_hermes_csv extends Horde_Data_csv { + + var $_mapped = false; + + function exportData($data) + { + return parent::exportData($this->_map($data), true); + } + + function _map($data) + { + if ($this->_mapped) { + return $data; + } + + $this->_mapped = true; + + $count = count($data); + for ($i = 0; $i < $count; $i++) { + $data[$i]['description'] = str_replace(array("\r", "\n"), array('', ' '), $data[$i]['description']); + $data[$i]['note'] = str_replace(array("\r", "\n"), array('', ' '), $data[$i]['note']); + $data[$i]['timestamp'] = $data[$i]['date']; + $data[$i]['date'] = date('m/d/y', $data[$i]['date']); + $data[$i]['duration'] = date('H:i', mktime(0, $data[$i]['hours'] * 60)); + $data[$i]['billable'] = $data[$i]['billable'] == 2 ? '' : $data[$i]['billable']; + } + + return $data; + } + +} diff --git a/hermes/lib/Data/hermes_tsv.php b/hermes/lib/Data/hermes_tsv.php new file mode 100644 index 000000000..ef4bded15 --- /dev/null +++ b/hermes/lib/Data/hermes_tsv.php @@ -0,0 +1,47 @@ + + * @package Horde_Data + */ +class Horde_Data_hermes_tsv extends Horde_Data_tsv { + + var $_mapped = false; + + function exportData($data) + { + return parent::exportData($this->_map($data), true); + } + + function _map($data) + { + if ($this->_mapped) { + return $data; + } + + $this->_mapped = true; + + $count = count($data); + for ($i = 0; $i < $count; $i++) { + $data[$i]['description'] = str_replace(array("\r", "\n"), array('', ' '), $data[$i]['description']); + $data[$i]['note'] = str_replace(array("\r", "\n"), array('', ' '), $data[$i]['note']); + $data[$i]['timestamp'] = $data[$i]['date']; + $data[$i]['date'] = date('m/d/y', $data[$i]['date']); + $data[$i]['duration'] = date('H:i', mktime(0, $data[$i]['hours'] * 60)); + $data[$i]['billable'] = $data[$i]['billable'] == 2 ? '' : $data[$i]['billable']; + } + + return $data; + } + +} diff --git a/hermes/lib/Data/hermes_xls.php b/hermes/lib/Data/hermes_xls.php new file mode 100644 index 000000000..97c660c54 --- /dev/null +++ b/hermes/lib/Data/hermes_xls.php @@ -0,0 +1,23 @@ + + * @package Horde_Data + */ +class Horde_Data_hermes_xls extends Horde_Data_hermes_tsv { + + var $_extension = 'xls'; + var $_contentType = 'application/msexcel'; + +} diff --git a/hermes/lib/Data/iif.php b/hermes/lib/Data/iif.php new file mode 100644 index 000000000..da97fab8b --- /dev/null +++ b/hermes/lib/Data/iif.php @@ -0,0 +1,70 @@ + + * @package Horde_Data + */ +class Horde_Data_iif extends Horde_Data { + + var $_extension = 'iif'; + var $_contentType = 'text/plain'; + var $_rawData; + var $_iifData; + var $_mapped = false; + + function exportData($data) + { + $this->_rawData = $data; + $newline = $this->getNewline(); + + $this->_map(); + + $data = "!TIMEACT\tDATE\tJOB\tEMP\tITEM\tDURATION\tNOTE\tBILLINGSTATUS\tPITEM$newline"; + foreach ($this->_iifData as $row) { + $data .= implode("\t", $row) . $newline; + } + + return $data; + } + + function _map() + { + if ($this->_mapped) { + return; + } + + $this->_mapped = true; + + foreach ($this->_rawData as $row) { + $row['description'] = str_replace(array("\r", "\n"), array('', ' '), $row['description']); + $row['note'] = str_replace(array("\r", "\n"), array('', ' '), $row['note']); + $this->_iifData[] = array('_label' => 'TIMEACT', + 'DATE' => date('m/d/y', $row['date']), + 'JOB' => $row['client'], + 'EMP' => $row['employee'], + 'ITEM' => $row['item'], + 'DURATION' => date('H:i', mktime(0, $row['hours'] * 60)), + 'NOTE' => $row['description'] . (!empty($row['note']) ? _("; Notes: ") . $row['note'] : ''), + 'BILLINGSTATUS' => $row['billable'] == 2 ? '' : $row['billable'], + 'PITEM' => 'Not Applicable'); + } + } + +} diff --git a/hermes/lib/Data/qbxml.php b/hermes/lib/Data/qbxml.php new file mode 100644 index 000000000..851dca092 --- /dev/null +++ b/hermes/lib/Data/qbxml.php @@ -0,0 +1,20 @@ + + * @package Horde_Data + */ +class Horde_Data_qbxml extends Horde_Data { + + var $_extension = 'xml'; + +} diff --git a/hermes/lib/Driver.php b/hermes/lib/Driver.php new file mode 100644 index 000000000..868dbddb0 --- /dev/null +++ b/hermes/lib/Driver.php @@ -0,0 +1,225 @@ + + * @since Hermes 0.1 + * @package Hermes + */ +class Hermes_Driver { + + /** + * Retrieve a specific job type record. + * + * @param integer $jobTypeID The ID of the job type. + * + * @return mixed Hash of job type properties, or PEAR_Error on failure. + */ + function getJobTypeByID($jobTypeID) + { + $jobtypes = $this->listJobTypes(array('id' => $jobTypeID)); + if (is_a($jobtypes, 'PEAR_Error')) { + return $jobtypes; + } + if (!isset($jobtypes[$jobTypeID])) { + return PEAR::raiseError(sprintf(_("No job type with ID \"%s\"."), + $jobTypeID)); + } + return $jobtypes[$jobTypeID]; + } + + /** + * Add or update a job type record. + * + * @abstract + * @param array $jobtype A hash of job type properties: + * 'id' => The ID of the job, if updating. If not + * present, a new job type is created. + * 'name' => The job type's name. + * 'enabled' => Whether the job type is enabled for new + * time entry. + * + * @return mixed The job's ID, or PEAR_Error on failure. + */ + function updateJobType($jobtype) + { + return PEAR::raiseError(_("Not implemented.")); + } + + /** + * Retrieve list of job types. + * + * @abstract + * + * @param array $criteria Hash of filter criteria: + * + * 'enabled' => If present, only retrieve enabled + * or disabled job types. + * + * @return mixed Associative array of job types, or PEAR_Error on failure. + */ + function listJobTypes($criteria = array()) + { + return PEAR::raiseError(_("Not implemented.")); + } + + /** + * Retrieve a deliverable by ID. + * + * @param integer $deliverableID The ID of the deliverable to + * retrieve. + * @return mixed Hash of deliverable's properties, or PEAR_Error on + * failure. + */ + function getDeliverableByID($deliverableID) + { + $deliverables = $this->listDeliverables(array('id' => $deliverableID)); + if (is_a($deliverables, 'PEAR_Error')) { + return $deliverables; + } + + if (!isset($deliverables[$deliverableID])) { + return PEAR::raiseError(sprintf(_("Deliverable %d not found."), + $deliverableID)); + } + + return $deliverables[$deliverableID]; + } + + /** + * Add or update a deliverable. + * + * @abstract + * @param array $deliverable A hash of deliverable properties: + * 'id' => The ID of the deliverable, if + * updating. If not present, a new + * ID is allocated. + * 'name' => The deliverable's display name. + * 'client_id' => The assigned client ID. + * 'parent' => ID of the deliverables parent + * deliverable (if a child). + * 'estimate' => Estimated number of hours for + * completion of the deliverable. + * 'active' => Whether this deliverable is active. + * 'description' => Text description (notes) for this + * deliverable. + * + * @return mixed Integer ID of new or saved deliverable, or PEAR_Error on + * failure. + */ + function updateDeliverable($deliverable) + { + return PEAR::raiseError(_("Not implemented.")); + } + + /** + * Retrieve list of deliverables. + * + * @abstract + * + * @param array $criteria A hash of search criteria: + * 'id' => If present, only deliverable with + * specified ID is searched for. + * 'client_id' => If present, list is filtered by + * client ID. + * + * @return mixed Associative array of job types, or PEAR_Error on failure. + */ + function listDeliverables($criteria = array()) + { + return PEAR::raiseError(_("Not implemented.")); + } + + /** + * Delete a deliverable. + * + * @abstract + * @param integer $deliverableID The ID of the deliverable. + * + * @return mixed Null, or PEAR_Error on failure. + */ + function deleteDeliverable($deliverableID) + { + return PEAR::raiseError(_("Not implemented.")); + } + + /** + * Attempts to return a concrete Hermes_Driver instance based on $driver. + * + * @param string $driver The type of concrete Hermes_Driver subclass to + * return. + * @param array $params A hash containing any additional configuration or + * connection parameters a subclass might need. + * + * @return mixed The newly created concrete Hermes_Driver instance, or + * false on error. + */ + function &factory($driver = null, $params = null) + { + if (is_null($driver)) { + $driver = $GLOBALS['conf']['storage']['driver']; + } + + $driver = basename($driver); + + if (is_null($params)) { + $params = Horde::getDriverConfig('storage', $driver); + } + + $class = 'Hermes_Driver_' . $driver; + if (class_exists($class)) { + $hermes = new $class($params); + } else { + $hermes = false; + } + + return $hermes; + } + + /** + * Attempts to return a reference to a concrete Hermes_Driver instance + * based on $driver. + * + * It will only create a new instance if no Hermes_Driver instance with the + * same parameters currently exists. + * + * This should be used if multiple storage sources are required. + * + * This method must be invoked as: $var = &Hermes_Driver::singleton() + * + * @param string $driver The type of concrete Hermes_Driver subclass to + * return. + * @param array $params A hash containing any additional configuration or + * connection parameters a subclass might need. + * + * @return mixed The created concrete Hermes_Driver instance, or false on + * error. + */ + function &singleton($driver = null, $params = null) + { + static $instances; + + if (is_null($driver)) { + $driver = $GLOBALS['conf']['storage']['driver']; + } + + if (is_null($params)) { + $params = Horde::getDriverConfig('storage', $driver); + } + + if (!isset($instances)) { + $instances = array(); + } + + $signature = serialize(array($driver, $params)); + if (!isset($instances[$signature])) { + $instances[$signature] = &Hermes_Driver::factory($driver, $params); + } + + return $instances[$signature]; + } + +} diff --git a/hermes/lib/Driver/sql.php b/hermes/lib/Driver/sql.php new file mode 100644 index 000000000..433e2c9b2 --- /dev/null +++ b/hermes/lib/Driver/sql.php @@ -0,0 +1,748 @@ + + * 'phptype' The database type (e.g. 'pgsql', 'mysql', etc.). + * + * Required by some database implementations:
+ *      'hostspec'      The hostname of the database server.
+ *      'protocol'      The communication protocol ('tcp', 'unix', etc.).
+ *      'database'      The name of the database.
+ *      'username'      The username with which to connect to the database.
+ *      'password'      The password associated with 'username'.
+ *      'options'       Additional options to pass to the database.
+ *      'tty'           The TTY on which to connect to the database.
+ *      'port'          The port on which to connect to the database.
+ * + * The table structure can be created by the + * scripts/drivers/hermes.sql script. + * + * @author Chuck Hagenbuch _params = $params; + } + + /** + * Save a row of billing information. + * + * @param string $employee The Horde ID of the person who worked the + * hours. + * @param array $entries The billing information to enter. Each array + * row must contain the following entries: + * 'date' The day the hours were worked (ISO format) + * 'client' The id of the client the work was done for. + * 'type' The type of work done. + * 'hours' The number of hours worked + * 'rate' The hourly rate the work was done at. + * 'billable' (optional) Whether or not the work is + * billable hours. + * 'description' A short description of the work. + * + * @return mixed True on success, PEAR_Error on failure. + */ + function enterTime($employee, $info) + { + require_once 'Date.php'; + + /* Make sure we have a valid database connection. */ + $this->_connect(); + + /* Get job rate */ + $sql = 'SELECT jobtype_rate FROM hermes_jobtypes WHERE jobtype_id = ?'; + $job_rate = $this->_db->getOne($sql, array($info['type'])); + + $dt = new Date($info['date']); + $timeslice_id = $this->_db->nextId('hermes_timeslices'); + $sql = 'INSERT INTO hermes_timeslices (timeslice_id, ' . + 'clientjob_id, employee_id, jobtype_id, ' . + 'timeslice_hours, timeslice_isbillable, ' . + 'timeslice_date, timeslice_description, ' . + 'timeslice_note, timeslice_rate, costobject_id) ' . + 'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + $values = array((int)$timeslice_id, + $info['client'], + $employee, + $info['type'], + $info['hours'], + isset($info['billable']) ? (int)$info['billable'] : 0, + (int)$dt->getTime(DATE_FORMAT_UNIXTIME) + 1, + $info['description'], + $info['note'], + (float)$job_rate, + (empty($info['costobject']) ? null : + $info['costobject'])); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + return $this->_db->query($sql, $values); + } + + /** + * Update a set of billing information. + * + * @param array $entries The billing information to enter. Each array row + * must contain the following entries: + * 'id' The id of this time entry. + * 'date' The day the hours were worked (ISO format) + * 'client' The id of the client the work was done for. + * 'type' The type of work done. + * 'hours' The number of hours worked + * 'rate' The hourly rate the work was done at. + * 'billable' Whether or not the work is billable hours. + * 'description' A short description of the work. + * + * If any rows contain a 'delete' entry, those rows + * will be deleted instead of updated. + * + * @return mixed True on success, PEAR_Error on failure. + */ + function updateTime($entries) + { + require_once 'Date.php'; + + /* Make sure we have a valid database connection. */ + $this->_connect(); + + foreach ($entries as $info) { + if (!Hermes::canEditTimeslice($info['id'])) { + return PEAR::raiseError(_("Access denied; user cannot modify this timeslice.")); + } + if (!empty($info['delete'])) { + $sql = 'DELETE FROM hermes_timeslices WHERE timeslice_id = ?'; + $values = array((int)$info['id']); + } else { + if (isset($info['employee'])) { + $employee_cl = ' employee_id = ?,'; + + $values = array($info['employee']); + } else { + $employee_cl = ''; + } + $dt = new Date($info['date']); + $sql = 'UPDATE hermes_timeslices SET' . $employee_cl . + ' clientjob_id = ?, jobtype_id = ?,' . + ' timeslice_hours = ?, timeslice_isbillable = ?,' . + ' timeslice_date = ?, timeslice_description = ?,' . + ' timeslice_note = ?, costobject_id = ?' . + ' WHERE timeslice_id = ?'; + $values = array($info['client'], + $info['type'], + $info['hours'], + (isset($info['billable']) ? (int)$info['billable'] : 0), + (int)$dt->getTime(DATE_FORMAT_UNIXTIME) + 1, + $info['description'], + $info['note'], + (empty($info['costobject']) ? null : $info['costobject']), + (int)$info['id']); + } + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + } + + return true; + } + + function getHours($filters = array(), $fields = array()) + { + global $conf; + + /* Make sure we have a valid database connection. */ + $this->_connect(); + + $fieldlist = array( + 'id' => 'b.timeslice_id as id', + 'client' => ' b.clientjob_id as client', + 'employee' => ' b.employee_id as employee', + 'type' => ' b.jobtype_id as type', + '_type_name' => ' j.jobtype_name as "_type_name"', + 'hours' => ' b.timeslice_hours as hours', + 'rate' => ' b.timeslice_rate as rate', + 'billable' => empty($conf['time']['choose_ifbillable']) + ? ' j.jobtype_billable as billable' + : ' b.timeslice_isbillable as billable', + 'date' => ' b.timeslice_date as "date"', + 'description' => ' b.timeslice_description as description', + 'note' => ' b.timeslice_note as note', + 'submitted' => ' b.timeslice_submitted as submitted', + 'costobject' => ' b.costobject_id as costobject'); + if (!empty($fields)) { + $fieldlist = array_keys(array_intersect(array_flip($fieldlist), $fields)); + } + $fieldlist = implode(', ', $fieldlist); + $sql = 'SELECT ' . $fieldlist . ' FROM hermes_timeslices b INNER JOIN hermes_jobtypes j ON b.jobtype_id = j.jobtype_id'; + if (count($filters) > 0) { + $where = ''; + $glue = ''; + foreach ($filters as $field => $filter) { + switch ($field) { + case 'client': + $where .= $glue . $this->_equalClause('b.clientjob_id', + $filter); + $glue = ' AND'; + break; + + case 'jobtype': + $where .= $glue . $this->_equalClause('b.jobtype_id', + $filter); + $glue = ' AND'; + break; + + case 'submitted': + $where .= $glue . ' timeslice_submitted = ' . (int)$filter; + $glue = ' AND'; + break; + + case 'exported': + $where .= $glue . ' timeslice_exported = ' . (int)$filter; + $glue = ' AND'; + break; + + case 'billable': + $where .= $glue + . (empty($conf['time']['choose_ifbillable']) + ? ' jobtype_billable = ' + : ' timeslice_isbillable = ') + . (int)$filter; + $glue = ' AND'; + break; + + case 'start': + $where .= $glue . ' timeslice_date >= ' . (int)$filter; + $glue = ' AND'; + break; + + case 'end': + $where .= $glue . ' timeslice_date <= ' . (int)$filter; + $glue = ' AND'; + break; + + case 'employee': + $where .= $glue . $this->_equalClause('employee_id', + $filter); + $glue = ' AND'; + break; + + case 'id': + $where .= $glue . $this->_equalClause('timeslice_id', + (int)$filter, false); + $glue = ' AND'; + break; + + case 'costobject': + $where .= $glue . $this->_equalClause('costobject_id', + $filter); + $glue = ' AND'; + break; + } + } + if (!empty($where)) { + $sql .= ' WHERE ' . $where; + } + } + + $sql .= ' ORDER BY timeslice_date DESC, clientjob_id'; + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + $hours = $this->_db->getAll($sql, DB_FETCHMODE_ASSOC); + if (is_a($hours, 'PEAR_Error')) { + return $hours; + } + + // Add cost object names to the results. + if (empty($fields) || in_array('costobject', $fields)) { + foreach (array_keys($hours) as $hkey) { + if (empty($hours[$hkey]['costobject'])) { + $hours[$hkey]['_costobject_name'] = ''; + } else { + $costobject = Hermes::getCostObjectByID($hours[$hkey]['costobject']); + if (is_a($costobject, 'PEAR_Error')) { + $hours[$hkey]['_costobject_name'] = sprintf(_("Error: %s"), $costobject->getMessage()); + } else { + $hours[$hkey]['_costobject_name'] = $costobject['name']; + } + } + } + } + + return $hours; + } + + /** + * @access private + */ + function _equalClause($lhs, $rhs, $quote = true) + { + require_once 'Horde/SQL.php'; + + if (!is_array($rhs)) { + if ($quote) { + return sprintf(' %s = %s', $lhs, $this->_db->quote($rhs)); + } + return sprintf(' %s = %s', $lhs, $rhs); + } + + if (count($rhs) == 0) { + return ' FALSE'; + } + + $glue = ''; + $ret = sprintf(' %s IN ( ', $lhs); + foreach ($rhs as $value) { + $ret .= $glue . $this->_db->quote($value); + $glue = ', '; + } + return $ret . ' )'; + } + + function markAs($field, $hours) + { + if (!count($hours)) { + return false; + } + + $this->_connect(); + + switch ($field) { + case 'submitted': + $h_field = 'timeslice_submitted'; + break; + + case 'exported': + $h_field = 'timeslice_exported'; + break; + + default: + return false; + } + + $ids = array(); + foreach ($hours as $entry) { + $ids[] = (int)$entry['id']; + } + + $sql = 'UPDATE hermes_timeslices SET ' . $h_field . ' = 1' . + ' WHERE timeslice_id IN (' . implode(',', $ids) . ')'; + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + return $this->_db->query($sql); + } + + function listJobTypes($criteria = array()) + { + /* Make sure we have a valid database connection. */ + $this->_connect(); + + $where = array(); + $values = array(); + if (isset($criteria['id'])) { + $where[] = 'jobtype_id = ?'; + $values[] = $criteria['id']; + } + if (isset($criteria['enabled'])) { + $where[] = 'jobtype_enabled = ?'; + $values[] = ($criteria['enabled'] ? 1 : 0); + } + + $sql = 'SELECT jobtype_id, jobtype_name, jobtype_enabled' . + ', jobtype_rate, jobtype_billable FROM hermes_jobtypes' . + (empty($where) ? '' : (' WHERE ' . join(' AND ', $where))) . + ' ORDER BY jobtype_name'; + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + $results = array(); + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + while (!empty($row) && !is_a($row, 'PEAR_Error')) { + $id = $row['jobtype_id']; + $results[$id] = array('id' => $id, + 'name' => $row['jobtype_name'], + 'rate' => (float)$row['jobtype_rate'], + 'billable' => (int)$row['jobtype_billable'], + 'enabled' => !empty($row['jobtype_enabled'])); + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + } + if (is_a($row, 'PEAR_Error')) { + return $row; + } + + return $results; + } + + function updateJobType($jobtype) + { + $this->_connect(); + + if (!isset($jobtype['enabled'])) { + $jobtype['enabled'] = 1; + } + if (!isset($jobtype['billable'])) { + $jobtype['billable'] = 1; + } + if (empty($jobtype['id'])) { + $jobtype['id'] = $this->_db->nextId('hermes_jobtypes'); + $sql = 'INSERT INTO hermes_jobtypes (jobtype_id, jobtype_name, ' . + ' jobtype_enabled, jobtype_rate, jobtype_billable) VALUES (?, ?, ?, ?, ?)'; + $values = array($jobtype['id'], $jobtype['name'], + (int)$jobtype['enabled'], (float)$jobtype['rate'], (int)$jobtype['billable']); + } else { + $sql = 'UPDATE hermes_jobtypes' . + ' SET jobtype_name = ?, jobtype_enabled = ?, jobtype_rate = ?,' . + ' jobtype_billable = ? WHERE jobtype_id = ?'; + $values = array($jobtype['name'], (int)$jobtype['enabled'],(float)$jobtype['rate'], + (int)$jobtype['billable'], $jobtype['id']); + } + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + return $jobtype['id']; + } + + function deleteJobType($jobTypeID) + { + /* Make sure we have a valid database connection. */ + $this->_connect(); + + $sql = 'DELETE FROM hermes_jobtypes WHERE jobtype_id = ?'; + $values = array($jobTypeID); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + return $this->_db->query($sql, $values); + } + + function updateDeliverable($deliverable) + { + $this->_connect(); + + if (empty($deliverable['id'])) { + $deliverable['id'] = $this->_db->nextId('hermes_deliverables'); + $sql = 'INSERT INTO hermes_deliverables (deliverable_id,' . + ' client_id, deliverable_name, deliverable_parent,' . + ' deliverable_estimate, deliverable_active,' . + ' deliverable_description) VALUES (?, ?, ?, ?, ?, ?, ?)'; + $values = array((int)$deliverable['id'], + $deliverable['client_id'], + $deliverable['name'], + (empty($deliverable['parent']) ? null : + (int)$deliverable['parent']), + (empty($deliverable['estimate']) ? null : + $deliverable['estimate']), + ($deliverable['active'] ? 1 : 0), + (empty($deliverable['description']) ? null : + $deliverable['description'])); + } else { + $sql = 'UPDATE hermes_deliverables SET client_id = ?,' . + ' deliverable_name = ?, deliverable_parent = ?,' . + ' deliverable_estimate = ?, deliverable_active = ?,' . + ' deliverable_description = ? WHERE deliverable_id = ?'; + $values = array($deliverable['client_id'], + $deliverable['name'], + (empty($deliverable['parent']) ? null : + (int)$deliverable['parent']), + (empty($deliverable['estimate']) ? null : + $deliverable['estimate']), + ($deliverable['active'] ? 1 : 0), + (empty($deliverable['description']) ? null : + $deliverable['description']), + $deliverable['id']); + } + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + return $deliverable['id']; + } + + function listDeliverables($criteria = array()) + { + $this->_connect(); + + $where = array(); + $values = array(); + if (isset($criteria['id'])) { + $where[] = 'deliverable_id = ?'; + $values[] = $criteria['id']; + } + if (isset($criteria['client_id'])) { + $where[] = 'client_id = ?'; + $values[] = $criteria['client_id']; + } + if (isset($criteria['active'])) { + if ($criteria['active']) { + $where[] = 'deliverable_active <> ?'; + } else { + $where[] = 'deliverable_active = ?'; + } + $values[] = 0; + } + + $sql = 'SELECT * FROM hermes_deliverables' . + (count($where) ? ' WHERE ' . join(' AND ', $where) : ''); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + $deliverables = array(); + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + while (!empty($row) && !is_a($row, 'PEAR_Error')) { + + $deliverable = array('id' => $row['deliverable_id'], + 'client_id' => $row['client_id'], + 'name' => $row['deliverable_name'], + 'parent' => $row['deliverable_parent'], + 'estimate' => $row['deliverable_estimate'], + 'active' => !empty($row['deliverable_active']), + 'description' => $row['deliverable_description']); + $deliverables[$row['deliverable_id']] = $deliverable; + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + } + + if (is_a($row, 'PEAR_Error')) { + return $row; + } + + return $deliverables; + } + + function deleteDeliverable($deliverableID) + { + $this->_connect(); + + $sql = 'SELECT COUNT(*) AS c FROM hermes_deliverables' . + ' WHERE deliverable_parent = ?'; + $values = array($deliverableID); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + if (!empty($row['c'])) { + return PEAR::raiseError(_("Cannot delete deliverable; it has children.")); + } + + $sql = 'SELECT COUNT(*) AS c FROM hermes_timeslices' . + ' WHERE costobject_id = ?'; + $values = array($deliverableID); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_db->query($sql, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + if (!empty($row['c'])) { + return PEAR::raiseError(_("Cannot delete deliverable; there is time entered on it.")); + } + + $sql = 'DELETE FROM hermes_deliverables WHERE deliverable_id = ?'; + $values = array($deliverableID); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + return $this->_db->query($sql, $values); + } + + function getClientSettings($clientID) + { + /* Make sure we have a valid database connection. */ + $this->_connect(); + + $clients = Hermes::listClients(); + if (empty($clientID) || !isset($clients[$clientID])) { + return PEAR::raiseError('Does not exist'); + } + + $sql = 'SELECT clientjob_id, clientjob_enterdescription,' . + ' clientjob_exportid FROM hermes_clientjobs' . + ' WHERE clientjob_id = ?'; + $values = array($clientID); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $clientJob = $this->_db->getAssoc($sql, false, $values); + if (is_a($clientJob, 'PEAR_Error')) { + return $clientJob; + } + + if (isset($clientJob[$clientID])) { + $settings = array('id' => $clientID, + 'enterdescription' => $clientJob[$clientID][0], + 'exportid' => $clientJob[$clientID][1]); + } else { + $settings = array('id' => $clientID, + 'enterdescription' => 1, + 'exportid' => null); + } + + $settings['name'] = $clients[$clientID]; + return $settings; + } + + function updateClientSettings($clientID, $enterdescription = 1, $exportid = null) + { + /* Make sure we have a valid database connection. */ + $this->_connect(); + + if (empty($exportid)) { + $exportid = null; + } + + $sql = 'SELECT clientjob_id FROM hermes_clientjobs' . + ' WHERE clientjob_id = ?'; + $values = array($clientID); + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + if ($this->_db->getOne($sql, $values) !== $clientID) { + $sql = 'INSERT INTO hermes_clientjobs (clientjob_id,' . + ' clientjob_enterdescription, clientjob_exportid)' . + ' VALUES (?, ?, ?)'; + $values = array($clientID, (int)$enterdescription, $exportid); + } else { + $sql = 'UPDATE hermes_clientjobs SET' . + ' clientjob_exportid = ?, clientjob_enterdescription = ?' . + ' WHERE clientjob_id = ?'; + $values = array($exportid, (int)$enterdescription, $clientID); + } + + Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + return $this->_db->query($sql, $values); + } + + function purge() + { + global $conf; + + /* Make sure we have a valid database connection. */ + $this->_connect(); + + $query = 'DELETE FROM hermes_timeslices' . + ' WHERE timeslice_exported = ? AND timeslice_date < ?'; + $values = array(1, mktime(0, 0, 0, date('n'), + date('j') - $conf['time']['days_to_keep'])); + return $this->_db->query($query, $values); + } + + /** + * Attempts to open a persistent connection to the SQL server. + * + * @return boolean True on success; exits (Horde::fatal()) on error. + */ + function _connect() + { + if (!$this->_connected) { + Horde::assertDriverConfig($this->_params, 'storage', + array('phptype')); + + if (!isset($this->_params['database'])) { + $this->_params['database'] = ''; + } + if (!isset($this->_params['username'])) { + $this->_params['username'] = ''; + } + if (!isset($this->_params['hostspec'])) { + $this->_params['hostspec'] = ''; + } + + /* Connect to the SQL server using the supplied parameters. */ + include_once 'DB.php'; + $this->_db = &DB::connect($this->_params, + array('persistent' => !empty($this->_params['persistent']))); + if (is_a($this->_db, 'PEAR_Error')) { + Horde::fatal($this->_db, __FILE__, __LINE__); + } + + // Set DB portability options. + switch ($this->_db->phptype) { + case 'mssql': + $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); + break; + default: + $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); + } + + $this->_connected = true; + } + + return true; + } + + /** + * Disconnect from the SQL server and clean up the connection. + * + * @return boolean True on success, false on failure. + */ + function _disconnect() + { + if ($this->_connected) { + $this->_connected = false; + return $this->_db->disconnect(); + } + + return true; + } + +} diff --git a/hermes/lib/Forms/Deliverable.php b/hermes/lib/Forms/Deliverable.php new file mode 100644 index 000000000..a25b85331 --- /dev/null +++ b/hermes/lib/Forms/Deliverable.php @@ -0,0 +1,64 @@ + + * @package Hermes + */ +class DeliverableClientSelector extends Horde_Form { + + function DeliverableClientSelector(&$vars) + { + parent::Horde_Form($vars, _("Select Client")); + + require 'Horde/Form/Action.php'; + $action = &Horde_Form_Action::factory('submit'); + list($clienttype, $clientparams) = $this->getClientType(); + + $cli = &$this->addVariable(_("Client"), 'client_id', $clienttype, true, false, null, $clientparams); + $cli->setAction($action); + $this->setButtons(_("Edit Deliverables")); + } + + function getClientType() + { + $clients = Hermes::listClients(); + if (is_a($clients, 'PEAR_Error')) { + return array('invalid', array(sprintf(_("An error occurred listing clients: %s"), + $clients->getMessage()))); + } elseif (count($clients)) { + return array('enum', array($clients)); + } else { + return array('invalid', array(_("There are no clients which you have access to."))); + } + } + +} + +class DeliverableForm extends Horde_Form { + + function DeliverableForm(&$vars) + { + parent::Horde_Form($vars, _("Deliverable Detail")); + + $this->addHidden('', 'deliverable_id', 'text', false); + $this->addHidden('', 'client_id', 'text', false); + $this->addHidden('', 'parent', 'text', false); + + $this->addVariable(_("Display Name"), 'name', 'text', true); + $this->addVariable(_("Active?"), 'active', 'boolean', true); + $this->addVariable(_("Estimated Hours"), 'estimate', 'number', false); + $this->addVariable(_("Description"), 'description', 'longtext', false); + } + +} diff --git a/hermes/lib/Forms/Export.php b/hermes/lib/Forms/Export.php new file mode 100644 index 000000000..028f1febd --- /dev/null +++ b/hermes/lib/Forms/Export.php @@ -0,0 +1,59 @@ + + * @author Jason M. Felice + * @package Hermes + */ +class ExportForm extends Horde_Form { + + var $_useFormToken = false; + + function ExportForm(&$vars) + { + global $perms; + + parent::Horde_Form($vars, _("Export Search Results")); + + $formats = array('hermes_csv' => _("Comma-Separated Variable (.csv)"), + 'hermes_xls' => _("Microsoft Excel (.xls)"), + 'iif' => _("QuickBooks (.iif)"), + 'hermes_tsv' => _("Tab-Separated Variable (.tsv, .txt)"), + ); + + $this->addVariable(_("Select the export format"), 'format', 'enum', + true, false, null, array($formats)); + + if ($perms->hasPermission('hermes:review', Horde_Auth::getAuth(), + Horde_Perms::EDIT)) { + $yesno = array('yes' => _("Yes"), + 'no' => _("No")); + $var = &$this->addVariable(_("Mark the time as exported?"), + 'mark_exported', 'enum', true, false, + null, array($yesno)); + $var->setDefault('no'); + } + + $this->setButtons(_("Export")); + } + +} diff --git a/hermes/lib/Forms/Search.php b/hermes/lib/Forms/Search.php new file mode 100644 index 000000000..ec62ec2d5 --- /dev/null +++ b/hermes/lib/Forms/Search.php @@ -0,0 +1,216 @@ + + * @package Hermes + */ +class SearchForm extends Horde_Form { + + var $_useFormToken = false; + + function SearchForm(&$vars) + { + parent::Horde_Form($vars, _("Search For Time")); + + if ($GLOBALS['perms']->hasPermission('hermes:review', Horde_Auth::getAuth(), Horde_Perms::SHOW)) { + $type = Hermes::getEmployeesType(); + $this->addVariable(_("Employees"), 'employees', $type[0], false, + false, null, $type[1]); + } + + require_once 'Horde/Form/Action.php'; + $type = $this->getClientsType(); + $cli = &$this->addVariable(_("Clients"), 'clients', $type[0], false, false, + null, $type[1]); + $cli->setAction(Horde_Form_Action::factory('submit')); + $cli->setOption('trackchange', true); + + $type = $this->getJobTypesType(); + $this->addVariable(_("Job Types"), 'jobtypes', $type[0], false, false, + null, $type[1]); + + $this->addVariable(_("Cost Objects"), 'costobjects', 'multienum', + false, false, null, + array($this->getCostObjectType($vars))); + + $this->addVariable(_("Do not include entries before"), 'start', + 'monthdayyear', false, false, null, + array(date('Y') - 10)); + $this->addVariable(_("Do not include entries after"), 'end', + 'monthdayyear', false, false, null, + array(date('Y') - 10)); + + $states = array('' => '', + '1' => _("Yes"), + '0' => _("No")); + $this->addVariable(_("Submitted?"), 'submitted', 'enum', false, false, + null, array($states)); + + $this->addVariable(_("Exported?"), 'exported', 'enum', false, false, + null, array($states)); + + $this->addVariable(_("Billable?"), 'billable', 'enum', false, false, + null, array($states)); + + $this->setButtons(_("Search")); + } + + function getClientsType() + { + $clients = Hermes::listClients(); + if (is_a($clients, 'PEAR_Error')) { + return array('invalid', array(sprintf(_("An error occurred listing clients: %s"), + $clients->getMessage()))); + } else { + $clients = array('' => _("- - None - -")) + $clients; + return array('multienum', array($clients)); + } + } + + function getJobTypesType() + { + global $hermes; + + $types = $hermes->listJobTypes(); + if (is_a($types, 'PEAR_Error')) { + return array('invalid', array(sprintf(_("An error occurred listing job types: %s"), + $types->getMessage()))); + } else { + $values = array(); + foreach ($types as $id => $type) { + $values[$id] = $type['name']; + if (empty($type['enabled'])) { + $values[$id] .= _(" (DISABLED)"); + } + } + return array('multienum', array($values)); + } + } + + function getCostObjectType($vars) + { + global $hermes, $registry; + + $clients = $vars->get('clients'); + if (count($clients) == 0){ + $clients = array(''); + } + + $costobjects = array(); + foreach ($clients as $client) { + $criteria = array('user' => Horde_Auth::getAuth(), + 'active' => true, + 'client_id' => $client); + + foreach ($registry->listApps() as $app) { + if ($registry->hasMethod('listCostObjects', $app)) { + $res = $registry->callByPackage($app, 'listCostObjects', + array($criteria)); + if (is_a($res, 'PEAR_Error')) { + global $notification; + $notification->push(sprintf(_("Error retrieving cost objects from \"%s\": %s"), $registry->get('name', $app), $res->getMessage()), 'horde.error'); + continue; + } + foreach (array_keys($res) as $catkey) { + foreach (array_keys($res[$catkey]['objects']) as $okey){ + $res[$catkey]['objects'][$okey]['id'] = $app . ':' . + $res[$catkey]['objects'][$okey]['id']; + } + } + $costobjects = array_merge($costobjects, $res); + } + } + } + + $elts = array(); + $counter = 0; + foreach ($costobjects as $category) { + Horde_Array::arraySort($category['objects'], 'name'); + foreach ($category['objects'] as $object) { + $name = $object['name']; + if (Horde_String::length($name) > 80) { + $name = Horde_String::substr($name, 0, 76) . ' ...'; + } + $elts[$object['id']] = $name; + } + } + + return $elts; + } + + + function getSearchCriteria(&$vars) + { + require_once 'Date.php'; + + if (!$this->isValid() || !$this->isSubmitted()) { + return null; + } + $this->getInfo($vars, $info); + + $criteria = array(); + if ($GLOBALS['perms']->hasPermission('hermes:review', Horde_Auth::getAuth(), Horde_Perms::SHOW)) { + if (!empty($info['employees'])) { + $auth = Horde_Auth::singleton($GLOBALS['conf']['auth']['driver']); + if (!$auth->capabilities['list']) { + $criteria['employee'] = explode(',', $info['employees']); + } else { + $criteria['employee'] = $info['employees']; + } + } + } else { + $criteria['employee'] = Horde_Auth::getAuth(); + } + if (!empty($info['clients'])) { + $criteria['client'] = $info['clients']; + } + if (!empty($info['jobtypes'])) { + $criteria['jobtype'] = $info['jobtypes']; + } + if (!empty($info['costobjects'])) { + $criteria['costobject'] = $info['costobjects']; + } + if (!empty($info['start'])) { + $dt = new Date($info['start']); + $criteria['start'] = $dt->getDate(DATE_FORMAT_UNIXTIME); + } + if (!empty($info['end'])) { + $dt = new Date($info['end']); + $dt->setHour(23); + $dt->setMinute(59); + $dt->setSecond(59); + $criteria['end'] = $dt->getDate(DATE_FORMAT_UNIXTIME); + } + if (isset($info['submitted']) && $info['submitted'] != '') { + $criteria['submitted'] = $info['submitted']; + } + if (isset($info['exported']) && $info['exported'] != '') { + $criteria['exported'] = $info['exported']; + } + if (isset($info['billable']) && $info['billable'] != '') { + $criteria['billable'] = $info['billable']; + } + + return $criteria; + } + +} diff --git a/hermes/lib/Forms/Time.php b/hermes/lib/Forms/Time.php new file mode 100644 index 000000000..ae4901901 --- /dev/null +++ b/hermes/lib/Forms/Time.php @@ -0,0 +1,328 @@ + + * @package Hermes + */ +class TimeForm extends Horde_Form { + + function TimeForm(&$vars, $name = null) + { + parent::Horde_Form($vars, $name); + } + + function getJobTypeType() + { + global $hermes; + + $types = $hermes->listJobTypes(array('enabled' => true)); + if (is_a($types, 'PEAR_Error')) { + return array('invalid', array(sprintf(_("An error occurred listing job types: %s"), + $types->getMessage()))); + } elseif (count($types)) { + $values = array(); + foreach ($types as $id => $type) { + $values[$id] = $type['name']; + } + return array('enum', array($values)); + } else { + return array('invalid', array(_("There are no job types configured."))); + } + } + + function getClientType() + { + $clients = Hermes::listClients(); + if (is_a($clients, 'PEAR_Error')) { + return array('invalid', array(sprintf(_("An error occurred listing clients: %s"), + $clients->getMessage()))); + } elseif ($clients) { + if (count($clients) > 1) { + $clients = array('' => _("--- Select A Client ---")) + $clients; + } + return array('enum', array($clients)); + } else { + return array('invalid', array(_("There are no clients which you have access to."))); + } + } + + /** + */ + function getCostObjectType($clientID = null) + { + global $hermes, $registry; + + /* Check to see if any other active applications are exporting cost + * objects to which we might want to bill our time. */ + $criteria = array('user' => Horde_Auth::getAuth(), + 'active' => true); + if (!empty($clientID)) { + $criteria['client_id'] = $clientID; + } + + $costobjects = array(); + foreach ($registry->listApps() as $app) { + if (!$registry->hasMethod('listCostObjects', $app)) { + continue; + } + + $result = $registry->callByPackage($app, 'listCostObjects', + array($criteria)); + if (is_a($result, 'PEAR_Error')) { + global $notification; + $notification->push(sprintf(_("Error retrieving cost objects from \"%s\": %s"), $registry->get('name', $app), $result->getMessage()), 'horde.error'); + continue; + } + + foreach (array_keys($result) as $catkey) { + foreach (array_keys($result[$catkey]['objects']) as $okey){ + $result[$catkey]['objects'][$okey]['id'] = $app . ':' . + $result[$catkey]['objects'][$okey]['id']; + } + } + + if ($app == $registry->getApp()) { + $costobjects = array_merge($result, $costobjects); + } else { + $costobjects = array_merge($costobjects, $result); + } + } + + $elts = array('' => _("--- No Cost Object ---")); + $counter = 0; + foreach ($costobjects as $category) { + Horde_Array::arraySort($category['objects'], 'name'); + $elts['category%' . $counter++] = sprintf('--- %s ---', $category['category']); + foreach ($category['objects'] as $object) { + $name = $object['name']; + if (Horde_String::length($name) > 80) { + $name = Horde_String::substr($name, 0, 76) . ' ...'; + } + + $hours = 0.0; + $filter = array('costobject' => $object['id']); + if (!empty($GLOBALS['conf']['time']['sum_billable_only'])) { + $filter['billable'] = true; + } + $result = $hermes->getHours($filter, array('hours')); + if (!is_a($result, 'PEAR_Error')) { + foreach ($result as $entry) { + if (!empty($entry['hours'])) { + $hours += $entry['hours']; + } + } + } + + /* Show summary of hours versus estimate for this + * deliverable. */ + if (empty($object['estimate'])) { + $name .= sprintf(_(" (%0.2f hours)"), $hours); + } else { + $name .= sprintf(_(" (%d%%, %0.2f of %0.2f hours)"), + (int)($hours / $object['estimate'] * 100), + $hours, $object['estimate']); + } + + $elts[$object['id']] = $name; + } + } + + return $elts; + } + +} + +/** + * TimeEntryForm Class. + * + * $Horde: hermes/lib/Forms/Time.php,v 1.23 2009/07/08 18:29:08 slusarz Exp $ + * + * Copyright 2002-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file LICENSE for license information (BSD). If you + * did not receive this file, see http://www.horde.org/licenses/bsdl.php. + * + * @author Chuck Hagenbuch + * @package Hermes + */ +class TimeEntryForm extends TimeForm { + + /** + * Reference to the form field storing the cost objects. + * + * @var Horde_Form_Variable + */ + var $_costObjects; + + function TimeEntryForm(&$vars) + { + global $hermes, $conf; + + if ($vars->exists('id')) { + parent::TimeForm($vars, _("Update Time")); + $delete_link = Horde::link(Horde_Util::addParameter(Horde::applicationUrl('time.php'), 'delete', $vars->get('id')), _("Delete Entry")) . _("Delete"); + $this->setExtra('' . $delete_link . ''); + } else { + parent::TimeForm($vars, _("New Time")); + } + $this->setButtons(_("Save")); + + list($clienttype, $clientparams) = $this->getClientType(); + if ($clienttype == 'enum') { + require_once 'Horde/Form/Action.php'; + $action = &Horde_Form_Action::factory('submit'); + } + + list($typetype, $typeparams) = $this->getJobTypeType(); + + if ($vars->exists('id')) { + $this->addHidden('', 'id', 'int', true); + } + + if ($vars->exists('url')) { + $this->addHidden('', 'url', 'text', true); + } + + $var = &$this->addVariable(_("Date"), 'date', 'monthdayyear', true, + false, null, array(date('Y') - 1)); + $var->setDefault(date('Y-m-d')); + + $cli = &$this->addVariable(_("Client"), 'client', $clienttype, true, false, null, $clientparams); + if (isset($action)) { + $cli->setAction($action); + $cli->setOption('trackchange', true); + } + + $this->addVariable(_("Job Type"), 'type', $typetype, true, false, null, $typeparams); + + $this->_costObjects = &$this->addVariable( + _("Cost Object"), 'costobject', 'enum', false, false, null, + array(array())); + + $this->addVariable(_("Hours"), 'hours', 'number', true); + + if ($conf['time']['choose_ifbillable']) { + $yesno = array(1 => _("Yes"), 0 => _("No")); + $this->addVariable(_("Billable?"), 'billable', 'enum', true, false, null, array($yesno)); + } + + if ($vars->exists('client')) { + $info = $hermes->getClientSettings($vars->get('client')); + if (!is_a($info, 'PEAR_Error') && !$info['enterdescription']) { + $vars->set('description', _("See Attached Timesheet")); + } + } + $descvar = &$this->addVariable(_("Description"), 'description', 'longtext', true, false, null, array(4, 60)); + + $this->addVariable(_("Additional Notes"), 'note', 'longtext', false, false, null, array(4, 60)); + } + + function setCostObjects($vars) + { + $this->_costObjects->type->setValues( + $this->getCostObjectType($vars->get('client'))); + } + +} + +/** + * TimeReviewForm Class. + * + * $Horde: hermes/lib/Forms/Time.php,v 1.23 2009/07/08 18:29:08 slusarz Exp $ + * + * Copyright 2003-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file LICENSE for license information (BSD). If you + * did not receive this file, see http://www.horde.org/licenses/bsdl.php. + * + * @author Jay 'Eraserhead' Felice + * @package Hermes + */ +class TimeReviewForm extends TimeForm { + + function TimeReviewForm(&$vars) + { + global $hermes, $conf; + + parent::TimeForm($vars, _("Update Submitted Time")); + $this->setButtons(_("Update time")); + + list($clienttype, $clientparams) = $this->getClientType(); + if ($clienttype == 'enum') { + $map = array(); + $clients = Hermes::listClients(); + foreach ($clients as $id => $name) { + $info = $hermes->getClientSettings($id); + if (!is_a($info, 'PEAR_Error')) { + $map[$id] = $info['enterdescription'] ? '' : _("See Attached Timesheet"); + } else { + $map[$id] = ''; + } + } + + require_once 'Horde/Form/Action.php'; + $action = &Horde_Form_Action::factory('conditional_setvalue', + array('map' => $map, + 'target' => 'description')); + } + + list($typetype, $typeparams) = $this->getJobTypeType(); + + $this->addHidden('', 'id', 'int', true); + + $employees = array(); + + require_once 'Horde/Identity.php'; + $auth = Horde_Auth::singleton($conf['auth']['driver']); + $users = $auth->listUsers(); + if (!is_a($users, 'PEAR_Error')) { + foreach ($users as $user) { + $identity = &Identity::singleton('none', $user); + $employees[$user] = $identity->getValue('fullname'); + } + } + + $this->addVariable(_("Employee"), 'employee', 'enum', true, false, null, array($employees)); + + $var = &$this->addVariable(_("Date"), 'date', 'monthdayyear', true); + $var->setDefault(date('y-m-d')); + + + $cli = &$this->addVariable(_("Client"), 'client', $clienttype, true, false, null, $clientparams); + if (isset($action)) { + $cli->setAction($action); + } + + $this->addVariable(_("Job Type"), 'type', $typetype, true, false, null, $typeparams); + $this->addVariable(_("Hours"), 'hours', 'number', true); + + if ($conf['time']['choose_ifbillable']) { + $yesno = array(1 => _("Yes"), 0 => _("No")); + $this->addVariable(_("Billable?"), 'billable', 'enum', true, false, null, array($yesno)); + } + + $this->addVariable(_("Description"), 'description', 'longtext', true, false, null, array(4, 60)); + $this->addVariable(_("Additional Notes"), 'note', 'longtext', false, false, null, array(4, 60)); + } + +} diff --git a/hermes/lib/Hermes.php b/hermes/lib/Hermes.php new file mode 100644 index 000000000..a18439b8d --- /dev/null +++ b/hermes/lib/Hermes.php @@ -0,0 +1,238 @@ + + * @package Hermes + */ +class Hermes { + + function &getDriver() + { + global $conf; + + require_once HERMES_BASE . '/lib/Driver.php'; + return Hermes_Driver::singleton(); + } + + function listClients() + { + static $clients; + + if (is_null($clients)) { + $result = $GLOBALS['registry']->call('clients/searchClients', array(array(''))); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + $client_name_field = $GLOBALS['conf']['client']['field']; + $clients = array(); + if (!empty($result)) { + $result = $result['']; + foreach ($result as $client) { + $clients[$client['id']] = $client[$client_name_field]; + } + } + + uasort($clients, 'strcoll'); + } + + return $clients; + } + + function getDayOfWeek($timestamp) + { + // Return 0-6, indicating the position of $timestamp in the + // period. + $dow = 7 + date('w', $timestamp) - $GLOBALS['prefs']->getValue('start_of_week'); + return ($dow % 7); + } + + /** + * Build Hermes' list of menu items. + */ + function getMenu($returnType = 'object') + { + global $registry, $conf, $perms, $print_link; + + $menu = new Horde_Menu(); + $menu->add(Horde::applicationUrl('time.php'), _("My _Time"), 'hermes.png', null, null, null, basename($_SERVER['PHP_SELF']) == 'index.php' ? 'current' : null); + $menu->add(Horde::applicationUrl('entry.php'), _("_New Time"), 'hermes.png', null, null, null, Horde_Util::getFormData('id') ? '__noselection' : null); + $menu->add(Horde::applicationUrl('search.php'), _("_Search"), 'search.png', $registry->getImageDir('horde')); + + if ($conf['time']['deliverables'] && Horde_Auth::isAdmin('hermes:deliverables')) { + $menu->add(Horde::applicationUrl('deliverables.php'), _("_Deliverables"), 'hermes.png'); + } + + if ($conf['invoices']['driver'] && Horde_Auth::isAdmin('hermes:invoicing')) { + $menu->add(Horde::applicationUrl('invoicing.php'), _("_Invoicing"), 'invoices.png'); + } + + /* Print. */ + if ($conf['menu']['print'] && isset($print_link)) { + $menu->add($print_link, _("_Print"), 'print.png', $registry->getImageDir('horde'), '_blank', 'popup(this.href); return false;', '__noselection'); + } + + /* Administration. */ + if (Horde_Auth::isAdmin()) { + $menu->add(Horde::applicationUrl('admin.php'), _("_Admin"), 'hermes.png'); + } + + if ($returnType == 'object') { + return $menu; + } else { + return $menu->render(); + } + } + + function canEditTimeslice($id) + { + global $hermes; + + if ($GLOBALS['perms']->hasPermission('hermes:review', Horde_Auth::getAuth(), Horde_Perms::EDIT)) { + return true; + } + + $hours = $hermes->getHours(array('id' => $id)); + if (!is_array($hours) || count($hours) != 1) { + return false; + } + $slice = $hours[0]; + + // We can edit our own time if it hasn't been submitted. + if ($slice['employee'] == Horde_Auth::getAuth() && !$slice['submitted']) { + return true; + } + + return false; + } + + /** + * Rewrite an hours array into a format useable by Horde_Data:: + * + * @param array $hours This is an array of the results from + * $hermes->getHours(). + * @return array an array suitable for Horde_Data:: + */ + function makeExportHours($hours) + { + if (is_null($hours)) { + return null; + } + require_once 'Horde/Identity.php'; + + $clients = Hermes::listClients(); + $namecache = array(); + for ($i = 0; $i < count($hours); $i++) { + $timeentry = &$hours[$i]; + + $timeentry['item'] = $timeentry['_type_name']; + if (isset($clients[$timeentry['client']])) { + $timeentry['client'] = $clients[$timeentry['client']]; + } + + $emp = &$timeentry['employee']; + if (isset($namecache[$emp])) { + $emp = $namecache[$emp]; + } else { + $ident = &Identity::singleton('none', $emp); + $fullname = $ident->getValue('fullname'); + if ($fullname) { + $namecache[$emp] = $emp = $fullname; + } else { + $namecache[$emp] = $emp; + } + } + } + + return $hours; + } + + /** + * Get form control type for users. + * + * What type of control we use depends on whether the Auth driver has list + * capability. + * + * @param string $enumtype The type to return if we have list capability + * (should be either 'enum' or 'multienum'). + * + * @return array A two-element array of the type and the type's parameters. + */ + function getEmployeesType($enumtype = 'multienum') + { + require_once 'Horde/Identity.php'; + $auth = Horde_Auth::singleton($GLOBALS['conf']['auth']['driver']); + if (!$auth->capabilities['list']) { + return array('text', array()); + } + $users = $auth->listUsers(); + if (is_a($users, 'PEAR_Error')) { + return array('invalid', + array(sprintf(_("An error occurred listing users: %s"), + $users->getMessage()))); + } + + $employees = array(); + foreach ($users as $user) { + $identity = &Identity::singleton('none', $user); + $label = $identity->getValue('fullname'); + if (empty($label)) { + $label = $user; + } + $employees[$user] = $label; + } + + return array($enumtype, array($employees)); + } + + function getCostObjectByID($id) + { + static $cost_objects; + + if (strpos($id, ':') !== false) { + list($app, $app_id) = explode(':', $id, 2); + + if (!isset($cost_objects[$app])) { + $results = $GLOBALS['registry']->callByPackage($app, 'listCostObjects', array(array())); + if (is_a($results, 'PEAR_Error')) { + return $results; + } + $cost_objects[$app] = $results; + } + + foreach (array_keys($cost_objects[$app]) as $catkey) { + foreach (array_keys($cost_objects[$app][$catkey]['objects']) as $objkey) { + if ($cost_objects[$app][$catkey]['objects'][$objkey]['id'] == $app_id) { + return $cost_objects[$app][$catkey]['objects'][$objkey]; + } + } + } + } + + return PEAR::raiseError(_("Not found.")); + } + + function tabs() + { + /* Build search mode tabs. */ + $sUrl = Horde::selfUrl(); + $tabs = new Horde_Ui_Tabs('search_mode', Horde_Variables::getDefaultVariables()); + $tabs->addTab(_("Summary"), $sUrl, 'summary'); + $tabs->addTab(_("By Date"), $sUrl, 'date'); + $tabs->addTab(_("By Employee"), $sUrl, 'employee'); + $tabs->addTab(_("By Client"), $sUrl, 'client'); + $tabs->addTab(_("By Job Type"), $sUrl, 'jobtype'); + $tabs->addTab(_("By Cost Object"), $sUrl, 'costobject'); + if ($mode = Horde_Util::getFormData('search_mode')) { + $_SESSION['hermes_search_mode'] = $mode; + } + if (!isset($_SESSION['hermes_search_mode'])) { + $_SESSION['hermes_search_mode'] = 'summary'; + } + return $tabs->render($_SESSION['hermes_search_mode']); + } + +} diff --git a/hermes/lib/Table.php b/hermes/lib/Table.php new file mode 100644 index 000000000..5025aefb2 --- /dev/null +++ b/hermes/lib/Table.php @@ -0,0 +1,244 @@ + + * + * See the enclosed file LICENSE for license information (BSD). If you + * did not receive this file, see http://www.horde.org/licenses/bsdl.php. + * + * @package Horde_Ui + */ +class Horde_Ui_Table extends Horde_Ui_Widget { + + /** + * Data loaded from the getTableMetaData API. + * + * @access private + * @var array + */ + var $_metaData = null; + + /** + * @var array + */ + var $_formVars = array(); + + function getMetaData() + { + if (is_null($this->_metaData)) { + list($app, $name) = explode('/', $this->_config['name']); + $args = array($name, $this->_config['params']); + $this->_metaData = $GLOBALS['registry']->callByPackage( + $app, 'getTableMetaData', $args); + if (is_a($this->_metaData, 'PEAR_Error')) { + return $this->_metaData; + } + + // We need to make vars for the columns. + foreach ($this->_metaData['sections'] as $secname => $section) { + foreach ($section['columns'] as $col) { + $title = isset($col['title']) ? $col['title'] : ''; + $typename = isset($col['type']) ? $col['type'] : 'text'; + $params = isset($col['params']) ? $col['params'] : array(); + + // Column types which begin with % are pseudo-types handled + // directly. + if (substr($typename, 0, 1) != '%') { + // This type needs to be assigned by reference! + $type = &Horde_Form::getType($typename, $params); + $var = new Horde_Form_Variable($title, $col['name'], + $type, false, true, ''); + $this->_formVars[$secname][$col['name']] = $var; + } + } + } + } + + return $this->_metaData; + } + + function _getData($range = null) + { + if (is_null($range)) { + $range = array(); + foreach (array_keys($this->_metaData['sections']) as $secname) { + $range[$secname] = array( + 0, + $this->_metaData['sections'][$secname]['rows']); + } + } + + list($app, $name) = explode('/', $this->_config['name']); + $args = array($name, $this->_config['params'], $range); + return $GLOBALS['registry']->callByPackage($app, 'getTableData', $args); + } + + /** + * Count the number of columns in this table. + * + * Returns the largest column count of any section, taking into account + * 'colspan' attributes. + * + * @return mixed number of columns or PEAR_Error + */ + function getColumnCount() + { + $res = $this->getMetaData(); + if (is_a($res, 'PEAR_Error')) { + return $res; + } + $colcount = 0; + foreach ($this->_metaData['sections'] as $section) { + $sec_colcount = 0; + foreach ($section['columns'] as $col) { + if (isset($col['colspan'])) { + $sec_colcount += $col['colspan']; + } else { + $sec_colcount++; + } + } + if ($sec_colcount > $colcount) { + $colcount = $sec_colcount; + } + } + + return $colcount; + } + + /** + * Render the table. + */ + function render() + { + global $notification; + + $result = $this->getMetaData(); + if (is_a($result, 'PEAR_Error')) { + $notification->push($result, 'horde.error'); + return false; + } + + $varRenderer = new Horde_Ui_VarRenderer_Html(); + + $html = '

'; + + // Table title. + if (isset($this->_config['title'])) { + $html .= $this->_config['title']; + } else { + $html .= _("Table"); + } + + // Hook for icons and things + if (isset($this->_config['title_extra'])) { + $html .= $this->_config['title_extra']; + } + + $html .= '

'; + + /* + // + // Export icon. We store the parameters in the session so that smart + // users can't hack it (in Hermes, you could make it show other + // people's time, for example). + // + $id = $this->_config['name'] . ':' . $this->_name; + $_SESSION['horde']['tables'][$id] = $this->_config; + $exportlink = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . + '/services/table/export.php'); + $exportlink = Horde_Util::addParameter($exportlink, array('id' => $id)); + + $html .= '  ' . Horde::link($exportlink, _("Export Data")) . + Horde::img('data.png', _("Export Data"), 'hspace="2"', + $GLOBALS['registry']->getImageDir('horde')) . + ''; + */ + + // Column titles. + $html .= ''; + foreach ($this->_metaData['sections']['data']['columns'] as $col) { + $html .= '' . $col['title'] . ''; + } + $html .= ''; + + // Display data. + $data = $this->_getData(); + if (is_a($data, 'PEAR_Error')) { + $notification->push($data, 'horde.error'); + $data = array(); + } + + foreach ($this->_metaData['sections'] as $secname => $section) { + if (empty($data[$secname])) { + continue; + } + + /* Open the table section, either a tbody or the tfoot. */ + $html .= ($secname == 'footer') ? '' : ''; + + /* This Horde_Variables object is populated for each table row + * so that we can use the Horde_Ui_VarRenderer. */ + $vars = new Horde_Variables(); + $form = null; + foreach ($data[$secname] as $row) { + $html .= ''; + foreach ($row as $key => $value) { + $vars->set($key, $value); + } + foreach ($section['columns'] as $col) { + $value = null; + if (isset($row[$col['name']])) { + $value = $row[$col['name']]; + } + $align = ''; + if (isset($col['align'])) { + $align = ' align="' . htmlspecialchars($col['align']) . '"'; + } + $colspan = ''; + if (isset($col['colspan'])) { + $colspan = ' colspan="' . + htmlspecialchars($col['colspan']) . '"'; + } + $html .= " with a class. + if (!empty($row['strong'])) { + $html .= ''; + } + if (isset($col['type']) && substr($col['type'], 0, 1) == '%') { + switch ($col['type']) { + case '%html': + if (!empty($row[$col['name']])) { + $html .= $row[$col['name']]; + } + break; + } + } else { + $html .= $varRenderer->render($form, $this->_formVars[$secname][$col['name']], $vars); + } + if (!empty($row['strong'])) { + $html .= ''; + } + $html .= ''; + } + $html .= ''; + } + + /* Close the table section. */ + $html .= ($secname == 'footer') ? '' : ''; + } + + Horde::addScriptFile('stripe.js', 'horde', true); + return $html . '
'; + } + +} diff --git a/hermes/lib/api.php b/hermes/lib/api.php new file mode 100644 index 000000000..7cd8ca54b --- /dev/null +++ b/hermes/lib/api.php @@ -0,0 +1,453 @@ + array(), + 'type' => '{urn:horde}stringArray'); + +$_services['getTableMetaData'] = array( + 'args' => array('name' => 'string', 'params' => '{urn:horde}stringArray'), + 'type' => '{urn:horde}stringArray'); + +$_services['getTableData'] = array( + 'args' => array('name' => 'string', 'params' => '{urn:horde}stringArray'), + 'type' => '{urn:horde}stringArray'); + +$_services['listCostObjects'] = array( + 'args' => array('criteria' => '{urn:horde}hash'), + 'type' => '{urn:horde}array'); + +$_services['listJobTypes'] = array( + 'arga' => array('criteria' => '{urn:horde}hash'), + 'type' => '{urn:horde}array'); + +$_services['listClients'] = array( + 'arga' => array(), + 'type' => '{urn:horde}array'); + +$_services['recordTime'] = array( + 'arga' => array('date' => 'int', + 'client' => 'string', + 'jobType' => 'int', + 'costObject' => 'int', + 'hours' => 'string', // Can not use 'float' + 'billable' => 'boolean', + 'description' => 'string', + 'notes' => 'string'), + 'type' => 'boolean'); // FIXME: Is there something more useful to return? + +function _hermes_perms() +{ + $perms = array(); + $perms['tree']['hermes']['review'] = array(); + $perms['title']['hermes:review'] = _("Time Review Screen"); + $perms['tree']['hermes']['deliverables'] = array(); + $perms['title']['hermes:deliverables'] = _("Deliverables"); + $perms['tree']['hermes']['invoicing'] = array(); + $perms['title']['hermes:invoicing'] = _("Invoicing"); + + return $perms; +} + +function _hermes_getTableMetaData($name, $params) +{ + require_once dirname(__FILE__) . '/base.php'; + + switch ($name) { + case 'hours': + $emptype = Hermes::getEmployeesType('enum'); + $clients = Hermes::listClients(); + $hours = $GLOBALS['hermes']->getHours($params); + $yesno = array(1 => _("Yes"), + 0 => _("No")); + + $columns = array( + array('name' => 'icons', + 'title' => '', + 'type' => '%html', + 'nobr' => true), + array('name' => 'checkbox', + 'title' => '', + 'type' => '%html', + 'nobr' => true), + array('name' => 'date', + 'title' => _("Date"), + 'type' => 'date', + 'params' => array($GLOBALS['prefs']->getValue('date_format')), + 'nobr' => true), + array('name' => 'employee', + 'title' => _("Employee"), + 'type' => $emptype[0], + 'params' => $emptype[1]), + array('name' => 'client', + 'title' => _("Client"), + 'type' => 'enum', + 'params' => array($clients)), + array('name' => '_type_name', + 'title' => _("Job Type")), + array('name' => '_costobject_name', + 'title' => _("Cost Object")), + array('name' => 'hours', + 'title' => _("Hours"), + 'type' => 'number', + 'align' => 'right')); + if ($GLOBALS['conf']['time']['choose_ifbillable']) { + $columns[] = + array('name' => 'billable', + 'title' => _("Bill?"), + 'type' => 'enum', + 'params' => array($yesno)); + } + $columns = array_merge($columns, array( + array('name' => 'description', + 'title' => _("Description")), + array('name' => 'note', + 'title' => _("Notes")))); + + $colspan = 6; + if ($GLOBALS['conf']['time']['choose_ifbillable']) { + $colspan++; + } + $fColumns = array( + array('name' => 'approval', + 'colspan' => $colspan, + 'type' => '%html', + 'align' => 'right'), + array('name' => 'hours', + 'type' => 'number', + 'align' => 'right')); + if ($GLOBALS['conf']['time']['choose_ifbillable']) { + $fColumns[] = + array('name' => 'billable', + 'type' => 'enum', + 'params' => array($yesno)); + } + $fColumns = array_merge($fColumns, array( + array('name' => 'description'), + array('name' => 'blank2'))); + + return array('title' => _("Search Results"), + 'sections' => array( + 'data' => array( + 'rows' => count($hours), + 'columns' => $columns), + 'footer' => array( + 'rows' => 3, + 'strong' => true, + 'columns' => $fColumns))); + + default: + return PEAR::raiseError(sprintf(_("\"%s\" is not a defined table."), + $name)); + } +} + +function _hermes_getTableData($name, $params) +{ + require_once dirname(__FILE__) . '/base.php'; + + switch ($name) { + case 'hours': + $time_data = $GLOBALS['hermes']->getHours($params); + if (is_a($time_data, 'PEAR_Error')) { + return $time_data; + } + + $subtotal_column = null; + if (isset($_SESSION['hermes_search_mode'])) { + switch ($_SESSION['hermes_search_mode']) { + case 'date': + $subtotal_column = 'date'; + break; + + case 'employee': + $subtotal_column = 'employee'; + break; + + case 'client': + $subtotal_column = '_client_name'; + break; + + case 'jobtype': + $subtotal_column = '_type_name'; + break; + + case 'costobject': + $subtotal_column = '_costobject_name'; + break; + } + + if (!empty($subtotal_column)) { + $clients = Hermes::listClients(); + $column = array(); + foreach ($time_data as $key => $row) { + if (empty($row['client'])) { + $time_data[$key]['_client_name'] = _("no client"); + } elseif (isset($clients[$row['client']])) { + $time_data[$key]['_client_name'] = $clients[$row['client']]; + } else { + $time_data[$key]['_client_name'] = $row['client']; + } + $column[$key] = $time_data[$key][$subtotal_column]; + } + array_multisort($column, SORT_ASC, $time_data); + } + } + + $total_hours = 0.0; + $total_billable_hours = 0.0; + $subtotal_hours = 0.0; + $subtotal_billable_hours = 0.0; + $subtotal_control = null; + + $result['data'] = array(); + foreach ($time_data as $k => $vals) { + // Initialize subtotal break value. + if (is_null($subtotal_control) && isset($vals[$subtotal_column])) { + $subtotal_control = $vals[$subtotal_column]; + } + + if (!empty($subtotal_column) && + $vals[$subtotal_column] != $subtotal_control) { + renderSubtotals($result['data'], $subtotal_hours, $subtotal_billable_hours, + $subtotal_column == 'date' ? strftime("%m/%d/%Y", $subtotal_control) : + $subtotal_control); + $subtotal_hours = 0.0; + $subtotal_billable_hours = 0.0; + $subtotal_control = $vals[$subtotal_column]; + } + + // Set up edit/delete icons. + if (Hermes::canEditTimeslice($vals['id'])) { + $edit_link = Horde::applicationUrl('entry.php', true); + $edit_link = Horde_Util::addParameter($edit_link, 'id', $vals['id']); + $edit_link = Horde_Util::addParameter($edit_link, 'url', Horde::selfUrl(true, true, true)); + + $vals['icons'] = + Horde::link($edit_link, _("Edit Entry")) . + Horde::img('edit.png', _("Edit Entry"), '', $GLOBALS['registry']->getImageDir('horde')) . ''; + + if (empty($vals['submitted'])) { + $vals['checkbox'] = + ''; + } else { + $vals['checkbox'] = ''; + } + } + + // Add to totals. + $subtotal_hours += (double)$vals['hours']; + $total_hours += (double)$vals['hours']; + if ($vals['billable']) { + $subtotal_billable_hours += (double)$vals['hours']; + $total_billable_hours += (double)$vals['hours']; + } + + // Localize hours. + $vals['hours'] = sprintf('%.02f', $vals['hours']); + + $result['data'][] = $vals; + } + + if (!empty($subtotal_column)) { + renderSubtotals($result['data'], $subtotal_hours, $subtotal_billable_hours, + $subtotal_column == 'date' ? strftime("%m/%d/%Y", $subtotal_control) : + $subtotal_control); + } + + // Avoid a divide by zero. + if ($total_hours == 0.0) { + $billable_pct = 0.0; + } else { + $billable_pct = round($total_billable_hours / $total_hours * 100.0); + } + + $descr = _("Billable Hours") . ' (' . $billable_pct . '%)'; + $result['footer'] = array(); + $result['footer'][] = array( + 'hours' => sprintf('%.02f', $total_billable_hours), + 'description' => $descr); + + $descr = _("Non-billable Hours") . ' (' . (100.0 - $billable_pct) . '%)'; + $result['footer'][] = array( + 'hours' => sprintf('%.02f', $total_hours - $total_billable_hours), + 'description' => $descr); + $result['footer'][] = array( + 'hours' => sprintf('%.02f', $total_hours), + 'description' => _("Total Hours"), + 'approval' => '
' . _("Approved By:") . + ' ________________________________________ ' . + ' 
'); + break; + } + + return $result; +} + +function renderSubtotals(&$table_data, $hours, $billable_hours, $value) +{ + $billable_pct = ($hours == 0.0) ? 0.0 : + round($billable_hours / $hours * 100.0); + $descr = _("Billable Hours") . ' (' . $billable_pct . '%)'; + $table_data[] = array( + 'date' => '', + 'employee' => '', + 'client' => '', + 'billable' => '', + 'note' => '', + '_type_name' => '', + '_costobject_name' => '', + 'hours' => sprintf('%.02f', $billable_hours), + 'description' => $descr); + $descr = _("Non-billable Hours") . ' (' . (100.0 - $billable_pct) . '%)'; + $table_data[] = array( + 'hours' => sprintf('%.02f', $hours - $billable_hours), + 'description' => $descr); + $table_data[] = array( + 'hours' => sprintf('%.02f', $hours), + 'description' => sprintf(_("Total Hours for %s"), $value), + ); + + return; +} + +function _hermes_listCostObjects($criteria) +{ + require_once dirname(__FILE__) . '/base.php'; + + if (!$GLOBALS['conf']['time']['deliverables']) { + return array(); + } + + $deliverables = $GLOBALS['hermes']->listDeliverables($criteria); + if (is_a($deliverables, 'PEAR_Error')) { + return PEAR::raiseError(sprintf(_("An error occurred retrieving deliverables: %s"), $deliverables->getMessage())); + } + + if (empty($criteria['id'])) { + /* Build heirarchical tree. */ + $levels = array(); + $hash = array(); + foreach ($deliverables as $deliverable) { + if (empty($deliverable['parent'])) { + $parent = -1; + } else { + $parent = $deliverable['parent']; + } + $levels[$parent][$deliverable['id']] = $deliverable['name']; + $hash[$deliverable['id']] = $deliverable; + } + + /* Sort levels alphabetically, keeping keys intact. */ + foreach ($levels as $key => $level) { + asort($levels[$key]); + } + + /* Traverse the tree and glue them back together. Lots of magic + * involved, so don't try to understand. */ + $elts = array(); + $stack = empty($levels[-1]) ? array() : array(-1); + while (count($stack)) { + if (!(list($key, $val) = each($levels[$stack[count($stack) - 1]]))) { + array_pop($stack); + continue; + } + $elts[$key] = str_repeat(' + ', count($stack)-1) . $val; + if (!empty($levels[$key])) { + $stack[] = $key; + } + } + + $results = array(); + foreach ($elts as $key => $value) { + $results[] = array('id' => $key, + 'active' => $hash[$key]['active'], + 'estimate' => $hash[$key]['estimate'], + 'name' => $value); + } + } else { + $results = $deliverables; + } + + if (!$results) { + return array(); + } + + return array(array('category' => _("Deliverables"), + 'objects' => $results)); +} + +/** + * Retrieve list of job types. + * + * @abstract + * + * @param array $criteria Hash of filter criteria: + * + * 'enabled' => If present, only retrieve enabled + * or disabled job types. + * + * @return mixed Associative array of job types, or PEAR_Error on failure. + */ +function _hermes_listJobTypes($criteria = array()) +{ + require_once dirname(__FILE__) . '/base.php'; + return $GLOBALS['hermes']->listJobTypes($criteria); +} + +function _hermes_listClients() +{ + require_once dirname(__FILE__) . '/base.php'; + return Hermes::listClients(); +} + +function _hermes_recordTime($date, $client, $jobType, + $costObject, $hours, $billable = true, + $description = '', $notes = '') +{ + require_once dirname(__FILE__) . '/base.php'; + require_once 'Date.php'; + require_once HERMES_BASE . '/lib/Forms/Time.php'; + + $dateobj = new Horde_Date($date); + $date['year'] = $dateobj->year; + $date['month'] = $dateobj->month; + $date['day'] = $dateobj->mday; + + $vars = Horde_Variables::getDefaultVariables(); + $vars->set('date', $date); + $vars->set('client', $client); + $vars->set('jobType', $jobType); + $vars->set('costObject', $costObject); + $vars->set('hours', $hours); + $vars->set('billable', $billable); + $vars->set('description', $description); + $vars->set('notes', $notes); + + // Validate and submit the data + $form = new TimeEntryForm($vars); + $form->setSubmitted(); + $form->useToken(false); + if ($form->validate($vars)) { + $form->getInfo($vars, $info); + $result = $GLOBALS['hermes']->enterTime(Horde_Auth::getAuth(), $info); + if (is_a($result, 'PEAR_Error')) { + return $result; + } else { + return true; + } + } else { + return PEAR::raiseError(_("Invalid entry: check data and retry.")); + } +} diff --git a/hermes/lib/base.php b/hermes/lib/base.php new file mode 100644 index 000000000..013a4585b --- /dev/null +++ b/hermes/lib/base.php @@ -0,0 +1,58 @@ + + * + * See the enclosed file LICENSE for license information (BSD). If you + * did not receive this file, see http://www.horde.org/licenses/bsdl.php. + * + * Hermes base inclusion file. + * + * This file brings in all of the dependencies that every Hermes script + * will need, and sets up objects that all scripts use. + */ + +// Check for a prior definition of HORDE_BASE (perhaps by an +// auto_prepend_file definition for site customization). +if (!defined('HORDE_BASE')) { + define('HORDE_BASE', dirname(__FILE__) . '/../..'); +} + +// Load the Horde Framework core, and set up inclusion paths. +require_once HORDE_BASE . '/lib/core.php'; + +// Registry. +$registry = Horde_Registry::singleton(); +try { + $registry->pushApp('hermes', !defined('AUTH_HANDLER')); +} catch (Horde_Exception $e) { + if ($e->getCode() == 'permission_denied') { + Horde::authenticationFailureRedirect(); + } + Horde::fatal($e, __FILE__, __LINE__, false); +} +$conf = &$GLOBALS['conf']; +define('HERMES_TEMPLATES', $registry->get('templates')); +$print_link = null; + +// Notification system. +$notification = &Horde_Notification::singleton(); +$notification->attach('status'); + +// Find the base file path of Hermes. +if (!defined('HERMES_BASE')) { + define('HERMES_BASE', dirname(__FILE__) . '/..'); +} + +// Hermes base libraries. +require_once HERMES_BASE . '/lib/Hermes.php'; +$GLOBALS['hermes'] = &Hermes::getDriver(); + +// Horde libraries. +require_once 'Horde/Form.php'; +require_once 'Horde/Form/Renderer.php'; +require_once 'Horde/Template.php'; + +// Start compression. +Horde::compressOutput(); diff --git a/hermes/lib/version.php b/hermes/lib/version.php new file mode 100644 index 000000000..0bd0620a8 --- /dev/null +++ b/hermes/lib/version.php @@ -0,0 +1 @@ + diff --git a/hermes/locale/de_DE/LC_MESSAGES/hermes.mo b/hermes/locale/de_DE/LC_MESSAGES/hermes.mo new file mode 100644 index 0000000000000000000000000000000000000000..623bc3264ee8f15744c10f96a83dc9ab76a84d2c GIT binary patch literal 168151 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 + + + + Hermes Job Types + A job type in Hermes characterizes what kind of work has been done + in a time slice. The administrator has set a number of job types to choose + from. + + + Hermes Cost Objects + Hermes draws possible cost objects from a variety of sources, for + example deliverable defined by the administator in Hermes, tasks from a + todo list manager, or tickets from a ticket-tracking system. + + + Hermes Time Format + Hermes does not format its times as hours and minutes, rather the + time slices are formatted as decimal portions of an hour. + + + Submitting Time Slices + Submitting time slices "marks" them as finshed. This is + also a sign for the administrator or bookkeeping department that they are + ready to be further processed. As long as you didn't submit your slices, + they are still considered due to be changed, but after submitting them you + can no longer change them. + Submitting Certain Time Slices + While this cannot be easily achieved from the default time slice + view, which shows all time slices for all clients, and the tabs simply + group the time slices differently, this can be accomplished by using the + search facility. Set the "Submitted?" field to "No" + and select any other criteria from the various from fields, then click + "Search". + On submission of the search form in that way, you are presented with + a view just like the initial time slice view, but containing just the + slices with the picked criteria, with all checkboxes already checked, so + you can just click "Submit Selected Time" to do so. + + diff --git a/hermes/locale/es_ES/LC_MESSAGES/hermes.mo b/hermes/locale/es_ES/LC_MESSAGES/hermes.mo new file mode 100644 index 0000000000000000000000000000000000000000..f5c7706bd5f0a5c4e63ff28203025428de12bd8e GIT binary patch literal 160609 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%0DA7eeB~XZY4%hKILP) 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 literal 0 HcmV?d00001 diff --git a/hermes/locale/es_ES/help.xml b/hermes/locale/es_ES/help.xml new file mode 100644 index 000000000..0202ccb88 --- /dev/null +++ b/hermes/locale/es_ES/help.xml @@ -0,0 +1,47 @@ + + + + + Tipos de objetos de trabajo/facturables de Hermes + Tipos de objetos de trabajo/facturables de Hermes + Hermes introduce el concepto de tareas a las que pertenece un periodo de tiempo, así como los periodos de tiempo correspondientes a un cliente, aunque la terminología utilizada es para una 'objeto de gastos', pero creo que ésto puede resultar algo confuso y por ello esta entrada. + Hermes (así parece) presenta posibles objetos de gastos desde múltiples orígenes, uno de los cuales son las notas de Mnemo, por lo que si quiere tener una tarea a la que asignar periodos de tiempo, una forma fácil de hacerlo sería crear una nota en Mnemo y asignar los periodos al objeto de gasto representado por la nota. + Alguien pronto podría desear añadir información sobre otros orígenes de objetos de gastos. Creo que las incidencias de Whups también se pueden usar como objetos de gastos, pero no estoy seguro. + + + Hermes Cost Objects + Hermes draws possible cost objects from a variety of sources, for + example deliverable defined by the administator in Hermes, tasks from a + todo list manager, or tickets from a ticket-tracking system. + + + Hermes Time Format + Hermes does not format its times as hours and minutes, rather the + time slices are formatted as decimal portions of an hour. + + + Submitting Time Slices + Submitting time slices "marks" them as finshed. This is + also a sign for the administrator or bookkeeping department that they are + ready to be further processed. As long as you didn't submit your slices, + they are still considered due to be changed, but after submitting them you + can no longer change them. + Submitting Certain Time Slices + While this cannot be easily achieved from the default time slice + view, which shows all time slices for all clients, and the tabs simply + group the time slices differently, this can be accomplished by using the + search facility. Set the "Submitted?" field to "No" + and select any other criteria from the various from fields, then click + "Search". + On submission of the search form in that way, you are presented with + a view just like the initial time slice view, but containing just the + slices with the picked criteria, with all checkboxes already checked, so + you can just click "Submit Selected Time" to do so. + + diff --git a/hermes/locale/fi_FI/LC_MESSAGES/hermes.mo b/hermes/locale/fi_FI/LC_MESSAGES/hermes.mo new file mode 100644 index 0000000000000000000000000000000000000000..b20c968c710b4d64272f49876d40f8cbe494faac GIT binary patch literal 152171 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 literal 0 HcmV?d00001 diff --git a/hermes/locale/zh_TW/LC_MESSAGES/hermes.mo b/hermes/locale/zh_TW/LC_MESSAGES/hermes.mo new file mode 100644 index 0000000000000000000000000000000000000000..986e6b8eb05d991b398cb779458e04d264655d1f GIT binary patch literal 132806 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 j, 2002-2008. +# +# deliverables: Ergebnisse +# time: Zeiteintrag +# timeslice: Zeitabschnitt +msgid "" +msgstr "" +"Project-Id-Version: Hermes 1.0-cvs\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2008-08-01 10:45+0200\n" +"PO-Revision-Date: 2008-07-02 11:38+0200\n" +"Last-Translator: Jan Schneider \n" +"Language-Team: German \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: lib/Forms/Time.php:139 +#, php-format +msgid " (%0.2f hours)" +msgstr " (%0.2f Stunden)" + +#: lib/Forms/Time.php:141 +#, php-format +msgid " (%d%%, %0.2f of %0.2f hours)" +msgstr " (%d%%, %0.2f von %0.2f Stunden)" + +#: lib/Admin.php:54 lib/Forms/Search.php:102 +msgid " (DISABLED)" +msgstr " (DEAKTIVIERT)" + +#: lib/api.php:149 +#, php-format +msgid "\"%s\" is not a defined table." +msgstr "\"%s\" ist nicht als Tabelle definiert." + +#: templates/deliverables/list.inc:4 +#, php-format +msgid "%s Deliverables" +msgstr "Ergebnisse für %s" + +#: lib/Forms/Search.php:84 +msgid "- - None - -" +msgstr "- - Keiner - -" + +#: lib/Forms/Time.php:111 +msgid "--- No Cost Object ---" +msgstr "--- Keine Kostenstelle ---" + +#: lib/Forms/Time.php:61 +msgid "--- Select A Client ---" +msgstr "--- Kunden auswählen ---" + +#: lib/Data/iif.php:64 +msgid "; Notes: " +msgstr "; Bemerkungen: " + +#: entry.php:74 lib/Driver/sql.php:142 +msgid "Access denied; user cannot modify this timeslice." +msgstr "" +"Zugriff verweigert; Benutzer kann diesen Zeitabschnitt nicht bearbeiten." + +#: lib/Forms/Deliverable.php:59 +msgid "Active?" +msgstr "Aktiv?" + +#: admin.php:59 admin.php:221 +msgid "Add Job Type" +msgstr "Arbeitsart hinzufügen" + +#: config/prefs.php.dist:21 +msgid "" +"Add stop watch name and start and end time to the description of the time " +"entry?" +msgstr "" +"Stoppuhr-Bezeichnung und Start- und Endezeit in die Beschreibung des " +"Zeiteintrags übernehmen?" + +#: lib/Forms/Time.php:237 lib/Forms/Time.php:325 +msgid "Additional Notes" +msgstr "Zusätzliche Bemerkungen" + +#: admin.php:35 +msgid "Administration" +msgstr "Administration" + +#: lib/Forms/Time.php:57 lib/Forms/Search.php:81 lib/Forms/Deliverable.php:37 +#, php-format +msgid "An error occurred listing clients: %s" +msgstr "Beim Anzeigen der Kunden ist ein Fehler aufgetreten: %s" + +#: lib/Forms/Time.php:40 lib/Forms/Search.php:95 +#, php-format +msgid "An error occurred listing job types: %s" +msgstr "Beim Anzeigen der Arbeitsart ist ein Fehler aufgetreten: %s" + +#: lib/Hermes.php:176 +#, php-format +msgid "An error occurred listing users: %s" +msgstr "Beim Anzeigen der Benutzer ist ein Fehler aufgetreten: %s" + +#: lib/api.php:335 +#, php-format +msgid "An error occurred retrieving deliverables: %s" +msgstr "Beim Lesen der Ergebnisse ist ein Fehler aufgetreten: %s" + +#: lib/api.php:289 +msgid "Approved By:" +msgstr "Bestätigt durch:" + +#: lib/api.php:106 +msgid "Bill?" +msgstr "Rechnung?" + +#: lib/api.php:276 lib/api.php:302 +msgid "Billable Hours" +msgstr "In Rechnung zu stellende Stunden" + +#: lib/Admin.php:30 lib/Admin.php:102 lib/Forms/Time.php:226 +#: lib/Forms/Time.php:321 lib/Forms/Search.php:71 +msgid "Billable?" +msgstr "Rechnung?" + +#: lib/Hermes.php:230 +msgid "By Client" +msgstr "Nach Kunde" + +#: lib/Hermes.php:232 +msgid "By Cost Object" +msgstr "Nach Kostenstelle" + +#: lib/Hermes.php:228 +msgid "By Date" +msgstr "Nach Datum" + +#: lib/Hermes.php:229 +msgid "By Employee" +msgstr "Nach Mitarbeiter" + +#: lib/Hermes.php:231 +msgid "By Job Type" +msgstr "Nach Arbeitsart" + +#: lib/Driver/sql.php:581 +msgid "Cannot delete deliverable; it has children." +msgstr "Ergebnis kann nicht gelöscht werden; es existieren Unterergebnisse." + +#: lib/Driver/sql.php:596 +msgid "Cannot delete deliverable; there is time entered on it." +msgstr "Ergebnis kann nicht gelöscht werden; es existieren Zeiteinträge dafür." + +#: invoicing.php:38 lib/Admin.php:187 lib/api.php:92 lib/Forms/Time.php:210 +#: lib/Forms/Time.php:311 lib/Forms/Deliverable.php:28 +msgid "Client" +msgstr "Kunde" + +#: lib/Admin.php:160 +msgid "Client Name" +msgstr "Kundenname" + +#: lib/Forms/Search.php:42 +msgid "Clients" +msgstr "Kunden" + +#: invoicing.php:75 +msgid "Combine same clients in one invoice" +msgstr "Denselben Kunden in einer Rechnung zusammenfassen" + +#: lib/Forms/Export.php:37 +msgid "Comma-Separated Variable (.csv)" +msgstr "Kommagetrennte Werte (.csv)" + +#: invoicing.php:46 lib/api.php:98 lib/Forms/Time.php:219 +msgid "Cost Object" +msgstr "Kostenstelle" + +#: lib/Forms/Search.php:51 +msgid "Cost Objects" +msgstr "Kostenstellen" + +#: invoicing.php:70 +msgid "Create invoice" +msgstr "Rechnung erstellen" + +#: invoicing.php:44 lib/api.php:83 lib/Forms/Time.php:206 +#: lib/Forms/Time.php:307 +msgid "Date" +msgstr "Datum" + +#: lib/Forms/Time.php:183 +msgid "Delete" +msgstr "Löschen" + +#: lib/Forms/Time.php:183 +msgid "Delete Entry" +msgstr "Eintrag löschen" + +#: admin.php:88 admin.php:220 +msgid "Delete Job Type" +msgstr "Arbeitsart löschen" + +#: admin.php:93 admin.php:208 +msgid "Delete Job Type: Confirmation" +msgstr "Arbeitsart löschen: Bestätigung" + +#: deliverables.php:107 +msgid "Delete This Deliverable" +msgstr "Dieses Ergebnis löschen" + +#: scripts/purge.php:26 +#, php-format +msgid "Deleting data that was exported/billed more than %s days ago.\n" +msgstr "" +"Lösche Daten, die vor mehr als %s Tagen exportiert/in Rechnung gestellt " +"wurden.\n" + +#: lib/Driver.php:85 +#, php-format +msgid "Deliverable %d not found." +msgstr "Ergebnis %d nicht gefunden." + +#: lib/Forms/Deliverable.php:52 +msgid "Deliverable Detail" +msgstr "Ergebnisdetail" + +#: deliverables.php:42 +msgid "Deliverable saved successfully." +msgstr "Ergebnis erfolgreich gespeichert." + +#: deliverables.php:55 +msgid "Deliverable successfully deleted." +msgstr "Ergebnis erfolgreich gelöscht." + +#: deliverables.php:61 lib/api.php:54 lib/api.php:387 +msgid "Deliverables" +msgstr "Ergebnisse" + +#: invoicing.php:45 lib/api.php:112 lib/Forms/Time.php:235 +#: lib/Forms/Time.php:324 lib/Forms/Deliverable.php:61 +msgid "Description" +msgstr "Beschreibung" + +#: lib/Forms/Deliverable.php:58 +msgid "Display Name" +msgstr "Anzeigename" + +#: lib/Forms/Search.php:58 +msgid "Do not include entries after" +msgstr "Keine Einträge einbeziehen nach" + +#: lib/Forms/Search.php:55 +msgid "Do not include entries before" +msgstr "Keine Einträge einbeziehen vor" + +#: deliverables.php:103 +#, php-format +msgid "Edit %s" +msgstr "%s Bearbeiten" + +#: admin.php:130 admin.php:222 +msgid "Edit Client Settings" +msgstr "Kundeneinstellungen bearbeiten" + +#: admin.php:122 admin.php:181 +msgid "Edit Client Settings, Step 2" +msgstr "Kundeneinstellungen bearbeiten, Schritt 2" + +#: lib/Forms/Deliverable.php:30 +msgid "Edit Deliverables" +msgstr "Ergebnisse bearbeiten" + +#: lib/api.php:236 lib/api.php:237 +msgid "Edit Entry" +msgstr "Eintrag bearbeiten" + +#: admin.php:75 admin.php:220 +msgid "Edit Job Type" +msgstr "Arbeitsart bearbeiten" + +#: admin.php:80 +msgid "Edit Job Type, Step 2" +msgstr "Arbeitsart bearbeiten, Schritt 2" + +#: entry.php:94 +msgid "Edit Time" +msgstr "Zeiteintrag bearbeiten" + +#: admin.php:103 +msgid "Edit job type" +msgstr "Arbeitsart bearbeiten" + +#: admin.php:156 +msgid "Edit job type, Step 2" +msgstr "Arbeitsart bearbeiten, Schritt 2" + +#: invoicing.php:39 lib/api.php:88 lib/Forms/Time.php:305 +msgid "Employee" +msgstr "Mitarbeiter" + +#: lib/Forms/Search.php:36 +msgid "Employees" +msgstr "Mitarbeiter" + +#: lib/Admin.php:28 lib/Admin.php:100 +msgid "Enabled?" +msgstr "Aktiviert?" + +#: lib/Block/tree_menu.php:3 lib/Block/tree_menu.php:21 +msgid "Enter Time" +msgstr "Zeit eintragen" + +#: deliverables.php:52 +#, php-format +msgid "Error deleting deliverable: %s" +msgstr "Fehler beim Löschen des Ergebnisses: %s" + +#: lib/Forms/Time.php:93 lib/Forms/Search.php:130 +#, php-format +msgid "Error retrieving cost objects from \"%s\": %s" +msgstr "Fehler beim Lesen der Kostenstellen aus \"%s\": %s" + +#: deliverables.php:38 +#, php-format +msgid "Error saving deliverable: %s" +msgstr "Fehler beim Speichern des Ergebnisses: %s" + +#: lib/Driver/sql.php:298 +#, php-format +msgid "Error: %s" +msgstr "Fehler: %s" + +#: lib/Forms/Deliverable.php:60 +msgid "Estimated Hours" +msgstr "Geschätzte Stunden" + +#: lib/Forms/Export.php:56 +msgid "Export" +msgstr "Exportieren" + +#: lib/Forms/Export.php:35 +msgid "Export Search Results" +msgstr "Suchergebnisse exportieren" + +#: lib/Forms/Search.php:68 +msgid "Exported?" +msgstr "Exportiert?" + +#: config/prefs.php.dist:9 +msgid "General Options" +msgstr "Allgemeine Einstellungen" + +#: lib/Admin.php:32 lib/Admin.php:104 +msgid "Hourly Rate" +msgstr "Stundensatz" + +#: invoicing.php:42 lib/api.php:100 lib/Forms/Time.php:222 +#: lib/Forms/Time.php:317 +msgid "Hours" +msgstr "Stunden" + +#: lib/Admin.php:195 +msgid "" +"ID for this client when exporting data, if different from the name displayed " +"above." +msgstr "" +"Kunden-ID für das Exportieren, falls sie sich von dem oben angezeigten Namen " +"unterscheidet." + +#: lib/api.php:452 +msgid "Invalid entry: check data and retry." +msgstr "" +"Ungültiger Eintrag: Überprüfen Sie die Daten und versuchen Sie es noch " +"einmal." + +#: invoicing.php:122 +#, php-format +msgid "Invoice for client %s successfuly created." +msgstr "Die Rechnung für Kunde %s wurde erfolgreich erstellt." + +#: lib/api.php:56 +msgid "Invoicing" +msgstr "Rechnungswesen" + +#: invoicing.php:32 +msgid "Invoicing system is not installed." +msgstr "Rechnungssystem ist nicht installiert." + +#: invoicing.php:40 lib/Admin.php:27 lib/Admin.php:95 lib/Admin.php:129 +#: lib/api.php:96 lib/Forms/Time.php:216 lib/Forms/Time.php:316 +msgid "Job Type" +msgstr "Arbeitsart" + +#: lib/Forms/Search.php:48 +msgid "Job Types" +msgstr "Arbeitsarten" + +#: lib/Admin.php:67 +msgid "JobType Name" +msgstr "Arbeitsart-Bezeichnung" + +#: lib/Forms/Export.php:50 +msgid "Mark the time as exported?" +msgstr "Diese Zeitspanne als exportiert markieren?" + +#: lib/Forms/Export.php:38 +msgid "Microsoft Excel (.xls)" +msgstr "Microsoft Excel (.xls)" + +#: time.php:72 +msgid "My Time" +msgstr "Meine Zeit" + +#: time.php:62 +msgid "My Unsubmitted Time" +msgstr "Meine nicht abgeschickten Zeiteinträge" + +#: lib/Hermes.php:63 +msgid "My _Time" +msgstr "_Meine Zeit" + +#: deliverables.php:105 +msgid "New Sub-deliverable" +msgstr "Neues Unterergebnis" + +#: entry.php:94 lib/Forms/Time.php:186 +msgid "New Time" +msgstr "Neuer Zeiteintrag" + +#: templates/deliverables/list.inc:10 +msgid "New Top-level Deliverable" +msgstr "Neues Hauptergebnis" + +#: invoicing.php:74 lib/Admin.php:125 lib/api.php:71 lib/Forms/Time.php:225 +#: lib/Forms/Time.php:320 lib/Forms/Search.php:64 lib/Forms/Export.php:49 +msgid "No" +msgstr "Nein" + +#: lib/Driver.php:28 +#, php-format +msgid "No job type with ID \"%s\"." +msgstr "Keine Arbeitsart mit der ID \"%s\"." + +#: search.php:54 search.php:60 +msgid "No search to export!" +msgstr "Keine Suche zu exportieren!" + +#: search.php:70 +msgid "No time to export!" +msgstr "Keine Zeiteinträge zu exportieren!" + +#: time.php:38 +msgid "No timeslices were selected to submit." +msgstr "Es wurden keine Zeitabschnitte ausgewählt." + +#: lib/api.php:282 lib/api.php:313 +msgid "Non-billable Hours" +msgstr "Nicht in Rechnung zu stellende Stunden" + +#: lib/Hermes.php:217 +msgid "Not found." +msgstr "Nicht gefunden." + +#: lib/Driver.php:49 lib/Driver.php:66 lib/Driver.php:115 lib/Driver.php:133 +#: lib/Driver.php:146 +msgid "Not implemented." +msgstr "Nicht implementiert." + +#: lib/api.php:114 +msgid "Notes" +msgstr "Bemerkungen" + +#: lib/Forms/Export.php:39 +msgid "QuickBooks (.iif)" +msgstr "QuickBooks (.iif)" + +#: invoicing.php:41 +msgid "Rate" +msgstr "Rate" + +#: lib/Admin.php:132 +msgid "Really delete this job type? This may cause data problems!!" +msgstr "" +"Diese Arbeitsart wirklich löschen? Das kann zu Problemen mit den Daten " +"führen!" + +#: lib/Forms/Time.php:188 +msgid "Save" +msgstr "Speichern" + +#: lib/Forms/Search.php:74 +msgid "Search" +msgstr "Suche" + +#: lib/Forms/Search.php:32 +msgid "Search For Time" +msgstr "Nach Zeit suchen" + +#: search.php:123 lib/api.php:138 +msgid "Search Results" +msgstr "Suchergebnisse" + +#: lib/Block/tree_menu.php:29 +msgid "Search Time" +msgstr "Zeit suchen" + +#: search.php:92 +msgid "Search for Time" +msgstr "Nach Zeit suchen" + +#: lib/Admin.php:190 lib/Forms/Time.php:232 lib/Forms/Time.php:277 +msgid "See Attached Timesheet" +msgstr "Siehe angehängte Zeitübersicht" + +#: lib/Forms/Deliverable.php:22 +msgid "Select Client" +msgstr "Kunde auswählen" + +#: invoicing.php:76 +msgid "Select hours to be invoiced" +msgstr "" +"Wählen Sie die Zeiteinträge aus, die in Rechnung gestellt werden sollen" + +#: lib/Forms/Export.php:43 +msgid "Select the export format" +msgstr "Wählen Sie das Exportformat" + +#: config/prefs.php.dist:11 +msgid "Set preferences on the stop watch timer." +msgstr "Legen Sie Ihre Einstellungen für die Stoppuhr fest." + +#: lib/Admin.php:190 +#, php-format +msgid "" +"Should users enter descriptions of their timeslices for this client? If not, " +"the description will automatically be \"%s\"." +msgstr "" +"Müssen die Benutzer Kommentare für Zeitabschnitte bei diesem Kunden angeben? " +"Wenn nicht, wird automatisch der Kommentar \"%s\" eingefügt." + +#: lib/Block/tree_stopwatch.php:28 +msgid "Start Watch" +msgstr "Stoppuhr starten" + +#: start.php:20 start.php:44 lib/Block/tree_stopwatch.php:3 +msgid "Stop Watch" +msgstr "Stoppuhr" + +#: start.php:21 +msgid "Stop watch description" +msgstr "Bezeichnung für Stoppuhr" + +#: templates/time/form.html:5 +msgid "Submit Selected Time" +msgstr "Ausgewählte Zeiteinträge abschicken" + +#: lib/Forms/Search.php:65 +msgid "Submitted?" +msgstr "Abgeschickt?" + +#: lib/Hermes.php:227 +msgid "Summary" +msgstr "Zusammenfassung" + +#: lib/Forms/Export.php:40 +msgid "Tab-Separated Variable (.tsv, .txt)" +msgstr "Tabgetrennte Werte (.tsv, .txt)" + +#: lib/Table.php:138 +msgid "Table" +msgstr "Tabelle" + +#: admin.php:175 +msgid "The client settings have been modified." +msgstr "Die Kundeneinstellungen wurde geändert." + +#: admin.php:51 +#, php-format +msgid "The job type \"%s\" has been added." +msgstr "Die Arbeitsart \"%s\" wurde hinzugefügt." + +#: admin.php:197 +msgid "The job type has been deleted." +msgstr "Die Arbeitsart wurde gelöscht." + +#: admin.php:148 +msgid "The job type has been modified." +msgstr "Die Arbeitsart wurde geändert." + +#: admin.php:202 +msgid "The job type was not deleted." +msgstr "Die Arbeitsart wurde nicht gelöscht." + +#: start.php:40 +#, php-format +msgid "" +"The stop watch \"%s\" has been started and will appear in the sidebar at the " +"next refresh." +msgstr "" +"Die Stoppuhr \"%s\" wurde gestartet und erscheint nach der nächsten " +"Aktualisierung im linken Menü." + +#: entry.php:31 +#, php-format +msgid "The stop watch \"%s\" has been stopped." +msgstr "Die Stoppuhr \"%s\" wurde angehalten." + +#: search.php:32 time.php:28 +msgid "The time entry was successfully deleted." +msgstr "Der Zeiteintrag wurde erfolgreich gelöscht." + +#: lib/Admin.php:157 +msgid "There are no clients to edit" +msgstr "Es gibt keine Kunden, die bearbeitet werden können" + +#: lib/Forms/Time.php:65 lib/Forms/Deliverable.php:42 +msgid "There are no clients which you have access to." +msgstr "Sie haben auf keinen Kunden Zugriff." + +#: lib/Forms/Time.php:49 +msgid "There are no job types configured." +msgstr "Es wurden keine Arbeitsarten konfiguriert." + +#: lib/Admin.php:64 +msgid "There are no job types to edit" +msgstr "Es gibt keine Arbeitsarten, die bearbeitet werden können" + +#: invoicing.php:28 +msgid "There is no submitted billable hours." +msgstr "Es gibt keine abgeschickten Zeiteinträge." + +#: admin.php:53 +#, php-format +msgid "There was an error adding the job type: %s." +msgstr "Beim Hinzufügen der Arbeitsart ist ein Fehler aufgetreten: %s." + +#: admin.php:199 +#, php-format +msgid "There was an error deleting the job type: %s." +msgstr "Beim Löschen der Arbeisart ist ein Fehler aufgetreten: %s." + +#: search.php:30 time.php:26 +#, php-format +msgid "There was an error deleting the time: %s" +msgstr "Beim Löschen des Zeiteintrags ist ein Fehler aufgetreten: %s" + +#: admin.php:173 +#, php-format +msgid "There was an error editing the client settings: %s." +msgstr "" +"Beim Bearbeiten der Kundeneinstellungen ist ein Fehler aufgetreten: %s." + +#: admin.php:150 +#, php-format +msgid "There was an error editing the job type: %s." +msgstr "Beim Bearbeiten der Arbeitsart ist ein Fehler aufgetreten: %s." + +#: entry.php:53 +#, php-format +msgid "There was an error storing your timesheet: %s" +msgstr "Beim Speichern Ihrer Zeiteinträge is ein Fehler aufgetreten: %s" + +#: time.php:46 +#, php-format +msgid "There was an error submitting your time: %s" +msgstr "Beim Abschicken Ihres Zeiteintrags ist ein Fehler aufgetreten: %s" + +#: lib/Admin.php:180 +msgid "This is not a valid client." +msgstr "Dies ist kein gültiger Kunde." + +#: lib/Admin.php:87 +msgid "This is not a valid job type." +msgstr "Dies ist keine gültige Arbeitsart." + +#: lib/api.php:52 +msgid "Time Review Screen" +msgstr "Überprüfung der Zeiteinträge" + +#: config/prefs.php.dist:10 +msgid "Timer Options" +msgstr "Stoppuhr-Einstellungen" + +#: invoicing.php:43 +msgid "Total" +msgstr "Insgesamt" + +#: lib/api.php:288 +msgid "Total Hours" +msgstr "Stunden gesamt" + +#: lib/api.php:319 +#, php-format +msgid "Total Hours for %s" +msgstr "Stunden gesamt für %s" + +#: lib/Forms/Time.php:267 +msgid "Update Submitted Time" +msgstr "Abgeschickten Zeiteintrag aktualisieren" + +#: lib/Forms/Time.php:182 +msgid "Update Time" +msgstr "Zeiteintrag aktualisieren" + +#: lib/Forms/Time.php:268 +msgid "Update time" +msgstr "Zeiteintrag aktualisieren" + +#: entry.php:29 +#, php-format +msgid "Using the \"%s\" stop watch from %s to %s" +msgstr "Mit Stoppuhr \"%s\" von %s bis %s" + +#: invoicing.php:74 lib/Admin.php:125 lib/api.php:70 lib/Forms/Time.php:225 +#: lib/Forms/Time.php:320 lib/Forms/Search.php:63 lib/Forms/Export.php:48 +msgid "Yes" +msgstr "Ja" + +#: entry.php:47 +msgid "Your time was successfully entered." +msgstr "Ihr Zeiteintrag wurde erfolgreich gespeichert." + +#: time.php:48 +msgid "Your time was successfully submitted." +msgstr "Ihr Zeiteintrag wurde erfolgreich abgeschickt." + +#: entry.php:43 +msgid "Your time was successfully updated." +msgstr "Ihr Zeiteintrag wurde erfolgreich aktualisiert." + +#: lib/Hermes.php:82 +msgid "_Admin" +msgstr "_Administration" + +#: lib/Hermes.php:68 +msgid "_Deliverables" +msgstr "E_rgebnisse" + +#: lib/Hermes.php:72 +msgid "_Invoicing" +msgstr "_Rechnungswesen" + +#: lib/Hermes.php:64 +msgid "_New Time" +msgstr "_Neuer Zeiteintrag" + +#: lib/Hermes.php:77 +msgid "_Print" +msgstr "_Drucken" + +#: lib/Hermes.php:65 +msgid "_Search" +msgstr "_Suche" + +#: lib/api.php:194 +msgid "no client" +msgstr "Kein Kunde" diff --git a/hermes/po/es_ES.po b/hermes/po/es_ES.po new file mode 100644 index 000000000..69eaf927a --- /dev/null +++ b/hermes/po/es_ES.po @@ -0,0 +1,747 @@ +# Spanish translations for hermes package +# Traducciones al español para el paquete hermes. +# Copyright 2008-2009 The Horde Project +# This file is distributed under the same license as the hermes package. +# Automatically generated, 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: Hermes 1.0-cvs\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2008-03-16 13:58+0100\n" +"PO-Revision-Date: 2008-03-16 13:58+0100\n" +"Last-Translator: Manuel P. Ayala \n" +"Language-Team: i18n@lists.horde.org\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: lib/Forms/Time.php:137 +#, php-format +msgid " (%0.2f hours)" +msgstr " (%0.2f horas)" + +#: lib/Forms/Time.php:139 +#, php-format +msgid " (%d%%, %0.2f of %0.2f hours)" +msgstr " (%d%%, %0.2f de %0.2f horas)" + +#: lib/Admin.php:54 lib/Forms/Search.php:102 +msgid " (DISABLED)" +msgstr " (DESACTIVADO)" + +#: lib/api.php:151 +#, php-format +msgid "\"%s\" is not a defined table." +msgstr "\"%s\" no es una tabla definida." + +#: templates/deliverables/list.inc:4 +#, php-format +msgid "%s Deliverables" +msgstr "%s prestaciones" + +#: lib/Forms/Search.php:84 +msgid "- - None - -" +msgstr "- - Ninguno - -" + +#: lib/Forms/Time.php:109 +msgid "--- No Cost Object ---" +msgstr "--- Sin objetos de gastos ---" + +#: lib/Forms/Time.php:60 +msgid "--- Select A Client ---" +msgstr "--- Seleccione un cliente ---" + +#: lib/Data/iif.php:64 +msgid "; Notes: " +msgstr "; Observaciones: " + +#: lib/Driver/sql.php:142 +msgid "Access denied; user cannot modify this timeslice." +msgstr "Se ha denegado el acceso: el usuario no puede modificar este periodo." + +#: lib/Forms/Deliverable.php:59 +msgid "Active?" +msgstr "¿Activa?" + +#: admin.php:59 admin.php:221 +msgid "Add Job Type" +msgstr "Añadir tipo de trabajo" + +#: config/.bak/prefs.php.dist:21 +msgid "Add stop watch name to the description of the time entry?" +msgstr "¿Añadir nombre del cronómetro a la descripción del registro de tiempo?" + +#: lib/Forms/Time.php:224 lib/Forms/Time.php:306 +msgid "Additional Notes" +msgstr "Observaciones adicionales" + +#: admin.php:35 +msgid "Administration" +msgstr "Administración" + +#: lib/Forms/Time.php:57 lib/Forms/Search.php:81 lib/Forms/Deliverable.php:37 +#, php-format +msgid "An error occurred listing clients: %s" +msgstr "Se ha producido un error al listar los clientes: %s" + +#: lib/Forms/Time.php:40 lib/Forms/Search.php:95 +#, php-format +msgid "An error occurred listing job types: %s" +msgstr "Se ha producido un error al listar los tipos de trabajos: %s" + +#: lib/Hermes.php:176 +#, php-format +msgid "An error occurred listing users: %s" +msgstr "Se ha producido un error al listar los usuarios: %s" + +#: lib/api.php:345 +#, php-format +msgid "An error occurred retrieving deliverables: %s" +msgstr "Se ha producido un error al recuperar los disponibles: %s" + +#: lib/api.php:298 +msgid "Approved By:" +msgstr "Aprobado por:" + +#: lib/api.php:108 +msgid "Bill?" +msgstr "¿Facturar?" + +#: lib/api.php:285 lib/api.php:311 +msgid "Billable Hours" +msgstr "Horas facturables" + +#: lib/Admin.php:30 lib/Admin.php:102 lib/Forms/Time.php:213 +#: lib/Forms/Time.php:302 lib/Forms/Search.php:71 +msgid "Billable?" +msgstr "¿Facturables?" + +#: lib/Hermes.php:230 +msgid "By Client" +msgstr "Por clientes" + +#: lib/Hermes.php:232 +msgid "By Cost Object" +msgstr "Por objetos de gastos" + +#: lib/Hermes.php:228 +msgid "By Date" +msgstr "Por fechas" + +#: lib/Hermes.php:229 +msgid "By Employee" +msgstr "Por empleados" + +#: lib/Hermes.php:231 +msgid "By Job Type" +msgstr "Por tipos de trabajos" + +#: lib/Driver/sql.php:578 +msgid "Cannot delete deliverable; it has children." +msgstr "No se puede eliminar la prestación; tiene descendientes." + +#: lib/Driver/sql.php:593 +msgid "Cannot delete deliverable; there is time entered on it." +msgstr "No se puede eliminar la prestación; se han introducido horas." + +#: invoicing.php:38 lib/api.php:94 lib/Admin.php:187 lib/Forms/Time.php:197 +#: lib/Forms/Time.php:292 lib/Forms/Deliverable.php:28 +msgid "Client" +msgstr "Cliente" + +#: lib/Admin.php:160 +msgid "Client Name" +msgstr "Nombre del cliente" + +#: lib/Forms/Search.php:42 +msgid "Clients" +msgstr "Clientes" + +#: invoicing.php:75 +msgid "Combine same clients in one invoice" +msgstr "Combinar los mismos clientes en una única factura" + +#: lib/Forms/Export.php:37 +msgid "Comma-Separated Variable (.csv)" +msgstr "Variables separadas por comas (.csv)" + +#: invoicing.php:46 lib/api.php:100 lib/Forms/Time.php:206 +msgid "Cost Object" +msgstr "Objeto de gastos" + +#: lib/Forms/Search.php:52 +msgid "Cost Objects" +msgstr "Objetos de gastos" + +#: invoicing.php:70 +msgid "Create invoice" +msgstr "Crear factura" + +#: invoicing.php:44 lib/api.php:85 lib/Forms/Time.php:193 +#: lib/Forms/Time.php:288 +msgid "Date" +msgstr "Fecha" + +#: lib/Forms/Time.php:174 +msgid "Delete" +msgstr "Eliminar" + +#: lib/Forms/Time.php:174 +msgid "Delete Entry" +msgstr "Eliminar entrada" + +#: admin.php:88 admin.php:220 +msgid "Delete Job Type" +msgstr "Eliminar tipo de trabajo" + +#: admin.php:93 admin.php:208 +msgid "Delete Job Type: Confirmation" +msgstr "Eliminar tipo de trabajo: confirmación" + +#: deliverables.php:107 +msgid "Delete This Deliverable" +msgstr "Eliminar esta prestación" + +#: scripts/purge.php:26 +#, php-format +msgid "Deleting data that was exported/billed more than %s days ago.\n" +msgstr "Eliminando datos exportados/facturados hace más de %s días.\n" + +#: lib/Driver.php:85 +#, php-format +msgid "Deliverable %d not found." +msgstr "No se encontró la prestación %d." + +#: lib/Forms/Deliverable.php:52 +msgid "Deliverable Detail" +msgstr "Detalles de la prestación" + +#: deliverables.php:42 +msgid "Deliverable saved successfully." +msgstr "Se ha guardado correctamente la prestación." + +#: deliverables.php:55 +msgid "Deliverable successfully deleted." +msgstr "Se ha eliminado correctamente la prestación." + +#: deliverables.php:61 lib/api.php:54 lib/api.php:397 +msgid "Deliverables" +msgstr "Prestaciones" + +#: invoicing.php:45 lib/api.php:114 lib/Forms/Time.php:222 +#: lib/Forms/Time.php:305 lib/Forms/Deliverable.php:61 +msgid "Description" +msgstr "Descripción" + +#: lib/Forms/Deliverable.php:58 +msgid "Display Name" +msgstr "Mostrar nombre" + +#: lib/Forms/Search.php:58 +msgid "Do not include entries after" +msgstr "Omitir posteriores a" + +#: lib/Forms/Search.php:55 +msgid "Do not include entries before" +msgstr "Omitir anteriores a" + +#: deliverables.php:103 +#, php-format +msgid "Edit %s" +msgstr "Modificar %s" + +#: admin.php:130 admin.php:222 +msgid "Edit Client Settings" +msgstr "Modificar opciones del cliente" + +#: admin.php:122 admin.php:181 +msgid "Edit Client Settings, Step 2" +msgstr "Modificar opciones del cliente. Paso 2" + +#: lib/Forms/Deliverable.php:30 +msgid "Edit Deliverables" +msgstr "Modificar prestaciones" + +#: lib/api.php:245 lib/api.php:246 +msgid "Edit Entry" +msgstr "Modificar entrada" + +#: admin.php:75 admin.php:220 +msgid "Edit Job Type" +msgstr "Modificar tipo de trabajo" + +#: admin.php:80 +msgid "Edit Job Type, Step 2" +msgstr "Modificar tipo de trabajo. Paso 2" + +#: entry.php:84 +msgid "Edit Time" +msgstr "Modificar hora" + +#: admin.php:103 +msgid "Edit job type" +msgstr "Modificar tipo de trabajo" + +#: admin.php:156 +msgid "Edit job type, Step 2" +msgstr "Modificar tipo de trabajo. Paso 2" + +#: invoicing.php:39 lib/api.php:90 lib/Forms/Time.php:286 +msgid "Employee" +msgstr "Empleado" + +#: lib/Forms/Search.php:36 +msgid "Employees" +msgstr "Empleados" + +#: lib/Admin.php:28 lib/Admin.php:100 +msgid "Enabled?" +msgstr "¿Activado?" + +#: lib/Block/tree_menu.php:3 lib/Block/tree_menu.php:21 +msgid "Enter Time" +msgstr "Añadir" + +#: deliverables.php:52 +#, php-format +msgid "Error deleting deliverable: %s" +msgstr "Se produjo un error al eliminar la prestación: %s" + +#: lib/Forms/Time.php:91 lib/Forms/Search.php:130 +#, php-format +msgid "Error retrieving cost objects from \"%s\": %s" +msgstr "Error al recuperar objetos de gastos de \"%s\": %s" + +#: deliverables.php:38 +#, php-format +msgid "Error saving deliverable: %s" +msgstr "Error al guardar la prestación: %s" + +#: lib/Driver/sql.php:295 +#, php-format +msgid "Error: %s" +msgstr "Error: %s" + +#: lib/Forms/Deliverable.php:60 +msgid "Estimated Hours" +msgstr "Horas estimadas" + +#: lib/Forms/Export.php:56 +msgid "Export" +msgstr "Exportar" + +#: lib/Forms/Export.php:35 +msgid "Export Search Results" +msgstr "Resultados de la búsqueda" + +#: lib/Forms/Search.php:68 +msgid "Exported?" +msgstr "¿Exportadas?" + +#: config/.bak/prefs.php.dist:9 +msgid "General Options" +msgstr "Opciones generales" + +#: lib/Admin.php:32 lib/Admin.php:104 +msgid "Hourly Rate" +msgstr "Tasa horaria" + +#: invoicing.php:42 lib/api.php:102 lib/Forms/Time.php:209 +#: lib/Forms/Time.php:298 +msgid "Hours" +msgstr "Horas" + +#: lib/Admin.php:195 +msgid "" +"ID for this client when exporting data, if different from the name displayed " +"above." +msgstr "" +"ID del cliente al exportar datos, si difiere del nombre mostrado " +"anteriormente." + +#: lib/api.php:471 +msgid "Invalid entry: check data and retry." +msgstr "Entrada no válida: compruebe los datos y vuelva a intentarlo." + +#: invoicing.php:122 +#, php-format +msgid "Invoice for client %s successfuly created." +msgstr "Se creó correctamente la factura del cliente %s." + +#: lib/api.php:56 +msgid "Invoicing" +msgstr "Facturación" + +#: invoicing.php:32 +msgid "Invoicing system is not installed." +msgstr "EL sistema de facturación no está instalado." + +#: invoicing.php:40 lib/api.php:98 lib/Admin.php:27 lib/Admin.php:95 +#: lib/Admin.php:129 lib/Forms/Time.php:203 lib/Forms/Time.php:297 +msgid "Job Type" +msgstr "Tipo de trabajo" + +#: lib/Forms/Search.php:48 +msgid "Job Types" +msgstr "Tipos de trabajos" + +#: lib/Admin.php:67 +msgid "JobType Name" +msgstr "Tipo de trabajo" + +#: lib/Forms/Export.php:50 +msgid "Mark the time as exported?" +msgstr "¿Señalar la hora como exportada?" + +#: lib/Forms/Export.php:38 +msgid "Microsoft Excel (.xls)" +msgstr "Excel de Microsoft (.xls)" + +#: time.php:72 +msgid "My Time" +msgstr "Mis horas" + +#: time.php:62 +msgid "My Unsubmitted Time" +msgstr "Mis horas no enviadas" + +#: lib/Hermes.php:63 +msgid "My _Time" +msgstr "Mis _horas" + +#: deliverables.php:105 +msgid "New Sub-deliverable" +msgstr "Añadir subprestación" + +#: entry.php:84 lib/Forms/Time.php:177 +msgid "New Time" +msgstr "Añadir" + +#: templates/deliverables/list.inc:10 +msgid "New Top-level Deliverable" +msgstr "Añadir prestación principal" + +#: invoicing.php:74 lib/api.php:73 lib/Admin.php:125 lib/Forms/Time.php:212 +#: lib/Forms/Time.php:301 lib/Forms/Export.php:49 lib/Forms/Search.php:64 +msgid "No" +msgstr "No" + +#: lib/Driver.php:28 +#, php-format +msgid "No job type with ID \"%s\"." +msgstr "No hay ningún tipo de trabajo con el ID \"%s\"." + +#: search.php:54 search.php:60 +msgid "No search to export!" +msgstr "¡No hay búsquedas a exportar!" + +#: search.php:70 +msgid "No time to export!" +msgstr "¡No hay horas a exportar!" + +#: time.php:38 +msgid "No timeslices were selected to submit." +msgstr "No se seleccionaron períodos a enviar." + +#: lib/api.php:291 lib/api.php:322 +msgid "Non-billable Hours" +msgstr "Horas no facturables" + +#: lib/Hermes.php:217 +msgid "Not found." +msgstr "No se encontró." + +#: lib/Driver.php:49 lib/Driver.php:66 lib/Driver.php:115 lib/Driver.php:133 +#: lib/Driver.php:146 +msgid "Not implemented." +msgstr "No se ha desarrollado." + +#: lib/api.php:116 +msgid "Notes" +msgstr "Observaciones" + +#: lib/Forms/Export.php:39 +msgid "QuickBooks (.iif)" +msgstr "QuickBooks (.iif)" + +#: invoicing.php:41 +msgid "Rate" +msgstr "Tasa" + +#: lib/Admin.php:132 +msgid "Really delete this job type? This may cause data problems!!" +msgstr "" +"¿Eliminar realmente este tipo de trabajo? ¡Puede ocasionar problemas de " +"datos!" + +#: lib/Forms/Time.php:179 +msgid "Save" +msgstr "Guardar" + +#: lib/Forms/Search.php:74 +msgid "Search" +msgstr "Buscar" + +#: lib/Forms/Search.php:32 +msgid "Search For Time" +msgstr "Buscar horas" + +#: search.php:123 lib/api.php:140 +msgid "Search Results" +msgstr "Resultados de la búsqueda" + +#: lib/Block/tree_menu.php:29 +msgid "Search Time" +msgstr "Buscar" + +#: search.php:92 +msgid "Search for Time" +msgstr "Buscar horas" + +#: lib/Admin.php:190 lib/Forms/Time.php:219 lib/Forms/Time.php:258 +msgid "See Attached Timesheet" +msgstr "Examine el horario adjunto" + +#: lib/Forms/Deliverable.php:22 +msgid "Select Client" +msgstr "Seleccionar cliente" + +#: invoicing.php:76 +msgid "Select hours to be invoiced" +msgstr "Seleccionar las horas a facturar" + +#: lib/Forms/Export.php:43 +msgid "Select the export format" +msgstr "Seleccione el formato de exportación" + +#: config/.bak/prefs.php.dist:11 +msgid "Set preferences on the stop watch timer." +msgstr "Define opciones del cronómetro." + +#: lib/Admin.php:190 +#, php-format +msgid "" +"Should users enter descriptions of their timeslices for this client? If not, " +"the description will automatically be \"%s\"." +msgstr "" +"¿Hay que introducir la descripción de los periodos del cliente? Si no es el " +"caso, de forma automática la descripción será \"%s\"." + +#: lib/Block/tree_stopwatch.php:28 +msgid "Start Watch" +msgstr "Iniciar" + +#: start.php:20 start.php:44 lib/Block/tree_stopwatch.php:3 +msgid "Stop Watch" +msgstr "Cronómetro" + +#: start.php:21 +msgid "Stop watch description" +msgstr "Descripción" + +#: templates/time/form.html:5 +msgid "Submit Selected Time" +msgstr "Enviar tiempo seleccionado" + +#: lib/Forms/Search.php:65 +msgid "Submitted?" +msgstr "¿Enviadas?" + +#: lib/Hermes.php:227 +msgid "Summary" +msgstr "Resumen" + +#: lib/Forms/Export.php:40 +msgid "Tab-Separated Variable (.tsv, .txt)" +msgstr "Variables separadas por tabuladores (.tsv, .txt)" + +#: lib/Table.php:137 +msgid "Table" +msgstr "Tabla" + +#: admin.php:175 +msgid "The client settings have been modified." +msgstr "Se han modificado las opciones del cliente." + +#: admin.php:51 +#, php-format +msgid "The job type \"%s\" has been added." +msgstr "Se ha añadido el tipo de trabajo \"%s\"." + +#: admin.php:197 +msgid "The job type has been deleted." +msgstr "Se ha eliminado el tipo de trabajo." + +#: admin.php:148 +msgid "The job type has been modified." +msgstr "Se ha modificado el tipo de trabajo." + +#: admin.php:202 +msgid "The job type was not deleted." +msgstr "No se eliminó el tipo de trabajo." + +#: start.php:40 +#, php-format +msgid "" +"The stop watch \"%s\" has been started and will appear in the sidebar at the " +"next refresh." +msgstr "" +"Se ha iniciado el cronómetro \"%s\" y aparecerá en la barra lateral en la " +"próxima actualización de la pantalla." + +#: entry.php:30 +#, php-format +msgid "The stop watch \"%s\" has been stopped." +msgstr "Se ha detenido el cronómetro \"%s\"." + +#: time.php:28 search.php:32 +msgid "The time entry was successfully deleted." +msgstr "Se ha eliminado correctamente la entrada de hora." + +#: lib/Admin.php:157 +msgid "There are no clients to edit" +msgstr "No hay clientes a modificar" + +#: lib/Forms/Time.php:63 lib/Forms/Deliverable.php:42 +msgid "There are no clients which you have access to." +msgstr "No hay clientes a los que tenga acceso." + +#: lib/Forms/Time.php:49 +msgid "There are no job types configured." +msgstr "No se han configurado tipos de trabajos." + +#: lib/Admin.php:64 +msgid "There are no job types to edit" +msgstr "No hay tipos de trabajos a modificar." + +#: invoicing.php:28 +msgid "There is no submitted billable hours." +msgstr "No se ha enviado ningún tiempo facturable." + +#: admin.php:53 +#, php-format +msgid "There was an error adding the job type: %s." +msgstr "Se produjo un error al añadir el tipo de trabajo: %s." + +#: admin.php:199 +#, php-format +msgid "There was an error deleting the job type: %s." +msgstr "Se produjo un error al eliminar el tipo de trabajo: %s." + +#: time.php:26 search.php:30 +#, php-format +msgid "There was an error deleting the time: %s" +msgstr "Se produjo un error al eliminar la hora: %s" + +#: admin.php:173 +#, php-format +msgid "There was an error editing the client settings: %s." +msgstr "Se produjo un error al modificar las opciones del cliente: %s." + +#: admin.php:150 +#, php-format +msgid "There was an error editing the job type: %s." +msgstr "Se produjo un error al modificar el tipo de trabajo: %s." + +#: entry.php:52 +#, php-format +msgid "There was an error storing your timesheet: %s" +msgstr "Se produjo un error al almacenar el horario: %s" + +#: time.php:46 +#, php-format +msgid "There was an error submitting your time: %s" +msgstr "Se produjo un error al enviar la hora: %s" + +#: lib/Admin.php:180 +msgid "This is not a valid client." +msgstr "Éste no es un cliente válido." + +#: lib/Admin.php:87 +msgid "This is not a valid job type." +msgstr "Éste no es un tipo de trabajo válido." + +#: lib/api.php:52 +msgid "Time Review Screen" +msgstr "Pantalla de visualización de hora" + +#: config/.bak/prefs.php.dist:10 +msgid "Timer Options" +msgstr "Opciones de temporización" + +#: invoicing.php:43 +msgid "Total" +msgstr "Total" + +#: lib/api.php:297 +msgid "Total Hours" +msgstr "Horas totales" + +#: lib/api.php:328 +#, php-format +msgid "Total Hours for %s" +msgstr "Horas totales de %s" + +#: lib/Forms/Time.php:248 +msgid "Update Submitted Time" +msgstr "Actualizar hora enviada" + +#: lib/Forms/Time.php:173 +msgid "Update Time" +msgstr "Actualizar hora" + +#: lib/Forms/Time.php:249 +msgid "Update time" +msgstr "Actualizar hora" + +#: entry.php:28 +#, php-format +msgid "Using the \"%s\" stop watch" +msgstr "Utilizando el cronómetro \"%s\"" + +#: invoicing.php:74 lib/api.php:72 lib/Admin.php:125 lib/Forms/Time.php:212 +#: lib/Forms/Time.php:301 lib/Forms/Export.php:48 lib/Forms/Search.php:63 +msgid "Yes" +msgstr "Sí" + +#: entry.php:46 +msgid "Your time was successfully entered." +msgstr "Se introdujo correctamente su tiempo." + +#: time.php:48 +msgid "Your time was successfully submitted." +msgstr "Se envió correctamente su tiempo." + +#: entry.php:42 +msgid "Your time was successfully updated." +msgstr "Se actualizó correctamente su tiempo." + +#: lib/Hermes.php:82 +msgid "_Admin" +msgstr "A_dministrar" + +#: lib/Hermes.php:68 +msgid "_Deliverables" +msgstr "_Prestaciones" + +#: lib/Hermes.php:72 +msgid "_Invoicing" +msgstr "_Facturación" + +#: lib/Hermes.php:64 +msgid "_New Time" +msgstr "_Añadir" + +#: lib/Hermes.php:77 +msgid "_Print" +msgstr "_Imprimir" + +#: lib/Hermes.php:65 +msgid "_Search" +msgstr "_Buscar" + +#: lib/api.php:199 +msgid "no client" +msgstr "sin cliente" diff --git a/hermes/po/fi_FI.po b/hermes/po/fi_FI.po new file mode 100644 index 000000000..8a9dc7527 --- /dev/null +++ b/hermes/po/fi_FI.po @@ -0,0 +1,541 @@ +# Finnish translation for Hermes. +# Copyright +# Leena Heino , 2004. +# +msgid "" +msgstr "" +"Project-Id-Version: Hermes 0.1-cvs\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2005-03-14 11:02+0200\n" +"PO-Revision-Date: 2004-12-10 12:59+0200\n" +"Last-Translator: Leena Heino \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8-bit\n" + +#: lib/Admin.php:39 lib/Search.php:71 +msgid " (DISABLED)" +msgstr " (POIS KÄYTÖSTÄ)" + +#: templates/deliverables/list.inc:4 +#, fuzzy, php-format +msgid "%s Deliverables" +msgstr "Tapahtui virhe listattaessa asiakkaita: %s" + +#: lib/api.php:129 +#, php-format +msgid "'%s' is not a defined table." +msgstr "'%s' ei ole määritelty taulukko." + +#: lib/TimeForm.php:92 +msgid "--- No Deliverable ---" +msgstr "" + +#: lib/Data/iif.php:67 +msgid "; Notes: " +msgstr "; Muistiinpanot: " + +#: lib/Driver/sql.php:135 +msgid "Access denied; user cannot modify this timeslice." +msgstr "Käyttö kielletty; käyttäjä ei voi muokata tämä aikasiivua." + +#: lib/DeliverableForm.php:59 +msgid "Active?" +msgstr "" + +#: admin.php:57 admin.php:219 +msgid "Add Job Type" +msgstr "Lisää työn tyyppi" + +#: lib/TimeForm.php:182 lib/TimeForm.php:265 lib/api.php:93 +msgid "Additional Notes" +msgstr "Lisämuistiinpanot" + +#: admin.php:33 +msgid "Administration" +msgstr "Ylläpito" + +#: lib/TimeForm.php:51 lib/Search.php:51 lib/DeliverableForm.php:37 +#, php-format +msgid "An error occurred listing clients: %s" +msgstr "Tapahtui virhe listattaessa asiakkaita: %s" + +#: lib/TimeForm.php:34 lib/Search.php:64 +#, php-format +msgid "An error occurred listing job types: %s" +msgstr "Tapahtui virhe listattaessa työn tyyppejä: %s" + +#: lib/Hermes.php:172 +#, php-format +msgid "An error occurred listing users: %s" +msgstr "Tapahtui virhe listattaessa käyttäjiä: %s" + +#: lib/TimeForm.php:70 +#, fuzzy, php-format +msgid "An error occurred retrieving deliverables: %s" +msgstr "Tapahtui virhe listattaessa asiakkaita: %s" + +#: lib/api.php:85 +msgid "Bill?" +msgstr "Lasku?" + +#: lib/api.php:196 +msgid "Billable Hours" +msgstr "Laskutettavat tunnit" + +#: lib/TimeForm.php:171 lib/TimeForm.php:261 +msgid "Billable?" +msgstr "Laskutettavissa?" + +#: lib/Driver/sql.php:511 +msgid "Cannot delete deliverable; it has children." +msgstr "" + +#: lib/Driver/sql.php:523 +msgid "Cannot delete deliverable; there is time entered on it." +msgstr "" + +#: lib/Admin.php:154 lib/TimeForm.php:153 lib/TimeForm.php:251 lib/api.php:69 +#: lib/DeliverableForm.php:26 +msgid "Client" +msgstr "Asiakas" + +#: lib/Admin.php:130 +msgid "Client Name" +msgstr "Asiakkaan nimi" + +#: lib/Search.php:23 +msgid "Clients" +msgstr "Asiakkaat" + +#: lib/Search.php:141 +msgid "Comma-Separated Variable (.csv)" +msgstr "Pilkuilla erotetut muuttujat (.csv)" + +#: search.php:124 +msgid "Could not retrieve timeslice: invalid id" +msgstr "Ei voitu hakea aikaviipaletta: epäkelpo id" + +#: lib/TimeForm.php:149 lib/TimeForm.php:247 lib/api.php:60 +msgid "Date" +msgstr "Päiväys" + +#: lib/api.php:168 lib/api.php:169 +msgid "Delete Entry" +msgstr "Poista merkintä" + +#: admin.php:86 admin.php:218 +msgid "Delete Job Type" +msgstr "Poista työn tyyppi" + +#: admin.php:91 admin.php:206 +msgid "Delete Job Type: Confirmation" +msgstr "Poista tuon tyyppi: Varmistus" + +#: deliverables.php:111 +#, fuzzy +msgid "Delete This Deliverable" +msgstr "Tapahtui virhe listattaessa asiakkaita: %s" + +#: scripts/purge.php:24 +#, php-format +msgid "Deleting data that was exported/billed more than %s days ago.\n" +msgstr "Poista tiedot, jotka viety/laskutettu %s päivää vanhempia.\n" + +#: lib/TimeForm.php:162 lib/api.php:76 +msgid "Deliverable" +msgstr "" + +#: lib/Driver.php:85 +#, fuzzy, php-format +msgid "Deliverable %d not found." +msgstr "Aikamerkinnän poistaminen onnistui." + +#: lib/DeliverableForm.php:52 +msgid "Deliverable Detail" +msgstr "" + +#: deliverables.php:40 +#, fuzzy +msgid "Deliverable saved successfully." +msgstr "Aikamerkinnän poistaminen onnistui." + +#: deliverables.php:53 +#, fuzzy +msgid "Deliverable successfully deleted." +msgstr "Aikamerkinnän poistaminen onnistui." + +#: deliverables.php:59 lib/api.php:31 +msgid "Deliverables" +msgstr "" + +#: lib/TimeForm.php:180 lib/TimeForm.php:264 lib/api.php:91 +#: lib/DeliverableForm.php:61 +msgid "Description" +msgstr "Kuvaus" + +#: lib/DeliverableForm.php:58 +msgid "Display Name" +msgstr "" + +#: lib/Search.php:33 +msgid "Do not include entries after" +msgstr "Älä sisällytä merkintöjä jälkeen" + +#: lib/Search.php:30 +msgid "Do not include entries before" +msgstr "Älä sisällytä merkintöjä ennen" + +#: admin.php:128 admin.php:220 +msgid "Edit Client Settings" +msgstr "Muokkaa asiakkaan asetuksia" + +#: admin.php:120 admin.php:179 +msgid "Edit Client Settings, Step 2" +msgstr "Muokkaa asiakkaan asetuksia, askel 2" + +#: lib/api.php:166 lib/api.php:167 +msgid "Edit Entry" +msgstr "Muokkaa merkintää" + +#: admin.php:73 admin.php:218 +msgid "Edit Job Type" +msgstr "Muokkaa työn tyyppiä" + +#: admin.php:78 +msgid "Edit Job Type, Step 2" +msgstr "Muokkaa työn tyyppiä, askel 2" + +#: admin.php:101 +msgid "Edit job type" +msgstr "Muokkaa työn tyyppiä" + +#: admin.php:154 +msgid "Edit job type, Step 2" +msgstr "Muokkaa työn tyyppiä, askel 2" + +#: lib/TimeForm.php:245 lib/api.php:65 +msgid "Employee" +msgstr "Työntekijä" + +#: lib/Search.php:18 +msgid "Employees" +msgstr "Työntekijät" + +#: lib/Admin.php:20 lib/Admin.php:80 +msgid "Enabled?" +msgstr "Käytössä?" + +#: entry.php:61 lib/TimeForm.php:133 +msgid "Enter Time" +msgstr "Anna aika" + +#: lib/TimeForm.php:134 +msgid "Enter my time" +msgstr "Anna oma aika" + +#: deliverables.php:50 +#, fuzzy, php-format +msgid "Error deleting deliverable: %s" +msgstr "Tapahtui virhe listattaessa asiakkaita: %s" + +#: deliverables.php:36 +#, fuzzy, php-format +msgid "Error saving deliverable: %s" +msgstr "Tapahtui virhe listattaessa asiakkaita: %s" + +#: lib/DeliverableForm.php:60 +#, fuzzy +msgid "Estimated Hours" +msgstr "Laskutettavat tunnit" + +#: lib/Search.php:139 +msgid "Export Search Results" +msgstr "Vie haun tulokset" + +#: lib/Search.php:43 +msgid "Exported?" +msgstr "Viety" + +#: lib/TimeForm.php:167 lib/TimeForm.php:257 lib/api.php:79 +msgid "Hours" +msgstr "Tunnit" + +#: lib/Admin.php:162 +msgid "" +"ID for this client when exporting data, if different from the name displayed " +"above." +msgstr "" +"ID tälle asiakkalle tietoja vietäessä, jos se on eri kuin yllä mainittu nimi." + +#: lib/Admin.php:19 lib/Admin.php:75 lib/Admin.php:102 lib/TimeForm.php:158 +#: lib/TimeForm.php:256 lib/api.php:73 +msgid "Job Type" +msgstr "Työn tyyppi" + +#: lib/Search.php:27 +msgid "Job Types" +msgstr "Työn tyypit" + +#: lib/Admin.php:50 +msgid "JobType Name" +msgstr "Työn tyypin nimitys" + +#: lib/Search.php:152 +msgid "Mark the time as exported?" +msgstr "Merkitse aika viedyksi?" + +#: time.php:54 +msgid "My Time" +msgstr "Oma aika" + +#: time.php:75 +msgid "My Unsubmitted Time" +msgstr "Oma lähettämätön aika" + +#: lib/Hermes.php:67 +msgid "My _Time" +msgstr "Oma _Aika" + +#: deliverables.php:109 +msgid "New Sub-deliverable" +msgstr "" + +#: templates/deliverables/list.inc:12 +msgid "New Top-level Deliverable" +msgstr "" + +#: lib/Admin.php:98 lib/TimeForm.php:170 lib/TimeForm.php:260 +#: lib/Search.php:39 lib/Search.php:151 lib/api.php:48 +msgid "No" +msgstr "Ei" + +#: lib/Driver.php:29 +#, php-format +msgid "No job type with ID '%s'." +msgstr "Ei työtyyppiä ID:llä '%s'." + +#: search.php:67 search.php:73 +msgid "No search to export!" +msgstr "Ei hakuja vietäväksi!" + +#: search.php:83 +msgid "No time to export!" +msgstr "Ei aikatietoja vietäväksi!" + +#: time.php:36 +msgid "No timeslices were selected to submit." +msgstr "Ei aikaviipaleita merkitty lähetettäväksi." + +#: lib/api.php:201 +msgid "Non-billable Hours" +msgstr "Ei laskutettavat tunnit" + +#: lib/Driver.php:50 lib/Driver.php:66 lib/Driver.php:115 lib/Driver.php:132 +#: lib/Driver.php:145 +msgid "Not implemented." +msgstr "Ei toteutettu." + +#: lib/Search.php:143 +msgid "QuickBooks (.iif)" +msgstr "QuickBooks (.iif)" + +#: lib/Admin.php:105 +msgid "Really delete this job type? This may cause data problems!!" +msgstr "Poistaanko tämä työn tyyppi? Tämä voi aiheuttaa ongelmia!!" + +#: lib/Search.php:14 +msgid "Search For Time" +msgstr "Etsi aikoja" + +#: search.php:152 lib/api.php:118 +msgid "Search Results" +msgstr "Haun tulokset" + +#: search.php:115 +msgid "Search for Time" +msgstr "Hae aikoja" + +#: lib/Admin.php:157 lib/TimeForm.php:177 lib/TimeForm.php:217 +msgid "See Attached Timesheet" +msgstr "Katso liitettyä aikataulukkoa" + +#: lib/DeliverableForm.php:23 +#, fuzzy +msgid "Select Client" +msgstr "Asiakas" + +#: lib/Search.php:145 +msgid "Select the export format" +msgstr "Valitse viennissä käytettävä muoto" + +#: lib/Admin.php:157 +#, php-format +msgid "" +"Should users enter descriptions of their timeslices for this client? If not, " +"the description will automatically be \"%s\"." +msgstr "" +"Saavatko käyttäjät laittaa omia kuvauksia heidän aikaviipaleilleen tälle " +"asiakkaalle? Jos ei niin, kuvaus on oletuksena \"%s\"." + +#: templates/time/form-footer.html:1 +msgid "Submit Selected Time" +msgstr "Lähetä valitut ajat" + +#: lib/Search.php:40 +msgid "Submitted?" +msgstr "Lähetetty?" + +#: lib/Search.php:142 +msgid "Tab-Separated Variable (.tsv,.txt)" +msgstr "Tabulaattorilla erotetut muuttujat (.tsv,.txt)" + +#: admin.php:173 +msgid "The client settings have been modified." +msgstr "Asiakkaan asetuksia on muokattu." + +#: admin.php:49 +#, php-format +msgid "The job type '%s' has been added." +msgstr "Työn tyyppi '%s' on lisätty." + +#: admin.php:195 +msgid "The job type has been deleted." +msgstr "Työn tyyppi on poistettu." + +#: admin.php:146 +msgid "The job type has been modified." +msgstr "Työn tyyppi on muokattu." + +#: admin.php:200 +msgid "The job type was not deleted." +msgstr "Työn tyyppiä ei poistettu." + +#: search.php:29 time.php:26 +msgid "The time entry was successfully deleted." +msgstr "Aikamerkinnän poistaminen onnistui." + +#: search.php:48 +msgid "The timeslice was successfully updated." +msgstr "Aikaviipaleen päivitysä onnistui." + +#: lib/Admin.php:127 +msgid "There are no clients to edit" +msgstr "Ei asiakkaita muokattavaksi" + +#: lib/TimeForm.php:57 lib/DeliverableForm.php:42 +msgid "There are no clients which you have access to." +msgstr "Ei asiakkaita, joihin on pääsy sallittu." + +#: lib/TimeForm.php:43 +msgid "There are no job types configured." +msgstr "Ei työn tyyppejä määriteltynä." + +#: lib/Admin.php:47 +msgid "There are no job types to edit" +msgstr "Ei työn tyyppejä muokattavaksi" + +#: admin.php:51 +#, php-format +msgid "There was an error adding the job type: %s." +msgstr "Tapahtui virhe lisättäessä työn tyypiä: %s." + +#: admin.php:197 +#, php-format +msgid "There was an error deleting the job type: %s." +msgstr "Tapahtui virhe poistettaessa työn tyyppiä: %s." + +#: search.php:27 time.php:24 +#, php-format +msgid "There was an error deleting the time: %s" +msgstr "Tapahtui virhe poistettaessa aikaa: %s" + +#: admin.php:171 +#, php-format +msgid "There was an error editing the client settings: %s." +msgstr "Tapahtui virhe muokattaessa asiakkaan asetuksia: %s." + +#: admin.php:148 +#, php-format +msgid "There was an error editing the job type: %s." +msgstr "Tapahtui virhe muokattaessa työn tyyppiä: %s." + +#: search.php:46 entry.php:33 +#, php-format +msgid "There was an error storing your timesheet: %s" +msgstr "Tapahtui virhe talletettaessa aikataulukkoasi: %s" + +#: time.php:44 +#, php-format +msgid "There was an error submitting your time: %s" +msgstr "Tapahtui virhe talletettaessa aikaasi: %s" + +#: lib/Admin.php:147 +msgid "This is not a valid client." +msgstr "Tämä ei ole kelvollinen asiakas." + +#: lib/Admin.php:67 +msgid "This is not a valid job type." +msgstr "Tämä ei ole kelvollinen työn tyyppi" + +#: lib/api.php:29 +msgid "Time Review Screen" +msgstr "Aikojen tarkistus ruutu" + +#: lib/api.php:205 +msgid "Total Hours" +msgstr "Tunnit yhteensä" + +#: lib/TimeForm.php:207 +msgid "Update Submitted Time" +msgstr "Päivitä lähetetty aika" + +#: lib/TimeForm.php:130 +msgid "Update Time" +msgstr "Päivitä aika" + +#: lib/TimeForm.php:131 +msgid "Update my time" +msgstr "Päivitä oma aika" + +#: lib/TimeForm.php:208 +msgid "Update time" +msgstr "Päivitä aika" + +#: lib/Admin.php:98 lib/TimeForm.php:170 lib/TimeForm.php:260 +#: lib/Search.php:38 lib/Search.php:150 lib/api.php:47 +msgid "Yes" +msgstr "Kyllä" + +#: entry.php:28 +msgid "Your time was successfully entered." +msgstr "Aikasi merkittiin onnistuneesti." + +#: time.php:46 +msgid "Your time was successfully submitted." +msgstr "Aikasi lähetettiin onnistuneesti." + +#: entry.php:25 +msgid "Your time was successfully updated." +msgstr "Aikasi päivitettiin onnistuneesti." + +#: lib/Hermes.php:86 +msgid "_Admin" +msgstr "_Ylläpito" + +#: lib/Hermes.php:76 +msgid "_Deliverables" +msgstr "" + +#: lib/Hermes.php:68 +msgid "_Enter Time" +msgstr "_Aseta aika" + +#: lib/Hermes.php:81 +msgid "_Print" +msgstr "_Tulosta" + +#: lib/Hermes.php:69 +msgid "_Search" +msgstr "_Haku" diff --git a/hermes/po/hermes.pot b/hermes/po/hermes.pot new file mode 100644 index 000000000..43199d101 --- /dev/null +++ b/hermes/po/hermes.pot @@ -0,0 +1,740 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright YEAR Horde Project +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2008-08-01 10:45+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: lib/Forms/Time.php:139 +#, php-format +msgid " (%0.2f hours)" +msgstr "" + +#: lib/Forms/Time.php:141 +#, php-format +msgid " (%d%%, %0.2f of %0.2f hours)" +msgstr "" + +#: lib/Admin.php:54 lib/Forms/Search.php:102 +msgid " (DISABLED)" +msgstr "" + +#: lib/api.php:149 +#, php-format +msgid "\"%s\" is not a defined table." +msgstr "" + +#: templates/deliverables/list.inc:4 +#, php-format +msgid "%s Deliverables" +msgstr "" + +#: lib/Forms/Search.php:84 +msgid "- - None - -" +msgstr "" + +#: lib/Forms/Time.php:111 +msgid "--- No Cost Object ---" +msgstr "" + +#: lib/Forms/Time.php:61 +msgid "--- Select A Client ---" +msgstr "" + +#: lib/Data/iif.php:64 +msgid "; Notes: " +msgstr "" + +#: entry.php:74 lib/Driver/sql.php:142 +msgid "Access denied; user cannot modify this timeslice." +msgstr "" + +#: lib/Forms/Deliverable.php:59 +msgid "Active?" +msgstr "" + +#: admin.php:59 admin.php:221 +msgid "Add Job Type" +msgstr "" + +#: config/prefs.php.dist:21 +msgid "" +"Add stop watch name and start and end time to the description of the time " +"entry?" +msgstr "" + +#: lib/Forms/Time.php:237 lib/Forms/Time.php:325 +msgid "Additional Notes" +msgstr "" + +#: admin.php:35 +msgid "Administration" +msgstr "" + +#: lib/Forms/Time.php:57 lib/Forms/Search.php:81 lib/Forms/Deliverable.php:37 +#, php-format +msgid "An error occurred listing clients: %s" +msgstr "" + +#: lib/Forms/Time.php:40 lib/Forms/Search.php:95 +#, php-format +msgid "An error occurred listing job types: %s" +msgstr "" + +#: lib/Hermes.php:176 +#, php-format +msgid "An error occurred listing users: %s" +msgstr "" + +#: lib/api.php:335 +#, php-format +msgid "An error occurred retrieving deliverables: %s" +msgstr "" + +#: lib/api.php:289 +msgid "Approved By:" +msgstr "" + +#: lib/api.php:106 +msgid "Bill?" +msgstr "" + +#: lib/api.php:276 lib/api.php:302 +msgid "Billable Hours" +msgstr "" + +#: lib/Admin.php:30 lib/Admin.php:102 lib/Forms/Time.php:226 +#: lib/Forms/Time.php:321 lib/Forms/Search.php:71 +msgid "Billable?" +msgstr "" + +#: lib/Hermes.php:230 +msgid "By Client" +msgstr "" + +#: lib/Hermes.php:232 +msgid "By Cost Object" +msgstr "" + +#: lib/Hermes.php:228 +msgid "By Date" +msgstr "" + +#: lib/Hermes.php:229 +msgid "By Employee" +msgstr "" + +#: lib/Hermes.php:231 +msgid "By Job Type" +msgstr "" + +#: lib/Driver/sql.php:581 +msgid "Cannot delete deliverable; it has children." +msgstr "" + +#: lib/Driver/sql.php:596 +msgid "Cannot delete deliverable; there is time entered on it." +msgstr "" + +#: invoicing.php:38 lib/Admin.php:187 lib/api.php:92 lib/Forms/Time.php:210 +#: lib/Forms/Time.php:311 lib/Forms/Deliverable.php:28 +msgid "Client" +msgstr "" + +#: lib/Admin.php:160 +msgid "Client Name" +msgstr "" + +#: lib/Forms/Search.php:42 +msgid "Clients" +msgstr "" + +#: invoicing.php:75 +msgid "Combine same clients in one invoice" +msgstr "" + +#: lib/Forms/Export.php:37 +msgid "Comma-Separated Variable (.csv)" +msgstr "" + +#: invoicing.php:46 lib/api.php:98 lib/Forms/Time.php:219 +msgid "Cost Object" +msgstr "" + +#: lib/Forms/Search.php:51 +msgid "Cost Objects" +msgstr "" + +#: invoicing.php:70 +msgid "Create invoice" +msgstr "" + +#: invoicing.php:44 lib/api.php:83 lib/Forms/Time.php:206 +#: lib/Forms/Time.php:307 +msgid "Date" +msgstr "" + +#: lib/Forms/Time.php:183 +msgid "Delete" +msgstr "" + +#: lib/Forms/Time.php:183 +msgid "Delete Entry" +msgstr "" + +#: admin.php:88 admin.php:220 +msgid "Delete Job Type" +msgstr "" + +#: admin.php:93 admin.php:208 +msgid "Delete Job Type: Confirmation" +msgstr "" + +#: deliverables.php:107 +msgid "Delete This Deliverable" +msgstr "" + +#: scripts/purge.php:26 +#, php-format +msgid "Deleting data that was exported/billed more than %s days ago.\n" +msgstr "" + +#: lib/Driver.php:85 +#, php-format +msgid "Deliverable %d not found." +msgstr "" + +#: lib/Forms/Deliverable.php:52 +msgid "Deliverable Detail" +msgstr "" + +#: deliverables.php:42 +msgid "Deliverable saved successfully." +msgstr "" + +#: deliverables.php:55 +msgid "Deliverable successfully deleted." +msgstr "" + +#: deliverables.php:61 lib/api.php:54 lib/api.php:387 +msgid "Deliverables" +msgstr "" + +#: invoicing.php:45 lib/api.php:112 lib/Forms/Time.php:235 +#: lib/Forms/Time.php:324 lib/Forms/Deliverable.php:61 +msgid "Description" +msgstr "" + +#: lib/Forms/Deliverable.php:58 +msgid "Display Name" +msgstr "" + +#: lib/Forms/Search.php:58 +msgid "Do not include entries after" +msgstr "" + +#: lib/Forms/Search.php:55 +msgid "Do not include entries before" +msgstr "" + +#: deliverables.php:103 +#, php-format +msgid "Edit %s" +msgstr "" + +#: admin.php:130 admin.php:222 +msgid "Edit Client Settings" +msgstr "" + +#: admin.php:122 admin.php:181 +msgid "Edit Client Settings, Step 2" +msgstr "" + +#: lib/Forms/Deliverable.php:30 +msgid "Edit Deliverables" +msgstr "" + +#: lib/api.php:236 lib/api.php:237 +msgid "Edit Entry" +msgstr "" + +#: admin.php:75 admin.php:220 +msgid "Edit Job Type" +msgstr "" + +#: admin.php:80 +msgid "Edit Job Type, Step 2" +msgstr "" + +#: entry.php:94 +msgid "Edit Time" +msgstr "" + +#: admin.php:103 +msgid "Edit job type" +msgstr "" + +#: admin.php:156 +msgid "Edit job type, Step 2" +msgstr "" + +#: invoicing.php:39 lib/api.php:88 lib/Forms/Time.php:305 +msgid "Employee" +msgstr "" + +#: lib/Forms/Search.php:36 +msgid "Employees" +msgstr "" + +#: lib/Admin.php:28 lib/Admin.php:100 +msgid "Enabled?" +msgstr "" + +#: lib/Block/tree_menu.php:3 lib/Block/tree_menu.php:21 +msgid "Enter Time" +msgstr "" + +#: deliverables.php:52 +#, php-format +msgid "Error deleting deliverable: %s" +msgstr "" + +#: lib/Forms/Time.php:93 lib/Forms/Search.php:130 +#, php-format +msgid "Error retrieving cost objects from \"%s\": %s" +msgstr "" + +#: deliverables.php:38 +#, php-format +msgid "Error saving deliverable: %s" +msgstr "" + +#: lib/Driver/sql.php:298 +#, php-format +msgid "Error: %s" +msgstr "" + +#: lib/Forms/Deliverable.php:60 +msgid "Estimated Hours" +msgstr "" + +#: lib/Forms/Export.php:56 +msgid "Export" +msgstr "" + +#: lib/Forms/Export.php:35 +msgid "Export Search Results" +msgstr "" + +#: lib/Forms/Search.php:68 +msgid "Exported?" +msgstr "" + +#: config/prefs.php.dist:9 +msgid "General Options" +msgstr "" + +#: lib/Admin.php:32 lib/Admin.php:104 +msgid "Hourly Rate" +msgstr "" + +#: invoicing.php:42 lib/api.php:100 lib/Forms/Time.php:222 +#: lib/Forms/Time.php:317 +msgid "Hours" +msgstr "" + +#: lib/Admin.php:195 +msgid "" +"ID for this client when exporting data, if different from the name displayed " +"above." +msgstr "" + +#: lib/api.php:452 +msgid "Invalid entry: check data and retry." +msgstr "" + +#: invoicing.php:122 +#, php-format +msgid "Invoice for client %s successfuly created." +msgstr "" + +#: lib/api.php:56 +msgid "Invoicing" +msgstr "" + +#: invoicing.php:32 +msgid "Invoicing system is not installed." +msgstr "" + +#: invoicing.php:40 lib/Admin.php:27 lib/Admin.php:95 lib/Admin.php:129 +#: lib/api.php:96 lib/Forms/Time.php:216 lib/Forms/Time.php:316 +msgid "Job Type" +msgstr "" + +#: lib/Forms/Search.php:48 +msgid "Job Types" +msgstr "" + +#: lib/Admin.php:67 +msgid "JobType Name" +msgstr "" + +#: lib/Forms/Export.php:50 +msgid "Mark the time as exported?" +msgstr "" + +#: lib/Forms/Export.php:38 +msgid "Microsoft Excel (.xls)" +msgstr "" + +#: time.php:72 +msgid "My Time" +msgstr "" + +#: time.php:62 +msgid "My Unsubmitted Time" +msgstr "" + +#: lib/Hermes.php:63 +msgid "My _Time" +msgstr "" + +#: deliverables.php:105 +msgid "New Sub-deliverable" +msgstr "" + +#: entry.php:94 lib/Forms/Time.php:186 +msgid "New Time" +msgstr "" + +#: templates/deliverables/list.inc:10 +msgid "New Top-level Deliverable" +msgstr "" + +#: invoicing.php:74 lib/Admin.php:125 lib/api.php:71 lib/Forms/Time.php:225 +#: lib/Forms/Time.php:320 lib/Forms/Search.php:64 lib/Forms/Export.php:49 +msgid "No" +msgstr "" + +#: lib/Driver.php:28 +#, php-format +msgid "No job type with ID \"%s\"." +msgstr "" + +#: search.php:54 search.php:60 +msgid "No search to export!" +msgstr "" + +#: search.php:70 +msgid "No time to export!" +msgstr "" + +#: time.php:38 +msgid "No timeslices were selected to submit." +msgstr "" + +#: lib/api.php:282 lib/api.php:313 +msgid "Non-billable Hours" +msgstr "" + +#: lib/Hermes.php:217 +msgid "Not found." +msgstr "" + +#: lib/Driver.php:49 lib/Driver.php:66 lib/Driver.php:115 lib/Driver.php:133 +#: lib/Driver.php:146 +msgid "Not implemented." +msgstr "" + +#: lib/api.php:114 +msgid "Notes" +msgstr "" + +#: lib/Forms/Export.php:39 +msgid "QuickBooks (.iif)" +msgstr "" + +#: invoicing.php:41 +msgid "Rate" +msgstr "" + +#: lib/Admin.php:132 +msgid "Really delete this job type? This may cause data problems!!" +msgstr "" + +#: lib/Forms/Time.php:188 +msgid "Save" +msgstr "" + +#: lib/Forms/Search.php:74 +msgid "Search" +msgstr "" + +#: lib/Forms/Search.php:32 +msgid "Search For Time" +msgstr "" + +#: search.php:123 lib/api.php:138 +msgid "Search Results" +msgstr "" + +#: lib/Block/tree_menu.php:29 +msgid "Search Time" +msgstr "" + +#: search.php:92 +msgid "Search for Time" +msgstr "" + +#: lib/Admin.php:190 lib/Forms/Time.php:232 lib/Forms/Time.php:277 +msgid "See Attached Timesheet" +msgstr "" + +#: lib/Forms/Deliverable.php:22 +msgid "Select Client" +msgstr "" + +#: invoicing.php:76 +msgid "Select hours to be invoiced" +msgstr "" + +#: lib/Forms/Export.php:43 +msgid "Select the export format" +msgstr "" + +#: config/prefs.php.dist:11 +msgid "Set preferences on the stop watch timer." +msgstr "" + +#: lib/Admin.php:190 +#, php-format +msgid "" +"Should users enter descriptions of their timeslices for this client? If not, " +"the description will automatically be \"%s\"." +msgstr "" + +#: lib/Block/tree_stopwatch.php:28 +msgid "Start Watch" +msgstr "" + +#: start.php:20 start.php:44 lib/Block/tree_stopwatch.php:3 +msgid "Stop Watch" +msgstr "" + +#: start.php:21 +msgid "Stop watch description" +msgstr "" + +#: templates/time/form.html:5 +msgid "Submit Selected Time" +msgstr "" + +#: lib/Forms/Search.php:65 +msgid "Submitted?" +msgstr "" + +#: lib/Hermes.php:227 +msgid "Summary" +msgstr "" + +#: lib/Forms/Export.php:40 +msgid "Tab-Separated Variable (.tsv, .txt)" +msgstr "" + +#: lib/Table.php:138 +msgid "Table" +msgstr "" + +#: admin.php:175 +msgid "The client settings have been modified." +msgstr "" + +#: admin.php:51 +#, php-format +msgid "The job type \"%s\" has been added." +msgstr "" + +#: admin.php:197 +msgid "The job type has been deleted." +msgstr "" + +#: admin.php:148 +msgid "The job type has been modified." +msgstr "" + +#: admin.php:202 +msgid "The job type was not deleted." +msgstr "" + +#: start.php:40 +#, php-format +msgid "" +"The stop watch \"%s\" has been started and will appear in the sidebar at the " +"next refresh." +msgstr "" + +#: entry.php:31 +#, php-format +msgid "The stop watch \"%s\" has been stopped." +msgstr "" + +#: search.php:32 time.php:28 +msgid "The time entry was successfully deleted." +msgstr "" + +#: lib/Admin.php:157 +msgid "There are no clients to edit" +msgstr "" + +#: lib/Forms/Time.php:65 lib/Forms/Deliverable.php:42 +msgid "There are no clients which you have access to." +msgstr "" + +#: lib/Forms/Time.php:49 +msgid "There are no job types configured." +msgstr "" + +#: lib/Admin.php:64 +msgid "There are no job types to edit" +msgstr "" + +#: invoicing.php:28 +msgid "There is no submitted billable hours." +msgstr "" + +#: admin.php:53 +#, php-format +msgid "There was an error adding the job type: %s." +msgstr "" + +#: admin.php:199 +#, php-format +msgid "There was an error deleting the job type: %s." +msgstr "" + +#: search.php:30 time.php:26 +#, php-format +msgid "There was an error deleting the time: %s" +msgstr "" + +#: admin.php:173 +#, php-format +msgid "There was an error editing the client settings: %s." +msgstr "" + +#: admin.php:150 +#, php-format +msgid "There was an error editing the job type: %s." +msgstr "" + +#: entry.php:53 +#, php-format +msgid "There was an error storing your timesheet: %s" +msgstr "" + +#: time.php:46 +#, php-format +msgid "There was an error submitting your time: %s" +msgstr "" + +#: lib/Admin.php:180 +msgid "This is not a valid client." +msgstr "" + +#: lib/Admin.php:87 +msgid "This is not a valid job type." +msgstr "" + +#: lib/api.php:52 +msgid "Time Review Screen" +msgstr "" + +#: config/prefs.php.dist:10 +msgid "Timer Options" +msgstr "" + +#: invoicing.php:43 +msgid "Total" +msgstr "" + +#: lib/api.php:288 +msgid "Total Hours" +msgstr "" + +#: lib/api.php:319 +#, php-format +msgid "Total Hours for %s" +msgstr "" + +#: lib/Forms/Time.php:267 +msgid "Update Submitted Time" +msgstr "" + +#: lib/Forms/Time.php:182 +msgid "Update Time" +msgstr "" + +#: lib/Forms/Time.php:268 +msgid "Update time" +msgstr "" + +#: entry.php:29 +#, php-format +msgid "Using the \"%s\" stop watch from %s to %s" +msgstr "" + +#: invoicing.php:74 lib/Admin.php:125 lib/api.php:70 lib/Forms/Time.php:225 +#: lib/Forms/Time.php:320 lib/Forms/Search.php:63 lib/Forms/Export.php:48 +msgid "Yes" +msgstr "" + +#: entry.php:47 +msgid "Your time was successfully entered." +msgstr "" + +#: time.php:48 +msgid "Your time was successfully submitted." +msgstr "" + +#: entry.php:43 +msgid "Your time was successfully updated." +msgstr "" + +#: lib/Hermes.php:82 +msgid "_Admin" +msgstr "" + +#: lib/Hermes.php:68 +msgid "_Deliverables" +msgstr "" + +#: lib/Hermes.php:72 +msgid "_Invoicing" +msgstr "" + +#: lib/Hermes.php:64 +msgid "_New Time" +msgstr "" + +#: lib/Hermes.php:77 +msgid "_Print" +msgstr "" + +#: lib/Hermes.php:65 +msgid "_Search" +msgstr "" + +#: lib/api.php:194 +msgid "no client" +msgstr "" diff --git a/hermes/po/zh_TW.po b/hermes/po/zh_TW.po new file mode 100644 index 000000000..81ae1c2b2 --- /dev/null +++ b/hermes/po/zh_TW.po @@ -0,0 +1,416 @@ +# Hermes Traditional Chinese Translation +# Copyright 2002 David Chang.±i¨}¤å,¥xÆW +# David Chang , 2002. +msgid "" +msgstr "" +"Project-Id-Version: Hermes 0.1-cvs\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2004-11-22 16:41+0800\n" +"PO-Revision-Date: 2003-01-08 10:53+0100\n" +"Last-Translator: David Chang \n" +"Language-Team: Traditional Chinese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=BIG5\n" +"Content-Transfer-Encoding: 8bit\n" + +#: lib/api.php:116 +#, php-format +msgid "'%s' is not a defined table." +msgstr "'%s' ¤£¬O¤@­Ó¤w©w¸qªºªí®æ." + +#: lib/Data/iif.php:67 +msgid "; Notes: " +msgstr "; ³Æµù: " + +#: lib/Driver/sql.php:130 +msgid "Access denied; user cannot modify this timeslice." +msgstr "¦s¨ú¾D©Ú;¨Ï¥ÎªÌµLªk­×§ï³o­Ó®É¬q." + +#: admin.php:56 admin.php:217 +msgid "Add Job Type" +msgstr "·s¼W¾·~«¬ºA" + +#: lib/TimeForm.php:128 lib/TimeForm.php:211 lib/api.php:87 +msgid "Additional Notes" +msgstr "¥[µù" + +#: admin.php:33 +msgid "Administration" +msgstr "ºÞ²z" + +#: lib/Search.php:49 lib/TimeForm.php:47 +#, php-format +msgid "An error occurred listing clients: %s" +msgstr "¦C¥X«È¤á: %s ®Éµo¥Í¤@­Ó¿ù»~" + +#: lib/Search.php:62 lib/TimeForm.php:34 +#, php-format +msgid "An error occurred listing job types: %s" +msgstr "¦C¥X¾·~«¬ºA: %s ®Éµo¥Í¤@­Ó¿ù»~" + +#: lib/Hermes.php:162 +#, php-format +msgid "An error occurred listing users: %s" +msgstr "¦C¥X¨Ï¥ÎªÌ: %s ®Éµo¥Í¤@­Ó¿ù»~" + +#: lib/api.php:79 +msgid "Bill?" +msgstr "¤ä¥I?" + +#: lib/api.php:184 +msgid "Billable Hours" +msgstr "¥i¤ä¥I®É¼Æ?" + +#: lib/TimeForm.php:124 lib/TimeForm.php:207 +msgid "Billable?" +msgstr "¤ä¥I?" + +#: lib/Admin.php:143 lib/TimeForm.php:114 lib/TimeForm.php:197 lib/api.php:67 +msgid "Client" +msgstr "«È¤á" + +#: lib/Admin.php:119 +msgid "Client Name" +msgstr "«È¤á¦WºÙ" + +#: lib/Search.php:23 +msgid "Clients" +msgstr "«È¤á" + +#: lib/Search.php:132 +msgid "Comma-Separated Variable (.csv)" +msgstr "³rÂI¤À¹j­È (.csv)" + +#: search.php:76 +msgid "Could not retrieve timeslice: invalid id" +msgstr "µLªkŪ¨ú®É¬q: µL®ÄªºÃѧO¸¹½X(id)" + +#: lib/TimeForm.php:111 lib/TimeForm.php:193 lib/api.php:58 +msgid "Date" +msgstr "¤é´Á" + +#: lib/api.php:155 lib/api.php:156 +msgid "Delete Entry" +msgstr "§R°£¬ö¿ý" + +#: admin.php:85 admin.php:216 +msgid "Delete Job Type" +msgstr "§R°£Â¾·~«¬ºA" + +#: admin.php:90 admin.php:204 +msgid "Delete Job Type: Confirmation" +msgstr "§R°£Â¾·~«¬ºA: ½T»{" + +#: scripts/purge.php:24 +#, php-format +msgid "Deleting data that was exported/billed more than %s days ago.\n" +msgstr "§R°£ %s ¤Ñ«e©Ò¦³¤w¶×¥X/¤w¤ä¥Iªº¸ê®Æ.\n" + +#: lib/TimeForm.php:127 lib/TimeForm.php:210 lib/api.php:85 +msgid "Description" +msgstr "´y­z" + +#: lib/Search.php:32 +msgid "Do not include entries after" +msgstr "¤£­n¥]¬A¤§«áªº¬ö¿ý" + +#: lib/Search.php:30 +msgid "Do not include entries before" +msgstr "¤£­n¥]¬A¤§«eªº¬ö¿ý" + +#: admin.php:127 admin.php:218 +msgid "Edit Client Settings" +msgstr "½s¿è«È¤áªº³]©w" + +#: admin.php:119 admin.php:177 +msgid "Edit Client Settings, Step 2" +msgstr "½s¿è«È¤áªº³]©w, ¨BÆJ 2" + +#: lib/api.php:153 lib/api.php:154 +msgid "Edit Entry" +msgstr "½s¿è¬ö¿ý" + +#: admin.php:72 admin.php:216 +msgid "Edit Job Type" +msgstr "½s¿è¾·~«¬ºA" + +#: admin.php:77 +msgid "Edit Job Type, Step 2" +msgstr "½s¿è¾·~«¬ºA, ¨BÆJ 2" + +#: admin.php:100 +msgid "Edit job type" +msgstr "½s¿è¾·~«¬ºA" + +#: admin.php:152 +msgid "Edit job type, Step 2" +msgstr "½s¿è¾·~«¬ºA, ¨BÆJ 2" + +#: lib/TimeForm.php:191 lib/api.php:63 +msgid "Employee" +msgstr "­û¤u" + +#: lib/Search.php:18 +msgid "Employees" +msgstr "­û¤u" + +#: entry.php:61 lib/TimeForm.php:82 +msgid "Enter Time" +msgstr "¿é¤J®É¶¡" + +#: lib/TimeForm.php:83 +msgid "Enter my time" +msgstr "¿é¤J§Úªº®É¶¡" + +#: lib/Search.php:130 +msgid "Export Search Results" +msgstr "¶×¥X·j´Mµ²ªG" + +#: lib/Search.php:41 +msgid "Exported?" +msgstr "¤w¶×¥X ?" + +#: lib/TimeForm.php:120 lib/TimeForm.php:203 lib/api.php:73 +msgid "Hours" +msgstr "®É" + +#: lib/Admin.php:151 +msgid "" +"ID for this client when exporting data, if different from the name displayed " +"above." +msgstr "" + +#: lib/Admin.php:19 lib/Admin.php:66 lib/Admin.php:91 lib/TimeForm.php:119 +#: lib/TimeForm.php:202 lib/api.php:71 +msgid "Job Type" +msgstr "¾·~«¬ºA" + +#: lib/Search.php:27 +msgid "Job Types" +msgstr "¾·~«¬ºA" + +#: lib/Admin.php:41 +msgid "JobType Name" +msgstr "¾·~«¬ºAªº¦WºÙ" + +#: lib/Search.php:143 +msgid "Mark the time as exported?" +msgstr "±N¦¹®É¶¡¼Ð°O¦¨¤w¶×¥X ?" + +#: time.php:54 +msgid "My Time" +msgstr "§Úªº®É¶¡" + +#: time.php:75 +msgid "My Unsubmitted Time" +msgstr "§Ú©|¥¼°e¥Xªº®É¶¡" + +#: lib/Hermes.php:65 +msgid "My _Time" +msgstr "§Úªº®É¶¡" + +#: lib/Admin.php:87 lib/Search.php:37 lib/Search.php:142 lib/TimeForm.php:123 +#: lib/TimeForm.php:206 lib/api.php:46 +msgid "No" +msgstr "§_" + +#: time.php:36 +msgid "No timeslices were selected to submit." +msgstr "°e¥X®É¨S¦³¿ï¾Ü®É¬q." + +#: lib/api.php:189 +msgid "Non-billable Hours" +msgstr "¥¼¤ä¥I®É¼Æ." + +#: lib/Search.php:134 +msgid "QuickBooks (.iif)" +msgstr "" + +#: lib/Admin.php:94 +msgid "Really delete this job type? This may cause data problems!!" +msgstr "½T©w­n§R°£¦¹Â¾·~«¬ºA? ³o»ò§@¦³¥i¯à³y¦¨¸ê®Æ¤Wªº°ÝÃD!!" + +#: lib/Search.php:14 +msgid "Search For Time" +msgstr "·j´M®É¶¡" + +#: search.php:104 lib/api.php:105 +msgid "Search Results" +msgstr "·j´Mµ²ªG" + +#: search.php:67 +msgid "Search for Time" +msgstr "·j´M®É¶¡" + +#: lib/Admin.php:146 lib/TimeForm.php:93 lib/TimeForm.php:163 +msgid "See Attached Timesheet" +msgstr "°Ñ¾\ªþ¥[ªº®É¶¡¬ö¿ý¥d" + +#: lib/Search.php:136 +msgid "Select the export format" +msgstr "¿ï¾Ü¶×¥X®æ¦¡" + +#: lib/Admin.php:146 +#, php-format +msgid "" +"Should users enter descriptions of their timeslices for this client? If not, " +"the description will automatically be \"%s\"." +msgstr "" +"¨Ï¥ÎªÌ¬O§_À³¸Ó¬°¦¹«È¤á¿é¤J¥L­Ìªº®É¬q´y­z ? ¦pªG¤£¬O,´y­z±N¦Û°Ê¥H\"%s\"¥N´À." + +#: templates/time/form-footer.html:1 +msgid "Submit Selected Time" +msgstr "°e¥X©Ò¿ï¾Üªº®É¶¡" + +#: lib/Search.php:38 +msgid "Submitted?" +msgstr "¤w°e¥X ?" + +#: lib/Search.php:133 +msgid "Tab-Separated Variable (.tsv,.txt)" +msgstr "" + +#: admin.php:171 +msgid "The client settings have been modified." +msgstr "«È¤áªº³]©w¤w­×§ï." + +#: admin.php:48 +#, php-format +msgid "The job type '%s' has been added." +msgstr "¾·~«¬ºA '%s' ¤w·s¼W." + +#: admin.php:193 +msgid "The job type has been deleted." +msgstr "¾·~«¬ºA '%s' ¤w§R°£." + +#: admin.php:144 +msgid "The job type has been modified." +msgstr "¾·~«¬ºA¤w­×§ï." + +#: admin.php:198 +msgid "The job type was not deleted." +msgstr "¾·~«¬ºA¥¼§R°£." + +#: search.php:29 time.php:26 +msgid "The time entry was successfully deleted." +msgstr "®É¶¡¬ö¿ý¤w§R°£§¹¦¨." + +#: search.php:48 +msgid "The timeslice was successfully updated." +msgstr "®É¬q¤wÅܧ󧹦¨." + +#: lib/Admin.php:116 +msgid "There are no clients to edit" +msgstr "¨S¦³«È¤á¥i¨Ñ½s¿è" + +#: lib/TimeForm.php:52 +msgid "There are no clients which you have access to." +msgstr "§A¥Ø«e©|¥¼¦s¨ú¥ô¦ó«È¤á." + +#: lib/TimeForm.php:39 +msgid "There are no job types configured." +msgstr "¥¼³]©w¥ô¦óªºÂ¾·~«¬ºA." + +#: lib/Admin.php:38 +msgid "There are no job types to edit" +msgstr "¥¼½s¿è¥ô¦óªºÂ¾·~«¬ºA" + +#: admin.php:50 +#, php-format +msgid "There was an error adding the job type: %s." +msgstr "·s¼W¾·~«¬ºA: %s ®Éµo¥Í¤@­Ó¿ù»~." + +#: admin.php:195 +#, php-format +msgid "There was an error deleting the job type: %s." +msgstr "§R°£Â¾·~«¬ºA: %s ®Éµo¥Í¤@­Ó¿ù»~." + +#: search.php:27 time.php:24 +#, php-format +msgid "There was an error deleting the time: %s" +msgstr "§R°£®É¶¡: %s ®Éµo¥Í¤@­Ó¿ù»~." + +#: admin.php:169 +#, php-format +msgid "There was an error editing the client settings: %s." +msgstr "½s¿è«È¤á³]©w: %s ®Éµo¥Í¤@­Ó¿ù»~." + +#: admin.php:146 +#, php-format +msgid "There was an error editing the job type: %s." +msgstr "½s¿è¾·~«¬ºA: %s ®Éµo¥Í¤@­Ó¿ù»~." + +#: entry.php:33 search.php:46 +#, php-format +msgid "There was an error storing your timesheet: %s" +msgstr "Àx¦s®É¶¡¬ö¿ý¥d: %s ®Éµo¥Í¤@­Ó¿ù»~" + +#: time.php:44 +#, php-format +msgid "There was an error submitting your time: %s" +msgstr "°e¥X®É¶¡: %s ®Éµo¥Í¤@­Ó¿ù»~" + +#: lib/Admin.php:136 +msgid "This is not a valid client." +msgstr "³o¤£¬O¤@­Ó¦³®Äªº«È¤á." + +#: lib/Admin.php:58 +msgid "This is not a valid job type." +msgstr "³o¤£¬O¤@­Ó¦³®ÄªºÂ¾·~«¬ºA." + +#: lib/api.php:29 +msgid "Time Review Screen" +msgstr "®É¶¡¦^ÅUµe­±" + +#: lib/api.php:193 +msgid "Total Hours" +msgstr "Á`®É¼Æ" + +#: lib/TimeForm.php:153 +msgid "Update Submitted Time" +msgstr "Åܧó°e¥Xªº®É¶¡" + +#: lib/TimeForm.php:79 +msgid "Update Time" +msgstr "Åܧó®É¶¡" + +#: lib/TimeForm.php:80 +msgid "Update my time" +msgstr "Åܧó§Úªº®É¶¡" + +#: lib/TimeForm.php:154 +msgid "Update time" +msgstr "Åܧó®É¶¡" + +#: lib/Admin.php:87 lib/Search.php:36 lib/Search.php:141 lib/TimeForm.php:123 +#: lib/TimeForm.php:206 lib/api.php:45 +msgid "Yes" +msgstr "¬O" + +#: entry.php:28 +msgid "Your time was successfully entered." +msgstr "§Aªº®É¶¡¤w¿é¤J§¹¦¨." + +#: time.php:46 +msgid "Your time was successfully submitted." +msgstr "§Aªº®É¶¡¤w°e¥X§¹¦¨." + +#: entry.php:25 +msgid "Your time was successfully updated." +msgstr "§Aªº®É¶¡¤wÅܧ󧹦¨." + +#: lib/Hermes.php:76 +msgid "_Admin" +msgstr "ºÞ²z_A" + +#: lib/Hermes.php:66 +msgid "_Enter Time" +msgstr "¿é¤J®É¶¡_E" + +#: lib/Hermes.php:71 +msgid "_Print" +msgstr "¦C¦L_P" + +#: lib/Hermes.php:67 +msgid "_Search" +msgstr "·j´M_S" diff --git a/hermes/scripts/.htaccess b/hermes/scripts/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/hermes/scripts/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/hermes/scripts/Sandals.wdgt/Default.png b/hermes/scripts/Sandals.wdgt/Default.png new file mode 100644 index 0000000000000000000000000000000000000000..8180b3feb27e28b86e4f4ea19e4fec306ed488c7 GIT binary patch literal 843 zcmeAS@N?(olHy`uVBq!ia0y~yU|a&kOdL!=5xZ=Yi9m|6ILO_JVcj{Imp~3%lDE4H z!+#K5uy^@npa^GyM`SSr1Gg{;GcwGYBLNg-FY)wsWxv79Eym1LKS4zfC?s3r8d2h$ zpPQSSSHj?2l$uzQnxasiS(2d;l98(5?&%xwK1DT;fq`j}r;B4q#jUs30(lt}c$^*E zZgd__nP}+rPUXwvrB`dk4!qyS$*_@Gz#5Hkc*Agn50k*65~vZI$|HPGGaI&t3TZRU zlWn-c*nvtUu`84@U=V1Epj>P!70NKp1S`id6Rew3g9m{Vfc_n3emk&)yQ+t+Ec=oC Rc3`q*@O1TaS?83{1OS{j{X75w literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/Icon.png b/hermes/scripts/Sandals.wdgt/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e7e8a85269a0ff37da9eeb9973ebb4749ae4f900 GIT binary patch literal 4797 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 VH}}T#-w%h$%*e{{xxwvw{|5>J_|yOZ literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/Info.plist b/hermes/scripts/Sandals.wdgt/Info.plist new file mode 100644 index 000000000..10636d421 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/Info.plist @@ -0,0 +1,31 @@ + + + + + + AllowMultipleInstances + + AllowNetworkAccess + + AllowSystem + + CFBundleDisplayName + Horde Sandals + CFBundleIdentifier + org.horde.widget.sandals + CFBundleName + Horde Sandals + CFBundleShortVersionString + 0.0.1 + CFBundleVersion + 0.0.1 + CloseBoxInsetX + 5 + CloseBoxInsetY + 5 + MainHTML + Sandals.html + Plugin + KeychainPlugIn.widgetplugin + + diff --git a/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Info.plist b/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Info.plist new file mode 100644 index 000000000..b11b89893 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Info.plist @@ -0,0 +1,23 @@ + + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + KeychainPlugIn + CFBundleIdentifier + org.horde.dashboard.KeychainPlugin + CFBundleInfoDictionaryVersion + 1.0 + CFBundleName + KeychainPlugIn + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/MacOS/KeychainPlugIn b/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/MacOS/KeychainPlugIn new file mode 100755 index 0000000000000000000000000000000000000000..66a52ab58a3085e877ecd1cc85462e6491fb987f GIT binary patch literal 46724 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 literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Resources/English.lproj/InfoPlist.strings b/hermes/scripts/Sandals.wdgt/KeychainPlugIn.widgetplugin/Contents/Resources/English.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..7934d23c1ab7839dfd2c09d5eb7dcf82210ac4d0 GIT binary patch literal 276 zcmZvW%?`m}5Jm6WQ#4jI(FzL*v9hT|MDPMtZT+@QTZD(lF=8i^d~?5 + + + + + + + + + + Sandals: Horde Timetracking + + + + + + + + + + + +

+
+
+ +
+
+ Horde Time Entry +
+ +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    * Date + + + Calendar +
    * Client + There are no clients + which you have access to. +
    * Job Type + There are no job + types configured. +
    * Cost Object +
    * Hours
    * Billable?
    * Description +
    Additional Notes +
    +
    + +
    + + + + +
    +
    + +
    +
    +
    +
    + + + + diff --git a/hermes/scripts/Sandals.wdgt/lib/Sandals.js b/hermes/scripts/Sandals.wdgt/lib/Sandals.js new file mode 100644 index 000000000..d7c5e5651 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/lib/Sandals.js @@ -0,0 +1,794 @@ +/** + * $Horde: hermes/scripts/Sandals.wdgt/lib/Sandals.js,v 1.5 2008/03/11 22:57:38 bklang Exp $ + * This file is part of Sandals.wdgt, distributed with the Hermes application. + * Hermes is part of the Horde Project (http://www.horde.org/) + * + * Sandals is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Sandals is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Horde; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright 2006-2008 Ben Klang + * + * serialize() based on phpSerialize + * phpSerialize() and getObjectClass() are courtesy of: + * http://magnetiq.com/2006/07/30/php-style-serialization-of-javascript-objects/ + * + * unserialize() based on PHP_Unserialize + * PHP_Unserialize (C) 2005 Richard Heyes + * + * @author Ben Klang + */ + +// Global variables +var gDoneButton; +var gInfoButton; +var currentArea = false; +// XML-RPC object +var hermes; +// Form data arrays +var clients; +var jobTypes; +var costObjects; +// Boolean: keep track of whether we need to force a refresh of the server data +var prefsChanged; + +// Connection details for Horde instance +var url = ''; +var username = ''; +var password = ''; + + +if (window.widget) { + //widget.onremove = onremove; + //widget.onhide = onhide; + widget.onshow = onshow; +} +// +//function onremove() +//{ +// alert("Remove"); +//} +// +//function onhide() +//{ +// alert("Hide"); +//} + +/** + * Seed the UI with the current date each time Dashboard is shown + */ +function onshow() +{ + var date = new Date(); + document.getElementById('date_month').value = date.getMonth() + 1; + document.getElementById('date_day').value = date.getDate(); + document.getElementById('date_year').value = date.getFullYear(); + document.getElementById('hours').focus(); +} + +/** + * Create the glowing "i" button to access the back panel + */ +function setup() +{ + try { + var front = document.getElementById('front'); + var infoButton = document.getElementById('infoButton'); + var back = document.getElementById('back'); + var doneButton = document.getElementById('doneButton'); + // Create the Info and Done buttons + gDoneButton = new AppleGlassButton(doneButton, "Done", hidePrefs); + gInfoButton = new AppleInfoButton(infoButton, front, "black", "white", showPrefs); + onshow(); + + // Try to load saved preferences + if (window.widget) { + url = widget.preferenceForKey(widget.identifier + '@url') || ''; + username = widget.preferenceForKey(widget.identifier + '@username') || ''; + + // Try to use Keychain to read the password information. + // This seems to work on OS X 10.5 only + if (widget.KeychainPlugIn && url != '') { + urlparts = splitURL(url); + password = KeychainPlugIn.getPassword(username, + urlparts.serverName, + urlparts.serverPath) || ''; + } else { + // Fall back to storing the password in preferences + password = widget.preferenceForKey(widget.identifier + '@password') || ''; + } + document.getElementById('horde_url').value = url; + document.getElementById('horde_username').value = username; + document.getElementById('horde_password').value = password; + + } + // Disable the spinners + document.getElementById('spinner-front').style.display = 'none'; + document.getElementById('spinner-back').style.display = 'none'; + } catch(e) { + // Disable the spinners + document.getElementById('spinner-front').style.display = 'none'; + document.getElementById('spinner-back').style.display = 'none'; + showMsg(e) + } + +} + +/** + * Flip to the back panel and show configuration options + */ +function showPrefs() +{ + var front = document.getElementById("front"); + var back = document.getElementById("back"); + + if (window.widget) { + widget.prepareForTransition("ToBack"); + } + + front.style.display="none"; + back.style.display="block"; + + if (window.widget) { + setTimeout ('widget.performTransition();', 0); + } +} + +/** + * This function will be called to flip back to the front screen. + * First check the user-supplied data. Then attempt to load the + * server data from Horde. If no errors occur flip back to the + * front UI. On error, show the message and do not flip back. + */ +function hidePrefs() +{ + // Clear any error messages + showMsg(); + + // Enable the spinners + document.getElementById('spinner-front').style.display = 'inline'; + document.getElementById('spinner-back').style.display = 'inline'; + + try { + validateAndStore(); + // If our configuration changed refresh the server data + if (prefsChanged) { + refreshServerData(); + } + } catch(e) { + // Disable the spinners and show the error + document.getElementById('spinner-front').style.display = 'none'; + document.getElementById('spinner-back').style.display = 'none'; + showMsg(e); + return false; + } + + var front = document.getElementById("front"); + var back = document.getElementById("back"); + + // Disable the spinners + document.getElementById('spinner-front').style.display = 'none'; + document.getElementById('spinner-back').style.display = 'none'; + + // Flip back to the front + if (window.widget) { + widget.prepareForTransition("ToFront"); + } + + front.style.display="block"; + back.style.display="none"; + + if (window.widget) { + setTimeout('widget.performTransition();', 0); + } + +} + +/** + * Check the URL, username, and password supplied by the user. + * Store this information in the widget preferences. + * Also determine whether the preferences have changed + * since the last time they were stored. This may indicate that + * a refresh of server data is required. + * Finally, construct a URL from that data and configure the + * XML-RPC handler. + */ +function validateAndStore() +{ + url = document.getElementById("horde_url").value || ''; + username = document.getElementById("horde_username").value || ''; + password = document.getElementById("horde_password").value || ''; + if (url == '' || username == '' || password == '') { + //throw('You must supply the full URL to Horde\'s rpc.php as well as a valid username and password to continue.'); + throw('Horde connection not yet configured.'); + } + + // Make sure the url has a schema. Default to non-SSL + if (url.indexOf('http') != 0) { + url = "http://"+url; + } + + // Determine if the Horde instance (url + username + password) changed + prefsChanged = true; + if (window.widget) { + var oldurl = widget.preferenceForKey(widget.identifier + '@url'); + var oldusername = widget.preferenceForKey(widget.identifier + '@username'); + var oldpassword = widget.preferenceForKey(widget.identifier + '@password'); + + if (url == oldurl && + username == oldusername && + password == oldpassword) { + + // Config data has not changed. + prefsChanged = false; + } + + // Store changed preferences + if (prefsChanged) { + widget.setPreferenceForKey(url, widget.identifier + "@url"); + widget.setPreferenceForKey(username, widget.identifier + "@username"); + // Try to use Keychain to store the password. + // This seems to work on OS X 10.5 only + if (widget.KeychainPlugIn) { + urlparts = splitURL(url); + KeychainPlugIn.addPassword(password, username, urlparts.serverName, + urlparts.serverPath); + } else { + // Fall back to preference storage + widget.setPreferenceForKey(password, widget.identifier + "@password"); + } + } + } + + // Will hold fully-qualified URL including username and password + var fqurl = ''; + // SSL flag + var ssl = false; + // Strip off 'http://' if it is there + if (url.indexOf('http://') == 0) { + fqurl = url.substr(7); + ssl = false; + } else if (url.indexOf('https://') == 0) { + fqurl = url.substr(8); + ssl = true; + } else { + fqurl = url; + } + + var creds = ''; + // Build the URL + if (username) { + creds += escape(username); + if (password) + creds += ':' + escape(password); + creds += '@'; + } + + if (ssl) { + fqurl = 'https://' + creds + fqurl; + } else { + fqurl = 'http://' + creds + fqurl; + } + + hermes = XMLRPC.getService(fqurl); + hermes.add("system.listMethods", "listMethods"); + hermes.add("time.listJobTypes", "listJobTypes"); + hermes.add("time.listClients", "listClients"); + hermes.add("time.listCostObjects", "listCostObjects"); + hermes.add("time.recordTime", "recordTime"); + XMLRPC.onerror = function(e){ showMsg(e); } + + return true; +} + +/** + * Force a refresh of the server data. This is initiated by a + * button press on the back panel. + */ +function forceRefresh() +{ + // Clear any old errors + showMsg(); + try { + validateAndStore(); + refreshServerData(); + } catch(e) { showMsg(e); } +} + +/** + * Refresh the current cache of server data, including the list of + * clients, job types, and cost objects. This method assumes + * a valid XML-RPC object has been instantiated. + * TODO: Spinner added but since this method is called synchronously it is + * never visible. Fix vcXMLRPC to use XMLHttpRequest and the onreadystatechange + * callback. + */ +function refreshServerData() +{ + try { + clients = hermes.listClients(); + jobTypes = hermes.listJobTypes(); + // TODO: use listMethods and enumerate all Horde apps providing a + // listCostObjects method. For now, we'll just use the deliverables + // configured in Hermes. + // FIXME: Iterate over clients and call once for each client. Yes, + // this is heavy-handed (and slow!) but it appears to be the only way + // to get a list of deliverables valid for each client. The + // alternative would be to change the information returned by the + // listCostObjects API. Maybe for Horde 4? + costObjects = hermes.listCostObjects(new Array()); + } catch(e) { + // vcXMLRPC doesn't do a good job of catching 401 so we do it manually. + // 401 (Unauthorized) is the proper error code when a username or + // password is incorrect. This is indeed what you get when tested in + // Safari. For some reason, when running under Dashboard, the status + // is set to -1012. My best guess is related to teh fact that + // 1012 is the error code for XML_RNGP_DEFINE_EMPTY in libxml. + // If that is not where the 1012 comes from, I have no idea. + if (e.http_status == 401 || e.http_status == -1012) { + throw "Invalid username or password."; + } + throw e; + } + + // TODO: Cache this information in Dashboard prefs + //if (window.widget) { + // widget.setPreferenceForKey(serialize(clients), + // widget.identifier + "@clients"); + // widget.setPreferenceForKey(serialize(jobTypes), + // widget.identifier + "@jobTypes"); + //} + + // + // Refresh the client list drop-down + // + var noClientsWarning = document.getElementById('noClients'); + var clientSelector = document.getElementById('client'); + + // Since the select-boxes are slightly taller than plain text, enlarge the + // window slightly so as not to cut off the bottom edge of the buttons. + if (window.widget && !clientSelector.firstChild) { + window.resizeBy(0, 4); + } + + while (clientSelector.firstChild) { + clientSelector.removeChild(clientSelector.firstChild); + } + for (client in clients) { + // FIXME: This is a hack + // Ignore the inherited toXMLRPC from vcXMLRPC + if (client == 'toXMLRPC') { + continue; + } + element = document.createElement('option'); + element.value = client; + element.innerHTML = clients[client]; + clientSelector.appendChild(element); + } + // If we have a valid list, show the selectbox. + if (clientSelector.firstChild) { + noClientsWarning.style.display = 'none'; + clientSelector.style.display = ''; + } else { + // ...otherwise show the "no clients" error + noClientsWarning.style.display = 'inline'; + clientSelector.style.display = 'none'; + } + + // + // Refresh the job types drop-down + // + var noJobTypesWarning = document.getElementById('noJobTypes'); + var jobTypeSelector = document.getElementById('jobType'); + while (jobTypeSelector.firstChild) { + jobTypeSelector.removeChild(jobTypeSelector.firstChild); + } + while (jobType = jobTypes.pop()) { + element = document.createElement('option'); + element.value = jobType.id; + element.innerHTML = jobType.name; + jobTypeSelector.appendChild(element); + } + // If we have a valid list, show the selectbox. + if (jobTypeSelector.firstChild) { + noJobTypesWarning.style.display = 'none'; + jobTypeSelector.style.display = ''; + } else { + // ...otherwise show the "no jobTypess" error + noJobTypesWarning.style.display = 'inline'; + jobTypeSelector.style.display = 'none'; + } + + // + // Refresh the cost objects drop-down + // + var costObjectSelector = document.getElementById('costObject'); + while (costObjectSelector.firstChild) { + costObjectSelector.removeChild(costObjectSelector.firstChild); + } + // Seed the default value + element = document.createElement('option'); + element.value = ''; + element.innerHTML = '--- No Cost Object ---'; + costObjectSelector.appendChild(element); + while (costObjectCategory = costObjects.pop()) { + // Create the category header + element = document.createElement('option'); + element.value = ''; + element.innerHTML = "---" + costObjectCategory.category + "---"; + costObjectSelector.appendChild(element); + while (costObject = costObjectCategory.objects.pop()) { + if (costObject.active) { + element = document.createElement('option'); + element.value = costObject.id; + element.innerHTML = costObject.name; + costObjectSelector.appendChild(element); + } + } + } +} + +function recordTime() +{ + try { + // date will be of the form YYYYMMDD for passing to + // the Horde_Date constructor + var date = ''; + date += document.getElementById('date_year').value; + var month = document.getElementById('date_month').value; + // zero-pad single-digit values + if (month < 10) { + date += '0'; + } + date += month; + var mday = document.getElementById('date_day').value; + if (mday < 10) { + date += '0'; + } + date += mday; + + var client = document.getElementById('client').value; + var jobType = document.getElementById('jobType').value; + var costObject = document.getElementById('costObject').value; + var hours = document.getElementById('hours').value; + var billable = document.getElementById('billable').value; + var description = document.getElementById('description').value; + var note = document.getElementById('note').value; + + hermes.recordTime(date, client, jobType, costObject, hours, + billable, description, note); + } catch(e) { + showMsg(e) + } +} + +function showMsg(message, level) +{ + if (message && !level) { + level = 'warning'; + } + + var prefMsgBox = document.getElementById('prefMsgBox'); + var msgBox = document.getElementById('msgBox'); + if (!message) { + // Clear the message box + // Assume the msgBox and prefMsgBox have the same number of children. + // This also allows consistent window resizing + while (msgBox.hasChildNodes()) { + prefMsgBox.removeChild(prefMsgBox.firstChild); + msgBox.removeChild(msgBox.firstChild); + if (window.widget) { + window.resizeBy(0, -27); + } + } + } else { + // Create an li entry for the error message + // and display the icon with the message + if (window.widget) { + window.resizeBy(0, 27); + } + msgbox = document.createElement('li'); + msgico = document.createElement('img'); + msgico.setAttribute('src', 'themes/graphics/alerts/'+level+'.png'); + prefMsgBox.appendChild(msgbox); + prefMsgBox.lastChild.appendChild(msgico); + prefMsgBox.lastChild.appendChild(document.createTextNode(message)); + + msgbox = document.createElement('li'); + msgico = document.createElement('img'); + msgico.setAttribute('src', 'themes/graphics/alerts/'+level+'.png'); + msgBox.appendChild(msgbox); + msgBox.lastChild.appendChild(msgico); + msgBox.lastChild.appendChild(document.createTextNode(message)); + } + return true; +} + +function showArea(area) +{ + try { + currentArea.style['display'] = 'hidden'; + } catch(e) {} + currentArea = document.getElementById(area); + currentArea.style['display'] = 'block'; +} + +/** + * Split a URL into server name and path + */ +function splitURL(url) +{ + if (!url) { + return false; + } + var m = url.match(/\w+:\/\/([^\/]*)\/(.*)/); + if (!m.length || m.length != 3) { + return false; + } + return { serverName: m[1], serverPath: m[2] }; +} + +function resetTimeForm() +{ + document.getElementById('hours').value=''; + document.getElementById('description').value=''; + document.getElementById('note').value=''; + showMsg(); +} + +/** + * Returns the class name of the argument or 'GenericObject' if + * it the object provenance cannot be determined. + */ +function getObjectClass(obj) +{ + if (obj && obj.constructor && obj.constructor.toString) + { + var arr = obj.constructor.toString().match( + /function\s*(\w+)/); + + if (arr && arr.length == 2) + { + return arr[1]; + } + } + + //return undefined; + return 'GenericObject'; +} + +/** + * Serializes the given argument, PHP-style. + * + * The type mapping is as follows: + * + * JavaScript Type PHP Type + * --------------- -------- + * Number Integer or Decimal + * String String + * Boolean Boolean + * Array Array + * Object Object + * undefined Null + * + * The special JavaScript object null also becomes PHP Null. + * This function may not handle associative arrays or array + * objects with additional properties well. + */ +function serialize(val) +{ + switch (typeof(val)) + { + case "number": + return (Math.floor(val) == val ? "i" : "d") + ":" + + val + ";"; + case "string": + return "s:" + val.length + ":\"" + val + "\";"; + case "boolean": + return "b:" + (val ? "1" : "0") + ";"; + case "object": + if (val == null) + { + return "N;"; + } + else if ("length" in val) + { + var idxobj = { idx: -1 }; + + return "a:" + val.length + ":{" + val.map( + function (item) + { + this.idx++; + + var ser = serialize(item); + + return ser ? + serialize(this.idx) + ser : + false; + }, idxobj).filter( + function (item) + { + return item; + }).join("") + "}"; + } + else + { + var class_name = getObjectClass(val); + + if (class_name == undefined) + { + return false; + } + + var props = new Array(); + + for (var prop in val) + { + var ser = serialize(val[prop]); + + if (ser) + { + props.push(serialize(prop) + ser); + } + } + return "O:" + class_name.length + ":\"" + + class_name + "\":" + props.length + ":{" + + props.join("") + "}"; + } + case "undefined": + return "N;"; + } + + return false; +} + +/** + * Unserializes a PHP serialized data type. Currently handles: + * o Strings + * o Integers + * o Doubles + * o Arrays + * o Booleans + * o NULL + * o Objects + * + * @param string input The serialized PHP data + * @return mixed The resulting datatype + */ +function unserialize(input) +{ + var result = PHP_Unserialize_(input); + alert(result.length); + return result[0]; +} + + +/** + * Function which performs the actual unserializing + * + * @param string input Input to parse + */ +function PHP_Unserialize_(input) +{ + var length = 0; + + switch (input.charAt(0)) { + /** + * Array + */ + case 'a': + length = PHP_Unserialize_GetLength(input); + input = input.substr(String(length).length + 4); + + var arr = new Array(); + var key = null; + var value = null; + + for (var i=0; i/g, "\n").split("\n"); + for (var i = 0; i < lines.length; ++i) { + nicetitle_length = Math.max(nicetitle_length, lines[i].length); + } + + var h_pixels = nicetitle_length * 7; + var t_pixels = nicetitle_length * 10; + + var w, h; + if (h_pixels > STD_WIDTH) { + w = h_pixels; + } else if (STD_WIDTH > t_pixels) { + w = t_pixels; + } else { + w = STD_WIDTH; + } + + // Make sure all of the tooltip is visible + var left = pos[0] + 20, + innerWidth = window.innerWidth || document.documentElement.clientWidth || document.body.offsetWidth, + pageXOffset = window.pageXOffset || document.documentElement.scrollLeft; + if (innerWidth && ((left + w) > (innerWidth + pageXOffset))) { + left = innerWidth - w - 40 + pageXOffset; + } + if (document.body.scrollWidth && ((left + w) > (document.body.scrollWidth + pageXOffset))) { + left = document.body.scrollWidth - w - 25 + pageXOffset; + } + + d.id = 'toolTip'; + d.style.left = left + 'px'; + d.style.width = Math.min(w, MAX_WIDTH) + 'px'; + d.style.top = (pos[1] + 10) + 'px'; + d.style.display = ''; + + document.getElementsByTagName('body')[0].appendChild(d); + ToolTips.current = d; + + if (typeof ToolTips_Option_Windowed_Controls != 'undefined') { + var iframe = document.getElementById('iframe_tt'); + if (iframe == null) { + iframe = document.createElement(''); + document.getElementsByTagName('body')[0].appendChild(iframe); + } + iframe.style.width = d.offsetWidth; + iframe.style.height = d.offsetHeight; + iframe.style.top = d.style.top; + iframe.style.left = d.style.left; + iframe.style.position = 'absolute'; + iframe.style.display = 'block'; + d.style.zIndex = 100; + iframe.style.zIndex = 99; + } + } catch (e) {} + } + +}; + +/** + * Return the [x,y] position of the mouse. + */ +function mousePos(event) +{ + return [event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)), + event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop))]; +} +/** + * Return the [x,y] position of an element. + */ +function eltPos(elt) +{ + if (elt.offsetParent) { + for (posX = 0, posY = 0; elt.offsetParent; elt = elt.offsetParent) { + posX += elt.offsetLeft; + posY += elt.offsetTop; + } + return [posX, posY]; + } else { + return [elt.x, elt.y]; + } +} + +/** + * Add an event listener as long as the browser supports it. Different + * browsers still handle these events slightly differently; in + * particular avoid using "this" in event functions. + * + * @author Scott Andrew + * @author Chuck Hagenbuch + */ +function addEvent(obj, evType, fn) +{ + if (obj.addEventListener) { + obj.addEventListener(evType, fn, true); + return true; + } else if (obj.attachEvent) { + var r = obj.attachEvent('on' + evType, fn); + EventCache.add(obj, evType, fn); + return r; + } else { + return false; + } +} + +var EventCache = function() +{ + var listEvents = []; + + return { + listEvents: listEvents, + + add: function(node, sEventName, fHandler, bCapture) + { + listEvents.push(arguments); + }, + + flush: function() + { + var i, item; + for (i = listEvents.length - 1; i >= 0; i = i - 1) { + item = listEvents[i]; + + if (item[0].removeEventListener) { + item[0].removeEventListener(item[1], item[2], item[3]); + }; + + /* From this point on we need the event names to be + * prefixed with 'on'. */ + if (item[1].substring(0, 2) != 'on') { + item[1] = 'on' + item[1]; + } + + if (item[0].detachEvent) { + item[0].detachEvent(item[1], item[2]); + } + + item[0][item[1]] = null; + } + } + }; +}(); + +if (document.createElement && document.getElementsByTagName) { + addEvent(window, 'load', ToolTips.attachBehavior); + addEvent(window, 'unload', ToolTips.out); + addEvent(window, 'unload', EventCache.flush); +} diff --git a/hermes/scripts/Sandals.wdgt/lib/open_calendar.js b/hermes/scripts/Sandals.wdgt/lib/open_calendar.js new file mode 100644 index 000000000..9f7223af6 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/lib/open_calendar.js @@ -0,0 +1,481 @@ +/** + * Horde Calendar javascript widget and utility functions. + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * $Horde: hermes/scripts/Sandals.wdgt/lib/open_calendar.js,v 1.3 2009/01/06 17:50:10 jan Exp $ + */ + +/** + * Backwards-compatible function that wraps access to Horde_Calendar + */ +function openCalendar(imgId, target, callback) +{ + var date = new Date(); + var y, m, d; + + if (document.getElementById(target + '[year]')) { + y = document.getElementById(target + '[year]').value; + m = document.getElementById(target + '[month]').value; + d = document.getElementById(target + '[day]').value; + } else if (document.getElementById(target + '_year')) { + y = document.getElementById(target + '_year').value; + m = document.getElementById(target + '_month').value; + d = document.getElementById(target + '_day').value; + } + + if (y && m && d) { + date = new Date(y, m - 1, d); + } + + Horde_Calendar.openDate = date.getTime(); + Horde_Calendar.draw(Horde_Calendar.openDate, imgId, target, callback); +} + +/** + * Configuration settings for Horde_Calendar. + */ +var Horde_Calendar_Vars = { + firstDayOfWeek: 1 +}; + +/** + * Translations for strings used in Horde_Calendar. + */ +var Horde_Calendar_Text = { + + /** + * Days of the week + */ + weekdays: [ + 'Su', + 'Mo', + 'Tu', + 'We', + 'Th', + 'Fr', + 'Sa' + ], + + /** + * Month names + */ + months: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ] + +}; + +/** + * Main Horde_Calendar object for rendering javascript calendars. + */ +var Horde_Calendar = { + + date: null, + target: null, + openDate: null, + + /** + * Days in the month (month is a zero-indexed javascript month) + */ + daysInMonth: function(month, year) + { + switch (month) { + case 3: + case 5: + case 8: + case 10: + return 30; + break; + + case 1: + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) { + return 29; + } else { + return 28; + } + break; + + default: + return 31; + break; + } + }, + + weeksInMonth: function(month, year) + { + var firstOfMonth = (new Date(year, month, 1)).getDay(); + var firstWeekDays, weeks; + if (Horde_Calendar_Vars.firstDayOfWeek == 1 && firstOfMonth == 0) { + firstWeekDays = 7 - firstOfMonth + Horde_Calendar_Vars.firstDayOfWeek; + weeks = 1; + } else if (Horde_Calendar_Vars.firstDayOfWeek == 0 && firstOfMonth == 6) { + firstWeekDays = 7 - firstOfMonth + Horde_Calendar_Vars.firstDayOfWeek; + weeks = 1; + } else { + firstWeekDays = Horde_Calendar_Vars.firstDayOfWeek - firstOfMonth; + weeks = 0; + } + firstWeekDays %= 7; + return Math.ceil((Horde_Calendar.daysInMonth(month, year) - firstWeekDays) / 7) + weeks; + }, + + draw: function(timestamp, imgId, target, callback) + { + var row, cell, img, link; + + Horde_Calendar.target = target; + if (typeof callback != 'function') { + callback = new Function(callback); + } + Horde_Calendar.callback = callback; + + Horde_Calendar.date = new Date(timestamp); + var month = Horde_Calendar.date.getMonth(); + var year = Horde_Calendar.date.getFullYear(); + + var startOfView; + var firstOfMonth = (new Date(year, month, 1)).getDay(); + var daysInView = Horde_Calendar.weeksInMonth(month, year) * 7; + var daysInMonth = Horde_Calendar.daysInMonth(month, year); + + if (Horde_Calendar_Vars.firstDayOfWeek == 0) { + startOfView = 1 - firstOfMonth; + + // We may need to adjust the number of days in the view if + // we're starting weeks on Sunday. + if (firstOfMonth == 0) { + //daysInView -= 7; + } + var lastOfMonth = new Date(year, month, daysInMonth); + lastOfMonth = lastOfMonth.getDay(); + if (lastOfMonth == 0) { + daysInView += 7; + } + } else { + // @TODO Adjust this for days other than Monday. + if (firstOfMonth == 0) { + startOfView = -5; + } else { + startOfView = 2 - firstOfMonth; + } + } + + var div = document.getElementById('goto'); + if (div.firstChild) { + div.removeChild(div.firstChild); + } + + var table = document.createElement('TABLE'); + var thead = document.createElement('THEAD'); + var tbody = document.createElement('TBODY'); + table.appendChild(thead); + table.appendChild(tbody); + table.className = 'calendarPopup'; + table.cellSpacing = 0; + + // Title bar. + row = document.createElement('TR'); + cell = document.createElement('TD'); + cell.colSpan = 7; + cell.className = 'rightAlign'; + link = document.createElement('A'); + link.href = '#'; + link.onclick = function() + { + var div = document.getElementById('goto'); + div.style.display = 'none'; + if (div.firstChild) { + div.removeChild(div.firstChild); + } + var iefix = document.getElementById('goto_iefix'); + if (iefix) { + iefix.style.display = 'none'; + } + return false; + } + link.appendChild(document.createTextNode('x')); + cell.appendChild(link); + row.appendChild(cell); + thead.appendChild(row); + + // Year. + row = document.createElement('TR'); + cell = document.createElement('TD'); + link = document.createElement('A'); + link.href = '#'; + link.innerHTML = '«'; + link.onclick = function() + { + newDate = new Date(Horde_Calendar.date.getFullYear() - 1, Horde_Calendar.date.getMonth(), 1); + Horde_Calendar.draw(newDate.getTime(), imgId, Horde_Calendar.target, Horde_Calendar.callback); + return false; + } + cell.appendChild(link); + row.appendChild(cell); + + cell = document.createElement('TD'); + cell.colSpan = 5; + cell.align = 'center'; + var y = document.createTextNode(year); + cell.appendChild(y); + row.appendChild(cell); + + cell = document.createElement('TD'); + link = document.createElement('A'); + link.href = '#'; + link.innerHTML = '»'; + link.onclick = function() + { + newDate = new Date(Horde_Calendar.date.getFullYear() + 1, Horde_Calendar.date.getMonth(), 1); + Horde_Calendar.draw(newDate.getTime(), imgId, Horde_Calendar.target, Horde_Calendar.callback); + return false; + } + cell.appendChild(link); + cell.className = 'rightAlign'; + row.appendChild(cell); + thead.appendChild(row); + + // Month name. + row = document.createElement('TR'); + cell = document.createElement('TD'); + link = document.createElement('A'); + link.href = '#'; + link.innerHTML = '«'; + link.onclick = function() + { + var newMonth = Horde_Calendar.date.getMonth() - 1; + var newYear = Horde_Calendar.date.getFullYear(); + if (newMonth == -1) { + newMonth = 11; + newYear -= 1; + } + newDate = new Date(newYear, newMonth, 1); + Horde_Calendar.draw(newDate.getTime(), imgId, Horde_Calendar.target, Horde_Calendar.callback); + return false; + } + cell.appendChild(link); + row.appendChild(cell); + + cell = document.createElement('TD'); + cell.colSpan = 5; + cell.align = 'center'; + var m = document.createTextNode(Horde_Calendar_Text.months[month]); + cell.appendChild(m); + row.appendChild(cell); + + cell = document.createElement('TD'); + cell.className = 'rightAlign'; + link = document.createElement('A'); + link.href = '#'; + link.innerHTML = '»'; + link.onclick = function() + { + newDate = new Date(Horde_Calendar.date.getFullYear(), Horde_Calendar.date.getMonth() + 1, 1); + Horde_Calendar.draw(newDate.getTime(), imgId, Horde_Calendar.target, Horde_Calendar.callback); + return false; + } + cell.appendChild(link); + row.appendChild(cell); + thead.appendChild(row); + + // Weekdays. + row = document.createElement('TR'); + for (var i = 0; i < 7; ++i) { + cell = document.createElement('TH'); + weekday = document.createTextNode(Horde_Calendar_Text.weekdays[(i + Horde_Calendar_Vars.firstDayOfWeek) % 7]); + cell.appendChild(weekday); + row.appendChild(cell); + } + thead.appendChild(row); + + // Cache today and open date. + var today = new Date(); + var today_year = today.getFullYear(); + var today_month = today.getMonth(); + var today_day = today.getDate(); + var open = new Date(Horde_Calendar.openDate); + var open_year = open.getFullYear(); + var open_month = open.getMonth(); + var open_day = open.getDate(); + + // Rows. + var count = 1; + for (var i = startOfView, i_max = startOfView + daysInView; i < i_max; ++i) { + if (count == 1) { + row = document.createElement('TR'); + } + + cell = document.createElement('TD'); + + if (i < 1 || i > daysInMonth) { + row.appendChild(cell); + + if (count == 7) { + tbody.appendChild(row); + count = 0; + } + + ++count; + continue; + } + + if (today_year == year && + today_month == month && + today_day == i) { + cell.className = 'today'; + } + if (open_year == year && + open_month == month && + open_day == i) { + if (cell.className.length) { + cell.className += ' current'; + } else { + cell.className = 'current'; + } + } + + link = document.createElement('A'); + cell.appendChild(link); + + link.href = i; + link.onclick = Horde_Calendar.day_onclick; + + day = document.createTextNode(i); + link.appendChild(day); + + row.appendChild(cell); + if (count == 7) { + tbody.appendChild(row); + count = 0; + } + ++count; + } + if (count > 1) { + tbody.appendChild(row); + } + + div.appendChild(table); + div.style.display = ''; + div.style.position = 'absolute'; + div.style.visibility = 'visible'; + + // Position the popup every time in case of a different input, + // window sizing changes, etc. + var el = document.getElementById(imgId); + var p = Horde_Calendar.getAbsolutePosition(el); + + if (p.x + div.offsetWidth > document.body.offsetWidth) { + div.style.left = (document.body.offsetWidth - 10 - div.offsetWidth) + 'px'; + } else { + div.style.left = p.x + 'px'; + } + if (p.y + div.offsetHeight > document.body.offsetHeight) { + div.style.top = (document.body.offsetHeight - 10 - div.offsetHeight) + 'px'; + } else { + div.style.top = p.y + 'px'; + } + + // Browser sniff for IE taken from Prototype. + if (!!(window.attachEvent && !window.opera)) { + // Fix for IE and select elements. + iefix = document.getElementById('goto_iefix'); + if (!iefix) { + iefix = document.createElement('IFRAME'); + iefix.id = 'goto_iefix'; + iefix.src = 'javascript:false;'; + iefix.scrolling = 'no'; + iefix.frameborder = 0; + iefix.style.display = 'none'; + iefix.style.position = 'absolute'; + document.body.appendChild(iefix); + } + iefix.style.width = div.offsetWidth; + iefix.style.height = div.offsetHeight; + iefix.style.top = div.style.top; + iefix.style.left = div.style.left; + + if (div.style.zIndex == '') { + div.style.zIndex = 2; + iefix.style.zIndex = 1; + } else { + iefix.style.zIndex = div.style.zIndex - 1; + } + iefix.style.display = ''; + } + }, + + day_onclick: function() + { + var day = this.href; + while (day.indexOf('/') != -1) { + day = day.substring(day.indexOf('/') + 1); + } + + // BC + if (document.getElementById(Horde_Calendar.target + '[year]')) { + Horde_Calendar.setSelectValue(document.getElementById(Horde_Calendar.target + '[year]'), Horde_Calendar.date.getFullYear()); + Horde_Calendar.setSelectValue(document.getElementById(Horde_Calendar.target + '[month]'), Horde_Calendar.date.getMonth() + 1); + Horde_Calendar.setSelectValue(document.getElementById(Horde_Calendar.target + '[day]'), day); + } else { + Horde_Calendar.setSelectValue(document.getElementById(Horde_Calendar.target + '_year'), Horde_Calendar.date.getFullYear()); + Horde_Calendar.setSelectValue(document.getElementById(Horde_Calendar.target + '_month'), Horde_Calendar.date.getMonth() + 1); + Horde_Calendar.setSelectValue(document.getElementById(Horde_Calendar.target + '_day'), day); + } + + var div = document.getElementById('goto'); + div.style.display = 'none'; + if (div.firstChild) { + div.removeChild(div.firstChild); + } + var iefix = document.getElementById('goto_iefix'); + if (iefix) { + iefix.style.display = 'none'; + } + + if (Horde_Calendar.callback) { + Horde_Calendar.callback(); + } + + return false; + }, + + getAbsolutePosition: function(el) + { + var r = { x: el.offsetLeft, y: el.offsetTop }; + if (el.offsetParent) { + var tmp = Horde_Calendar.getAbsolutePosition(el.offsetParent); + r.x += tmp.x; + r.y += tmp.y; + } + return r; + }, + + setSelectValue: function(select, value) + { + select.value = value; + if (select.value != value) { + for (var i = 0; i < select.options.length; ++i) { + if (select.options[i].value == value) { + select.selectedIndex = i; + return true; + } + } + } + + return false; + } + +}; diff --git a/hermes/scripts/Sandals.wdgt/lib/stripe.js b/hermes/scripts/Sandals.wdgt/lib/stripe.js new file mode 100644 index 000000000..33088881d --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/lib/stripe.js @@ -0,0 +1,97 @@ +/** + * Javascript code for finding all tables with classname "striped" and + * dynamically striping their row colors. + * + * Copyright 2006-2009 The Horde Project (http://www.horde.org/) + * + * $Horde: hermes/scripts/Sandals.wdgt/lib/stripe.js,v 1.3 2009/01/06 17:50:10 jan Exp $ + * + * @author Chuck Hagenbuch + * @author Matt Warden + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + */ + +/* We do everything onload so that the entire document is present + * before we start searching it for tables. */ +if (window.addEventListener) { + window.addEventListener('load', findStripedElements, false); +} else if (window.attachEvent) { + window.attachEvent('onload', findStripedElements); +} else if (window.onload != null) { + var oldOnLoad = window.onload; + window.onload = function(e) + { + oldOnLoad(e); + findStripedElements(); + }; +} else { + window.onload = findStripedElements; +} + +function findStripedElements() +{ + if (!document.getElementsByTagName) { + return; + } + var elts = document.getElementsByTagName('*'); + for (var i = 0; i < elts.length; ++i) { + var e = elts[i]; + if (e.className.indexOf('striped') != -1) { + if (e.tagName == 'TABLE') { + stripeTable(e); + } else { + stripeElement(e); + } + } + } +} + +function stripeTable(table) +{ + // The flag we'll use to keep track of whether the current row is + // odd or even. + var even = false; + + // Tables can have more than one tbody element; get all child + // tbody tags and interate through them. + var tbodies = table.childNodes; + for (var c = 0; c < tbodies.length; c++) { + if (tbodies[c].tagName == 'TBODY') { + var trs = tbodies[c].childNodes; + for (var i = 0; i < trs.length; i++) { + if (trs[i].tagName == 'TR') { + trs[i].className = trs[i].className.replace(/ ?rowEven ?/, '').replace(/ ?rowOdd ?/, ''); + if (trs[i].className) { + trs[i].className += ' '; + } + trs[i].className += even ? 'rowEven' : 'rowOdd'; + + // Flip from odd to even, or vice-versa. + even = !even; + } + } + } + } +} + +function stripeElement(parent) +{ + // The flag we'll use to keep track of whether the current elt is + // odd or even. + var even = false; + + // Toggle the classname of any child node that is an element. + var children = parent.childNodes; + for (var i = 0; i < children.length; i++) { + var tag = children[i]; + if (tag.nodeType && tag.nodeType == 1) { + tag.className = tag.className.replace(/ ?rowEven ?/, '').replace(/ ?rowOdd ?/, ''); + tag.className = tag.className.split(' ').concat([even ? 'rowEven' : 'rowOdd']).join(' '); + + // Flip from odd to even, or vice-versa. + even = !even; + } + } +} diff --git a/hermes/scripts/Sandals.wdgt/lib/vcXMLRPC.js b/hermes/scripts/Sandals.wdgt/lib/vcXMLRPC.js new file mode 100644 index 000000000..4c2d1a298 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/lib/vcXMLRPC.js @@ -0,0 +1,640 @@ +/** + * This file is distributed as a component of Sandals.wdgt + * Sandals is a part of the Hermes application of the Horde Project + * The Horde Project (http://www.horde.org/) + * $Horde: hermes/scripts/Sandals.wdgt/lib/vcXMLRPC.js,v 1.3 2009/01/06 17:50:10 jan Exp $ + * + * Copyright 2000, 2001, 2002 Virtual Cowboys info@virtualcowboys.nl + * + * Author: Ruben Daniels + * Version: 0.91 + * Date: 29-08-2001 + * Site: www.vcdn.org/Public/XMLRPC/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @author Ruben Daniels + */ + + +Object.prototype.toXMLRPC = function(){ + var wo = this.valueOf(); + + if(wo.toXMLRPC == this.toXMLRPC){ + retstr = ""; + + for(prop in this){ + if(typeof wo[prop] != "function"){ + retstr += "" + prop + "" + XMLRPC.getXML(wo[prop]) + ""; + } + } + retstr += ""; + + return retstr; + } + else{ + return wo.toXMLRPC(); + } +} + +String.prototype.toXMLRPC = function(){ + // + return "";//.replace(/" + this + ""; + } + else if(this == parseFloat(this)){ + return "" + this + ""; + } + else{ + return false.toXMLRPC(); + } +} + +Boolean.prototype.toXMLRPC = function(){ + if(this) return "1"; + else return "0"; +} + +Date.prototype.toXMLRPC = function(){ + //Could build in possibilities to express dates + //in weeks or other iso8601 possibillities + //hmmmm ???? + //19980717T14:08:55 + return "" + doYear(this.getUTCYear()) + doZero(this.getMonth()) + doZero(this.getUTCDate()) + "T" + doZero(this.getHours()) + ":" + doZero(this.getMinutes()) + ":" + doZero(this.getSeconds()) + ""; + + function doZero(nr) { + nr = String("0" + nr); + return nr.substr(nr.length-2, 2); + } + + function doYear(year) { + if(year > 9999 || year < 0) + XMLRPC.handleError(new Error("Unsupported year: " + year)); + + year = String("0000" + year) + return year.substr(year.length-4, 4); + } +} + +Array.prototype.toXMLRPC = function(){ + var retstr = ""; + for(var i=0;i"; + } + return retstr + ""; +} + +function VirtualService(servername, oRPC){ + this.version = '0.91'; + this.URL = servername; + this.multicall = false; + this.autoroute = true; + this.onerror = null; + + this.rpc = oRPC; + this.receive = {}; + + this.purge = function(receive){ + return this.rpc.purge(this, receive); + } + + this.revert = function(){ + this.rpc.revert(this); + } + + this.add = function(name, alias, receive){ + this.rpc.validateMethodName();if(this.rpc.stop){this.rpc.stop = false;return false} + if(receive) this.receive[name] = receive; + this[(alias || name)] = new Function('var args = new Array(), i;for(i=0;i mask/s + * -------------------- + * undefined -> 0/1 [default] + * number -> 2 + * boolean -> 4 + * string -> 8 + * function -> 16 + * object -> 32 + * -------------------- + * Examples: + * Want [String] only: (eqv. (typeof(vDunno) == 'string') ) + * Soya.Common.typematch(unknown, 8) + * Anything else than 'undefined' acceptable: + * Soya.Common.typematch(unknown) + * Want [Number], [Boolean] or [Function]: + * Soya.Common.typematch(unknown, 2 + 4 + 16) + * Want [Number] only: + * Soya.Common.typematch(unknown, 2) + **/ + typematch : function (vDunno, nCase){ + var nMask; + switch(typeof(vDunno)){ + case 'number' : nMask = 2; break; + case 'boolean' : nMask = 4; break; + case 'string' : nMask = 8; break; + case 'function': nMask = 16; break; + case 'object' : nMask = 32; break; + default : nMask = 1; break; + } + return Boolean(nMask & (nCase || 62)); + }, + + getNode : function(data, tree){ + var nc = 0;//nodeCount + //node = 1 + if(data != null){ + for(i=0;i 1){ + tree.shift(); + data = this.getNode(data, tree); + } + return data; + } + nc++ + } + } + } + + return false; + }, + + toObject : function(data){ + var ret, i; + switch(data.tagName){ + case "string": + return (data.firstChild) ? new String(data.firstChild.nodeValue) : ""; + break; + case "int": + case "i4": + case "double": + return (data.firstChild) ? new Number(data.firstChild.nodeValue) : 0; + break; + case "dateTime.iso8601": + /* + Have to read the spec to be able to completely + parse all the possibilities in iso8601 + 07-17-1998 14:08:55 + 19980717T14:08:55 + */ + + var sn = (isIE) ? "-" : "/"; + + if(/^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/.test(data.firstChild.nodeValue)){;//data.text)){ + return new Date(RegExp.$2 + sn + RegExp.$3 + sn + + RegExp.$1 + " " + RegExp.$4 + ":" + + RegExp.$5 + ":" + RegExp.$6); + } + else{ + return new Date(); + } + + break; + case "array": + data = this.getNode(data, [0]); + + if(data && data.tagName == "data"){ + ret = new Array(); + + var i = 0; + while(child = this.getNode(data, [i++])){ + ret.push(this.toObject(child)); + } + + return ret; + } + else{ + this.handleError(new Error("Malformed XMLRPC Message1")); + return false; + } + break; + case "struct": + ret = {}; + + var i = 0; + while(child = this.getNode(data, [i++])){ + if(child.tagName == "member"){ + ret[this.getNode(child, [0]).firstChild.nodeValue] = this.toObject(this.getNode(child, [1])); + } + else{ + this.handleError(new Error("Malformed XMLRPC Message2")); + return false; + } + } + + return ret; + break; + case "boolean": + return Boolean(isNaN(parseInt(data.firstChild.nodeValue)) ? (data.firstChild.nodeValue == "true") : parseInt(data.firstChild.nodeValue)) + + break; + case "base64": + return this.decodeBase64(data.firstChild.nodeValue); + break; + case "value": + child = this.getNode(data, [0]); + return (!child) ? ((data.firstChild) ? new String(data.firstChild.nodeValue) : "") : this.toObject(child); + + break; + default: + this.handleError(new Error("Malformed XMLRPC Message: " + data.tagName)); + return false; + break; + } + }, + + /*** Decode Base64 ****** + * Original Idea & Code by thomas@saltstorm.net + * from Soya.Encode.Base64 [http://soya.saltstorm.net] + **/ + decodeBase64 : function(sEncoded){ + // Input must be dividable with 4. + if(!sEncoded || (sEncoded.length % 4) > 0) + return sEncoded; + + /* Use NN's built-in base64 decoder if available. + This procedure is horribly slow running under NN4, + so the NN built-in equivalent comes in very handy. :) */ + + else if(typeof(atob) != 'undefined') + return atob(sEncoded); + + var nBits, i, sDecoded = ''; + var base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + sEncoded = sEncoded.replace(/\W|=/g, ''); + + for(i=0; i < sEncoded.length; i += 4){ + nBits = + (base64.indexOf(sEncoded.charAt(i)) & 0xff) << 18 | + (base64.indexOf(sEncoded.charAt(i+1)) & 0xff) << 12 | + (base64.indexOf(sEncoded.charAt(i+2)) & 0xff) << 6 | + base64.indexOf(sEncoded.charAt(i+3)) & 0xff; + sDecoded += String.fromCharCode( + (nBits & 0xff0000) >> 16, (nBits & 0xff00) >> 8, nBits & 0xff); + } + + // not sure if the following statement behaves as supposed under + // all circumstances, but tests up til now says it does. + + return sDecoded.substring(0, sDecoded.length - + ((sEncoded.charCodeAt(i - 2) == 61) ? 2 : + (sEncoded.charCodeAt(i - 1) == 61 ? 1 : 0))); + }, + + getObject : function(type, message){ + if(type == "HTTP"){ + if(isIE) + obj = new ActiveXObject("microsoft.XMLHTTP"); + else if(isNS) + obj = new XMLHttpRequest(); + } + else if(type == "XMLDOM"){ + if(isIE){ + obj = new ActiveXObject("microsoft.XMLDOM"); + obj.loadXML(message) + }else if(isNS){ + obj = new DOMParser(); + obj = obj.parseFromString(message, "text/xml"); + } + + } + else{ + this.handleError(new Error("Unknown Object")); + } + + return obj; + }, + + validateMethodName : function(name){ + /*do Checking: + + The string may only contain identifier characters, + upper and lower-case A-Z, the numeric characters, 0-9, + underscore, dot, colon and slash. + + */ + if(/^[A-Za-z0-9\._\/:]+$/.test(name)) + return true + else + this.handleError(new Error("Incorrect method name")); + }, + + getXML : function(obj){ + if(typeof obj == "function"){ + this.handleError(new Error("Cannot Parse functions")); + }else if(obj == null || obj == undefined || (typeof obj == "number" && !isFinite(obj))) + return false.toXMLRPC(); + else + return obj.toXMLRPC(); + }, + + handleError : function(e){ + if(!this.onerror || !this.onerror(e)){ + //alert("An error has occured: " + e.message); + throw e; + } + this.stop = true; + this.lastError = e; + }, + + cancel : function(id){ + //You can only cancel a request when it was executed async (I think) + if(!this.queue[id]) return false; + + this.queue[id][0].abort(); + return true; + }, + + send : function(serverAddress, functionName, args, receive, multicall, autoroute){ + var id, http; + //default is sync + this.validateMethodName(); + if(this.stop){this.stop = false; return false;} + + //setting up multicall + multicall = (multicall != null) ? multicall : this.multicall; + + if(multicall){ + if(!this.stack[serverAddress]) this.stack[serverAddress] = new Array(); + this.stack[serverAddress].push({methodName : functionName, params : args}); + return true; + } + + //creating http object + var http = this.getObject("HTTP"); + + //setting some things for async/sync transfers + if(!receive || isNS){; + async = false; + } + else{ + async = true; + /* The timer functionality is implemented instead of + the onreadystatechange event because somehow + the calling of this event crashed IE5.x + */ + id = this.queue.push([http, receive, null, new Date()])-1; + + this.queue[id][2] = new Function("var id='" + id + "';var dt = new Date(new Date().getTime() - XMLRPC.queue[id][3].getTime());diff = parseInt(dt.getSeconds()*1000 + dt.getMilliseconds());if(diff > XMLRPC.timeout){if(XMLRPC.ontimeout) XMLRPC.ontimeout(); clearInterval(XMLRPC.timers[id]);XMLRPC.cancel(id);return};if(XMLRPC.queue[id][0].readyState == 4){XMLRPC.queue[id][0].onreadystatechange = function(){};XMLRPC.receive(id);clearInterval(XMLRPC.timers[id])}"); + this.timers[id] = setInterval("XMLRPC.queue[" + id + "][2]()", 20); + } + + //setting up the routing + autoroute = (autoroute || this.autoroute); + + //'active' is only set when direct sending the message has failed + var srv = (autoroute == "active") ? this.routeServer : serverAddress; + + try{ + http.open('POST', srv, async); + http.setRequestHeader("User-Agent", "vcXMLRPC v0.91 (" + navigator.userAgent + ")"); + http.setRequestHeader("Host", srv.replace(/^https?:\/{2}([:\[\]\-\w\.]+)\/?.*/, '$1')); + http.setRequestHeader("Content-type", "text/xml"); + if(autoroute == "active"){ + http.setRequestHeader("X-Proxy-Request", serverAddress); + http.setRequestHeader("X-Compress-Response", "gzip"); + } + } + catch(e){ + if(autoroute == true){ + //Access has been denied, Routing call. + autoroute = "active"; + if(id){ + delete this.queue[id]; + clearInterval(this.timers[id]); + } + return this.send(serverAddress, functionName, args, receive, multicall, autoroute); + } + + //Routing didn't work either..Throwing error + this.handleError(new Error("Could not sent XMLRPC Message (Reason: Access Denied on client)")); + if(this.stop){this.stop = false;return false} + } + + //Construct the message + var message = '' + functionName + ''; + for(i=0;i'; + } + message += ''; + + var xmldom = this.getObject('XMLDOM', message); + if(self.DEBUG) alert(message); + + try{ + //send message + http.send(xmldom); + } + catch(e){ + //Most likely the message timed out(what happend to your internet connection?) + this.handleError(new Error("XMLRPC Message not Sent(Reason: " + e.message + ")")); + if(this.stop){this.stop = false;return false} + } + + if(!async && receive) + return [autoroute, receive(this.processResult(http))]; + else if(receive) + return [autoroute, id]; + else + return [autoroute, this.processResult(http)]; + }, + + receive : function(id){ + //Function for handling async transfers.. + if(this.queue[id]){ + var data = this.processResult(this.queue[id][0]); + this.queue[id][1](data); + delete this.queue[id]; + } + else{ + this.handleError(new Error("Error while processing queue")); + } + }, + + processResult : function(http){ + if(self.DEBUG) alert(http.responseText); + if(http.status == 200){ + //getIncoming message + dom = http.responseXML; + + if(dom){ + var rpcErr, main; + + //Check for XMLRPC Errors + rpcErr = dom.getElementsByTagName("fault"); + if(rpcErr.length > 0){ + rpcErr = this.toObject(rpcErr[0].firstChild); + this.handleError(new Error(rpcErr.faultCode, rpcErr.faultString)); + return false + } + + //handle method result + main = dom.getElementsByTagName("param"); + if(main.length == 0) this.handleError(new Error("Malformed XMLRPC Message")); + data = this.toObject(this.getNode(main[0], [0])); + + //handle receiving + if(this.onreceive) this.onreceive(data); + return data; + } + else{ + this.handleError(new Error("Malformed XMLRPC Message")); + } + } + else{ + e = new Error("HTTP Exception: (" + http.status + ") " + http.statusText + "\n\n" + http.responseText); + e.http_status = http.status; + e.http_statusText = http.statusText; + this.handleError(e); + //this.handleError(new Error("HTTP Exception: (" + http.status + ") " + http.statusText + "\n\n" + http.responseText)); + } + } +} + +//Smell something +ver = navigator.appVersion; +app = navigator.appName; +isNS = Boolean(navigator.productSub) +//moz_can_do_http = (parseInt(navigator.productSub) >= 20010308) + +isIE = (ver.indexOf("MSIE 5") != -1 || ver.indexOf("MSIE 6") != -1) ? 1 : 0; +isIE55 = (ver.indexOf("MSIE 5.5") != -1) ? 1 : 0; + +isOTHER = (!isNS && !isIE) ? 1 : 0; + +if(isOTHER) alert("Sorry your browser doesn't support the features of vcXMLRPC"); diff --git a/hermes/scripts/Sandals.wdgt/themes/bluewhite-screen.css b/hermes/scripts/Sandals.wdgt/themes/bluewhite-screen.css new file mode 100644 index 000000000..4d3dcddf5 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/themes/bluewhite-screen.css @@ -0,0 +1,162 @@ +/** + * $Horde: hermes/scripts/Sandals.wdgt/themes/bluewhite-screen.css,v 1.1 2008/03/08 06:49:07 bklang Exp $ + */ + +body { + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + background: #fff; +} +a { + color: #339; +} +.headerbox { + border-color: #66a; +} +.selected { + background: #C6D3FF; +} +.header { + color: #fff; + background: #66a; + border-bottom: 1px solid #000; +} +.header a { + color: #fff; +} +.header a:hover, a.header:hover { + color: yellow; + text-decoration: none; +} +a.header { + border-bottom: 0; + background: transparent; +} +a.fixed { + color: #339; +} +.light { + color: #333; +} +.smallheader { + color: #fff; + background: #66a; + font-family: Verdana,Helvetica,sans-serif; +} +a.smallheader:hover { + color: #cce; + text-decoration: none; +} +.control { + background: #ddd; +} +.widget { + color: #224; +} + +/* Form styles. */ +input, select, textarea { + color: #000; + background: #f3f3f9; + border: 1px solid #669; +} +input:focus, textarea:focus { + background: #fff; + border: 1px solid #99f; +} +.button, .button:focus { + color: #fff; + background: #66a; + border: 1px solid #C4C4B8; + border-bottom-color: #333; + border-right-color: #000; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} +.button:hover, .button:focus, a.button:hover, a.button:focus { + background: #339; +} + +/* Alternating styles. item0, item1 are deprecated. */ +.rowEven, .item0 { + background-color: #eef; +} +.rowOdd, .item1 { + background-color: #fff; +} + +/* Various popup and status layers. */ +.tooltip, div.nicetitle { + color: #fff; + background: #66a; + border: 2px double #fff; +} + +/* Menu styles. */ +#menu { + color: #fff; + background: #66a; + border-bottom: 2px solid #000; +} +#menu a { + color: #fff; +} +#menu a.current { + background: #339; + border-bottom: 1px solid #aac; + border-right: 1px solid #aac; + border-left: 1px solid #000; + border-top: 1px solid #000; + padding: 2px; +} +#menuBottom { + background: #eef; + border-left: 1px solid #ccc; + border-bottom: 1px solid #ccc; + -moz-border-radius-bottomleft: 10px; + -webkit-border-bottom-left-radius: 10px; +} + +/* Sidebar styles. */ +body.sidebar { + background: #fff; +} +#sidebarPanel { + border-right: 1px solid #006; + border-bottom: 1px solid #006; + background: #e9e9ff; +} +#sidebarPanel span.toggle, #sidebarPanel a { + padding: 4px; +} +#sidebarPanel a, #sidebarPanel span { + color: #006; +} +#sidebarPanel a:hover { + color: #fff; + background: #66a; +} +#sidebarPanel a:hover span { + color: #fff; +} +#expandButton { + margin-right: 1px; +} + +/* Tab styles. */ +.tabset { + background: none; + border-bottom: 1px solid #66a; +} +.tabset li a { + border: 1px solid #66a; + border-bottom-color: #e9e9e9; +} +.tabset li.activeTab a { + background: #66a; + color: #fff; + border-bottom: 1px solid #66a; +} +.tabset li.activeTab a:hover { + background: #66a; + color: #fff; +} diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/alarm.png b/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/alarm.png new file mode 100644 index 0000000000000000000000000000000000000000..70c1e1d2c66f6f0fe768c7cb78ea23ce8d8cea64 GIT binary patch literal 422 zcmV;X0a^ZuP);g9;~eEsWs`st1L=BE4Woc8Lp|L=_c z@0b7ZlKSwh{qd;$@v{8!wEXhE`trp8^sfK(v;XzB`t#5K^}GM|y#M&j{`k}X`r7{b z=l}oz0001s^X+5+0004WQchCgVg2sLbmZtku|66|mVA~r6r&K62MFePmAmX7wers}*bPz8Jjc1~s{`f6hA z5G711I_7#>8j7-l9AE(tQE52^8A$FQ8otB|(0{Ffkl7LrjeHTcFxVPZ!6K zid(to4fzfz@Hhvmcz255uqyr^eNBaBC4 zE9UWU;qMEAIv+Z|{A*OyUQxiPUs1rw{A`j&*}tMqf8TmOW|b7@WRh~~?*m%G;OXk; Jvd$@?2>^-4euMx3 literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/message.png b/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/message.png new file mode 100644 index 0000000000000000000000000000000000000000..1cae1e8af95e9791a3fc46342946f8cf28e13da3 GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQnS0K$JEF~hXEGn%mqpYoL z;cMg;qwk$=;GJ&lpJU>mV;WRo8CK#Fkz*TG;SgQn6_x80SL2q{;FZ?mo!0D^)e)N8 z9-QABlHU_vJTba_YHC?$e8r@Miiz>nGn4D*rq|EPXkM7pzBI3WVR_rM+O8Rm)7Cc3 z*xWvQ-Lw^ZXRO*gbIpM{YxXYMba?5OW6QRl*s%B9e^S7*a_wrM9~?@8{DMi*hea*J zq3Vq;K(l&0T^vIyZsqoe^Br>FacPg+)FR;J@nT`SmHLB!+Yf!?nxORTz3us|+&x|& znWoJ@ux`g3e%l(CzlCSaSErh-t!!LwFmvfi4lRSrmNV5JCkktEz1BWnD_ov9=}_~9 zBfigBjq~s)H;t4(zjC+v+L4<)Qd$y=NQGMNfVI>Y_@C?92c5>!z5u X@v0v7OUjY}x{JZn)z4*}Q$iB}*>?kW literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/success.png b/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/success.png new file mode 100644 index 0000000000000000000000000000000000000000..4af9076c74e4deb3e1b904b0af81f18770c4f3dd GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf`~aU2R~9A~n;;b#EfJq89Udtb z6FZfhsu-Ur8yzhj9zK?mNiiZ~A~97iHM4S9xL9n`WOTGtZ0u}8(tKj7Y)p(yWRyf& zW|gQIiHIoi_{6#J@bR?F%i-bT@yRoB@v>oIW3dTSQPC3#snZdWPn9V^r!tlV`2{mL zJiCzw^3oM>A1RBT(Qhzl2gv6eTf~SZ7lZk6^!hcGPA8#1D(L&>FVdQ&MBb@0O8kg AoB#j- literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/warning.png b/hermes/scripts/Sandals.wdgt/themes/graphics/alerts/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..7f6d50fabf0d8e6b6b9065b6ee67ae61beca847a GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!L4Z$)tDvA@d3m{-6oZY8&9Vlm z|7VOHjCp~Qyu7@{k-VSws~M{?=Al0dm2PZ!6K zid(U#9JvlSa5!JgacWcg@^8EDr&2>+j!%_Ukw)iRyk2o_+{~E3f3ZnbY68#2hA+7q zOfC(40*p0%idhW}91orwy6_4JT$T0uxK(3+?T=@i`>)tCXaG%T@O1TaS?83{1ONft BRb&7F literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/calendar.png b/hermes/scripts/Sandals.wdgt/themes/graphics/calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..2712746411c9d05bb343df1e3d6b6168a9f752f9 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}U4T!BE0F#V0zdx$|9$$@ft4#3 zOr6quVE^{XlX_;)nzCxe!tGnvZQHW;@2?M2CiTpiHu2Ao_xpBl*}Y@qrE|wl9^H58 z-0}ZA+-6RjxZ2n8dz8=N0FNI(eti7+@y(kz4<0VfmhE0gZNZnrz6T65%cROt3ynNA$v-L+*JgbUd8 zCTR3MnKWlh`7P1NZHz?|XBu=hzw#^1PqX@ycZQu?+k3vqv%T-T{_|>f3GP%ne!EnJ d({^4pGe?!!v&+wvy@5_(@O1TaS?83{1OTA8!dw6V literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/hermes.png b/hermes/scripts/Sandals.wdgt/themes/graphics/hermes.png new file mode 100644 index 0000000000000000000000000000000000000000..f6919137bc0b0851c4e7b4e47b86ed349a44b458 GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfu>hYCS0MfW|NlRK{`~&^``52u zKY#xG@#Dw$@87?D`}Xzg*DqhbeE$6T)2B}#KYsl1;lum)@87+9_xA1EH*em&e*OB@ zt5+{yzI^fG#q;OSpFMl_^y$+lPo6w}{P@wMM-Lx9ynFZV?c296T)1%d?AeniPo6k& z;=q9e`}XbIyLa!NJ$rWV-o10@&TZSaZQZ(c%a$#hHf`FlVZ-|M>z6HCwqU`6xpU{v znl)?Mv}qG2Oz7?Ht*NPri;J_jx3{&mwY0P}F)=YTG&C?U(AU=&7Z(S*Uo+{770@S6 zB|(0{KrUr~!9@%dRt%>+T^vIsBv}vc_HqssalN?n+b&1lBjPNRo~gZjV-nF-uq6GWYJqO-zhmpZv>xS@!Xt!8(B}mrurT zx^?c%^vzxc|K`j*IgMq#xXa%k%`I#!o2AaEc&G@@5?=FblGCfxR<|xFv`+Q8{VZ7M z*#mCPN3)k7Jio}8|C{W#w=X{?ACc2~eNxR>)%C_=j&)JDdvmR;rn5XGSQjw-VXnz_cKfRy_ZZ|YPgg&ebxsLQ04(E2v;Y7A literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/graphics/required.png b/hermes/scripts/Sandals.wdgt/themes/graphics/required.png new file mode 100644 index 0000000000000000000000000000000000000000..175636206894ea07bc2eeccef284afbdc7d5f40e GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xGmzZ=C-xtZVhivIaoq}JFfhDNu;v6(OeH~n z!T%YaZa44(@?v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/hermes/scripts/Sandals.wdgt/themes/hermes-screen.css b/hermes/scripts/Sandals.wdgt/themes/hermes-screen.css new file mode 100644 index 000000000..ffe0348d9 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/themes/hermes-screen.css @@ -0,0 +1,40 @@ +/** + * $Horde: hermes/scripts/Sandals.wdgt/themes/hermes-screen.css,v 1.1 2008/03/08 06:49:07 bklang Exp $ + */ + +/* Special handling for non-printed timesheets. */ +#approval { + display: none; +} + +/* Time list tables */ +table.time { + width: 100%; + margin-bottom: 8px; + border-top: 1px solid #ddd; + border-left: 1px solid #ddd; +} +table.time th { + padding: 3px; + background: #e9e9e9; + border-right: 1px solid #ccc; + text-align: left; +} +table.time td { + padding: 3px; + border-right: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} +table.time th.sortup { + background: #bbcbff url("graphics/za.png") center left no-repeat; + padding-left: 10px; +} +table.time th.sortdown { + background: #bbcbff url("graphics/az.png") center left no-repeat; + padding-left: 10px; +} +table.time tfoot td { + background: #ddd; + font-weight: bold; + padding: 1px; +} diff --git a/hermes/scripts/Sandals.wdgt/themes/sandals-screen.css b/hermes/scripts/Sandals.wdgt/themes/sandals-screen.css new file mode 100644 index 000000000..fc56db442 --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/themes/sandals-screen.css @@ -0,0 +1,6 @@ +/* $Horde: hermes/scripts/Sandals.wdgt/themes/sandals-screen.css,v 1.2 2008/03/08 06:52:38 bklang Exp $ */ +#title +{ + width: 100%; + height: 45px; +} diff --git a/hermes/scripts/Sandals.wdgt/themes/screen.css b/hermes/scripts/Sandals.wdgt/themes/screen.css new file mode 100644 index 000000000..28538873b --- /dev/null +++ b/hermes/scripts/Sandals.wdgt/themes/screen.css @@ -0,0 +1,795 @@ +/** + * $Horde: hermes/scripts/Sandals.wdgt/themes/screen.css,v 1.2 2008/04/08 18:07:29 chuck Exp $ + */ + +/* Global default styles. */ +* { + /* Zero out all padding and margins to start with for better + * cross-browser control. */ + padding: 0; + margin: 0; +} + +body { + font-family: Geneva,Arial,Helvetica,sans-serif; + font-size: 75%; + background: #fff; + color: #000; +} + +body.scrollbar-quirk { + margin-right: 15px; +} + +p { + margin-bottom: 10px; +} + +img, .img, .img:active, .img:hover, .img:visited, .image { + border: none; + vertical-align: middle; + background: transparent; +} +/* This must be declared seperately or IE will ignore all of the selectors. */ +input[type=image] { + border: none; + vertical-align: middle; + background: transparent; +} + +ins { + background: #cfc; +} +del { + background: #fcc; +} + +br.spacer { + line-height: 8px; +} + +.leftAlign { + text-align: left; +} +.rightAlign { + text-align: right; +} +.leftFloat { + float: left; +} +.rightFloat { + float: right; +} + +.box { + padding: 3px; + border: 1px dashed #999; + background: #fff; +} +.solidbox { + border: 1px solid #000; +} +.greybox { + border: 1px solid #000; + background: #e9e9e9; +} +.headerbox { + border-left: 1px solid #000; + border-right: 1px solid #000; + border-bottom: 1px solid #000; + background: #fff; +} +.roundedBox { + -moz-border-radius: 15px; + -webkit-border-radius: 15px; +} +.roundedTop { + -moz-border-radius-topright: 15px; + -moz-border-radius-topleft: 15px; + -webkit-border-top-right-radius: 15px; + -webkit-border-top-left-radius: 15px; +} +.roundedBottom { + -moz-border-radius-bottomright: 15px; + -moz-border-radius-bottomleft: 15px; + -webkit-border-bottom-right-radius: 15px; + -webkit-border-bottom-left-radius: 15px; +} +.header { + font-family: Verdana,Helvetica,sans-serif; + font-weight: bold; + font-size: 125%; + padding: 3px; +} +.header a:hover, a.header:hover { + color: #333; +} +.header img { + vertical-align: bottom; +} +.header input, .header select { + font-size: 80%; +} +.header .smallheader input, .header .smallheader select { + font-size: 100%; +} +.header .button, .header .smallheader .button { + font-size: 72%; +} +.header ul { + float: right; + text-align: right; + font-size: 80%; +} +.header li { + list-style: none; + display: inline; +} + +.nowrap { + white-space: nowrap; +} +.clear { + clear: both; + line-height: 0; + height: 0; +} + +a { + color: blue; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +.selected { + background: #bbcbff; +} +.selected-over { + background: #cef; +} + +/* Table styles. */ +table { + border: none; +} +td, th { + padding: 1px; +} +th { + color: #333; + font-family: Verdana,Helvetica,sans-serif; + font-size: 90%; +} +td { + font-family: Geneva,Arial,Helvetica,sans-serif; +} +ul.linedRow { + list-style-type: none; +} +.linedRow, tr.linedRow td, table.linedRow td, ul.linedRow li { + color: #000; + background: #fff; + border-bottom: 1px solid #ddd; +} +table.linedRow, ul.linedRow { + border-bottom: none; +} +.linedRowSelectedCol, td.linedRowSelectedCol, table.linedRow td.linedRowSelectedCol { + color: #000; + background: #f3f3f3; + border-bottom: 1px solid #ddd; +} +.selectedRow, tr.selectedRow td { + background: #ffc; +} +.selectedRow:hover, tr.selectedRow:hover td, .selectedRow-over, tr.selectedRow-over td { + background: #ffd; +} +table.nopadding td, table.nopadding th { + padding: 0; +} +.sortup { + background: #bbcbff url("graphics/za.png") center left no-repeat; + padding-left: 10px; +} +.sortdown { + background: #bbcbff url("graphics/az.png") center left no-repeat; + padding-left: 10px; +} +/* Alternating styles. item0, item1 are deprecated. */ +.striped, .rowEven, .item0 { + background-color: #eee; +} +.rowOdd, .item1 { + background-color: #ddd; +} + +.widget { + font-family: Verdana,Helvetica,sans-serif; + font-size: 90%; +} + +.light { + font-family: Geneva,Arial,Helvetica,sans-serif; +} +.smallheader { + font-family: Geneva,Arial,Helvetica,sans-serif; + font-size: 100%; + font-weight: bold; +} +.header .smallheader { + font-size: 80%; +} +.header .smallheader a.smallheader { + font-size: 100%; +} +small, .small { + font-size: 80%; +} +.control { + color: #000; + background: #ccc; + border-bottom: 1px solid #999; + padding: 1px; +} +.item { + color: #000; + background: #eee; +} +.accessKey { + text-decoration: underline; +} +.text { + color: #000; + background: #fff; +} + +/* Form styles. */ +.form table { + width: 100%; + padding: 2px; + border-collapse: collapse; +} +form[action^="https://"] input[type="submit"] { + background-image: url("graphics/locked.png"); + background-position: 95% center; + background-repeat: no-repeat; + padding-right: 10%; +} +.htmlarea .statusBar .statusBarTree a { + font: inherit; +} +.htmlarea table { + width: auto; +} +.form-error { + color: #f00; +} +input, select, textarea { + font-family: Geneva,Arial,Helvetica,sans-serif; + font-size: 100%; + font-weight: normal; +} +input { + padding: 1px; +} +option { + padding: 0 5px 0 3px; +} +.checkbox { + border: 0; + height: 14px; + width: 14px; + background: transparent; +} +.button { + cursor: pointer; + font-size: 90%; + font-family: Verdana,Helvetica,sans-serif; + padding: 1px 6px; +} +a.button { + padding: 2px 8px; + font-weight: normal; + text-decoration: none; +} + +pre, code, .fixed { + font-size: 100%; + font-family: "Lucida Console",Courier,"Courier New"; +} + +/* Styles for email-like messages. */ +.signature { + color: #ccc; +} +.signature-fixed { + color: #ccc; + font-family: "Lucida Console",Courier,"Courier New"; +} +.citation { + margin: 1em 0; + padding-left: 1em; + border-left-width: 1px; + border-left-style: solid; +} +.quoted1 { + color: #606; + border-left-color: #606; +} +.quoted2 { + color: #077; + border-left-color: #077; +} +.quoted3 { + color: #900; + border-left-color: #900; +} +.quoted4 { + color: #009; + border-left-color: #009; +} +.quoted5 { + color: #b60; + border-left-color: #b60; +} + +/* Various popup and status layers. */ +.notices { + margin: .5em 8px; + list-style-type: none; +} +.notices li { + font-weight: bold; + color: #000; + background: #ffc; + border: 1px solid #aaa; + padding: 1px 1px 1px 5px; +} +.notices img { + margin-right: .5em; +} +.tooltip, div.nicetitle { + font: 11px/12px Verdana,Arial,serif; + color: #000; + background: #ffc; + border: 1px solid #000; + padding: 5px; + z-index: 1001; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} +div.nicetitle { + position: absolute; + overflow: hidden; + opacity: .90; +} +div.nicetitle pre { + font-family: "Lucida Console",Courier,"Courier New"; +} +.inProgress { + font: 10px Geneva,Arial,Helvetica,sans-serif; + padding: 2px; + color: #fff; + background: #f00; +} + +/* Tree styles. */ +.treeRow { + overflow: hidden; + min-height: 20px; + clear: both; +} + +/* Menu styles. */ +#menu { + overflow: hidden; + min-height: 50px; + font-family: Verdana,Helvetica,sans-serif; + margin-bottom: 8px; +} +#menu ul { + padding: 5px; +} +#menu li { + list-style-type: none; + text-align: center; + margin: 2px; + float: left; +} +#menu li.separator { + width: 40px; +} +#menu a { + display: block; + white-space: pre; + font-family: Verdana,Helvetica,sans-serif; + font-size: 90%; + text-decoration: none; + padding: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} +#menu h1 { + font-family: Verdana,Helvetica,sans-serif; + font-weight: bold; + font-size: 150%; + line-height: 48px; + vertical-align: bottom; +} +#menu input, #menu select { + margin-top: 16px; +} +#menuBottom { + margin: -8px 0 0 0; + padding: 4px; + float: right; + text-align: right; + font-size: 90%; + background: #eee; +} + +/* Sidebar styles. */ +.sidebar #menu { + margin: 0; +} +#sidebarPanel { + -moz-border-radius-bottomright: 15px; + -webkit-border-bottom-right-radius: 15px; + padding-top: 5px; + padding-bottom: 10px; + background: #eee; + white-space: nowrap; +} +#sidebarPanel a, #sidebarPanel span { + color: #000; + white-space: pre; + font-family: Verdana,Helvetica,sans-serif; + font-size: 90%; + text-decoration: none; +} +#sidebarPanel span.accessKey { + text-decoration: underline; +} +#sidebarPanel span.toggle { + cursor: pointer; +} +#sidebarPanel a:hover { + color: #000; +} + +/* Pager. */ +.pager { + text-align: center; +} + +/* Tab styles. */ +.tabset { + float: left; + width: 100%; + font-weight: bold; + background: url("graphics/tab_bottom.gif") repeat-x bottom; +} +.tabset ul { + margin-top: 4px; + padding-left: 8px; + list-style: none; +} +.tabset li { + float: left; + margin: -3px 2px 0 0; + white-space: nowrap; +} +.tabset li a { + color: #000; + background-color: #e9e9e9; + padding: 2px 0.5em; + display: block; + border: 1px solid #000; + border-bottom-color: #e9e9e9; + -moz-border-radius-topleft: 10px; + -moz-border-radius-topright: 10px; + -moz-border-top-left-radius: 10px; + -moz-border-top-right-radius: 10px; +} +.tabset li a:hover { + text-decoration: none; + background-color: #fff; +} +.tabset li.activeTab a { + border-bottom: 1px solid #000; + background-color: #000; + color: #fff; +} +.tabset li.activeTab a:hover { +} +.tabset img { + display: block; + float: left; + padding-right: 2px; +} + +/* Preferences. */ +.prefsOverview div { + float: left; +} +.prefsOverview div div { + padding-left: 10px; + width: 95%; +} +.prefsOverview h2 { + font-size: 150%; + font-weight: bold; +} +.prefsOverview dt a { + display: block; + padding: 2px; + font-weight: bold; + border: 1px solid #000; + border-bottom: 1px solid #446; + background: #e9e9e9; +} +.prefsOverview dd { + padding: 2px; + margin-bottom: 10px; + color: #000; + background: #fff; + border-left: 1px solid #000; + border-right: 1px solid #000; + border-bottom: 1px solid #000; +} +div.prefsContainer { + padding: 1em; +} +div.prefsContainer p { + padding-top: 1em; +} + +/* Block styles. */ +.currentBlock { + border: 2px solid red; +} +#googlesearch { + padding: .3em; +} + +/* Help styles. */ +body.help_about, body.help_entry { + margin: 0.5em; +} +.helplink { + cursor: help; +} +.help { + background: #fff; + color: #000; +} +.help h1 { + font-size: 125%; + padding-top: 0.5em; + padding-bottom: 0.5em; +} +.help h2 { + padding-top: 1em; + padding-bottom: 0.5em; + font-size: 110%; +} +.help p { + margin-left: 1em; + margin-right: 1em; + margin-bottom: 1em; +} +.help em { + display: block; + padding: 5px; + margin-left: 1em; + margin-right: 1em; + margin-bottom: 1em; +} +.help em.helpTip { + color: #090; + background: #e0f0e0; +} +.help em.helpWarn { + color: #900; + background: #f0e0e0; +} + +/* Source markup styles. */ +table.lineNumbered * { + font-family: "Lucida Console",Courier,"Courier New"; + font-size: 100%; + line-height: 16px; +} +.lineNumbered th { + background: #e9e9e9; + border-right: 1px solid #e0e0e0; + border-bottom: none; + padding-left: 10px; + padding-right: 10px; + text-align: right; +} +.lineNumbered td { + vertical-align: top; + width: 100%; + white-space: pre; + background: #fff; + padding-left: 10px; +} +.parentheses { + color: #2a6; + font-weight: bold; +} +.comment { + color: #aac; +} +.htag { + color: #569; + background: #d5d6da; + font-weight: bold; +} +.metac { + color: #0ff; + background: #d5d6da; +} +.id { + color: #e82; + background: #e4e4e0; +} +.attr { + color: #6af; +} +.value { + color: #d46; +} +.color { + color: #f57; +} +.eol { + color: #26e; +} +.url { + color: #962; +} +.file { + color: #444; + background: #fe4; +} +.class { + font-style: italic; +} + +/* Drop shadows. */ +.dropShadow { + float: left; + background: url("graphics/shadow.png") no-repeat bottom right !important; + background: url("graphics/shadow.gif") no-repeat bottom right; + margin: 10px 0 0 5px; +} + +.dropShadow img { + display: block; + position: relative; + background: #fff; + border: 1px solid #666; + margin: -3px 5px 5px -3px; + padding: 2px; +} + +/* MIME styles. */ +.mimeStatusMessage, .mimeStatusWarning, .mimeHeaders, .mimePartInfo { + padding: 1px; + margin-bottom: 2px; + font-family: Verdana,Arial,serif; + font-size: 90%; +} +.mimeStatusMessage { + color: #000; + background: #ffc; + border: 1px solid #fff760; + width: 100%; +} +.mimeStatusWarning { + border: 1px solid #800; + background: #e81222; + color: #fff; + width: 100%; +} +.mimeHeaders { + border: 1px solid #ccc; + background: #f9f9f9; + width: 100%; + font-family: "Lucida Console",Courier,"Courier New"; +} +.mimePartInfo { + border: 1px solid #ccc; + background: #f9f9f9; +} +.mimePartInfo, .mimePartInfo a { + color: #666; +} +.mimeStatusIcon { + vertical-align: middle; + width: 1%; +} +.download { + padding: 2px 20px 2px 0; + background: transparent url("graphics/download.png") center right no-repeat; +} + +/* Calendar Popup. */ +table.calendarPopup { + border: 1px solid #ccc; + background: #fff; + width: auto; + z-index: 1001; +} +.calendarPopup thead { + font-weight: bold; +} +.calendarPopup th { + border-bottom: 1px solid #ccc; +} +.calendarPopup tbody { + text-align: right; +} +.calendarPopup td { + font-family: tahoma; + font-size: 75%; +} +.calendarPopup a { + color: black; + display: block; + padding: 2px; +} +.calendarPopup tbody a:hover { + background: #ffc; +} +.calendarPopup .current { + font-weight: bold; + background: #eef; +} +.calendarPopup .today { + font-weight: bold; +} + +.hidden { + display: none; +} + +/* Redbox styles. */ +#RB_overlay { + position: absolute; + z-index: 100; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + min-height: 100%; + background-color: #000; + opacity: .6; + filter: alpha(opacity=60); +} +#RB_loading { + z-index: 101; + width: 70px; + margin-left: auto; + margin-right: auto; + margin-top: 200px; + padding-bottom: 30px; + text-align: center; + background: url("graphics/redbox_spinner.gif") no-repeat bottom center; +} +#RB_window { + z-index: 102; + background-color: #fff; + display: block; + text-align: left; + overflow: hidden; + margin: 20px auto 0 auto; + position: fixed; + position: absolute; +} diff --git a/hermes/scripts/purge.php b/hermes/scripts/purge.php new file mode 100755 index 000000000..b9011db2b --- /dev/null +++ b/hermes/scripts/purge.php @@ -0,0 +1,27 @@ +#!/usr/bin/php + + */ + +@define('HERMES_BASE', dirname(__FILE__) . '/..'); +@define('HORDE_BASE', dirname(__FILE__) . '/../..'); +require_once HORDE_BASE . '/lib/core.php'; + +// Registry +$registry = Horde_Registry::singleton(); +$registry->pushApp('hermes', false); + +// Hermes base libraries. +require_once HERMES_BASE . '/lib/Hermes.php'; +$hermes = &Hermes::getDriver(); + +printf(_("Deleting data that was exported/billed more than %s days ago.\n"), $conf['time']['days_to_keep']); +$hermes->purge(); diff --git a/hermes/scripts/sql/hermes.mssql.sql b/hermes/scripts/sql/hermes.mssql.sql new file mode 100644 index 000000000..16dd6f40d --- /dev/null +++ b/hermes/scripts/sql/hermes.mssql.sql @@ -0,0 +1,51 @@ +-- $Horde: hermes/scripts/sql/hermes.mssql.sql,v 1.7 2008/06/30 09:03:11 jan Exp $ + +CREATE TABLE hermes_timeslices ( + timeslice_id INT NOT NULL, + clientjob_id VARCHAR(255) NOT NULL, + employee_id VARCHAR(255) NOT NULL, + jobtype_id INT NOT NULL, + timeslice_hours NUMERIC(10, 2) NOT NULL, + timeslice_rate NUMERIC(10, 2), + timeslice_isbillable SMALLINT DEFAULT 0 NOT NULL, + timeslice_date INT NOT NULL, + timeslice_description VARCHAR(MAX) NOT NULL, + timeslice_note VARCHAR(MAX), + timeslice_submitted SMALLINT DEFAULT 0 NOT NULL, + timeslice_exported SMALLINT DEFAULT 0 NOT NULL, + costobject_id VARCHAR(255), +-- + PRIMARY KEY (timeslice_id) +); + +CREATE TABLE hermes_jobtypes ( + jobtype_id INT NOT NULL, + jobtype_name VARCHAR(255), + jobtype_enabled SMALLINT DEFAULT 1 NOT NULL, + jobtype_rate NUMERIC(10, 2), + jobtype_billable SMALLINT DEFAULT 0 NOT NULL, +-- + PRIMARY KEY (jobtype_id) +); + +CREATE TABLE hermes_clientjobs ( + clientjob_id VARCHAR(255) NOT NULL, + clientjob_enterdescription SMALLINT DEFAULT 1 NOT NULL, + clientjob_exportid VARCHAR(255), +-- + PRIMARY KEY (clientjob_id) +); + +CREATE TABLE hermes_deliverables ( + deliverable_id INT NOT NULL, + client_id VARCHAR(250) NOT NULL, + deliverable_name VARCHAR(250) NOT NULL, + deliverable_parent INT, + deliverable_estimate NUMERIC(10, 2), + deliverable_active SMALLINT DEFAULT 1 NOT NULL, + deliverable_description VARCHAR(MAX), +-- + PRIMARY KEY (deliverable_id) +); + +CREATE INDEX hermes_deliverables_client ON hermes_deliverables (client_id, deliverable_name); diff --git a/hermes/scripts/sql/hermes.oci8.sql b/hermes/scripts/sql/hermes.oci8.sql new file mode 100644 index 000000000..c72abfdbd --- /dev/null +++ b/hermes/scripts/sql/hermes.oci8.sql @@ -0,0 +1,51 @@ +-- $Horde: hermes/scripts/sql/hermes.oci8.sql,v 1.8 2009/10/19 11:18:26 jan Exp $ + +CREATE TABLE hermes_timeslices ( + timeslice_id NUMBER(16) NOT NULL, + clientjob_id VARCHAR2(255) NOT NULL, + employee_id VARCHAR2(255) NOT NULL, + jobtype_id NUMBER(16) NOT NULL, + timeslice_hours NUMBER(10, 2) NOT NULL, + timeslice_rate NUMBER(10, 2), + timeslice_isbillable NUMBER(1) DEFAULT 0 NOT NULL, + timeslice_date NUMBER(16) NOT NULL, + timeslice_description CLOB NOT NULL, + timeslice_note CLOB, + timeslice_submitted NUMBER(1) DEFAULT 0 NOT NULL, + timeslice_exported NUMBER(1) DEFAULT 0 NOT NULL, + costobject_id VARCHAR2(255), +-- + PRIMARY KEY (timeslice_id) +); + +CREATE TABLE hermes_jobtypes ( + jobtype_id NUMBER(16) NOT NULL, + jobtype_name VARCHAR2(255), + jobtype_enabled NUMBER(1) DEFAULT 1 NOT NULL, + jobtype_rate NUMBER(10, 2), + jobtype_billable NUMBER(1) DEFAULT 0 NOT NULL, +-- + PRIMARY KEY (jobtype_id) +); + +CREATE TABLE hermes_clientjobs ( + clientjob_id VARCHAR2(255) NOT NULL, + clientjob_enterdescription NUMBER(1) DEFAULT 1 NOT NULL, + clientjob_exportid VARCHAR2(255), +-- + PRIMARY KEY (clientjob_id) +); + +CREATE TABLE hermes_deliverables ( + deliverable_id NUMBER(16) NOT NULL, + client_id VARCHAR2(250) NOT NULL, + deliverable_name VARCHAR2(250) NOT NULL, + deliverable_parent NUMBER(16), + deliverable_estimate NUMBER(10, 2), + deliverable_active NUMBER(1) DEFAULT 1 NOT NULL, + deliverable_description CLOB, +-- + PRIMARY KEY (deliverable_id) +); + +CREATE INDEX hermes_deliverables_client ON hermes_deliverables (client_id, deliverable_name); diff --git a/hermes/scripts/sql/hermes.sql b/hermes/scripts/sql/hermes.sql new file mode 100644 index 000000000..1562baac8 --- /dev/null +++ b/hermes/scripts/sql/hermes.sql @@ -0,0 +1,52 @@ +-- $Horde: hermes/scripts/sql/hermes.sql,v 1.15 2008/06/30 22:39:27 jan Exp $ + +CREATE TABLE hermes_timeslices ( + timeslice_id INT NOT NULL, + clientjob_id VARCHAR(255) NOT NULL, + employee_id VARCHAR(255) NOT NULL, + jobtype_id INT NOT NULL, + timeslice_hours NUMERIC(10, 2) NOT NULL, + timeslice_rate NUMERIC(10, 2), + timeslice_isbillable SMALLINT DEFAULT 0 NOT NULL, + timeslice_date INT NOT NULL, + timeslice_description TEXT NOT NULL, + timeslice_note TEXT, + timeslice_submitted SMALLINT DEFAULT 0 NOT NULL, + timeslice_exported SMALLINT DEFAULT 0 NOT NULL, + costobject_id VARCHAR(255), +-- + PRIMARY KEY (timeslice_id) +); + +CREATE TABLE hermes_jobtypes ( + jobtype_id INT NOT NULL, + jobtype_name VARCHAR(255), + jobtype_enabled SMALLINT DEFAULT 1 NOT NULL, + jobtype_rate NUMERIC(10, 2), + jobtype_billable SMALLINT DEFAULT 0 NOT NULL, +-- + PRIMARY KEY (jobtype_id) +); + +CREATE TABLE hermes_clientjobs ( + clientjob_id VARCHAR(255) NOT NULL, + clientjob_enterdescription SMALLINT DEFAULT 1 NOT NULL, + clientjob_exportid VARCHAR(255), +-- + PRIMARY KEY (clientjob_id) +); + +CREATE TABLE hermes_deliverables ( + deliverable_id INT NOT NULL, + client_id VARCHAR(255) NOT NULL, + deliverable_name VARCHAR(255) NOT NULL, + deliverable_parent INT, + deliverable_estimate NUMERIC(10, 2), + deliverable_active SMALLINT DEFAULT 1 NOT NULL, + deliverable_description TEXT, +-- + PRIMARY KEY (deliverable_id) +); + +CREATE INDEX hermes_deliverables_client ON hermes_deliverables (client_id); +CREATE INDEX hermes_deliverables_active ON hermes_deliverables (deliverable_active); diff --git a/hermes/scripts/sql/hermes.xml b/hermes/scripts/sql/hermes.xml new file mode 100644 index 000000000..2b5a07276 --- /dev/null +++ b/hermes/scripts/sql/hermes.xml @@ -0,0 +1,315 @@ + + + + name + false + false + + + + hermes_clientjobs + + + + + clientjob_id + text + + true + 255 + + + + clientjob_enterdescription + integer + 1 + true + 1 + + + + clientjob_exportid + text + + false + 255 + + + + hermes_clientjobs_pKey + true + + clientjob_id + ascending + + + + + +
    + + + + hermes_deliverables + + + + + deliverable_id + integer + 0 + true + + + + client_id + text + + true + 255 + + + + deliverable_name + text + + true + 255 + + + + deliverable_parent + integer + + false + + + + deliverable_estimate + decimal + + false + 10,2 + + + + deliverable_active + integer + 1 + true + 1 + + + + deliverable_description + text + + false + + + + hermes_deliverables_client + + client_id + ascending + + + + + hermes_deliverables_active + + deliverable_active + ascending + + + + + hermes_deliverables_pKey + true + + deliverable_id + ascending + + + + + +
    + + + + hermes_jobtypes + + + + + jobtype_id + integer + 0 + true + + + + jobtype_name + text + + false + 255 + + + + jobtype_enabled + integer + 1 + true + 1 + + + + jobtype_rate + decimal + + false + 10,2 + + + + jobtype_billable + integer + 0 + true + 1 + + + + hermes_jobtypes_pKey + true + + jobtype_id + ascending + + + + + +
    + + + + hermes_timeslices + + + + + timeslice_id + integer + 0 + true + + + + clientjob_id + text + + true + 255 + + + + employee_id + text + + true + 255 + + + + jobtype_id + integer + 0 + true + + + + timeslice_hours + decimal + 0.00 + true + 10,2 + + + + timeslice_rate + decimal + + false + 10,2 + + + + timeslice_isbillable + integer + 0 + true + 1 + + + + timeslice_date + integer + 0 + true + + + + timeslice_description + text + + true + + + + timeslice_note + text + + false + + + + timeslice_submitted + integer + 0 + true + 1 + + + + timeslice_exported + integer + 0 + true + 1 + + + + costobject_id + text + + false + 255 + + + + hermes_timeslices_pKey + true + + timeslice_id + ascending + + + + + +
    + +
    diff --git a/hermes/scripts/upgrades/2007-04-20_drop_invoicing.sql b/hermes/scripts/upgrades/2007-04-20_drop_invoicing.sql new file mode 100644 index 000000000..d47847836 --- /dev/null +++ b/hermes/scripts/upgrades/2007-04-20_drop_invoicing.sql @@ -0,0 +1,5 @@ +-- $Horde: hermes/scripts/upgrades/2007-04-20_drop_invoicing.sql,v 1.1 2007/04/19 23:14:43 jan Exp $ + +DROP TABLE hermes_invoice_batches; +DROP TABLE hermes_invoices; +DROP TABLE hermes_invoice_items; diff --git a/hermes/scripts/upgrades/2007-04-25_add_jobtype_rate.sql b/hermes/scripts/upgrades/2007-04-25_add_jobtype_rate.sql new file mode 100644 index 000000000..3c110c931 --- /dev/null +++ b/hermes/scripts/upgrades/2007-04-25_add_jobtype_rate.sql @@ -0,0 +1 @@ +ALTER TABLE hermes_jobtypes ADD jobtype_rate FLOAT; diff --git a/hermes/scripts/upgrades/2007-10-17_add_jobtype_billable.sql b/hermes/scripts/upgrades/2007-10-17_add_jobtype_billable.sql new file mode 100644 index 000000000..2ff9cc683 --- /dev/null +++ b/hermes/scripts/upgrades/2007-10-17_add_jobtype_billable.sql @@ -0,0 +1 @@ +ALTER TABLE hermes_jobtypes ADD jobtype_billable SMALLINT DEFAULT 1 NOT NULL; diff --git a/hermes/scripts/upgrades/2008-07-01_deliverables_index.sql b/hermes/scripts/upgrades/2008-07-01_deliverables_index.sql new file mode 100644 index 000000000..6390de3bb --- /dev/null +++ b/hermes/scripts/upgrades/2008-07-01_deliverables_index.sql @@ -0,0 +1,3 @@ +ALTER TABLE hermes_deliverables DROP INDEX hermes_deliverables_client; +CREATE INDEX hermes_deliverables_client ON hermes_deliverables (client_id); +CREATE INDEX hermes_deliverables_active ON hermes_deliverables (deliverable_active); diff --git a/hermes/search.php b/hermes/search.php new file mode 100644 index 000000000..2e4643c87 --- /dev/null +++ b/hermes/search.php @@ -0,0 +1,141 @@ + + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; +require_once HERMES_BASE . '/lib/Forms/Export.php'; +require_once HERMES_BASE . '/lib/Forms/Search.php'; +require_once HERMES_BASE . '/lib/Forms/Time.php'; +require_once HERMES_BASE . '/lib/Table.php'; +require_once 'Horde/Identity.php'; +require_once 'Horde/Data.php'; + +$vars = Horde_Variables::getDefaultVariables(); + +$delete = $vars->get('delete'); +if (!empty($delete)) { + $result = $hermes->updateTime(array(array('id' => $delete, 'delete' => true))); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + $notification->push(sprintf(_("There was an error deleting the time: %s"), $result->getMessage()), 'horde.error'); + } else { + $notification->push(_("The time entry was successfully deleted."), 'horde.success'); + $vars->remove('delete'); + } +} + +$criteria = null; + +$formname = $vars->get('formname'); +switch ($formname) { +case 'searchform': + $form = new SearchForm($vars); + $form->validate($vars); + $criteria = $form->getSearchCriteria($vars); + if (is_null($criteria)) { + unset($_SESSION['hermes_search_criteria']); + } else { + $_SESSION['hermes_search_criteria'] = serialize($vars); + } + break; + +case 'exportform': + if (!isset($_SESSION['hermes_search_criteria'])) { + $notification->push(_("No search to export!"), 'horde.error'); + } else { + $searchVars = unserialize($_SESSION['hermes_search_criteria']); + $searchForm = new SearchForm($searchVars); + $criteria = $searchForm->getSearchCriteria($searchVars); + if (is_null($criteria)) { + $notification->push(_("No search to export!"), 'horde.error'); + } else { + $form = new ExportForm($vars); + $form->validate($vars); + if ($form->isValid()) { + $form->getInfo($vars, $info); + $hours = $hermes->getHours($criteria); + if (is_a($hours, 'PEAR_Error')) { + $notification->push($hours, 'horde.error'); + } elseif (is_null($hours) || count($hours) == 0) { + $notification->push(_("No time to export!"), 'horde.error'); + } else { + $exportHours = Hermes::makeExportHours($hours); + $data = Horde_Data::factory(array('hermes', $info['format'])); + $filedata = $data->exportData($exportHours); + $browser->downloadHeaders($data->getFilename('export'), $data->getContentType(), false, strlen($filedata)); + + echo $filedata; + if (!empty($info['mark_exported']) && + $info['mark_exported'] == 'yes' && + $perms->hasPermission('hermes:review', Horde_Auth::getAuth(), + Horde_Perms::EDIT)) { + $hermes->markAs('exported', $hours); + } + exit; + } + } + } + } +} + + +$title = _("Search for Time"); +$print_view = (bool)$vars->get('print'); +if (!$print_view) { + Horde::addScriptFile('popup.js', 'horde', true); +} +require HERMES_TEMPLATES . '/common-header.inc'; + +if (isset($_SESSION['hermes_search_criteria'])) { + $searchVars = unserialize($_SESSION['hermes_search_criteria']); +} else { + $searchVars = $vars; +} +$form = new SearchForm($searchVars); + +if ($print_view) { + require_once $registry->get('templates', 'horde') . '/javascript/print.js'; +} else { + $print_link = Horde::url(Horde_Util::addParameter('search.php', array('print' => 'true'))); + require HERMES_TEMPLATES . '/menu.inc'; + $form->renderActive(new Horde_Form_Renderer(), $searchVars, 'search.php', 'post'); + echo '
    '; +} + +if (isset($_SESSION['hermes_search_criteria'])) { + echo Hermes::tabs(); + + if (is_null($criteria)) { + $criteria = $form->getSearchCriteria($searchVars); + } + + $table = new Horde_Ui_Table('results', $vars, + array('title' => _("Search Results"), + 'name' => 'hermes/hours', + 'params' => $criteria)); + + $template = new Horde_Template(); + $template->setOption('gettext', true); + $template->set('postUrl', Horde::applicationUrl('time.php', false, -1)); + $template->set('sessionId', Horde_Util::formInput()); + $template->set('table', $table->render()); + + echo $template->fetch(HERMES_TEMPLATES . '/time/form.html'); +} + +if (!$print_view) { + echo '
    '; + $exportForm = new ExportForm($vars); + $exportForm->renderActive(new Horde_Form_Renderer(), $vars, 'search.php', 'post'); +} + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/hermes/start.php b/hermes/start.php new file mode 100644 index 000000000..07b7509c1 --- /dev/null +++ b/hermes/start.php @@ -0,0 +1,49 @@ + + * @author Jan Schneider + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; + +$vars = Horde_Variables::getDefaultVariables(); + +$form = new Horde_Form($vars, _("Stop Watch")); +$form->addVariable(_("Stop watch description"), 'description', 'text', true); + +if ($form->validate($vars)) { + $timers = $prefs->getValue('running_timers', false); + if (empty($timers)) { + $timers = array(); + } else { + $timers = @unserialize($timers); + if (!$timers) { + $timers = array(); + } + } + $now = time(); + $timers[$now] = array('name' => Horde_String::convertCharset($vars->get('description'), + Horde_Nls::getCharset(), + $prefs->getCharset()), + 'time' => $now); + $prefs->setValue('running_timers', serialize($timers), false); + + Horde_Util::closeWindowJS('alert(\'' . addslashes(sprintf(_("The stop watch \"%s\" has been started and will appear in the sidebar at the next refresh."), $vars->get('description'))) . '\');'); + exit; +} + +$title = _("Stop Watch"); +require HERMES_TEMPLATES . '/common-header.inc'; + +$renderer = new Horde_Form_Renderer(); +$form->renderActive($renderer, $vars, 'start.php', 'post'); + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/hermes/templates/common-header.inc b/hermes/templates/common-header.inc new file mode 100644 index 000000000..b64edd578 --- /dev/null +++ b/hermes/templates/common-header.inc @@ -0,0 +1,29 @@ + + + + + +' : '' ?> + +get('name'); +if (!empty($title)) $page_title .= ' :: ' . $title; +if (!empty($refresh_time) && ($refresh_time > 0) && !empty($refresh_url)) { + echo "\n"; +} + +Horde::includeScriptFiles(); + +?> +<?php echo htmlspecialchars($page_title) ?> + + + + +> diff --git a/hermes/templates/deliverables/list.inc b/hermes/templates/deliverables/list.inc new file mode 100644 index 000000000..bdcb85cb2 --- /dev/null +++ b/hermes/templates/deliverables/list.inc @@ -0,0 +1,13 @@ +
    + + + +
    1, 'client_id' => $vars->get('client_id'))); + +?>
    renderTree() ?>
    diff --git a/hermes/templates/menu.inc b/hermes/templates/menu.inc new file mode 100644 index 000000000..1864954df --- /dev/null +++ b/hermes/templates/menu.inc @@ -0,0 +1,4 @@ + +notify(array('listeners' => 'status')) ?> diff --git a/hermes/templates/time/form.html b/hermes/templates/time/form.html new file mode 100644 index 000000000..07952fdb0 --- /dev/null +++ b/hermes/templates/time/form.html @@ -0,0 +1,6 @@ +
    + + + + + diff --git a/hermes/themes/graphics/clockout.png b/hermes/themes/graphics/clockout.png new file mode 100644 index 0000000000000000000000000000000000000000..2802414d458483e3a82ee9015748a1ca56c4ea6e GIT binary patch literal 560 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQn*W+*g=5KmZKJj$X!FTUP zr4o}@D&-x%{pJ7En?F8&`SmX&W9Q3%S3dnOnZJ3;lGQ67{n>r)^{Sg6Crvx8=e1PK zaBA~~&puNx2W1q6&AYv2*X^D~msgi8did@C```c1-1}I(;QHwg|D#$@#Z@2pKV!P1 z)AW@)?=II5(97Jv_R!O3KmK#`@&!aE%-#Fw|GRf8jtivXw%2-9&pUA|;mD^CAHL5# z`OeZaz`gq5qGcE27vEmE_-sN#f^qGs?fdToo&O(*{{I)e*3|{%IFtnW1p~R10ER== z8(n~A-S>2H43Ur&J=pEkWFWzIp`IgegQk*rzJ_q%oGDYMr5@P#y?*rznL`Kcty5ph z)bel~SR9wp2F={X0UaQ)Y?z-gbqwVoNmjY*phHUz~d`kS~eeW+{R9<}| zl1s4d;uGbr77uwj*=#{C&sisUqc(1Qa$ILhRN*?lZy`4tE*uqHIj1aUZ*(;i2 z|4S2b9LMqflGQK$7Wl*d0_nE~CjFQ(voaJS%6{9g`ymPXF&tED6~&?;hk@YyQlp@T zV63pYQ`^?mCD*>_d9pcg&Z}*@arM)y&%N;@*TCHyp2yt=58ijTS@_&jTaWVY80zde z1@`rc(>=#d4zX*!$A&D2&GGi@&|{}o9r>$i*vHy*kYzfA-0;3ZKdZI96TJg>@u$8E zZLiXZnM2o}P2$Sn3nX)j9%1#0ih8+Zj&Y>#$;3Xgg~Y}tV(WQ=YQGiisRiur%$kG)~xTW*sxBHGCFV@o6Q4sbmTt zm&60`SN>-MW`MdMj^QHfl7}!%|43tMIfW04BHn*rK_HgIVrXW8kRk($nFWqGSayPHwHnIhGD@Wq3WdS}c>cbhuvZLt`DG5zLlJ_Ml)#Yz z)>Xa{ZKJ9x6h%QUmxClpNT<^rB<$&Qn2;?oOo;t~pZ^2wEUQI7=opK(k!2a#Y!;#@ zQlU_YgY;`}KpeCUy*WD2lecq_Z9|A42nYlM@Or)UdB<%JM~t`C#vzVbNjHGOU=Ti^ z4=$IBuFnk)H$!Nef=;Isy*C}ENK^1gOG_6A%@K3Z&T=$9T;u!$biny9EABfW00000 LNkvXXu0mjfZBiw8 literal 0 HcmV?d00001 diff --git a/hermes/themes/graphics/favicon.ico b/hermes/themes/graphics/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5379a757e65b99f9d050607d7e355acab810c118 GIT binary patch literal 1406 zcmeHHOHUe66#iz$8JK~o!)rzq#lCFCTA;t8EU9?S`F1l*MfhwVjFK3Yu;@Y-ChU!g55xyA5qX=~J7epgsNc=GIp@3QCg(eg51`1AB#>K=Pb?q< zcu0a!7$u?d|6nlyY7p`omzS5gxVS*C*F(44MW@q2yWK{s)k3q`M5EEb`T05O^*YYZ z&QPn>aC&-*YPE_=rGj#~j8dtDVzG#mlM@^tALHog2#1GyXJ;`pGlN(xhDaoWa5#)$Fo-}P0KeZ4pU(%c z*9(uw1Gn1^MNzKzaFg6@;D6gdNX3e;Bj{LR$0jZ+89RL6T literal 0 HcmV?d00001 diff --git a/hermes/themes/graphics/hermes.png b/hermes/themes/graphics/hermes.png new file mode 100644 index 0000000000000000000000000000000000000000..f6919137bc0b0851c4e7b4e47b86ed349a44b458 GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfu>hYCS0MfW|NlRK{`~&^``52u zKY#xG@#Dw$@87?D`}Xzg*DqhbeE$6T)2B}#KYsl1;lum)@87+9_xA1EH*em&e*OB@ zt5+{yzI^fG#q;OSpFMl_^y$+lPo6w}{P@wMM-Lx9ynFZV?c296T)1%d?AeniPo6k& z;=q9e`}XbIyLa!NJ$rWV-o10@&TZSaZQZ(c%a$#hHf`FlVZ-|M>z6HCwqU`6xpU{v znl)?Mv}qG2Oz7?Ht*NPri;J_jx3{&mwY0P}F)=YTG&C?U(AU=&7Z(S*Uo+{770@S6 zB|(0{KrUr~!9@%dRt%>+T^vIsBv}vc_HqssalN?n+b&1lBjPNRo~gZjV-nF-uq6GWYJqO-zhmpZv>xS@!Xt!8(B}mrurT zx^?c%^vzxc|K`j*IgMq#xXa%k%`I#!o2AaEc&G@@5?=FblGCfxR<|xFv`+Q8{VZ7M z*#mCPN3)k7Jio}8|C{W#w=X{?ACc2~eNxR>)%C_=j&)JDdvmR;rn5XGSQjw-VXnz_cKfRy_ZZ|YPgg&ebxsLQ04(E2v;Y7A literal 0 HcmV?d00001 diff --git a/hermes/themes/graphics/invoices.png b/hermes/themes/graphics/invoices.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5084b19038ce5c8d23cd8e0e66d12938264b66 GIT binary patch literal 533 zcmV+w0_y#VP)$dKg{xaN`{A^xON64a(mdpjnBOP9C@;-b_-(%LL-g_xhAV<~M@ zhk`@7*7!RHvPc~oIwTl^WU3%8ujhR5!J(wr7hcZC!{c3WC^QODjc7jNF-2v^BNbO->|=x8L*%Nu3D`Ygb7eCmoXR&P%4!WkH;BA zwE|e8&8sWR`miCU(`n>#Iow?TMd!~i%uG+iG)>rF-Z3D-0Vd=XP7ij;;y2O|%}E1u zbF(Ps*YR>KN1Go#T!j6p$N)=y2l6AC-$7&V2cAB8OwpGX;wZdWMdz#m`(pv>6%2s00000NkvXXu0mjfr4sJv literal 0 HcmV?d00001 diff --git a/hermes/themes/graphics/newdeliverable.png b/hermes/themes/graphics/newdeliverable.png new file mode 100644 index 0000000000000000000000000000000000000000..13accaa4f3d937e1833cddb7adee60989285b328 GIT binary patch literal 503 zcmVd z<;P~_~&qx7vIvuoHtv)ac8-b(zY6_^` zZll?3qF%3~TCMg#vp*_7>gww2>+9_7?CtIC?(XjI@9*&N@bU5S^78WY z^Yird^!4@i_V)Jo_xJet`1$$y`uh6&`}_R-{Qv*|0000niT{xR0004WQchC4;RMropG0yD8nC0}%k-o85D-p14CJFEQk*s_fN9>vC!8+I0oaSY z6Ni$yH-rFSl4V)@@)o{fA+U{#;v_lNc7eAt5p3~NVHm0{tf_NFFqn8sDW75u4{MHd zo0J7y@PK))eXr}y2GsL?-=h!P>;oyqab08OSa;n^X)JE0d7agPRQdn@4+U{0AgTx9 Qk^lez07*qoM6N<$f-kTE761SM literal 0 HcmV?d00001 diff --git a/hermes/themes/graphics/timer-stop.png b/hermes/themes/graphics/timer-stop.png new file mode 100644 index 0000000000000000000000000000000000000000..a14f92d5ee366adfa64e3e5c34431371470ef8ee GIT binary patch literal 529 zcmV+s0`C2ZP)SaprEFvrn0iKw6wIgwzj*wyS%)-y}iA_z`)7L$<58p(9qD`-QDrp(DU2T z;^N};+|u;j)8pgg_1@Fu!`QX&|;n(!y+UMuz_~O{;=;-$3+xg?!>FMeE ziXu~>+9?M=G*M-?CtIC?(XjQ>*x6E-F{Z_V)Jo_xJet`1$$y`uh6&`}_R-{Qv*|00016&0SIe0004WQchC + */ + +@define('HERMES_BASE', dirname(__FILE__)); +require_once HERMES_BASE . '/lib/base.php'; +require_once HERMES_BASE . '/lib/Forms/Time.php'; +require_once HERMES_BASE . '/lib/Table.php'; + +$vars = Horde_Variables::getDefaultVariables(); + +$delete = $vars->get('delete'); +if (!empty($delete)) { + $result = $hermes->updateTime(array(array('id' => $delete, 'delete' => true))); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + $notification->push(sprintf(_("There was an error deleting the time: %s"), $result->getMessage()), 'horde.error'); + } else { + $notification->push(_("The time entry was successfully deleted."), 'horde.success'); + $vars->remove('delete'); + } +} + +switch ($vars->get('formname')) { +case 'submittimeform': + $time = array(); + $item = $vars->get('item'); + if (is_null($item) || !count($item)) { + $notification->push(_("No timeslices were selected to submit."), + 'horde.error'); + } else { + foreach ($item as $id => $val) { + $time[] = array('id' => $id); + } + $result = $hermes->markAs('submitted', $time); + if (is_a($result, 'PEAR_Error')) { + $notification->push(sprintf(_("There was an error submitting your time: %s"), $result->getMessage()), 'horde.error'); + } else { + $notification->push(_("Your time was successfully submitted."), + 'horde.success'); + $vars = new Horde_Variables(); + } + } + break; +} + +// We are displaying all time. +$tabs = Hermes::tabs(); +$criteria = array('employee' => Horde_Auth::getAuth(), + 'submitted' => false, + 'link_page' => 'time.php'); +$table = new Horde_Ui_Table('week', $vars, + array('title' => _("My Unsubmitted Time"), + 'name' => 'hermes/hours', + 'params' => $criteria)); + +$template = new Horde_Template(); +$template->setOption('gettext', true); +$template->set('postUrl', Horde::applicationUrl('time.php', false, -1)); +$template->set('sessionId', Horde_Util::formInput()); +$template->set('table', $table->render()); + +$title = _("My Time"); +$print_view = (Horde_Util::getFormData('print') == 'true'); +if (!$print_view) { + Horde::addScriptFile('popup.js', 'horde', true); +} +require HERMES_TEMPLATES . '/common-header.inc'; + +if ($print_view) { + require $registry->get('templates', 'horde') . '/javascript/print.js'; +} else { + $print_link = Horde_Util::addParameter(Horde::applicationUrl('time.php'), 'print', 'true'); + require HERMES_TEMPLATES . '/menu.inc'; +} + +echo $tabs; +echo $template->fetch(HERMES_TEMPLATES . '/time/form.html'); +require $registry->get('templates', 'horde') . '/common-footer.inc'; -- 2.11.0