From e16926f7fe6d661a32533b6ec902ad04556fbd5d Mon Sep 17 00:00:00 2001 From: David Hayes Date: Tue, 24 Sep 2019 11:17:44 -0500 Subject: [PATCH 1/4] Add ability to edit cusotm data on volunteer projects on esiting volunteer projects --- CRM/Volunteer/Form/CustomData.php | 147 +++++++++++++++ ang/volunteer.js | 84 +++++++++ ang/volunteer/CustomData.html | 9 + ang/volunteer/Project.html | 8 +- ang/volunteer/Project.js | 194 +++++++++++++------- templates/CRM/Volunteer/Form/CustomData.tpl | 33 ++++ xml/Menu/Volunteer.xml | 5 + 7 files changed, 408 insertions(+), 72 deletions(-) create mode 100644 CRM/Volunteer/Form/CustomData.php create mode 100644 ang/volunteer/CustomData.html create mode 100644 templates/CRM/Volunteer/Form/CustomData.tpl diff --git a/CRM/Volunteer/Form/CustomData.php b/CRM/Volunteer/Form/CustomData.php new file mode 100644 index 00000000..4030d189 --- /dev/null +++ b/CRM/Volunteer/Form/CustomData.php @@ -0,0 +1,147 @@ +_entityName = CRM_Utils_Request::retrieve('entityName', 'String', $this, TRUE); + $this->_entityID = CRM_Utils_Request::retrieve('entityID', 'Positive', $this, TRUE); + $this->_groupID = CRM_Utils_Request::retrieve('groupID', 'Positive', $this, FALSE); + // $this->_subTypeID = CRM_Utils_Request::retrieve('subType', 'Positive', $this, TRUE); + + if (!in_array($this->_entityName, ['VolunteerProject'])) { + $this->_entityName = 'VolunteerProject'; + } + + $groupTree = CRM_Core_BAO_CustomGroup::getTree($this->_entityName, + NULL, + $this->_entityID, + $this->_groupID, + NULL // $this->_subTypeID + ); + // simplified formatted groupTree + $groupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree, 1, $this); + // Array contains only one item + foreach ($groupTree as $groupValues) { + $this->_customTitle = $groupValues['title']; + CRM_Utils_System::setTitle(ts('Edit %1', [1 => $groupValues['title']])); + } + + $this->_defaults = []; + CRM_Core_BAO_CustomGroup::setDefaults($groupTree, $this->_defaults); + $this->setDefaults($this->_defaults); + + CRM_Core_BAO_CustomGroup::buildQuickForm($this, $groupTree); + + //need to assign custom data type and subtype to the template + $this->assign('entityName', $this->_entityName); + $this->assign('entityID', $this->_entityID); + $this->assign('groupID', $this->_groupID); + // $this->assign('subType', $this->_subTypeID); + } + + /** + * Build the form object. + */ + public function buildQuickForm() { + // make this form an upload since we dont know if the custom data injected dynamically + // is of type file etc + $this->addButtons([ + [ + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ], + [ + 'type' => 'cancel', + 'name' => ts('Cancel'), + ], + ]); + } + + /** + * Process the user submitted custom data values. + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + + $transaction = new CRM_Core_Transaction(); + + $entityTable = 'civicrm_volunteer_project'; + + CRM_Core_BAO_CustomValueTable::postProcess($params, + $entityTable, + $this->_entityID, + $this->_entityName + ); + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/vol', "#/volunteer/manage/{$this->_entityID}")); + + $transaction->commit(); + } + +} diff --git a/ang/volunteer.js b/ang/volunteer.js index 8f8ff5be..70c25674 100644 --- a/ang/volunteer.js +++ b/ang/volunteer.js @@ -164,6 +164,90 @@ }; }) + // // Custom Data + // .directive('volunteerCustomData', function($timeout) { + // return { + // restrict: 'A', + // link: function (scope, elem, attrs) { + // var form; + // console.log( + // scope, + // scope.item, + // scope.project, + // 'blah2', + // // elem, + // // attrs, + // ); + + // function close() { + // form.remove(); + // elem.show(); + // form = null; + // } + + // if (!form) { + // var url = CRM.url('civicrm/volunteer/cd/edit', { + // action: 'update', + // reset: 1, + // entityName: 'VolunteerProject', + // entityID: scope.project.id, + // // groupID: scope.customGroup.id, + // // subType: scope.item.case_type_id, + // // civicase_reload: scope.caseGetParams() + // }); + // console.log(url); + // form = $('
').html(elem.hide().html()); + // form.insertAfter(elem) + // // .on('click', '.cancel', close) + // // .on('crmLoad', function() { + // // // Workaround bug where href="#" changes the angular route + // // $('a.crm-clear-link', form).removeAttr('href'); + // // }) + // // .on('crmFormSuccess', function(e, data) { + // // scope.$apply(function() { + // // scope.pushCaseData(data.civicase_reload[0]); + // // close(); + // // }); + // // }); + // CRM.loadForm(url, {target: form, dialog: true}); + // } + // } + // }; + // }) + + // Editable custom data blocks + .directive('volunteerEditCustomData', function($timeout) { + return { + restrict: 'A', + link: function (scope, elem, attrs) { + elem + .addClass('crm-editable-enabled') + .on('click', function(e) { + var url = CRM.url('civicrm/volunteer/cd/edit', { + action: 'update', + reset: 1, + entityName: 'VolunteerProject', + entityID: scope.project.id, + groupID: scope.customGroup.id, + // subType: scope.item.case_type_id, + }); + + var settings = { + dialog: { + width: "85%", + height:"80%", + }, + }; + CRM + .loadForm(url, settings) + .on('crmFormSuccess', function(e, data) { + console.log('success', data); + scope.refreshCustomData(); + }); + }); + } + }; + }) /** * This is a service for loading the backbone-based volunteer UIs (and their diff --git a/ang/volunteer/CustomData.html b/ang/volunteer/CustomData.html new file mode 100644 index 00000000..97f04c80 --- /dev/null +++ b/ang/volunteer/CustomData.html @@ -0,0 +1,9 @@ +
+ {{ ::customGroup.title }} +
+
+ {{ field.label }}: + {{ field.value.display }} +
+
+
\ No newline at end of file diff --git a/ang/volunteer/Project.html b/ang/volunteer/Project.html index ffefa74b..0eda3d18 100644 --- a/ang/volunteer/Project.html +++ b/ang/volunteer/Project.html @@ -107,10 +107,16 @@ -
+ + +
+
+
+
+
diff --git a/ang/volunteer/Project.js b/ang/volunteer/Project.js index 27ff6e75..fc96fed3 100644 --- a/ang/volunteer/Project.js +++ b/ang/volunteer/Project.js @@ -1,74 +1,93 @@ (function(angular, $, _) { + function processCustomValueTree(customData) { + _.each(customData, function(customGroup, index) { + customGroup.collapse_display = customGroup.collapse_display === '1'; + }); + return customData; + } + angular.module('volunteer').config(function($routeProvider) { - $routeProvider.when('/volunteer/manage/:projectId', { - controller: 'VolunteerProject', - templateUrl: '~/volunteer/Project.html', - resolve: { - countries: function(crmApi) { - return crmApi('VolunteerUtil', 'getcountries', {}).then(function(result) { - return result.values; - }); - }, - project: function(crmApi, $route) { - if ($route.current.params.projectId == 0) { - return { - id: 0 - }; - } else { - return crmApi('VolunteerProject', 'getsingle', { - id: $route.current.params.projectId - }).then( - // success - null, - // error - function () { - CRM.alert( - ts('No volunteer project exists with an ID of %1', {1: $route.current.params.projectId}), - ts('Not Found'), - 'error' - ); - } - ); - } - }, - supporting_data: function(crmApi) { - return crmApi('VolunteerUtil', 'getsupportingdata', { - controller: 'VolunteerProject' - }); - }, - campaigns: function(crmApi) { - return crmApi('VolunteerUtil', 'getcampaigns').then(function(data) { - return data.values; - }); - }, - relationship_data: function(crmApi, $route) { - var params = { - "sequential": 1, - "project_id": $route.current.params.projectId + $routeProvider.when('/volunteer/manage/:projectId', { + controller: 'VolunteerProject', + templateUrl: '~/volunteer/Project.html', + resolve: { + countries: function(crmApi) { + return crmApi('VolunteerUtil', 'getcountries', {}).then(function(result) { + return result.values; + }); + }, + project: function(crmApi, $route) { + if ($route.current.params.projectId == 0) { + return { + id: 0 }; - return crmApi('VolunteerProjectContact', 'get', params).then(function(result) { - var relationships = {}; - $(result.values).each(function (index, vpc) { - if (!relationships.hasOwnProperty(vpc.relationship_type_id)) { - relationships[vpc.relationship_type_id] = []; + } else { + return crmApi('VolunteerProject', 'getsingle', { + id: $route.current.params.projectId, + 'api.CustomValue.gettree': { + sequential: 1, + entity_id: "$value.id", + entity_type: 'VolunteerProject', + return: ['custom_group.id', 'custom_group.name', 'custom_group.title', 'custom_group.collapse_display', 'custom_field.name', 'custom_field.label', 'custom_value.display'] + }, + }).then( + // success + function (result) { + if(!result.is_error) { + result.customData = processCustomValueTree(result['api.CustomValue.gettree'].values || []); + delete result['api.CustomValue.gettree']; + return result; + } else { + CRM.alert(result.error); } - relationships[vpc.relationship_type_id].push(vpc.contact_id); - }); - return relationships; - }); - }, - location_blocks: function(crmApi) { - return crmApi('VolunteerProject', 'locations', {}); - }, - profile_status: function(crmProfiles) { - return crmProfiles.load(); + }, + // error + function () { + CRM.alert( + ts('No volunteer project exists with an ID of %1', {1: $route.current.params.projectId}), + ts('Not Found'), + 'error' + ); + } + ); } + }, + supporting_data: function(crmApi) { + return crmApi('VolunteerUtil', 'getsupportingdata', { + controller: 'VolunteerProject' + }); + }, + campaigns: function(crmApi) { + return crmApi('VolunteerUtil', 'getcampaigns').then(function(data) { + return data.values; + }); + }, + relationship_data: function(crmApi, $route) { + var params = { + "sequential": 1, + "project_id": $route.current.params.projectId + }; + return crmApi('VolunteerProjectContact', 'get', params).then(function(result) { + var relationships = {}; + $(result.values).each(function (index, vpc) { + if (!relationships.hasOwnProperty(vpc.relationship_type_id)) { + relationships[vpc.relationship_type_id] = []; + } + relationships[vpc.relationship_type_id].push(vpc.contact_id); + }); + return relationships; + }); + }, + location_blocks: function(crmApi) { + return crmApi('VolunteerProject', 'locations', {}); + }, + profile_status: function(crmProfiles) { + return crmProfiles.load(); } - }); - } - ); - + } + }); + }); angular.module('volunteer').controller('VolunteerProject', function($scope, $sce, $location, $q, $route, crmApi, crmUiAlert, crmUiHelp, countries, project, profile_status, campaigns, relationship_data, supporting_data, location_blocks, volBackbone) { @@ -245,6 +264,39 @@ } }, true); + /** + * Populates project customdata + * + * Makes an API request. + */ + $scope.refreshCustomData = function() { + if (!!$scope.project.id) { + crmApi('CustomValue', 'gettree', { + sequential: 1, + entity_id: $scope.project.id, + entity_type: 'VolunteerProject', + return: ['custom_group.id', 'custom_group.name', 'custom_group.title', 'custom_group.collapse_display', 'custom_field.name', 'custom_field.label', 'custom_value.display'] + }).then( + // success + function (result) { + if(!result.is_error) { + $scope.project.customData = processCustomValueTree(result.values || []); + } else { + CRM.alert(result.error); + } + }, + // error + function () { + CRM.alert( + ts('No volunteer project custom data exists with an ID of %1', {1: $scope.project.id}), + ts('Not Found'), + 'error' + ); + } + ); + } + }; + $scope.addProfile = function() { $scope.profiles.push({ "entity_table": "civicrm_volunteer_project", @@ -324,13 +376,13 @@ return valid; }; - /** - * Helper validation function. - * - * Ensures that a value is set for each required project relationship. - * - * @returns {Boolean} - */ + /** + * Helper validation function. + * + * Ensures that a value is set for each required project relationship. + * + * @returns {Boolean} + */ validateRelationships = function() { var isValid = true; diff --git a/templates/CRM/Volunteer/Form/CustomData.tpl b/templates/CRM/Volunteer/Form/CustomData.tpl new file mode 100644 index 00000000..a7e5465e --- /dev/null +++ b/templates/CRM/Volunteer/Form/CustomData.tpl @@ -0,0 +1,33 @@ +{* + +--------------------------------------------------------------------+ + | CiviCRM version 5 | + +--------------------------------------------------------------------+ + | Copyright CiviCRM LLC (c) 2004-2019 | + +--------------------------------------------------------------------+ + | This file is a part of CiviCRM. | + | | + | CiviCRM is free software; you can copy, modify, and distribute it | + | under the terms of the GNU Affero General Public License | + | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | + | | + | CiviCRM is distributed in the hope that it will be useful, but | + | WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | + | See the GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public | + | License and the CiviCRM Licensing Exception along | + | with this program; if not, contact CiviCRM LLC | + | at info[AT]civicrm[DOT]org. If you have questions about the | + | GNU Affero General Public License or the licensing of CiviCRM, | + | see the CiviCRM license FAQ at http://civicrm.org/licensing | + +--------------------------------------------------------------------+ +*} +
+ {if $groupID>0} + {include file="CRM/Custom/Form/CustomData.tpl" skipTitle=1} + {else} + {include file="CRM/Custom/Form/CustomData.tpl"} + {/if} +
{include file="CRM/common/formButtons.tpl" location="bottom"}
+
diff --git a/xml/Menu/Volunteer.xml b/xml/Menu/Volunteer.xml index 83c0bf2b..c94c8c63 100644 --- a/xml/Menu/Volunteer.xml +++ b/xml/Menu/Volunteer.xml @@ -88,6 +88,11 @@ 1 true + + civicrm/volunteer/cd/edit + Volunteer Custom Set + CRM_Volunteer_Form_CustomData + civicrm/volunteer/roster CRM_Volunteer_Page_Roster From 88141c32f41c8ac9461ffa21e82cb57299386920 Mon Sep 17 00:00:00 2001 From: David Hayes Date: Tue, 24 Sep 2019 14:08:29 -0500 Subject: [PATCH 2/4] remove console .log --- ang/volunteer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ang/volunteer.js b/ang/volunteer.js index 70c25674..f7d001ac 100644 --- a/ang/volunteer.js +++ b/ang/volunteer.js @@ -241,7 +241,6 @@ CRM .loadForm(url, settings) .on('crmFormSuccess', function(e, data) { - console.log('success', data); scope.refreshCustomData(); }); }); From 734b8505a99d09727c613bc629d46850f2f58388 Mon Sep 17 00:00:00 2001 From: David Hayes Date: Tue, 24 Sep 2019 15:21:51 -0500 Subject: [PATCH 3/4] remove custom data inline edit --- ang/volunteer.js | 51 -------------------------------------- ang/volunteer/Project.html | 1 - 2 files changed, 52 deletions(-) diff --git a/ang/volunteer.js b/ang/volunteer.js index f7d001ac..96d4b99b 100644 --- a/ang/volunteer.js +++ b/ang/volunteer.js @@ -164,57 +164,6 @@ }; }) - // // Custom Data - // .directive('volunteerCustomData', function($timeout) { - // return { - // restrict: 'A', - // link: function (scope, elem, attrs) { - // var form; - // console.log( - // scope, - // scope.item, - // scope.project, - // 'blah2', - // // elem, - // // attrs, - // ); - - // function close() { - // form.remove(); - // elem.show(); - // form = null; - // } - - // if (!form) { - // var url = CRM.url('civicrm/volunteer/cd/edit', { - // action: 'update', - // reset: 1, - // entityName: 'VolunteerProject', - // entityID: scope.project.id, - // // groupID: scope.customGroup.id, - // // subType: scope.item.case_type_id, - // // civicase_reload: scope.caseGetParams() - // }); - // console.log(url); - // form = $('
').html(elem.hide().html()); - // form.insertAfter(elem) - // // .on('click', '.cancel', close) - // // .on('crmLoad', function() { - // // // Workaround bug where href="#" changes the angular route - // // $('a.crm-clear-link', form).removeAttr('href'); - // // }) - // // .on('crmFormSuccess', function(e, data) { - // // scope.$apply(function() { - // // scope.pushCaseData(data.civicase_reload[0]); - // // close(); - // // }); - // // }); - // CRM.loadForm(url, {target: form, dialog: true}); - // } - // } - // }; - // }) - // Editable custom data blocks .directive('volunteerEditCustomData', function($timeout) { return { diff --git a/ang/volunteer/Project.html b/ang/volunteer/Project.html index 0eda3d18..c27d60fc 100644 --- a/ang/volunteer/Project.html +++ b/ang/volunteer/Project.html @@ -111,7 +111,6 @@ -

From 61b0b19cc6645eedff28bbb330f141646b0fe48a Mon Sep 17 00:00:00 2001 From: David Hayes Date: Tue, 24 Sep 2019 15:47:14 -0500 Subject: [PATCH 4/4] add export fields and formatting --- CRM/Volunteer/BAO/Project.php | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/CRM/Volunteer/BAO/Project.php b/CRM/Volunteer/BAO/Project.php index 000215de..e780dc1c 100644 --- a/CRM/Volunteer/BAO/Project.php +++ b/CRM/Volunteer/BAO/Project.php @@ -35,6 +35,13 @@ class CRM_Volunteer_BAO_Project extends CRM_Volunteer_DAO_Project { + /** + * Static field for all the case information that we can potentially export. + * + * @var array + */ + public static $_exportableFields = NULL; + /** * Array of attributes on the related entity, translated to a common vocabulary. * @@ -362,7 +369,7 @@ public static function create(array $params) { * * @see CRM_Volunteer_BAO_Assignment::setActivityDefaults() */ - public function updateAssociatedActivities () { + public function updateAssociatedActivities() { $activities = CRM_Volunteer_BAO_Assignment::retrieve(array( 'project_id' => $this->id, )); @@ -688,7 +695,7 @@ public function getEntityAttributes() { * @param int $project_id * @return mixed Integer on success, else NULL */ - public static function getFlexibleNeedID ($project_id) { + public static function getFlexibleNeedID($project_id) { $result = NULL; if (is_int($project_id) || ctype_digit($project_id)) { @@ -833,8 +840,7 @@ public static function getDefaultProjectContacts() { * * @var array */ - public static function getProjectProfileAudienceTypes() - { + public static function getProjectProfileAudienceTypes() { return array( "primary" => array( "type" => "primary", @@ -853,6 +859,29 @@ public static function getProjectProfileAudienceTypes() ), ); } + + /** + * Combine all the exportable fields from the lower levels object. + * + * @return array + * array of exportable Fields + */ + public static function &exportableFields() { + if (!self::$_exportableFields) { + if (!self::$_exportableFields) { + self::$_exportableFields = array(); + } + + $fields = CRM_Volunteer_DAO_Project::export(); + + // add custom data for volunteer projects + $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('VolunteerProject')); + + self::$_exportableFields = $fields; + } + return self::$_exportableFields; + } + /** * Sets and returns the start date of the entity associated with this Project * @@ -957,7 +986,6 @@ private function _get_roles() { return $this->roles; } - /** * Sets and returns $this->open_needs. Delegate of __get(). *