From 84db44f9aaa1e6aa205e62b3b743d506a1dd2701 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Sun, 7 Jul 2013 17:03:23 +0200 Subject: [PATCH 01/21] Correction on view_bug_pm_summary functions The summary labels were ignoring translations --- ProjectManagement/ProjectManagement.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ProjectManagement/ProjectManagement.php b/ProjectManagement/ProjectManagement.php index e853473..9a27165 100644 --- a/ProjectManagement/ProjectManagement.php +++ b/ProjectManagement/ProjectManagement.php @@ -515,9 +515,9 @@ function view_bug_pm_summary( $p_event, $p_bug_id ) { $t_todo = get_actual_work_todo( $t_work ); echo ''; - echo 'Est' . minutes_to_time( $t_est, true ) . ' - Done' . minutes_to_time( $t_done, false ) . ' - Todo' . minutes_to_time( $t_todo, true ) . ''; + echo '' . plugin_lang_get( 'est' ) . '' . minutes_to_time( $t_est, true ) . ' + ' . plugin_lang_get( 'done' ) . '' . minutes_to_time( $t_done, false ) . ' + ' . plugin_lang_get( 'todo' ) . '' . minutes_to_time( $t_todo, true ) . ''; } # Fetch customer payment summary From b477cec13a6ae6a99e5075937847adba9b814a2e Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Tue, 9 Jul 2013 15:18:07 +0200 Subject: [PATCH 02/21] Update time_registration_page.php Gets translation of month string --- ProjectManagement/pages/time_registration_page.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/pages/time_registration_page.php b/ProjectManagement/pages/time_registration_page.php index 89ed29b..9e0fd2f 100644 --- a/ProjectManagement/pages/time_registration_page.php +++ b/ProjectManagement/pages/time_registration_page.php @@ -326,12 +326,12 @@ > - + > - + From eb94da11b5679839d2606606d22d68fb6b11c0c7 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Tue, 9 Jul 2013 15:18:53 +0200 Subject: [PATCH 03/21] Update strings_english.txt Added month literals in english --- ProjectManagement/lang/strings_english.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ProjectManagement/lang/strings_english.txt b/ProjectManagement/lang/strings_english.txt index 731ff0b..3e3be07 100644 --- a/ProjectManagement/lang/strings_english.txt +++ b/ProjectManagement/lang/strings_english.txt @@ -151,4 +151,17 @@ $s_plugin_ProjectManagement_friday = 'friday'; $s_plugin_ProjectManagement_saturday = 'saturday'; $s_plugin_ProjectManagement_sunday = 'sunday'; + + $s_plugin_ProjectManagement_January = 'January'; + $s_plugin_ProjectManagement_February = 'February'; + $s_plugin_ProjectManagement_March = 'March'; + $s_plugin_ProjectManagement_April = 'April'; + $s_plugin_ProjectManagement_May = 'May'; + $s_plugin_ProjectManagement_June = 'June'; + $s_plugin_ProjectManagement_July = 'July'; + $s_plugin_ProjectManagement_August = 'August'; + $s_plugin_ProjectManagement_September = 'September'; + $s_plugin_ProjectManagement_October = 'October'; + $s_plugin_ProjectManagement_November = 'November'; + $s_plugin_ProjectManagement_December = 'December ?> From 7f8003d62d32cc4fe9d6ae83c025ce2ea70ed77a Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Tue, 9 Jul 2013 15:19:16 +0200 Subject: [PATCH 04/21] Update strings_spanish.txt Added month literals in english --- ProjectManagement/lang/strings_spanish.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ProjectManagement/lang/strings_spanish.txt b/ProjectManagement/lang/strings_spanish.txt index 15bb3ac..2df81fc 100644 --- a/ProjectManagement/lang/strings_spanish.txt +++ b/ProjectManagement/lang/strings_spanish.txt @@ -148,4 +148,17 @@ $s_plugin_ProjectManagement_friday = 'viernes'; $s_plugin_ProjectManagement_saturday = 'sabado'; $s_plugin_ProjectManagement_sunday = 'domingo'; + + $s_plugin_ProjectManagement_January = 'Enero'; + $s_plugin_ProjectManagement_February = 'Febrero'; + $s_plugin_ProjectManagement_March = 'Marzo'; + $s_plugin_ProjectManagement_April = 'Abril'; + $s_plugin_ProjectManagement_May = 'Mayo'; + $s_plugin_ProjectManagement_June = 'Junio'; + $s_plugin_ProjectManagement_July = 'Julio'; + $s_plugin_ProjectManagement_August = 'Agosto'; + $s_plugin_ProjectManagement_September = 'Septiembre'; + $s_plugin_ProjectManagement_October = 'Octubre'; + $s_plugin_ProjectManagement_November = 'Noviembre'; + $s_plugin_ProjectManagement_December = 'Diciembre'; ?> From b88f4e2ee3aaa5058ce6a9cec150fe151e3df2e6 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Tue, 9 Jul 2013 20:19:13 +0200 Subject: [PATCH 05/21] Update time_registration_page.php --- ProjectManagement/pages/time_registration_page.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/pages/time_registration_page.php b/ProjectManagement/pages/time_registration_page.php index 9e0fd2f..f149a97 100644 --- a/ProjectManagement/pages/time_registration_page.php +++ b/ProjectManagement/pages/time_registration_page.php @@ -326,12 +326,12 @@ > - + > - + From a16eed2b77028a87c6c248cfa0be96e5853fc11f Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 20:10:21 +0200 Subject: [PATCH 06/21] Update report_resource_progress_page.php When selecting a project (without versions) with subprojects (with versions), the first $f_target_version is referring to a child project, so version_get_id fails to recover info for current project. I have included a previous check to avoid an "ugly" error. The logic should be reviewed but now is safer ;-) --- ProjectManagement/pages/report_resource_progress_page.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ProjectManagement/pages/report_resource_progress_page.php b/ProjectManagement/pages/report_resource_progress_page.php index 68689cc..3052fac 100644 --- a/ProjectManagement/pages/report_resource_progress_page.php +++ b/ProjectManagement/pages/report_resource_progress_page.php @@ -33,6 +33,8 @@ echo plugin_lang_get( 'project_without_versions' ); } else if ( $t_all_versions_selected ) { echo plugin_lang_get( 'all_versions_selected' ); +} else if ( version_get_id( $f_target_version ) === false ) { + echo plugin_lang_get( 'project_without_versions' ); } else { # Release dates of previous and current version $t_release_date_target = version_get_field( version_get_id( $f_target_version ), 'date_order' ); @@ -347,4 +349,4 @@ } echo ''; # The whole page must be a form to include the input elements from underlying sections -} \ No newline at end of file +} From 719677b2a1f5afd4e9c8ba8a8223a2df09e933ca Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:02:35 +0200 Subject: [PATCH 07/21] Update PlottableBug.class.php Changed call to get work_types array --- ProjectManagement/classes/PlottableBug.class.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/classes/PlottableBug.class.php b/ProjectManagement/classes/PlottableBug.class.php index f25821a..7b04b62 100644 --- a/ProjectManagement/classes/PlottableBug.class.php +++ b/ProjectManagement/classes/PlottableBug.class.php @@ -39,7 +39,8 @@ protected function calculate_data_specific( $p_reference_date ) { # Step 1: Calculate the est, done, work and overdue - $t_worktypes = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); + // TODO: Validate if the new call is needed here or not + $t_worktypes = plugin_lang_get_enum( 'work_types' ); // MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); $this->todo = 0; foreach ( $t_worktypes as $t_work_type => $t_value ) { @@ -166,4 +167,4 @@ public function plot_specific_start( $p_unique_id, $p_last_dev_day, $p_min_date, Date: Wed, 10 Jul 2013 23:06:58 +0200 Subject: [PATCH 08/21] Update html_api.php Functions modified to work with localized enums --- ProjectManagement/pages/html_api.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/pages/html_api.php b/ProjectManagement/pages/html_api.php index e86c994..d7f82b3 100644 --- a/ProjectManagement/pages/html_api.php +++ b/ProjectManagement/pages/html_api.php @@ -88,10 +88,22 @@ function print_plugin_enum_string_option_list( $p_enum_name, $p_val = 0 ) { foreach ( $t_enum_values as $t_key => $t_value ) { echo ''; + echo '>' . plugin_get_enum_element ( $p_enum_name, $t_key ) . ''; } } +function print_plugin_enum_string_selected_value( $p_enum_name, $p_val = 0 ) { + $t_config_var_value = plugin_config_get( $p_enum_name ); + $t_enum_values = MantisEnum::getAssocArrayIndexedByValues( $t_config_var_value ); + + foreach ( $t_enum_values as $t_key => $t_value ) { + if ( $p_val == $t_key ) + return plugin_get_enum_element ( $p_enum_name, $t_key ); + } + + return null; +} + /*** * Prints the start of a region that is used as header of a collapsable section. * @param $p_div_id string The unique name for this div. @@ -264,4 +276,4 @@ function print_resource_unavailability_list( $p_user_id ) { } } -?> \ No newline at end of file +?> From 08ff4cf56d916e65ac32449ad47ff33b42c06838 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:08:08 +0200 Subject: [PATCH 09/21] Update report_registration_page.php Changed call to get work_types array --- ProjectManagement/pages/report_registration_page.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/pages/report_registration_page.php b/ProjectManagement/pages/report_registration_page.php index d618ff2..5ee829e 100644 --- a/ProjectManagement/pages/report_registration_page.php +++ b/ProjectManagement/pages/report_registration_page.php @@ -20,7 +20,7 @@ $t_bug_table = db_get_table( 'mantis_bug_table' ); $t_project_table = db_get_table( 'mantis_project_table' ); $t_category_table = db_get_table( 'mantis_category_table' ); -$t_work_types = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); +$t_work_types = plugin_lang_get_enum( 'work_types' ); $t_customer_work_type_exclusion_clause = build_customer_worktype_exclude_clause('work_type'); $t_const_done = PLUGIN_PM_DONE; @@ -146,7 +146,7 @@ $t_category_link = $t_plugin_page . '&category_id=' . $row["category_id"]; $t_bug_summary = $row["bug_summary"]; $t_book_date = date( config_get( 'short_date_format' ), $row["book_date"] ); - $t_work_type = MantisEnum::getLabel( plugin_config_get( "work_types" ), $row["work_type"] ); + $t_work_type = plugin_get_enum_element( 'work_types', $row["work_type"] ); $t_work_type_link = $t_plugin_page . '&work_type=' . $row["work_type"]; $t_hours = format( $row["minutes"] / 60 ); $t_hourly_rate = format( $row["hourly_rate"] ); From 9bc24f3cedb4578a3b8dc2c5ab889c8605a7b3a8 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:09:06 +0200 Subject: [PATCH 10/21] Update target_overview_page.php Changed call to get work_types array --- ProjectManagement/pages/target_overview_page.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/pages/target_overview_page.php b/ProjectManagement/pages/target_overview_page.php index cc7cd23..2cb932b 100644 --- a/ProjectManagement/pages/target_overview_page.php +++ b/ProjectManagement/pages/target_overview_page.php @@ -102,7 +102,7 @@ $t_category_name = $row["category_name"]; $t_bug_id = string_get_bug_view_link( $row['bug_id'], null, false ); $t_bug_summary = $row["summary"]; - $t_work_type = MantisEnum::getLabel( plugin_config_get( "work_types" ), $row["work_type"] ); + $t_work_type = plugin_get_enum_element( 'work_types', $row["work_type"] ); $t_target_date = date( config_get( 'short_date_format' ), $row["target_date"] ); $t_days_overdue = days_between( $row["target_date"] ) * -1; @@ -139,4 +139,4 @@ } ?> - \ No newline at end of file + From 5942ff2598076f89fe9fa209fb6c95bc995f25c6 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:10:30 +0200 Subject: [PATCH 11/21] Update ProjectManagement.php Changed call to get work_types array --- ProjectManagement/ProjectManagement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectManagement/ProjectManagement.php b/ProjectManagement/ProjectManagement.php index 9a27165..e5398be 100644 --- a/ProjectManagement/ProjectManagement.php +++ b/ProjectManagement/ProjectManagement.php @@ -573,7 +573,7 @@ function view_bug_time_registration( $p_event, $p_bug_id ) { $t_result_fetch_todo = db_query_bound( $t_query_fetch_todo ); # Get the different worktypes as an array - $t_work_types = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); + $t_work_types = plugin_lang_get_enum( 'work_types' ); # Remove worktypes which are off limits for this account $t_limited_work_types = plugin_config_get( 'work_type_thresholds' ); From 90523976874ee655ee865f6aed01aef67df35632 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:15:30 +0200 Subject: [PATCH 12/21] Update ProjectManagementAPI.php New functions to support plugin enums management --- ProjectManagement/ProjectManagementAPI.php | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ProjectManagement/ProjectManagementAPI.php b/ProjectManagement/ProjectManagementAPI.php index 612d570..ce3554a 100644 --- a/ProjectManagement/ProjectManagementAPI.php +++ b/ProjectManagement/ProjectManagementAPI.php @@ -41,6 +41,29 @@ class Action { const DELETE = 3; } + +/* + * TODO: Review if is the correct place for this function!! + */ +function plugin_get_enum_element( $p_enum_name, $p_val, $p_user = null, $p_project = null ) { + $config_var = plugin_config_get( $p_enum_name, null, $p_user, $p_project ); + $string_var = plugin_lang_get( $p_enum_name . '_enum_string' ); + + return MantisEnum::getLocalizedLabel( $config_var, $string_var, $p_val ); +} + +function plugin_lang_get_enum( $p_enum_name ) { + $t_config_var_value = plugin_config_get( $p_enum_name ); + $t_enum_values = MantisEnum::getAssocArrayIndexedByValues( $t_config_var_value ); + + foreach ( $t_enum_values as $t_key => $t_value ) { + $t_enum_values[$t_key] = plugin_get_enum_element ( $p_enum_name, $t_key ); + } + + return $t_enum_values; +} + + /** * Converts the specified amount of minutes to a string formatted as 'HH:MM'. * @param float $p_minutes an amount of minutes. From 053498dd60d2dbff94ae1122d21e232bb76146e4 Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:18:28 +0200 Subject: [PATCH 13/21] Update html_api.php Changed call to get unavailability_types array translated --- ProjectManagement/pages/html_api.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ProjectManagement/pages/html_api.php b/ProjectManagement/pages/html_api.php index d7f82b3..c4218cc 100644 --- a/ProjectManagement/pages/html_api.php +++ b/ProjectManagement/pages/html_api.php @@ -262,8 +262,7 @@ function print_resource_unavailability_list( $p_user_id ) { # First print an empty entry to avoid accidental deletion! echo ''; - $t_config_var_value = plugin_config_get( 'unavailability_types' ); - $t_enum_values = MantisEnum::getAssocArrayIndexedByValues( $t_config_var_value ); + $t_enum_values = plugin_lang_get_enum ( 'unavailability_types' ); while ( $t_row = db_fetch_array( $t_result ) ) { $t_period_string = date( config_get( 'short_date_format' ), $t_row["start_date"] ) . ' - ' . From aeb2046ee66926a4e7fc4b1fc4634d83e74c0cfc Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Wed, 10 Jul 2013 23:20:04 +0200 Subject: [PATCH 14/21] Update strings_english.txt Added enum strings to show how should be the name formated --- ProjectManagement/lang/strings_english.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ProjectManagement/lang/strings_english.txt b/ProjectManagement/lang/strings_english.txt index 3e3be07..3be2f14 100644 --- a/ProjectManagement/lang/strings_english.txt +++ b/ProjectManagement/lang/strings_english.txt @@ -1,4 +1,7 @@ Date: Fri, 19 Jul 2013 17:01:56 +0200 Subject: [PATCH 15/21] Update PlottableBug.class.php --- ProjectManagement/classes/PlottableBug.class.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ProjectManagement/classes/PlottableBug.class.php b/ProjectManagement/classes/PlottableBug.class.php index 7b04b62..4a35cca 100644 --- a/ProjectManagement/classes/PlottableBug.class.php +++ b/ProjectManagement/classes/PlottableBug.class.php @@ -39,8 +39,7 @@ protected function calculate_data_specific( $p_reference_date ) { # Step 1: Calculate the est, done, work and overdue - // TODO: Validate if the new call is needed here or not - $t_worktypes = plugin_lang_get_enum( 'work_types' ); // MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); + $t_worktypes = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); $this->todo = 0; foreach ( $t_worktypes as $t_work_type => $t_value ) { From 03706c9b4e0a8f41f76b831c5cbd4a94ccd0e57b Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Fri, 19 Jul 2013 17:02:42 +0200 Subject: [PATCH 16/21] Update strings_english.txt Removed enum strings transaltions --- ProjectManagement/lang/strings_english.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/ProjectManagement/lang/strings_english.txt b/ProjectManagement/lang/strings_english.txt index 3be2f14..3e3be07 100644 --- a/ProjectManagement/lang/strings_english.txt +++ b/ProjectManagement/lang/strings_english.txt @@ -1,7 +1,4 @@ Date: Fri, 19 Jul 2013 17:03:21 +0200 Subject: [PATCH 17/21] Update strings_english.txt --- ProjectManagement/lang/strings_english.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectManagement/lang/strings_english.txt b/ProjectManagement/lang/strings_english.txt index 3e3be07..45041ae 100644 --- a/ProjectManagement/lang/strings_english.txt +++ b/ProjectManagement/lang/strings_english.txt @@ -163,5 +163,5 @@ $s_plugin_ProjectManagement_September = 'September'; $s_plugin_ProjectManagement_October = 'October'; $s_plugin_ProjectManagement_November = 'November'; - $s_plugin_ProjectManagement_December = 'December -?> + $s_plugin_ProjectManagement_December = 'December'; + From 4385c707365f3afa39be1c0a15d249f26d66b35b Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Fri, 19 Jul 2013 17:12:26 +0200 Subject: [PATCH 18/21] Spanish translations update to test local Git config --- ProjectManagement/lang/strings_spanish.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ProjectManagement/lang/strings_spanish.txt b/ProjectManagement/lang/strings_spanish.txt index 2df81fc..568df4a 100644 --- a/ProjectManagement/lang/strings_spanish.txt +++ b/ProjectManagement/lang/strings_spanish.txt @@ -1,5 +1,6 @@ Date: Fri, 19 Jul 2013 17:13:57 +0200 Subject: [PATCH 19/21] Restituido fichero de traduccion --- ProjectManagement/lang/strings_spanish.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/ProjectManagement/lang/strings_spanish.txt b/ProjectManagement/lang/strings_spanish.txt index 568df4a..6fedd02 100644 --- a/ProjectManagement/lang/strings_spanish.txt +++ b/ProjectManagement/lang/strings_spanish.txt @@ -1,5 +1,4 @@ Date: Sat, 20 Jul 2013 17:57:47 +0200 Subject: [PATCH 20/21] Issue view: - Added link at the top of the issue view (EVENT_MENU_ISSUE). Created view 2: - Register time for work type and minutes type. - Added 'info' field in table 'work' - Substract 'todo' when 'done' is informed - When minutes_type=='est' => target_date=book_date - When minutes_type=='done' => done=done+minutes / todo=todo-minutes - When minutes_type=='completed' (new just for select) => completed_date=book_date / done=done+minutes / todo=0 - Remove own time register (if admin_own_threshold) - Remove others time register (if admin_threshold) - Show/Hide all work types on target table (show_all_work_types_on_bug_targets) - When a 'todo' is defined without 'est', 'todo' is shown in red and with a tooltip containing the error Config options: - [bug_view_mode][new] View selection: 1 (original) or 2 (purposed) - [show_all_work_types_on_bug_targets][new] Show/Hide all work types on target table. Only works on view 2 - [admin_own_threshold][new] Enabled to remove custom registers. Only works on view 2 - [edit_targets_threshold][old] Enable to modify targets over the targets table. It was defined on function config, but now is updatable from config page - [billable_mandatory_minimun_status] Select the minimun status for billable required shows the error - [billable_behavior_over_severity] Define behavior of billing requirement according to severity General: - More specific errors - More detailed history actions Customers: - Added 'association_mode' field in table 'customer' - Created 'project_customer' table - Customer management page updated with 'association_mode' field - When a new project is created, the customers with association_mode='auto' are attached automatically - From project, you can attach/detach customers, except those marked with association_mode='all' - When a issue is resolved or closed, 'all customers' is transformed in the current customers list. It avoids future billing changes when adding a new customer to the project. - 'paying_customers' is required only if 'is_billable' is set to true, and the issue has adquired the minimum status (currently, the minimum status is defined hardcoded in 'pm_bug_is_billable_affecting_required_paying_customers') Reports: - Added 'dashboard' report - Error control added for 'Resource progress' report - Added validation in 'print_progressbar_span' and 'print_progress_span' to avoid error when no resources are defined (only exploited when $g_show_detailed_errors=ON) - Show hourly rate and cost only is user has 'view_billing_threshold' permissions Report 'Time registration overview': - Layout adjustment to avoid paddings and margins - Collapsible panels Report 'Billing': - Shows only issues marked as billable Account configuration: - Moved the unavailability management to a self account preferences menu - Added list of future and past unavailability, allowing to remove just for future --- ProjectManagement/ProjectManagement.php | 1293 ++++++++--------- ProjectManagement/ProjectManagementAPI.php | 381 ++++- ProjectManagement/changes.txt | 58 + .../classes/PlottableBug.class.php | 2 +- ProjectManagement/lang/strings_english.txt | 69 +- ProjectManagement/lang/strings_french.txt | 2 - ProjectManagement/lang/strings_spanish.txt | 185 ++- .../pages/account_unavailability_delete.php | 20 + .../pages/account_unavailability_inc.php | 106 ++ .../pages/account_unavailability_page.php | 18 + .../pages/account_unavailability_update.php | 46 + ProjectManagement/pages/billing_page.php | 21 +- ProjectManagement/pages/bug_view_customer.php | 91 ++ .../pages/bug_view_target_option1.php | 177 +++ .../pages/bug_view_target_option2.php | 323 ++++ .../bug_view_time_registration_option1.php | 158 ++ .../bug_view_time_registration_option2.php | 229 +++ ProjectManagement/pages/config_page.php | 237 +-- ProjectManagement/pages/config_update.php | 11 + .../pages/customer_overview_page.php | 9 +- ProjectManagement/pages/customer_update.php | 7 +- .../pages/customer_update_page.php | 10 + ProjectManagement/pages/html_api.php | 256 +++- .../pages/project_customer_add.php | 28 + .../pages/project_customer_delete.php | 30 + .../pages/report_dashboard_page.php | 163 +++ .../pages/report_registration_page.php | 214 ++- ...egistration_page_time_per_category_inc.php | 59 + ...ation_page_time_per_project_detail_inc.php | 158 ++ ...registration_page_time_per_project_inc.php | 89 ++ ...on_page_time_per_project_work_type_inc.php | 80 + ...gistration_page_time_per_work_type_inc.php | 59 + ...egistration_page_time_registration_inc.php | 106 ++ .../pages/report_resource_progress_page.php | 4 +- .../pages/target_overview_page.php | 2 +- ProjectManagement/pages/target_update.php | 39 +- .../pages/time_registration_delete.php | 30 + .../pages/time_registration_update.php | 205 ++- 38 files changed, 3935 insertions(+), 1040 deletions(-) create mode 100644 ProjectManagement/changes.txt create mode 100644 ProjectManagement/pages/account_unavailability_delete.php create mode 100644 ProjectManagement/pages/account_unavailability_inc.php create mode 100644 ProjectManagement/pages/account_unavailability_page.php create mode 100644 ProjectManagement/pages/account_unavailability_update.php create mode 100644 ProjectManagement/pages/bug_view_customer.php create mode 100644 ProjectManagement/pages/bug_view_target_option1.php create mode 100644 ProjectManagement/pages/bug_view_target_option2.php create mode 100644 ProjectManagement/pages/bug_view_time_registration_option1.php create mode 100644 ProjectManagement/pages/bug_view_time_registration_option2.php create mode 100644 ProjectManagement/pages/project_customer_add.php create mode 100644 ProjectManagement/pages/project_customer_delete.php create mode 100644 ProjectManagement/pages/report_dashboard_page.php create mode 100644 ProjectManagement/pages/report_registration_page_time_per_category_inc.php create mode 100644 ProjectManagement/pages/report_registration_page_time_per_project_detail_inc.php create mode 100644 ProjectManagement/pages/report_registration_page_time_per_project_inc.php create mode 100644 ProjectManagement/pages/report_registration_page_time_per_project_work_type_inc.php create mode 100644 ProjectManagement/pages/report_registration_page_time_per_work_type_inc.php create mode 100644 ProjectManagement/pages/report_registration_page_time_registration_inc.php create mode 100644 ProjectManagement/pages/time_registration_delete.php diff --git a/ProjectManagement/ProjectManagement.php b/ProjectManagement/ProjectManagement.php index e5398be..9280159 100644 --- a/ProjectManagement/ProjectManagement.php +++ b/ProjectManagement/ProjectManagement.php @@ -3,19 +3,19 @@ class ProjectManagementPlugin extends MantisPlugin { function register() { - $this->name = 'Project Management'; + $this->name = 'Project Management'; $this->description = 'Project management plugin that adds advanced functionality for timetracking, estimations, reporting,...'; - $this->page = 'config_page'; + $this->page = 'config_page'; - $this->version = '1.4.1'; + $this->version = '1.5.0'; // TO REVIEW: Changed from 1.4.2 $this->requires = array( 'MantisCore' => '1.2.0', - 'ArrayExportExcel' => '0.3' + 'ArrayExportExcel' => '0.3' ); $this->author = 'Vincent Sels'; $this->contact = 'vincent@selsitsolutions.com'; - $this->url = ''; + $this->url = ''; } function schema() { @@ -26,7 +26,7 @@ function schema() { user_id I NOTNULL UNSIGNED, work_type I2 NOTNULL DEFAULT 50, minutes_type I2 NOTNULL DEFAULT 0, - minutes I NOTNULL DEFAULT 0, + minutes I NOTNULL DEFAULT 0, book_date I, timestamp I " ) ), @@ -34,90 +34,106 @@ function schema() { plugin_table( 'work' ), 'bug_id' ) ), array( 'CreateTableSQL', array( plugin_table( 'resource' ), " user_id I NOTNULL UNSIGNED PRIMARY, - hours_per_week I UNSIGNED, + hours_per_week I UNSIGNED, hourly_rate F(3,2) " ) ), array( 'CreateIndexSQL', array( 'idx_plugin_pm_work_user_id_book_date', # used for reporting plugin_table( 'work' ), 'user_id, book_date' ) ), array( 'AddColumnSQL', array( plugin_table( 'resource' ), 'color I UNSIGNED' ) ), array( 'CreateTableSQL', array( plugin_table( 'customer' ), " - id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY, - name C(64) NOTNULL, - share F(3,5) NOTNULL DEFAULT 0, - can_approve L NOTNULL DEFAULT 1 + id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY, + name C(64) NOTNULL, + share F(3,5) NOTNULL DEFAULT 0, + can_approve L NOTNULL DEFAULT 1 + " ) ), + array( 'CreateTableSQL', array( plugin_table( 'bug' ), " + bug_id I NOTNULL UNSIGNED PRIMARY, + is_billable L NOTNULL DEFAULT 1 " ) ), array( 'CreateTableSQL', array( plugin_table( 'bug_customer' ), " - bug_id I NOTNULL UNSIGNED PRIMARY, - type I2 NOTNULL PRIMARY, - customers C(64) NOTNULL DEFAULT '0' + bug_id I NOTNULL UNSIGNED PRIMARY, + type I2 NOTNULL PRIMARY, + customers C(64) NOTNULL DEFAULT '0' " ) ), array( 'CreateTableSQL', array( plugin_table( 'user_customer' ), " - user_id I NOTNULL UNSIGNED PRIMARY, - customer_id I NOTNULL, - function_description C(64) + user_id I NOTNULL UNSIGNED PRIMARY, + customer_id I NOTNULL, + function_description C(64) + " ) ), + array( 'CreateTableSQL', array( plugin_table( 'project_customer' ), " + project_id I NOTNULL UNSIGNED PRIMARY, + customer_id I NOTNULL PRIMARY " ) ), array( 'CreateTableSQL', array( plugin_table( 'target' ), " - id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY, - bug_id I NOTNULL UNSIGNED, - owner_id I NOTNULL UNSIGNED, - work_type I2 NOTNULL DEFAULT 50, - target_date I NOTNULL UNSIGNED, - completed_date I UNSIGNED + id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY, + bug_id I NOTNULL UNSIGNED, + owner_id I NOTNULL UNSIGNED, + work_type I2 NOTNULL DEFAULT 50, + target_date I NOTNULL UNSIGNED, + completed_date I UNSIGNED " ) ), array( 'CreateTableSQL', array( plugin_table( 'resource_unavailable' ), " - id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY, - user_id I NOTNULL UNSIGNED, - start_date I NOTNULL UNSIGNED, - end_date I NOTNULL UNSIGNED, - type I2 NOTNULL UNSIGNED DEFAULT 10, - include_work L NOTNULL DEFAULT 0, - note C(64) + id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY, + user_id I NOTNULL UNSIGNED, + start_date I NOTNULL UNSIGNED, + end_date I NOTNULL UNSIGNED, + type I2 NOTNULL UNSIGNED DEFAULT 10, + include_work L NOTNULL DEFAULT 0, + note C(64) " ) ), - array( 'AddColumnSQL', array( plugin_table( 'resource' ), 'deployability I NOTNULL UNSIGNED DEFAULT 80' ) ), - array( 'UpdateFunction', '', array() ) # required to trigger a new schema version + array( 'AddColumnSQL', array( plugin_table( 'resource' ), 'deployability I NOTNULL UNSIGNED DEFAULT 80' ) ), + array( 'AddColumnSQL', array( plugin_table( 'work' ), 'info C(255) DEFAULT NULL' ) ), + array( 'AddColumnSQL', array( plugin_table( 'customer' ), 'association_mode I2 NOTNULL DEFAULT 1' ) ), + array( 'UpdateFunction', '', array() ) # required to trigger a new schema version ); } function config() { return array( - 'work_types' => '20:analysis,50:development,80:testing', - 'enable_time_registration_threshold' => DEVELOPER, + 'work_types' => '20:analysis,50:development,80:testing', + 'enable_time_registration_threshold' => DEVELOPER, 'view_time_reg_summary_threshold' => REPORTER, - 'edit_estimates_threshold' => MANAGER, - 'include_bookdate_threshold' => DEVELOPER, - 'view_registration_worksheet_threshold' => DEVELOPER, - 'view_registration_report_threshold' => DEVELOPER, - 'view_resource_management_threshold' => MANAGER, - 'view_project_progress_threshold' => DEVELOPER, + 'edit_estimates_threshold' => MANAGER, + 'include_bookdate_threshold' => DEVELOPER, + 'view_registration_worksheet_threshold' => DEVELOPER, + 'view_registration_report_threshold' => DEVELOPER, + 'view_resource_management_threshold' => MANAGER, + 'view_project_progress_threshold' => DEVELOPER, 'admin_threshold' => ADMINISTRATOR, - 'work_type_thresholds' => array( 50 => DEVELOPER ), - 'default_worktype' => 50, + 'admin_own_threshold' => DEVELOPER, + 'work_type_thresholds' => array( 50 => DEVELOPER ), + 'default_worktype' => 50, 'dark_saturation' => 33, - 'dark_lightness' => 45, - 'light_saturation' => 100, + 'dark_lightness' => 45, + 'light_saturation' => 100, 'light_lightness' => 90, - 'display_detailed_bug_link' => TRUE, - 'finish_upon_resolving' => array( 20, 50 ), + 'display_detailed_bug_link' => TRUE, + 'finish_upon_resolving' => array( 20, 50 ), 'finish_upon_closing' => array( 80 ), - 'work_types_for_customer' => array( 20 ), - 'decimal_separator' => ',', - 'thousand_separator' => '', - 'include_bugs_with_deadline' => ON, + 'work_types_for_customer' => array( 20 ), + 'bug_view_mode' => 1, + 'decimal_separator' => ',', + 'thousand_separator' => '', + 'include_bugs_with_deadline' => ON, 'view_customer_payment_summary_threshold' => REPORTER, - 'enable_customer_payment_threshold' => DEVELOPER, - 'enable_customer_approval_threshold' => UPDATER, - 'view_billing_threshold' => MANAGER, - 'edit_targets_threshold' => DEVELOPER, - 'unavailability_types' => '10:unspecified,20:unavailable,30:out of office,40:appointment,50:private appointment,60:vacation,70:administration,80:service desk,90:other', - 'default_unavailability_type' => 10, - 'unavailability_ignore_work' => array(60, 80), + 'enable_customer_payment_threshold' => DEVELOPER, + 'enable_customer_approval_threshold' => UPDATER, + 'view_billing_threshold' => MANAGER, + 'edit_targets_threshold' => DEVELOPER, + 'billable_behavior_over_severity' => array( 10 => 1, 20 => 1, 30 => 1, 40 => 1, 50 => 1, 60 => 1, 70 => 1, 80 => 1), + 'billable_mandatory_minimun_status' => RESOLVED, + 'unavailability_types' => '10:unspecified,20:unavailable,30:out of office,40:appointment,50:private appointment,60:vacation,70:administration,80:service desk,90:other', + 'default_unavailability_type' => 10, + 'unavailability_ignore_work' => array(60, 80), 'release_buffer' => 21, 'view_target_overview_threshold' => REPORTER, 'view_all_targets_threshold' => MANAGER, 'group_by_projects_by_default' => TRUE, 'show_projects_by_default' => TRUE, - 'work_hours_per_day' => array( 1 => 8, 2 => 8, 3 => 8, 4 => 8, 5 => 7, 6 => 0, 7 => 0 ), - 'fields_to_include_in_overviews' => array() + 'show_all_work_types_on_bug_targets' => TRUE, + 'work_hours_per_day' => array( 1 => 8, 2 => 8, 3 => 8, 4 => 8, 5 => 7, 6 => 0, 7 => 0 ), + 'fields_to_include_in_overviews' => array(), + 'currency_symbol' => '€', ); } @@ -131,18 +147,22 @@ function events() { function hooks() { return array( - 'EVENT_VIEW_BUG_DETAILS' => 'view_bug_pm_summary', - 'EVENT_VIEW_BUG_EXTRA' => 'view_bug_time_registration', - 'EVENT_MENU_MAIN' => 'main_menu', - 'EVENT_BUG_DELETED' => 'delete_time_registration', - 'EVENT_REPORT_BUG' => 'bug_set_recently_visited', - 'EVENT_UPDATE_BUG' => 'update_bug', - 'EVENT_FILTER_COLUMNS' => 'filter_columns', - 'EVENT_LAYOUT_RESOURCES' => 'link_files', - 'EVENT_UPDATE_BUG_FORM' => 'update_bug_form', - 'EVENT_UPDATE_BUG_STATUS_FORM' => 'update_bug_form', - 'EVENT_ACCOUNT_PREF_UPDATE_FORM' => 'view_resource', - 'EVENT_ACCOUNT_PREF_UPDATE' => 'update_resource' + 'EVENT_VIEW_BUG_DETAILS' => 'view_bug_pm_summary', + 'EVENT_VIEW_BUG_EXTRA' => 'view_bug_time_registration', + 'EVENT_MENU_ISSUE' => 'timerecord_menu', + 'EVENT_MENU_MAIN' => 'main_menu', + 'EVENT_BUG_DELETED' => 'delete_time_registration', + 'EVENT_REPORT_BUG' => 'bug_set_recently_visited', + 'EVENT_UPDATE_BUG' => 'update_bug', + 'EVENT_FILTER_COLUMNS' => 'filter_columns', + 'EVENT_LAYOUT_RESOURCES' => 'link_files', + 'EVENT_UPDATE_BUG_FORM' => 'update_bug_form', + 'EVENT_UPDATE_BUG_STATUS_FORM' => 'update_bug_form', + 'EVENT_MENU_ACCOUNT' => 'account_menu', + 'EVENT_ACCOUNT_PREF_UPDATE_FORM' => 'view_resource', + 'EVENT_ACCOUNT_PREF_UPDATE' => 'update_resource', + 'EVENT_MANAGE_PROJECT_PAGE' => 'manage_project_page', + 'EVENT_MANAGE_PROJECT_CREATE' => 'manage_project_create', ); } @@ -169,33 +189,70 @@ function filter_columns() { require_once( 'classes/ProjectManagementDoneColumn.class.php' ); require_once( 'classes/ProjectManagementEstColumn.class.php' ); require_once( 'classes/ProjectManagementTodoColumn.class.php' ); - require_once( 'classes/ProjectManagementCustomersColumn.class.php' ); + require_once( 'classes/ProjectManagementCustomersColumn.class.php' ); return array( 'ProjectManagementEstColumn', 'ProjectManagementDoneColumn', 'ProjectManagementTodoColumn', - 'ProjectManagementCustomersColumn' + 'ProjectManagementCustomersColumn' ); } - function upgrade( $p_schema ) { - if ( $p_schema == 11 ) { - # In v1.4.1 config option 'default_owner' no longer exists and is replaced by option - # 'work_types_for_customer'. Migration required. - - $default_owners = plugin_config_get( 'default_owner' ); - $work_types_for_reporter_and_under = array(); - foreach ( $default_owners as $work_type => $owner ) { - if ( $owner <= REPORTER ) { - $work_types_for_reporter_and_under[] = $work_type; - } - } - plugin_config_set( 'work_types_for_customer', $work_types_for_reporter_and_under ); - plugin_config_delete( 'default_owner' ); - } - - return true; - } + function upgrade( $p_schema ) { + if ( $p_schema == 11 ) { + # In v1.4.1 option 'default_owner' no longer exists and is replaced by option + # 'work_types_for_customer'. Migration required. + + $default_owners = plugin_config_get( 'default_owner' ); + $work_types_for_reporter_and_under = array(); + foreach ( $default_owners as $work_type => $owner ) { + if ( $owner <= REPORTER ) { + $work_types_for_reporter_and_under[] = $work_type; + } + } + plugin_config_set( 'work_types_for_customer', $work_types_for_reporter_and_under ); + plugin_config_delete( 'default_owner' ); + } + + // TODO: + // array( 'CreateTableSQL', array( plugin_table( 'project_customer' ), " + // project_id I NOTNULL UNSIGNED PRIMARY, + // customer_id I NOTNULL PRIMARY + // " ) ), + //array( 'CreateTableSQL', array( plugin_table( 'bug' ), " + // bug_id I NOTNULL UNSIGNED PRIMARY, + // is_billable L NOTNULL DEFAULT 1 + // " ) ), + // array( 'AddColumnSQL', array( plugin_table( 'work' ), 'info C(255) DEFAULT NULL' ) ), + // array( 'AddColumnSQL', array( plugin_table( 'customer' ), 'association_mode I2 NOTNULL DEFAULT 1' ) ), + // UPDATE plugin_table( 'customer' ) SET association_mode = 0; + + + return true; + } + + function timerecord_menu() { + $t_bugid = gpc_get_int( 'id' ); + if( access_has_project_level( plugin_config_get( 'enable_time_registration_threshold' ) ) ) { + $import_page = 'view.php?'; + $import_page .= 'id='; + $import_page .= $t_bugid ; + $import_page .= '#time_registration'; + + return array( plugin_lang_get( 'timerecord_menu' ) => $import_page); + } + else { + return array (); + } + } + + function account_menu ( $p_event ) { + $t_account_unavailability_page = plugin_page( 'account_unavailability_page', false ); + if ( $t_account_unavailability_page == $_SERVER['REQUEST_URI'] ) { + $t_account_unavailability_page = ''; + } + print_bracket_link( $t_account_unavailability_page, plugin_lang_get( 'unavailability' ) ); + } function main_menu( $p_event, $p_bug_id ) { $t_pagename = plugin_lang_get( 'reports' ); @@ -215,34 +272,63 @@ function main_menu( $p_event, $p_bug_id ) { } function bug_set_recently_visited( $p_event, $p_bug_data, $p_bug_id ) { + # Check if bug brands new to pre-process billable state + if ( basename($_SERVER['PHP_SELF']) != 'bug_report_page.php' ) { + $t_is_billable = is_billable( $p_bug_data->severity ); + + pm_bug_update_or_insert( $p_bug_id, $t_is_billable ); + } + recently_visited_bug_add( $p_bug_id ); } function view_resource( $p_event, $p_user_id ) { + if ( basename($_SERVER['PHP_SELF']) != 'account_prefs_page.php' ) { ?> > - : - - - - -
- : -
- : - -
- + + + + + + + + + + + + + + +
+ : + + + - + + + + +
+ : + + +
+ : + + +
> @@ -257,30 +343,31 @@ function view_resource( $p_event, $p_user_id ) {
> + value=""> > + value=""> - > + > - - + + - + - + - + - + - + - + - - - + + + > + value=""> - - > - - - - - - + + + severity, gpc_get_bool( 'is_billable_' . $p_bug_id, 0 ) ); + $t_all_customers = gpc_get_bool( $p_bug_id . '_' . PLUGIN_PM_CUST_PAYING . '_' . PLUGIN_PM_ALL_CUSTOMERS, false ); + + if ( ( $p_bug_data->status >= config_get( 'bug_closed_status_threshold' ) || $p_bug_data->status >= config_get( 'bug_resolved_status_threshold' ) ) + && $t_all_customers ) { + foreach ( $t_customers as $t_cust ) { + $t_data[PLUGIN_PM_CUST_PAYING][$t_cust['id']] = true; + $t_data[PLUGIN_PM_CUST_APPROVING][$t_cust['id']] = true; + } + } + else { + foreach ( $t_customers as $t_cust ) { + $t_data[PLUGIN_PM_CUST_PAYING][$t_cust['id']] = + gpc_get_bool( $p_bug_id . '_' . PLUGIN_PM_CUST_PAYING . '_' . $t_cust['id'], false ); + $t_data[PLUGIN_PM_CUST_APPROVING][$t_cust['id']] = + gpc_get_bool( $p_bug_id . '_' . PLUGIN_PM_CUST_APPROVING . '_' . $t_cust['id'], false ); + } + # Add possible 'all customers' + $t_data[PLUGIN_PM_CUST_PAYING][PLUGIN_PM_ALL_CUSTOMERS] = $t_all_customers; } - # Add possible 'all customers' - $t_data[PLUGIN_PM_CUST_PAYING][PLUGIN_PM_ALL_CUSTOMERS] = - gpc_get_bool( $p_bug_id . '_' . PLUGIN_PM_CUST_PAYING . '_' . PLUGIN_PM_ALL_CUSTOMERS, false ); + if ( access_has_bug_level( plugin_config_get( 'enable_customer_payment_threshold' ), $p_bug_id ) ) { # In case customer payment is enabled, check to see whether at least one paying customer was selected @@ -440,11 +541,14 @@ function update_bug( $p_event, $p_bug_data, $p_bug_id ) { } } } - if ( empty( $t_paying_string ) ) { + + # Wait to show error to higher level + if ( empty( $t_paying_string ) && $t_is_billable && pm_bug_is_billable_affecting_required_paying_customers( $p_bug_data->status ) ) { # No customers selected, at least one is required. error_parameters( plugin_lang_get( 'paying_customers' ) ); trigger_error( ERROR_EMPTY_FIELD, ERROR ); } + bug_customer_update_or_insert( $p_bug_id, $t_paying_string, PLUGIN_PM_CUST_PAYING ); } @@ -459,6 +563,8 @@ function update_bug( $p_event, $p_bug_data, $p_bug_id ) { } bug_customer_update_or_insert( $p_bug_id, $t_approving_string, PLUGIN_PM_CUST_APPROVING ); } + + pm_bug_update_or_insert( $p_bug_id, $t_is_billable ); } } @@ -467,7 +573,7 @@ function update_bug( $p_event, $p_bug_data, $p_bug_id ) { $t_work_types_to_finish_upon_resolving = plugin_config_get( 'finish_upon_resolving' ); if ( is_array( $t_work_types_to_finish_upon_resolving ) ) { foreach ( $t_work_types_to_finish_upon_resolving as $t_work_type ) { - set_work( $p_bug_id, $t_work_type, PLUGIN_PM_TODO, 0, null, ACTION::INSERT_OR_UPDATE ); + set_work_if_minutes_changed( $p_bug_id, $t_work_type, PLUGIN_PM_TODO, 0, null, ACTION::INSERT ); //_OR_UPDATE ); } } } @@ -477,7 +583,7 @@ function update_bug( $p_event, $p_bug_data, $p_bug_id ) { $t_work_types_to_finish_upon_closing = plugin_config_get( 'finish_upon_closing' ); if ( is_array( $t_work_types_to_finish_upon_closing ) ) { foreach ( $t_work_types_to_finish_upon_closing as $t_work_type ) { - set_work( $p_bug_id, $t_work_type, PLUGIN_PM_TODO, 0, null, ACTION::INSERT_OR_UPDATE ); + set_work_if_minutes_changed( $p_bug_id, $t_work_type, PLUGIN_PM_TODO, 0, null, ACTION::INSERT ); //_OR_UPDATE ); } } } @@ -489,13 +595,24 @@ function view_bug_pm_summary( $p_event, $p_bug_id ) { # Fetch time registration summary if ( access_has_bug_level( plugin_config_get( 'view_time_reg_summary_threshold' ), $p_bug_id ) ) { $t_table = plugin_table( 'work' ); - $t_customer_work_type_exclusion_clause = build_customer_worktype_exclude_clause('work_type'); + $t_customer_work_type_exclusion_clause = build_customer_worktype_exclude_clause('work_type'); $t_query = "SELECT work_type, minutes_type, sum(minutes) as minutes - FROM $t_table - WHERE bug_id = $p_bug_id - AND $t_customer_work_type_exclusion_clause - GROUP BY work_type, minutes_type - ORDER BY work_type, minutes_type"; + FROM $t_table + WHERE minutes_type = 1 AND bug_id = $p_bug_id + AND $t_customer_work_type_exclusion_clause + GROUP BY work_type, minutes_type"; + $t_query .= " UNION "; + $t_query .= "SELECT work_type, minutes_type, sum(minutes) as minutes + FROM $t_table W + WHERE minutes_type <> 1 AND bug_id = $p_bug_id + AND $t_customer_work_type_exclusion_clause + AND W.id = ( + SELECT id FROM $t_table TEMP + WHERE TEMP.bug_id = W.bug_id AND TEMP.work_type = W.work_type AND TEMP.minutes_type = W.minutes_type + ORDER BY timestamp DESC LIMIT 1 + ) + GROUP BY work_type, minutes_type + ORDER BY work_type, minutes_type"; $t_result = db_query_bound( $t_query ); $t_est = null; @@ -514,21 +631,26 @@ function view_bug_pm_summary( $p_event, $p_bug_id ) { $t_todo = get_actual_work_todo( $t_work ); + echo ''; echo ''; - echo '' . plugin_lang_get( 'est' ) . '' . minutes_to_time( $t_est, true ) . ' + echo ''. plugin_lang_get( 'est' ) . '' . minutes_to_time( $t_est, true ) . ' ' . plugin_lang_get( 'done' ) . '' . minutes_to_time( $t_done, false ) . ' ' . plugin_lang_get( 'todo' ) . '' . minutes_to_time( $t_todo, true ) . ''; } # Fetch customer payment summary if ( access_has_bug_level( plugin_config_get( 'view_time_reg_summary_threshold' ), $p_bug_id ) ) { - $t_selected_cust = bug_customer_get_selected( $p_bug_id, PLUGIN_PM_CUST_PAYING ); + $t_bug_data = bug_get( $p_bug_id ); + $t_billable_behavior_over_severity = get_billable_behavior_over_severity ( $t_bug_data->severity ); + if ( $t_billable_behavior_over_severity != PLUGIN_PM_BILLABLE_BEHAVIOR_NEVER_BILLABLE ) { + $t_selected_cust = bug_customer_get_selected( $p_bug_id, PLUGIN_PM_CUST_PAYING ); - $t_selected_cust_string = customer_list_to_string( $t_selected_cust ); + $t_selected_cust_string = customer_list_to_string( $t_selected_cust ); - echo ''; - echo '' . plugin_lang_get( 'paying_customers' ) . ''; - echo '' . $t_selected_cust_string . ''; + echo ''; + echo '' . plugin_lang_get( 'paying_customers' ) . ''; + echo '' . $t_selected_cust_string . ''; + } } } @@ -552,26 +674,44 @@ function view_bug_time_registration( $p_event, $p_bug_id ) { # Fetch estimates for all work types $t_query_fetch_est = "SELECT work_type, minutes as est - FROM $t_work_table - WHERE bug_id = $p_bug_id - AND minutes_type = $t_est"; + FROM $t_work_table W + WHERE bug_id = $p_bug_id + AND minutes_type = $t_est + AND id = ( + SELECT id FROM $t_work_table TEMP + WHERE TEMP.bug_id = W.bug_id AND TEMP.work_type = W.work_type AND TEMP.minutes_type = W.minutes_type + ORDER BY timestamp DESC LIMIT 1 + )"; $t_result_fetch_est = db_query_bound( $t_query_fetch_est ); # Fetch totals total of done of all work types $t_query_fetch_done = "SELECT work_type, SUM(minutes) as done - FROM $t_work_table - WHERE bug_id = $p_bug_id - AND minutes_type = $t_done - GROUP BY work_type"; + FROM $t_work_table + WHERE bug_id = $p_bug_id + AND minutes_type = $t_done + GROUP BY work_type"; $t_result_fetch_done = db_query_bound( $t_query_fetch_done ); # Fetch todo of all work types $t_query_fetch_todo = "SELECT work_type, minutes as todo - FROM $t_work_table - WHERE bug_id = $p_bug_id - AND minutes_type = $t_todo"; + FROM $t_work_table W + WHERE bug_id = $p_bug_id + AND minutes_type = $t_todo + AND id = ( + SELECT id FROM $t_work_table TEMP + WHERE TEMP.bug_id = W.bug_id AND TEMP.work_type = W.work_type AND TEMP.minutes_type = W.minutes_type + ORDER BY timestamp DESC LIMIT 1 + )"; $t_result_fetch_todo = db_query_bound( $t_query_fetch_todo ); + # Fetch all work types + $t_query_fetch_all = "SELECT W.id, W.user_id, U.realname, W.work_type, W.minutes_type, W.minutes, W.book_date, W.info, W.timestamp + FROM $t_work_table W + LEFT JOIN mantis_user_table U ON U.id = W.user_id + WHERE bug_id = $p_bug_id + ORDER BY timestamp DESC"; + $t_result_fetch_all = db_query_bound( $t_query_fetch_all ); + # Get the different worktypes as an array $t_work_types = plugin_lang_get_enum( 'work_types' ); @@ -602,9 +742,14 @@ function view_bug_time_registration( $p_event, $p_bug_id ) { } while ( $row = db_fetch_array( $t_result_fetch_todo ) ) { $t_work[PLUGIN_PM_TODO][$row["work_type"]] = $row["todo"]; - @$t_work[PLUGIN_PM_TODO][PLUGIN_PM_WORKTYPE_TOTAL] += $row["todo"]; + # PATCH-LITE + # Do not add TODO work if EST is not defined; else, total has no coherence with ticket overview + if ( isset ( $t_work[PLUGIN_PM_EST][$row["work_type"]] ) ) { + @$t_work[PLUGIN_PM_TODO][PLUGIN_PM_WORKTYPE_TOTAL] += $row["todo"]; + } + # END PATCH-LITE } - + foreach ( $t_work_types as $t_work_type_code => $t_work_type_label ) { # Calculate remaining if ( isset( $t_work[PLUGIN_PM_EST][$t_work_type_code] ) ) { @@ -621,7 +766,7 @@ function view_bug_time_registration( $p_event, $p_bug_id ) { } else { # If remaining is negative, this is the difference if ( $t_work[PLUGIN_PM_REMAINING][$t_work_type_code] <= 0 ) { - $t_work[PLUGIN_PM_DIFF][$t_work_type_code] = $t_work[PLUGIN_PM_REMAINING][$t_work_type_code]; + $t_work[PLUGIN_PM_DIFF][$t_work_type_code] = $t_work[PLUGIN_PM_REMAINING][$t_work_type_code]; $t_work[PLUGIN_PM_REMAINING][$t_work_type_code] = 0; } @@ -631,6 +776,9 @@ function view_bug_time_registration( $p_event, $p_bug_id ) { } } } + + + # Fetch target data for all work types $t_query_fetch_targets = "SELECT work_type, owner_id, target_date, completed_date @@ -644,459 +792,175 @@ function view_bug_time_registration( $p_event, $p_bug_id ) { $t_targets[$row["work_type"]] = $row; } - ?> -
- - - - - + + '; + } + ?> + + + + + status ); + $t_enable_customer_approval_threshold = access_has_bug_level( plugin_config_get( 'enable_customer_approval_threshold' ), $p_bug_id ); + $t_is_event_bug_status_form = ($p_event == 'EVENT_UPDATE_BUG_STATUS_FORM' ? true : false); + $t_billable_behavior_over_severity = get_billable_behavior_over_severity ( $t_bug_data->severity ); ?> - - - + - - ", $p_bug_id ); - ?> - -
+ $t_time_registered = array(); + while ( $row = db_fetch_array( $t_result_fetch_all ) ) { + $t_time_registered[$row["id"]] = $row; + } - - + echo '
'; + include 'pages/bug_view_time_registration_option2.php'; + # ******************************* END TIME REGISTRATION ******************************* --> + + # ******************************* TARGETS ******************************* --> + echo '
'; + include 'pages/bug_view_target_option2.php'; + # ******************************* END TARGETS ******************************* --> + + # ******************************* CUSTOMER ******************************* --> + if ( access_has_bug_level( plugin_config_get( 'enable_customer_payment_threshold' ), $p_bug_id ) || + access_has_bug_level( plugin_config_get( 'enable_customer_approval_threshold' ), $p_bug_id ) + ) { + echo '
'; + include 'pages/bug_view_customer.php'; + } + + # ******************************* END CUSTOMER ******************************* --> + } + else { ?> -
+ + + + +
+ + include 'pages/bug_view_time_registration_option1.php'; + # ******************************* END TIME REGISTRATION ******************************* --> + + # ******************************* CUSTOMER ******************************* --> + if ( access_has_bug_level( plugin_config_get( 'enable_customer_payment_threshold' ), $p_bug_id ) || + access_has_bug_level( plugin_config_get( 'enable_customer_approval_threshold' ), $p_bug_id ) + ) { + echo '
'; + include 'pages/bug_view_customer.php'; + } + # ******************************* END CUSTOMER ******************************* --> + ?> +
+ + include 'pages/bug_view_target_option1.php'; + # ******************************* END TARGETS ******************************* --> + ?> +
", $p_bug_id ); + } + + } + + function update_bug_form( $p_event, $p_bug_id ) { + # All data in 1 row + /* + if ( access_has_bug_level( plugin_config_get( 'enable_customer_payment_threshold' ), $p_bug_id ) ) { + $t_pm_bug = pm_bug_get( $p_bug_id ); + $t_bug_data = bug_get( $p_bug_id ); + $t_bug_data_status = gpc_get_int( 'new_status', $t_bug_data->status ); + $t_enable_customer_approval_threshold = access_has_bug_level( plugin_config_get( 'enable_customer_approval_threshold' ), $p_bug_id ); + $t_is_event_bug_status_form = ($p_event == 'EVENT_UPDATE_BUG_STATUS_FORM' ? true : false); + $t_spacer_colspan = '4'; + if ( $t_is_event_bug_status_form ) { + $t_spacer_colspan = '2'; + } + else if ( $t_enable_customer_approval_threshold ) { + $t_spacer_colspan = '6'; + } ?> - - - - - - - - - - - - - $t_work_type_label ) { - ?> - > - - - - - - - - - + + > + + '; - if ( isset( $t_work[PLUGIN_PM_DIFF][$t_work_type_code] ) ) { - ?> - - '; - } ?> - - + + '; } - ?> - - - - -
- -
-
-
-
-
-
-
-
-
-
-
- - -> > - - - - + > - - - - - '; + + +
+ + + '; } - if ( $t_work_type_code != PLUGIN_PM_WORKTYPE_TOTAL ) { - ?> - -> > - - > - '; } - echo '> -
- - '; - date_print_calendar( 'book_date_cal' ); - date_finish_calendar( 'book_date', 'book_date_cal' ); - } - ?> -
- - - - - - - -
-
-
- - - -
- - -
- ", $p_bug_id ); - echo ''; - ?> - - - - - + - - - - *'; } - if ( access_has_bug_level( plugin_config_get( 'enable_customer_approval_threshold' ), $p_bug_id ) ) { - ?> - - - - - - - - - - -
- - - - -
-
- - - - -
- - - - -
- - - - '; - echo plugin_lang_get( 'integration_custom_dev_info' ) - ?> -
- - - - - - -
-
-
- - +
> + +
+ + + +
- - + + +
- - - - - - - - > + - - - $t_work_type_label ) { - if ( $t_work_type_code == PLUGIN_PM_WORKTYPE_TOTAL ) { - continue; - } else if ( array_key_exists( $t_work_type_code, $t_targets ) ) { - $t_target = $t_targets[$t_work_type_code]; - $t_target_date = date( config_get( 'short_date_format' ), $t_target["target_date"] ); - $t_owner_id = $t_target["owner_id"]; - $t_completed_date = format_short_date( $t_target["completed_date"] ); - $t_days_overdue = days_between( $t_target["target_date"], $t_target["completed_date"] ) * -1; - $t_days_overdue_class = $t_days_overdue < 0 ? 'class="negative"' : 'class="positive"'; - - $t_target_date_class = ''; - if ( is_null( $t_completed_date ) ) { - if ( $t_owner_id == auth_get_current_user_id() ) { - if ( $t_days_overdue < 0 ) { - $t_target_date_class = 'class="target-date-overdue"'; - } else if ( $t_days_overdue == 0 ) { - $t_target_date_class = 'class="target-date-notice"'; - } - } else if ( $t_days_overdue < 0 ) { - $t_target_date_class = 'class="target-date-notice"'; + > - - - - - - - - - - - - - - - -
- -
-
-
-
-
- -
+
+ -
-
+ '; } - } - - $t_days_overdue = abs( $t_days_overdue ); - } else { - # target for this worktype has not yet been defined - $t_target_date = null; - $t_target_date_class = ''; - $t_days_overdue = null; - $t_days_overdue_class = ''; - $t_completed_date = null; - # Find the default owner for this work type - $t_customer_work_types = plugin_config_get( 'work_types_for_customer' ); - $t_work_type_for_customer = false; - foreach ( $t_customer_work_types as $work_type ) { - if ( $work_type == $t_work_type_code ) { - $t_work_type_for_customer = true; - } - } - if ( $t_work_type_for_customer ) { - $t_reporter_id = bug_get_field( $p_bug_id, 'reporter_id' ); - $t_owner_id = is_null( $t_reporter_id ) ? -1 : $t_reporter_id; - } else { - $t_handler_id = bug_get_field( $p_bug_id, 'handler_id' ); - $t_owner_id = is_null( $t_handler_id ) ? -1 : $t_handler_id; - } - } - - $t_can_edit_targets = access_has_global_level( plugin_config_get( 'edit_targets_threshold' ) ); - ?> -
> - - - - > - - - - - - - -
- + else { + echo ''; + } + ?>
- - - - - - - -
-
- - - - - - - '; - - ?> + > *'; + if ( $t_billable_behavior_over_severity != PLUGIN_PM_BILLABLE_BEHAVIOR_NEVER_REQUIRED + && ( pm_bug_is_billable_affecting_required_paying_customers( $t_bug_data_status ) + || $t_billable_behavior_over_severity == PLUGIN_PM_BILLABLE_BEHAVIOR_ALWAYS_REQUIRED ) ) { + echo '*'; + } echo plugin_lang_get( 'paying_customers' ); ?> @@ -1104,10 +968,10 @@ function update_bug_form( $p_event, $p_bug_id ) { - + > @@ -1116,10 +980,131 @@ function update_bug_form( $p_event, $p_bug_id ) { - $t_association_mode_all + + ORDER BY name + "; + + $t_result_fetch_associated = db_query_bound( $t_query_fetch_associated ); + + # Fetch NOT associated customers + $t_query_fetch_not_associated = + "SELECT id, name, share, can_approve, association_mode + FROM $t_customer_table + WHERE association_mode <> $t_association_mode_all + AND NOT id IN (SELECT customer_id FROM $t_project_customer_table WHERE project_id = $p_project_id) + "; + + $t_result_fetch_not_associated = db_query_bound( $t_query_fetch_not_associated ); + $t_count_not_associated = db_num_rows( $t_result_fetch_not_associated ); + + ?> +
+
+ + + + + + + + + + + -} + ' : ' '; + $t_association_mode = $row['association_mode']; + ?> + > + + + + + + + -?> + 0 ) { ?> + + + + + + +
% + +
+ + + + +
+ +
+ + + + +
+
+ + $t_value ) { if ( !empty( $t_value ) && ( !is_numeric( $t_value ) || ( $t_value < 0 && !$p_allow_negative ) ) ) { if ( $p_throw_error_on_invalid_input ) { - trigger_error( ERROR_CUSTOM_FIELD_INVALID_VALUE, E_USER_ERROR ); + trigger_error( plugin_lang_get( 'time_error' ), E_USER_ERROR ); } else { return null; } @@ -153,7 +168,7 @@ function time_to_minutes( $p_time, $p_allow_negative = true, $p_throw_error_on_i $t_minutes += abs( $t_time_array[0] ) * 60; } else { if ( $p_throw_error_on_invalid_input || ( $t_value < 0 && !$p_allow_negative ) ) { - trigger_error( ERROR_CUSTOM_FIELD_INVALID_VALUE, E_USER_ERROR ); + trigger_error( plugin_lang_get( 'time_error' ), E_USER_ERROR ); } else { return null; } @@ -171,7 +186,7 @@ function time_to_minutes( $p_time, $p_allow_negative = true, $p_throw_error_on_i * Update the work of the specified $p_bug_id. * @return number number of affected rows. */ -function set_work( $p_bug_id, $p_work_type, $p_minutes_type, $p_minutes, $p_book_date, $p_action ) { +function set_work( $p_bug_id, $p_work_type, $p_minutes_type, $p_minutes, $p_book_date, $p_action, $p_info ) { $t_rows_affected = 0; $t_table = plugin_table( 'work' ); $t_user_id = auth_get_current_user_id(); @@ -184,17 +199,30 @@ function set_work( $p_bug_id, $p_work_type, $p_minutes_type, $p_minutes, $p_book if ( $p_action == ACTION::UPDATE || $p_action == ACTION::INSERT_OR_UPDATE ) { #Update and check for rows affected - $t_query = "UPDATE $t_table SET minutes = $p_minutes, timestamp = $t_timestamp, user_id = $t_user_id, book_date= $p_book_date - WHERE bug_id = $p_bug_id AND work_type = $p_work_type AND minutes_type = $p_minutes_type"; + if ( empty( $p_info ) ) { + $t_query = "UPDATE $t_table SET minutes = $p_minutes, timestamp = $t_timestamp, user_id = $t_user_id, book_date= $p_book_date + WHERE bug_id = $p_bug_id AND work_type = $p_work_type AND minutes_type = $p_minutes_type"; + } else { + $t_query = "UPDATE $t_table SET minutes = $p_minutes, timestamp = $t_timestamp, user_id = $t_user_id, book_date= $p_book_date, info = '$p_info' + WHERE bug_id = $p_bug_id AND work_type = $p_work_type AND minutes_type = $p_minutes_type"; + } db_query_bound( $t_query ); + $t_rows_affected = db_affected_rows(); } if ( $p_action == ACTION::INSERT || ( $p_action == ACTION::INSERT_OR_UPDATE && $t_rows_affected == 0 ) ) { #Insert and check for rows affected - $t_query = "INSERT INTO $t_table ( bug_id, user_id, work_type, minutes_type, - minutes, book_date, timestamp ) - VALUES ( $p_bug_id, $t_user_id, $p_work_type, $p_minutes_type, - $p_minutes, $p_book_date, $t_timestamp )"; + if ( empty( $p_info ) ) { + $t_query = "INSERT INTO $t_table ( bug_id, user_id, work_type, minutes_type, + minutes, book_date, timestamp ) + VALUES ( $p_bug_id, $t_user_id, $p_work_type, $p_minutes_type, + $p_minutes, $p_book_date, $t_timestamp )"; + } else { + $t_query = "INSERT INTO $t_table ( bug_id, user_id, work_type, minutes_type, + minutes, book_date, info, timestamp ) + VALUES ( $p_bug_id, $t_user_id, $p_work_type, $p_minutes_type, + $p_minutes, $p_book_date, '$p_info', $t_timestamp )"; + } db_query_bound( $t_query ); $t_rows_affected = db_affected_rows(); } @@ -208,6 +236,33 @@ function set_work( $p_bug_id, $p_work_type, $p_minutes_type, $p_minutes, $p_book return $t_rows_affected; } +/** + * Update the work of the specified $p_bug_id, if time is different to the previous work, and previus work exists. + * @return number number of affected rows. + */ +function set_work_if_minutes_changed( $p_bug_id, $p_work_type, $p_minutes_type, $p_minutes, $p_book_date, $p_action, $p_info = null) { + $t_rows_affected = 0; + $t_table = plugin_table( 'work' ); + $t_user_id = auth_get_current_user_id(); + $t_timestamp = time(); + + $t_query = "SELECT minutes + FROM $t_table + WHERE bug_id = $p_bug_id + AND work_type = $p_work_type + AND minutes_type = $p_minutes_type + ORDER BY timestamp DESC LIMIT 1"; + $t_result = db_query_bound( $t_query ); + $t_row = db_fetch_array( $t_result ); + $t_old = ( $t_row == false ? null : $t_row["minutes"] ); + + if ( $t_old == null || $t_old === $p_minutes ) { + return 0; + } + + return set_work($p_bug_id, $p_work_type, $p_minutes_type, $p_minutes, $p_book_date, $p_action, $p_info); +} + /** * Calculates the actual work todo based on the supplied data. * The data must be a multi-dimentional array in the form of @@ -272,6 +327,20 @@ function get_translated_assoc_array_for_enum( $p_enum_string ) { return $t_translated; } +/** + * Returns an array of key value pairs containing the key of the specified $p_enum_string + * and the translated label as its value. + * @param string $p_enum_string the enum string (without trailing 'enum_string' + */ +function get_plugin_translated_assoc_array_for_enum( $p_enum_string ) { + $t_untranslated = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( $p_enum_string . '_enum_string' ) ); + $t_translated = array(); + foreach ( $t_untranslated as $t_key => $t_value ) { + $t_translated[$t_key] = get_enum_element( $p_enum_string, $t_key ); + } + return $t_translated; +} + /** * Locale-aware floatval * @link http://www.php.net/manual/en/function.floatval.php#92563 @@ -297,6 +366,13 @@ function format_short_date( $p_date = null ) { return date( config_get( 'short_date_format' ), $p_date ); } +function format_date_complete ( $p_date = null ) { + if ( is_null( $p_date ) || empty( $p_date ) ) { + return null; + } + return date( config_get("complete_date_format"), $p_date ); +} + /** * Formats the specified $p_date in a way that's safe to use in a filename, format * Y-m-d_His eg 2013-01-11_131911. @@ -477,6 +553,67 @@ function customer_get_all( $p_type = PLUGIN_PM_CUST_BOTH ) { return $t_cust; } +/** + * Retrieves an array of all customers associated to a bug, indexed by the customer_id. + * @param int $p_type Optionally specify to only retrieve customers that 'can approve'. + * @return array A list of all customers. + */ +function customer_get_by_bug( $p_bug_id, $p_type = PLUGIN_PM_CUST_BOTH ) { + $row = bug_get_row ( $p_bug_id ); + return customer_get_by_project ( $row["project_id"], $p_type ); +} + + +/** + * Retrieves an array of all customers associated to a project, indexed by the customer_id. + * @param int $p_type Optionally specify to only retrieve customers that 'can approve'. + * @return array A list of all customers. + */ +function customer_get_by_project( $p_project_id, $p_type = PLUGIN_PM_CUST_BOTH ) { + + $t_customer_table = plugin_table( 'customer' ); + $t_project_customer_table = plugin_table( 'project_customer' ); + $t_association_mode_all = PLUGIN_PM_ASSOCIATION_ALL; + + $t_query_cust = + "SELECT id, name, share, can_approve, association_mode + FROM $t_customer_table + WHERE association_mode = $t_association_mode_all + "; + + if ( $p_type == PLUGIN_PM_CUST_APPROVING ) { + $t_query_cust .= " AND can_approve = 1"; + } + + $t_query_cust .= " + UNION + + SELECT C.id, C.name, C.share, C.can_approve, C.association_mode + FROM $t_project_customer_table P + LEFT JOIN $t_customer_table C ON C.id = P.customer_id + WHERE P.project_id = $p_project_id + AND C.association_mode <> $t_association_mode_all + "; + + if ( $p_type == PLUGIN_PM_CUST_APPROVING ) { + $t_query_cust .= " AND can_approve = 1"; + } + + $t_query_cust .= " ORDER BY name"; + + + //$t_customer_table = plugin_table( 'customer' ); + //$t_query_cust = "SELECT * FROM $t_customer_table"; + $t_cust = array(); + + $t_result_cust = db_query_bound( $t_query_cust ); + while ( $row = db_fetch_array( $t_result_cust ) ) { + $t_cust[$row['id']] = $row; + } + + return $t_cust; +} + /** * Gets an array with the selected customer_id's for the specified bug. * @param $p_bug_id @@ -569,6 +706,49 @@ function bug_customer_update_or_insert( $p_bug_id, $p_cust_string, $p_type = PLU } } +/** + * Gets an array with the selected bug_id. + * @param $p_bug_id + * @return array the bug info in PM + */ +function pm_bug_get( $p_bug_id ) { + $t_bug = null; + + if ( !is_null( $p_bug_id ) ) { + $t_bug_table = plugin_table( 'bug' ); + $t_query_bug = "SELECT * FROM $t_bug_table WHERE bug_id = $p_bug_id"; + $t_result_bug = db_query_bound( $t_query_bug ); + $t_bug = db_fetch_array( $t_result_bug ); + } + + return $t_bug; +} + +function pm_bug_update_or_insert( $p_bug_id, $p_is_billable = 0 ) { + $t_bug = pm_bug_get( $p_bug_id ); + $t_bug_table = plugin_table( 'bug' ); + $t_is_billable = ( $p_is_billable ? '1' : '0' ); + + if ( $t_bug != null && $t_bug["is_billable"] != $t_is_billable ) { + $t_query = "UPDATE $t_bug_table SET is_billable = $t_is_billable + where bug_id = $p_bug_id"; + db_query_bound( $t_query ); + } + else if ( $t_bug == null ) { + $t_query = "INSERT INTO $t_bug_table (bug_id, is_billable) + VALUES($p_bug_id, $t_is_billable)"; + db_query_bound( $t_query ); + } +} + +/** + * Indicates if the given bug status enforce paying_customers to be required + * if is_billable is true. + */ +function pm_bug_is_billable_affecting_required_paying_customers( $p_bug_data_status ) { + return $p_bug_data_status >= plugin_config_get( 'billable_mandatory_minimun_status' ); +} + /** * Returns the days between two given dates, or between the given date and today if only one is supplied. * Returns a positive number if the given date is in the past, negative if it is in the future. @@ -610,15 +790,15 @@ function target_update( $p_bug_id, $p_work_type, $p_owner_id, $p_target_date, $p # Log updated record to history if ( $t_old["owner_id"] != $p_owner_id ) { - history_log_event_direct( $p_bug_id, plugin_lang_get( 'owner' ) . " ($t_work_types[$p_work_type])", + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_owner_changed' ), $t_work_types[$p_work_type] ), user_get_name( $t_old["owner_id"] ), user_get_name( $p_owner_id ) ); } if ( $t_old["target_date"] != $p_target_date ) { - history_log_event_direct( $p_bug_id, plugin_lang_get( 'target_date' ) . " ($t_work_types[$p_work_type])", + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_change_target' ), $t_work_types[$p_work_type] ), format_short_date( $t_old["target_date"] ), format_short_date( $p_target_date ) ); } if ( $t_old["completed_date"] != $p_completed_date ) { - history_log_event_direct( $p_bug_id, plugin_lang_get( 'completed' ) . " ($t_work_types[$p_work_type])", + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_completed_date' ), $t_work_types[$p_work_type] ), format_short_date( $t_old["completed_date"] ), format_short_date( $p_completed_date ) ); } } else { @@ -627,8 +807,90 @@ function target_update( $p_bug_id, $p_work_type, $p_owner_id, $p_target_date, $p db_query_bound( $t_query ); # Log new record to history - history_log_event_direct( $p_bug_id, plugin_lang_get( 'new_target' ) . " ($t_work_types[$p_work_type])", - null, format_short_date( $p_target_date ) . ' (' . user_get_name( $p_owner_id ) . ')' ); + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_new_target' ), $t_work_types[$p_work_type] ), + null, format_short_date( $p_completed_date ) . ' (' . user_get_name( $p_owner_id ) . ')' ); + } +} + +function target_update_target_date( $p_bug_id, $p_work_type, $p_owner_id, $p_target_date ) { + if ( $p_target_date == null ) { + trigger_error( plugin_lang_get( 'date_error' ), E_USER_ERROR ); + } + + $t_work_types = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); + $t_target_table = plugin_table( 'target' ); + + $t_query = "SELECT * FROM $t_target_table WHERE bug_id = $p_bug_id AND work_type = $p_work_type"; + $t_result = db_query_bound( $t_query ); + $t_exists = false; + if ( db_num_rows( $t_result ) > 0 ) { + $t_exists = true; + $t_old = db_fetch_array( $t_result ); + } + + if ( $t_exists ) { + $t_query = "UPDATE $t_target_table + SET owner_id = $p_owner_id, target_date = $p_target_date + WHERE bug_id = $p_bug_id + AND work_type = $p_work_type"; + db_query_bound( $t_query ); + + # Log updated record to history + if ( $t_old["owner_id"] != $p_owner_id ) { + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_owner_changed' ), $t_work_types[$p_work_type] ), + user_get_name( $t_old["owner_id"] ), user_get_name( $p_owner_id ) ); + } + if ( $t_old["target_date"] != $p_target_date ) { + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_change_target' ), $t_work_types[$p_work_type] ), + format_short_date( $t_old["target_date"] ), format_short_date( $p_target_date ) ); + } + } else { + $t_query = "INSERT INTO $t_target_table(bug_id, work_type, owner_id, target_date, completed_date) + VALUES($p_bug_id, $p_work_type, $p_owner_id, $p_target_date, NULL)"; + db_query_bound( $t_query ); + + # Log new record to history + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_new_target' ), $t_work_types[$p_work_type] ), + null, format_short_date( $p_completed_date ) . ' (' . user_get_name( $p_owner_id ) . ')' ); + } +} + +function target_update_completed_date( $p_bug_id, $p_work_type, $p_owner_id, $p_completed_date ) { + $t_work_types = MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); + $t_target_table = plugin_table( 'target' ); + + $t_query = "SELECT * FROM $t_target_table WHERE bug_id = $p_bug_id AND work_type = $p_work_type"; + $t_result = db_query_bound( $t_query ); + $t_exists = false; + if ( db_num_rows( $t_result ) > 0 ) { + $t_exists = true; + $t_old = db_fetch_array( $t_result ); + } + + if ( $t_exists ) { + $t_query = "UPDATE $t_target_table + SET owner_id = $p_owner_id, completed_date = $p_completed_date + WHERE bug_id = $p_bug_id + AND work_type = $p_work_type"; + db_query_bound( $t_query ); + + # Log updated record to history + if ( $t_old["owner_id"] != $p_owner_id ) { + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_owner_changed' ), $t_work_types[$p_work_type] ), + user_get_name( $t_old["owner_id"] ), user_get_name( $p_owner_id ) ); + } + if ( $t_old["completed_date"] != $p_completed_date ) { + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_completed_date' ), $t_work_types[$p_work_type] ), + format_short_date( $t_old["completed_date"] ), format_short_date( $p_completed_date ) ); + } + } else { + $t_query = "INSERT INTO $t_target_table(bug_id, work_type, owner_id, target_date, completed_date) + VALUES($p_bug_id, $p_work_type, $p_owner_id, $p_completed_date, $p_completed_date)"; + db_query_bound( $t_query ); + + # Log new record to history + history_log_event_direct( $p_bug_id, sprintf( plugin_lang_get( 'history_new_target' ), $t_work_types[$p_work_type] ), + null, format_short_date( $p_completed_date ) . ' (' . user_get_name( $p_owner_id ) . ')' ); } } @@ -790,6 +1052,19 @@ function get_all_tasks( $f_target_version, $f_user_id = ALL_USERS, $p_include_bu return $t_result; } +function set_project_customer ( $p_project_id, $p_customer_id ) { + $t_project_customer_table = plugin_table( 'project_customer' ); + + $t_query = "SELECT * FROM $t_project_customer_table WHERE project_id = $p_project_id AND customer_id = $p_customer_id"; + $t_result = db_query_bound( $t_query ); + $t_row = db_fetch_array( $t_result ); + + if ( $t_row == false ) { + $t_query = "INSERT INTO $t_project_customer_table (project_id, customer_id) values ($p_project_id, $p_customer_id)"; + db_query_bound( $t_query ); + } +} + function get_limit_clause_after_select( $p_limit_amount ) { if ( !stristr( config_get( 'db_type', '' ), 'mssql') ) { return ' '; @@ -838,6 +1113,79 @@ function get_plugin_col_value( MantisColumn $p_plugin_col, $p_bug ) { return $t_output; } +/* + * Indicates the billable state fot the given severity. + */ +function is_billable ( $p_severity, $p_current_value = -1 ) { + $t_is_billable = $p_current_value; + $t_billable_behavior_over_severity_enum = plugin_config_get ( 'billable_behavior_over_severity' ); + + if ( array_key_exists ( $p_severity, $t_billable_behavior_over_severity_enum ) ) { + if ( $t_billable_behavior_over_severity_enum[$p_severity] == PLUGIN_PM_BILLABLE_BEHAVIOR_ALWAYS_REQUIRED ) { + $t_is_billable = true; + } + else if ( $t_billable_behavior_over_severity_enum[$p_severity] == PLUGIN_PM_BILLABLE_BEHAVIOR_NEVER_REQUIRED ) { + $t_is_billable = false; + } + else if ( $t_billable_behavior_over_severity_enum[$p_severity] == PLUGIN_PM_BILLABLE_BEHAVIOR_NEVER_BILLABLE ) { + $t_is_billable = false; + } + else if ( $t_is_billable == -1 ) { + if ( $t_billable_behavior_over_severity_enum[$p_severity] == PLUGIN_PM_BILLABLE_BEHAVIOR_OPTIONAL_UNSELECTED ) { + $t_is_billable = false; + } + else if ( $t_billable_behavior_over_severity_enum[$p_severity] == PLUGIN_PM_BILLABLE_BEHAVIOR_OPTIONAL_SELECTED ) { + $t_is_billable = true; + } + } + } + + return $t_is_billable; +} + +function get_billable_behavior_over_severity ( $p_severity ) { + $t_billable_behavior_over_severity = PLUGIN_PM_BILLABLE_BEHAVIOR_OPTIONAL_UNSELECTED; + $t_billable_behavior_over_severity_enum = plugin_config_get ( 'billable_behavior_over_severity' ); + if ( array_key_exists ( $p_severity, $t_billable_behavior_over_severity_enum ) ) { + $t_billable_behavior_over_severity = $t_billable_behavior_over_severity_enum[$p_severity]; + } + + return $t_billable_behavior_over_severity; +} + +function get_severity_enum() { + $t_config_var_value = config_get( 'severity_enum_string' ); + + $t_enum_values = MantisEnum::getValues( $t_config_var_value ); + $t_enum_list = array(); + + foreach ( $t_enum_values as $t_key ) { + $t_enum_list[$t_key] = get_enum_element( 'severity', $t_key ); + } + + return $t_enum_list; +} + +/** + * Returns a list of all status options + * @param int $p_user_auth User's access level + * @param int $p_current_value Current issue's status + * @param int $p_project_id + * @return array + */ +function get_status_option_list_all( $p_user_auth = 0, $p_current_value = 0, $p_project_id = ALL_PROJECTS ) { + $t_config_var_value = config_get( 'status_enum_string', null, null, $p_project_id ); + + $t_enum_values = MantisEnum::getValues( $t_config_var_value ); + $t_enum_list = array(); + + foreach ( $t_enum_values as $t_enum_value ) { + $t_enum_list[$t_enum_value] = get_enum_element( 'status', $t_enum_value ); + } + + return $t_enum_list; +} + if ( !function_exists( 'strtotime_safe' ) ) { /** * Fixes 0013332: Due date not saved successfully when date-format is set to 'd/m/Y' @@ -880,4 +1228,3 @@ function build_customer_worktype_exclude_clause( $p_column_name ) { return $t_exclude_clause; } } -?> diff --git a/ProjectManagement/changes.txt b/ProjectManagement/changes.txt new file mode 100644 index 0000000..349a438 --- /dev/null +++ b/ProjectManagement/changes.txt @@ -0,0 +1,58 @@ +Issue view: + - Added link at the top of the issue view (EVENT_MENU_ISSUE). + +Created view 2: + - Register time for work type and minutes type. + - Added 'info' field in table 'work' + - Substract 'todo' when 'done' is informed + - When minutes_type=='est' => target_date=book_date + - When minutes_type=='done' => done=done+minutes / todo=todo-minutes + - When minutes_type=='completed' (new just for select) => completed_date=book_date / done=done+minutes / todo=0 + - Remove own time register (if admin_own_threshold) + - Remove others time register (if admin_threshold) + - Show/Hide all work types on target table (show_all_work_types_on_bug_targets) + - When a 'todo' is defined without 'est', 'todo' is shown in red and with a tooltip containing the error + +Config options: + - [bug_view_mode][new] View selection: 1 (original) or 2 (purposed) + - [show_all_work_types_on_bug_targets][new] Show/Hide all work types on target table. Only works on view 2 + - [admin_own_threshold][new] Enabled to remove custom registers. Only works on view 2 + - [edit_targets_threshold][old] Enable to modify targets over the targets table. It was defined on function config, but now is updatable from config page + - [billable_mandatory_minimun_status] Select the minimun status for billable required shows the error + - [billable_behavior_over_severity] Define behavior of billing requirement according to severity + + +General: + - More specific errors + - More detailed history actions + +Customers: + - Added 'association_mode' field in table 'customer' + - Created 'project_customer' table + - Customer management page updated with 'association_mode' field + - When a new project is created, the customers with association_mode='auto' are attached automatically + - From project, you can attach/detach customers, except those marked with association_mode='all' + - When a issue is resolved or closed, 'all customers' is transformed in the current customers list. It avoids future billing changes when adding a new customer to the project. + - 'paying_customers' is required only if 'is_billable' is set to true, and the issue has adquired the minimum status (currently, the minimum status is defined hardcoded in 'pm_bug_is_billable_affecting_required_paying_customers') + +Reports: + - Added 'dashboard' report + - Error control added for 'Resource progress' report + - Added validation in 'print_progressbar_span' and 'print_progress_span' to avoid error when no resources are defined (only exploited when $g_show_detailed_errors=ON) + - Show hourly rate and cost only is user has 'view_billing_threshold' permissions + +Report 'Time registration overview': + - Layout adjustment to avoid paddings and margins + - Collapsible panels + +Report 'Billing': + - Shows only issues marked as billable + +Account configuration: + - Moved the unavailability management to a self account preferences menu + - Added list of future and past unavailability, allowing to remove just for future + + +*** TODO's *** +- Upgrade plugin task to upgrade database in a existing installation +- update_bug_form has 2 view options... decide which is better and delete the other diff --git a/ProjectManagement/classes/PlottableBug.class.php b/ProjectManagement/classes/PlottableBug.class.php index 4a35cca..f25821a 100644 --- a/ProjectManagement/classes/PlottableBug.class.php +++ b/ProjectManagement/classes/PlottableBug.class.php @@ -166,4 +166,4 @@ public function plot_specific_start( $p_unique_id, $p_last_dev_day, $p_min_date, Syntax: array ( val => ACCLEVEL[, val2 => ACCLEVEL2,...] )
Example: array ( 20 => REPORTER, 50 => DEVELOPER )'; @@ -70,6 +85,12 @@ $s_plugin_ProjectManagement_view_target_overview_threshold = 'View target overview threshold'; $s_plugin_ProjectManagement_view_all_targets_threshold = 'Threshold for viewing other users\' targets'; $s_plugin_ProjectManagement_admin_threshold = 'Plugin administrator threshold'; + $s_plugin_ProjectManagement_admin_own_threshold = 'Manage own registers threshold'; + $s_plugin_ProjectManagement_edit_targets_threshold = 'Manage targets threshold'; + $s_plugin_ProjectManagement_show_all_work_types_on_bug_targets = 'Show all work types available on ticket'; + $s_plugin_ProjectManagement_show_all_work_types_on_bug_targets_info = 'Show all work types available on targets table in the ticket view'; + $s_plugin_ProjectManagement_bug_view_mode = 'View mode on ticket'; + $s_plugin_ProjectManagement_bug_view_mode_info = 'Only two options available: 1 or 2'; $s_plugin_ProjectManagement_decimal_separator = 'Decimal separator'; $s_plugin_ProjectManagement_thousand_separator = 'Thousand separator'; @@ -85,8 +106,16 @@ $s_plugin_ProjectManagement_enable_customer_approval_threshold = 'Enable customer approval threshold'; $s_plugin_ProjectManagement_enable_customer_approval_threshold_info = 'Allows customers to indicate whether or not they approve development on specific bugs.'; $s_plugin_ProjectManagement_view_billing_threshold = 'View billing threshold'; + $s_plugin_ProjectManagement_billable_mandatory_minimun_status = 'Estado mínimo para requerir que se indiquen los clientes a facturar'; + $s_plugin_ProjectManagement_billable_behavior_over_severity = 'Comportamiento del requisito de facturable según la severidad del ticket'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_optional_unselected = 'Optional, unselected by default'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_optional_selected = 'Optional, selected by default'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_always_required = 'Always required'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_never_required = 'Never required'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_never_billable = 'Never billable'; $s_plugin_ProjectManagement_customer_section = 'Customer section'; + $s_plugin_ProjectManagement_is_billable = 'Issue is billable'; $s_plugin_ProjectManagement_paying_customers = 'Paying customers'; $s_plugin_ProjectManagement_integration_custom_dev = 'Integration custom development'; $s_plugin_ProjectManagement_integration_custom_dev_info = 'Integration of a core functionality with existing custom features.'; @@ -94,10 +123,12 @@ $s_plugin_ProjectManagement_general_configuration = 'Plugin configuration'; $s_plugin_ProjectManagement_customer_management = 'Customer configuration'; $s_plugin_ProjectManagement_add_new_customer = 'Add new customer'; + $s_plugin_ProjectManagement_add_customer = 'Add customer'; $s_plugin_ProjectManagement_edit_customer = 'Edit customer'; $s_plugin_ProjectManagement_customer_name = 'Customer name'; $s_plugin_ProjectManagement_customer_share = 'Share'; $s_plugin_ProjectManagement_customer_can_approve = 'Can approve'; + $s_plugin_ProjectManagement_customer_association_mode = 'Association mode'; $s_plugin_ProjectManagement_billing = 'Billing'; $s_plugin_ProjectManagement_fields_to_include_in_overviews = 'Extra columns to include in overviews'; $s_plugin_ProjectManagement_fields_to_include_in_overviews_info = 'Both custom fields and plugin-columns are possible. Use the column names as suggested in \'Manage configuration\' > \'Manage columns\''; @@ -114,9 +145,13 @@ $s_plugin_ProjectManagement_all_versions_selected = 'In order to view this page, a specific project must be selected instead of \'All projects\'.'; $s_plugin_ProjectManagement_project_selection_disabled = 'In order to view this page, the configuration \'show_project_menu_bar\' must be turned \'ON\'. Contact an administrator.'; + $s_plugin_ProjectManagement_unavailability_account_title = 'Unavailability'; + $s_plugin_ProjectManagement_unavailability_period_title = 'Unavailability periods'; + $s_plugin_ProjectManagement_unavailability_past_period_title = 'Past unavailability periods'; $s_plugin_ProjectManagement_unavailability = 'Unavailability'; $s_plugin_ProjectManagement_unavailability_types = 'Unavailability types'; - $s_plugin_ProjectManagement_unavailability_add_new = 'Add new period of unavailability'; + $s_plugin_ProjectManagement_unavailability_add_new_title = 'Add new period of unavailability'; + $s_plugin_ProjectManagement_unavailability_add_new = 'Add'; $s_plugin_ProjectManagement_unavailability_overview = 'Overview of periods of unavailability'; $s_plugin_ProjectManagement_unavailability_remove = 'Remove period of unavailability'; $s_plugin_ProjectManagement_unavailability_period = 'Period'; @@ -126,6 +161,15 @@ $s_plugin_ProjectManagement_unavailability_ignore_work = 'Ignore work during these periods'; $s_plugin_ProjectManagement_unavailability_ignore_work_info = 'Hours registered during a period of unavailability of this type will be ignored on the \'Resource progress\' page.
Example: array ( 60, 80 )'; + $s_plugin_ProjectManagement_user = 'User'; + $s_plugin_ProjectManagement_information = 'Information'; + $s_plugin_ProjectManagement_entry_date = 'Entry Date (automatic)'; + $s_plugin_ProjectManagement_time_error = 'Please enter a valid number in field Hours!'; + $s_plugin_ProjectManagement_date_error = 'Please enter a valid date'; + $s_plugin_ProjectManagement_minutes_type = 'Time type'; + $s_plugin_ProjectManagement_add_time_registration = 'Add'; + $s_plugin_ProjectManagement_delete_time_registration = 'Delete'; + $s_plugin_ProjectManagement_unplanned = 'Unplanned'; $s_plugin_ProjectManagement_planned = 'Planned'; $s_plugin_ProjectManagement_unavailable = 'Unavailable'; @@ -164,4 +208,11 @@ $s_plugin_ProjectManagement_October = 'October'; $s_plugin_ProjectManagement_November = 'November'; $s_plugin_ProjectManagement_December = 'December'; - + + $s_plugin_ProjectManagement_history_deleted = 'Time registration deleted'; + $s_plugin_ProjectManagement_history_added = 'Time registration added for \'%1$s\': %2$s'; + $s_plugin_ProjectManagement_history_completed_date = 'Completed date updated for \'%1$s\''; + $s_plugin_ProjectManagement_history_owner_changed = 'Owner changed for \'%1$s\''; + $s_plugin_ProjectManagement_history_new_target = 'New target for \'%1$s\''; + $s_plugin_ProjectManagement_history_change_target = 'Target updated for \'%1$s\''; + $s_plugin_ProjectManagement_todo_without_est_warning = 'Pendant work is not used while estimated time is not defined'; diff --git a/ProjectManagement/lang/strings_french.txt b/ProjectManagement/lang/strings_french.txt index 822a67c..481d844 100644 --- a/ProjectManagement/lang/strings_french.txt +++ b/ProjectManagement/lang/strings_french.txt @@ -96,7 +96,6 @@ $s_plugin_ProjectManagement_customer_share = 'Partage'; $s_plugin_ProjectManagement_customer_can_approve = 'Peut valider'; $s_plugin_ProjectManagement_billing = 'Facturation'; - $s_plugin_ProjectManagement_custom_fields_to_include_in_overviews = 'Champs personnalisés à inclure dans les résumés'; $s_plugin_ProjectManagement_targets = 'Objectifs'; $s_plugin_ProjectManagement_target_date = 'Date ciblée'; @@ -147,5 +146,4 @@ $s_plugin_ProjectManagement_friday = 'vendredi'; $s_plugin_ProjectManagement_saturday = 'samedi'; $s_plugin_ProjectManagement_sunday = 'dimanche'; - $s_plugin_ProjectManagement_project = 'projet'; ?> diff --git a/ProjectManagement/lang/strings_spanish.txt b/ProjectManagement/lang/strings_spanish.txt index 6fedd02..ff45571 100644 --- a/ProjectManagement/lang/strings_spanish.txt +++ b/ProjectManagement/lang/strings_spanish.txt @@ -1,31 +1,46 @@ Sintaxis: array ( val => ACCLEVEL[, val2 => ACCLEVEL2,...] )
Ejemplo: array ( 20 => REPORTER, 50 => DEVELOPER )'; $s_plugin_ProjectManagement_finish_upon_resolving = 'Tipo de trabajo a finalizar cuando se resuelve'; - $s_plugin_ProjectManagement_finish_upon_resolving_info = 'Especificar para que tipos de trabajo deben fijarse a cero las horas \'todo\'al resolver un bug.
Ejemplo: array ( 20, 50 )'; + $s_plugin_ProjectManagement_finish_upon_resolving_info = 'Especificar para qué tipos de trabajo deben fijarse a cero las horas \'todo\'al resolver un ticket.
Ejemplo: array ( 20, 50 )'; $s_plugin_ProjectManagement_finish_upon_closing = 'Tipos de trabajo a finalizar cuando se cierra'; - $s_plugin_ProjectManagement_finish_upon_closing_info = 'Especificar para que tipos de trabajo deben fijarse a cero las horas \'todo\' al cerrar el bug.
Ejemplo: array ( 20, 50 )'; + $s_plugin_ProjectManagement_finish_upon_closing_info = 'Especificar para qué tipos de trabajo deben fijarse a cero las horas \'todo\' al cerrar el ticket.
Ejemplo: array ( 20, 50 )'; + + $s_plugin_ProjectManagement_work_types_for_customer = 'Tareas para clientes'; + $s_plugin_ProjectManagement_work_types_for_customer_info = 'Se considera que estos tipos de trabajo deben ser realizados por los clientes, y se excluirán de los cálculos de estimaciones, hecho y pendiente en todos los informes.
Ejemplo: array ( 20 )'; $s_plugin_ProjectManagement_enable_time_registration_threshold = 'Habilitar umbral de registro de tiempo'; - $s_plugin_ProjectManagement_view_time_reg_summary_threshold = 'Ver el resumen del umbral de registro de tiempo'; - $s_plugin_ProjectManagement_view_time_registration_worksheet_threshold = 'Ver el umbral de la hoja de registro de tiempos'; - $s_plugin_ProjectManagement_view_report_registration_threshold = 'Ver el umbral del informe de registro de tiempos'; - $s_plugin_ProjectManagement_view_resource_management_threshold = 'Ver el umbral de gestion de recursos'; - $s_plugin_ProjectManagement_view_project_progress_threshold = 'Ver el umbral de asignacion de recursos'; - $s_plugin_ProjectManagement_view_target_overview_threshold = 'Ver el umbral de prevision de objetivo'; + $s_plugin_ProjectManagement_view_time_reg_summary_threshold = 'Umbral para ver el resumen de registro de tiempo'; + $s_plugin_ProjectManagement_view_time_registration_worksheet_threshold = 'Umbral para ver la hoja de registro de tiempos'; + $s_plugin_ProjectManagement_view_report_registration_threshold = 'Umbral para ver el informe de registro de tiempos'; + $s_plugin_ProjectManagement_view_resource_management_threshold = 'Umbral para ver la gestión de recursos'; + $s_plugin_ProjectManagement_view_project_progress_threshold = 'Umbral para ver la asignación de recursos'; + $s_plugin_ProjectManagement_view_target_overview_threshold = 'Umbral para ver la previsión de objetivos'; $s_plugin_ProjectManagement_view_all_targets_threshold = 'Umbral para ver los objetivos de otros usuarios'; - $s_plugin_ProjectManagement_admin_threshold = 'Umbral para administracion del plugin'; + $s_plugin_ProjectManagement_admin_threshold = 'Umbral para administración del plugin'; + $s_plugin_ProjectManagement_admin_own_threshold = 'Umbral para administrar los registros propios'; + $s_plugin_ProjectManagement_edit_targets_threshold = 'Umbral para la gestión de objetivos'; + $s_plugin_ProjectManagement_show_all_work_types_on_bug_targets = 'Mostrar tipos de tarea en ticket'; + $s_plugin_ProjectManagement_show_all_work_types_on_bug_targets_info = 'Muestra todos los tipos de tarea disponibles en el cuadro de objetivos del ticket'; + $s_plugin_ProjectManagement_bug_view_mode = 'Modo de presentación en el ticket'; + $s_plugin_ProjectManagement_bug_view_mode_info = 'Sólo existen 2 opciones: 1 y 2'; $s_plugin_ProjectManagement_decimal_separator = 'Separador decimal'; $s_plugin_ProjectManagement_thousand_separator = 'Separador de miles'; - $s_plugin_ProjectManagement_localization = 'Localizacion'; + $s_plugin_ProjectManagement_localization = 'Localización'; - $s_plugin_ProjectManagement_include_bugs_with_deadline = 'Incluir bugs con fecha limite'; - $s_plugin_ProjectManagement_include_bugs_with_deadline_info = 'En la pantalla de progreso del proyecto, incluir tambien bugs con fecha limite anterior a la fecha de liberacion del proyecto.'; - $s_plugin_ProjectManagement_include_bugs_with_deadline_warning = 'Atencion: Esta opcion tiene un impacto negativo en el rendimiento de esta pagina.'; + $s_plugin_ProjectManagement_include_bugs_with_deadline = 'Incluir tickets con fecha límite'; + $s_plugin_ProjectManagement_include_bugs_with_deadline_info = 'En la pantalla de progreso del proyecto, incluir también tickets con fecha límite anterior a la fecha de entrega del proyecto.'; + $s_plugin_ProjectManagement_include_bugs_with_deadline_warning = 'Atención: Esta opción tiene un impacto negativo en el rendimiento de esta página.'; - $s_plugin_ProjectManagement_view_customer_payment_summary_threshold = 'Ver umbral de resumen de pagos de cliente'; + $s_plugin_ProjectManagement_view_customer_payment_summary_threshold = 'Umbral para ver resumen de pagos de cliente'; $s_plugin_ProjectManagement_enable_customer_payment_threshold = 'Habilitar umbral de pagos de cliente'; - $s_plugin_ProjectManagement_enable_customer_payment_threshold_info = 'Permitir que los bugs sean pagados por un cliente especifico solamente.'; - $s_plugin_ProjectManagement_enable_customer_approval_threshold = 'Habilitar el umbral de aprobacion de cliente'; - $s_plugin_ProjectManagement_enable_customer_approval_threshold_info = 'Permitir a los clientes indicar si aprueban el desarrollo en bugs especificos.'; - $s_plugin_ProjectManagement_view_billing_threshold = 'Ver umbral de facturacion'; - - $s_plugin_ProjectManagement_customer_section = 'Seccion de cliente'; - $s_plugin_ProjectManagement_paying_customers = 'Clientes pagadores'; - $s_plugin_ProjectManagement_integration_custom_dev = 'Desarrollo especifico de integracion'; - $s_plugin_ProjectManagement_integration_custom_dev_info = 'Integracion de una funcionalidad del core con funcionalidades personalizadas existentes.'; - $s_plugin_ProjectManagement_approving_customers = 'Aprovacion de clientes'; - $s_plugin_ProjectManagement_general_configuration = 'Configuracion del plugin'; - $s_plugin_ProjectManagement_customer_management = 'Configuracion de clientes'; + $s_plugin_ProjectManagement_enable_customer_payment_threshold_info = 'Permitir que los tickets sean pagados por un cliente específico solamente.'; + $s_plugin_ProjectManagement_enable_customer_approval_threshold = 'Habilitar el umbral de aprobación de cliente'; + $s_plugin_ProjectManagement_enable_customer_approval_threshold_info = 'Permitir a los clientes indicar si aprueban el desarrollo en tickets específicos.'; + $s_plugin_ProjectManagement_view_billing_threshold = 'Umbral para ver la facturación'; + $s_plugin_ProjectManagement_billable_mandatory_minimun_status = 'Estado mínimo para requerir que se indiquen los clientes a facturar'; + $s_plugin_ProjectManagement_billable_behavior_over_severity = 'Comportamiento del requisito de facturable'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_info = 'Se debe indicar, para cada nivel de severidad, cómo debe comportarse el requisito de facturable en el ticket'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_optional_unselected = 'Opcional, deseleccionado por defecto'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_optional_selected = 'Opcional, seleccionado por defecto'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_always_required = 'Siempre requerido'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_never_required = 'Nunca requerido'; + $s_plugin_ProjectManagement_billable_behavior_over_severity_never_billable = 'Nunca facturable'; + + $s_plugin_ProjectManagement_customer_section = 'Sección de cliente'; + $s_plugin_ProjectManagement_is_billable = 'Ticket facturable'; + $s_plugin_ProjectManagement_paying_customers = 'Clientes a facturar'; + $s_plugin_ProjectManagement_integration_custom_dev = 'Desarrollo específico de integración'; + $s_plugin_ProjectManagement_integration_custom_dev_info = 'Integración de una funcionalidad del core con funcionalidades personalizadas existentes.'; + $s_plugin_ProjectManagement_approving_customers = 'Aprobación de clientes'; + $s_plugin_ProjectManagement_general_configuration = 'Configuración del plugin'; + $s_plugin_ProjectManagement_customer_management = 'Configuración de clientes'; $s_plugin_ProjectManagement_add_new_customer = 'Agregar cliente nuevo'; + $s_plugin_ProjectManagement_add_customer = 'Agregar cliente'; $s_plugin_ProjectManagement_edit_customer = 'Editar cliente'; $s_plugin_ProjectManagement_customer_name = 'Nombre de cliente'; $s_plugin_ProjectManagement_customer_share = 'Compartir'; $s_plugin_ProjectManagement_customer_can_approve = 'Puede aprobar'; - $s_plugin_ProjectManagement_billing = 'Facturacion'; - $s_plugin_ProjectManagement_fields_to_include_in_overviews = 'Columnas extra a incluir en los resumenes'; - $s_plugin_ProjectManagement_fields_to_include_in_overviews_info = 'Es posible indicar tanto campos personalizados como columnas del plugin. Utilice los nombres de columnas como se indica en \'Gestion de configuracion\' > \'Gestionar columnas\''; + $s_plugin_ProjectManagement_customer_association_mode = 'Modo de vinculación'; + $s_plugin_ProjectManagement_billing = 'Facturación'; + $s_plugin_ProjectManagement_fields_to_include_in_overviews = 'Columnas extra a incluir en los resúmenes'; + $s_plugin_ProjectManagement_fields_to_include_in_overviews_info = 'Es posible indicar tanto campos personalizados como columnas del plugin. Utilice los nombres de columnas como se indica en \'Gestión de configuración\' > \'Gestionar columnas\''; $s_plugin_ProjectManagement_targets = 'Objetivos'; $s_plugin_ProjectManagement_target_date = 'Fecha objetivo'; $s_plugin_ProjectManagement_overdue = 'Retrasado'; - $s_plugin_ProjectManagement_owner = 'Propietario'; + $s_plugin_ProjectManagement_owner = 'Responsable'; $s_plugin_ProjectManagement_completed = 'Completado'; $s_plugin_ProjectManagement_new_target = 'Nuevo objetivo'; $s_plugin_ProjectManagement_target_overview = 'Resumen de objetivos'; - $s_plugin_ProjectManagement_project_without_versions = 'Para ver esta pagina, debe seleccionar un proyectoque contenga versiones con fechas de publicacion.'; - $s_plugin_ProjectManagement_all_versions_selected = 'Para ver esta pagina debe seleccionar un proyecto concreto en lugar de \'Todos los proyectos\'.'; - $s_plugin_ProjectManagement_project_selection_disabled = 'Para ver esta pagina, el parametro \'Motrar la barra de menu de proyecto\' debe estar a \'ON\'. Contacte con el administrador.'; + $s_plugin_ProjectManagement_project_without_versions = 'Para ver esta página, debe seleccionar un proyecto que contenga versiones con fechas de publicación.'; + $s_plugin_ProjectManagement_all_versions_selected = 'Para ver esta página debe seleccionar un proyecto concreto en lugar de \'Todos los proyectos\'.'; + $s_plugin_ProjectManagement_project_selection_disabled = 'Para ver esta página, el parámetro \'Motrar la barra de menú de proyecto\' debe estar a \'ON\'. Contacte con el administrador.'; + $s_plugin_ProjectManagement_unavailability_account_title = 'Indisponibilidad'; + $s_plugin_ProjectManagement_unavailability_period_title = 'Periodos de indisponibilidad'; + $s_plugin_ProjectManagement_unavailability_past_period_title = 'Periodos de indisponibilidad pasados'; $s_plugin_ProjectManagement_unavailability = 'Indisponibilidad'; $s_plugin_ProjectManagement_unavailability_types = 'Tipos de indisponibilidad'; - $s_plugin_ProjectManagement_unavailability_add_new = 'Agregar un nuevo periodo de indisponibilidad'; + $s_plugin_ProjectManagement_unavailability_add_new_title = 'Agregar un nuevo periodo de indisponibilidad'; + $s_plugin_ProjectManagement_unavailability_add_new = 'Agregar'; $s_plugin_ProjectManagement_unavailability_overview = 'Resumen de periodos de indisponibilidad'; $s_plugin_ProjectManagement_unavailability_remove = 'Eliminar periodo de indisponibilidad'; $s_plugin_ProjectManagement_unavailability_period = 'Periodo'; @@ -121,32 +160,41 @@ $s_plugin_ProjectManagement_unavailability_note = 'Nota'; $s_plugin_ProjectManagement_unavailability_ignore_work = 'Ignorar trabajo durante estos periodos'; - $s_plugin_ProjectManagement_unavailability_ignore_work_info = 'Las horas registradas durante un periodo de indisponibilidad de este tipo seran ignoradas en la pagina \'Progreso del recurso\' .
Ejemplo: array ( 60, 80 )'; + $s_plugin_ProjectManagement_unavailability_ignore_work_info = 'Las horas registradas durante un periodo de indisponibilidad de este tipo seran ignoradas en la página \'Progreso del recurso\' .
Ejemplo: array ( 60, 80 )'; + $s_plugin_ProjectManagement_user = 'Usuario'; + $s_plugin_ProjectManagement_information = 'Comentario'; + $s_plugin_ProjectManagement_entry_date = 'Fecha entrada (automático)'; + $s_plugin_ProjectManagement_time_error = 'Por favor, introduce un número correcto para el campo horas/días!'; + $s_plugin_ProjectManagement_date_error = 'Por favor, introduce una fecha correcta!'; + $s_plugin_ProjectManagement_minutes_type = 'Tipo de registro'; + $s_plugin_ProjectManagement_add_time_registration = 'Enviar'; + $s_plugin_ProjectManagement_delete_time_registration = 'Eliminar'; + $s_plugin_ProjectManagement_unplanned = 'No planificado'; $s_plugin_ProjectManagement_planned = 'Planificado'; $s_plugin_ProjectManagement_unavailable = 'No disponible'; $s_plugin_ProjectManagement_finished = 'Finalizado'; - $s_plugin_ProjectManagement_select_target_version = 'Seleccione una version objetivo'; - $s_plugin_ProjectManagement_select_from_version = 'Opcionalmente especifique una version de referencia'; + $s_plugin_ProjectManagement_select_target_version = 'Seleccione una versión objetivo'; + $s_plugin_ProjectManagement_select_from_version = 'Opcionalmente especifique una versión de referencia'; $s_plugin_ProjectManagement_select_from_date = 'o fecha de referencia'; $s_plugin_ProjectManagement_reference_date = 'Fecha de referencia'; - $s_plugin_ProjectManagement_release_date = 'Fecha de liberacion'; - $s_plugin_ProjectManagement_last_dev_day = 'Ultimo dia de desarrollo'; - $s_plugin_ProjectManagement_group_by_projects = 'Agrupar por proyectos y categorias'; - $s_plugin_ProjectManagement_group_by_projects_by_default = 'Agrupar por proyectos y categorias por defecto'; + $s_plugin_ProjectManagement_release_date = 'Fecha de entrega'; + $s_plugin_ProjectManagement_last_dev_day = 'Último día de desarrollo'; + $s_plugin_ProjectManagement_group_by_projects = 'Agrupar por proyectos y categorías'; + $s_plugin_ProjectManagement_group_by_projects_by_default = 'Agrupar por proyectos y categorías por defecto'; $s_plugin_ProjectManagement_show_projects_by_default = 'Mostrar proyectos para cada recurso por defecto inmediatamente'; - $s_plugin_ProjectManagement_release_buffer = 'Acumular dias hasta la liberacion'; + $s_plugin_ProjectManagement_release_buffer = 'Acumular días hasta la entrega'; - $s_plugin_ProjectManagement_error_enddate_before_startdate = 'La fecha de finalizacion debe ser posterior a la fecha de comienzo.'; + $s_plugin_ProjectManagement_error_enddate_before_startdate = 'La fecha de finalización debe ser posterior a la fecha de comienzo.'; - $s_plugin_ProjectManagement_work_hours_per_day = 'Horas de trabajo por dia'; + $s_plugin_ProjectManagement_work_hours_per_day = 'Horas de trabajo por día'; $s_plugin_ProjectManagement_monday = 'lunes'; $s_plugin_ProjectManagement_tuesday = 'martes'; - $s_plugin_ProjectManagement_wednesday = 'miercoles'; + $s_plugin_ProjectManagement_wednesday = 'miércoles'; $s_plugin_ProjectManagement_thursday = 'jueves'; $s_plugin_ProjectManagement_friday = 'viernes'; - $s_plugin_ProjectManagement_saturday = 'sabado'; + $s_plugin_ProjectManagement_saturday = 'sábado'; $s_plugin_ProjectManagement_sunday = 'domingo'; $s_plugin_ProjectManagement_January = 'Enero'; @@ -161,4 +209,11 @@ $s_plugin_ProjectManagement_October = 'Octubre'; $s_plugin_ProjectManagement_November = 'Noviembre'; $s_plugin_ProjectManagement_December = 'Diciembre'; -?> + + $s_plugin_ProjectManagement_history_deleted = 'Registro de tiempo eliminado'; + $s_plugin_ProjectManagement_history_added = 'Registro de tiempo para \'%1$s\': %2$s'; + $s_plugin_ProjectManagement_history_completed_date = 'Fecha de cumplimiento actualizada para \'%1$s\''; + $s_plugin_ProjectManagement_history_owner_changed = 'Responsable cambiado para \'%1$s\''; + $s_plugin_ProjectManagement_history_new_target = 'Nuevo objetivo para \'%1$s\''; + $s_plugin_ProjectManagement_history_change_target = 'Objetivo cambiado para \'%1$s\''; + $s_plugin_ProjectManagement_todo_without_est_warning = 'El tiempo pendiente no se tiene en cuenta mientras no se defina el tiempo estimado'; diff --git a/ProjectManagement/pages/account_unavailability_delete.php b/ProjectManagement/pages/account_unavailability_delete.php new file mode 100644 index 0000000..b043afa --- /dev/null +++ b/ProjectManagement/pages/account_unavailability_delete.php @@ -0,0 +1,20 @@ + +
+
+
+ + + + + + + + + + > + + + + +
+ + + +
+ + + + + + + + + + + + + +
+ : + + + - + + +
+ : + + +
+ : + + +
+
+ +
+ +
+ + +
+ + + +
+
+'; @@ -277,14 +284,14 @@ foreach ( $t_plugin_columns_to_include as $col_name => $col_obj ) { echo ' ' . $row[$col_obj->title] . ''; } - echo ' ' . $row['username'] . ''; - echo ' ' . $row['bug_id'] . ''; + echo ' ' . $row['realname'] . ''; + echo ' ' . $bug_view_link . ''; echo ' ' . $row['bug_summary'] . ''; - echo ' ' . format( $row['hours'], 2, false ) . ''; - echo ' ' . format( $row['hourly_rate'], 2, false ) . ''; - echo ' ' . format( $row['cost'], 2, false ) . ''; + echo '
' . format( $row['hours'], 2, false ) . '
'; + echo '
' . format( $row['hourly_rate'], 2, false ) . ' ' . ($row['hourly_rate'] ? plugin_config_get ( 'currency_symbol' ) : '') . '
'; + echo '
' . format( $row['cost'], 2, false ) . ' ' . ($row['cost'] ? plugin_config_get ( 'currency_symbol' ) : '') . '
'; foreach ( $t_all_customers as $cust ) { - echo ' ' . format( $row[$cust['name']], 2, false ) . ''; + echo '
' . format( $row[$cust['name']], 2, false ) . ' ' . ($row[$cust['name']] ? plugin_config_get ( 'currency_symbol' ) : '') . '
'; } echo ''; } diff --git a/ProjectManagement/pages/bug_view_customer.php b/ProjectManagement/pages/bug_view_customer.php new file mode 100644 index 0000000..3b956ba --- /dev/null +++ b/ProjectManagement/pages/bug_view_customer.php @@ -0,0 +1,91 @@ + + +
+ ", $p_bug_id ); + echo ''; + ?> + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + '; + echo plugin_lang_get( 'integration_custom_dev_info' ) + ?> +
+ + + + + + +
+
+
+ + \ No newline at end of file diff --git a/ProjectManagement/pages/bug_view_target_option1.php b/ProjectManagement/pages/bug_view_target_option1.php new file mode 100644 index 0000000..4764c7b --- /dev/null +++ b/ProjectManagement/pages/bug_view_target_option1.php @@ -0,0 +1,177 @@ + + +
+ ", $p_bug_id ); + ?> + + + + + + + + + + + + + $t_work_type_label ) { + if ( $t_work_type_code == PLUGIN_PM_WORKTYPE_TOTAL ) { + continue; + } else if ( array_key_exists( $t_work_type_code, $t_targets ) ) { + $t_target = $t_targets[$t_work_type_code]; + $t_target_date = date( config_get( 'short_date_format' ), $t_target["target_date"] ); + $t_owner_id = $t_target["owner_id"]; + $t_completed_date = format_short_date( $t_target["completed_date"] ); + $t_days_overdue = days_between( $t_target["target_date"], $t_target["completed_date"] ) * -1; + $t_days_overdue_class = $t_days_overdue < 0 ? 'class="negative"' : 'class="positive"'; + + $t_target_date_class = ''; + if ( is_null( $t_completed_date ) ) { + if ( $t_owner_id == auth_get_current_user_id() ) { + if ( $t_days_overdue < 0 ) { + $t_target_date_class = 'class="target-date-overdue"'; + } else if ( $t_days_overdue == 0 ) { + $t_target_date_class = 'class="target-date-notice"'; + } + } else if ( $t_days_overdue < 0 ) { + $t_target_date_class = 'class="target-date-notice"'; + } + } + + $t_days_overdue = abs( $t_days_overdue ); + } else { + # target for this worktype has not yet been defined + $t_target_date = null; + $t_target_date_class = ''; + $t_days_overdue = null; + $t_days_overdue_class = ''; + $t_completed_date = null; + # Find the default owner for this work type + $t_customer_work_types = plugin_config_get( 'work_types_for_customer' ); + $t_work_type_for_customer = false; + foreach ( $t_customer_work_types as $work_type ) { + if ( $work_type == $t_work_type_code ) { + $t_work_type_for_customer = true; + } + } + if ( $t_work_type_for_customer ) { + $t_reporter_id = bug_get_field( $p_bug_id, 'reporter_id' ); + $t_owner_id = is_null( $t_reporter_id ) ? -1 : $t_reporter_id; + } else { + $t_handler_id = bug_get_field( $p_bug_id, 'handler_id' ); + $t_owner_id = is_null( $t_handler_id ) ? -1 : $t_handler_id; + } + } + + $t_can_edit_targets = access_has_global_level( plugin_config_get( 'edit_targets_threshold' ) ); + ?> + > + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ +
+
+
+
> + + + + > + + + + + + + +
+ +
+ + + + + + + +
+
+
+ + \ No newline at end of file diff --git a/ProjectManagement/pages/bug_view_target_option2.php b/ProjectManagement/pages/bug_view_target_option2.php new file mode 100644 index 0000000..cbde526 --- /dev/null +++ b/ProjectManagement/pages/bug_view_target_option2.php @@ -0,0 +1,323 @@ + + +
+ ", $p_bug_id ); + ?> + + + + + + + + + + + + + + + + + + + + $t_work_type_label ) { + if ( $t_work_type_code == PLUGIN_PM_WORKTYPE_TOTAL ) { + if ( access_has_bug_level( plugin_config_get( 'view_time_reg_summary_threshold' ), $p_bug_id ) ) { + ?> + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + '; + if ( isset( $t_work[PLUGIN_PM_DIFF][$t_work_type_code] ) ) { + ?> + + + + + + + + + +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
  +
+ +
+
+
+ +
+
+
+ +
+
> +
+ +
+
 
> + + + + > + + + + + + + +
+ +
+ +
+ +
+
> + +
'; + } + echo '>
+
'; + } ?> + + + + +
+ +
+ + + + + + + +
+
+
+ + \ No newline at end of file diff --git a/ProjectManagement/pages/bug_view_time_registration_option1.php b/ProjectManagement/pages/bug_view_time_registration_option1.php new file mode 100644 index 0000000..73aad3d --- /dev/null +++ b/ProjectManagement/pages/bug_view_time_registration_option1.php @@ -0,0 +1,158 @@ + + +
+ ", $p_bug_id ); + ?> + + + + + + + + + + + + + + $t_work_type_label ) { + ?> + > + + + + + + + + + + '; + } ?> + + + + + + +
+ +
+
+
+
+
+
+
+
+
+
+
+ + -> > + + + + + > + + + + + '; + } + if ( $t_work_type_code != PLUGIN_PM_WORKTYPE_TOTAL ) { + ?> + -> > + + > + '; + if ( isset( $t_work[PLUGIN_PM_DIFF][$t_work_type_code] ) ) { + ?> + > +
+ + '; + date_print_calendar( 'book_date_cal' ); + date_finish_calendar( 'book_date', 'book_date_cal' ); + } + ?> +
+ + + + + + + + +
+
+
+ + \ No newline at end of file diff --git a/ProjectManagement/pages/bug_view_time_registration_option2.php b/ProjectManagement/pages/bug_view_time_registration_option2.php new file mode 100644 index 0000000..b33f141 --- /dev/null +++ b/ProjectManagement/pages/bug_view_time_registration_option2.php @@ -0,0 +1,229 @@ + + +
+ ", $p_bug_id ); + ?> + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + > + + + + + + + + + + + + + + +
+ +
 
+
+ +
+
+
+ +
+
+
+ '; + date_print_calendar( 'book_date_cal' ); + date_finish_calendar( 'book_date', 'book_date_cal', false ); + } + ?> + + + + + +
+
+
+ + name= value="00:00"> + name= value="00:00"> + name= value="00:00"> + name= value="00:00"> +
+
+
+ +
+
  +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ + + "> + + + +
+
+ + + + + + + + +
+
+ + + \ No newline at end of file diff --git a/ProjectManagement/pages/config_page.php b/ProjectManagement/pages/config_page.php index 6c76093..2980257 100644 --- a/ProjectManagement/pages/config_page.php +++ b/ProjectManagement/pages/config_page.php @@ -9,7 +9,7 @@ $f_options_changed = gpc_get( 'options_changed', 0 ); if ( $f_options_changed > 0 ) { - echo '

' . plugin_lang_get('settings_updated') . ': ' . $f_options_changed . '

'; + echo '

' . plugin_lang_get('settings_updated') . ': ' . $f_options_changed . '

'; } print_pm_config_menu( 'config_page' ); @@ -42,6 +42,18 @@ name="view_time_reg_summary_threshold"> + > + + + + + > + + + + >
@@ -75,20 +87,35 @@ - - > -
- - - -
+ + > +
+ + + + + > +
+ + + + > +
+ + > + + +
- - - - +
+ + + > -

+
- - - - +
+ + + > -

+
- - - - +
+ + + > > - + -

@@ -179,95 +206,127 @@


- - - - - > - - - - + > + + + + > + + + + +

-
> -

+
+ + $t_value ) { + ?> + + + + + +
+ : + + +
+ + +

+ + + + + + > + + + + > - > - - + - - > - - > + + - + + - > + > - - + - - - > - - - - > - - - - - > - - - + + + + + > + + + + > + + + + + > + + + diff --git a/ProjectManagement/pages/config_update.php b/ProjectManagement/pages/config_update.php index a067dfe..5ed441b 100644 --- a/ProjectManagement/pages/config_update.php +++ b/ProjectManagement/pages/config_update.php @@ -14,6 +14,8 @@ function maybe_set_option( $name, $value ) { $t_total_options_changed = 0; $t_total_options_changed += maybe_set_option( 'work_types', gpc_get_string( 'work_types' ) ); +$t_total_options_changed += maybe_set_option( 'edit_targets_threshold', gpc_get_int( 'edit_targets_threshold' ) ); +$t_total_options_changed += maybe_set_option( 'show_all_work_types_on_bug_targets', gpc_get_bool( 'show_all_work_types_on_bug_targets' ) ); $t_total_options_changed += maybe_set_option( 'edit_estimates_threshold', gpc_get_int( 'edit_estimates_threshold' ) ); $t_total_options_changed += maybe_set_option( 'view_time_reg_summary_threshold', gpc_get_int( 'view_time_reg_summary_threshold' ) ); $t_total_options_changed += maybe_set_option( 'include_bookdate_threshold', gpc_get_int( 'include_bookdate_threshold' ) ); @@ -21,6 +23,7 @@ function maybe_set_option( $name, $value ) { $t_total_options_changed += maybe_set_option( 'finish_upon_resolving', string_to_array( gpc_get_string( 'finish_upon_resolving', null ) ) ); $t_total_options_changed += maybe_set_option( 'finish_upon_closing', string_to_array( gpc_get_string( 'finish_upon_closing', null ) ) ); $t_total_options_changed += maybe_set_option( 'work_types_for_customer', string_to_array( gpc_get_string( 'work_types_for_customer', null ) ) ); +$t_total_options_changed += maybe_set_option( 'bug_view_mode', gpc_get_string( 'bug_view_mode' ) ); $t_total_options_changed += maybe_set_option( 'enable_time_registration_threshold', gpc_get_int( 'enable_time_registration_threshold' ) ); $t_total_options_changed += maybe_set_option( 'view_registration_worksheet_threshold', gpc_get_int( 'view_registration_worksheet_threshold' ) ); $t_total_options_changed += maybe_set_option( 'view_registration_report_threshold', gpc_get_int( 'view_registration_report_threshold' ) ); @@ -36,6 +39,7 @@ function maybe_set_option( $name, $value ) { $t_total_options_changed += maybe_set_option( 'enable_customer_approval_threshold', gpc_get_int( 'enable_customer_approval_threshold' ) ); $t_total_options_changed += maybe_set_option( 'view_customer_payment_summary_threshold', gpc_get_int( 'view_customer_payment_summary_threshold' ) ); $t_total_options_changed += maybe_set_option( 'view_billing_threshold', gpc_get_int( 'view_billing_threshold' ) ); +$t_total_options_changed += maybe_set_option( 'billable_mandatory_minimun_status', gpc_get_int( 'billable_mandatory_minimun_status' ) ); $t_total_options_changed += maybe_set_option( 'release_buffer', gpc_get_string( 'release_buffer' ) ); $t_total_options_changed += maybe_set_option( 'group_by_projects_by_default', gpc_get_bool( 'group_by_projects_by_default' ) ); $t_total_options_changed += maybe_set_option( 'show_projects_by_default', gpc_get_bool( 'show_projects_by_default' ) ); @@ -43,6 +47,13 @@ function maybe_set_option( $name, $value ) { $t_total_options_changed += maybe_set_option( 'unavailability_ignore_work', string_to_array( gpc_get_string( 'unavailability_ignore_work', null ) ) ); $t_total_options_changed += maybe_set_option( 'fields_to_include_in_overviews', string_to_array( gpc_get_string( 'fields_to_include_in_overviews', null ) ) ); +$t_billable_behavior_over_severity = array(); +$t_severity_enum = get_severity_enum(); +foreach ( $t_severity_enum as $t_key => $t_value ) { + $t_billable_behavior_over_severity[$t_key] = gpc_get_int( 'billable_behavior_over_severity_' . $t_key, 1 ); +} +plugin_config_set( 'billable_behavior_over_severity', $t_billable_behavior_over_severity ); + $t_hours_for_day = array(); for ( $i = 1; $i <= 7; $i++ ) { $t_hours_for_day[$i] = gpc_get_int( 'work_hours_per_day_' . $i, 0 ); diff --git a/ProjectManagement/pages/customer_overview_page.php b/ProjectManagement/pages/customer_overview_page.php index 71c8bc6..4dbb24f 100644 --- a/ProjectManagement/pages/customer_overview_page.php +++ b/ProjectManagement/pages/customer_overview_page.php @@ -17,13 +17,13 @@

+
> +
> + >
+
> -
+ - + - + - + - + - + - -
-
-
-
+
+
+
- + + @@ -33,11 +33,13 @@ $t_name = $row['name']; $t_share = format( $row['share'], 2 ); $t_can_approve = $row['can_approve'] == 1 ? 'X' : ' '; + $t_association_mode = $row['association_mode']; ?> > + - +
%
@@ -56,8 +58,7 @@
diff --git a/ProjectManagement/pages/customer_update.php b/ProjectManagement/pages/customer_update.php index 5f56170..e97fb06 100644 --- a/ProjectManagement/pages/customer_update.php +++ b/ProjectManagement/pages/customer_update.php @@ -8,18 +8,19 @@ $f_name = gpc_get_string( 'customer_name', null ); $f_share = parse_float( gpc_get_string( 'customer_share', 0 ) ); $f_can_approve = gpc_get_bool( 'customer_can_approve', 0 ); +$f_association_mode = gpc_get_int( 'association_mode', 0 ); $t_customer_table = plugin_table( 'customer' ); if ( empty( $f_customer_id ) ) { # Insert new customer - $t_query = "INSERT INTO $t_customer_table (name, share, can_approve) - VALUES ('$f_name', $f_share, $f_can_approve)"; + $t_query = "INSERT INTO $t_customer_table (name, share, can_approve, association_mode) + VALUES ('$f_name', $f_share, $f_can_approve, $f_association_mode)"; db_query_bound( $t_query ); } else { # Update existing customer $t_query = "UPDATE $t_customer_table - SET name = '$f_name', share = $f_share, can_approve = $f_can_approve + SET name = '$f_name', share = $f_share, can_approve = $f_can_approve, association_mode = $f_association_mode WHERE id = $f_customer_id"; db_query_bound( $t_query ); } diff --git a/ProjectManagement/pages/customer_update_page.php b/ProjectManagement/pages/customer_update_page.php index 668689e..bb1d5b8 100644 --- a/ProjectManagement/pages/customer_update_page.php +++ b/ProjectManagement/pages/customer_update_page.php @@ -10,6 +10,7 @@ $t_name = null; $t_share = null; $t_can_approve = null; +$t_association_mode = null; if ( !empty( $f_customer_id ) ) { $t_customer_table = plugin_table( 'customer' ); @@ -20,6 +21,7 @@ $t_name = $t_customer['name']; $t_share = format( $t_customer['share'], 5 ); $t_can_approve = $t_customer['can_approve']; + $t_association_mode = $t_customer['association_mode']; } } @@ -58,6 +60,14 @@ id="customer_can_approve" > + > +
+ + + + + + diff --git a/ProjectManagement/pages/html_api.php b/ProjectManagement/pages/html_api.php index c4218cc..2a81881 100644 --- a/ProjectManagement/pages/html_api.php +++ b/ProjectManagement/pages/html_api.php @@ -1,15 +1,19 @@

'; + if ( access_has_global_level( plugin_config_get( 'view_registration_report_threshold' ) ) ) { + print_bracket_link( $t_pm_time_dashboard_page, plugin_lang_get( 'time_dashboard' ) ); + } if ( access_has_global_level( plugin_config_get( 'view_registration_worksheet_threshold' ) ) ) { print_bracket_link( $t_pm_time_registration_page, plugin_lang_get( 'time_registration_worksheet' ) ); } @@ -84,7 +91,7 @@ function print_pm_config_menu( $p_page = '' ) { function print_plugin_enum_string_option_list( $p_enum_name, $p_val = 0 ) { $t_config_var_value = plugin_config_get( $p_enum_name ); $t_enum_values = MantisEnum::getAssocArrayIndexedByValues( $t_config_var_value ); - + foreach ( $t_enum_values as $t_key => $t_value ) { echo '

+'; +print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) ); +?> +
+ + +
+
+'; +print_bracket_link( $t_redirect_url, lang_get( 'proceed' ) ); +?> +
+ + + +
+ + + + +
+
+ '; + date_print_calendar( 'period_start_cal' ); + date_finish_calendar( 'period_start', 'period_start_cal' ); + echo ' - '; + date_print_calendar( 'period_end_cal' ); + date_finish_calendar( 'period_end', 'period_end_cal' ); + echo ' - ', lang_get( 'username' ), ': '; + ?> + + +
+
+
+ + + + +
+ + + + + +
+ + + +
+ +
+ + + diff --git a/ProjectManagement/pages/report_registration_page.php b/ProjectManagement/pages/report_registration_page.php index 5ee829e..84be7a5 100644 --- a/ProjectManagement/pages/report_registration_page.php +++ b/ProjectManagement/pages/report_registration_page.php @@ -20,7 +20,7 @@ $t_bug_table = db_get_table( 'mantis_bug_table' ); $t_project_table = db_get_table( 'mantis_project_table' ); $t_category_table = db_get_table( 'mantis_category_table' ); -$t_work_types = plugin_lang_get_enum( 'work_types' ); +$t_work_types = plugin_lang_get_enum( 'work_types' ); // MantisEnum::getAssocArrayIndexedByValues( plugin_config_get( 'work_types' ) ); $t_customer_work_type_exclusion_clause = build_customer_worktype_exclude_clause('work_type'); $t_const_done = PLUGIN_PM_DONE; @@ -64,6 +64,7 @@ $t_per_project = array(); $t_per_category = array(); +$t_collapse_time_registration = 'plugin_pm_time_registration'; ?>
@@ -92,10 +93,13 @@
+
+ @@ -124,12 +128,14 @@ + + @@ -148,143 +154,117 @@ $t_book_date = date( config_get( 'short_date_format' ), $row["book_date"] ); $t_work_type = plugin_get_enum_element( 'work_types', $row["work_type"] ); $t_work_type_link = $t_plugin_page . '&work_type=' . $row["work_type"]; - $t_hours = format( $row["minutes"] / 60 ); + $t_hours = minutes_to_time( $row["minutes"] ); $t_hourly_rate = format( $row["hourly_rate"] ); $t_cost = format( $row["minutes"] * $row["hourly_rate"] / 60 ); - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo "'; + echo ''; + echo ''; + echo ''; + echo ''; + echo '"; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; + echo ''; + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + } + echo ''; + + @$t_per_work_type[$row["user_id"]][$row["work_type"]] += $row["minutes"]; // / 60; + @$t_per_work_type[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"]; // / 60; + + //@$t_per_project[$row["user_id"]][$row["project_id"]] += $row["minutes"] / 60; + //@$t_per_project[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + + //@$t_per_project[$row["project_id"]][$row["user_id"]] += $row["minutes"] / 60; + //@$t_per_project[$row["project_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; - @$t_per_work_type[$row["user_id"]][$row["work_type"]] += $row["minutes"] / 60; - @$t_per_work_type[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + /* - @$t_per_project[$row["user_id"]][$row["project_id"]] += $row["minutes"] / 60; - @$t_per_project[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + if ( ! isset ( $t_per_project[$row["project_id"]]) || ! array_key_exists( $row["user_id"], $t_per_project[$row["project_id"]]["users"] ) ) { + @$t_per_project[$row["project_id"]]["total_hourly_rate"] += $t_hourly_rate; + @$t_per_project[$row["project_id"]]["total_users"] += 1; + @$t_per_project[$row["project_id"]]["average_hourly_rate"] = @$t_per_project[$row["project_id"]]["total_hourly_rate"] / @$t_per_project[$row["project_id"]]["total_users"]; + } + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["time"] += $row["minutes"]; // / 60; + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["hourly_rate"] = $t_hourly_rate; + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["cost"] += $t_cost; + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["work_types"][$row["work_type"]]["time"] += $row["minutes"]; // / 60; + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["work_types"][$row["work_type"]]["cost"] += $t_cost; + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["total_work_types_time"] += $row["minutes"]; // / 60; + @$t_per_project[$row["project_id"]]["users"][$row["user_id"]]["total_work_types_cost"] += $t_cost; + @$t_per_project[$row["project_id"]]["total_time"] += $row["minutes"]; // / 60; + @$t_per_project[$row["project_id"]]["total_cost"] += $t_cost; - @$t_per_category[$row["user_id"]][$row["category_id"]] += $row["minutes"] / 60; - @$t_per_category[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + @$t_per_project[$row["project_id"]]["work_types"][$row["work_type"]]["time"] += $row["minutes"]; // / 60; + @$t_per_project[$row["project_id"]]["work_types"][$row["work_type"]]["cost"] += $t_cost; + + */ + + @$t_per_category[$row["user_id"]][$row["category_id"]] += $row["minutes"]; // / 60; + @$t_per_category[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"]; // / 60; @$t_total_cost += $row["minutes"] * $row["hourly_rate"] / 60; + @$t_total_time += $row["minutes"]; } # Display a total cost line - echo ''; - echo ''; - echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } ?>
+
$t_username$t_book_date$t_project_name$t_category_name"; + echo '
' . $t_username . '' . $t_book_date . '' . $t_project_name . '' . $t_category_name . ''; print_bug_link( $row["bug_id"] ); - echo "$t_bug_summary$t_work_type$t_hours$t_hourly_rate$t_cost
' . $t_bug_summary . '' . $t_work_type . '' . $t_hours . '' . $t_hourly_rate . plugin_config_get ( 'currency_symbol' ) . '' . $t_cost . plugin_config_get ( 'currency_symbol' ) . '
' . plugin_lang_get( 'total_cost' ) . '' . format( $t_total_cost ) . '
' . plugin_lang_get( 'total_cost' ) . '' . minutes_to_time( $t_total_time ) . '' . format( $t_total_cost ) . plugin_config_get ( 'currency_symbol' ) . '
+ - +
- -
- 0 ) { - ?> -
- - - - - - - $t_work_type_label ) { - ?> - - - - - - $t_categories ) { - echo ""; - echo '"; - foreach ( $t_work_types as $t_work_type_value => $t_work_type_label ) { - echo ""; - } - echo ""; - } - ?> - -
- - - -
-
-
-
-
-
-
'; - print_user( $t_user ); - echo "" . format( @$t_categories[$t_work_type_value] ) . "" . format( @$t_categories[plugin_lang_get( 'total' )] ) . "
- +
+ + - 0 ) { - ?> -
- - - - - - - - - - - - - $t_categories ) { - echo ""; - echo '"; - foreach ( category_get_all_rows( $f_project_id ) as $row ) { - echo ""; - } - echo ""; - } - ?> + +
- - - -
-
-
-
-
-
-
'; - print_user( $t_user ); - echo "" . format( @$t_categories[$row["id"]] ) . "" . format( @$t_categories[plugin_lang_get( 'total' )] ) . "
+ -
- + + 0 ) { + ?> + +
+ + + 0 ) { + + if ( count( $t_per_work_type ) > 0 ) { + echo ''; + } + else { + echo ''; } - ?> + ?> +
+ + + + + + + + + + + + + + + $t_categories ) { + echo ""; + echo '"; + foreach ( category_get_all_rows( $f_project_id ) as $row ) { + echo ""; + } + echo ""; + } + ?> +
+ + - + +
+
+
+
+
+
+
'; + print_user( $t_user ); + echo "" . minutes_to_time( @$t_categories[$row["id"]] ) . "" . minutes_to_time( @$t_categories[plugin_lang_get( 'total' )] ) . "
+ + + + + +
+ + - + +
+ diff --git a/ProjectManagement/pages/report_registration_page_time_per_project_detail_inc.php b/ProjectManagement/pages/report_registration_page_time_per_project_detail_inc.php new file mode 100644 index 0000000..23d93f3 --- /dev/null +++ b/ProjectManagement/pages/report_registration_page_time_per_project_detail_inc.php @@ -0,0 +1,158 @@ + + + + + + + + $t_project_data ) { + echo ''; + echo ''; + echo ''; + + + echo ''; + echo ''; + echo '
' . lang_get( 'username' ) . '
'; + echo ''; + foreach ( $t_work_types as $t_work_type_value => $t_work_type_label ) { + echo ''; + echo '
' . $t_work_type_label . '
'; + echo ''; + } + echo ''; + echo '
' . plugin_lang_get( 'total' ) . '
'; + echo ''; + echo '
'; + + if ( $t_can_view_cost ) { + echo ''; + foreach ( $t_work_types as $t_work_type_value => $t_work_type_label ) { + echo ''; + echo ''; + } + echo ''; + echo ''; + echo ''; + } + + foreach ( $t_project_data["users"] as $t_user_id => $t_data ) { + echo ''; + echo ''; + + + foreach ( $t_work_types as $t_work_type_value => $t_work_type_label ) { + echo ''; + if ( $t_can_view_cost ) { + echo ''; + } + } + + echo ''; + if ( $t_can_view_cost ) { + echo ''; + } + echo ''; + /* + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + } + echo '';*/ + } + echo ''; + echo ''; + + foreach ( $t_work_types as $t_work_type_value => $t_work_type_label ) { + echo ''; + if ( $t_can_view_cost ) { + echo ''; + } + } + echo ''; + if ( $t_can_view_cost ) { + echo ''; + } + /* + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + }*/ + echo ''; + } + ?> +
+ + +
'; + echo project_get_name ( $t_project_id ); + echo '
'; + echo '
' . plugin_lang_get( 'hours' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'cost' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'hours' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'cost' ) . '
'; + echo '
'; + print_user ( $t_user_id ); + echo ''; + if ( array_key_exists ( $t_work_type_value, $t_data["work_types"] ) ) { + echo minutes_to_time ( $t_data["work_types"][$t_work_type_value]["time"] ); + } + echo ''; + if ( array_key_exists ( $t_work_type_value, $t_data["work_types"] ) ) { + echo format ( $t_data["work_types"][$t_work_type_value]["cost"] ) . plugin_config_get ( 'currency_symbol' ); + } + echo ''; + echo minutes_to_time ( $t_data["total_work_types_time"] ); + echo ''; + echo format ( $t_data["total_work_types_cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
'; + echo format( $t_data["time"] ); + echo ''; + echo format( $t_data["hourly_rate"] ) . plugin_config_get ( 'currency_symbol' ); + echo ''; + echo format( $t_data["cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
' . plugin_lang_get( 'total' ) . ''; + if ( array_key_exists ( $t_work_type_value, $t_data["work_types"] ) ) { + echo minutes_to_time ( $t_project_data["work_types"][$t_work_type_value]["time"] ); + } + echo ''; + if ( array_key_exists ( $t_work_type_value, $t_data["work_types"] ) ) { + echo format ( $t_project_data["work_types"][$t_work_type_value]["cost"] ) . plugin_config_get ( 'currency_symbol' ); + } + echo ''; + echo minutes_to_time( $t_project_data["total_time"] ); + echo ''; + echo format( $t_project_data["total_cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo ''; + echo format( $t_project_data["total_time"] ); + echo ''; + echo format( $t_project_data["average_hourly_rate"] ) . plugin_config_get ( 'currency_symbol' ); + echo ''; + echo format( $t_project_data["total_cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
+ + + + + +
+ + - + +
+ diff --git a/ProjectManagement/pages/report_registration_page_time_per_project_inc.php b/ProjectManagement/pages/report_registration_page_time_per_project_inc.php new file mode 100644 index 0000000..43344b4 --- /dev/null +++ b/ProjectManagement/pages/report_registration_page_time_per_project_inc.php @@ -0,0 +1,89 @@ + + + + + + + + $t_project_data ) { + echo ''; + echo ''; + echo ''; + + + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + } + echo ''; + + foreach ( $t_project_data["users"] as $t_user_id => $t_data ) { + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + } + echo ''; + } + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + echo ''; + } + echo ''; + } + ?> +
+ + +
'; + echo project_get_name ( $t_project_id ); + echo '
'; + echo '
' . lang_get( 'username' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'hours' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'hourly_rate' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'cost' ) . '
'; + echo '
'; + print_user ( $t_user_id ); + echo ''; + echo minutes_to_time( $t_data["time"] ); + echo ''; + echo format( $t_data["hourly_rate"] ) . plugin_config_get ( 'currency_symbol' ); + echo ''; + echo format( $t_data["cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
' . plugin_lang_get( 'total' ) . ''; + echo minutes_to_time( $t_project_data["total_time"] ); + echo ''; + echo format( $t_project_data["average_hourly_rate"] ) . plugin_config_get ( 'currency_symbol' ); + echo ''; + echo format( $t_project_data["total_cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
+ + + + + +
+ + - + +
+ diff --git a/ProjectManagement/pages/report_registration_page_time_per_project_work_type_inc.php b/ProjectManagement/pages/report_registration_page_time_per_project_work_type_inc.php new file mode 100644 index 0000000..b6a4be9 --- /dev/null +++ b/ProjectManagement/pages/report_registration_page_time_per_project_work_type_inc.php @@ -0,0 +1,80 @@ + + + + + + + + $t_project_data ) { + echo ''; + echo ''; + echo ''; + + + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + } + echo ''; + + foreach ( $t_project_data["work_types"] as $t_work_type => $t_data ) { + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + } + echo ''; + } + echo ''; + echo ''; + echo ''; + if ( access_has_global_level( plugin_config_get( 'view_customer_payment_summary_threshold' ) ) ) { + echo ''; + } + echo ''; + } + ?> +
+ + +
'; + echo project_get_name ( $t_project_id ); + echo '
'; + echo '
' . plugin_lang_get( 'work_type' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'hours' ) . '
'; + echo '
'; + echo '
' . plugin_lang_get( 'cost' ) . '
'; + echo '
'; + echo print_plugin_enum_string_selected_value( 'work_types', $t_work_type ); + echo ''; + echo minutes_to_time( $t_data["time"] ); + echo ''; + echo format( $t_data["cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
' . plugin_lang_get( 'total' ) . ''; + echo minutes_to_time( $t_project_data["total_time"] ); + echo ''; + echo format( $t_project_data["total_cost"] ) . plugin_config_get ( 'currency_symbol' ); + echo '
+ + + + + +
+ + - + +
+ diff --git a/ProjectManagement/pages/report_registration_page_time_per_work_type_inc.php b/ProjectManagement/pages/report_registration_page_time_per_work_type_inc.php new file mode 100644 index 0000000..0993390 --- /dev/null +++ b/ProjectManagement/pages/report_registration_page_time_per_work_type_inc.php @@ -0,0 +1,59 @@ + + + + + + + + $t_work_type_label ) { + ?> + + + + + + $t_categories ) { + echo ""; + echo '"; + foreach ( $t_work_types as $t_work_type_value => $t_work_type_label ) { + echo ""; + } + echo ""; + } + ?> + +
+ + - + +
+
+
+
+
+
+
'; + print_user( $t_user ); + echo "" . minutes_to_time( @$t_categories[$t_work_type_value] ) . "" . minutes_to_time( @$t_categories[plugin_lang_get( 'total' )] ) . "
+ + + + + +
+ + - + +
+ diff --git a/ProjectManagement/pages/report_registration_page_time_registration_inc.php b/ProjectManagement/pages/report_registration_page_time_registration_inc.php new file mode 100644 index 0000000..b89c060 --- /dev/null +++ b/ProjectManagement/pages/report_registration_page_time_registration_inc.php @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + "; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + @$t_per_work_type[$row["user_id"]][$row["work_type"]] += $row["minutes"] / 60; + @$t_per_work_type[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + + @$t_per_project[$row["user_id"]][$row["project_id"]] += $row["minutes"] / 60; + @$t_per_project[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + + @$t_per_category[$row["user_id"]][$row["category_id"]] += $row["minutes"] / 60; + @$t_per_category[$row["user_id"]][plugin_lang_get( 'total' )] += $row["minutes"] / 60; + + @$t_total_cost += $row["minutes"] * $row["hourly_rate"] / 60; + } + + # Display a total cost line + echo ''; + echo ''; + echo ''; + ?> + +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
$t_username$t_book_date$t_project_name$t_category_name"; + print_bug_link( $row["bug_id"] ); + echo "$t_bug_summary$t_work_type$t_hours$t_hourly_rate$t_cost
' . plugin_lang_get( 'total_cost' ) . '' . format( $t_total_cost ) . '
+ + + + + + +
+ + +
+ diff --git a/ProjectManagement/pages/report_resource_progress_page.php b/ProjectManagement/pages/report_resource_progress_page.php index 3052fac..b83491a 100644 --- a/ProjectManagement/pages/report_resource_progress_page.php +++ b/ProjectManagement/pages/report_resource_progress_page.php @@ -32,7 +32,7 @@ if ( $t_project_without_versions ) { echo plugin_lang_get( 'project_without_versions' ); } else if ( $t_all_versions_selected ) { - echo plugin_lang_get( 'all_versions_selected' ); + echo plugin_lang_get( 'all_versions_selected' ) . 'pp'; } else if ( version_get_id( $f_target_version ) === false ) { echo plugin_lang_get( 'project_without_versions' ); } else { @@ -349,4 +349,4 @@ } echo ''; # The whole page must be a form to include the input elements from underlying sections -} +} \ No newline at end of file diff --git a/ProjectManagement/pages/target_overview_page.php b/ProjectManagement/pages/target_overview_page.php index 2cb932b..834f6b3 100644 --- a/ProjectManagement/pages/target_overview_page.php +++ b/ProjectManagement/pages/target_overview_page.php @@ -139,4 +139,4 @@ } ?> - + \ No newline at end of file diff --git a/ProjectManagement/pages/target_update.php b/ProjectManagement/pages/target_update.php index cf8a6a6..db5dcfb 100644 --- a/ProjectManagement/pages/target_update.php +++ b/ProjectManagement/pages/target_update.php @@ -18,24 +18,24 @@ !access_has_global_level( $t_work_type_thresholds[$t_work_type] ) ) continue; # Ignore otherwise - $f_data[$t_bug_id][$t_work_type]["target_date"] = - strtotime_safe( gpc_get_string( $t_bug_id . '_target_date_' . $t_work_type, - date( config_get( 'short_date_format' ) ), null ), true ); - $f_data[$t_bug_id][$t_work_type]["owner_id"] = - gpc_get_int( $t_bug_id . '_owner_id_' . $t_work_type, -1 ); - - $t_completed_date_as_string = gpc_get_string( $t_bug_id . '_completed_date_' . $t_work_type, - date( config_get( 'short_date_format' ) ), null ); - if ( !is_null( $t_completed_date_as_string ) ) { - $f_data[$t_bug_id][$t_work_type]["completed_date"] = - strtotime_safe( $t_completed_date_as_string, true ); - } - - # Check for errors - if ( !empty( $f_data[$t_bug_id][$t_work_type]["target_date"] ) && - $f_data[$t_bug_id][$t_work_type]["owner_id"] == -1 ) { - error_parameters( $t_work_types[$t_work_type] ); - trigger_error( ERROR_CUSTOM_FIELD_INVALID_VALUE, E_USER_ERROR ); + $t_target_date_as_string = gpc_get_string( $t_bug_id . '_target_date_' . $t_work_type, null ); + $t_completed_date_as_string = gpc_get_string( $t_bug_id . '_completed_date_' . $t_work_type, null ); + + # Check if input fields exists + if ($t_target_date_as_string != null || $t_completed_date_as_string != null ) { + $f_data[$t_bug_id][$t_work_type]["target_date"] = strtotime_safe( $t_target_date_as_string, true ); + $f_data[$t_bug_id][$t_work_type]["owner_id"] = gpc_get_int( $t_bug_id . '_owner_id_' . $t_work_type, -1 ); + + if ( !is_null( $t_completed_date_as_string ) ) { + $f_data[$t_bug_id][$t_work_type]["completed_date"] = strtotime_safe( $t_completed_date_as_string, true ); + } + + # Check for errors + if ( !empty( $f_data[$t_bug_id][$t_work_type]["target_date"] ) && + $f_data[$t_bug_id][$t_work_type]["owner_id"] == -1 ) { + error_parameters( $t_work_types[$t_work_type] ); + trigger_error( plugin_lang_get( 'date_error' ), E_USER_ERROR ); + } } } } @@ -43,8 +43,7 @@ foreach ( $f_data as $t_bug_id => $t_work_type_data ) { foreach ( $t_work_type_data as $t_work_type => $t_data ) { if ( !empty( $t_data["target_date"] ) ) { - target_update( $t_bug_id, $t_work_type, - $t_data["owner_id"], $t_data["target_date"], $t_data["completed_date"] ); + target_update( $t_bug_id, $t_work_type, $t_data["owner_id"], $t_data["target_date"], $t_data["completed_date"] ); } } } diff --git a/ProjectManagement/pages/time_registration_delete.php b/ProjectManagement/pages/time_registration_delete.php new file mode 100644 index 0000000..207df40 --- /dev/null +++ b/ProjectManagement/pages/time_registration_delete.php @@ -0,0 +1,30 @@ + $t_work_type_label ) { - error_parameters( $t_work_type_label ); - $f_data[$t_bug_id][PLUGIN_PM_EST][$t_work_type_code] = - time_to_minutes( - gpc_get_string( 'change_' . $t_bug_id . '_' . PLUGIN_PM_EST . - ( $f_redirect_page == 'time_registration_page' ? '' : '_' . $t_work_type_code ), null ), false ); - $f_data[$t_bug_id][PLUGIN_PM_DONE][$t_work_type_code] = - time_to_minutes( - gpc_get_string( 'add_' . $t_bug_id . '_' . PLUGIN_PM_DONE . - ( $f_redirect_page == 'time_registration_page' ? '' : '_' . $t_work_type_code ), null ) ); - $f_data[$t_bug_id][PLUGIN_PM_TODO][$t_work_type_code] = - time_to_minutes( - gpc_get_string( 'change_' . $t_bug_id . '_' . PLUGIN_PM_TODO . - ( $f_redirect_page == 'time_registration_page' ? '' : '_' . $t_work_type_code ), null ), false ); - $f_data[$t_bug_id]['clear_todo'][$t_work_type_code] = - gpc_get_bool( 'clear_' . $t_bug_id . '_' . PLUGIN_PM_TODO . '_' . $t_work_type_code, null ); + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 ) { + foreach ( $t_work_types_to_check as $t_work_type_code => $t_work_type_label ) { + error_parameters( $t_work_type_label ); + $f_data[$t_bug_id][PLUGIN_PM_EST][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'change_' . $t_bug_id . '_' . PLUGIN_PM_EST, null ), false ); + $f_data[$t_bug_id][PLUGIN_PM_DONE][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'add_' . $t_bug_id . '_' . PLUGIN_PM_DONE, null ) ); + $f_data[$t_bug_id][PLUGIN_PM_TODO][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'change_' . $t_bug_id . '_' . PLUGIN_PM_TODO, null ), false ); + $f_data[$t_bug_id][PLUGIN_PM_COMPLETED][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'add_' . $t_bug_id . '_' . PLUGIN_PM_COMPLETED, null ), false ); + $f_data[$t_bug_id]['clear_todo'][$t_work_type_code] = + gpc_get_bool( 'clear_' . $t_bug_id . '_' . PLUGIN_PM_TODO, null ); + } + } + else { + foreach ( $t_work_types_to_check as $t_work_type_code => $t_work_type_label ) { + error_parameters( $t_work_type_label ); + $f_data[$t_bug_id][PLUGIN_PM_EST][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'change_' . $t_bug_id . '_' . PLUGIN_PM_EST . + ( $f_redirect_page == 'time_registration_page' ? '' : '_' . $t_work_type_code ), null ), false ); + $f_data[$t_bug_id][PLUGIN_PM_DONE][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'add_' . $t_bug_id . '_' . PLUGIN_PM_DONE . + ( $f_redirect_page == 'time_registration_page' ? '' : '_' . $t_work_type_code ), null ) ); + $f_data[$t_bug_id][PLUGIN_PM_TODO][$t_work_type_code] = + time_to_minutes( + gpc_get_string( 'change_' . $t_bug_id . '_' . PLUGIN_PM_TODO . + ( $f_redirect_page == 'time_registration_page' ? '' : '_' . $t_work_type_code ), null ), false ); + $f_data[$t_bug_id]['clear_todo'][$t_work_type_code] = + gpc_get_bool( 'clear_' . $t_bug_id . '_' . PLUGIN_PM_TODO . '_' . $t_work_type_code, null ); + } } } foreach ( $f_data as $t_bug_id => $t_bug_data ) { - if ( count( $t_bug_data[PLUGIN_PM_EST] ) > 0 ) { # Handle est: insert or update foreach ( $t_bug_data[PLUGIN_PM_EST] as $t_work_type => $t_minutes ) { @@ -61,6 +90,7 @@ $t_row = db_fetch_array( $t_result ); $t_old_value = ( $t_row == false ? null : round( $t_row["minutes"] / 60, 2 ) ); $t_new_value = round( $t_minutes / 60, 2 ); + $t_user_id = auth_get_current_user_id(); # Security repeated: check whether estimations may be modified! if ( !access_has_bug_level( plugin_config_get( 'edit_estimates_threshold' ), $t_bug_id ) ) { @@ -69,49 +99,145 @@ } } - set_work( $t_bug_id, $t_work_type, PLUGIN_PM_EST, $t_minutes, $f_book_date, Action::INSERT_OR_UPDATE ); + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_EST, $t_minutes, $f_book_date, Action::INSERT, $f_time_info ); //Action::INSERT_OR_UPDATE ); + + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 ) { + target_update_target_date( $t_bug_id, $t_work_type, $t_user_id, $f_book_date ); + } - history_log_event_direct( $t_bug_id, plugin_lang_get( 'est' ) . " ($t_work_types[$t_work_type])", + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'est' ) ), $t_old_value, $t_new_value ); } } } - if ( count( $t_bug_data[PLUGIN_PM_DONE] ) > 0 ) { # Handle done: insert foreach ( $t_bug_data[PLUGIN_PM_DONE] as $t_work_type => $t_minutes ) { - if ( isset( $t_minutes ) ) { + $t_minutes_type = PLUGIN_PM_TODO; + $t_query = "SELECT minutes + FROM $t_table + WHERE bug_id = $t_bug_id + AND work_type = $t_work_type + AND minutes_type = $t_minutes_type + ORDER BY timestamp DESC LIMIT 1"; + $t_result = db_query_bound( $t_query ); + $t_row_todo = db_fetch_array( $t_result ); + $t_old_todo = ( $t_row_todo == false ? null : $t_row_todo["minutes"] ); + $t_old_todo = ( $t_old_todo === null || $t_old_todo <= 0 ? null : $t_old_todo ); + $t_old_todo_hours = ( $t_old_todo !== null && $t_old_todo > 0 ? round( $t_old_todo / 60, 2 ) : $t_old_todo ); + $t_new_todo = ( $t_old_todo === null ? null : $t_old_todo - $t_minutes ); + $t_new_todo = ( $t_new_todo !== null && $t_new_todo < 0 ? 0 : $t_new_todo ); + $t_new_todo_hours = ( $t_new_todo !== null && $t_new_todo > 0 ? round( $t_new_todo / 60, 2 ) : $t_new_todo ); + # Get the old value $t_minutes_type = PLUGIN_PM_DONE; $t_query = "SELECT sum( minutes ) as minutes - FROM $t_table - WHERE bug_id = $t_bug_id - AND work_type = $t_work_type - AND minutes_type = $t_minutes_type"; + FROM $t_table + WHERE bug_id = $t_bug_id + AND work_type = $t_work_type + AND minutes_type = $t_minutes_type"; $t_result = db_query_bound( $t_query ); $t_row = db_fetch_array( $t_result ); $t_old_value = ( $t_row == false ? null : round( $t_row["minutes"] / 60, 2 ) ); $t_hours = round( $t_minutes / 60, 2 ); $t_new_value = $t_old_value + $t_hours; + $t_user_id = auth_get_current_user_id(); # Extra check: negative totals not possible! if ( $t_new_value < 0 ) { error_parameters( $t_work_types[$t_work_type] ); - trigger_error( ERROR_CUSTOM_FIELD_INVALID_VALUE, E_USER_ERROR ); + trigger_error( plugin_lang_get( 'time_error' ), E_USER_ERROR ); } - set_work( $t_bug_id, $t_work_type, PLUGIN_PM_DONE, $t_minutes, $f_book_date, Action::INSERT ); - + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_DONE, $t_minutes, $f_book_date, Action::INSERT, $f_time_info ); + + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 && !( $t_new_todo === null ) ) { + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_TODO, $t_new_todo, $f_book_date, Action::INSERT ); + } + if ( $t_hours < 0 ) { $t_sign = ' - '; } else { $t_sign = ' + '; } $t_change = $t_old_value . $t_sign . abs( $t_hours ); - history_log_event_direct( $t_bug_id, plugin_lang_get( 'done' ) . " ($t_work_types[$t_work_type])", + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'done' ) ), $t_change, $t_new_value ); + + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 && !( $t_new_todo === null ) ) { + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'todo' ) ), + $t_old_todo_hours, $t_new_todo_hours ); + } + } + } + } + + if ( count( $t_bug_data[PLUGIN_PM_COMPLETED] ) > 0 ) { + # Handle done: insert + foreach ( $t_bug_data[PLUGIN_PM_COMPLETED] as $t_work_type => $t_minutes ) { + if ( isset( $t_minutes ) ) { + + $t_minutes_type = PLUGIN_PM_TODO; + $t_query = "SELECT minutes + FROM $t_table + WHERE bug_id = $t_bug_id + AND work_type = $t_work_type + AND minutes_type = $t_minutes_type + ORDER BY timestamp DESC LIMIT 1"; + $t_result = db_query_bound( $t_query ); + $t_row_todo = db_fetch_array( $t_result ); + $t_old_todo = ( $t_row_todo == false ? null : $t_row_todo["minutes"] ); + $t_old_todo = ( $t_old_todo === null || $t_old_todo <= 0 ? null : $t_old_todo ); + $t_old_todo_hours = ( $t_old_todo !== null && $t_old_todo > 0 ? round( $t_old_todo / 60, 2 ) : $t_old_todo ); + $t_new_todo = ( $t_old_todo === null ? null : 0 ); + $t_new_todo_hours = ( $t_new_todo === null ? null : 0 ); + + # Get the old value + $t_minutes_type = PLUGIN_PM_DONE; + $t_query = "SELECT sum( minutes ) as minutes + FROM $t_table + WHERE bug_id = $t_bug_id + AND work_type = $t_work_type + AND minutes_type = $t_minutes_type"; + $t_result = db_query_bound( $t_query ); + $t_row = db_fetch_array( $t_result ); + $t_old_value = ( $t_row == false ? null : round( $t_row["minutes"] / 60, 2 ) ); + $t_hours = round( $t_minutes / 60, 2 ); + $t_new_value = $t_old_value + $t_hours; + $t_user_id = auth_get_current_user_id(); + + # Extra check: negative totals not possible! + if ( $t_new_value < 0 ) { + error_parameters( $t_work_types[$t_work_type] ); + trigger_error( plugin_lang_get( 'time_error' ), E_USER_ERROR ); + } + + if ($t_minutes > 0) { + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_DONE, $t_minutes, $f_book_date, Action::INSERT, $f_time_info ); + + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 && !( $t_new_todo === null ) ) { + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_TODO, $t_new_todo, $f_book_date, Action::INSERT ); + } + + if ( $t_hours < 0 ) { + $t_sign = ' - '; + } else { + $t_sign = ' + '; + } + $t_change = $t_old_value . $t_sign . abs( $t_hours ); + + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'done' ) ), + $t_change, $t_new_value ); + + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 && !( $t_new_todo === null ) ) { + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'todo' ) ), + $t_old_todo_hours, $t_new_todo_hours ); + } + } + + target_update_completed_date( $t_bug_id, $t_work_type, $t_user_id, $f_book_date ); } } } @@ -132,10 +258,15 @@ $t_row = db_fetch_array( $t_result ); $t_old_value = ( $t_row == false ? null : round( $t_row["minutes"] / 60, 2 ) ); $t_new_value = round( $t_minutes / 60, 2 ); + $t_user_id = auth_get_current_user_id(); - set_work( $t_bug_id, $t_work_type, PLUGIN_PM_TODO, $t_minutes, $f_book_date, Action::INSERT_OR_UPDATE ); + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_TODO, $t_minutes, $f_book_date, Action::INSERT, $f_time_info ); //Action::INSERT_OR_UPDATE ); + + if ( $t_view_mode == PLUGIN_PM_BUG_VIEW_MODE_2 ) { + target_update_completed_date( $t_bug_id, $t_work_type, $t_user_id, $f_book_date ); + } - history_log_event_direct( $t_bug_id, plugin_lang_get( 'todo' ) . " ($t_work_types[$t_work_type])", + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'todo' ) ), $t_old_value, $t_new_value ); } } @@ -158,9 +289,9 @@ $t_old_value = ( $t_row == false ? null : round( $t_row["minutes"] / 60, 2 ) ); $t_new_value = plugin_lang_get( 'clear' ); - set_work( $t_bug_id, $t_work_type, PLUGIN_PM_TODO, $t_minutes, $f_book_date, Action::DELETE ); + set_work( $t_bug_id, $t_work_type, PLUGIN_PM_TODO, $t_minutes, $f_book_date, Action::DELETE, $f_time_info ); - history_log_event_direct( $t_bug_id, plugin_lang_get( 'todo' ) . " ($t_work_types[$t_work_type])", + history_log_event_direct( $t_bug_id, sprintf( plugin_lang_get( 'history_added' ), $t_work_types[$t_work_type], plugin_lang_get( 'todo' ) ), $t_old_value, $t_new_value ); } } @@ -175,5 +306,3 @@ } else { print_successful_redirect( plugin_page( $f_redirect_page, true ) ); } - -?> \ No newline at end of file From bf2da18f27517ef504d3e1a8594d4d41c919fe7d Mon Sep 17 00:00:00 2001 From: Daniel Tamajon Date: Sat, 20 Jul 2013 18:04:01 +0200 Subject: [PATCH 21/21] Language translations corrected --- ProjectManagement/lang/strings_english.txt | 4 ---- ProjectManagement/lang/strings_spanish.txt | 4 ---- 2 files changed, 8 deletions(-) diff --git a/ProjectManagement/lang/strings_english.txt b/ProjectManagement/lang/strings_english.txt index c21af29..c93294b 100644 --- a/ProjectManagement/lang/strings_english.txt +++ b/ProjectManagement/lang/strings_english.txt @@ -1,8 +1,4 @@