From 6a4880350680e1e4d20e5c8a622a791f926ca750 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 28 Feb 2013 21:49:20 -0800 Subject: [PATCH] Import from SVN (r45945, r596) --- CRM/ACL/API.php | 207 + CRM/ACL/BAO/ACL.php | 934 + CRM/ACL/BAO/Cache.php | 148 + CRM/ACL/BAO/EntityRole.php | 93 + CRM/ACL/Form/ACL.php | 312 + CRM/ACL/Form/ACLBasic.php | 169 + CRM/ACL/Form/EntityRole.php | 101 + CRM/ACL/Form/WordPress/Permissions.php | 185 + CRM/ACL/Page/ACL.php | 275 + CRM/ACL/Page/ACLBasic.php | 212 + CRM/ACL/Page/EntityRole.php | 220 + CRM/Activity/BAO/Activity.php | 2639 + CRM/Activity/BAO/ActivityAssignment.php | 151 + CRM/Activity/BAO/ActivityTarget.php | 127 + CRM/Activity/BAO/ICalendar.php | 133 + CRM/Activity/BAO/Query.php | 607 + CRM/Activity/Controller/Search.php | 68 + CRM/Activity/Form/Activity.php | 1170 + CRM/Activity/Form/ActivityFilter.php | 67 + CRM/Activity/Form/ActivityLinks.php | 115 + CRM/Activity/Form/ActivityView.php | 133 + CRM/Activity/Form/Search.php | 499 + CRM/Activity/Form/Task.php | 191 + CRM/Activity/Form/Task/Batch.php | 293 + CRM/Activity/Form/Task/Delete.php | 92 + CRM/Activity/Form/Task/Email.php | 99 + CRM/Activity/Form/Task/FileOnCase.php | 181 + CRM/Activity/Form/Task/PickOption.php | 188 + CRM/Activity/Form/Task/PickProfile.php | 179 + CRM/Activity/Form/Task/Print.php | 108 + CRM/Activity/Form/Task/SMS.php | 85 + .../Form/Task/SearchTaskHookSample.php | 95 + CRM/Activity/Import/Controller.php | 53 + CRM/Activity/Import/Field.php | 117 + CRM/Activity/Import/Form/MapField.php | 608 + CRM/Activity/Import/Form/Preview.php | 232 + CRM/Activity/Import/Form/Summary.php | 131 + CRM/Activity/Import/Form/UploadFile.php | 180 + CRM/Activity/Import/Parser.php | 651 + CRM/Activity/Import/Parser/Activity.php | 389 + CRM/Activity/Import/StateMachine.php | 63 + CRM/Activity/Page/AJAX.php | 455 + CRM/Activity/Page/Tab.php | 223 + CRM/Activity/Page/UserDashboard.php | 76 + CRM/Activity/Selector/Activity.php | 485 + CRM/Activity/Selector/Search.php | 416 + CRM/Activity/StateMachine/Search.php | 108 + CRM/Activity/Task.php | 198 + CRM/Admin/Form.php | 143 + CRM/Admin/Form/CMSUser.php | 75 + CRM/Admin/Form/ContactType.php | 154 + CRM/Admin/Form/Extensions.php | 222 + CRM/Admin/Form/Job.php | 207 + CRM/Admin/Form/LabelFormats.php | 209 + CRM/Admin/Form/LocationType.php | 130 + CRM/Admin/Form/MailSettings.php | 186 + CRM/Admin/Form/Mapping.php | 112 + CRM/Admin/Form/MessageTemplates.php | 269 + CRM/Admin/Form/Navigation.php | 167 + CRM/Admin/Form/OptionGroup.php | 130 + CRM/Admin/Form/OptionValue.php | 287 + CRM/Admin/Form/Options.php | 421 + CRM/Admin/Form/ParticipantStatus.php | 135 + CRM/Admin/Form/PaymentProcessor.php | 392 + CRM/Admin/Form/PaymentProcessorType.php | 245 + CRM/Admin/Form/PdfFormats.php | 131 + CRM/Admin/Form/Persistent.php | 101 + CRM/Admin/Form/Preferences.php | 296 + CRM/Admin/Form/Preferences/Address.php | 237 + CRM/Admin/Form/Preferences/Campaign.php | 64 + CRM/Admin/Form/Preferences/Display.php | 230 + CRM/Admin/Form/Preferences/Event.php | 61 + CRM/Admin/Form/Preferences/Mailing.php | 101 + CRM/Admin/Form/Preferences/Member.php | 76 + CRM/Admin/Form/Preferences/Multisite.php | 77 + CRM/Admin/Form/PreferencesDate.php | 142 + CRM/Admin/Form/RelationshipType.php | 177 + CRM/Admin/Form/ScheduleReminders.php | 486 + CRM/Admin/Form/Setting.php | 283 + CRM/Admin/Form/Setting/Component.php | 181 + CRM/Admin/Form/Setting/Date.php | 70 + CRM/Admin/Form/Setting/Debugging.php | 64 + CRM/Admin/Form/Setting/Localization.php | 336 + CRM/Admin/Form/Setting/Mail.php | 64 + CRM/Admin/Form/Setting/Mapping.php | 101 + CRM/Admin/Form/Setting/Miscellaneous.php | 130 + CRM/Admin/Form/Setting/Path.php | 77 + CRM/Admin/Form/Setting/Search.php | 99 + CRM/Admin/Form/Setting/Smtp.php | 278 + CRM/Admin/Form/Setting/UF.php | 75 + .../Form/Setting/UpdateConfigBackend.php | 152 + CRM/Admin/Form/Setting/Url.php | 99 + CRM/Admin/Form/Tag.php | 179 + CRM/Admin/Form/WordReplacements.php | 269 + CRM/Admin/Page/AJAX.php | 523 + CRM/Admin/Page/APIDoc.php | 59 + CRM/Admin/Page/APIExplorer.php | 59 + CRM/Admin/Page/Access.php | 68 + CRM/Admin/Page/Admin.php | 119 + CRM/Admin/Page/CMSUser.php | 73 + CRM/Admin/Page/ConfigTaskList.php | 68 + CRM/Admin/Page/ContactType.php | 163 + CRM/Admin/Page/EventTemplate.php | 164 + CRM/Admin/Page/Extensions.php | 305 + CRM/Admin/Page/ExtensionsUpgrade.php | 33 + CRM/Admin/Page/Job.php | 214 + CRM/Admin/Page/JobLog.php | 156 + CRM/Admin/Page/LabelFormats.php | 146 + CRM/Admin/Page/LocationType.php | 122 + CRM/Admin/Page/MailSettings.php | 153 + CRM/Admin/Page/Mapping.php | 140 + CRM/Admin/Page/MessageTemplates.php | 269 + CRM/Admin/Page/Navigation.php | 106 + CRM/Admin/Page/OptionGroup.php | 128 + CRM/Admin/Page/OptionValue.php | 242 + CRM/Admin/Page/Options.php | 276 + CRM/Admin/Page/ParticipantStatus.php | 113 + CRM/Admin/Page/PaymentProcessor.php | 187 + CRM/Admin/Page/PaymentProcessorType.php | 122 + CRM/Admin/Page/PdfFormats.php | 137 + CRM/Admin/Page/Persistent.php | 142 + CRM/Admin/Page/PreferencesDate.php | 121 + CRM/Admin/Page/RelationshipType.php | 128 + CRM/Admin/Page/ScheduleReminders.php | 153 + CRM/Admin/Page/Setting.php | 47 + CRM/Admin/Page/Tag.php | 208 + CRM/Batch/BAO/Batch.php | 779 + CRM/Batch/Form/Batch.php | 142 + CRM/Batch/Form/Entry.php | 742 + CRM/Batch/Form/Search.php | 64 + CRM/Batch/Page/AJAX.php | 110 + CRM/Batch/Page/Batch.php | 123 + CRM/Bridge/OG/CiviCRM.php | 106 + CRM/Bridge/OG/Drupal.php | 238 + CRM/Bridge/OG/Utils.php | 119 + CRM/Campaign/BAO/Campaign.php | 645 + CRM/Campaign/BAO/Petition.php | 631 + CRM/Campaign/BAO/Query.php | 584 + CRM/Campaign/BAO/Survey.php | 1081 + CRM/Campaign/Config.php | 39 + CRM/Campaign/Controller/Search.php | 66 + CRM/Campaign/Form/Campaign.php | 408 + CRM/Campaign/Form/Gotv.php | 182 + CRM/Campaign/Form/Petition.php | 255 + CRM/Campaign/Form/Petition/Signature.php | 675 + CRM/Campaign/Form/Search.php | 591 + CRM/Campaign/Form/Search/Campaign.php | 129 + CRM/Campaign/Form/Search/Petition.php | 106 + CRM/Campaign/Form/Search/Survey.php | 116 + CRM/Campaign/Form/Survey.php | 186 + CRM/Campaign/Form/Survey/Delete.php | 112 + CRM/Campaign/Form/Survey/Main.php | 246 + CRM/Campaign/Form/Survey/Questions.php | 148 + CRM/Campaign/Form/Survey/Results.php | 482 + CRM/Campaign/Form/Survey/TabHeader.php | 156 + CRM/Campaign/Form/SurveyType.php | 185 + CRM/Campaign/Form/Task.php | 159 + CRM/Campaign/Form/Task/Interview.php | 651 + CRM/Campaign/Form/Task/Print.php | 117 + CRM/Campaign/Form/Task/Release.php | 169 + CRM/Campaign/Form/Task/Reserve.php | 352 + CRM/Campaign/Form/Task/Result.php | 68 + CRM/Campaign/Info.php | 118 + CRM/Campaign/Page/AJAX.php | 845 + CRM/Campaign/Page/Campaign.php | 136 + CRM/Campaign/Page/DashBoard.php | 463 + CRM/Campaign/Page/Petition.php | 60 + CRM/Campaign/Page/Petition/Confirm.php | 117 + CRM/Campaign/Page/Petition/ThankYou.php | 62 + CRM/Campaign/Page/Survey.php | 121 + CRM/Campaign/Page/SurveyType.php | 220 + CRM/Campaign/Page/Vote.php | 137 + CRM/Campaign/PseudoConstant.php | 163 + CRM/Campaign/Selector/Search.php | 372 + CRM/Campaign/StateMachine/Search.php | 107 + CRM/Campaign/Task.php | 160 + CRM/Campaign/xml/Menu/Campaign.xml | 176 + CRM/Case/Audit/Audit.php | 218 + CRM/Case/Audit/AuditConfig.php | 226 + CRM/Case/Audit/audit.conf.xml | 60 + CRM/Case/BAO/Case.php | 3069 ++ CRM/Case/BAO/Query.php | 744 + CRM/Case/Config.php | 40 + CRM/Case/Controller/Search.php | 66 + CRM/Case/Form/Activity.php | 707 + .../Form/Activity/ChangeCaseStartDate.php | 241 + CRM/Case/Form/Activity/ChangeCaseStatus.php | 167 + CRM/Case/Form/Activity/ChangeCaseType.php | 184 + CRM/Case/Form/Activity/LinkCases.php | 140 + CRM/Case/Form/Activity/OpenCase.php | 352 + CRM/Case/Form/ActivityToCase.php | 100 + CRM/Case/Form/ActivityView.php | 184 + CRM/Case/Form/Case.php | 434 + CRM/Case/Form/CaseView.php | 537 + CRM/Case/Form/CustomData.php | 183 + CRM/Case/Form/EditClient.php | 125 + CRM/Case/Form/Report.php | 139 + CRM/Case/Form/Search.php | 554 + CRM/Case/Form/Task.php | 173 + CRM/Case/Form/Task/Delete.php | 101 + CRM/Case/Form/Task/Print.php | 109 + CRM/Case/Form/Task/Restore.php | 90 + CRM/Case/Form/Task/Result.php | 68 + CRM/Case/Form/Task/SearchTaskHookSample.php | 92 + CRM/Case/Info.php | 111 + CRM/Case/Page/AJAX.php | 183 + CRM/Case/Page/CaseDetails.php | 72 + CRM/Case/Page/DashBoard.php | 114 + CRM/Case/Page/Tab.php | 330 + CRM/Case/PseudoConstant.php | 280 + CRM/Case/Selector/Search.php | 494 + CRM/Case/StateMachine/Search.php | 118 + CRM/Case/Task.php | 184 + CRM/Case/XMLProcessor.php | 127 + CRM/Case/XMLProcessor/Process.php | 510 + CRM/Case/XMLProcessor/Report.php | 908 + CRM/Case/XMLProcessor/Settings.php | 59 + CRM/Case/xml/HRD/CivilAndPolitical.xml | 84 + CRM/Case/xml/HRD/EconomicSocialCultural.xml | 84 + CRM/Case/xml/HRD/GenderIssues.xml | 84 + CRM/Case/xml/HRD/HRD.mysql | 45 + CRM/Case/xml/Menu/Case.xml | 138 + .../AdultDayCareReferral.xml | 84 + .../configuration.sample/HousingSupport.xml | 109 + .../configuration.sample/SampleConfig.mysql | 58 + .../xml/configuration.sample/Settings.xml | 25 + CRM/Case/xml/samples/report.xml | 210 + CRM/Contact/BAO/Contact.php | 2971 ++ CRM/Contact/BAO/Contact/Location.php | 200 + CRM/Contact/BAO/Contact/Optimizer.php | 178 + CRM/Contact/BAO/Contact/Permission.php | 310 + CRM/Contact/BAO/Contact/Utils.php | 1091 + CRM/Contact/BAO/ContactType.php | 852 + CRM/Contact/BAO/Group.php | 1167 + CRM/Contact/BAO/GroupContact.php | 792 + CRM/Contact/BAO/GroupContactCache.php | 511 + CRM/Contact/BAO/GroupNesting.php | 688 + CRM/Contact/BAO/GroupNestingCache.php | 230 + CRM/Contact/BAO/GroupOrganization.php | 155 + CRM/Contact/BAO/Household.php | 73 + CRM/Contact/BAO/Individual.php | 408 + CRM/Contact/BAO/ProximityQuery.php | 364 + CRM/Contact/BAO/Query.php | 4964 ++ CRM/Contact/BAO/Relationship.php | 1518 + CRM/Contact/BAO/RelationshipType.php | 174 + CRM/Contact/BAO/SavedSearch.php | 296 + CRM/Contact/BAO/SearchCustom.php | 136 + CRM/Contact/BAO/SubscriptionHistory.php | 76 + CRM/Contact/Controller/Search.php | 68 + CRM/Contact/DAO/Factory.php | 61 + CRM/Contact/Form/Contact.php | 1448 + CRM/Contact/Form/CustomData.php | 234 + CRM/Contact/Form/DedupeFind.php | 114 + CRM/Contact/Form/DedupeRules.php | 284 + CRM/Contact/Form/Domain.php | 298 + CRM/Contact/Form/Edit/Address.php | 551 + .../Form/Edit/CommunicationPreferences.php | 238 + CRM/Contact/Form/Edit/CustomData.php | 116 + CRM/Contact/Form/Edit/Demographics.php | 78 + CRM/Contact/Form/Edit/Email.php | 119 + CRM/Contact/Form/Edit/Household.php | 104 + CRM/Contact/Form/Edit/IM.php | 81 + CRM/Contact/Form/Edit/Individual.php | 157 + CRM/Contact/Form/Edit/Lock.php | 80 + CRM/Contact/Form/Edit/Notes.php | 50 + CRM/Contact/Form/Edit/OpenID.php | 78 + CRM/Contact/Form/Edit/Organization.php | 105 + CRM/Contact/Form/Edit/Phone.php | 83 + CRM/Contact/Form/Edit/TagsAndGroups.php | 227 + CRM/Contact/Form/Edit/Website.php | 78 + CRM/Contact/Form/GroupContact.php | 170 + CRM/Contact/Form/Inline.php | 183 + CRM/Contact/Form/Inline/Address.php | 209 + .../Form/Inline/CommunicationPreferences.php | 104 + CRM/Contact/Form/Inline/ContactInfo.php | 96 + CRM/Contact/Form/Inline/ContactName.php | 76 + CRM/Contact/Form/Inline/CustomData.php | 113 + CRM/Contact/Form/Inline/Demographics.php | 78 + CRM/Contact/Form/Inline/Email.php | 174 + CRM/Contact/Form/Inline/IM.php | 176 + CRM/Contact/Form/Inline/Lock.php | 100 + CRM/Contact/Form/Inline/OpenID.php | 176 + CRM/Contact/Form/Inline/Phone.php | 177 + CRM/Contact/Form/Inline/Website.php | 128 + CRM/Contact/Form/Location.php | 119 + CRM/Contact/Form/Merge.php | 361 + CRM/Contact/Form/NewContact.php | 80 + CRM/Contact/Form/RelatedContact.php | 195 + CRM/Contact/Form/Relationship.php | 832 + CRM/Contact/Form/Search.php | 974 + CRM/Contact/Form/Search/Advanced.php | 394 + CRM/Contact/Form/Search/Basic.php | 285 + CRM/Contact/Form/Search/Builder.php | 476 + CRM/Contact/Form/Search/Criteria.php | 569 + CRM/Contact/Form/Search/Custom.php | 131 + .../Form/Search/Custom/ActivitySearch.php | 352 + CRM/Contact/Form/Search/Custom/Base.php | 168 + CRM/Contact/Form/Search/Custom/Basic.php | 163 + .../Form/Search/Custom/ContribSYBNT.php | 331 + .../Search/Custom/ContributionAggregate.php | 253 + CRM/Contact/Form/Search/Custom/DateAdded.php | 394 + .../Form/Search/Custom/EmployerListing.php | 258 + .../Form/Search/Custom/EventAggregate.php | 308 + CRM/Contact/Form/Search/Custom/FullText.php | 1035 + CRM/Contact/Form/Search/Custom/Group.php | 600 + .../Form/Search/Custom/MultipleValues.php | 301 + .../Form/Search/Custom/PostalMailing.php | 121 + CRM/Contact/Form/Search/Custom/PriceSet.php | 307 + CRM/Contact/Form/Search/Custom/Proximity.php | 278 + .../Form/Search/Custom/RandomSegment.php | 343 + CRM/Contact/Form/Search/Custom/Sample.php | 181 + .../Form/Search/Custom/TagContributions.php | 225 + .../Form/Search/Custom/ZipCodeRange.php | 150 + CRM/Contact/Form/Search/Interface.php | 109 + CRM/Contact/Form/Search/Simple.php | 98 + CRM/Contact/Form/Task.php | 393 + CRM/Contact/Form/Task/AddToGroup.php | 250 + CRM/Contact/Form/Task/AddToHousehold.php | 288 + CRM/Contact/Form/Task/AddToOrganization.php | 177 + CRM/Contact/Form/Task/AddToTag.php | 154 + CRM/Contact/Form/Task/AlterPreferences.php | 141 + CRM/Contact/Form/Task/Batch.php | 329 + CRM/Contact/Form/Task/Delete.php | 270 + CRM/Contact/Form/Task/Email.php | 123 + CRM/Contact/Form/Task/EmailCommon.php | 432 + CRM/Contact/Form/Task/HookSample.php | 96 + CRM/Contact/Form/Task/Label.php | 496 + CRM/Contact/Form/Task/Map.php | 245 + CRM/Contact/Form/Task/Map/Event.php | 66 + CRM/Contact/Form/Task/Merge.php | 94 + CRM/Contact/Form/Task/PDF.php | 125 + CRM/Contact/Form/Task/PDFLetterCommon.php | 403 + CRM/Contact/Form/Task/PickProfile.php | 177 + CRM/Contact/Form/Task/Print.php | 148 + CRM/Contact/Form/Task/ProximityCommon.php | 177 + CRM/Contact/Form/Task/RemoveFromGroup.php | 97 + CRM/Contact/Form/Task/RemoveFromTag.php | 143 + CRM/Contact/Form/Task/Result.php | 116 + CRM/Contact/Form/Task/SMS.php | 101 + CRM/Contact/Form/Task/SMSCommon.php | 429 + CRM/Contact/Form/Task/SaveSearch.php | 221 + CRM/Contact/Form/Task/SaveSearch/Update.php | 80 + CRM/Contact/Form/Task/Unhold.php | 40 + CRM/Contact/Form/Task/Useradd.php | 156 + CRM/Contact/Form/Test.php | 85 + CRM/Contact/Page/AJAX.php | 1217 + CRM/Contact/Page/CustomSearch.php | 103 + CRM/Contact/Page/DashBoard.php | 121 + CRM/Contact/Page/Dashlet.php | 86 + CRM/Contact/Page/DedupeException.php | 93 + CRM/Contact/Page/DedupeFind.php | 359 + CRM/Contact/Page/DedupeRules.php | 211 + CRM/Contact/Page/Inline/Actions.php | 73 + CRM/Contact/Page/Inline/Address.php | 122 + .../Page/Inline/CommunicationPreferences.php | 71 + CRM/Contact/Page/Inline/ContactInfo.php | 79 + CRM/Contact/Page/Inline/ContactName.php | 76 + CRM/Contact/Page/Inline/CustomData.php | 77 + CRM/Contact/Page/Inline/Demographics.php | 78 + CRM/Contact/Page/Inline/Email.php | 86 + CRM/Contact/Page/Inline/IM.php | 77 + CRM/Contact/Page/Inline/OpenID.php | 75 + CRM/Contact/Page/Inline/Phone.php | 88 + CRM/Contact/Page/Inline/Website.php | 75 + CRM/Contact/Page/SavedSearch.php | 169 + CRM/Contact/Page/Task.php | 55 + CRM/Contact/Page/View.php | 462 + CRM/Contact/Page/View/CustomData.php | 142 + CRM/Contact/Page/View/Email.php | 107 + CRM/Contact/Page/View/GroupContact.php | 223 + CRM/Contact/Page/View/Log.php | 104 + CRM/Contact/Page/View/Note.php | 315 + CRM/Contact/Page/View/Print.php | 79 + CRM/Contact/Page/View/Relationship.php | 363 + CRM/Contact/Page/View/SMS.php | 97 + CRM/Contact/Page/View/Summary.php | 387 + CRM/Contact/Page/View/Sunlight.php | 71 + CRM/Contact/Page/View/Tag.php | 83 + CRM/Contact/Page/View/UserDashBoard.php | 262 + .../Page/View/UserDashBoard/GroupContact.php | 142 + CRM/Contact/Page/View/Useradd.php | 63 + CRM/Contact/Page/View/Vcard.php | 168 + CRM/Contact/Selector.php | 1084 + CRM/Contact/Selector/Controller.php | 40 + CRM/Contact/Selector/Custom.php | 407 + CRM/Contact/StateMachine/Search.php | 144 + CRM/Contact/Task.php | 346 + CRM/Contribute/BAO/Contribution.php | 2966 ++ CRM/Contribute/BAO/Contribution/Utils.php | 805 + CRM/Contribute/BAO/ContributionPage.php | 757 + CRM/Contribute/BAO/ContributionRecur.php | 461 + CRM/Contribute/BAO/ManagePremiums.php | 148 + CRM/Contribute/BAO/Premium.php | 269 + CRM/Contribute/BAO/Query.php | 872 + CRM/Contribute/BAO/Widget.php | 199 + CRM/Contribute/Config.php | 40 + CRM/Contribute/Controller/Contribution.php | 71 + .../Controller/ContributionPage.php | 66 + CRM/Contribute/Controller/Search.php | 66 + CRM/Contribute/Form.php | 138 + CRM/Contribute/Form/AbstractEditPayment.php | 547 + CRM/Contribute/Form/AdditionalInfo.php | 517 + CRM/Contribute/Form/CancelSubscription.php | 321 + CRM/Contribute/Form/Contribution.php | 1657 + CRM/Contribute/Form/Contribution/Confirm.php | 1714 + CRM/Contribute/Form/Contribution/Main.php | 1443 + .../Form/Contribution/OnBehalfOf.php | 178 + CRM/Contribute/Form/Contribution/ThankYou.php | 298 + CRM/Contribute/Form/ContributionBase.php | 827 + CRM/Contribute/Form/ContributionCharts.php | 241 + CRM/Contribute/Form/ContributionPage.php | 426 + .../Form/ContributionPage/AddProduct.php | 297 + .../Form/ContributionPage/Amount.php | 718 + .../Form/ContributionPage/Custom.php | 217 + .../Form/ContributionPage/Delete.php | 156 + .../Form/ContributionPage/Premium.php | 154 + .../Form/ContributionPage/Settings.php | 333 + .../Form/ContributionPage/TabHeader.php | 193 + .../Form/ContributionPage/ThankYou.php | 143 + .../Form/ContributionPage/Widget.php | 260 + CRM/Contribute/Form/ContributionView.php | 225 + CRM/Contribute/Form/ManagePremiums.php | 417 + CRM/Contribute/Form/Search.php | 561 + CRM/Contribute/Form/SearchContribution.php | 85 + CRM/Contribute/Form/Task.php | 189 + CRM/Contribute/Form/Task/Batch.php | 276 + CRM/Contribute/Form/Task/Delete.php | 94 + CRM/Contribute/Form/Task/Email.php | 99 + CRM/Contribute/Form/Task/PDF.php | 267 + CRM/Contribute/Form/Task/PDFLetter.php | 146 + CRM/Contribute/Form/Task/PDFLetterCommon.php | 115 + CRM/Contribute/Form/Task/PickProfile.php | 154 + CRM/Contribute/Form/Task/Print.php | 108 + CRM/Contribute/Form/Task/Result.php | 68 + .../Form/Task/SearchTaskHookSample.php | 94 + CRM/Contribute/Form/Task/Status.php | 342 + CRM/Contribute/Form/UpdateBilling.php | 442 + CRM/Contribute/Form/UpdateSubscription.php | 322 + CRM/Contribute/Import/Controller.php | 58 + CRM/Contribute/Import/Field.php | 202 + CRM/Contribute/Import/Form/MapField.php | 679 + CRM/Contribute/Import/Form/Preview.php | 226 + CRM/Contribute/Import/Form/Summary.php | 142 + CRM/Contribute/Import/Form/UploadFile.php | 206 + CRM/Contribute/Import/Parser.php | 897 + CRM/Contribute/Import/Parser/Contribution.php | 587 + CRM/Contribute/Import/StateMachine.php | 63 + CRM/Contribute/Info.php | 118 + CRM/Contribute/Page/ContributionPage.php | 668 + CRM/Contribute/Page/ContributionRecur.php | 113 + CRM/Contribute/Page/DashBoard.php | 128 + CRM/Contribute/Page/ManagePremiums.php | 206 + CRM/Contribute/Page/Premium.php | 222 + CRM/Contribute/Page/SubscriptionStatus.php | 63 + CRM/Contribute/Page/Tab.php | 534 + CRM/Contribute/Page/UserDashboard.php | 149 + CRM/Contribute/PseudoConstant.php | 415 + CRM/Contribute/Selector/Search.php | 501 + CRM/Contribute/StateMachine/Contribution.php | 62 + .../StateMachine/ContributionPage.php | 77 + CRM/Contribute/StateMachine/Search.php | 115 + CRM/Contribute/Task.php | 196 + CRM/Contribute/xml/Menu/Contribute.xml | 276 + CRM/Contribute/xml/Menu/PCP.xml | 28 + CRM/Core/Action.php | 365 + CRM/Core/BAO/ActionLog.php | 75 + CRM/Core/BAO/ActionSchedule.php | 1034 + CRM/Core/BAO/Address.php | 1133 + CRM/Core/BAO/Block.php | 522 + CRM/Core/BAO/CMSUser.php | 494 + CRM/Core/BAO/Cache.php | 341 + CRM/Core/BAO/ConfigSetting.php | 664 + CRM/Core/BAO/CustomField.php | 2394 + CRM/Core/BAO/CustomGroup.php | 2091 + CRM/Core/BAO/CustomOption.php | 295 + CRM/Core/BAO/CustomQuery.php | 659 + CRM/Core/BAO/CustomValue.php | 219 + CRM/Core/BAO/CustomValueTable.php | 670 + CRM/Core/BAO/Dashboard.php | 458 + CRM/Core/BAO/Discount.php | 144 + CRM/Core/BAO/Domain.php | 299 + CRM/Core/BAO/Email.php | 310 + CRM/Core/BAO/EntityTag.php | 389 + CRM/Core/BAO/Extension.php | 112 + CRM/Core/BAO/File.php | 551 + CRM/Core/BAO/FinancialTrxn.php | 374 + CRM/Core/BAO/IM.php | 170 + CRM/Core/BAO/Job.php | 146 + CRM/Core/BAO/LabelFormat.php | 521 + CRM/Core/BAO/Location.php | 389 + CRM/Core/BAO/LocationType.php | 178 + CRM/Core/BAO/Log.php | 182 + CRM/Core/BAO/MailSettings.php | 205 + CRM/Core/BAO/Mapping.php | 1213 + CRM/Core/BAO/MessageTemplates.php | 527 + CRM/Core/BAO/Navigation.php | 832 + CRM/Core/BAO/Note.php | 570 + CRM/Core/BAO/OpenID.php | 144 + CRM/Core/BAO/OptionGroup.php | 236 + CRM/Core/BAO/OptionValue.php | 423 + CRM/Core/BAO/PaperSize.php | 351 + CRM/Core/BAO/PdfFormat.php | 404 + CRM/Core/BAO/Persistent.php | 109 + CRM/Core/BAO/Phone.php | 251 + CRM/Core/BAO/Preferences.php | 141 + CRM/Core/BAO/PreferencesDate.php | 100 + CRM/Core/BAO/PrevNextCache.php | 430 + CRM/Core/BAO/SchemaHandler.php | 455 + CRM/Core/BAO/Setting.php | 914 + CRM/Core/BAO/Tag.php | 427 + CRM/Core/BAO/UFField.php | 1085 + CRM/Core/BAO/UFGroup.php | 3501 ++ CRM/Core/BAO/UFJoin.php | 176 + CRM/Core/BAO/UFMatch.php | 652 + CRM/Core/BAO/Website.php | 192 + CRM/Core/Base.php | 47 + CRM/Core/Block.php | 634 + CRM/Core/ClassLoader.php | 130 + CRM/Core/Component.php | 379 + CRM/Core/Component/Config.php | 66 + CRM/Core/Component/Info.php | 351 + CRM/Core/Config.php | 766 + CRM/Core/Config/Defaults.php | 233 + CRM/Core/Config/Variables.php | 584 + CRM/Core/Controller.php | 753 + CRM/Core/Controller/Simple.php | 119 + CRM/Core/DAO.php | 1716 + CRM/Core/DAO/.permissions.php | 572 + CRM/Core/DAO/Factory.php | 55 + CRM/Core/Error.php | 837 + CRM/Core/Exception.php | 33 + CRM/Core/Form.php | 1243 + CRM/Core/Form/Date.php | 141 + CRM/Core/Form/Renderer.php | 178 + CRM/Core/Form/Tag.php | 266 + CRM/Core/HTMLInputCoder.php | 205 + CRM/Core/I18n.php | 435 + CRM/Core/I18n/Form.php | 111 + CRM/Core/I18n/NativeGettext.php | 60 + CRM/Core/I18n/PseudoConstant.php | 81 + CRM/Core/I18n/Schema.php | 576 + CRM/Core/I18n/SchemaStructure_2_2_0.php | 60 + CRM/Core/I18n/SchemaStructure_3_0_alpha1.php | 242 + CRM/Core/I18n/SchemaStructure_3_0_beta1.php | 258 + CRM/Core/I18n/SchemaStructure_3_0_beta4.php | 271 + CRM/Core/I18n/SchemaStructure_3_1_alpha1.php | 275 + CRM/Core/I18n/SchemaStructure_3_1_beta2.php | 278 + CRM/Core/I18n/SchemaStructure_3_2_beta4.php | 279 + CRM/Core/I18n/SchemaStructure_3_3_beta1.php | 288 + CRM/Core/I18n/SchemaStructure_3_4_0.php | 214 + CRM/Core/I18n/SchemaStructure_3_4_beta2.php | 287 + CRM/Core/I18n/SchemaStructure_3_4_beta3.php | 213 + CRM/Core/I18n/SchemaStructure_4_1_0.php | 220 + CRM/Core/I18n/SchemaStructure_4_1_alpha1.php | 217 + CRM/Core/I18n/SchemaStructure_4_2_alpha1.php | 227 + CRM/Core/IDS.php | 275 + CRM/Core/Invoke.php | 474 + CRM/Core/JobManager.php | 251 + CRM/Core/Joomla.php | 77 + CRM/Core/Key.php | 150 + CRM/Core/Lock.php | 112 + CRM/Core/ManagedEntities.php | 267 + CRM/Core/Menu.php | 669 + CRM/Core/Module.php | 70 + CRM/Core/OptionGroup.php | 560 + CRM/Core/OptionValue.php | 465 + CRM/Core/Page.php | 367 + CRM/Core/Page/AJAX.php | 166 + CRM/Core/Page/AJAX/Location.php | 334 + CRM/Core/Page/Basic.php | 377 + CRM/Core/Page/File.php | 76 + CRM/Core/Page/Inline/Help.php | 54 + CRM/Core/Page/QUnit.php | 71 + CRM/Core/Payment.php | 379 + CRM/Core/Payment/AuthorizeNet.php | 760 + CRM/Core/Payment/AuthorizeNetIPN.php | 318 + CRM/Core/Payment/BaseIPN.php | 763 + CRM/Core/Payment/Dummy.php | 131 + CRM/Core/Payment/Elavon.php | 463 + CRM/Core/Payment/FirstData.php | 386 + CRM/Core/Payment/Form.php | 425 + CRM/Core/Payment/Google.php | 410 + CRM/Core/Payment/GoogleIPN.php | 663 + CRM/Core/Payment/IATS.php | 334 + CRM/Core/Payment/Moneris.php | 326 + CRM/Core/Payment/PayJunction.php | 283 + CRM/Core/Payment/PayPalIPN.php | 345 + CRM/Core/Payment/PayPalImpl.php | 745 + CRM/Core/Payment/PayPalProIPN.php | 380 + CRM/Core/Payment/PayflowPro.php | 650 + CRM/Core/Payment/PaymentExpress.php | 256 + CRM/Core/Payment/PaymentExpressIPN.php | 432 + CRM/Core/Payment/PaymentExpressUtils.php | 81 + CRM/Core/Payment/ProcessorForm.php | 134 + CRM/Core/Payment/Realex.php | 522 + CRM/Core/Payment/eWAY.php | 556 + CRM/Core/Permission.php | 583 + CRM/Core/Permission/Base.php | 192 + CRM/Core/Permission/Drupal.php | 148 + CRM/Core/Permission/Drupal6.php | 186 + CRM/Core/Permission/DrupalBase.php | 264 + CRM/Core/Permission/Joomla.php | 77 + CRM/Core/Permission/Soap.php | 54 + CRM/Core/Permission/UnitTests.php | 63 + CRM/Core/Permission/WordPress.php | 80 + CRM/Core/PseudoConstant.php | 2227 + CRM/Core/QuickForm/Action.php | 86 + CRM/Core/QuickForm/Action/Back.php | 63 + CRM/Core/QuickForm/Action/Cancel.php | 66 + CRM/Core/QuickForm/Action/Display.php | 234 + CRM/Core/QuickForm/Action/Done.php | 84 + CRM/Core/QuickForm/Action/Jump.php | 81 + CRM/Core/QuickForm/Action/Next.php | 63 + CRM/Core/QuickForm/Action/Process.php | 66 + CRM/Core/QuickForm/Action/Refresh.php | 80 + CRM/Core/QuickForm/Action/Reload.php | 73 + CRM/Core/QuickForm/Action/Submit.php | 86 + CRM/Core/QuickForm/Action/Upload.php | 164 + CRM/Core/QuickForm/GroupMultiSelect.php | 279 + CRM/Core/QuickForm/NestedAdvMultiSelect.php | 55 + CRM/Core/Region.php | 253 + CRM/Core/Report/Excel.php | 199 + CRM/Core/Resources.php | 521 + CRM/Core/ScheduledJob.php | 124 + CRM/Core/SelectValues.php | 815 + CRM/Core/Selector/API.php | 135 + CRM/Core/Selector/Base.php | 183 + CRM/Core/Selector/Controller.php | 536 + CRM/Core/Session.php | 552 + CRM/Core/ShowHideBlocks.php | 262 + CRM/Core/Smarty.php | 227 + CRM/Core/Smarty/plugins/block.crmRegion.php | 25 + CRM/Core/Smarty/plugins/block.edit.php | 54 + CRM/Core/Smarty/plugins/block.htxt.php | 55 + CRM/Core/Smarty/plugins/block.localize.php | 67 + CRM/Core/Smarty/plugins/block.serialize.php | 51 + CRM/Core/Smarty/plugins/block.ts.php | 52 + CRM/Core/Smarty/plugins/compiler.continue.php | 8 + CRM/Core/Smarty/plugins/function.crmAPI.php | 77 + CRM/Core/Smarty/plugins/function.crmDBTpl.php | 50 + CRM/Core/Smarty/plugins/function.crmKey.php | 51 + .../plugins/function.crmNavigationMenu.php | 61 + .../Smarty/plugins/function.crmResURL.php | 49 + .../Smarty/plugins/function.crmScript.php | 64 + .../Smarty/plugins/function.crmSetting.php | 63 + CRM/Core/Smarty/plugins/function.crmStyle.php | 64 + CRM/Core/Smarty/plugins/function.docURL.php | 54 + CRM/Core/Smarty/plugins/function.help.php | 83 + .../Smarty/plugins/function.isValueChange.php | 89 + .../Smarty/plugins/function.sectionTotal.php | 80 + .../function.simpleActivityContacts.php | 64 + .../Smarty/plugins/modifier.crmAddClass.php | 56 + .../Smarty/plugins/modifier.crmBtnType.php | 54 + .../plugins/modifier.crmBtnValidate.php | 58 + CRM/Core/Smarty/plugins/modifier.crmDate.php | 60 + .../Smarty/plugins/modifier.crmDelete.php | 57 + .../Smarty/plugins/modifier.crmFirstWord.php | 54 + .../Smarty/plugins/modifier.crmICalDate.php | 47 + .../Smarty/plugins/modifier.crmICalText.php | 47 + .../Smarty/plugins/modifier.crmInsert.php | 53 + CRM/Core/Smarty/plugins/modifier.crmMoney.php | 48 + .../plugins/modifier.crmNumberFormat.php | 66 + .../Smarty/plugins/modifier.crmReplace.php | 58 + .../plugins/modifier.crmStripAlternatives.php | 47 + CRM/Core/Smarty/plugins/modifier.htmlize.php | 48 + CRM/Core/Smarty/plugins/modifier.json.php | 49 + .../Smarty/plugins/modifier.mb_truncate.php | 91 + .../Smarty/plugins/modifier.substring.php | 61 + CRM/Core/Smarty/resources/String.php | 61 + CRM/Core/State.php | 215 + CRM/Core/StateMachine.php | 388 + CRM/Core/TableHierarchy.php | 87 + CRM/Core/TemporaryErrorScope.php | 65 + CRM/Core/Transaction.php | 206 + CRM/Core/xml/Menu/Activity.xml | 54 + CRM/Core/xml/Menu/Admin.xml | 768 + CRM/Core/xml/Menu/Contact.xml | 418 + CRM/Core/xml/Menu/Custom.xml | 8 + CRM/Core/xml/Menu/Group.xml | 31 + CRM/Core/xml/Menu/Import.xml | 33 + CRM/Core/xml/Menu/Location.xml | 16 + CRM/Core/xml/Menu/Misc.xml | 174 + CRM/Core/xml/Menu/PCP.xml | 29 + CRM/Core/xml/Menu/Profile.xml | 24 + CRM/Custom/Form/ChangeFieldType.php | 305 + CRM/Custom/Form/CustomData.php | 161 + CRM/Custom/Form/DeleteField.php | 121 + CRM/Custom/Form/DeleteFile.php | 93 + CRM/Custom/Form/DeleteGroup.php | 122 + CRM/Custom/Form/Field.php | 988 + CRM/Custom/Form/Group.php | 549 + CRM/Custom/Form/MoveField.php | 176 + CRM/Custom/Form/Option.php | 495 + CRM/Custom/Form/Preview.php | 138 + CRM/Custom/Page/Field.php | 304 + CRM/Custom/Page/Group.php | 337 + CRM/Custom/Page/Option.php | 327 + CRM/Dashlet/Page/Activity.php | 81 + CRM/Dashlet/Page/AllCases.php | 68 + CRM/Dashlet/Page/Blog.php | 111 + CRM/Dashlet/Page/CaseDashboard.php | 67 + CRM/Dashlet/Page/MyCases.php | 68 + CRM/Dedupe/BAO/QueryBuilder.php | 17 + .../BAO/QueryBuilder/IndividualGeneral.php | 61 + .../BAO/QueryBuilder/IndividualSupervised.php | 47 + .../QueryBuilder/IndividualUnsupervised.php | 74 + CRM/Dedupe/BAO/Rule.php | 227 + CRM/Dedupe/BAO/RuleGroup.php | 425 + CRM/Dedupe/Finder.php | 310 + CRM/Dedupe/Merger.php | 1488 + CRM/Event/BAO/Event.php | 2010 + CRM/Event/BAO/Participant.php | 1763 + CRM/Event/BAO/ParticipantPayment.php | 110 + CRM/Event/BAO/ParticipantStatusType.php | 293 + CRM/Event/BAO/Query.php | 633 + CRM/Event/Badge.php | 184 + CRM/Event/Badge/Logo.php | 39 + CRM/Event/Badge/Logo5395.php | 39 + CRM/Event/Badge/NameTent.php | 82 + CRM/Event/Badge/Simple.php | 59 + CRM/Event/Cart/BAO/Cart.php | 249 + CRM/Event/Cart/BAO/Conference.php | 34 + CRM/Event/Cart/BAO/EventInCart.php | 222 + CRM/Event/Cart/BAO/MerParticipant.php | 115 + CRM/Event/Cart/Controller/Checkout.php | 22 + CRM/Event/Cart/Form/Cart.php | 148 + .../Cart/Form/Checkout/ConferenceEvents.php | 142 + .../Form/Checkout/ParticipantsAndPrices.php | 228 + CRM/Event/Cart/Form/Checkout/Payment.php | 709 + CRM/Event/Cart/Form/Checkout/ThankYou.php | 77 + CRM/Event/Cart/Form/MerParticipant.php | 93 + CRM/Event/Cart/Page/AddToCart.php | 27 + CRM/Event/Cart/Page/CheckoutAJAX.php | 50 + CRM/Event/Cart/Page/RemoveFromCart.php | 18 + CRM/Event/Cart/Page/ViewCart.php | 18 + CRM/Event/Cart/StateMachine/Checkout.php | 36 + CRM/Event/Config.php | 39 + CRM/Event/Controller/Registration.php | 61 + CRM/Event/Controller/Search.php | 80 + CRM/Event/Form/EventFees.php | 587 + CRM/Event/Form/ManageEvent.php | 372 + CRM/Event/Form/ManageEvent/Conference.php | 128 + CRM/Event/Form/ManageEvent/Delete.php | 120 + CRM/Event/Form/ManageEvent/EventInfo.php | 411 + CRM/Event/Form/ManageEvent/Fee.php | 781 + CRM/Event/Form/ManageEvent/Location.php | 318 + CRM/Event/Form/ManageEvent/Registration.php | 834 + .../Form/ManageEvent/ScheduleReminders.php | 395 + CRM/Event/Form/ManageEvent/TabHeader.php | 217 + CRM/Event/Form/Participant.php | 1771 + CRM/Event/Form/ParticipantView.php | 211 + CRM/Event/Form/Registration.php | 1427 + .../Registration/AdditionalParticipant.php | 866 + CRM/Event/Form/Registration/Confirm.php | 1132 + .../Form/Registration/ParticipantConfirm.php | 225 + CRM/Event/Form/Registration/Register.php | 1472 + CRM/Event/Form/Registration/ThankYou.php | 234 + CRM/Event/Form/Search.php | 597 + CRM/Event/Form/SearchEvent.php | 111 + CRM/Event/Form/Task.php | 179 + CRM/Event/Form/Task/Badge.php | 182 + CRM/Event/Form/Task/Batch.php | 382 + CRM/Event/Form/Task/Cancel.php | 97 + CRM/Event/Form/Task/Delete.php | 141 + CRM/Event/Form/Task/Email.php | 105 + CRM/Event/Form/Task/ParticipantStatus.php | 61 + CRM/Event/Form/Task/PickProfile.php | 154 + CRM/Event/Form/Task/Print.php | 108 + CRM/Event/Form/Task/Result.php | 71 + CRM/Event/Form/Task/SaveSearch.php | 141 + CRM/Event/Form/Task/SaveSearch/Update.php | 78 + CRM/Event/Form/Task/SearchTaskHookSample.php | 91 + CRM/Event/Import/Controller.php | 58 + CRM/Event/Import/Field.php | 135 + CRM/Event/Import/Form/MapField.php | 613 + CRM/Event/Import/Form/Preview.php | 217 + CRM/Event/Import/Form/Summary.php | 130 + CRM/Event/Import/Form/UploadFile.php | 209 + CRM/Event/Import/Parser.php | 697 + CRM/Event/Import/Parser/Participant.php | 506 + CRM/Event/Import/StateMachine.php | 63 + CRM/Event/Info.php | 124 + CRM/Event/Page/AJAX.php | 154 + CRM/Event/Page/DashBoard.php | 93 + CRM/Event/Page/EventInfo.php | 341 + CRM/Event/Page/ICalendar.php | 106 + CRM/Event/Page/ManageEvent.php | 462 + CRM/Event/Page/ParticipantListing.php | 99 + CRM/Event/Page/ParticipantListing/Name.php | 42 + .../Page/ParticipantListing/NameAndEmail.php | 42 + .../ParticipantListing/NameStatusAndDate.php | 178 + CRM/Event/Page/ParticipantListing/Simple.php | 163 + CRM/Event/Page/Tab.php | 305 + CRM/Event/Page/UserDashboard.php | 70 + CRM/Event/PseudoConstant.php | 303 + CRM/Event/Selector/Search.php | 500 + CRM/Event/StateMachine/Registration.php | 99 + CRM/Event/StateMachine/Search.php | 118 + CRM/Event/Task.php | 223 + CRM/Event/xml/Menu/Event.xml | 333 + CRM/Event/xml/Menu/PCP.xml | 35 + CRM/Export/BAO/Export.php | 1804 + CRM/Export/Form/Map.php | 256 + CRM/Export/Form/Select.php | 484 + CRM/Extension/Browser.php | 301 + CRM/Extension/Container/Basic.php | 173 + CRM/Extension/Container/Collection.php | 153 + CRM/Extension/Container/Interface.php | 66 + CRM/Extension/Container/Static.php | 86 + CRM/Extension/Downloader.php | 206 + CRM/Extension/Exception.php | 29 + .../Exception/DependencyException.php | 33 + CRM/Extension/Exception/MissingException.php | 32 + CRM/Extension/Exception/ParseException.php | 32 + CRM/Extension/Info.php | 120 + CRM/Extension/Manager.php | 488 + CRM/Extension/Manager/Base.php | 118 + CRM/Extension/Manager/Interface.php | 82 + CRM/Extension/Manager/Module.php | 83 + CRM/Extension/Manager/Payment.php | 282 + CRM/Extension/Manager/Report.php | 119 + CRM/Extension/Manager/Search.php | 110 + CRM/Extension/Mapper.php | 364 + CRM/Extension/System.php | 235 + CRM/Extension/Upgrades.php | 75 + CRM/Financial/BAO/ExportFormat.php | 222 + CRM/Financial/BAO/ExportFormat/CSV.php | 212 + CRM/Financial/BAO/ExportFormat/IIF.php | 343 + CRM/Financial/BAO/FinancialAccount.php | 196 + CRM/Financial/BAO/FinancialItem.php | 207 + CRM/Financial/BAO/FinancialType.php | 201 + CRM/Financial/BAO/FinancialTypeAccount.php | 213 + CRM/Financial/BAO/PaymentProcessor.php | 325 + CRM/Financial/BAO/PaymentProcessorType.php | 217 + CRM/Financial/Form/BatchTransaction.php | 197 + CRM/Financial/Form/Export.php | 193 + CRM/Financial/Form/FinancialAccount.php | 151 + CRM/Financial/Form/FinancialBatch.php | 311 + CRM/Financial/Form/FinancialType.php | 114 + CRM/Financial/Form/FinancialTypeAccount.php | 330 + CRM/Financial/Form/Search.php | 130 + CRM/Financial/Page/AJAX.php | 464 + CRM/Financial/Page/Batch.php | 123 + CRM/Financial/Page/BatchTransaction.php | 161 + CRM/Financial/Page/FinancialAccount.php | 193 + CRM/Financial/Page/FinancialBatch.php | 143 + CRM/Financial/Page/FinancialType.php | 214 + CRM/Financial/Page/FinancialTypeAccount.php | 216 + CRM/Friend/BAO/Friend.php | 347 + CRM/Friend/Form.php | 330 + CRM/Friend/Form/Contribute.php | 136 + CRM/Friend/Form/Event.php | 136 + CRM/Grant/BAO/Grant.php | 426 + CRM/Grant/BAO/Query.php | 372 + CRM/Grant/Config.php | 36 + CRM/Grant/Controller/PaymentSearch.php | 72 + CRM/Grant/Controller/Search.php | 66 + CRM/Grant/Form/Grant.php | 367 + CRM/Grant/Form/GrantView.php | 140 + CRM/Grant/Form/Search.php | 433 + CRM/Grant/Form/Task.php | 168 + CRM/Grant/Form/Task/Delete.php | 98 + CRM/Grant/Form/Task/Print.php | 108 + CRM/Grant/Form/Task/Result.php | 85 + CRM/Grant/Form/Task/SearchTaskHookSample.php | 92 + CRM/Grant/Form/Task/Update.php | 119 + CRM/Grant/Info.php | 111 + CRM/Grant/Page/DashBoard.php | 80 + CRM/Grant/Page/GrantProgram.php | 143 + CRM/Grant/Page/Payment.php | 97 + CRM/Grant/Page/Tab.php | 217 + CRM/Grant/PseudoConstant.php | 114 + CRM/Grant/Selector/PaymentSearch.php | 419 + CRM/Grant/Selector/Search.php | 421 + CRM/Grant/StateMachine/Search.php | 109 + CRM/Grant/Task.php | 167 + CRM/Grant/xml/Menu/Grant.xml | 40 + CRM/Group/Controller.php | 79 + CRM/Group/Form/Edit.php | 493 + CRM/Group/Form/Search.php | 109 + CRM/Group/Page/AJAX.php | 87 + CRM/Group/Page/Group.php | 167 + CRM/Group/StateMachine.php | 63 + CRM/Import/Controller.php | 58 + CRM/Import/DataSource.php | 78 + CRM/Import/DataSource/CSV.php | 227 + CRM/Import/DataSource/SQL.php | 73 + CRM/Import/Field.php | 175 + CRM/Import/Form/DataSource.php | 390 + CRM/Import/Form/MapField.php | 1105 + CRM/Import/Form/Preview.php | 599 + CRM/Import/Form/Summary.php | 158 + CRM/Import/Form/UploadFile.php | 0 CRM/Import/ImportJob.php | 425 + CRM/Import/Importer.php | 58 + CRM/Import/Page/AJAX.php | 63 + CRM/Import/Parser.php | 1030 + CRM/Import/Parser/Contact.php | 2076 + CRM/Import/StateMachine.php | 63 + CRM/Logging/Differ.php | 330 + CRM/Logging/ReportDetail.php | 216 + CRM/Logging/ReportSummary.php | 285 + CRM/Logging/Reverter.php | 194 + CRM/Logging/Schema.php | 462 + CRM/Mailing/BAO/BouncePattern.php | 110 + CRM/Mailing/BAO/Component.php | 121 + CRM/Mailing/BAO/Job.php | 929 + CRM/Mailing/BAO/Mailing.php | 2725 + CRM/Mailing/BAO/Query.php | 353 + CRM/Mailing/BAO/Recipients.php | 73 + CRM/Mailing/BAO/Spool.php | 139 + CRM/Mailing/BAO/TrackableURL.php | 128 + CRM/Mailing/Config.php | 94 + CRM/Mailing/Controller/Send.php | 82 + CRM/Mailing/Event/BAO/Bounce.php | 268 + CRM/Mailing/Event/BAO/Confirm.php | 149 + CRM/Mailing/Event/BAO/Delivered.php | 303 + CRM/Mailing/Event/BAO/Forward.php | 369 + CRM/Mailing/Event/BAO/Opened.php | 215 + CRM/Mailing/Event/BAO/Queue.php | 316 + CRM/Mailing/Event/BAO/Reply.php | 430 + CRM/Mailing/Event/BAO/Resubscribe.php | 294 + CRM/Mailing/Event/BAO/Subscribe.php | 414 + CRM/Mailing/Event/BAO/TrackableURLOpen.php | 258 + CRM/Mailing/Event/BAO/Unsubscribe.php | 587 + CRM/Mailing/Form/Approve.php | 250 + CRM/Mailing/Form/Browse.php | 115 + CRM/Mailing/Form/Component.php | 187 + CRM/Mailing/Form/ForwardMailing.php | 163 + CRM/Mailing/Form/Group.php | 598 + CRM/Mailing/Form/Schedule.php | 361 + CRM/Mailing/Form/Search.php | 117 + CRM/Mailing/Form/Settings.php | 260 + CRM/Mailing/Form/Subscribe.php | 204 + CRM/Mailing/Form/Test.php | 381 + CRM/Mailing/Form/Upload.php | 681 + CRM/Mailing/Info.php | 131 + CRM/Mailing/MailStore.php | 159 + CRM/Mailing/MailStore/Imap.php | 124 + CRM/Mailing/MailStore/Localdir.php | 143 + CRM/Mailing/MailStore/Maildir.php | 125 + CRM/Mailing/MailStore/Mbox.php | 107 + CRM/Mailing/MailStore/Pop3.php | 97 + CRM/Mailing/Page/AJAX.php | 63 + CRM/Mailing/Page/Browse.php | 374 + CRM/Mailing/Page/Common.php | 125 + CRM/Mailing/Page/Component.php | 121 + CRM/Mailing/Page/Confirm.php | 64 + CRM/Mailing/Page/Event.php | 94 + CRM/Mailing/Page/Optout.php | 41 + CRM/Mailing/Page/Preview.php | 105 + CRM/Mailing/Page/Report.php | 120 + CRM/Mailing/Page/Resubscribe.php | 41 + CRM/Mailing/Page/Unsubscribe.php | 42 + CRM/Mailing/Page/View.php | 157 + CRM/Mailing/PseudoConstant.php | 246 + CRM/Mailing/Selector/Browse.php | 570 + CRM/Mailing/Selector/Event.php | 463 + CRM/Mailing/StateMachine/Send.php | 76 + CRM/Mailing/xml/Menu/Mailing.xml | 208 + CRM/Member/BAO/Membership.php | 2714 + CRM/Member/BAO/MembershipLog.php | 81 + CRM/Member/BAO/MembershipStatus.php | 384 + CRM/Member/BAO/MembershipType.php | 749 + CRM/Member/BAO/Query.php | 455 + CRM/Member/Config.php | 36 + CRM/Member/Controller/Search.php | 66 + CRM/Member/Form.php | 198 + CRM/Member/Form/Membership.php | 1843 + CRM/Member/Form/MembershipBlock.php | 476 + CRM/Member/Form/MembershipRenewal.php | 906 + CRM/Member/Form/MembershipStatus.php | 148 + CRM/Member/Form/MembershipType.php | 464 + CRM/Member/Form/MembershipView.php | 374 + CRM/Member/Form/Search.php | 480 + CRM/Member/Form/Task.php | 186 + CRM/Member/Form/Task/Batch.php | 290 + CRM/Member/Form/Task/Delete.php | 95 + CRM/Member/Form/Task/Email.php | 106 + CRM/Member/Form/Task/PickProfile.php | 153 + CRM/Member/Form/Task/Print.php | 108 + CRM/Member/Form/Task/Result.php | 68 + CRM/Member/Form/Task/SearchTaskHookSample.php | 91 + CRM/Member/Import/Controller.php | 58 + CRM/Member/Import/Field.php | 196 + CRM/Member/Import/Form/MapField.php | 645 + CRM/Member/Import/Form/Preview.php | 236 + CRM/Member/Import/Form/Summary.php | 131 + CRM/Member/Import/Form/UploadFile.php | 205 + CRM/Member/Import/Parser.php | 692 + CRM/Member/Import/Parser/Membership.php | 636 + CRM/Member/Import/StateMachine.php | 63 + CRM/Member/Info.php | 119 + CRM/Member/Page/AJAX.php | 75 + CRM/Member/Page/DashBoard.php | 430 + CRM/Member/Page/MembershipStatus.php | 207 + CRM/Member/Page/MembershipType.php | 169 + CRM/Member/Page/Tab.php | 566 + CRM/Member/Page/UserDashboard.php | 99 + CRM/Member/PseudoConstant.php | 132 + CRM/Member/Selector/Search.php | 527 + CRM/Member/StateMachine/Search.php | 115 + CRM/Member/Task.php | 181 + CRM/Member/xml/Menu/Member.xml | 89 + CRM/Note/Form/Note.php | 206 + CRM/PCP/BAO/PCP.php | 890 + CRM/PCP/Controller/PCP.php | 73 + CRM/PCP/Form/Campaign.php | 366 + CRM/PCP/Form/Contribute.php | 187 + CRM/PCP/Form/Event.php | 220 + CRM/PCP/Form/PCP.php | 232 + CRM/PCP/Form/PCPAccount.php | 298 + CRM/PCP/Page/PCP.php | 409 + CRM/PCP/Page/PCPInfo.php | 341 + CRM/PCP/PseudoConstant.php | 107 + CRM/PCP/StateMachine/PCP.php | 64 + CRM/Pledge/BAO/Pledge.php | 1086 + CRM/Pledge/BAO/PledgeBlock.php | 301 + CRM/Pledge/BAO/PledgePayment.php | 758 + CRM/Pledge/BAO/Query.php | 647 + CRM/Pledge/Config.php | 39 + CRM/Pledge/Controller/Search.php | 66 + CRM/Pledge/Form/Payment.php | 196 + CRM/Pledge/Form/Pledge.php | 760 + CRM/Pledge/Form/PledgeView.php | 152 + CRM/Pledge/Form/Search.php | 529 + CRM/Pledge/Form/Task.php | 170 + CRM/Pledge/Form/Task/Delete.php | 97 + CRM/Pledge/Form/Task/Print.php | 109 + CRM/Pledge/Form/Task/Result.php | 68 + CRM/Pledge/Form/Task/SearchTaskHookSample.php | 89 + CRM/Pledge/Info.php | 108 + CRM/Pledge/Page/AJAX.php | 90 + CRM/Pledge/Page/DashBoard.php | 123 + CRM/Pledge/Page/Payment.php | 102 + CRM/Pledge/Page/Tab.php | 219 + CRM/Pledge/Page/UserDashboard.php | 79 + CRM/Pledge/Selector/Search.php | 457 + CRM/Pledge/StateMachine/Search.php | 117 + CRM/Pledge/Task.php | 178 + CRM/Pledge/xml/Menu/Pledge.xml | 50 + CRM/Price/BAO/Field.php | 677 + CRM/Price/BAO/FieldValue.php | 222 + CRM/Price/BAO/LineItem.php | 391 + CRM/Price/BAO/Set.php | 1168 + CRM/Price/Form/DeleteField.php | 113 + CRM/Price/Form/DeleteSet.php | 109 + CRM/Price/Form/Field.php | 683 + CRM/Price/Form/Option.php | 329 + CRM/Price/Form/Preview.php | 151 + CRM/Price/Form/Set.php | 295 + CRM/Price/Page/Field.php | 327 + CRM/Price/Page/Option.php | 310 + CRM/Price/Page/Set.php | 325 + CRM/Profile/Form.php | 1334 + CRM/Profile/Form/Dynamic.php | 130 + CRM/Profile/Form/Edit.php | 404 + CRM/Profile/Form/Search.php | 139 + CRM/Profile/Page/Dynamic.php | 405 + CRM/Profile/Page/Listings.php | 487 + .../Page/MultipleRecordFieldsListing.php | 282 + CRM/Profile/Page/View.php | 207 + CRM/Profile/Selector/Listings.php | 785 + CRM/Project/BAO/TaskStatus.php | 185 + CRM/Queue/BAO/QueueItem.php | 66 + CRM/Queue/ErrorPolicy.php | 166 + CRM/Queue/Menu.php | 82 + CRM/Queue/Page/AJAX.php | 115 + CRM/Queue/Page/Runner.php | 83 + CRM/Queue/Queue.php | 141 + CRM/Queue/Queue/Memory.php | 189 + CRM/Queue/Queue/Sql.php | 225 + CRM/Queue/Runner.php | 313 + CRM/Queue/Service.php | 155 + CRM/Queue/Task.php | 87 + CRM/Queue/TaskContext.php | 43 + CRM/Report/BAO/Instance.php | 64 + CRM/Report/Config.php | 42 + CRM/Report/Form.php | 3198 ++ CRM/Report/Form/Activity.php | 657 + CRM/Report/Form/ActivitySummary.php | 527 + CRM/Report/Form/Campaign/SurveyDetails.php | 904 + CRM/Report/Form/Case/Demographics.php | 460 + CRM/Report/Form/Case/Detail.php | 647 + CRM/Report/Form/Case/Summary.php | 375 + CRM/Report/Form/Case/TimeSpent.php | 345 + CRM/Report/Form/Contact/CurrentEmployer.php | 376 + CRM/Report/Form/Contact/Detail.php | 874 + CRM/Report/Form/Contact/Log.php | 284 + CRM/Report/Form/Contact/LoggingDetail.php | 86 + CRM/Report/Form/Contact/LoggingSummary.php | 252 + CRM/Report/Form/Contact/Relationship.php | 565 + CRM/Report/Form/Contact/Summary.php | 312 + CRM/Report/Form/Contribute/Bookkeeping.php | 333 + CRM/Report/Form/Contribute/Detail.php | 711 + CRM/Report/Form/Contribute/History.php | 743 + .../Form/Contribute/HouseholdSummary.php | 522 + CRM/Report/Form/Contribute/LoggingDetail.php | 66 + CRM/Report/Form/Contribute/LoggingSummary.php | 231 + CRM/Report/Form/Contribute/Lybunt.php | 445 + .../Form/Contribute/OrganizationSummary.php | 539 + CRM/Report/Form/Contribute/PCP.php | 310 + CRM/Report/Form/Contribute/Repeat.php | 943 + CRM/Report/Form/Contribute/SoftCredit.php | 460 + CRM/Report/Form/Contribute/Summary.php | 607 + CRM/Report/Form/Contribute/Sybunt.php | 459 + CRM/Report/Form/Contribute/TopDonor.php | 426 + CRM/Report/Form/Event.php | 57 + CRM/Report/Form/Event/Income.php | 351 + CRM/Report/Form/Event/IncomeCountSummary.php | 405 + .../Form/Event/ParticipantListCount.php | 561 + CRM/Report/Form/Event/ParticipantListing.php | 496 + CRM/Report/Form/Event/Summary.php | 387 + CRM/Report/Form/Extended.php | 1281 + CRM/Report/Form/Grant/Detail.php | 414 + CRM/Report/Form/Grant/Statistics.php | 583 + CRM/Report/Form/Instance.php | 410 + CRM/Report/Form/Mailing/Bounce.php | 379 + CRM/Report/Form/Mailing/Clicks.php | 325 + CRM/Report/Form/Mailing/Detail.php | 487 + CRM/Report/Form/Mailing/Opened.php | 313 + CRM/Report/Form/Mailing/Summary.php | 549 + CRM/Report/Form/Member/ContributionDetail.php | 891 + CRM/Report/Form/Member/Detail.php | 492 + CRM/Report/Form/Member/Lapse.php | 427 + CRM/Report/Form/Member/Summary.php | 604 + CRM/Report/Form/Membership/Summary.php | 431 + CRM/Report/Form/Pledge/Detail.php | 547 + CRM/Report/Form/Pledge/Pbnp.php | 348 + CRM/Report/Form/Pledge/Summary.php | 418 + CRM/Report/Form/Register.php | 190 + CRM/Report/Form/Walklist/Walklist.php | 283 + CRM/Report/Info.php | 94 + CRM/Report/Interface.php | 113 + CRM/Report/Page/Instance.php | 112 + CRM/Report/Page/InstanceList.php | 202 + CRM/Report/Page/List.php | 86 + CRM/Report/Page/Options.php | 226 + CRM/Report/Page/Report.php | 89 + CRM/Report/Page/TemplateList.php | 109 + CRM/Report/Utils/Get.php | 255 + CRM/Report/Utils/Report.php | 483 + CRM/Report/xml/Menu/Report.xml | 73 + CRM/SMS/BAO/Provider.php | 140 + CRM/SMS/Controller/Send.php | 73 + CRM/SMS/Form/Group.php | 365 + CRM/SMS/Form/Provider.php | 194 + CRM/SMS/Form/Schedule.php | 218 + CRM/SMS/Form/Upload.php | 435 + CRM/SMS/Page/Callback.php | 48 + CRM/SMS/Page/Provider.php | 184 + CRM/SMS/Provider.php | 295 + CRM/SMS/StateMachine/Send.php | 62 + CRM/Tag/Form/Tag.php | 150 + CRM/UF/Form/AbstractPreview.php | 130 + CRM/UF/Form/AdvanceSetting.php | 103 + CRM/UF/Form/Field.php | 943 + CRM/UF/Form/Group.php | 380 + CRM/UF/Form/Inline/Preview.php | 80 + CRM/UF/Form/Inline/PreviewById.php | 66 + CRM/UF/Form/Preview.php | 147 + CRM/UF/Page/AJAX.php | 53 + CRM/UF/Page/Field.php | 293 + CRM/UF/Page/Group.php | 473 + CRM/UF/Page/ProfileEditor.php | 230 + .../civicrm_msg_template.tpl | 16 + .../event_online_receipt_html.tpl | 433 + .../event_online_receipt_text.tpl | 227 + .../civicrm_msg_template.tpl | 89 + .../message_templates/case_activity_html.tpl | 83 + .../case_activity_subject.tpl | 1 + .../message_templates/case_activity_text.tpl | 28 + .../contribution_dupalert_html.tpl | 89 + .../contribution_dupalert_subject.tpl | 1 + .../contribution_dupalert_text.tpl | 20 + .../contribution_offline_receipt_html.tpl | 250 + .../contribution_offline_receipt_subject.tpl | 9 + .../contribution_offline_receipt_text.tpl | 94 + .../contribution_online_receipt_html.tpl | 384 + .../contribution_online_receipt_subject.tpl | 1 + .../contribution_online_receipt_text.tpl | 177 + .../contribution_recurring_notify_html.tpl | 71 + .../contribution_recurring_notify_subject.tpl | 1 + .../contribution_recurring_notify_text.tpl | 32 + .../event_offline_receipt_html.tpl | 433 + .../event_offline_receipt_subject.tpl | 1 + .../event_offline_receipt_text.tpl | 226 + .../event_online_receipt_html.tpl | 433 + .../event_online_receipt_subject.tpl | 1 + .../event_online_receipt_text.tpl | 226 + .../message_templates/friend_html.tpl | 40 + .../message_templates/friend_subject.tpl | 1 + .../message_templates/friend_text.tpl | 15 + .../membership_offline_receipt_html.tpl | 203 + .../membership_offline_receipt_subject.tpl | 9 + .../membership_offline_receipt_text.tpl | 70 + .../membership_online_receipt_html.tpl | 490 + .../membership_online_receipt_subject.tpl | 1 + .../membership_online_receipt_text.tpl | 209 + .../participant_cancelled_html.tpl | 153 + .../participant_cancelled_subject.tpl | 1 + .../participant_cancelled_text.tpl | 61 + .../participant_confirm_html.tpl | 165 + .../participant_confirm_subject.tpl | 1 + .../participant_confirm_text.tpl | 68 + .../participant_expired_html.tpl | 156 + .../participant_expired_subject.tpl | 1 + .../participant_expired_text.tpl | 65 + .../message_templates/pcp_notify_html.tpl | 94 + .../message_templates/pcp_notify_subject.tpl | 1 + .../message_templates/pcp_notify_text.tpl | 20 + .../pcp_status_change_html.tpl | 59 + .../pcp_status_change_subject.tpl | 1 + .../pcp_status_change_text.tpl | 47 + .../pcp_supporter_notify_html.tpl | 100 + .../pcp_supporter_notify_subject.tpl | 1 + .../pcp_supporter_notify_text.tpl | 58 + .../pledge_acknowledge_html.tpl | 132 + .../pledge_acknowledge_subject.tpl | 1 + .../pledge_acknowledge_text.tpl | 55 + .../pledge_reminder_html.tpl | 107 + .../pledge_reminder_subject.tpl | 1 + .../pledge_reminder_text.tpl | 33 + .../message_templates/test_preview_html.tpl | 10 + .../test_preview_subject.tpl | 1 + .../message_templates/test_preview_text.tpl | 7 + .../message_templates/uf_notify_html.tpl | 74 + .../message_templates/uf_notify_subject.tpl | 1 + .../message_templates/uf_notify_text.tpl | 11 + .../civicrm_msg_template.tpl | 16 + .../message_templates/case_activity_html.tpl | 83 + .../contribution_dupalert_html.tpl | 89 + .../contribution_offline_receipt_html.tpl | 250 + .../contribution_online_receipt_html.tpl | 384 + .../contribution_recurring_notify_html.tpl | 71 + .../event_offline_receipt_html.tpl | 433 + .../event_online_receipt_html.tpl | 433 + .../message_templates/friend_html.tpl | 40 + .../membership_offline_receipt_html.tpl | 203 + .../membership_online_receipt_html.tpl | 490 + .../participant_cancelled_html.tpl | 153 + .../participant_confirm_html.tpl | 165 + .../participant_confirm_text.tpl | 68 + .../participant_expired_html.tpl | 156 + .../message_templates/pcp_notify_html.tpl | 94 + .../pcp_status_change_html.tpl | 59 + .../pcp_supporter_notify_html.tpl | 100 + .../pledge_acknowledge_html.tpl | 132 + .../pledge_reminder_html.tpl | 107 + .../message_templates/uf_notify_html.tpl | 74 + .../civicrm_msg_template.tpl | 16 + .../contribution_online_receipt_html.tpl | 384 + .../contribution_online_receipt_text.tpl | 177 + .../event_offline_receipt_html.tpl | 433 + .../event_offline_receipt_text.tpl | 226 + .../event_online_receipt_html.tpl | 433 + .../event_online_receipt_text.tpl | 226 + .../membership_online_receipt_html.tpl | 490 + .../membership_online_receipt_text.tpl | 209 + .../participant_cancelled_html.tpl | 153 + .../participant_cancelled_text.tpl | 61 + .../participant_expired_html.tpl | 156 + .../participant_expired_text.tpl | 65 + .../civicrm_msg_template.tpl | 16 + .../contribution_offline_receipt_subject.tpl | 1 + .../membership_offline_receipt_subject.tpl | 5 + .../civicrm_msg_template.tpl | 16 + .../event_online_receipt_text.tpl | 227 + .../pcp_status_change_html.tpl | 59 + .../pcp_status_change_text.tpl | 47 + .../civicrm_msg_template.tpl | 16 + .../contribution_offline_receipt_html.tpl | 261 + .../contribution_offline_receipt_text.tpl | 97 + .../contribution_online_receipt_html.tpl | 384 + .../contribution_online_receipt_text.tpl | 177 + .../civicrm_msg_template.tpl | 16 + .../case_activity_subject.tpl | 1 + .../event_offline_receipt_html.tpl | 453 + .../event_offline_receipt_text.tpl | 270 + .../event_online_receipt_html.tpl | 448 + .../event_online_receipt_text.tpl | 269 + .../civicrm_msg_template.tpl | 16 + .../contribution_offline_receipt_html.tpl | 261 + .../contribution_offline_receipt_text.tpl | 97 + .../3.2.alpha3.languages/languages.tpl | 199 + .../civicrm_msg_template.tpl | 16 + .../message_templates/case_activity_html.tpl | 97 + .../message_templates/case_activity_text.tpl | 35 + .../civicrm_msg_template.tpl | 16 + .../message_templates/case_activity_html.tpl | 104 + .../message_templates/case_activity_text.tpl | 38 + .../contribution_recurring_notify_html.tpl | 71 + .../contribution_recurring_notify_text.tpl | 32 + .../membership_online_receipt_html.tpl | 483 + .../membership_online_receipt_text.tpl | 205 + .../civicrm_msg_template.tpl | 16 + .../contribution_recurring_notify_html.tpl | 82 + .../contribution_recurring_notify_text.tpl | 44 + .../civicrm_msg_template.tpl | 16 + .../petition_confirmation_needed_html.tpl | 10 + .../petition_confirmation_needed_subject.tpl | 1 + .../petition_confirmation_needed_text.tpl | 9 + .../message_templates/petition_sign_html.tpl | 3 + .../petition_sign_subject.tpl | 1 + .../message_templates/petition_sign_text.tpl | 1 + .../civicrm_msg_template.tpl | 16 + .../contribution_offline_receipt_html.tpl | 261 + .../contribution_offline_receipt_text.tpl | 97 + .../contribution_online_receipt_html.tpl | 384 + .../contribution_online_receipt_text.tpl | 177 + .../event_offline_receipt_html.tpl | 460 + .../event_offline_receipt_text.tpl | 277 + .../event_online_receipt_html.tpl | 455 + .../event_online_receipt_text.tpl | 276 + .../petition_confirmation_needed_text.tpl | 8 + .../civicrm_msg_template.tpl | 16 + .../contribution_online_receipt_html.tpl | 387 + .../contribution_online_receipt_text.tpl | 175 + .../membership_online_receipt_html.tpl | 486 + .../membership_online_receipt_text.tpl | 203 + .../civicrm_msg_template.tpl | 16 + .../contribution_online_receipt_html.tpl | 382 + .../event_online_receipt_html.tpl | 421 + .../event_online_receipt_text.tpl | 273 + .../membership_online_receipt_html.tpl | 481 + .../civicrm_msg_template.tpl | 16 + .../membership_offline_receipt_html.tpl | 248 + .../membership_offline_receipt_text.tpl | 92 + .../membership_online_receipt_html.tpl | 520 + .../membership_online_receipt_text.tpl | 220 + .../civicrm_msg_template.tpl | 16 + .../membership_offline_receipt_html.tpl | 240 + .../membership_offline_receipt_text.tpl | 90 + .../membership_online_receipt_html.tpl | 512 + .../membership_online_receipt_text.tpl | 218 + .../civicrm_msg_template.tpl | 59 + .../event_online_receipt_html.tpl | 455 + .../event_online_receipt_text.tpl | 276 + .../petition_confirmation_needed_html.tpl | 10 + .../petition_confirmation_needed_subject.tpl | 1 + .../petition_confirmation_needed_text.tpl | 8 + .../message_templates/petition_sign_html.tpl | 3 + .../petition_sign_subject.tpl | 1 + .../message_templates/petition_sign_text.tpl | 1 + .../civicrm_msg_template.tpl | 16 + .../contribution_online_receipt_html.tpl | 391 + .../event_online_receipt_html.tpl | 472 + .../event_online_receipt_text.tpl | 299 + .../civicrm_msg_template.tpl | 67 + .../contribution_online_receipt_html.tpl | 395 + .../contribution_online_receipt_text.tpl | 179 + .../contribution_recurring_billing_html.tpl | 65 + ...contribution_recurring_billing_subject.tpl | 1 + .../contribution_recurring_billing_text.tpl | 23 + .../contribution_recurring_cancelled_html.tpl | 33 + ...ntribution_recurring_cancelled_subject.tpl | 1 + .../contribution_recurring_cancelled_text.tpl | 3 + .../contribution_recurring_edit_html.tpl | 36 + .../contribution_recurring_edit_subject.tpl | 1 + .../contribution_recurring_edit_text.tpl | 8 + .../contribution_recurring_notify_html.tpl | 125 + .../contribution_recurring_notify_text.tpl | 50 + .../event_online_receipt_html.tpl | 451 + .../event_online_receipt_text.tpl | 285 + .../membership_autorenew_billing_html.tpl | 66 + .../membership_autorenew_billing_subject.tpl | 1 + .../membership_autorenew_billing_text.tpl | 23 + .../membership_autorenew_cancelled_html.tpl | 70 + ...membership_autorenew_cancelled_subject.tpl | 1 + .../membership_autorenew_cancelled_text.tpl | 12 + .../membership_online_receipt_html.tpl | 517 + .../membership_online_receipt_text.tpl | 220 + .../pledge_acknowledge_html.tpl | 132 + .../pledge_acknowledge_text.tpl | 55 + .../pledge_reminder_html.tpl | 107 + .../pledge_reminder_text.tpl | 33 + .../civicrm_msg_template.tpl | 16 + .../event_offline_receipt_html.tpl | 459 + .../event_offline_receipt_text.tpl | 277 + .../event_online_receipt_html.tpl | 460 + .../event_online_receipt_text.tpl | 289 + .../membership_offline_receipt_text.tpl | 90 + .../civicrm_msg_template.tpl | 16 + .../contribution_online_receipt_text.tpl | 179 + .../civicrm_msg_template.tpl | 16 + .../event_online_receipt_html.tpl | 453 + .../event_online_receipt_text.tpl | 280 + .../civicrm_msg_template.tpl | 16 + .../contribution_offline_receipt_html.tpl | 261 + .../contribution_offline_receipt_text.tpl | 97 + .../event_offline_receipt_html.tpl | 459 + .../event_offline_receipt_text.tpl | 277 + .../event_online_receipt_html.tpl | 453 + .../event_online_receipt_text.tpl | 280 + .../membership_offline_receipt_html.tpl | 240 + .../membership_offline_receipt_text.tpl | 90 + .../membership_online_receipt_html.tpl | 514 + .../membership_online_receipt_text.tpl | 221 + .../civicrm_msg_template.tpl | 16 + .../event_online_receipt_html.tpl | 453 + .../event_online_receipt_text.tpl | 280 + .../message_templates/pcp_notify_html.tpl | 96 + .../civicrm_msg_template.tpl | 16 + .../contribution_online_receipt_html.tpl | 394 + .../contribution_online_receipt_text.tpl | 179 + .../membership_online_receipt_html.tpl | 514 + .../membership_online_receipt_text.tpl | 221 + CRM/Upgrade/Controller.php | 59 + CRM/Upgrade/Form.php | 652 + CRM/Upgrade/Headless.php | 83 + CRM/Upgrade/Incremental/Legacy.php | 532 + CRM/Upgrade/Incremental/php/FourOne.php | 403 + CRM/Upgrade/Incremental/php/FourThree.php | 679 + CRM/Upgrade/Incremental/php/FourTwo.php | 897 + CRM/Upgrade/Incremental/php/FourZero.php | 44 + CRM/Upgrade/Incremental/php/ThreeFour.php | 342 + CRM/Upgrade/Incremental/php/ThreeThree.php | 386 + CRM/Upgrade/Incremental/php/ThreeTwo.php | 272 + CRM/Upgrade/Incremental/sql/2.1.2.mysql | 20 + CRM/Upgrade/Incremental/sql/2.2.0.mysql.tpl | 11 + CRM/Upgrade/Incremental/sql/2.2.1.mysql.tpl | 40 + CRM/Upgrade/Incremental/sql/2.2.3.mysql.tpl | 39 + CRM/Upgrade/Incremental/sql/2.2.6.mysql.tpl | 3 + CRM/Upgrade/Incremental/sql/2.2.7.mysql.tpl | 121 + .../Incremental/sql/2.2.alpha1.mysql.tpl | 684 + .../Incremental/sql/2.2.alpha3.mysql.tpl | 75 + .../Incremental/sql/2.2.beta1.mysql.tpl | 16 + .../Incremental/sql/2.2.beta2.mysql.tpl | 37 + .../Incremental/sql/2.2.beta3.mysql.tpl | 56 + .../Incremental/sql/2.2.beta4.mysql.tpl | 8 + CRM/Upgrade/Incremental/sql/3.0.0.mysql.tpl | 85 + CRM/Upgrade/Incremental/sql/3.0.1.mysql.tpl | 7 + CRM/Upgrade/Incremental/sql/3.0.2.mysql.tpl | 11 + CRM/Upgrade/Incremental/sql/3.0.3.mysql.tpl | 64 + CRM/Upgrade/Incremental/sql/3.0.4.mysql.tpl | 15 + CRM/Upgrade/Incremental/sql/3.0.5.mysql.tpl | 2 + .../Incremental/sql/3.0.alpha1.mysql.tpl | 904 + .../Incremental/sql/3.0.alpha2.mysql.tpl | 10 + .../Incremental/sql/3.0.alpha3.mysql.tpl | 3 + .../Incremental/sql/3.0.beta1.mysql.tpl | 52 + .../Incremental/sql/3.0.beta2.mysql.tpl | 12 + .../Incremental/sql/3.0.beta4.mysql.tpl | 69 + .../Incremental/sql/3.0.beta5.mysql.tpl | 2 + CRM/Upgrade/Incremental/sql/3.1.0.mysql.tpl | 26 + CRM/Upgrade/Incremental/sql/3.1.3.mysql.tpl | 30 + CRM/Upgrade/Incremental/sql/3.1.4.mysql.tpl | 33 + CRM/Upgrade/Incremental/sql/3.1.5.mysql.tpl | 32 + .../Incremental/sql/3.1.alpha1.mysql.tpl | 281 + .../Incremental/sql/3.1.alpha2.mysql.tpl | 24 + .../Incremental/sql/3.1.beta1.mysql.tpl | 109 + .../Incremental/sql/3.1.beta2.mysql.tpl | 109 + .../Incremental/sql/3.1.beta3.mysql.tpl | 6 + .../Incremental/sql/3.1.beta4.mysql.tpl | 14 + .../Incremental/sql/3.1.beta5.mysql.tpl | 32 + .../Incremental/sql/3.1.beta6.mysql.tpl | 27 + CRM/Upgrade/Incremental/sql/3.2.0.mysql.tpl | 3 + CRM/Upgrade/Incremental/sql/3.2.1.mysql.tpl | 50 + CRM/Upgrade/Incremental/sql/3.2.2.mysql.tpl | 39 + CRM/Upgrade/Incremental/sql/3.2.3.mysql.tpl | 30 + CRM/Upgrade/Incremental/sql/3.2.4.mysql.tpl | 11 + CRM/Upgrade/Incremental/sql/3.2.5.mysql.tpl | 2 + .../Incremental/sql/3.2.alpha1.mysql.tpl | 300 + .../Incremental/sql/3.2.alpha2.mysql.tpl | 3 + .../Incremental/sql/3.2.alpha3.mysql.tpl | 146 + .../Incremental/sql/3.2.alpha4.mysql.tpl | 42 + .../Incremental/sql/3.2.beta1.mysql.tpl | 28 + .../Incremental/sql/3.2.beta3.mysql.tpl | 39 + .../Incremental/sql/3.2.beta4.mysql.tpl | 66 + .../Incremental/sql/3.2.beta5.mysql.tpl | 22 + CRM/Upgrade/Incremental/sql/3.3.0.mysql.tpl | 280 + CRM/Upgrade/Incremental/sql/3.3.1.mysql.tpl | 9 + CRM/Upgrade/Incremental/sql/3.3.2.mysql.tpl | 118 + CRM/Upgrade/Incremental/sql/3.3.3.mysql.tpl | 5 + CRM/Upgrade/Incremental/sql/3.3.4.mysql.tpl | 64 + CRM/Upgrade/Incremental/sql/3.3.6.mysql.tpl | 17 + CRM/Upgrade/Incremental/sql/3.3.7.mysql.tpl | 8 + .../Incremental/sql/3.3.alpha1.mysql.tpl | 342 + .../Incremental/sql/3.3.alpha2.mysql.tpl | 16 + .../Incremental/sql/3.3.beta1.mysql.tpl | 108 + .../Incremental/sql/3.3.beta2.mysql.tpl | 48 + .../Incremental/sql/3.3.beta3.mysql.tpl | 3 + CRM/Upgrade/Incremental/sql/3.4.0.mysql.tpl | 15 + CRM/Upgrade/Incremental/sql/3.4.1.mysql.tpl | 63 + CRM/Upgrade/Incremental/sql/3.4.2.mysql.tpl | 112 + CRM/Upgrade/Incremental/sql/3.4.3.mysql.tpl | 139 + CRM/Upgrade/Incremental/sql/3.4.5.mysql.tpl | 99 + CRM/Upgrade/Incremental/sql/3.4.6.mysql.tpl | 97 + CRM/Upgrade/Incremental/sql/3.4.7.mysql.tpl | 2 + .../Incremental/sql/3.4.alpha1.mysql.tpl | 130 + .../Incremental/sql/3.4.alpha2.mysql.tpl | 57 + .../Incremental/sql/3.4.alpha3.mysql.tpl | 27 + .../Incremental/sql/3.4.beta1.mysql.tpl | 20 + .../Incremental/sql/3.4.beta2.mysql.tpl | 14 + .../Incremental/sql/3.4.beta3.mysql.tpl | 31 + CRM/Upgrade/Incremental/sql/4.1.0.mysql.tpl | 9 + CRM/Upgrade/Incremental/sql/4.1.1.mysql.tpl | 20 + CRM/Upgrade/Incremental/sql/4.1.2.mysql.tpl | 22 + CRM/Upgrade/Incremental/sql/4.1.3.mysql.tpl | 5 + .../Incremental/sql/4.1.alpha1.mysql.tpl | 529 + .../Incremental/sql/4.1.alpha2.mysql.tpl | 12 + .../Incremental/sql/4.1.beta1.mysql.tpl | 11 + .../Incremental/sql/4.1.beta2.mysql.tpl | 119 + .../Incremental/sql/4.1.beta3.mysql.tpl | 33 + CRM/Upgrade/Incremental/sql/4.2.0.mysql.tpl | 34 + CRM/Upgrade/Incremental/sql/4.2.1.mysql.tpl | 4 + CRM/Upgrade/Incremental/sql/4.2.2.mysql.tpl | 21 + CRM/Upgrade/Incremental/sql/4.2.3.mysql.tpl | 49 + CRM/Upgrade/Incremental/sql/4.2.5.mysql.tpl | 10 + CRM/Upgrade/Incremental/sql/4.2.6.mysql.tpl | 2 + CRM/Upgrade/Incremental/sql/4.2.7.mysql.tpl | 15 + CRM/Upgrade/Incremental/sql/4.2.8.mysql.tpl | 2 + CRM/Upgrade/Incremental/sql/4.2.9.mysql.tpl | 2 + .../Incremental/sql/4.2.alpha1.mysql.tpl | 400 + .../Incremental/sql/4.2.alpha2.mysql.tpl | 9 + .../Incremental/sql/4.2.alpha3.mysql.tpl | 2 + .../Incremental/sql/4.2.beta1.mysql.tpl | 37 + .../Incremental/sql/4.2.beta2.mysql.tpl | 1 + .../Incremental/sql/4.2.beta3.mysql.tpl | 2 + .../Incremental/sql/4.2.beta5.mysql.tpl | 1 + .../Incremental/sql/4.2.beta6.mysql.tpl | 23 + .../Incremental/sql/4.3.alpha1.mysql.tpl | 890 + .../Incremental/sql/4.3.alpha2.mysql.tpl | 40 + .../Incremental/sql/4.3.alpha3.mysql.tpl | 4 + .../Incremental/sql/4.3.beta1.mysql.tpl | 1 + CRM/Upgrade/Incremental/sql/README.txt | 98 + CRM/Upgrade/Page/Cleanup.php | 48 + CRM/Upgrade/Page/Upgrade.php | 201 + CRM/Upgrade/Snapshot/V4p2/Price/BAO/Field.php | 623 + .../Snapshot/V4p2/Price/BAO/FieldValue.php | 222 + .../Snapshot/V4p2/Price/BAO/LineItem.php | 300 + CRM/Upgrade/Snapshot/V4p2/Price/BAO/Set.php | 1104 + CRM/Upgrade/Snapshot/V4p2/Price/DAO/Field.php | 446 + .../Snapshot/V4p2/Price/DAO/FieldValue.php | 339 + .../Snapshot/V4p2/Price/DAO/LineItem.php | 315 + CRM/Upgrade/Snapshot/V4p2/Price/DAO/Set.php | 339 + .../Snapshot/V4p2/Price/DAO/SetEntity.php | 240 + CRM/Upgrade/StateMachine.php | 58 + CRM/Upgrade/ThreeOne/ThreeOne.php | 351 + CRM/Upgrade/ThreeZero/ThreeZero.php | 286 + CRM/Upgrade/TwoOne/Controller.php | 46 + CRM/Upgrade/TwoOne/Form/Step1.php | 307 + CRM/Upgrade/TwoOne/Form/Step2.php | 151 + CRM/Upgrade/TwoOne/Form/Step3.php | 126 + CRM/Upgrade/TwoOne/Form/Step4.php | 95 + CRM/Upgrade/TwoOne/Form/TwoOneTwo.php | 146 + CRM/Upgrade/TwoOne/Page/Upgrade.php | 138 + CRM/Upgrade/TwoOne/sql/domain_ids.mysql | 335 + CRM/Upgrade/TwoOne/sql/group_values.mysql | 261 + CRM/Upgrade/TwoOne/sql/misc.mysql | 620 + CRM/Upgrade/TwoOne/sql/two_one_two.mysql | 20 + CRM/Upgrade/TwoTwo/Controller.php | 46 + CRM/Upgrade/TwoTwo/Form/Step1.php | 196 + CRM/Upgrade/TwoTwo/Form/Step2.php | 121 + CRM/Upgrade/TwoTwo/Form/Step3.php | 297 + CRM/Upgrade/TwoTwo/Form/Step4.php | 108 + CRM/Utils/Address.php | 299 + CRM/Utils/Address/BatchUpdate.php | 260 + CRM/Utils/Address/USPS.php | 121 + CRM/Utils/Array.php | 619 + CRM/Utils/Cache.php | 166 + CRM/Utils/Cache/APCcache.php | 101 + CRM/Utils/Cache/ArrayCache.php | 37 + CRM/Utils/Cache/Interface.php | 68 + CRM/Utils/Cache/Memcache.php | 130 + CRM/Utils/Cache/Memcached.php | 144 + CRM/Utils/Cache/NoCache.php | 73 + CRM/Utils/Cache/SerializeCache.php | 68 + CRM/Utils/Cache/SqlGroup.php | 112 + CRM/Utils/Constant.php | 44 + CRM/Utils/Crypt.php | 87 + CRM/Utils/Date.php | 1538 + CRM/Utils/DeprecatedUtils.php | 1612 + CRM/Utils/File.php | 602 + CRM/Utils/Geocode/Google.php | 159 + CRM/Utils/Geocode/Yahoo.php | 208 + CRM/Utils/Hook.php | 1227 + CRM/Utils/Hook/Drupal.php | 114 + CRM/Utils/Hook/Drupal6.php | 116 + CRM/Utils/Hook/Joomla.php | 93 + CRM/Utils/Hook/Soap.php | 56 + CRM/Utils/Hook/UnitTests.php | 85 + CRM/Utils/Hook/WordPress.php | 50 + CRM/Utils/HttpClient.php | 97 + CRM/Utils/ICalendar.php | 127 + CRM/Utils/JS.php | 66 + CRM/Utils/JSON.php | 135 + CRM/Utils/Mail.php | 364 + CRM/Utils/Mail/EmailProcessor.php | 398 + CRM/Utils/Mail/Incoming.php | 360 + CRM/Utils/Migrate/Export.php | 406 + CRM/Utils/Migrate/ExportJSON.php | 580 + CRM/Utils/Migrate/Import.php | 389 + CRM/Utils/Migrate/ImportJSON.php | 260 + CRM/Utils/Money.php | 124 + CRM/Utils/OpenFlashChart.php | 515 + CRM/Utils/PDF/Label.php | 260 + CRM/Utils/PDF/Utils.php | 317 + CRM/Utils/Pager.php | 339 + CRM/Utils/PagerAToZ.php | 164 + CRM/Utils/PseudoConstant.php | 160 + CRM/Utils/REST.php | 689 + CRM/Utils/ReCAPTCHA.php | 123 + CRM/Utils/Recent.php | 204 + CRM/Utils/Request.php | 125 + CRM/Utils/Rule.php | 607 + CRM/Utils/Signer.php | 126 + CRM/Utils/SoapServer.php | 255 + CRM/Utils/Sort.php | 287 + CRM/Utils/String.php | 635 + CRM/Utils/Sunlight.php | 148 + CRM/Utils/System.php | 1529 + CRM/Utils/System/Base.php | 104 + CRM/Utils/System/Drupal.php | 1027 + CRM/Utils/System/Drupal6.php | 931 + CRM/Utils/System/Joomla.php | 672 + CRM/Utils/System/Soap.php | 199 + CRM/Utils/System/UnitTests.php | 178 + CRM/Utils/System/WordPress.php | 607 + CRM/Utils/Time.php | 90 + CRM/Utils/Token.php | 1284 + CRM/Utils/Tree.php | 245 + CRM/Utils/Type.php | 332 + CRM/Utils/Verp.php | 116 + CRM/Utils/VersionCheck.php | 307 + CRM/Utils/Weight.php | 464 + CRM/Utils/Wrapper.php | 119 + CRM/Utils/XML.php | 136 + CRM/Utils/Zip.php | 139 + CRM/Widget/Widget.php | 192 + README.txt | 65 + Sponsors.txt | 229 + agpl-3.0.exception.txt | 17 + agpl-3.0.txt | 662 + api/Exception.php | 49 + api/Wrapper.php | 14 + api/api.php | 537 + api/class.api.php | 282 + api/v2/Activity.php | 554 + api/v2/ActivityContact.php | 117 + api/v2/ActivityType.php | 113 + api/v2/Case.php | 626 + api/v2/Constant.php | 113 + api/v2/Contact.php | 855 + api/v2/Contribute.php | 41 + api/v2/Contribution.php | 578 + api/v2/CustomGroup.php | 247 + api/v2/Domain.php | 107 + api/v2/EntityTag.php | 230 + api/v2/Event.php | 264 + api/v2/File.php | 331 + api/v2/Group.php | 153 + api/v2/GroupContact.php | 199 + api/v2/GroupNesting.php | 155 + api/v2/GroupOrganization.php | 148 + api/v2/Location.php | 978 + api/v2/Mailer.php | 389 + api/v2/Membership.php | 129 + api/v2/MembershipContact.php | 418 + api/v2/MembershipContributionLink.php | 131 + api/v2/MembershipStatus.php | 260 + api/v2/MembershipType.php | 211 + api/v2/Note.php | 221 + api/v2/Participant.php | 362 + api/v2/ParticipantPayment.php | 146 + api/v2/Pledge.php | 470 + api/v2/PledgePayment.php | 483 + api/v2/Relationship.php | 470 + api/v2/RelationshipType.php | 194 + api/v2/SurveyRespondant.php | 91 + api/v2/Tag.php | 165 + api/v2/UFGroup.php | 464 + api/v2/UFJoin.php | 154 + api/v2/utils.php | 8 + api/v2/utils.v2.php | 1599 + api/v3/Activity.php | 425 + api/v3/ActivityType.php | 128 + api/v3/Address.php | 139 + api/v3/Batch.php | 78 + api/v3/Campaign.php | 99 + api/v3/Case.php | 436 + api/v3/Constant.php | 181 + api/v3/Contact.php | 886 + api/v3/ContactType.php | 101 + api/v3/Contribution.php | 379 + api/v3/ContributionPage.php | 93 + api/v3/ContributionRecur.php | 95 + api/v3/CustomField.php | 271 + api/v3/CustomGroup.php | 131 + api/v3/CustomSearch.php | 75 + api/v3/CustomValue.php | 236 + api/v3/Domain.php | 147 + api/v3/Email.php | 102 + api/v3/Entity.php | 68 + api/v3/EntityTag.php | 195 + api/v3/Event.php | 222 + api/v3/Extension.php | 278 + api/v3/File.php | 168 + api/v3/Generic.php | 275 + api/v3/Generic/Getactions.php | 26 + api/v3/Generic/Setvalue.php | 76 + api/v3/Generic/Update.php | 25 + api/v3/Grant.php | 101 + api/v3/Group.php | 145 + api/v3/GroupContact.php | 236 + api/v3/GroupNesting.php | 99 + api/v3/GroupOrganization.php | 109 + api/v3/Im.php | 89 + api/v3/Job.php | 599 + api/v3/LineItem.php | 95 + api/v3/LocBlock.php | 137 + api/v3/Location.php | 20 + api/v3/LocationType.php | 108 + api/v3/MailSettings.php | 94 + api/v3/Mailing.php | 270 + api/v3/MailingEventConfirm.php | 75 + api/v3/MailingEventResubscribe.php | 80 + api/v3/MailingEventSubscribe.php | 91 + api/v3/MailingEventUnsubscribe.php | 88 + api/v3/MailingGroup.php | 119 + api/v3/MailingJob.php | 77 + api/v3/MailingRecipients.php | 57 + api/v3/Membership.php | 340 + api/v3/MembershipPayment.php | 104 + api/v3/MembershipStatus.php | 196 + api/v3/MembershipType.php | 121 + api/v3/Note.php | 157 + api/v3/OptionGroup.php | 47 + api/v3/OptionValue.php | 122 + api/v3/Participant.php | 205 + api/v3/ParticipantPayment.php | 115 + api/v3/ParticipantStatusType.php | 98 + api/v3/PaymentProcessorType.php | 124 + api/v3/Phone.php | 106 + api/v3/Phone/Get.php | 21 + api/v3/Pledge.php | 211 + api/v3/PledgePayment.php | 150 + api/v3/PriceField.php | 90 + api/v3/PriceFieldValue.php | 100 + api/v3/PriceSet.php | 110 + api/v3/Profile.php | 331 + api/v3/Relationship.php | 281 + api/v3/RelationshipType.php | 136 + api/v3/ReportTemplate.php | 172 + api/v3/Setting.php | 329 + api/v3/Survey.php | 95 + api/v3/SurveyRespondant.php | 96 + api/v3/System.php | 72 + api/v3/Tag.php | 113 + api/v3/UFField.php | 178 + api/v3/UFGroup.php | 109 + api/v3/UFJoin.php | 88 + api/v3/UFMatch.php | 99 + api/v3/Website.php | 117 + .../Activity/ContactRefCustomField.php | 91 + .../Activity/ContactRefCustomFieldGet.php | 84 + api/v3/examples/Activity/DateTimeHigh.php | 73 + api/v3/examples/Activity/DateTimeLow.php | 72 + .../Activity/GetTargetandAssignee.php | 92 + .../Activity/ReturnAssigneeContact.php | 150 + api/v3/examples/ActivityCreate.php | 88 + api/v3/examples/ActivityDelete.php | 53 + api/v3/examples/ActivityGet.php | 72 + api/v3/examples/ActivityGetFields.php | 292 + api/v3/examples/ActivityTypeCreate.php | 78 + api/v3/examples/ActivityTypeDelete.php | 51 + api/v3/examples/ActivityTypeGet.php | 97 + api/v3/examples/Address/AddressLike.php | 72 + api/v3/examples/Address/AddressParse.php | 71 + api/v3/examples/Address/AddressSort.php | 91 + api/v3/examples/AddressCreate.php | 77 + api/v3/examples/AddressDelete.php | 61 + api/v3/examples/AddressGet.php | 70 + api/v3/examples/BatchCreate.php | 78 + api/v3/examples/BatchDelete.php | 53 + api/v3/examples/BatchGet.php | 61 + api/v3/examples/BatchUpdate.php | 78 + api/v3/examples/CampaignCreate.php | 76 + api/v3/examples/CampaignDelete.php | 53 + api/v3/examples/CampaignGet.php | 65 + api/v3/examples/ConstantGet.php | 59 + api/v3/examples/Contact/APIChainedArray.php | 205 + .../Contact/APIChainedArrayFormats.php | 141 + .../Contact/APIChainedArrayMultipleCustom.php | 186 + ...IChainedArrayValuesFromSiblingFunction.php | 121 + api/v3/examples/Contact/ChainTwoWebsites.php | 192 + .../Contact/ChainTwoWebsitesSyntax2.php | 197 + api/v3/examples/Contact/CustomFieldCreate.php | 107 + api/v3/examples/Contact/CustomFieldGet.php | 64 + .../CustomFieldGetReturnSyntaxVariation.php | 62 + .../examples/Contact/FormatIsSuccess_Fail.php | 50 + .../examples/Contact/FormatIsSuccess_True.php | 50 + api/v3/examples/Contact/FormatOnlyID.php | 51 + api/v3/examples/Contact/FormatSingleValue.php | 51 + api/v3/examples/Contact/GetCountContact.php | 49 + api/v3/examples/Contact/GetFieldsOptions.php | 611 + api/v3/examples/Contact/GetSingleContact.php | 112 + .../Contact/GroupFilterUsingContactAPI.php | 122 + api/v3/examples/ContactCreate.php | 193 + api/v3/examples/ContactDelete.php | 53 + api/v3/examples/ContactGet.php | 118 + api/v3/examples/ContactGetoptions.php | 56 + .../ContributionCreateWithNote.php | 97 + .../ContributionCreateWithSoftCredit.php | 94 + .../CreateWithNestedLineItems.php | 157 + api/v3/examples/ContributionCreate.php | 93 + api/v3/examples/ContributionDelete.php | 56 + api/v3/examples/ContributionGet.php | 103 + api/v3/examples/ContributionPageCreate.php | 108 + api/v3/examples/ContributionPageDelete.php | 53 + api/v3/examples/ContributionPageGet.php | 77 + api/v3/examples/ContributionRecurCreate.php | 91 + api/v3/examples/ContributionRecurDelete.php | 53 + api/v3/examples/ContributionRecurGet.php | 72 + api/v3/examples/CustomFieldCreate.php | 90 + api/v3/examples/CustomFieldDelete.php | 53 + api/v3/examples/CustomGroupCreate.php | 86 + api/v3/examples/CustomGroupDelete.php | 53 + api/v3/examples/CustomGroupGet.php | 69 + .../examples/CustomValue/formatFieldName.php | 83 + api/v3/examples/CustomValueCreate.php | 54 + api/v3/examples/CustomValueGet.php | 103 + api/v3/examples/DomainCreate.php | 68 + api/v3/examples/DomainGet.php | 102 + api/v3/examples/Email/NestedReplaceEmail.php | 224 + api/v3/examples/EmailCreate.php | 72 + api/v3/examples/EmailDelete.php | 56 + api/v3/examples/EmailReplace.php | 151 + api/v3/examples/EntityTagCreate.php | 54 + api/v3/examples/EntityTagDelete.php | 54 + api/v3/examples/EntityTagGet.php | 0 api/v3/examples/Event/IsCurrentOption.php | 88 + api/v3/examples/Event/IsFullOption.php | 75 + api/v3/examples/EventCreate.php | 134 + api/v3/examples/EventDelete.php | 53 + api/v3/examples/EventGet.php | 79 + api/v3/examples/EventUpdate.php | 122 + api/v3/examples/GrantCreate.php | 79 + api/v3/examples/GrantDelete.php | 60 + api/v3/examples/GrantGet.php | 73 + api/v3/examples/Group/getfields.php | 170 + api/v3/examples/GroupContact.php | 32 + .../examples/GroupContact/GetWithGroupID.php | 132 + api/v3/examples/GroupContactCreate.php | 58 + api/v3/examples/GroupContactDelete.php | 57 + api/v3/examples/GroupContactGet.php | 64 + api/v3/examples/GroupGet.php | 79 + api/v3/examples/GroupNestingCreate.php | 57 + api/v3/examples/GroupNestingDelete.php | 53 + api/v3/examples/GroupNestingGet.php | 61 + api/v3/examples/GroupOrganizationCreate.php | 59 + api/v3/examples/GroupOrganizationDelete.php | 53 + api/v3/examples/GroupOrganizationGet.php | 53 + api/v3/examples/ImCreate.php | 67 + api/v3/examples/ImDelete.php | 53 + api/v3/examples/ImGet.php | 67 + api/v3/examples/JobCreate.php | 74 + api/v3/examples/JobDelete.php | 53 + api/v3/examples/LineItemCreate.php | 90 + api/v3/examples/LineItemDelete.php | 53 + api/v3/examples/LineItemGet.php | 68 + api/v3/examples/LocBlockCreate.php | 68 + api/v3/examples/LocBlockCreateEntities.php | 127 + api/v3/examples/LocBlockGet.php | 88 + .../MailSettings/ChainedGetDelete.php | 85 + api/v3/examples/MailSettingsCreate.php | 77 + api/v3/examples/MailSettingsDelete.php | 59 + api/v3/examples/MailSettingsGet.php | 72 + api/v3/examples/MailingCreate.php | 116 + api/v3/examples/MailingGroupSubscribe.php | 62 + .../examples/Membership/filterIsCurrent.php | 80 + api/v3/examples/MembershipCreate.php | 80 + api/v3/examples/MembershipDelete.php | 53 + api/v3/examples/MembershipGet.php | 72 + api/v3/examples/MembershipPaymentCreate.php | 61 + api/v3/examples/MembershipPaymentGet.php | 61 + api/v3/examples/MembershipStatusCreate.php | 72 + api/v3/examples/MembershipStatusGet.php | 67 + api/v3/examples/MembershipTypeCreate.php | 87 + api/v3/examples/MembershipTypeDelete.php | 53 + api/v3/examples/MembershipTypeGet.php | 69 + api/v3/examples/MembershipUpdate.php | 80 + api/v3/examples/NoteCreate.php | 70 + api/v3/examples/NoteDelete.php | 53 + api/v3/examples/NoteGet.php | 70 + api/v3/examples/OptionGroupCreate.php | 74 + api/v3/examples/OptionGroupGet.php | 62 + api/v3/examples/OptionValue/SortOption.php | 62 + api/v3/examples/OptionValueGet.php | 109 + .../Participant/CreateParticipantPayment.php | 136 + api/v3/examples/Participant/NestedDelete.php | 123 + .../examples/Participant/NestedEventGet.php | 125 + api/v3/examples/ParticipantCreate.php | 81 + api/v3/examples/ParticipantGet.php | 83 + api/v3/examples/ParticipantPaymentCreate.php | 61 + api/v3/examples/ParticipantPaymentDelete.php | 53 + api/v3/examples/ParticipantPaymentGet.php | 61 + .../examples/ParticipantStatusTypeCreate.php | 73 + .../examples/ParticipantStatusTypeDelete.php | 60 + api/v3/examples/ParticipantStatusTypeGet.php | 73 + .../examples/PaymentProcessorTypeCreate.php | 84 + .../examples/PaymentProcessorTypeDelete.php | 53 + api/v3/examples/PhoneCreate.php | 70 + api/v3/examples/PhoneDelete.php | 56 + api/v3/examples/PhoneGet.php | 65 + api/v3/examples/Pledge/GetFilterHighDate.php | 78 + api/v3/examples/PledgeCreate.php | 94 + api/v3/examples/PledgeDelete.php | 56 + api/v3/examples/PledgeGet.php | 78 + api/v3/examples/PledgePaymentCreate.php | 71 + api/v3/examples/PledgePaymentDelete.php | 56 + api/v3/examples/PledgePaymentGet.php | 98 + api/v3/examples/PledgePaymentUpdate.php | 70 + api/v3/examples/PriceFieldCreate.php | 79 + api/v3/examples/PriceFieldDelete.php | 53 + api/v3/examples/PriceFieldGet.php | 69 + api/v3/examples/PriceFieldValueCreate.php | 79 + api/v3/examples/PriceFieldValueDelete.php | 53 + api/v3/examples/PriceFieldValueGet.php | 67 + api/v3/examples/PriceSetCreate.php | 77 + api/v3/examples/PriceSetDelete.php | 53 + api/v3/examples/PriceSetGet.php | 65 + api/v3/examples/PriceSetSet.php | 73 + api/v3/examples/ProfileApply.php | 91 + api/v3/examples/ProfileGet.php | 61 + api/v3/examples/ProfileSet.php | 111 + .../Relationship/BetweenRelationshipType.php | 110 + .../Relationship/INRelationshipType.php | 93 + .../NotBetweenRelationshipType.php | 77 + .../Relationship/NotInRelationshipType.php | 93 + .../examples/Relationship/filterIsCurrent.php | 74 + api/v3/examples/RelationshipCreate.php | 65 + api/v3/examples/RelationshipDelete.php | 63 + api/v3/examples/RelationshipGet.php | 74 + api/v3/examples/RelationshipTypeCreate.php | 75 + api/v3/examples/RelationshipTypeDelete.php | 53 + api/v3/examples/Setting/CreateAllDomains.php | 70 + .../Setting/CreateSettingCurrentDomain.php | 58 + .../Setting/CreateSpecifiedDomains.php | 64 + api/v3/examples/Setting/GetAllDomains.php | 64 + api/v3/examples/Setting/GetDefaults.php | 63 + .../Setting/GetSettingCurrentDomain.php | 58 + .../examples/Setting/GetSpecifiedDomains.php | 66 + api/v3/examples/SettingCreate.php | 59 + api/v3/examples/SettingGet.php | 59 + api/v3/examples/SettingGetValue.php | 49 + api/v3/examples/SettingGetfields.php | 1290 + api/v3/examples/SettingRevert.php | 69 + api/v3/examples/Survey/ChainedGetDelete.php | 73 + api/v3/examples/SurveyCreate.php | 79 + api/v3/examples/SurveyDelete.php | 56 + api/v3/examples/SurveyGet.php | 69 + api/v3/examples/SurveyRespondantGet.php | 54 + api/v3/examples/System/Flush.php | 52 + api/v3/examples/Tag/getReturnArray.php | 63 + api/v3/examples/TagCreate.php | 68 + api/v3/examples/TagDelete.php | 53 + api/v3/examples/TagGet.php | 66 + api/v3/examples/UFFieldCreate.php | 84 + api/v3/examples/UFFieldDelete.php | 53 + api/v3/examples/UFFieldGet.php | 71 + api/v3/examples/UFFieldReplace.php | 147 + api/v3/examples/UFGroupCreate.php | 98 + api/v3/examples/UFGroupDelete.php | 72 + api/v3/examples/UFGroupGet.php | 98 + api/v3/examples/UFJoinCreate.php | 70 + api/v3/examples/UFJoinGet.php | 66 + api/v3/examples/UFMatchGet.php | 61 + api/v3/examples/WebsiteCreate.php | 63 + api/v3/examples/WebsiteDelete.php | 53 + api/v3/examples/WebsiteGet.php | 63 + api/v3/utils.php | 1542 + bin/ContributionProcessor.php | 426 + bin/cleanup42.php | 69 + bin/cli.class.php | 395 + bin/cli.php | 31 + bin/cron.php | 55 + bin/csv/delete.php | 41 + bin/csv/export.php | 40 + bin/csv/import.php | 39 + bin/deprecated/CiviReportMail.php | 75 + bin/deprecated/EmailProcessor.php | 111 + bin/deprecated/ParticipantProcessor.php | 261 + bin/deprecated/RespondentProcessor.php | 105 + bin/deprecated/UpdateAddress.php | 276 + bin/deprecated/UpdateGreeting.php | 233 + bin/deprecated/UpdateMembershipRecord.php | 81 + .../UpdateMembershipReminderDate.php | 110 + bin/deprecated/UpdatePledgeRecord.php | 295 + bin/deprecated/action.cronjob.php | 68 + bin/deprecated/civimail.cronjob.php | 67 + bin/encryptDB.php | 103 + bin/migrate/export.php | 52 + bin/migrate/exportJSON.php | 53 + bin/migrate/import.php | 61 + bin/migrate/importJSON.php | 52 + bin/migrate/move.php | 46 + bin/regen.sh | 56 + bin/regen.sh.txt | 56 + bin/setup.conf.txt | 44 + bin/setup.sh | 101 + bin/setup.sh.txt | 99 + css/Audit/style.css | 141 + css/arrow.png | Bin 0 -> 273 bytes css/bg_button_a.gif | Bin 0 -> 581 bytes css/bg_button_span.gif | Bin 0 -> 1425 bytes css/bluemarine.css | 359 + css/civicrm-new.css | 55 + css/civicrm.css | 3917 ++ css/crm.designer.css | 224 + css/drupal.css | 554 + css/extras.css | 7 + css/joomla.css | 517 + css/joomla_frontend.css | 10 + css/menu-collapsed.png | Bin 0 -> 108 bytes css/menu-expanded.png | Bin 0 -> 106 bytes css/menu-leaf.png | Bin 0 -> 108 bytes css/print.css | 121 + distmaker/distmaker.conf.dist | 8 + distmaker/distmaker.sh | 191 + distmaker/dists/drupal6_php5.sh | 94 + distmaker/dists/drupal_php5.sh | 77 + distmaker/dists/drupal_sk_php5.sh | 86 + distmaker/dists/joomla_php5.sh | 124 + distmaker/dists/l10n.sh | 56 + distmaker/dists/wordpress_php5.sh | 89 + distmaker/utils/joomlaxml.php | 107 + extern/authorizeIPN.php | 40 + extern/googleNotify.php | 41 + extern/ipn.php | 71 + extern/open.php | 28 + extern/pxIPN.php | 51 + extern/rest.php | 43 + extern/soap.php | 60 + extern/url.php | 57 + extern/widget.php | 59 + gpl.txt | 347 + header-afl.txt | 4 + header-agpl.txt | 23 + header.sql | 23 + header.tpl | 25 + header.txt | 37 + i/BarGraph.png | Bin 0 -> 345 bytes i/Bulb.png | Bin 0 -> 641 bytes i/EnvelopeIn.gif | Bin 0 -> 991 bytes i/Error.gif | Bin 0 -> 214 bytes i/Eyeball.gif | Bin 0 -> 1065 bytes i/Inform.gif | Bin 0 -> 1022 bytes i/TreeMinus.gif | Bin 0 -> 67 bytes i/TreeMinusWhite.gif | Bin 0 -> 67 bytes i/TreePlus.gif | Bin 0 -> 70 bytes i/TreePlusWhite.gif | Bin 0 -> 70 bytes i/admin/01.png | Bin 0 -> 3059 bytes i/admin/02.png | Bin 0 -> 2761 bytes i/admin/03.png | Bin 0 -> 1945 bytes i/admin/04.png | Bin 0 -> 2442 bytes i/admin/05.png | Bin 0 -> 2261 bytes i/admin/06.png | Bin 0 -> 3067 bytes i/admin/07.png | Bin 0 -> 1369 bytes i/admin/08.png | Bin 0 -> 2812 bytes i/admin/09.png | Bin 0 -> 2591 bytes i/admin/10.png | Bin 0 -> 2449 bytes i/admin/11.png | Bin 0 -> 1944 bytes i/admin/12.png | Bin 0 -> 2597 bytes i/admin/13.png | Bin 0 -> 2385 bytes i/admin/14.png | Bin 0 -> 2516 bytes i/admin/36.png | Bin 0 -> 1880 bytes i/admin/DataStore.gif | Bin 0 -> 1172 bytes i/admin/PayPal_mark_37x23.gif | Bin 0 -> 402 bytes i/admin/Premiums.png | Bin 0 -> 2403 bytes i/admin/Profile.png | Bin 0 -> 2860 bytes i/admin/Synch_user.png | Bin 0 -> 2320 bytes i/admin/accepted_creditcards.png | Bin 0 -> 2128 bytes i/admin/communication.png | Bin 0 -> 1545 bytes i/admin/contribution_types.png | Bin 0 -> 2860 bytes i/admin/custm_data.png | Bin 0 -> 2182 bytes i/admin/domain.png | Bin 0 -> 1268 bytes i/admin/duplicate_matching.png | Bin 0 -> 3202 bytes i/admin/event_manage.png | Bin 0 -> 2805 bytes i/admin/event_type.png | Bin 0 -> 2706 bytes i/admin/import_export_map.png | Bin 0 -> 3182 bytes i/admin/membership_status.png | Bin 0 -> 2502 bytes i/admin/membership_type.png | Bin 0 -> 2666 bytes i/admin/online_contribution_pages.png | Bin 0 -> 2779 bytes i/admin/option.png | Bin 0 -> 3251 bytes i/admin/parti_role.png | Bin 0 -> 897 bytes i/admin/parti_status.png | Bin 0 -> 857 bytes i/admin/payment_instruments.png | Bin 0 -> 2850 bytes i/admin/price_sets.png | Bin 0 -> 2095 bytes i/admin/rela_type.png | Bin 0 -> 3101 bytes i/admin/small/01.png | Bin 0 -> 1746 bytes i/admin/small/02.png | Bin 0 -> 1721 bytes i/admin/small/03.png | Bin 0 -> 1635 bytes i/admin/small/04.png | Bin 0 -> 1740 bytes i/admin/small/05.png | Bin 0 -> 2033 bytes i/admin/small/06.png | Bin 0 -> 1919 bytes i/admin/small/07.png | Bin 0 -> 1385 bytes i/admin/small/08.png | Bin 0 -> 1896 bytes i/admin/small/09.png | Bin 0 -> 1808 bytes i/admin/small/10.png | Bin 0 -> 1658 bytes i/admin/small/11.png | Bin 0 -> 1484 bytes i/admin/small/12.png | Bin 0 -> 1544 bytes i/admin/small/13.png | Bin 0 -> 1503 bytes i/admin/small/36.png | Bin 0 -> 1427 bytes i/admin/small/Premiums.png | Bin 0 -> 1947 bytes i/admin/small/Profile.png | Bin 0 -> 1589 bytes i/admin/small/Synch_user.png | Bin 0 -> 1649 bytes i/admin/small/accepted_creditcards.png | Bin 0 -> 1237 bytes i/admin/small/case_type.gif | Bin 0 -> 320 bytes i/admin/small/case_type.png | Bin 0 -> 1008 bytes i/admin/small/communication.png | Bin 0 -> 1314 bytes i/admin/small/contribution_types.png | Bin 0 -> 1833 bytes i/admin/small/custm_data.png | Bin 0 -> 1498 bytes i/admin/small/domain.png | Bin 0 -> 1277 bytes i/admin/small/duplicate_matching.png | Bin 0 -> 1803 bytes i/admin/small/event_manage.png | Bin 0 -> 1796 bytes i/admin/small/event_type.png | Bin 0 -> 1770 bytes i/admin/small/grant_type.png | Bin 0 -> 635 bytes i/admin/small/import_export_map.png | Bin 0 -> 1901 bytes i/admin/small/membership_status.png | Bin 0 -> 1826 bytes i/admin/small/membership_type.png | Bin 0 -> 1866 bytes i/admin/small/online_contribution_pages.png | Bin 0 -> 1856 bytes i/admin/small/option.png | Bin 0 -> 1861 bytes i/admin/small/parti_role.png | Bin 0 -> 1210 bytes i/admin/small/parti_status.png | Bin 0 -> 1153 bytes i/admin/small/payment_instruments.png | Bin 0 -> 1680 bytes i/admin/small/price_sets.png | Bin 0 -> 1641 bytes i/admin/small/redaction_type.png | Bin 0 -> 1138 bytes i/admin/small/rela_type.png | Bin 0 -> 1917 bytes i/admin/small/report_list.gif | Bin 0 -> 828 bytes i/admin/small/report_template.gif | Bin 0 -> 833 bytes i/admin/small/template.png | Bin 0 -> 1248 bytes i/admin/small/title.png | Bin 0 -> 1712 bytes i/admin/small/updatepath.png | Bin 0 -> 3218 bytes i/admin/template.png | Bin 0 -> 1617 bytes i/admin/title.png | Bin 0 -> 2300 bytes i/applications-internet.png | Bin 0 -> 1397 bytes i/arrow.gif | Bin 0 -> 605 bytes i/arrow/down.gif | Bin 0 -> 64 bytes i/arrow/first.gif | Bin 0 -> 63 bytes i/arrow/last.gif | Bin 0 -> 63 bytes i/arrow/spacer.gif | Bin 0 -> 820 bytes i/arrow/up.gif | Bin 0 -> 63 bytes i/binocular.gif | Bin 0 -> 1015 bytes i/block_small.png | Bin 0 -> 9148 bytes i/cal.gif | Bin 0 -> 644 bytes i/check.gif | Bin 0 -> 537 bytes i/close.png | Bin 0 -> 220 bytes i/collapsable.gif | Bin 0 -> 183 bytes i/contact_all.ico | Bin 0 -> 1150 bytes i/contact_house.png | Bin 0 -> 860 bytes i/contact_ind.gif | Bin 0 -> 995 bytes i/contact_ind_medium.gif | Bin 0 -> 1199 bytes i/contact_org.gif | Bin 0 -> 971 bytes i/contribute/default_premium.jpg | Bin 0 -> 49908 bytes i/contribute/default_premium_thumb.jpg | Bin 0 -> 49908 bytes i/contribute/incomplete.gif | Bin 0 -> 659 bytes i/contribute/pcp_achieve.gif | Bin 0 -> 162 bytes i/contribute/pcp_remain.gif | Bin 0 -> 162 bytes i/contribute/premium_sample_mug.jpg | Bin 0 -> 38211 bytes i/contribute/premium_sample_mug_thumb.jpg | Bin 0 -> 33574 bytes i/copy.png | Bin 0 -> 471 bytes i/crm-button-bg.gif | Bin 0 -> 1458 bytes i/crm-button-black.gif | Bin 0 -> 11412 bytes i/crm-button-blue.gif | Bin 0 -> 11347 bytes i/crm-button-dark-blue.gif | Bin 0 -> 12065 bytes i/crm-button-dark.gif | Bin 0 -> 10940 bytes i/crm-button.gif | Bin 0 -> 6593 bytes i/custom_activity.gif | Bin 0 -> 998 bytes i/dataTable/sort_sprites.acorn | Bin 0 -> 2295 bytes i/dataTable/sort_sprites.png | Bin 0 -> 320 bytes i/delete.png | Bin 0 -> 892 bytes i/draggable.png | Bin 0 -> 349 bytes i/dropdown-pointer.gif | Bin 0 -> 98 bytes i/edit.png | Bin 0 -> 946 bytes i/expandable.gif | Bin 0 -> 176 bytes i/fblike.png | Bin 0 -> 3502 bytes i/fbshare.png | Bin 0 -> 3789 bytes i/feed-icon.png | Bin 0 -> 1300 bytes i/geotag_16.png | Bin 0 -> 894 bytes i/grippie.png | Bin 0 -> 162 bytes i/group.png | Bin 0 -> 678 bytes i/ical_feed.gif | Bin 0 -> 683 bytes i/icons/jquery-ui-2786C2.png | Bin 0 -> 4369 bytes i/icons/jquery-ui-3E3E3E.png | Bin 0 -> 5355 bytes i/icons/jquery-ui-52534D.png | Bin 0 -> 5355 bytes i/icons/jquery-ui-8A1F11.png | Bin 0 -> 4369 bytes i/icons/jquery-ui-91CE00.png | Bin 0 -> 4369 bytes i/icons/jquery-ui-F5F6F1.png | Bin 0 -> 5355 bytes i/icons/jquery-ui-FFFFFF.png | Bin 0 -> 5355 bytes i/icons/jquery-ui-b0d730.png | Bin 0 -> 4369 bytes i/item_sprites.png | Bin 0 -> 8723 bytes i/langs.png | Bin 0 -> 452 bytes i/loading-2f2f2e.gif | Bin 0 -> 1849 bytes i/loading-E6E6DC.gif | Bin 0 -> 1849 bytes i/loading.gif | Bin 0 -> 1849 bytes i/logo16px.png | Bin 0 -> 760 bytes i/logo_words_small.png | Bin 0 -> 5988 bytes i/magnify.gif | Bin 0 -> 91 bytes i/meeting.gif | Bin 0 -> 646 bytes i/menu-collapsed.png | Bin 0 -> 108 bytes i/menu-expanded.png | Bin 0 -> 106 bytes i/message-icons.png | Bin 0 -> 4950 bytes i/mini_cvv2.gif | Bin 0 -> 509 bytes i/notes.png | Bin 0 -> 6881 bytes i/office-calendar.png | Bin 0 -> 807 bytes i/openid-icon-small.gif | Bin 0 -> 237 bytes i/overlay-pointer.png | Bin 0 -> 290 bytes i/popupMenuBg.gif | Bin 0 -> 151 bytes i/powered_by.png | Bin 0 -> 4691 bytes i/print-icon.png | Bin 0 -> 3757 bytes i/print_pdf.gif | Bin 0 -> 985 bytes i/quiz.png | Bin 0 -> 196 bytes i/rss2.png | Bin 0 -> 282 bytes i/smallLogo.png | Bin 0 -> 2996 bytes i/spacer.gif | Bin 0 -> 820 bytes i/stop-icon.png | Bin 0 -> 595 bytes i/tel.gif | Bin 0 -> 617 bytes i/tracker.gif | Bin 0 -> 49 bytes i/traffic_green.gif | Bin 0 -> 987 bytes i/traffic_red.gif | Bin 0 -> 989 bytes i/tweet.png | Bin 0 -> 645 bytes i/vcard-icon.png | Bin 0 -> 1164 bytes i/widget/favicon.png | Bin 0 -> 4557 bytes i/widget/logo.png | Bin 0 -> 950 bytes install/block_small.png | Bin 0 -> 8900 bytes install/civicrm.php | 279 + install/error.html | 16 + install/index.php | 1295 + install/network-save.gif | Bin 0 -> 1849 bytes install/template.css | 65 + install/template.html | 126 + js/Audit/audit.js | 53 + js/Common.js | 825 + js/crm.backbone.js | 120 + js/crm.designerapp.js | 12 + js/jquery.conflict.js | 1 + js/jquery/jquery.crmProfileSelector.js | 67 + js/jquery/jquery.crmasmselect.js | 420 + js/jquery/jquery.crmeditable.js | 329 + js/jquery/jquery.crmtemplate.js | 28 + js/model/crm.designer.js | 109 + js/model/crm.profile-selector.js | 10 + js/model/crm.schema-mapped.js | 48 + js/model/crm.schema.js | 52 + js/model/crm.uf.js | 734 + js/rest.js | 228 + js/view/crm.designer.js | 778 + js/view/crm.profile-selector.js | 188 + settings/Address.setting.php | 82 + settings/Campaign.setting.php | 69 + settings/Contribute.setting.php | 54 + settings/Core.setting.php | 524 + settings/Developer.setting.php | 119 + settings/Directory.setting.php | 132 + settings/Event.setting.php | 54 + settings/Localization.setting.php | 254 + settings/Mailing.setting.php | 139 + settings/Member.setting.php | 57 + settings/Multisite.setting.php | 88 + settings/Search.setting.php | 59 + settings/Url.setting.php | 83 + sql/GenerateData.README | 451 + sql/GenerateData.php | 1870 + sql/GenerateGroups.php | 70 + sql/GenerateMailing.php | 100 + sql/GenerateReportData.php | 1640 + sql/README.txt | 7 + sql/case_sample.mysql | 68 + sql/case_sample1.mysql | 25 + sql/civicrm_arms_sample_data.sql | 27 + sql/civicrm_case_sql.mysql | 77 + sql/civicrm_demo_processor.mysql | 40 + sql/civicrm_devel_config.mysql | 31 + sql/civicrm_generated.mysql | 1608 + sql/civicrm_generated_report.mysql | 1465 + sql/civicrm_queue_item.mysql | 30 + sql/civicrm_sample_custom_data.mysql | 109 + sql/civicrm_upgradedb_v1.1_v1.2_40.mysql | 333 + sql/civicrm_upgradedb_v1.1_v1.2_41.mysql | 329 + sql/civicrm_upgradedb_v1.2_v1.3_40.mysql | 446 + sql/civicrm_upgradedb_v1.2_v1.3_41.mysql | 457 + sql/civicrm_upgradedb_v1.3_v1.4_40.mysql | 344 + sql/civicrm_upgradedb_v1.3_v1.4_41.mysql | 335 + sql/civicrm_upgradedb_v1.4_v1.5_40.mysql | 691 + sql/civicrm_upgradedb_v1.4_v1.5_41.mysql | 692 + sql/civicrm_upgradedb_v1.5_v1.6_40.mysql | 659 + sql/civicrm_upgradedb_v1.5_v1.6_41.mysql | 668 + sql/civicrm_upgradedb_v1.6_v1.7_40.mysql | 338 + sql/civicrm_upgradedb_v1.6_v1.7_41.mysql | 363 + sql/civicrm_upgradedb_v1.7_v1.8_41.mysql | 632 + sql/civicrm_upgradedb_v1.8_v1.9_41.mysql | 406 + sql/counties.US.sql.gz | Bin 0 -> 15519 bytes sql/sample_data.xml | 423 + sql/sample_data_pl.xml | 211 + sql/test_data.mysql | 11 + sql/test_data_second_domain.mysql | 1021 + sql/trigger.mysql | 67 + sql/upgrade_pcm.mysql | 40 + sql/webtest_data.mysql | 3 + sql/zipcodes.mysql | 43220 ++++++++++++++++ templates/CRM/ACL/Form/ACL.tpl | 162 + templates/CRM/ACL/Form/ACLBasic.tpl | 60 + templates/CRM/ACL/Form/EntityRole.tpl | 56 + .../CRM/ACL/Form/WordPress/Permissions.tpl | 71 + templates/CRM/ACL/Page/ACL.tpl | 89 + templates/CRM/ACL/Page/ACLBasic.tpl | 80 + templates/CRM/ACL/Page/EntityRole.tpl | 81 + templates/CRM/Activity/Calendar/ICal.tpl | 48 + templates/CRM/Activity/Form/Activity.tpl | 361 + templates/CRM/Activity/Form/ActivityLinks.tpl | 64 + templates/CRM/Activity/Form/ActivityView.tpl | 150 + templates/CRM/Activity/Form/Search.tpl | 85 + templates/CRM/Activity/Form/Search/Common.tpl | 237 + .../CRM/Activity/Form/Search/EmptyResults.tpl | 40 + templates/CRM/Activity/Form/Selector.tpl | 132 + templates/CRM/Activity/Form/Task.tpl | 41 + templates/CRM/Activity/Form/Task/Batch.tpl | 67 + templates/CRM/Activity/Form/Task/Delete.tpl | 36 + templates/CRM/Activity/Form/Task/Email.tpl | 26 + .../CRM/Activity/Form/Task/FileOnCase.tpl | 56 + .../CRM/Activity/Form/Task/PickOption.tpl | 49 + .../CRM/Activity/Form/Task/PickProfile.tpl | 42 + templates/CRM/Activity/Form/Task/Print.tpl | 90 + templates/CRM/Activity/Form/Task/SMS.tpl | 26 + .../Form/Task/SearchTaskHookSample.tpl | 59 + .../CRM/Activity/Import/Form/MapField.tpl | 55 + .../CRM/Activity/Import/Form/MapTable.tpl | 121 + .../CRM/Activity/Import/Form/Preview.tpl | 95 + .../CRM/Activity/Import/Form/Summary.tpl | 134 + .../CRM/Activity/Import/Form/UploadFile.hlp | 40 + .../CRM/Activity/Import/Form/UploadFile.tpl | 68 + templates/CRM/Activity/Page/Tab.tpl | 38 + templates/CRM/Activity/Page/UserDashboard.tpl | 69 + templates/CRM/Activity/Selector/Activity.tpl | 129 + templates/CRM/Activity/Selector/Selector.tpl | 169 + templates/CRM/Admin/Form/ActivityType.tpl | 50 + templates/CRM/Admin/Form/CMSUser.tpl | 38 + templates/CRM/Admin/Form/ContactType.tpl | 74 + templates/CRM/Admin/Form/DomainDump.tpl | 45 + templates/CRM/Admin/Form/Extensions.tpl | 51 + templates/CRM/Admin/Form/Job.tpl | 114 + templates/CRM/Admin/Form/LabelFormats.tpl | 171 + templates/CRM/Admin/Form/LocationType.tpl | 66 + templates/CRM/Admin/Form/MailSettings.tpl | 74 + templates/CRM/Admin/Form/Mapping.tpl | 54 + templates/CRM/Admin/Form/MessageTemplates.tpl | 148 + templates/CRM/Admin/Form/Navigation.hlp | 59 + templates/CRM/Admin/Form/Navigation.tpl | 57 + templates/CRM/Admin/Form/OptionGroup.tpl | 55 + templates/CRM/Admin/Form/OptionValue.tpl | 98 + templates/CRM/Admin/Form/Options.tpl | 160 + .../CRM/Admin/Form/ParticipantStatus.tpl | 88 + templates/CRM/Admin/Form/PaymentProcessor.tpl | 166 + .../CRM/Admin/Form/PaymentProcessorType.tpl | 119 + templates/CRM/Admin/Form/PdfFormats.tpl | 145 + templates/CRM/Admin/Form/Persistent.tpl | 20 + .../CRM/Admin/Form/Preferences/Address.hlp | 80 + .../CRM/Admin/Form/Preferences/Address.tpl | 98 + .../CRM/Admin/Form/Preferences/Campaign.tpl | 26 + .../CRM/Admin/Form/Preferences/Display.hlp | 37 + .../CRM/Admin/Form/Preferences/Display.tpl | 187 + .../CRM/Admin/Form/Preferences/Event.tpl | 26 + .../CRM/Admin/Form/Preferences/Mailing.tpl | 26 + .../CRM/Admin/Form/Preferences/Member.tpl | 26 + .../CRM/Admin/Form/Preferences/Multisite.tpl | 26 + templates/CRM/Admin/Form/PreferencesDate.tpl | 54 + templates/CRM/Admin/Form/RelationshipType.tpl | 78 + .../CRM/Admin/Form/ScheduleReminders.tpl | 289 + .../CRM/Admin/Form/Setting/Component.hlp | 39 + .../CRM/Admin/Form/Setting/Component.tpl | 37 + templates/CRM/Admin/Form/Setting/Date.hlp | 49 + templates/CRM/Admin/Form/Setting/Date.tpl | 80 + .../CRM/Admin/Form/Setting/Debugging.hlp | 52 + .../CRM/Admin/Form/Setting/Debugging.tpl | 62 + templates/CRM/Admin/Form/Setting/Event.tpl | 41 + .../CRM/Admin/Form/Setting/Localization.tpl | 149 + templates/CRM/Admin/Form/Setting/Mail.tpl | 60 + templates/CRM/Admin/Form/Setting/Mapping.hlp | 31 + templates/CRM/Admin/Form/Setting/Mapping.tpl | 68 + .../CRM/Admin/Form/Setting/Miscellaneous.tpl | 113 + templates/CRM/Admin/Form/Setting/Path.tpl | 71 + templates/CRM/Admin/Form/Setting/Search.tpl | 83 + templates/CRM/Admin/Form/Setting/Smtp.tpl | 134 + templates/CRM/Admin/Form/Setting/UF.tpl | 48 + .../Form/Setting/UpdateConfigBackend.tpl | 67 + templates/CRM/Admin/Form/Setting/Url.hlp | 88 + templates/CRM/Admin/Form/Setting/Url.tpl | 89 + templates/CRM/Admin/Form/Tag.tpl | 75 + templates/CRM/Admin/Form/WordReplacements.hlp | 34 + templates/CRM/Admin/Form/WordReplacements.tpl | 113 + templates/CRM/Admin/Page/Access.tpl | 66 + templates/CRM/Admin/Page/Admin.tpl | 94 + templates/CRM/Admin/Page/CMSUser.tpl | 28 + templates/CRM/Admin/Page/ConfigTaskList.tpl | 192 + templates/CRM/Admin/Page/ContactType.hlp | 43 + templates/CRM/Admin/Page/ContactType.tpl | 72 + templates/CRM/Admin/Page/DomainDump.tpl | 28 + templates/CRM/Admin/Page/EventTemplate.tpl | 81 + templates/CRM/Admin/Page/ExtensionDetails.tpl | 45 + templates/CRM/Admin/Page/Extensions.tpl | 145 + templates/CRM/Admin/Page/Extensions/About.tpl | 5 + .../CRM/Admin/Page/Extensions/AddNew.tpl | 47 + .../CRM/Admin/Page/Extensions/AddNewReq.tpl | 9 + templates/CRM/Admin/Page/Extensions/Main.tpl | 51 + .../CRM/Admin/Page/Extensions/Refresh.tpl | 3 + templates/CRM/Admin/Page/Job.tpl | 89 + templates/CRM/Admin/Page/JobLog.tpl | 77 + templates/CRM/Admin/Page/LabelFormats.tpl | 76 + templates/CRM/Admin/Page/LocationType.tpl | 79 + templates/CRM/Admin/Page/MailSettings.tpl | 83 + templates/CRM/Admin/Page/Mapping.tpl | 62 + templates/CRM/Admin/Page/MessageTemplates.hlp | 69 + templates/CRM/Admin/Page/MessageTemplates.tpl | 171 + templates/CRM/Admin/Page/Navigation.hlp | 44 + templates/CRM/Admin/Page/Navigation.tpl | 146 + templates/CRM/Admin/Page/OptionGroup.tpl | 70 + templates/CRM/Admin/Page/OptionValue.tpl | 86 + templates/CRM/Admin/Page/Options.hlp | 35 + templates/CRM/Admin/Page/Options.tpl | 166 + .../CRM/Admin/Page/ParticipantStatus.hlp | 34 + .../CRM/Admin/Page/ParticipantStatus.tpl | 69 + templates/CRM/Admin/Page/PaymentProcessor.hlp | 419 + templates/CRM/Admin/Page/PaymentProcessor.tpl | 79 + .../CRM/Admin/Page/PaymentProcessorType.tpl | 76 + templates/CRM/Admin/Page/PdfFormats.tpl | 75 + templates/CRM/Admin/Page/Persistent.tpl | 69 + templates/CRM/Admin/Page/PreferencesDate.tpl | 55 + templates/CRM/Admin/Page/RelationshipType.hlp | 39 + templates/CRM/Admin/Page/RelationshipType.tpl | 89 + templates/CRM/Admin/Page/Reminders.tpl | 60 + .../CRM/Admin/Page/ScheduleReminders.tpl | 48 + templates/CRM/Admin/Page/Setting.tpl | 100 + templates/CRM/Admin/Page/Tag.tpl | 200 + templates/CRM/Batch/Form/Batch.tpl | 66 + templates/CRM/Batch/Form/Entry.tpl | 406 + templates/CRM/Batch/Form/Search.tpl | 135 + templates/CRM/Batch/Page/Batch.tpl | 30 + templates/CRM/Block/Add.tpl | 67 + templates/CRM/Block/CreateNew.tpl | 64 + templates/CRM/Block/Dashboard.tpl | 30 + templates/CRM/Block/Event.tpl | 42 + templates/CRM/Block/FullTextSearch.tpl | 65 + templates/CRM/Block/Gcc.tpl | 32 + templates/CRM/Block/LangSwitch.tpl | 34 + templates/CRM/Block/Mail.tpl | 30 + templates/CRM/Block/RecentlyViewed.tpl | 54 + templates/CRM/Block/Subject.tpl | 26 + templates/CRM/Block/blocks.tpl | 33 + templates/CRM/Campaign/Form/Campaign.tpl | 128 + templates/CRM/Campaign/Form/Gotv.tpl | 233 + templates/CRM/Campaign/Form/Petition.tpl | 124 + .../CRM/Campaign/Form/Petition/Block.tpl | 165 + .../CRM/Campaign/Form/Petition/Signature.tpl | 64 + templates/CRM/Campaign/Form/ResultOptions.tpl | 173 + templates/CRM/Campaign/Form/Search.tpl | 80 + .../CRM/Campaign/Form/Search/Campaign.tpl | 277 + templates/CRM/Campaign/Form/Search/Common.tpl | 256 + .../CRM/Campaign/Form/Search/EmptyResults.tpl | 42 + .../CRM/Campaign/Form/Search/Petition.tpl | 254 + templates/CRM/Campaign/Form/Search/Survey.tpl | 306 + templates/CRM/Campaign/Form/Selector.tpl | 86 + templates/CRM/Campaign/Form/Survey/Delete.tpl | 35 + templates/CRM/Campaign/Form/Survey/Main.tpl | 122 + .../CRM/Campaign/Form/Survey/Questions.tpl | 43 + .../CRM/Campaign/Form/Survey/Results.tpl | 62 + templates/CRM/Campaign/Form/Survey/Tab.tpl | 27 + templates/CRM/Campaign/Form/SurveyType.tpl | 1 + .../CRM/Campaign/Form/Task/Interview.tpl | 408 + templates/CRM/Campaign/Form/Task/Print.tpl | 43 + templates/CRM/Campaign/Form/Task/Release.tpl | 43 + templates/CRM/Campaign/Form/Task/Reserve.tpl | 100 + templates/CRM/Campaign/Form/Task/Result.tpl | 32 + .../Campaign/Form/addCampaignToComponent.hlp | 32 + .../Campaign/Form/addCampaignToComponent.tpl | 108 + templates/CRM/Campaign/Page/Campaign.tpl | 69 + templates/CRM/Campaign/Page/DashBoard.tpl | 93 + templates/CRM/Campaign/Page/Petition.tpl | 72 + .../CRM/Campaign/Page/Petition/Confirm.tpl | 44 + .../Page/Petition/SocialNetwork.drupal | 112 + .../Campaign/Page/Petition/SocialNetwork.tpl | 7 + .../CRM/Campaign/Page/Petition/ThankYou.tpl | 55 + templates/CRM/Campaign/Page/Survey.tpl | 72 + templates/CRM/Campaign/Page/SurveyType.tpl | 58 + templates/CRM/Campaign/Page/Vote.tpl | 75 + templates/CRM/Case/Audit/Audit.tpl | 182 + templates/CRM/Case/Audit/Report.tpl | 154 + templates/CRM/Case/Form/Activity.tpl | 341 + .../Form/Activity/ChangeCaseStartDate.tpl | 40 + .../Case/Form/Activity/ChangeCaseStatus.tpl | 37 + .../CRM/Case/Form/Activity/ChangeCaseType.tpl | 49 + .../CRM/Case/Form/Activity/LinkCases.tpl | 47 + templates/CRM/Case/Form/Activity/OpenCase.tpl | 52 + .../CRM/Case/Form/ActivityChangeStatus.tpl | 106 + templates/CRM/Case/Form/ActivityToCase.tpl | 205 + templates/CRM/Case/Form/ActivityView.tpl | 112 + templates/CRM/Case/Form/Case.hlp | 65 + templates/CRM/Case/Form/Case.tpl | 163 + templates/CRM/Case/Form/CaseView.tpl | 1105 + templates/CRM/Case/Form/CustomData.tpl | 30 + templates/CRM/Case/Form/EditClient.tpl | 84 + templates/CRM/Case/Form/Report.tpl | 54 + templates/CRM/Case/Form/Search.tpl | 89 + .../Case/Form/Search/AdvancedSearchPane.tpl | 32 + templates/CRM/Case/Form/Search/Common.tpl | 91 + .../CRM/Case/Form/Search/EmptyResults.tpl | 42 + templates/CRM/Case/Form/Selector.tpl | 167 + templates/CRM/Case/Form/Task.tpl | 41 + templates/CRM/Case/Form/Task/Delete.tpl | 36 + templates/CRM/Case/Form/Task/Print.tpl | 68 + templates/CRM/Case/Form/Task/Restore.tpl | 35 + .../Case/Form/Task/SearchTaskHookSample.tpl | 36 + templates/CRM/Case/Page/CaseDetails.tpl | 59 + templates/CRM/Case/Page/ConfigureError.tpl | 34 + templates/CRM/Case/Page/CustomDataView.tpl | 148 + templates/CRM/Case/Page/DashBoard.tpl | 112 + templates/CRM/Case/Page/DashboardSelector.tpl | 153 + templates/CRM/Case/Page/Tab.tpl | 80 + templates/CRM/Case/XMLProcessor/Report.tpl | 73 + templates/CRM/Contact/Form/Contact.hlp | 189 + templates/CRM/Contact/Form/Contact.tpl | 261 + .../CRM/Contact/Form/CurrentEmployer.tpl | 80 + templates/CRM/Contact/Form/CustomData.tpl | 50 + templates/CRM/Contact/Form/DedupeFind.tpl | 38 + templates/CRM/Contact/Form/DedupeRules.tpl | 115 + templates/CRM/Contact/Form/Domain.hlp | 62 + templates/CRM/Contact/Form/Domain.tpl | 92 + templates/CRM/Contact/Form/Edit/Address.tpl | 119 + .../Contact/Form/Edit/Address/CustomData.tpl | 49 + .../Contact/Form/Edit/Address/CustomField.tpl | 117 + .../Form/Edit/Address/address_name.tpl | 33 + .../Form/Edit/Address/city_postal_code.tpl | 47 + .../Edit/Address/country_state_province.tpl | 44 + .../CRM/Contact/Form/Edit/Address/county.tpl | 33 + .../Contact/Form/Edit/Address/geo_code.tpl | 42 + .../Form/Edit/Address/street_address.tpl | 106 + .../Edit/Address/supplemental_address_1.tpl | 33 + .../Edit/Address/supplemental_address_2.tpl | 33 + .../Form/Edit/CommunicationPreferences.tpl | 159 + .../CRM/Contact/Form/Edit/CustomData.tpl | 97 + .../CRM/Contact/Form/Edit/Demographics.tpl | 67 + templates/CRM/Contact/Form/Edit/Email.tpl | 69 + templates/CRM/Contact/Form/Edit/Household.tpl | 42 + templates/CRM/Contact/Form/Edit/IM.tpl | 55 + .../CRM/Contact/Form/Edit/Individual.tpl | 132 + templates/CRM/Contact/Form/Edit/Lock.tpl | 34 + templates/CRM/Contact/Form/Edit/Notes.tpl | 44 + templates/CRM/Contact/Form/Edit/OpenID.tpl | 53 + .../CRM/Contact/Form/Edit/Organization.tpl | 48 + templates/CRM/Contact/Form/Edit/Phone.tpl | 56 + .../CRM/Contact/Form/Edit/TagsAndGroups.tpl | 67 + templates/CRM/Contact/Form/Edit/Website.tpl | 53 + templates/CRM/Contact/Form/GroupContact.tpl | 31 + templates/CRM/Contact/Form/Inline/Address.tpl | 109 + .../Form/Inline/CommunicationPreferences.tpl | 169 + .../CRM/Contact/Form/Inline/ContactInfo.tpl | 69 + .../CRM/Contact/Form/Inline/ContactName.tpl | 65 + .../CRM/Contact/Form/Inline/CustomData.tpl | 33 + .../CRM/Contact/Form/Inline/Demographics.tpl | 76 + templates/CRM/Contact/Form/Inline/Email.tpl | 83 + templates/CRM/Contact/Form/Inline/IM.tpl | 70 + templates/CRM/Contact/Form/Inline/OpenID.tpl | 70 + templates/CRM/Contact/Form/Inline/Phone.tpl | 70 + templates/CRM/Contact/Form/Inline/Website.tpl | 73 + templates/CRM/Contact/Form/Merge.hlp | 33 + templates/CRM/Contact/Form/Merge.tpl | 180 + templates/CRM/Contact/Form/NewContact.tpl | 152 + templates/CRM/Contact/Form/OnBehalfOf.tpl | 280 + templates/CRM/Contact/Form/RelatedContact.tpl | 32 + templates/CRM/Contact/Form/Relationship.tpl | 622 + .../CRM/Contact/Form/Search/Advanced.hlp | 105 + .../CRM/Contact/Form/Search/Advanced.tpl | 97 + .../Contact/Form/Search/AdvancedCriteria.tpl | 145 + templates/CRM/Contact/Form/Search/Basic.hlp | 79 + templates/CRM/Contact/Form/Search/Basic.tpl | 74 + .../CRM/Contact/Form/Search/BasicCriteria.tpl | 108 + templates/CRM/Contact/Form/Search/Builder.hlp | 34 + templates/CRM/Contact/Form/Search/Builder.js | 277 + templates/CRM/Contact/Form/Search/Builder.tpl | 72 + .../Contact/Form/Search/Criteria/Activity.tpl | 30 + .../Contact/Form/Search/Criteria/Basic.tpl | 259 + .../Form/Search/Criteria/ChangeLog.tpl | 46 + .../Contact/Form/Search/Criteria/Custom.tpl | 26 + .../Form/Search/Criteria/Demographics.tpl | 51 + .../Contact/Form/Search/Criteria/Location.tpl | 157 + .../Contact/Form/Search/Criteria/Notes.tpl | 39 + .../Contact/Form/Search/Criteria/Quest.tpl | 33 + .../Form/Search/Criteria/Relationship.tpl | 85 + .../CRM/Contact/Form/Search/Criteria/Task.tpl | 45 + templates/CRM/Contact/Form/Search/Custom.tpl | 184 + .../Form/Search/Custom/ActivitySearch.tpl | 153 + .../Form/Search/Custom/ContribSYBNT.tpl | 164 + .../Search/Custom/ContributionAggregate.tpl | 155 + .../Form/Search/Custom/EmptyResults.tpl | 43 + .../Form/Search/Custom/EventDetails.tpl | 156 + .../Contact/Form/Search/Custom/FullText.hlp | 34 + .../Contact/Form/Search/Custom/FullText.tpl | 298 + .../Form/Search/Custom/MultipleValues.tpl | 111 + .../Search/Custom/MultipleValuesCriteria.tpl | 116 + .../Contact/Form/Search/Custom/Proximity.tpl | 140 + .../CRM/Contact/Form/Search/Custom/Sample.tpl | 29 + .../CRM/Contact/Form/Search/EmptyResults.tpl | 52 + templates/CRM/Contact/Form/Search/Intro.tpl | 51 + .../CRM/Contact/Form/Search/ResultTasks.tpl | 111 + templates/CRM/Contact/Form/Search/Simple.tpl | 54 + templates/CRM/Contact/Form/Search/table.tpl | 60 + templates/CRM/Contact/Form/Selector.tpl | 208 + templates/CRM/Contact/Form/ShareAddress.tpl | 163 + templates/CRM/Contact/Form/Task.tpl | 123 + .../CRM/Contact/Form/Task/AddToGroup.tpl | 85 + .../CRM/Contact/Form/Task/AddToHousehold.tpl | 108 + .../Contact/Form/Task/AddToOrganization.tpl | 109 + templates/CRM/Contact/Form/Task/AddToTag.tpl | 52 + .../Contact/Form/Task/AlterPreferences.tpl | 48 + templates/CRM/Contact/Form/Task/Batch.tpl | 99 + templates/CRM/Contact/Form/Task/Delete.tpl | 42 + templates/CRM/Contact/Form/Task/Email.hlp | 101 + templates/CRM/Contact/Form/Task/Email.tpl | 121 + .../CRM/Contact/Form/Task/EmailCommon.tpl | 104 + .../CRM/Contact/Form/Task/GMapsInput.tpl | 48 + .../CRM/Contact/Form/Task/HookSample.tpl | 60 + templates/CRM/Contact/Form/Task/Label.hlp | 34 + templates/CRM/Contact/Form/Task/Label.tpl | 49 + templates/CRM/Contact/Form/Task/Map.tpl | 30 + .../CRM/Contact/Form/Task/Map/Google.tpl | 121 + .../Contact/Form/Task/Map/OpenStreetMaps.tpl | 181 + templates/CRM/Contact/Form/Task/PDF.tpl | 33 + .../CRM/Contact/Form/Task/PDFLetterCommon.hlp | 52 + .../CRM/Contact/Form/Task/PDFLetterCommon.tpl | 312 + .../CRM/Contact/Form/Task/PickProfile.tpl | 42 + templates/CRM/Contact/Form/Task/Print.tpl | 104 + .../CRM/Contact/Form/Task/ProximityCommon.tpl | 37 + .../CRM/Contact/Form/Task/RemoveFromGroup.tpl | 38 + .../CRM/Contact/Form/Task/RemoveFromTag.tpl | 52 + templates/CRM/Contact/Form/Task/Result.tpl | 34 + templates/CRM/Contact/Form/Task/SMS.hlp | 66 + templates/CRM/Contact/Form/Task/SMS.tpl | 104 + templates/CRM/Contact/Form/Task/SMSCommon.tpl | 107 + .../CRM/Contact/Form/Task/SaveSearch.tpl | 55 + .../Contact/Form/Task/SaveSearch/Update.tpl | 26 + templates/CRM/Contact/Form/Task/Unhold.tpl | 34 + templates/CRM/Contact/Form/Test.tpl | 48 + templates/CRM/Contact/Page/ContactImage.tpl | 43 + templates/CRM/Contact/Page/CustomSearch.hlp | 38 + templates/CRM/Contact/Page/CustomSearch.tpl | 43 + templates/CRM/Contact/Page/DashBoard.tpl | 43 + .../CRM/Contact/Page/DashBoardDashlet.tpl | 109 + templates/CRM/Contact/Page/Dashboard.hlp | 69 + templates/CRM/Contact/Page/Dashlet.tpl | 130 + .../CRM/Contact/Page/DedupeException.tpl | 63 + templates/CRM/Contact/Page/DedupeFind.tpl | 83 + templates/CRM/Contact/Page/DedupeRules.hlp | 58 + templates/CRM/Contact/Page/DedupeRules.tpl | 70 + templates/CRM/Contact/Page/Inline/Actions.tpl | 101 + templates/CRM/Contact/Page/Inline/Address.tpl | 84 + .../Page/Inline/CommunicationPreferences.tpl | 85 + .../CRM/Contact/Page/Inline/ContactInfo.tpl | 69 + .../CRM/Contact/Page/Inline/ContactName.tpl | 38 + .../CRM/Contact/Page/Inline/CustomData.tpl | 27 + .../CRM/Contact/Page/Inline/Demographics.tpl | 73 + templates/CRM/Contact/Page/Inline/Email.tpl | 98 + templates/CRM/Contact/Page/Inline/IM.tpl | 51 + templates/CRM/Contact/Page/Inline/OpenID.tpl | 51 + templates/CRM/Contact/Page/Inline/Phone.tpl | 57 + templates/CRM/Contact/Page/Inline/Website.tpl | 49 + templates/CRM/Contact/Page/SavedSearch.tpl | 72 + .../CRM/Contact/Page/View/CustomData.tpl | 54 + .../Contact/Page/View/CustomDataFieldView.tpl | 68 + .../CRM/Contact/Page/View/CustomDataView.tpl | 44 + templates/CRM/Contact/Page/View/Delete.tpl | 33 + templates/CRM/Contact/Page/View/Email.tpl | 38 + templates/CRM/Contact/Page/View/Group.tpl | 59 + .../CRM/Contact/Page/View/GroupContact.tpl | 169 + templates/CRM/Contact/Page/View/Log.tpl | 91 + templates/CRM/Contact/Page/View/Note.tpl | 285 + templates/CRM/Contact/Page/View/Print.tpl | 56 + .../CRM/Contact/Page/View/Relationship.tpl | 189 + templates/CRM/Contact/Page/View/SMS.tpl | 37 + templates/CRM/Contact/Page/View/Summary.hlp | 31 + templates/CRM/Contact/Page/View/Summary.js | 269 + templates/CRM/Contact/Page/View/Summary.tpl | 350 + .../CRM/Contact/Page/View/SummaryHook.tpl | 28 + templates/CRM/Contact/Page/View/Sunlight.tpl | 59 + templates/CRM/Contact/Page/View/Tag.tpl | 28 + .../CRM/Contact/Page/View/UserDashBoard.tpl | 47 + .../Page/View/UserDashBoard/GroupContact.tpl | 133 + templates/CRM/Contact/Page/View/Useradd.tpl | 51 + templates/CRM/Contact/Selector.tpl | 27 + .../CRM/Contribute/Form/AcceptCreditCard.tpl | 57 + .../Form/AdditionalInfo/AdditionalDetail.tpl | 44 + .../Form/AdditionalInfo/CreditCard.tpl | 84 + .../Form/AdditionalInfo/Honoree.tpl | 80 + .../Form/AdditionalInfo/PaymentReminders.tpl | 36 + .../Form/AdditionalInfo/Premium.tpl | 94 + .../Contribute/Form/CancelSubscription.tpl | 58 + .../CRM/Contribute/Form/Contribution.tpl | 637 + .../Form/Contribution/AuthorizeNetARB.tpl | 122 + .../Contribute/Form/Contribution/Confirm.tpl | 278 + .../Contribute/Form/Contribution/Honor.tpl | 37 + .../CRM/Contribute/Form/Contribution/Main.tpl | 494 + .../Form/Contribution/MembershipBlock.tpl | 305 + .../Form/Contribution/OnBehalfOf.tpl | 322 + .../Form/Contribution/PremiumBlock.tpl | 314 + .../Form/Contribution/PreviewHeader.tpl | 31 + .../Contribute/Form/Contribution/ThankYou.tpl | 298 + .../Contribute/Form/ContributionCharts.tpl | 99 + .../Form/ContributionPage/AddProduct.hlp | 28 + .../Form/ContributionPage/AddProduct.tpl | 112 + .../Form/ContributionPage/Amount.tpl | 388 + .../Form/ContributionPage/Custom.hlp | 48 + .../Form/ContributionPage/Custom.tpl | 86 + .../Form/ContributionPage/Delete.tpl | 37 + .../Contribute/Form/ContributionPage/PCP.hlp | 90 + .../Form/ContributionPage/Premium.tpl | 114 + .../Form/ContributionPage/Settings.hlp | 86 + .../Form/ContributionPage/Settings.tpl | 179 + .../Contribute/Form/ContributionPage/Tab.hlp | 79 + .../Contribute/Form/ContributionPage/Tab.tpl | 65 + .../Form/ContributionPage/ThankYou.tpl | 115 + .../Form/ContributionPage/Widget.hlp | 34 + .../Form/ContributionPage/Widget.tpl | 149 + .../CRM/Contribute/Form/ContributionView.tpl | 273 + .../CRM/Contribute/Form/ManagePremiums.tpl | 180 + .../CRM/Contribute/Form/PCP/Campaign.tpl | 89 + templates/CRM/Contribute/Form/PCP/Delete.tpl | 35 + templates/CRM/Contribute/Form/PCP/PCP.tpl | 40 + .../CRM/Contribute/Form/PCP/PCPAccount.tpl | 49 + .../CRM/Contribute/Form/PaymentInstrument.tpl | 44 + templates/CRM/Contribute/Form/Preview.tpl | 103 + templates/CRM/Contribute/Form/Search.tpl | 124 + .../Form/Search/AdvancedSearchPane.tpl | 32 + .../CRM/Contribute/Form/Search/Common.tpl | 187 + .../Contribute/Form/Search/EmptyResults.tpl | 42 + .../Contribute/Form/SearchContribution.tpl | 54 + templates/CRM/Contribute/Form/Selector.tpl | 106 + templates/CRM/Contribute/Form/Task.tpl | 41 + templates/CRM/Contribute/Form/Task/Batch.tpl | 67 + templates/CRM/Contribute/Form/Task/Delete.tpl | 35 + templates/CRM/Contribute/Form/Task/Email.tpl | 26 + templates/CRM/Contribute/Form/Task/PDF.tpl | 49 + .../CRM/Contribute/Form/Task/PDFLetter.tpl | 48 + .../CRM/Contribute/Form/Task/PickProfile.tpl | 39 + templates/CRM/Contribute/Form/Task/Print.tpl | 74 + templates/CRM/Contribute/Form/Task/Result.tpl | 32 + .../Form/Task/SearchTaskHookSample.tpl | 38 + templates/CRM/Contribute/Form/Task/Status.tpl | 68 + .../CRM/Contribute/Form/UpdateBilling.tpl | 41 + .../Contribute/Form/UpdateSubscription.tpl | 59 + .../CRM/Contribute/Import/Form/MapField.tpl | 53 + .../CRM/Contribute/Import/Form/MapTable.tpl | 122 + .../CRM/Contribute/Import/Form/Preview.tpl | 92 + .../CRM/Contribute/Import/Form/Summary.tpl | 167 + .../CRM/Contribute/Import/Form/UploadFile.hlp | 48 + .../CRM/Contribute/Import/Form/UploadFile.tpl | 54 + .../CRM/Contribute/Page/ContributionHonor.tpl | 57 + .../CRM/Contribute/Page/ContributionPage.hlp | 40 + .../CRM/Contribute/Page/ContributionPage.tpl | 122 + .../CRM/Contribute/Page/ContributionRecur.tpl | 84 + .../CRM/Contribute/Page/ContributionSoft.tpl | 60 + .../Contribute/Page/ContributionTotals.tpl | 55 + .../CRM/Contribute/Page/ContributionType.tpl | 78 + templates/CRM/Contribute/Page/DashBoard.hlp | 36 + templates/CRM/Contribute/Page/DashBoard.tpl | 148 + .../CRM/Contribute/Page/ManagePremiums.tpl | 88 + .../CRM/Contribute/Page/PcpUserDashboard.tpl | 90 + templates/CRM/Contribute/Page/Premium.tpl | 77 + .../Contribute/Page/SubscriptionStatus.tpl | 59 + templates/CRM/Contribute/Page/Tab.hlp | 74 + templates/CRM/Contribute/Page/Tab.tpl | 91 + .../CRM/Contribute/Page/UserDashboard.tpl | 122 + templates/CRM/Contribute/Page/Widget.tpl | 239 + templates/CRM/Core/APIDoc.tpl | 88 + templates/CRM/Core/AjaxDoc.tpl | 231 + templates/CRM/Core/BillingBlock.tpl | 293 + templates/CRM/Core/Calendar/GData.tpl | 61 + templates/CRM/Core/Calendar/ICal.tpl | 64 + templates/CRM/Core/Calendar/Rss.tpl | 64 + templates/CRM/Core/Date.tpl | 27 + templates/CRM/Core/DateRange.tpl | 52 + templates/CRM/Core/I18n/Dialog.tpl | 51 + templates/CRM/Core/I18n/Form.tpl | 64 + templates/CRM/Core/Page/QUnit.tpl | 5 + templates/CRM/Custom/Form/AutoComplete.tpl | 50 + templates/CRM/Custom/Form/ChangeFieldType.tpl | 62 + .../CRM/Custom/Form/ContactReference.tpl | 58 + templates/CRM/Custom/Form/CustomData.tpl | 74 + templates/CRM/Custom/Form/CustomField.tpl | 106 + templates/CRM/Custom/Form/DeleteField.tpl | 34 + templates/CRM/Custom/Form/DeleteFile.tpl | 38 + templates/CRM/Custom/Form/DeleteGroup.tpl | 39 + templates/CRM/Custom/Form/Field.tpl | 326 + templates/CRM/Custom/Form/Group.tpl | 177 + templates/CRM/Custom/Form/MoveField.tpl | 37 + templates/CRM/Custom/Form/Option.tpl | 66 + templates/CRM/Custom/Form/Optionfields.tpl | 121 + templates/CRM/Custom/Form/Preview.tpl | 116 + templates/CRM/Custom/Form/Search.tpl | 121 + templates/CRM/Custom/Page/CustomDataView.tpl | 150 + templates/CRM/Custom/Page/Field.tpl | 89 + templates/CRM/Custom/Page/Group.hlp | 113 + templates/CRM/Custom/Page/Group.tpl | 94 + templates/CRM/Custom/Page/Option.tpl | 81 + templates/CRM/Dashlet/Page/Activity.tpl | 27 + templates/CRM/Dashlet/Page/AllCases.tpl | 35 + templates/CRM/Dashlet/Page/Blog.tpl | 36 + templates/CRM/Dashlet/Page/CaseDashboard.tpl | 87 + templates/CRM/Dashlet/Page/MyCases.tpl | 35 + .../CRM/Event/Badge/CRM_Event_Badge_Logo.png | Bin 0 -> 15405 bytes .../Event/Badge/CRM_Event_Badge_Logo5395.png | Bin 0 -> 15405 bytes .../Cart/Form/Checkout/ConferenceEvents.tpl | 54 + .../Event/Cart/Form/Checkout/Participant.tpl | 31 + .../Form/Checkout/ParticipantsAndPrices.tpl | 89 + .../CRM/Event/Cart/Form/Checkout/Payment.tpl | 187 + .../CRM/Event/Cart/Form/Checkout/ThankYou.tpl | 164 + .../CRM/Event/Cart/Form/viewCartLink.tpl | 4 + templates/CRM/Event/Cart/Page/AddToCart.tpl | 3 + templates/CRM/Event/Cart/Page/ViewCart.tpl | 29 + templates/CRM/Event/Form/EventFees.tpl | 278 + .../CRM/Event/Form/ManageEvent/Conference.tpl | 83 + .../CRM/Event/Form/ManageEvent/Delete.tpl | 45 + .../CRM/Event/Form/ManageEvent/EventInfo.hlp | 127 + .../CRM/Event/Form/ManageEvent/EventInfo.tpl | 191 + templates/CRM/Event/Form/ManageEvent/Fee.tpl | 388 + .../CRM/Event/Form/ManageEvent/Location.tpl | 166 + .../Event/Form/ManageEvent/Registration.hlp | 90 + .../Event/Form/ManageEvent/Registration.tpl | 453 + .../Form/ManageEvent/ScheduleReminders.tpl | 232 + templates/CRM/Event/Form/ManageEvent/Tab.hlp | 87 + templates/CRM/Event/Form/ManageEvent/Tab.tpl | 101 + templates/CRM/Event/Form/Participant.tpl | 625 + templates/CRM/Event/Form/ParticipantView.tpl | 141 + .../Registration/AdditionalParticipant.tpl | 125 + .../CRM/Event/Form/Registration/Confirm.tpl | 215 + .../Form/Registration/DisplayProfile.tpl | 93 + .../Form/Registration/EventInfoBlock.tpl | 87 + .../Form/Registration/ParticipantConfirm.tpl | 34 + .../Event/Form/Registration/PreviewHeader.tpl | 31 + .../CRM/Event/Form/Registration/Register.tpl | 343 + .../CRM/Event/Form/Registration/ThankYou.tpl | 219 + templates/CRM/Event/Form/Search.tpl | 86 + .../Event/Form/Search/AdvancedSearchPane.tpl | 32 + templates/CRM/Event/Form/Search/Common.tpl | 114 + .../CRM/Event/Form/Search/EmptyResults.tpl | 42 + templates/CRM/Event/Form/Search/Results.hlp | 31 + templates/CRM/Event/Form/SearchEvent.tpl | 77 + templates/CRM/Event/Form/Selector.tpl | 113 + templates/CRM/Event/Form/Task.tpl | 41 + templates/CRM/Event/Form/Task/Badge.tpl | 38 + templates/CRM/Event/Form/Task/Batch.tpl | 105 + templates/CRM/Event/Form/Task/Cancel.tpl | 42 + templates/CRM/Event/Form/Task/Delete.tpl | 45 + templates/CRM/Event/Form/Task/Email.tpl | 26 + .../CRM/Event/Form/Task/ParticipantStatus.hlp | 34 + .../CRM/Event/Form/Task/ParticipantStatus.tpl | 26 + templates/CRM/Event/Form/Task/PickProfile.tpl | 43 + templates/CRM/Event/Form/Task/Print.tpl | 80 + templates/CRM/Event/Form/Task/Result.tpl | 30 + templates/CRM/Event/Form/Task/SaveSearch.tpl | 60 + .../CRM/Event/Form/Task/SaveSearch/Update.tpl | 26 + .../Event/Form/Task/SearchTaskHookSample.tpl | 36 + templates/CRM/Event/Import/Form/MapField.tpl | 69 + templates/CRM/Event/Import/Form/MapTable.tpl | 117 + templates/CRM/Event/Import/Form/Preview.tpl | 100 + templates/CRM/Event/Import/Form/Summary.tpl | 140 + .../CRM/Event/Import/Form/UploadFile.hlp | 59 + .../CRM/Event/Import/Form/UploadFile.tpl | 89 + templates/CRM/Event/Page/DashBoard.hlp | 41 + templates/CRM/Event/Page/DashBoard.tpl | 149 + templates/CRM/Event/Page/EventInfo.tpl | 248 + templates/CRM/Event/Page/ICalendar.tpl | 60 + templates/CRM/Event/Page/ManageEvent.hlp | 69 + templates/CRM/Event/Page/ManageEvent.tpl | 248 + .../Event/Page/ParticipantListing/Name.tpl | 55 + .../Page/ParticipantListing/NameAndEmail.tpl | 56 + .../ParticipantListing/NameStatusAndDate.tpl | 57 + templates/CRM/Event/Page/Tab.tpl | 66 + templates/CRM/Event/Page/UserDashboard.tpl | 72 + templates/CRM/Event/Page/iCalLinks.tpl | 31 + templates/CRM/Export/Form/Map.tpl | 48 + templates/CRM/Export/Form/Select.hlp | 16 + templates/CRM/Export/Form/Select.tpl | 154 + templates/CRM/Export/Form/table.tpl | 92 + templates/CRM/Financial/ExportFormat/IIF.tpl | 66 + .../CRM/Financial/Form/BatchTransaction.tpl | 371 + templates/CRM/Financial/Form/Export.tpl | 64 + .../CRM/Financial/Form/FinancialAccount.tpl | 137 + .../CRM/Financial/Form/FinancialBatch.tpl | 101 + .../CRM/Financial/Form/FinancialType.tpl | 70 + .../Financial/Form/FinancialTypeAccount.tpl | 167 + templates/CRM/Financial/Form/Search.tpl | 333 + templates/CRM/Financial/Page/Batch.tpl | 29 + .../CRM/Financial/Page/BatchTransaction.tpl | 193 + .../CRM/Financial/Page/FinancialAccount.tpl | 88 + .../CRM/Financial/Page/FinancialBatch.hlp | 60 + .../CRM/Financial/Page/FinancialBatch.tpl | 28 + .../CRM/Financial/Page/FinancialType.tpl | 78 + .../Financial/Page/FinancialTypeAccount.tpl | 80 + templates/CRM/Form/attachment.tpl | 191 + templates/CRM/Form/basicForm.tpl | 56 + templates/CRM/Form/body.tpl | 60 + templates/CRM/Form/default.tpl | 36 + templates/CRM/Form/element.tpl | 31 + templates/CRM/Form/error.tpl | 30 + templates/CRM/Form/label.tpl | 39 + templates/CRM/Form/quest.tpl | 32 + templates/CRM/Form/validate.tpl | 85 + templates/CRM/Friend/Form.tpl | 101 + templates/CRM/Friend/Form/Contribute.tpl | 27 + templates/CRM/Friend/Form/Event.tpl | 27 + templates/CRM/Friend/Form/Friend.tpl | 135 + templates/CRM/Friend/Form/Pledge.tpl | 27 + templates/CRM/Grant/Form/Grant.tpl | 147 + templates/CRM/Grant/Form/GrantView.tpl | 83 + templates/CRM/Grant/Form/Search.tpl | 79 + .../Grant/Form/Search/AdvancedSearchPane.tpl | 30 + templates/CRM/Grant/Form/Search/Common.tpl | 99 + .../CRM/Grant/Form/Search/EmptyResults.tpl | 42 + templates/CRM/Grant/Form/Selector.tpl | 91 + templates/CRM/Grant/Form/Task.tpl | 42 + templates/CRM/Grant/Form/Task/Delete.tpl | 32 + templates/CRM/Grant/Form/Task/Print.tpl | 65 + .../Grant/Form/Task/SearchTaskHookSample.tpl | 34 + templates/CRM/Grant/Form/Task/Update.tpl | 71 + templates/CRM/Grant/Page/DashBoard.tpl | 70 + templates/CRM/Grant/Page/Payment.tpl | 28 + templates/CRM/Grant/Page/Tab.tpl | 58 + templates/CRM/Group/Form/Delete.tpl | 40 + templates/CRM/Group/Form/Edit.tpl | 173 + templates/CRM/Group/Form/Search.tpl | 292 + templates/CRM/Group/Page/Group.hlp | 65 + templates/CRM/Group/Page/Group.tpl | 53 + templates/CRM/Group/Page/GroupRows.tpl | 37 + templates/CRM/HRDCase/Form/Case.tpl | 150 + templates/CRM/HRDCase/Form/CaseActivity.tpl | 51 + templates/CRM/HRDCase/Form/CaseView.tpl | 44 + templates/CRM/Import/Form/CSV.tpl | 42 + templates/CRM/Import/Form/DataSource.hlp | 118 + templates/CRM/Import/Form/DataSource.tpl | 192 + templates/CRM/Import/Form/MapField.tpl | 58 + templates/CRM/Import/Form/MapTable.tpl | 172 + templates/CRM/Import/Form/Mapper.tpl | 86 + templates/CRM/Import/Form/Preview.tpl | 246 + templates/CRM/Import/Form/SQL.tpl | 35 + templates/CRM/Import/Form/Summary.tpl | 170 + templates/CRM/Logging/ReportDetail.tpl | 55 + templates/CRM/Logging/ReportSummary.tpl | 26 + templates/CRM/Mailing/Form/Approve.tpl | 69 + templates/CRM/Mailing/Form/Component.tpl | 40 + templates/CRM/Mailing/Form/Count.tpl | 97 + templates/CRM/Mailing/Form/ForwardMailing.tpl | 85 + templates/CRM/Mailing/Form/Group.hlp | 86 + templates/CRM/Mailing/Form/Group.tpl | 96 + templates/CRM/Mailing/Form/InsertTokens.tpl | 467 + templates/CRM/Mailing/Form/Schedule.hlp | 42 + templates/CRM/Mailing/Form/Schedule.tpl | 102 + templates/CRM/Mailing/Form/Search.tpl | 64 + .../Form/Search/AdvancedSearchPane.tpl | 7 + templates/CRM/Mailing/Form/Search/Common.tpl | 82 + templates/CRM/Mailing/Form/Settings.hlp | 40 + templates/CRM/Mailing/Form/Settings.tpl | 119 + templates/CRM/Mailing/Form/Subscribe.tpl | 61 + templates/CRM/Mailing/Form/Test.hlp | 38 + templates/CRM/Mailing/Form/Test.tpl | 77 + templates/CRM/Mailing/Form/Upload.hlp | 63 + templates/CRM/Mailing/Form/Upload.tpl | 134 + templates/CRM/Mailing/Page/Browse.hlp | 38 + templates/CRM/Mailing/Page/Browse.tpl | 155 + templates/CRM/Mailing/Page/Component.tpl | 70 + templates/CRM/Mailing/Page/Confirm.tpl | 33 + templates/CRM/Mailing/Page/Event.tpl | 99 + templates/CRM/Mailing/Page/Optout.tpl | 43 + templates/CRM/Mailing/Page/Report.tpl | 235 + templates/CRM/Mailing/Page/Resubscribe.tpl | 43 + templates/CRM/Mailing/Page/Unsubscribe.tpl | 60 + templates/CRM/Member/Form/Membership.hlp | 41 + templates/CRM/Member/Form/Membership.tpl | 798 + templates/CRM/Member/Form/MembershipBlock.hlp | 46 + templates/CRM/Member/Form/MembershipBlock.tpl | 224 + .../CRM/Member/Form/MembershipRelated.tpl | 64 + .../CRM/Member/Form/MembershipRenewal.tpl | 396 + .../CRM/Member/Form/MembershipStatus.tpl | 109 + templates/CRM/Member/Form/MembershipType.tpl | 267 + templates/CRM/Member/Form/MembershipView.tpl | 94 + templates/CRM/Member/Form/Search.hlp | 35 + templates/CRM/Member/Form/Search.tpl | 80 + .../Member/Form/Search/AdvancedSearchPane.tpl | 32 + templates/CRM/Member/Form/Search/Common.tpl | 111 + .../CRM/Member/Form/Search/EmptyResults.tpl | 42 + templates/CRM/Member/Form/Selector.tpl | 103 + templates/CRM/Member/Form/Task.tpl | 41 + templates/CRM/Member/Form/Task/Batch.tpl | 70 + templates/CRM/Member/Form/Task/Delete.tpl | 39 + templates/CRM/Member/Form/Task/Email.tpl | 26 + .../CRM/Member/Form/Task/PickProfile.tpl | 37 + templates/CRM/Member/Form/Task/Print.tpl | 66 + templates/CRM/Member/Form/Task/Result.tpl | 32 + .../Member/Form/Task/SearchTaskHookSample.tpl | 36 + templates/CRM/Member/Import/Form/MapField.tpl | 53 + templates/CRM/Member/Import/Form/MapTable.tpl | 116 + templates/CRM/Member/Import/Form/Preview.tpl | 95 + templates/CRM/Member/Import/Form/Summary.tpl | 134 + .../CRM/Member/Import/Form/UploadFile.hlp | 56 + .../CRM/Member/Import/Form/UploadFile.tpl | 79 + templates/CRM/Member/Page/DashBoard.hlp | 38 + templates/CRM/Member/Page/DashBoard.tpl | 160 + .../CRM/Member/Page/MembershipStatus.tpl | 82 + templates/CRM/Member/Page/MembershipType.hlp | 70 + templates/CRM/Member/Page/MembershipType.tpl | 90 + templates/CRM/Member/Page/Tab.hlp | 44 + templates/CRM/Member/Page/Tab.tpl | 187 + templates/CRM/Member/Page/UserDashboard.tpl | 94 + templates/CRM/Note/Form/Note.tpl | 28 + templates/CRM/PCP/Form/Campaign.tpl | 91 + templates/CRM/PCP/Form/Contribute.hlp | 90 + templates/CRM/PCP/Form/Contribute.tpl | 36 + templates/CRM/PCP/Form/Event.hlp | 104 + templates/CRM/PCP/Form/Event.tpl | 36 + templates/CRM/PCP/Form/PCP.tpl | 103 + templates/CRM/PCP/Form/PCP/Delete.tpl | 35 + templates/CRM/PCP/Form/PCP/PCP.tpl | 41 + templates/CRM/PCP/Form/PCPAccount.tpl | 53 + templates/CRM/PCP/Page/Contribute.tpl | 26 + templates/CRM/PCP/Page/Event.tpl | 26 + templates/CRM/PCP/Page/PCP.hlp | 34 + templates/CRM/PCP/Page/PCP.tpl | 83 + templates/CRM/PCP/Page/PCPInfo.tpl | 148 + templates/CRM/Pledge/Form/Payment.tpl | 57 + templates/CRM/Pledge/Form/Pledge.tpl | 308 + templates/CRM/Pledge/Form/PledgeView.tpl | 87 + templates/CRM/Pledge/Form/Search.tpl | 88 + .../Pledge/Form/Search/AdvancedSearchPane.tpl | 32 + templates/CRM/Pledge/Form/Search/Common.tpl | 105 + .../CRM/Pledge/Form/Search/EmptyResults.tpl | 40 + templates/CRM/Pledge/Form/Selector.tpl | 142 + templates/CRM/Pledge/Form/Task.tpl | 41 + templates/CRM/Pledge/Form/Task/Delete.tpl | 33 + templates/CRM/Pledge/Form/Task/Print.tpl | 65 + templates/CRM/Pledge/Form/Task/Result.tpl | 30 + templates/CRM/Pledge/Form/Task/SaveSearch.tpl | 58 + .../Pledge/Form/Task/SaveSearch/Update.tpl | 26 + .../Pledge/Form/Task/SearchTaskHookSample.tpl | 37 + templates/CRM/Pledge/Page/DashBoard.tpl | 90 + templates/CRM/Pledge/Page/Payment.hlp | 42 + templates/CRM/Pledge/Page/Payment.tpl | 74 + templates/CRM/Pledge/Page/Tab.hlp | 41 + templates/CRM/Pledge/Page/Tab.tpl | 67 + templates/CRM/Pledge/Page/UserDashboard.tpl | 130 + templates/CRM/Price/Form/Calculate.tpl | 225 + templates/CRM/Price/Form/DeleteField.tpl | 33 + templates/CRM/Price/Form/DeleteSet.tpl | 35 + templates/CRM/Price/Form/Field.tpl | 230 + templates/CRM/Price/Form/LineItem.tpl | 152 + templates/CRM/Price/Form/Option.tpl | 129 + templates/CRM/Price/Form/OptionFields.tpl | 129 + templates/CRM/Price/Form/ParticipantCount.tpl | 207 + templates/CRM/Price/Form/Preview.tpl | 44 + templates/CRM/Price/Form/PriceSet.tpl | 90 + templates/CRM/Price/Form/Set.tpl | 95 + templates/CRM/Price/Page/Field.hlp | 105 + templates/CRM/Price/Page/Field.tpl | 108 + templates/CRM/Price/Page/LineItem.tpl | 122 + templates/CRM/Price/Page/Option.tpl | 97 + templates/CRM/Price/Page/Set.tpl | 94 + templates/CRM/Price/Page/table.tpl | 75 + templates/CRM/Profile/Form/Dynamic.tpl | 376 + templates/CRM/Profile/Form/Edit.tpl | 26 + templates/CRM/Profile/Form/GreetingType.tpl | 47 + templates/CRM/Profile/Form/Search.tpl | 179 + templates/CRM/Profile/Page/Dynamic.tpl | 46 + templates/CRM/Profile/Page/Listings.tpl | 92 + .../Page/MultipleRecordFieldsListing.tpl | 107 + templates/CRM/Profile/Page/Overlay.tpl | 55 + templates/CRM/Profile/Page/View.tpl | 57 + templates/CRM/Queue/Page/Runner.tpl | 146 + templates/CRM/Report/Form.tpl | 68 + templates/CRM/Report/Form/Actions.tpl | 85 + templates/CRM/Report/Form/Activity.tpl | 26 + templates/CRM/Report/Form/ActivitySummary.tpl | 26 + .../Report/Form/Campaign/SurveyCoverSheet.tpl | 91 + .../Report/Form/Campaign/SurveyDetails.tpl | 26 + .../CRM/Report/Form/Case/Demographics.tpl | 26 + templates/CRM/Report/Form/Case/Detail.tpl | 320 + templates/CRM/Report/Form/Case/Summary.tpl | 26 + templates/CRM/Report/Form/Case/TimeSpent.tpl | 26 + .../Report/Form/Contact/CurrentEmployer.tpl | 26 + templates/CRM/Report/Form/Contact/Detail.tpl | 203 + templates/CRM/Report/Form/Contact/Log.tpl | 26 + .../CRM/Report/Form/Contact/LoggingDetail.tpl | 26 + .../Report/Form/Contact/LoggingSummary.tpl | 26 + .../CRM/Report/Form/Contact/Relationship.tpl | 26 + templates/CRM/Report/Form/Contact/Summary.tpl | 26 + .../Report/Form/Contribute/Bookkeeping.tpl | 26 + .../CRM/Report/Form/Contribute/Detail.tpl | 26 + .../CRM/Report/Form/Contribute/History.tpl | 26 + .../Form/Contribute/HouseholdSummary.tpl | 26 + .../Report/Form/Contribute/LoggingDetail.tpl | 26 + .../Report/Form/Contribute/LoggingSummary.tpl | 26 + .../CRM/Report/Form/Contribute/Lybunt.tpl | 26 + .../Form/Contribute/OrganizationSummary.tpl | 26 + templates/CRM/Report/Form/Contribute/PCP.tpl | 26 + .../CRM/Report/Form/Contribute/Repeat.tpl | 26 + .../CRM/Report/Form/Contribute/SoftCredit.tpl | 26 + .../CRM/Report/Form/Contribute/Summary.tpl | 26 + .../CRM/Report/Form/Contribute/Sybunt.tpl | 26 + .../CRM/Report/Form/Contribute/TopDonor.tpl | 26 + templates/CRM/Report/Form/Criteria.tpl | 263 + templates/CRM/Report/Form/ErrorMessage.tpl | 30 + templates/CRM/Report/Form/Event/Income.tpl | 93 + .../Report/Form/Event/IncomeCountSummary.tpl | 27 + .../Form/Event/ParticipantListCount.tpl | 27 + .../Report/Form/Event/ParticipantListing.tpl | 26 + templates/CRM/Report/Form/Event/Summary.tpl | 26 + templates/CRM/Report/Form/Fields.tpl | 81 + templates/CRM/Report/Form/Grant/Detail.tpl | 26 + .../CRM/Report/Form/Grant/Statistics.tpl | 122 + templates/CRM/Report/Form/Instance.tpl | 145 + templates/CRM/Report/Form/Layout/Graph.tpl | 87 + templates/CRM/Report/Form/Layout/Overlay.tpl | 153 + templates/CRM/Report/Form/Layout/Table.tpl | 154 + templates/CRM/Report/Form/Mailing/Bounce.tpl | 26 + templates/CRM/Report/Form/Mailing/Clicks.tpl | 26 + templates/CRM/Report/Form/Mailing/Detail.tpl | 26 + templates/CRM/Report/Form/Mailing/Opened.tpl | 26 + templates/CRM/Report/Form/Mailing/Summary.tpl | 26 + .../Report/Form/Member/ContributionDetail.tpl | 26 + templates/CRM/Report/Form/Member/Detail.tpl | 26 + templates/CRM/Report/Form/Member/Lapse.tpl | 26 + templates/CRM/Report/Form/Member/Summary.tpl | 26 + .../CRM/Report/Form/Membership/Summary.tpl | 26 + templates/CRM/Report/Form/Pledge/Detail.tpl | 26 + templates/CRM/Report/Form/Pledge/Pbnp.tpl | 26 + templates/CRM/Report/Form/Pledge/Summary.tpl | 26 + templates/CRM/Report/Form/Register.tpl | 97 + templates/CRM/Report/Form/Settings.hlp | 78 + templates/CRM/Report/Form/Statistics.tpl | 65 + .../CRM/Report/Form/Walklist/Walklist.tpl | 26 + templates/CRM/Report/Page/InstanceList.tpl | 91 + templates/CRM/Report/Page/List.tpl | 80 + templates/CRM/Report/Page/Options.tpl | 87 + templates/CRM/Report/Page/TemplateList.tpl | 75 + templates/CRM/SMS/Form/Group.hlp | 64 + templates/CRM/SMS/Form/Group.tpl | 81 + templates/CRM/SMS/Form/Provider.tpl | 90 + templates/CRM/SMS/Form/Schedule.hlp | 42 + templates/CRM/SMS/Form/Schedule.tpl | 99 + templates/CRM/SMS/Form/Task/SMS.tpl | 43 + templates/CRM/SMS/Form/Upload.hlp | 51 + templates/CRM/SMS/Form/Upload.tpl | 87 + templates/CRM/SMS/Page/Provider.tpl | 79 + templates/CRM/Tag/Form/Search.tpl | 80 + templates/CRM/Tag/Form/Tag.tpl | 168 + templates/CRM/UF/Form/AdvanceSetting.tpl | 102 + templates/CRM/UF/Form/Block.tpl | 193 + templates/CRM/UF/Form/Field.hlp | 95 + templates/CRM/UF/Form/Field.tpl | 311 + templates/CRM/UF/Form/Group.hlp | 171 + templates/CRM/UF/Form/Group.tpl | 80 + templates/CRM/UF/Form/Preview.tpl | 175 + templates/CRM/UF/Page/Field.tpl | 105 + templates/CRM/UF/Page/Group.hlp | 58 + templates/CRM/UF/Page/Group.tpl | 160 + templates/CRM/UF/Page/ProfileTemplates.tpl | 137 + templates/CRM/Upgrade/Base.tpl | 35 + templates/CRM/Widget/Page/Inline/Example.tpl | 40 + templates/CRM/Widget/widget.tpl | 50 + templates/CRM/common/CMSUser.tpl | 112 + templates/CRM/common/Filter.tpl | 138 + templates/CRM/common/Navigation.tpl | 164 + templates/CRM/common/ReCAPTCHA.tpl | 40 + templates/CRM/common/SectionNav.tpl | 51 + templates/CRM/common/SocialNetwork.tpl | 81 + templates/CRM/common/TabHeader.tpl | 104 + templates/CRM/common/Tag.tpl | 385 + templates/CRM/common/TrackingFields.tpl | 40 + templates/CRM/common/WizardHeader.tpl | 87 + templates/CRM/common/accesskeys.hlp | 36 + templates/CRM/common/accesskeys.tpl | 30 + templates/CRM/common/activityView.tpl | 66 + templates/CRM/common/additionalBlocks.tpl | 202 + templates/CRM/common/batchCopy.tpl | 170 + templates/CRM/common/buildProfileLink.tpl | 14 + .../CRM/common/checkUsernameAvailable.tpl | 82 + templates/CRM/common/civicrm.settings.php.tpl | 310 + templates/CRM/common/civicrm_variables.tpl | 10 + templates/CRM/common/commonCSS.tpl | 46 + templates/CRM/common/contactFooter.tpl | 40 + templates/CRM/common/crmeditable.tpl | 7 + templates/CRM/common/customData.tpl | 124 + templates/CRM/common/dashboard.tpl | 215 + templates/CRM/common/debug.tpl | 48 + templates/CRM/common/dedupe.tpl | 81 + .../CRM/common/displaySearchCriteria.tpl | 66 + templates/CRM/common/drupal.tpl | 81 + templates/CRM/common/drupal6.tpl | 81 + templates/CRM/common/enableDisable.tpl | 206 + templates/CRM/common/fatal.tpl | 88 + templates/CRM/common/footer.tpl | 43 + templates/CRM/common/formButtons.tpl | 41 + templates/CRM/common/formNavigate.tpl | 34 + templates/CRM/common/highLightImport.tpl | 98 + templates/CRM/common/info.tpl | 33 + templates/CRM/common/jcalendar.tpl | 149 + templates/CRM/common/joomla.tpl | 105 + templates/CRM/common/jquery.files.tpl | 71 + templates/CRM/common/jsortable.tpl | 228 + templates/CRM/common/langSwitch.tpl | 36 + templates/CRM/common/localNav.tpl | 34 + templates/CRM/common/notifications.tpl | 8 + templates/CRM/common/openFlashChart.tpl | 62 + templates/CRM/common/overlay.tpl | 54 + templates/CRM/common/pager.tpl | 60 + templates/CRM/common/pagerAToZ.tpl | 33 + templates/CRM/common/paymentBlock.tpl | 81 + templates/CRM/common/print.tpl | 66 + templates/CRM/common/printBody.tpl | 33 + templates/CRM/common/recentlyViewed.tpl | 34 + templates/CRM/common/redirectJS.tpl | 14 + templates/CRM/common/scripts.tpl | 66 + templates/CRM/common/searchResultTasks.tpl | 79 + templates/CRM/common/showHide.tpl | 32 + templates/CRM/common/showHideByFieldValue.tpl | 38 + templates/CRM/common/snippet.tpl | 59 + templates/CRM/common/stateCountry.tpl | 72 + templates/CRM/common/status.tpl | 38 + templates/CRM/common/success.tpl | 60 + templates/CRM/common/upgradeCleanup.tpl | 53 + templates/CRM/common/wordpress.tpl | 121 + templates/CRM/common/wysiwyg.tpl | 35 + tests/README.txt | 16 + tests/bin/api3.php | 0 tests/bin/run.php | 0 tests/extensions/README.txt | 8 + .../info.xml | 4 + .../moduletest.php | 29 + .../info.xml | 21 + .../main.php | 36 + .../info.xml | 8 + .../main.php | 49 + .../info.xml | 8 + .../main.php | 174 + tests/phpunit/AllTests.php | 74 + tests/phpunit/CRM/Activity/AllTests.php | 74 + .../Activity/BAO/ActivityAssignmentTest.php | 125 + .../CRM/Activity/BAO/ActivityTargetTest.php | 74 + .../phpunit/CRM/Activity/BAO/ActivityTest.php | 553 + .../BAO/activities_for_dashboard_count.xml | 518 + tests/phpunit/CRM/AllTests.php | 74 + tests/phpunit/CRM/Bridge/OG/DrupalTest.php | 80 + tests/phpunit/CRM/Contact/AllTests.php | 74 + tests/phpunit/CRM/Contact/BAO/ContactTest.php | 1597 + .../BAO/ContactType/ContactSearchTest.php | 341 + .../Contact/BAO/ContactType/ContactTest.php | 281 + .../BAO/ContactType/ContactTypeTest.php | 234 + .../BAO/ContactType/RelationshipTest.php | 322 + .../CRM/Contact/BAO/DupeContactTest.php | 228 + .../CRM/Contact/BAO/GroupContactCacheTest.php | 259 + .../CRM/Contact/BAO/GroupContactTest.php | 164 + tests/phpunit/CRM/Contact/BAO/GroupTest.php | 97 + tests/phpunit/CRM/Contact/BAO/QueryTest.php | 63 + .../CRM/Contact/BAO/QueryTestDataProvider.php | 146 + .../phpunit/CRM/Contact/BAO/queryDataset.xml | 382 + .../Contact/Form/Search/Custom/GroupTest.php | 262 + .../Search/Custom/GroupTestDataProvider.php | 223 + .../Contact/Form/Search/Custom/dataset.xml | 452 + tests/phpunit/CRM/Contribute/AllTests.php | 74 + .../Contribute/BAO/ContributionPageTest.php | 178 + .../CRM/Contribute/BAO/ContributionTest.php | 456 + .../Contribute/BAO/ContributionTypeTest.php | 120 + .../CRM/Contribute/BAO/ManagePremiumsTest.php | 142 + tests/phpunit/CRM/Core/AllTests.php | 74 + .../CRM/Core/BAO/ActionScheduleTest.php | 471 + tests/phpunit/CRM/Core/BAO/AddressTest.php | 336 + .../phpunit/CRM/Core/BAO/CustomFieldTest.php | 249 + .../phpunit/CRM/Core/BAO/CustomGroupTest.php | 555 + .../Core/BAO/CustomValueTableMultipleTest.php | 156 + .../Core/BAO/CustomValueTableSetGetTest.php | 204 + .../CRM/Core/BAO/CustomValueTableTest.php | 268 + .../phpunit/CRM/Core/BAO/CustomValueTest.php | 159 + tests/phpunit/CRM/Core/BAO/EmailTest.php | 158 + .../CRM/Core/BAO/FinancialTrxnTest.php | 71 + tests/phpunit/CRM/Core/BAO/IMTest.php | 82 + tests/phpunit/CRM/Core/BAO/LocationTest.php | 556 + tests/phpunit/CRM/Core/BAO/OpenIDTest.php | 178 + tests/phpunit/CRM/Core/BAO/PhoneTest.php | 122 + .../phpunit/CRM/Core/BAO/PreferencesTest.php | 70 + tests/phpunit/CRM/Core/BAO/SettingTest.php | 198 + tests/phpunit/CRM/Core/BAO/UFFieldTest.php | 208 + .../phpunit/CRM/Core/BAO/dataset/im_test.xml | 27 + tests/phpunit/CRM/Core/ErrorTest.php | 100 + tests/phpunit/CRM/Core/JobManagerTest.php | 21 + .../phpunit/CRM/Core/ManagedEntitiesTest.php | 282 + tests/phpunit/CRM/Core/Page/AJAXTest.php | 61 + .../CRM/Core/Payment/AuthorizeNetTest.php | 341 + .../phpunit/CRM/Core/Payment/BaseIPNTest.php | 615 + tests/phpunit/CRM/Core/RegionTest.php | 236 + tests/phpunit/CRM/Core/ResourcesTest.php | 302 + tests/phpunit/CRM/Event/AllTests.php | 74 + .../CRM/Event/BAO/ParticipantStatusTest.php | 188 + .../phpunit/CRM/Event/BAO/ParticipantTest.php | 433 + tests/phpunit/CRM/Extension/AllTests.php | 74 + tests/phpunit/CRM/Extension/BrowserTest.php | 67 + .../CRM/Extension/Container/AllTests.php | 74 + .../CRM/Extension/Container/BasicTest.php | 99 + .../Extension/Container/CollectionTest.php | 103 + .../CRM/Extension/Container/StaticTest.php | 62 + tests/phpunit/CRM/Extension/InfoTest.php | 63 + .../CRM/Extension/Manager/AllTests.php | 74 + .../CRM/Extension/Manager/ModuleTest.php | 277 + .../CRM/Extension/Manager/PaymentTest.php | 105 + .../CRM/Extension/Manager/ReportTest.php | 57 + .../CRM/Extension/Manager/SearchTest.php | 58 + tests/phpunit/CRM/Extension/ManagerTest.php | 395 + tests/phpunit/CRM/Extension/MapperTest.php | 90 + .../dataset/good-repository/index.html | 4 + .../test.crm.extension.browsertest.a.xml | 11 + .../test.crm.extension.browsertest.b.xml | 7 + .../Financial/BAO/FinancialAccountTest.php | 154 + .../CRM/Financial/BAO/FinancialItemTest.php | 275 + .../BAO/FinancialTypeAccountTest.php | 197 + .../CRM/Financial/BAO/FinancialTypeTest.php | 126 + .../BAO/PaymentProcessorTypeTest.php | 137 + tests/phpunit/CRM/Mailing/BAO/QueryTest.php | 68 + .../CRM/Mailing/BAO/QueryTestDataProvider.php | 119 + tests/phpunit/CRM/Mailing/BAO/SpoolTest.php | 93 + .../phpunit/CRM/Mailing/BAO/queryDataset.xml | 119 + tests/phpunit/CRM/Member/AllTests.php | 74 + .../CRM/Member/BAO/MembershipLogTest.php | 175 + .../CRM/Member/BAO/MembershipStatusTest.php | 154 + .../phpunit/CRM/Member/BAO/MembershipTest.php | 628 + .../CRM/Member/BAO/MembershipTypeTest.php | 367 + tests/phpunit/CRM/Member/Form/AllTests.php | 74 + .../CRM/Member/Form/MembershipTest.php | 524 + .../phpunit/CRM/Member/Form/dataset/data.xml | 127 + tests/phpunit/CRM/PCP/BAO/PCPTest.php | 200 + tests/phpunit/CRM/Pledge/AllTests.php | 74 + tests/phpunit/CRM/Pledge/BAO/PaymentTest.php | 274 + .../CRM/Pledge/BAO/PledgeBlockTest.php | 190 + tests/phpunit/CRM/Pledge/BAO/PledgeTest.php | 138 + tests/phpunit/CRM/Queue/AllTests.php | 74 + tests/phpunit/CRM/Queue/Queue/AllTests.php | 74 + tests/phpunit/CRM/Queue/Queue/SqlTest.php | 148 + tests/phpunit/CRM/Queue/QueueTest.php | 288 + tests/phpunit/CRM/Queue/RunnerTest.php | 275 + .../phpunit/CRM/UF/Page/ProfileEditorTest.php | 43 + tests/phpunit/CRM/Utils/ArrayTest.php | 85 + tests/phpunit/CRM/Utils/Cache/AllTests.php | 74 + .../phpunit/CRM/Utils/Cache/SqlGroupTest.php | 83 + .../phpunit/CRM/Utils/DeprecatedUtilsTest.php | 112 + tests/phpunit/CRM/Utils/FileTest.php | 18 + tests/phpunit/CRM/Utils/HttpClientTest.php | 70 + tests/phpunit/CRM/Utils/JSTest.php | 110 + tests/phpunit/CRM/Utils/MailTest.php | 64 + tests/phpunit/CRM/Utils/SignerTest.php | 140 + tests/phpunit/CRM/Utils/StringTest.php | 108 + tests/phpunit/CRM/Utils/SystemTest.php | 37 + tests/phpunit/CRM/Utils/ZipTest.php | 145 + tests/phpunit/CiviTest/AuthorizeNet.php | 50 + tests/phpunit/CiviTest/CiviDBAssert.php | 154 + tests/phpunit/CiviTest/CiviMailUtils.php | 321 + .../CiviTest/CiviSeleniumSettings.php.txt | 33 + .../phpunit/CiviTest/CiviSeleniumTestCase.php | 1759 + tests/phpunit/CiviTest/CiviTestCase.php | 175 + tests/phpunit/CiviTest/CiviTestSuite.php | 207 + tests/phpunit/CiviTest/CiviUnitTestCase.php | 2297 + tests/phpunit/CiviTest/Contact.php | 86 + tests/phpunit/CiviTest/ContributionPage.php | 51 + tests/phpunit/CiviTest/Custom.php | 110 + tests/phpunit/CiviTest/Event.php | 43 + tests/phpunit/CiviTest/Membership.php | 77 + tests/phpunit/CiviTest/PCP.php | 116 + tests/phpunit/CiviTest/Participant.php | 36 + tests/phpunit/CiviTest/PaypalPro.php | 50 + .../CiviTest/ReleaseTestSettings.php.txt | 35 + .../CiviTest/civicrm.settings.dist.php | 146 + .../CiviTest/civicrm.settings.local.php.txt | 16 + tests/phpunit/CiviTest/truncate-option.xml | 7 + tests/phpunit/CiviTest/truncate-tag.xml | 7 + tests/phpunit/CiviTest/truncate-ufgroup.xml | 11 + tests/phpunit/CiviTest/truncate.xml | 299 + tests/phpunit/HelloTest.php | 74 + tests/phpunit/Utils.php | 141 + .../WebTest/ACL/AssignUsersToRolesTest.php | 82 + .../Activity/ContactContextAddTest.php | 160 + tests/phpunit/WebTest/Activity/IcalTest.php | 119 + .../WebTest/Activity/StandaloneAddTest.php | 187 + tests/phpunit/WebTest/Admin/CustomAddTest.php | 214 + .../Admin/Form/ScheduleReminderTest.php | 100 + .../Admin/Form/Setting/LocalizationTest.php | 66 + .../WebTest/Admin/MoveCustomDataTest.php | 445 + .../WebTest/Admin/RelationshipTypeAddTest.php | 135 + tests/phpunit/WebTest/AllTests.php | 59 + .../phpunit/WebTest/Campaign/ActivityTest.php | 232 + .../Campaign/CampaignDescriptionTest.php | 112 + .../phpunit/WebTest/Campaign/MailingTest.php | 306 + .../WebTest/Campaign/MembershipTest.php | 196 + .../Campaign/OfflineContributionTest.php | 326 + .../Campaign/OfflineEventRegistrationTest.php | 275 + .../Campaign/OnlineContributionTest.php | 354 + .../Campaign/OnlineEventRegistrationTest.php | 360 + .../Campaign/PetitionUsageScenarioTest.php | 325 + tests/phpunit/WebTest/Campaign/PledgeTest.php | 233 + .../Campaign/SurveyUsageScenarioTest.php | 629 + .../WebTest/Case/ActivityToCaseTest.php | 339 + tests/phpunit/WebTest/Case/AddCaseTest.php | 260 + .../WebTest/Case/CaseCustomFieldsTest.php | 317 + .../WebTest/Case/CaseDashboardTest.php | 114 + .../WebTest/Contact/AddCmsUserTest.php | 133 + .../AddContactsToEventAdvancedSearchTest.php | 83 + tests/phpunit/WebTest/Contact/AddTest.php | 498 + .../WebTest/Contact/AddViaProfileTest.php | 76 + .../WebTest/Contact/AddressParsingTest.php | 164 + .../WebTest/Contact/AdvanceSearchPaneTest.php | 402 + .../AdvanceSearchPrivacyOptionsTest.php | 217 + .../WebTest/Contact/AdvancedSearchTest.php | 508 + .../AdvancedSearchedRelatedContactTest.php | 348 + .../Contact/ContactReferenceFieldTest.php | 194 + .../WebTest/Contact/ContactTagTest.php | 182 + .../Contact/CreateCmsUserFromContactTest.php | 243 + .../WebTest/Contact/CustomDataAddTest.php | 383 + .../DeceasedContactsAdvancedSearchTest.php | 129 + .../WebTest/Contact/DupeContactTest.php | 104 + .../phpunit/WebTest/Contact/GroupAddTest.php | 231 + .../WebTest/Contact/InlineFieldsEditTest.php | 336 + .../WebTest/Contact/MergeContactsTest.php | 676 + .../Contact/MultipleContactSubTypes.php | 318 + .../phpunit/WebTest/Contact/PrevNextTest.php | 143 + .../Contact/PrivacyOptionSearchTest.php | 183 + .../WebTest/Contact/ProfileChecksumTest.php | 190 + .../WebTest/Contact/RelationshipAddTest.php | 368 + .../WebTest/Contact/SearchBuilderTest.php | 352 + tests/phpunit/WebTest/Contact/SearchTest.php | 266 + .../Contact/SearchbyDateFilterTest.php | 372 + .../phpunit/WebTest/Contact/SignatureTest.php | 198 + tests/phpunit/WebTest/Contact/TagAddTest.php | 129 + .../WebTest/Contact/TagSetSearchTest.php | 184 + .../Contact/TaskActionAddToGroupTest.php | 142 + .../Contact/TaskActionSendMassMailing.php | 158 + .../WebTest/Contact/TaskActionSendSMS.php | 132 + .../WebTest/Contact/UpdateProfileTest.php | 79 + .../WebTest/Contribute/AddBatchesTest.php | 249 + .../WebTest/Contribute/AddPricesetTest.php | 840 + .../Contribute/ConfirmOptionalTest.php | 111 + .../Contribute/ContactContextAddTest.php | 213 + .../Contribute/ContributionPageAddTest.php | 235 + .../Contribute/OfflineContributionTest.php | 377 + .../OfflineRecurContributionTest.php | 115 + .../Contribute/OnBehalfOfOrganization.php | 1603 + .../Contribute/OnlineContributionTest.php | 201 + .../OnlineMultiplePaymentProcessorTest.php | 223 + .../OnlineRecurContributionTest.php | 159 + .../phpunit/WebTest/Contribute/PCPAddTest.php | 230 + .../WebTest/Contribute/StandaloneAddTest.php | 199 + .../UpdateBatchPendingContributionTest.php | 267 + .../Contribute/UpdateContributionTest.php | 580 + .../UpdatePendingContributionTest.php | 316 + .../Contribute/VerifySSLContributionTest.php | 135 + tests/phpunit/WebTest/Event/AddEventTest.php | 577 + .../WebTest/Event/AddParticipationTest.php | 422 + .../phpunit/WebTest/Event/AddPricesetTest.php | 528 + .../WebTest/Event/ChangeParticipantStatus.php | 182 + .../WebTest/Event/EventListingTest.php | 174 + .../WebTest/Event/EventWaitListTest.php | 235 + .../MultipleEventRegistrationbyCartTest.php | 476 + .../WebTest/Event/MultiprofileEventTest.php | 841 + tests/phpunit/WebTest/Event/PCPAddTest.php | 509 + .../WebTest/Event/ParticipantCountTest.php | 465 + .../WebTest/Event/ParticipantSearchTest.php | 286 + .../WebTest/Event/PricesetMaxCountTest.php | 1236 + .../phpunit/WebTest/Event/TellAFriendTest.php | 273 + tests/phpunit/WebTest/Export/ContactTest.php | 354 + .../Export/ExportCiviSeleniumTestCase.php | 152 + .../Financial/FinancialAccountTest.php | 138 + .../Financial/FinancialAccountTypeTest.php | 161 + .../Financial/FinancialBatchExport.php | 128 + .../WebTest/Generic/CheckActivityTest.php | 91 + .../WebTest/Generic/CheckDashboardTest.php | 133 + .../phpunit/WebTest/Generic/CheckFindTest.php | 48 + .../Generic/GeneralClickAroundTest.php | 436 + .../WebTest/Grant/ContactContextAddTest.php | 159 + .../WebTest/Grant/CustomFieldsetTest.php | 134 + .../WebTest/Grant/StandaloneAddTest.php | 137 + tests/phpunit/WebTest/Import/ActivityTest.php | 99 + .../WebTest/Import/AddressImportTest.php | 305 + .../WebTest/Import/AddressParsingTest.php | 296 + .../WebTest/Import/ContactCustomDataTest.php | 191 + .../WebTest/Import/ContactSubtypeTest.php | 454 + tests/phpunit/WebTest/Import/ContactTest.php | 430 + .../WebTest/Import/ContributionTest.php | 189 + .../phpunit/WebTest/Import/CustomDataTest.php | 348 + .../phpunit/WebTest/Import/DateFormatTest.php | 482 + .../WebTest/Import/DuplicateMatchingTest.php | 504 + tests/phpunit/WebTest/Import/GroupTest.php | 151 + .../Import/ImportCiviSeleniumTestCase.php | 602 + .../WebTest/Import/MatchExternalIdTest.php | 376 + tests/phpunit/WebTest/Import/MemberTest.php | 208 + .../Import/MultipleRelationshipTest.php | 228 + .../WebTest/Import/ParticipantTest.php | 355 + .../WebTest/Import/SavedMappingTest.php | 145 + tests/phpunit/WebTest/Import/TagTest.php | 146 + .../Mailing/AddMessageTemplateTest.php | 195 + .../Mailing/AddNewMailingComponentTest.php | 195 + tests/phpunit/WebTest/Mailing/MailingTest.php | 585 + tests/phpunit/WebTest/Mailing/SpoolTest.php | 98 + .../Member/BatchUpdateViaProfileTest.php | 288 + .../WebTest/Member/ContactContextAddTest.php | 263 + .../Member/DefaultMembershipPricesetTest.php | 287 + .../WebTest/Member/EditMembershipTest.php | 109 + .../Member/FixedMembershipTypeTest.php | 692 + .../Member/InheritedMembershipTest.php | 280 + .../Member/OfflineAutoRenewMembershipTest.php | 125 + .../OfflineMembershipAddPricesetTest.php | 430 + .../Member/OfflineMembershipRenewTest.php | 444 + .../OnlineAutoRenewMembershipGCTest.php | 198 + .../Member/OnlineAutoRenewMembershipTest.php | 231 + .../OnlineMembershipAddPricesetTest.php | 548 + .../Member/OnlineMembershipCreateTest.php | 262 + .../Member/OnlineMembershipRenewTest.php | 738 + .../Member/SeperateMembershipPaymentTest.php | 185 + .../WebTest/Member/StandaloneAddTest.php | 176 + .../Member/UpdateMembershipScriptTest.php | 138 + .../WebTest/Pledge/ContactContextAddTest.php | 140 + .../ContactContextPledgePaymentAddTest.php | 525 + .../Pledge/StandaloneAddDeleteTest.php | 145 + .../WebTest/Pledge/StandaloneAddTest.php | 119 + .../WebTest/Profile/BatchUpdateTest.php | 776 + tests/phpunit/WebTest/Profile/DedupeTest.php | 89 + .../Profile/MultiRecordProfileAddTest.php | 402 + .../WebTest/Profile/ProfileAddTest.php | 146 + .../Profile/ProfileGroupSubscriptionTest.php | 154 + tests/phpunit/WebTest/Profile/SearchTest.php | 178 + tests/phpunit/WebTest/README | 4 + .../phpunit/WebTest/Release/InstallScript.php | 66 + .../WebTest/Release/ReleaseTestCase.php | 63 + .../phpunit/WebTest/Release/UpgradeScript.php | 50 + tests/phpunit/WebTest/Report/AddTest.php | 198 + .../WebTest/Report/DonarReportTest.php | 122 + .../WebTest/Report/LoggingReportTest.php | 338 + .../Report/RolePermissionReportTest.php | 323 + .../import/ImportActivityTestWHdrs.csv | 1 + .../import/ImportContactTestWHdrs.csv | 1 + .../resources/import/ImportContribs1.csv | 1 + .../resources/import/ImportContribs2.csv | 1 + .../resources/import/ImportContribsExtID.csv | 1 + .../import/ImportContribs_custom.csv | 1 + .../resources/import/ImportHouse_Update.csv | 1 + .../import/ImportHouseholds_WHdrs.csv | 1 + .../resources/import/ImportIndiv_Update.csv | 1 + .../resources/import/ImportOrgs_Update.csv | 1 + .../resources/import/ImportOrgs_WHdrs.csv | 1 + .../resources/import/Import_Participants.csv | 1 + tests/phpunit/api/v3/ACLPermissionTest.php | 274 + tests/phpunit/api/v3/APIStandardsTest.php | 180 + tests/phpunit/api/v3/APITest.php | 172 + tests/phpunit/api/v3/ActivityTest.php | 1382 + tests/phpunit/api/v3/ActivityTypeTest.php | 122 + tests/phpunit/api/v3/AddressTest.php | 314 + tests/phpunit/api/v3/AllTests.php | 80 + tests/phpunit/api/v3/BatchTest.php | 239 + tests/phpunit/api/v3/CRM11793Test.php | 77 + tests/phpunit/api/v3/CampaignTest.php | 57 + tests/phpunit/api/v3/CaseTest.php | 537 + tests/phpunit/api/v3/ConstantTest.php | 188 + tests/phpunit/api/v3/ContactTest.php | 1795 + tests/phpunit/api/v3/ContactTypeTest.php | 457 + tests/phpunit/api/v3/ContributionPageTest.php | 141 + .../phpunit/api/v3/ContributionRecurTest.php | 115 + tests/phpunit/api/v3/ContributionTest.php | 1662 + tests/phpunit/api/v3/CustomFieldTest.php | 310 + tests/phpunit/api/v3/CustomGroupTest.php | 421 + tests/phpunit/api/v3/CustomSearchTest.php | 74 + .../api/v3/CustomValueContactTypeTest.php | 316 + tests/phpunit/api/v3/CustomValueTest.php | 133 + tests/phpunit/api/v3/DomainTest.php | 232 + tests/phpunit/api/v3/EmailTest.php | 414 + tests/phpunit/api/v3/EntityTagTest.php | 481 + tests/phpunit/api/v3/EventTest.php | 607 + tests/phpunit/api/v3/GrantTest.php | 189 + tests/phpunit/api/v3/GroupContactTest.php | 227 + tests/phpunit/api/v3/GroupNestingTest.php | 325 + .../phpunit/api/v3/GroupOrganizationTest.php | 275 + tests/phpunit/api/v3/GroupTest.php | 184 + tests/phpunit/api/v3/ImTest.php | 104 + tests/phpunit/api/v3/JobTest.php | 221 + tests/phpunit/api/v3/LineItemTest.php | 122 + tests/phpunit/api/v3/LocBlockTest.php | 102 + tests/phpunit/api/v3/MailSettingsTest.php | 73 + tests/phpunit/api/v3/MailingGroupTest.php | 217 + tests/phpunit/api/v3/MailingTest.php | 161 + .../phpunit/api/v3/MembershipPaymentTest.php | 185 + tests/phpunit/api/v3/MembershipStatusTest.php | 304 + tests/phpunit/api/v3/MembershipTest.php | 783 + tests/phpunit/api/v3/MembershipTypeTest.php | 367 + tests/phpunit/api/v3/NoteTest.php | 372 + tests/phpunit/api/v3/OptionGroupTest.php | 123 + tests/phpunit/api/v3/OptionValueTest.php | 211 + .../phpunit/api/v3/ParticipantPaymentTest.php | 468 + .../api/v3/ParticipantStatusTypeTest.php | 61 + tests/phpunit/api/v3/ParticipantTest.php | 800 + .../api/v3/PaymentProcessorTypeTest.php | 318 + tests/phpunit/api/v3/PhoneTest.php | 213 + tests/phpunit/api/v3/PledgePaymentTest.php | 338 + tests/phpunit/api/v3/PledgeTest.php | 574 + tests/phpunit/api/v3/PriceFieldTest.php | 107 + tests/phpunit/api/v3/PriceFieldValueTest.php | 204 + tests/phpunit/api/v3/PriceSetTest.php | 118 + tests/phpunit/api/v3/ProfileTest.php | 655 + tests/phpunit/api/v3/RelationshipTest.php | 993 + tests/phpunit/api/v3/RelationshipTypeTest.php | 394 + tests/phpunit/api/v3/ReportTemplateTest.php | 121 + tests/phpunit/api/v3/SettingTest.php | 489 + tests/phpunit/api/v3/SurveyRespondantTest.php | 85 + tests/phpunit/api/v3/SurveyTest.php | 103 + .../v3/SyntaxConformanceAllEntitiesTest.php | 804 + tests/phpunit/api/v3/SystemTest.php | 94 + tests/phpunit/api/v3/TagTest.php | 274 + tests/phpunit/api/v3/UFFieldTest.php | 420 + tests/phpunit/api/v3/UFGroupTest.php | 290 + tests/phpunit/api/v3/UFJoinTest.php | 294 + tests/phpunit/api/v3/UFMatchTest.php | 163 + tests/phpunit/api/v3/UtilsTest.php | 259 + tests/phpunit/api/v3/WebsiteTest.php | 108 + tests/phpunit/api/v3/dataset/acl_1_all.xml | 43 + .../api/v3/dataset/activity_1_emailed.xml | 58 + .../api/v3/dataset/activity_4_created.xml | 56 + tests/phpunit/api/v3/dataset/activity_email | 6 + .../api/v3/dataset/activity_email_unparseable | 1 + .../v3/dataset/activity_target_1_emailed.xml | 14 + .../api/v3/dataset/activity_type_5.xml | 52 + tests/phpunit/api/v3/dataset/contact_1.xml | 94 + tests/phpunit/api/v3/dataset/contact_17.xml | 94 + tests/phpunit/api/v3/dataset/contact_hld.xml | 104 + .../api/v3/dataset/contact_hld_upd.xml | 104 + tests/phpunit/api/v3/dataset/contact_ind.xml | 104 + .../api/v3/dataset/contact_ind_upd.xml | 104 + tests/phpunit/api/v3/dataset/contact_org.xml | 104 + .../api/v3/dataset/contact_org_upd.xml | 104 + .../api/v3/dataset/contribution_types.xml | 31 + .../v3/dataset/custom_group_activity_type.xml | 23 + .../api/v3/dataset/email_contact_17.xml | 28 + .../api/v3/dataset/financial_accounts.xml | 34 + .../api/v3/dataset/financial_types.xml | 25 + .../v3/dataset/financial_types_account.xml | 25 + tests/phpunit/api/v3/dataset/group_admins.xml | 40 + .../api/v3/dataset/group_contact_admins_1.xml | 20 + .../phpunit/api/v3/dataset/group_nesting.xml | 29 + .../api/v3/dataset/group_subscribers.xml | 76 + .../api/v3/dataset/location_type_data.xml | 58 + tests/phpunit/api/v3/dataset/openid.xml | 9 + .../api/v3/dataset/option_group_acl_role.xml | 20 + .../api/v3/dataset/option_group_activity.xml | 25 + .../api/v3/dataset/option_group_case.xml | 18 + .../option_group_contribution_status.xml | 11 + .../dataset/option_group_email_greeting.xml | 11 + .../option_group_from_email_address.xml | 11 + .../v3/dataset/option_group_mail_protocol.xml | 10 + .../v3/dataset/option_group_phone_type.xml | 10 + .../api/v3/dataset/option_value_acl_roles.xml | 38 + .../api/v3/dataset/option_value_activity.xml | 181 + .../api/v3/dataset/option_value_case.xml | 121 + .../v3/dataset/option_value_case_activity.xml | 308 + .../option_value_contribution_status.xml | 123 + .../dataset/option_value_email_greeting.xml | 77 + .../option_value_from_email_address.xml | 38 + .../v3/dataset/option_value_mail_protocol.xml | 88 + .../v3/dataset/option_value_phone_type.xml | 105 + .../api/v3/Contact/ExampleAction2.php | 12 + .../api/v3/Generic/ExampleAction1.php | 12 + .../api/v3/Generic/ExampleAction2.php | 12 + .../v3/dataset/resolver/api/v3/TestEntity.php | 12 + .../api/v3/dataset/uf_field_uf_group_25.xml | 156 + tests/phpunit/api/v3/dataset/uf_group_25.xml | 52 + .../dataset/uf_group_contact_activity_26.xml | 132 + .../phpunit/api/v3/dataset/uf_group_test.xml | 22 + .../configuration/AdultDayCareReferral.xml | 84 + .../Case/xml/configuration/HousingSupport.xml | 109 + .../CRM/Case/xml/configuration/Settings.xml | 25 + tests/qunit/README.txt | 114 + tests/qunit/example/test.js | 11 + tests/qunit/example/test.php | 4 + tests/qunit/profile-editor/test.js | 50 + tests/qunit/profile-editor/test.php | 2 + tests/templates/documentFunction.tpl | 45 + tools/CRM/Auction/BAO/Auction.php | 195 + tools/CRM/Auction/BAO/Item.php | 202 + tools/CRM/Auction/Config.php | 41 + tools/CRM/Auction/Controller/Item.php | 75 + tools/CRM/Auction/Form/Auction.php | 260 + tools/CRM/Auction/Form/Item.php | 335 + tools/CRM/Auction/Form/ItemAccount.php | 223 + tools/CRM/Auction/Form/SearchAuction.php | 102 + tools/CRM/Auction/Form/SearchItem.php | 91 + tools/CRM/Auction/Info.php | 101 + tools/CRM/Auction/Page/AddItem.php | 98 + tools/CRM/Auction/Page/DashBoard.php | 54 + tools/CRM/Auction/Page/Item.php | 279 + tools/CRM/Auction/Page/Manage.php | 340 + tools/CRM/Auction/Page/ManageItem.php | 373 + tools/CRM/Auction/StateMachine/Item.php | 66 + tools/CRM/Auction/xml/Menu/Auction.xml | 100 + tools/CRM/Touchstone/Config.php | 42 + tools/CRM/Touchstone/Info.php | 93 + tools/CRM/Touchstone/PseudoConstant.php | 59 + tools/CRM/Touchstone/Task.php | 80 + tools/bin/scripts/ImportTags.php | 95 + tools/bin/scripts/NormalizePhone.php | 138 + tools/bin/scripts/README.txt | 1 + tools/bin/scripts/ajax.php | 248 + tools/bin/scripts/cli.php | 103 + tools/bin/scripts/createdoc.sh | 68 + tools/bin/scripts/delete.sh | 10 + tools/bin/scripts/drop-closing-php-tags.sh | 5 + tools/bin/scripts/ircbot-civi.py | 225 + tools/bin/scripts/memcache.php | 13 + tools/bin/scripts/postIPN.sh | 3 + tools/bin/scripts/replace.sh | 7 + tools/bin/scripts/runCPSTest.sh | 69 + tools/bin/scripts/runStressTest.sh.txt | 86 + tools/bin/scripts/runTest.sh | 202 + tools/bin/scripts/soapClient.php.txt | 16 + tools/bin/scripts/syncPackages.sh | 17 + tools/bin/scripts/testProcess.php | 36 + tools/bin/scripts/test_sandbox.sh | 208 + tools/bin/scripts/updateNameCache.php | 159 + .../ccrm_extensionvalidation.info | 13 + .../ccrm_extensionvalidation.module | 334 + .../ccrm_extensionvalidation.test | 170 + .../ccrm_extensionvalidation.version.inc | 107 + .../civicrm_ICIRR/ICIRR/Form/Profile.php | 89 + .../modules/civicrm_ICIRR/civicrm_ICIRR.info | 6 + .../civicrm_ICIRR/civicrm_ICIRR.module | 158 + .../CRM/Activity/Form/Activity.extra.tpl | 96 + .../templates/CRM/Activity/Form/Activity.tpl | 364 + .../templates/ICIRR/Form/Profile.tpl | 68 + .../modules/civicrm_NYSS/civicrm_NYSS.info | 6 + .../modules/civicrm_NYSS/civicrm_NYSS.module | 173 + .../civicrm_NYSS/sql/civicrm_NYSS.mysql | 7 + .../civicrm_giftaid/CustomGroupData.xml | 427 + .../GiftAid/Form/Task/AddToGiftAid.php | 162 + .../Report/Form/Contribute/GiftAid.php | 176 + .../GiftAid/Utils/Contribution.php | 264 + .../civicrm_giftaid/GiftAid/Utils/GiftAid.php | 325 + .../civicrm_giftaid/GiftAid/Utils/Hook.php | 109 + tools/drupal/modules/civicrm_giftaid/README | 8 + .../civicrm_giftaid/civicrm_giftaid.admin.inc | 30 + .../civicrm_giftaid/civicrm_giftaid.info | 7 + .../civicrm_giftaid/civicrm_giftaid.install | 6 + .../civicrm_giftaid/civicrm_giftaid.module | 229 + .../GiftAid/Form/Task/AddToGiftAid.tpl | 151 + .../Report/Form/Contribute/GiftAid.tpl | 27 + .../civicrm_giftaid/tests/DeclarationTest.php | 113 + .../civicrm_giftaid_alpha/CustomGroupData.xml | 80 + .../civicrm_giftaid_alpha.info | 8 + .../civicrm_giftaid_alpha.module | 180 + .../civicrm_professionals.info | 6 + .../civicrm_professionals.module | 44 + .../civicrm_regsite/civicrm_regsite.info | 6 + .../civicrm_regsite/civicrm_regsite.module | 408 + .../templates/CRM/Profile/Form/15/Edit.tpl | 307 + .../CRM/Profile/Form/Survey/Edit.tpl | 290 + .../CRM/Profile/Page/Regsite/Dynamic.tpl | 53 + .../CRM/Profile/Page/Survey/Dynamic.tpl | 51 + .../templates/Mail/RegSite/Message.tpl | 26 + .../templates/Mail/RegSite/Subject.tpl | 1 + .../templates/Mail/Survey/Message.tpl | 10 + .../templates/Mail/Survey/Subject.tpl | 1 + .../civicrm_regsite/xml/CustomGroupData.xml | 1243 + tools/drupal/modules/civicrm_van/VAN/Auth.php | 79 + .../modules/civicrm_van/VAN/Contact.php | 198 + .../drupal/modules/civicrm_van/VAN/Person.php | 142 + .../modules/civicrm_van/VAN/apiKey.php.txt | 3 + .../modules/civicrm_van/civicrm_van.info | 7 + .../modules/civicrm_van/civicrm_van.module | 34 + tools/drupal/modules/civicrm_van/run.php | 11 + .../civicrm_van/xml/CustomGroupData.xml | 281 + .../civicrm_webtest/civicrm_webtest.info | 7 + .../civicrm_webtest/civicrm_webtest.install | 91 + .../civicrm_webtest/civicrm_webtest.module | 1 + tools/drupal/modules/extdir/extdir.info | 5 + tools/drupal/modules/extdir/extdir.module | 65 + tools/drupal/modules/extdir/extdir.pages.inc | 258 + .../drupal/modules/extdir/extdir_list.tpl.php | 11 + .../modules/multicurrency/multicurrency.info | 7 + .../multicurrency/multicurrency.module | 213 + .../multicurrency.module.discount | 197 + .../multicurrency.module.original | 90 + .../Event/Form/Registration/4/Register.tpl | 195 + .../Event/Form/Registration/8/Register.tpl | 195 + .../templates/CRM/Event/Page/4/EventInfo.tpl | 83 + .../templates/CRM/Event/Page/8/EventInfo.tpl | 83 + .../CRM/Demoqueue/Page/DemoQueue.php | 82 + .../CRM/Demoqueue/Page/DemoQueueDone.php | 11 + .../org.civicrm.demoqueue/demoqueue.civix.php | 33 + .../org.civicrm.demoqueue/demoqueue.php | 19 + .../extensions/org.civicrm.demoqueue/info.xml | 22 + .../CRM/Demoqueue/Page/DemoQueue.tpl | 7 + .../CRM/Demoqueue/Page/DemoQueueDone.tpl | 1 + .../xml/Menu/demoqueue.xml | 15 + tools/extensions/org.civicrm.multisite.zip | Bin 0 -> 7467 bytes .../api/v3/MultisiteDomain/Create.php | 58 + .../extensions/org.civicrm.multisite/info.xml | 27 + .../org.civicrm.multisite/multisite.civix.php | 169 + .../org.civicrm.multisite/multisite.php | 304 + .../settings/Multisite.setting.php | 52 + .../org.civicrm.payment.googlecheckout.zip | Bin 0 -> 37060 bytes .../GoogleCheckout.php | 317 + .../GoogleIPN.php | 565 + .../googleNotify.php | 46 + .../info.xml | 40 + .../packages/Google/README | 115 + .../packages/Google/demo/cartdemo.php | 178 + .../Google/demo/responsehandlerdemo.php | 292 + .../packages/Google/library/googlecart.php | 454 + .../packages/Google/library/googleitem.php | 55 + .../library/googlemerchantcalculations.php | 97 + .../Google/library/googleresponse.php | 271 + .../packages/Google/library/googleresult.php | 100 + .../Google/library/googleshipping.php | 117 + .../packages/Google/library/googletaxrule.php | 81 + .../Google/library/googletaxtable.php | 47 + .../library/xml-processing/xmlbuilder.php | 89 + .../library/xml-processing/xmlparser.php | 170 + .../Baykeeper.php | 670 + .../templates/Baykeeper.tpl | 33 + tools/extensions/org.civicrm.report.grant.zip | Bin 0 -> 4681 bytes .../org.civicrm.report.grant/Grant.php | 339 + .../org.civicrm.report.grant/info.xml | 27 + .../templates/Grant.tpl | 26 + .../org.civicrm.search.activity.zip | Bin 0 -> 8088 bytes .../ActivitySearch.php | 355 + .../org.civicrm.search.activity/info.xml | 22 + .../templates/ActivitySearch.tpl | 155 + tools/extensions/org.civicrm.search.basic.zip | Bin 0 -> 2751 bytes .../org.civicrm.search.basic/Basic.php | 142 + .../org.civicrm.search.basic/info.xml | 21 + .../org.civicrm.search.multivalue.zip | Bin 0 -> 6321 bytes .../MultiValue.php | 250 + .../org.civicrm.search.multivalue/info.xml | 23 + .../templates/MultipleValues.tpl | 148 + .../extensions/org.civicrm.sms.clickatell.zip | Bin 0 -> 7342 bytes .../clickatell.civix.php | 152 + .../org.civicrm.sms.clickatell/clickatell.php | 115 + .../org.civicrm.sms.clickatell/info.xml | 19 + .../org_civicrm_sms_clickatell.php | 440 + tools/extensions/org.civicrm.sms.twilio.zip | Bin 0 -> 7327 bytes .../org.civicrm.sms.twilio/info.xml | 19 + .../org_civicrm_sms_twilio.php | 223 + .../org.civicrm.sms.twilio/twilio.civix.php | 152 + .../org.civicrm.sms.twilio/twilio.php | 115 + tools/scripts/build.xml | 34 + .../civimail-spooler/civimail-spooler.php | 45 + tools/scripts/csv-generator/csv_generator.php | 32 + tools/scripts/mk-drupal-test-site | 142 + tools/scripts/phpdoc | 46 + tools/scripts/phpunit | 76 + tools/scripts/phpunit-jenkins | 50 + .../scripts/phpunit-xslt/coverage-frames.xsl | 668 + tools/scripts/phpunit-xslt/log.xsl | 216 + tools/scripts/phpunit-xslt/phpunit-frames.xsl | 694 + .../scripts/phpunit-xslt/phpunit-noframes.xsl | 448 + .../phpunit-xslt/str.replace.function.xsl | 105 + tools/scripts/phpunit.xml | 30 + tools/scripts/procmail/original-to.pl | 22 + .../release-testing/schemaverificationtest.sh | 17 + .../release-testing/simpleupgradetest.sh | 8 + tools/scripts/release-testing/upgrader.sh.txt | 376 + tools/scripts/releaser/build-tarballs | 84 + tools/scripts/runTests.sh.txt | 180 + tools/scripts/solr/createMigrationTable.sql | 8 + tools/scripts/solr/createSolrJSON.php | 344 + tools/scripts/solr/createSolrXML.php | 237 + tools/scripts/solr/createSyncJSON.php | 482 + tools/scripts/solr/database.xml | 3160 ++ tools/scripts/solr/schema.xml | 328 + tools/scripts/solr/solrconfig.xml | 301 + .../scripts/upgrade-test/run-upgrade-test.sh | 35 + tools/sites/latest/robots.txt | 2 + tools/sites/latest/stable.php | 160 + tools/sites/stats/graphs.php | 111 + tools/sites/stats/index.php | 242 + tools/sites/stats/robots.txt | 2 + tools/sites/stats/stats.php | 212 + tools/sql/civiauction_sample.mysql | 80 + tools/templates/CRM/Auction/Form/Auction.tpl | 61 + tools/templates/CRM/Auction/Form/Item.tpl | 53 + .../CRM/Auction/Form/ItemAccount.tpl | 52 + .../CRM/Auction/Form/SearchAuction.tpl | 72 + .../templates/CRM/Auction/Form/SearchItem.tpl | 53 + .../templates/CRM/Auction/Page/DashBoard.tpl | 26 + tools/templates/CRM/Auction/Page/Item.tpl | 85 + tools/templates/CRM/Auction/Page/Manage.tpl | 86 + .../templates/CRM/Auction/Page/ManageItem.tpl | 97 + .../Form/Search/AdvancedSearchPane.tpl | 34 + tools/tests/reports/index.html | 13 + tools/xml/schema/Auction/Auction.xml | 134 + tools/xml/schema/Auction/Bid.xml | 100 + tools/xml/schema/Auction/Item.xml | 258 + tools/xml/schema/Auction/files.xml | 8 + xml/GenCode.php | 920 + xml/configuration/AdultDayCareReferral.xml | 84 + xml/configuration/HousingSupport.xml | 109 + xml/configuration/Settings.xml | 25 + xml/plugins/block.ts.php | 5 + xml/schema/ACL/ACL.xml | 95 + xml/schema/ACL/Cache.xml | 58 + xml/schema/ACL/EntityRole.xml | 59 + xml/schema/ACL/files.xml | 9 + xml/schema/Activity/Activity.xml | 389 + xml/schema/Activity/ActivityAssignment.xml | 101 + xml/schema/Activity/ActivityContact.xml | 70 + xml/schema/Activity/ActivityTarget.xml | 61 + xml/schema/Activity/files.xml | 6 + xml/schema/Batch/Batch.xml | 153 + xml/schema/Batch/EntityBatch.xml | 61 + xml/schema/Batch/files.xml | 6 + xml/schema/Bridge/OG.xml | 83 + xml/schema/Bridge/Role.xml | 44 + xml/schema/Bridge/files.xml | 8 + xml/schema/Campaign/Campaign.xml | 201 + xml/schema/Campaign/CampaignGroup.xml | 60 + xml/schema/Campaign/Survey.xml | 201 + xml/schema/Campaign/files.xml | 7 + xml/schema/Case/Case.xml | 164 + xml/schema/Case/CaseActivity.xml | 76 + xml/schema/Case/CaseContact.xml | 55 + xml/schema/Case/files.xml | 7 + xml/schema/Contact/ACLContactCache.xml | 63 + xml/schema/Contact/Contact.xml | 658 + xml/schema/Contact/ContactType.xml | 82 + xml/schema/Contact/DashboardContact.xml | 94 + xml/schema/Contact/Group.xml | 190 + xml/schema/Contact/GroupContact.xml | 94 + xml/schema/Contact/GroupContactCache.xml | 55 + xml/schema/Contact/GroupNesting.xml | 49 + xml/schema/Contact/GroupOrganization.xml | 56 + xml/schema/Contact/Household.xml | 68 + xml/schema/Contact/Individual.xml | 225 + xml/schema/Contact/Organization.xml | 87 + xml/schema/Contact/Relationship.xml | 130 + xml/schema/Contact/RelationshipType.xml | 121 + xml/schema/Contact/SavedSearch.xml | 80 + xml/schema/Contact/SubscriptionHistory.xml | 76 + xml/schema/Contact/files.xml | 19 + xml/schema/Contribute/Contribution.xml | 391 + xml/schema/Contribute/ContributionPage.xml | 406 + xml/schema/Contribute/ContributionProduct.xml | 110 + xml/schema/Contribute/ContributionRecur.xml | 270 + xml/schema/Contribute/ContributionSoft.xml | 113 + xml/schema/Contribute/Premium.xml | 96 + xml/schema/Contribute/PremiumsProduct.xml | 77 + xml/schema/Contribute/Product.xml | 175 + xml/schema/Contribute/Widget.xml | 127 + xml/schema/Contribute/files.xml | 14 + xml/schema/Core/ActionLog.xml | 85 + xml/schema/Core/ActionMapping.xml | 75 + xml/schema/Core/ActionSchedule.xml | 220 + xml/schema/Core/Address.xml | 319 + xml/schema/Core/AddressFormat.xml | 26 + xml/schema/Core/Cache.xml | 80 + xml/schema/Core/Component.xml | 37 + xml/schema/Core/Country.xml | 97 + xml/schema/Core/County.xml | 58 + xml/schema/Core/CustomField.xml | 238 + xml/schema/Core/CustomGroup.xml | 184 + xml/schema/Core/Dashboard.xml | 124 + xml/schema/Core/Discount.xml | 95 + xml/schema/Core/Domain.xml | 130 + xml/schema/Core/Email.xml | 141 + xml/schema/Core/EntityFile.xml | 60 + xml/schema/Core/EntityTag.xml | 83 + xml/schema/Core/Extension.xml | 93 + xml/schema/Core/File.xml | 60 + xml/schema/Core/IM.xml | 94 + xml/schema/Core/Job.xml | 101 + xml/schema/Core/JobLog.xml | 73 + xml/schema/Core/LocBlock.xml | 117 + xml/schema/Core/LocationType.xml | 76 + xml/schema/Core/Log.xml | 67 + xml/schema/Core/MailSettings.xml | 106 + xml/schema/Core/Managed.xml | 65 + xml/schema/Core/Mapping.xml | 54 + xml/schema/Core/MappingField.xml | 133 + xml/schema/Core/Menu.xml | 171 + xml/schema/Core/MessageTemplate.xml | 91 + xml/schema/Core/Navigation.xml | 98 + xml/schema/Core/Note.xml | 87 + xml/schema/Core/OpenID.xml | 79 + xml/schema/Core/OptionGroup.xml | 64 + xml/schema/Core/OptionValue.xml | 164 + xml/schema/Core/Persistent.xml | 49 + xml/schema/Core/Phone.xml | 144 + xml/schema/Core/Preferences.xml | 202 + xml/schema/Core/PreferencesDate.xml | 75 + xml/schema/Core/PrevNextCache.xml | 67 + xml/schema/Core/Setting.xml | 110 + xml/schema/Core/StateProvince.xml | 58 + xml/schema/Core/Tag.xml | 101 + xml/schema/Core/Timezone.xml | 60 + xml/schema/Core/UFField.xml | 188 + xml/schema/Core/UFGroup.xml | 214 + xml/schema/Core/UFJoin.xml | 77 + xml/schema/Core/UFMatch.xml | 104 + xml/schema/Core/Website.xml | 61 + xml/schema/Core/Worldregion.xml | 29 + xml/schema/Core/files.xml | 54 + xml/schema/Dedupe/Exception.xml | 54 + xml/schema/Dedupe/Rule.xml | 61 + xml/schema/Dedupe/RuleGroup.xml | 76 + xml/schema/Dedupe/files.xml | 8 + xml/schema/Event/Cart/Cart.xml | 39 + xml/schema/Event/Cart/EventInCart.xml | 46 + xml/schema/Event/Cart/files.xml | 5 + xml/schema/Event/Event.xml | 619 + xml/schema/Event/EventPage.xml | 209 + xml/schema/Event/Participant.xml | 262 + xml/schema/Event/ParticipantPayment.xml | 57 + xml/schema/Event/ParticipantStatusType.xml | 79 + xml/schema/Event/files.xml | 7 + xml/schema/Financial/Currency.xml | 51 + .../Financial/EntityFinancialAccount.xml | 59 + xml/schema/Financial/EntityFinancialTrxn.xml | 63 + xml/schema/Financial/FinancialAccount.xml | 147 + xml/schema/Financial/FinancialItem.xml | 138 + xml/schema/Financial/FinancialTrxn.xml | 196 + xml/schema/Financial/FinancialType.xml | 80 + xml/schema/Financial/PaymentProcessor.xml | 176 + xml/schema/Financial/PaymentProcessorType.xml | 171 + xml/schema/Financial/Receipt.xml | 144 + xml/schema/Financial/files.xml | 15 + xml/schema/Friend/Friend.xml | 83 + xml/schema/Friend/files.xml | 7 + xml/schema/GccSchema.xml | 23 + xml/schema/Grant/Grant.xml | 183 + xml/schema/Grant/files.xml | 5 + xml/schema/Mailing/BouncePattern.xml | 35 + xml/schema/Mailing/BounceType.xml | 36 + xml/schema/Mailing/Component.xml | 62 + xml/schema/Mailing/Event/Bounce.xml | 47 + xml/schema/Mailing/Event/Confirm.xml | 36 + xml/schema/Mailing/Event/Delivered.xml | 36 + xml/schema/Mailing/Event/Forward.xml | 47 + xml/schema/Mailing/Event/Opened.xml | 36 + xml/schema/Mailing/Event/Queue.xml | 73 + xml/schema/Mailing/Event/Reply.xml | 36 + xml/schema/Mailing/Event/Subscribe.xml | 55 + xml/schema/Mailing/Event/TrackableURLOpen.xml | 48 + xml/schema/Mailing/Event/Unsubscribe.xml | 42 + xml/schema/Mailing/Event/files.xml | 16 + xml/schema/Mailing/Group.xml | 59 + xml/schema/Mailing/Job.xml | 92 + xml/schema/Mailing/Mailing.xml | 293 + xml/schema/Mailing/Recipients.xml | 66 + xml/schema/Mailing/Spool.xml | 54 + xml/schema/Mailing/TrackableURL.xml | 37 + xml/schema/Mailing/files.xml | 14 + xml/schema/Member/Membership.xml | 205 + xml/schema/Member/MembershipBlock.xml | 120 + xml/schema/Member/MembershipLog.xml | 103 + xml/schema/Member/MembershipPayment.xml | 54 + xml/schema/Member/MembershipStatus.xml | 122 + xml/schema/Member/MembershipType.xml | 216 + xml/schema/Member/files.xml | 11 + xml/schema/PCP/PCP.xml | 150 + xml/schema/PCP/PCPBlock.xml | 116 + xml/schema/PCP/files.xml | 6 + xml/schema/Pledge/Pledge.xml | 279 + xml/schema/Pledge/PledgeBlock.xml | 80 + xml/schema/Pledge/PledgePayment.xml | 126 + xml/schema/Pledge/files.xml | 8 + xml/schema/Price/Field.xml | 162 + xml/schema/Price/FieldValue.xml | 153 + xml/schema/Price/LineItem.xml | 148 + xml/schema/Price/Set.xml | 143 + xml/schema/Price/SetEntity.xml | 55 + xml/schema/Price/files.xml | 9 + xml/schema/Project/Project.xml | 98 + xml/schema/Project/Task.xml | 120 + xml/schema/Project/TaskStatus.xml | 109 + xml/schema/Project/files.xml | 8 + xml/schema/QuestSchema.xml | 24 + xml/schema/Queue/QueueItem.xml | 59 + xml/schema/Queue/files.xml | 5 + xml/schema/Report/Instance.xml | 170 + xml/schema/Report/files.xml | 6 + xml/schema/SMS/History.xml | 49 + xml/schema/SMS/Provider.xml | 77 + xml/schema/SMS/files.xml | 8 + xml/schema/Schema.xml | 34 + xml/schema/Standalone/OpenID/Associations.xml | 58 + xml/schema/Standalone/OpenID/Nonces.xml | 43 + xml/schema/Standalone/OpenID/files.xml | 7 + xml/templates/access.tpl | 10 + xml/templates/civicrm_acl.tpl | 103 + xml/templates/civicrm_country.tpl | 290 + xml/templates/civicrm_currency.tpl | 209 + xml/templates/civicrm_data.tpl | 1534 + xml/templates/civicrm_msg_template.tpl | 247 + xml/templates/civicrm_navigation.tpl | 825 + xml/templates/civicrm_sample.tpl | 251 + xml/templates/civicrm_state_province.tpl | 3897 ++ xml/templates/civicrm_version.tpl | 11 + xml/templates/dao.tpl | 374 + xml/templates/drop.tpl | 36 + xml/templates/joomla.tpl | 52 + xml/templates/languages.tpl | 208 + .../message_templates/case_activity_html.tpl | 104 + .../case_activity_subject.tpl | 1 + .../message_templates/case_activity_text.tpl | 38 + .../contribution_dupalert_html.tpl | 89 + .../contribution_dupalert_subject.tpl | 1 + .../contribution_dupalert_text.tpl | 20 + .../contribution_offline_receipt_html.tpl | 261 + .../contribution_offline_receipt_subject.tpl | 1 + .../contribution_offline_receipt_text.tpl | 97 + .../contribution_online_receipt_html.tpl | 394 + .../contribution_online_receipt_subject.tpl | 1 + .../contribution_online_receipt_text.tpl | 179 + .../contribution_recurring_billing_html.tpl | 65 + ...contribution_recurring_billing_subject.tpl | 1 + .../contribution_recurring_billing_text.tpl | 23 + .../contribution_recurring_cancelled_html.tpl | 33 + ...ntribution_recurring_cancelled_subject.tpl | 1 + .../contribution_recurring_cancelled_text.tpl | 3 + .../contribution_recurring_edit_html.tpl | 36 + .../contribution_recurring_edit_subject.tpl | 1 + .../contribution_recurring_edit_text.tpl | 8 + .../contribution_recurring_notify_html.tpl | 125 + .../contribution_recurring_notify_subject.tpl | 1 + .../contribution_recurring_notify_text.tpl | 50 + .../event_offline_receipt_html.tpl | 459 + .../event_offline_receipt_subject.tpl | 1 + .../event_offline_receipt_text.tpl | 277 + .../event_online_receipt_html.tpl | 453 + .../event_online_receipt_subject.tpl | 1 + .../event_online_receipt_text.tpl | 280 + .../event_registration_receipt_html.tpl | 189 + .../event_registration_receipt_subject.tpl | 1 + .../event_registration_receipt_text.tpl | 94 + .../message_templates/friend_html.tpl | 40 + .../message_templates/friend_subject.tpl | 1 + .../message_templates/friend_text.tpl | 15 + .../message_templates/grant_approved_html.tpl | 26 + .../grant_approved_subject.tpl | 1 + .../message_templates/grant_approved_text.tpl | 13 + .../grant_awaiting_info_html.tpl | 26 + .../grant_awaiting_info_subject.tpl | 1 + .../grant_awaiting_info_text.tpl | 13 + .../message_templates/grant_paid_html.tpl | 26 + .../message_templates/grant_paid_subject.tpl | 1 + .../message_templates/grant_paid_text.tpl | 13 + .../message_templates/grant_rejected_html.tpl | 26 + .../grant_rejected_subject.tpl | 1 + .../message_templates/grant_rejected_text.tpl | 13 + .../grant_submitted_html.tpl | 26 + .../grant_submitted_subject.tpl | 1 + .../grant_submitted_text.tpl | 13 + .../membership_autorenew_billing_html.tpl | 66 + .../membership_autorenew_billing_subject.tpl | 1 + .../membership_autorenew_billing_text.tpl | 23 + .../membership_autorenew_cancelled_html.tpl | 70 + ...membership_autorenew_cancelled_subject.tpl | 1 + .../membership_autorenew_cancelled_text.tpl | 12 + .../membership_offline_receipt_html.tpl | 240 + .../membership_offline_receipt_subject.tpl | 5 + .../membership_offline_receipt_text.tpl | 90 + .../membership_online_receipt_html.tpl | 514 + .../membership_online_receipt_subject.tpl | 1 + .../membership_online_receipt_text.tpl | 221 + .../participant_cancelled_html.tpl | 153 + .../participant_cancelled_subject.tpl | 1 + .../participant_cancelled_text.tpl | 61 + .../participant_confirm_html.tpl | 185 + .../participant_confirm_subject.tpl | 1 + .../participant_confirm_text.tpl | 86 + .../participant_expired_html.tpl | 156 + .../participant_expired_subject.tpl | 1 + .../participant_expired_text.tpl | 65 + .../message_templates/pcp_notify_html.tpl | 96 + .../message_templates/pcp_notify_subject.tpl | 1 + .../message_templates/pcp_notify_text.tpl | 20 + .../pcp_status_change_html.tpl | 59 + .../pcp_status_change_subject.tpl | 1 + .../pcp_status_change_text.tpl | 47 + .../pcp_supporter_notify_html.tpl | 100 + .../pcp_supporter_notify_subject.tpl | 1 + .../pcp_supporter_notify_text.tpl | 58 + .../petition_confirmation_needed_html.tpl | 10 + .../petition_confirmation_needed_subject.tpl | 1 + .../petition_confirmation_needed_text.tpl | 8 + .../message_templates/petition_sign_html.tpl | 3 + .../petition_sign_subject.tpl | 1 + .../message_templates/petition_sign_text.tpl | 1 + .../pledge_acknowledge_html.tpl | 132 + .../pledge_acknowledge_subject.tpl | 1 + .../pledge_acknowledge_text.tpl | 55 + .../pledge_reminder_html.tpl | 107 + .../pledge_reminder_subject.tpl | 1 + .../pledge_reminder_text.tpl | 33 + .../message_templates/test_preview_html.tpl | 10 + .../test_preview_subject.tpl | 1 + .../message_templates/test_preview_text.tpl | 7 + .../message_templates/uf_notify_html.tpl | 74 + .../message_templates/uf_notify_subject.tpl | 1 + .../message_templates/uf_notify_text.tpl | 11 + xml/templates/schema.tpl | 86 + xml/templates/schema_structure.tpl | 86 + xml/version.xml | 4 + 4205 files changed, 810342 insertions(+) create mode 100644 CRM/ACL/API.php create mode 100644 CRM/ACL/BAO/ACL.php create mode 100644 CRM/ACL/BAO/Cache.php create mode 100644 CRM/ACL/BAO/EntityRole.php create mode 100644 CRM/ACL/Form/ACL.php create mode 100644 CRM/ACL/Form/ACLBasic.php create mode 100644 CRM/ACL/Form/EntityRole.php create mode 100644 CRM/ACL/Form/WordPress/Permissions.php create mode 100644 CRM/ACL/Page/ACL.php create mode 100644 CRM/ACL/Page/ACLBasic.php create mode 100644 CRM/ACL/Page/EntityRole.php create mode 100644 CRM/Activity/BAO/Activity.php create mode 100644 CRM/Activity/BAO/ActivityAssignment.php create mode 100644 CRM/Activity/BAO/ActivityTarget.php create mode 100644 CRM/Activity/BAO/ICalendar.php create mode 100644 CRM/Activity/BAO/Query.php create mode 100644 CRM/Activity/Controller/Search.php create mode 100644 CRM/Activity/Form/Activity.php create mode 100644 CRM/Activity/Form/ActivityFilter.php create mode 100644 CRM/Activity/Form/ActivityLinks.php create mode 100644 CRM/Activity/Form/ActivityView.php create mode 100644 CRM/Activity/Form/Search.php create mode 100644 CRM/Activity/Form/Task.php create mode 100755 CRM/Activity/Form/Task/Batch.php create mode 100755 CRM/Activity/Form/Task/Delete.php create mode 100644 CRM/Activity/Form/Task/Email.php create mode 100644 CRM/Activity/Form/Task/FileOnCase.php create mode 100644 CRM/Activity/Form/Task/PickOption.php create mode 100755 CRM/Activity/Form/Task/PickProfile.php create mode 100644 CRM/Activity/Form/Task/Print.php create mode 100644 CRM/Activity/Form/Task/SMS.php create mode 100644 CRM/Activity/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Activity/Import/Controller.php create mode 100644 CRM/Activity/Import/Field.php create mode 100644 CRM/Activity/Import/Form/MapField.php create mode 100644 CRM/Activity/Import/Form/Preview.php create mode 100644 CRM/Activity/Import/Form/Summary.php create mode 100644 CRM/Activity/Import/Form/UploadFile.php create mode 100644 CRM/Activity/Import/Parser.php create mode 100644 CRM/Activity/Import/Parser/Activity.php create mode 100644 CRM/Activity/Import/StateMachine.php create mode 100644 CRM/Activity/Page/AJAX.php create mode 100644 CRM/Activity/Page/Tab.php create mode 100644 CRM/Activity/Page/UserDashboard.php create mode 100644 CRM/Activity/Selector/Activity.php create mode 100644 CRM/Activity/Selector/Search.php create mode 100644 CRM/Activity/StateMachine/Search.php create mode 100644 CRM/Activity/Task.php create mode 100644 CRM/Admin/Form.php create mode 100644 CRM/Admin/Form/CMSUser.php create mode 100644 CRM/Admin/Form/ContactType.php create mode 100644 CRM/Admin/Form/Extensions.php create mode 100644 CRM/Admin/Form/Job.php create mode 100644 CRM/Admin/Form/LabelFormats.php create mode 100644 CRM/Admin/Form/LocationType.php create mode 100644 CRM/Admin/Form/MailSettings.php create mode 100644 CRM/Admin/Form/Mapping.php create mode 100644 CRM/Admin/Form/MessageTemplates.php create mode 100644 CRM/Admin/Form/Navigation.php create mode 100644 CRM/Admin/Form/OptionGroup.php create mode 100644 CRM/Admin/Form/OptionValue.php create mode 100644 CRM/Admin/Form/Options.php create mode 100644 CRM/Admin/Form/ParticipantStatus.php create mode 100644 CRM/Admin/Form/PaymentProcessor.php create mode 100644 CRM/Admin/Form/PaymentProcessorType.php create mode 100644 CRM/Admin/Form/PdfFormats.php create mode 100644 CRM/Admin/Form/Persistent.php create mode 100644 CRM/Admin/Form/Preferences.php create mode 100644 CRM/Admin/Form/Preferences/Address.php create mode 100644 CRM/Admin/Form/Preferences/Campaign.php create mode 100644 CRM/Admin/Form/Preferences/Display.php create mode 100644 CRM/Admin/Form/Preferences/Event.php create mode 100644 CRM/Admin/Form/Preferences/Mailing.php create mode 100644 CRM/Admin/Form/Preferences/Member.php create mode 100644 CRM/Admin/Form/Preferences/Multisite.php create mode 100644 CRM/Admin/Form/PreferencesDate.php create mode 100644 CRM/Admin/Form/RelationshipType.php create mode 100644 CRM/Admin/Form/ScheduleReminders.php create mode 100644 CRM/Admin/Form/Setting.php create mode 100644 CRM/Admin/Form/Setting/Component.php create mode 100644 CRM/Admin/Form/Setting/Date.php create mode 100644 CRM/Admin/Form/Setting/Debugging.php create mode 100644 CRM/Admin/Form/Setting/Localization.php create mode 100644 CRM/Admin/Form/Setting/Mail.php create mode 100644 CRM/Admin/Form/Setting/Mapping.php create mode 100644 CRM/Admin/Form/Setting/Miscellaneous.php create mode 100644 CRM/Admin/Form/Setting/Path.php create mode 100644 CRM/Admin/Form/Setting/Search.php create mode 100644 CRM/Admin/Form/Setting/Smtp.php create mode 100644 CRM/Admin/Form/Setting/UF.php create mode 100644 CRM/Admin/Form/Setting/UpdateConfigBackend.php create mode 100644 CRM/Admin/Form/Setting/Url.php create mode 100644 CRM/Admin/Form/Tag.php create mode 100644 CRM/Admin/Form/WordReplacements.php create mode 100644 CRM/Admin/Page/AJAX.php create mode 100644 CRM/Admin/Page/APIDoc.php create mode 100644 CRM/Admin/Page/APIExplorer.php create mode 100644 CRM/Admin/Page/Access.php create mode 100644 CRM/Admin/Page/Admin.php create mode 100644 CRM/Admin/Page/CMSUser.php create mode 100644 CRM/Admin/Page/ConfigTaskList.php create mode 100644 CRM/Admin/Page/ContactType.php create mode 100644 CRM/Admin/Page/EventTemplate.php create mode 100644 CRM/Admin/Page/Extensions.php create mode 100644 CRM/Admin/Page/ExtensionsUpgrade.php create mode 100644 CRM/Admin/Page/Job.php create mode 100644 CRM/Admin/Page/JobLog.php create mode 100644 CRM/Admin/Page/LabelFormats.php create mode 100644 CRM/Admin/Page/LocationType.php create mode 100644 CRM/Admin/Page/MailSettings.php create mode 100644 CRM/Admin/Page/Mapping.php create mode 100644 CRM/Admin/Page/MessageTemplates.php create mode 100644 CRM/Admin/Page/Navigation.php create mode 100644 CRM/Admin/Page/OptionGroup.php create mode 100644 CRM/Admin/Page/OptionValue.php create mode 100644 CRM/Admin/Page/Options.php create mode 100644 CRM/Admin/Page/ParticipantStatus.php create mode 100644 CRM/Admin/Page/PaymentProcessor.php create mode 100644 CRM/Admin/Page/PaymentProcessorType.php create mode 100644 CRM/Admin/Page/PdfFormats.php create mode 100644 CRM/Admin/Page/Persistent.php create mode 100644 CRM/Admin/Page/PreferencesDate.php create mode 100644 CRM/Admin/Page/RelationshipType.php create mode 100644 CRM/Admin/Page/ScheduleReminders.php create mode 100644 CRM/Admin/Page/Setting.php create mode 100644 CRM/Admin/Page/Tag.php create mode 100644 CRM/Batch/BAO/Batch.php create mode 100644 CRM/Batch/Form/Batch.php create mode 100644 CRM/Batch/Form/Entry.php create mode 100644 CRM/Batch/Form/Search.php create mode 100644 CRM/Batch/Page/AJAX.php create mode 100644 CRM/Batch/Page/Batch.php create mode 100644 CRM/Bridge/OG/CiviCRM.php create mode 100644 CRM/Bridge/OG/Drupal.php create mode 100644 CRM/Bridge/OG/Utils.php create mode 100644 CRM/Campaign/BAO/Campaign.php create mode 100644 CRM/Campaign/BAO/Petition.php create mode 100755 CRM/Campaign/BAO/Query.php create mode 100644 CRM/Campaign/BAO/Survey.php create mode 100644 CRM/Campaign/Config.php create mode 100755 CRM/Campaign/Controller/Search.php create mode 100644 CRM/Campaign/Form/Campaign.php create mode 100755 CRM/Campaign/Form/Gotv.php create mode 100644 CRM/Campaign/Form/Petition.php create mode 100644 CRM/Campaign/Form/Petition/Signature.php create mode 100755 CRM/Campaign/Form/Search.php create mode 100755 CRM/Campaign/Form/Search/Campaign.php create mode 100755 CRM/Campaign/Form/Search/Petition.php create mode 100755 CRM/Campaign/Form/Search/Survey.php create mode 100644 CRM/Campaign/Form/Survey.php create mode 100644 CRM/Campaign/Form/Survey/Delete.php create mode 100644 CRM/Campaign/Form/Survey/Main.php create mode 100644 CRM/Campaign/Form/Survey/Questions.php create mode 100644 CRM/Campaign/Form/Survey/Results.php create mode 100644 CRM/Campaign/Form/Survey/TabHeader.php create mode 100644 CRM/Campaign/Form/SurveyType.php create mode 100755 CRM/Campaign/Form/Task.php create mode 100755 CRM/Campaign/Form/Task/Interview.php create mode 100755 CRM/Campaign/Form/Task/Print.php create mode 100644 CRM/Campaign/Form/Task/Release.php create mode 100644 CRM/Campaign/Form/Task/Reserve.php create mode 100755 CRM/Campaign/Form/Task/Result.php create mode 100644 CRM/Campaign/Info.php create mode 100644 CRM/Campaign/Page/AJAX.php create mode 100644 CRM/Campaign/Page/Campaign.php create mode 100644 CRM/Campaign/Page/DashBoard.php create mode 100644 CRM/Campaign/Page/Petition.php create mode 100644 CRM/Campaign/Page/Petition/Confirm.php create mode 100644 CRM/Campaign/Page/Petition/ThankYou.php create mode 100644 CRM/Campaign/Page/Survey.php create mode 100644 CRM/Campaign/Page/SurveyType.php create mode 100644 CRM/Campaign/Page/Vote.php create mode 100755 CRM/Campaign/PseudoConstant.php create mode 100755 CRM/Campaign/Selector/Search.php create mode 100755 CRM/Campaign/StateMachine/Search.php create mode 100755 CRM/Campaign/Task.php create mode 100644 CRM/Campaign/xml/Menu/Campaign.xml create mode 100644 CRM/Case/Audit/Audit.php create mode 100644 CRM/Case/Audit/AuditConfig.php create mode 100644 CRM/Case/Audit/audit.conf.xml create mode 100644 CRM/Case/BAO/Case.php create mode 100644 CRM/Case/BAO/Query.php create mode 100644 CRM/Case/Config.php create mode 100644 CRM/Case/Controller/Search.php create mode 100644 CRM/Case/Form/Activity.php create mode 100644 CRM/Case/Form/Activity/ChangeCaseStartDate.php create mode 100644 CRM/Case/Form/Activity/ChangeCaseStatus.php create mode 100644 CRM/Case/Form/Activity/ChangeCaseType.php create mode 100644 CRM/Case/Form/Activity/LinkCases.php create mode 100644 CRM/Case/Form/Activity/OpenCase.php create mode 100644 CRM/Case/Form/ActivityToCase.php create mode 100644 CRM/Case/Form/ActivityView.php create mode 100644 CRM/Case/Form/Case.php create mode 100644 CRM/Case/Form/CaseView.php create mode 100644 CRM/Case/Form/CustomData.php create mode 100644 CRM/Case/Form/EditClient.php create mode 100644 CRM/Case/Form/Report.php create mode 100644 CRM/Case/Form/Search.php create mode 100644 CRM/Case/Form/Task.php create mode 100644 CRM/Case/Form/Task/Delete.php create mode 100644 CRM/Case/Form/Task/Print.php create mode 100644 CRM/Case/Form/Task/Restore.php create mode 100644 CRM/Case/Form/Task/Result.php create mode 100644 CRM/Case/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Case/Info.php create mode 100644 CRM/Case/Page/AJAX.php create mode 100644 CRM/Case/Page/CaseDetails.php create mode 100644 CRM/Case/Page/DashBoard.php create mode 100644 CRM/Case/Page/Tab.php create mode 100644 CRM/Case/PseudoConstant.php create mode 100644 CRM/Case/Selector/Search.php create mode 100644 CRM/Case/StateMachine/Search.php create mode 100644 CRM/Case/Task.php create mode 100644 CRM/Case/XMLProcessor.php create mode 100644 CRM/Case/XMLProcessor/Process.php create mode 100644 CRM/Case/XMLProcessor/Report.php create mode 100644 CRM/Case/XMLProcessor/Settings.php create mode 100644 CRM/Case/xml/HRD/CivilAndPolitical.xml create mode 100644 CRM/Case/xml/HRD/EconomicSocialCultural.xml create mode 100644 CRM/Case/xml/HRD/GenderIssues.xml create mode 100644 CRM/Case/xml/HRD/HRD.mysql create mode 100644 CRM/Case/xml/Menu/Case.xml create mode 100644 CRM/Case/xml/configuration.sample/AdultDayCareReferral.xml create mode 100644 CRM/Case/xml/configuration.sample/HousingSupport.xml create mode 100644 CRM/Case/xml/configuration.sample/SampleConfig.mysql create mode 100644 CRM/Case/xml/configuration.sample/Settings.xml create mode 100644 CRM/Case/xml/samples/report.xml create mode 100644 CRM/Contact/BAO/Contact.php create mode 100644 CRM/Contact/BAO/Contact/Location.php create mode 100644 CRM/Contact/BAO/Contact/Optimizer.php create mode 100644 CRM/Contact/BAO/Contact/Permission.php create mode 100644 CRM/Contact/BAO/Contact/Utils.php create mode 100644 CRM/Contact/BAO/ContactType.php create mode 100644 CRM/Contact/BAO/Group.php create mode 100644 CRM/Contact/BAO/GroupContact.php create mode 100644 CRM/Contact/BAO/GroupContactCache.php create mode 100644 CRM/Contact/BAO/GroupNesting.php create mode 100644 CRM/Contact/BAO/GroupNestingCache.php create mode 100644 CRM/Contact/BAO/GroupOrganization.php create mode 100644 CRM/Contact/BAO/Household.php create mode 100644 CRM/Contact/BAO/Individual.php create mode 100644 CRM/Contact/BAO/ProximityQuery.php create mode 100644 CRM/Contact/BAO/Query.php create mode 100644 CRM/Contact/BAO/Relationship.php create mode 100644 CRM/Contact/BAO/RelationshipType.php create mode 100644 CRM/Contact/BAO/SavedSearch.php create mode 100644 CRM/Contact/BAO/SearchCustom.php create mode 100644 CRM/Contact/BAO/SubscriptionHistory.php create mode 100644 CRM/Contact/Controller/Search.php create mode 100644 CRM/Contact/DAO/Factory.php create mode 100644 CRM/Contact/Form/Contact.php create mode 100644 CRM/Contact/Form/CustomData.php create mode 100644 CRM/Contact/Form/DedupeFind.php create mode 100644 CRM/Contact/Form/DedupeRules.php create mode 100644 CRM/Contact/Form/Domain.php create mode 100644 CRM/Contact/Form/Edit/Address.php create mode 100644 CRM/Contact/Form/Edit/CommunicationPreferences.php create mode 100644 CRM/Contact/Form/Edit/CustomData.php create mode 100644 CRM/Contact/Form/Edit/Demographics.php create mode 100644 CRM/Contact/Form/Edit/Email.php create mode 100644 CRM/Contact/Form/Edit/Household.php create mode 100644 CRM/Contact/Form/Edit/IM.php create mode 100644 CRM/Contact/Form/Edit/Individual.php create mode 100644 CRM/Contact/Form/Edit/Lock.php create mode 100644 CRM/Contact/Form/Edit/Notes.php create mode 100644 CRM/Contact/Form/Edit/OpenID.php create mode 100644 CRM/Contact/Form/Edit/Organization.php create mode 100644 CRM/Contact/Form/Edit/Phone.php create mode 100644 CRM/Contact/Form/Edit/TagsAndGroups.php create mode 100644 CRM/Contact/Form/Edit/Website.php create mode 100644 CRM/Contact/Form/GroupContact.php create mode 100644 CRM/Contact/Form/Inline.php create mode 100644 CRM/Contact/Form/Inline/Address.php create mode 100644 CRM/Contact/Form/Inline/CommunicationPreferences.php create mode 100644 CRM/Contact/Form/Inline/ContactInfo.php create mode 100644 CRM/Contact/Form/Inline/ContactName.php create mode 100644 CRM/Contact/Form/Inline/CustomData.php create mode 100644 CRM/Contact/Form/Inline/Demographics.php create mode 100644 CRM/Contact/Form/Inline/Email.php create mode 100644 CRM/Contact/Form/Inline/IM.php create mode 100644 CRM/Contact/Form/Inline/Lock.php create mode 100644 CRM/Contact/Form/Inline/OpenID.php create mode 100644 CRM/Contact/Form/Inline/Phone.php create mode 100644 CRM/Contact/Form/Inline/Website.php create mode 100644 CRM/Contact/Form/Location.php create mode 100644 CRM/Contact/Form/Merge.php create mode 100644 CRM/Contact/Form/NewContact.php create mode 100644 CRM/Contact/Form/RelatedContact.php create mode 100644 CRM/Contact/Form/Relationship.php create mode 100644 CRM/Contact/Form/Search.php create mode 100644 CRM/Contact/Form/Search/Advanced.php create mode 100644 CRM/Contact/Form/Search/Basic.php create mode 100644 CRM/Contact/Form/Search/Builder.php create mode 100644 CRM/Contact/Form/Search/Criteria.php create mode 100644 CRM/Contact/Form/Search/Custom.php create mode 100644 CRM/Contact/Form/Search/Custom/ActivitySearch.php create mode 100644 CRM/Contact/Form/Search/Custom/Base.php create mode 100644 CRM/Contact/Form/Search/Custom/Basic.php create mode 100644 CRM/Contact/Form/Search/Custom/ContribSYBNT.php create mode 100644 CRM/Contact/Form/Search/Custom/ContributionAggregate.php create mode 100644 CRM/Contact/Form/Search/Custom/DateAdded.php create mode 100644 CRM/Contact/Form/Search/Custom/EmployerListing.php create mode 100644 CRM/Contact/Form/Search/Custom/EventAggregate.php create mode 100644 CRM/Contact/Form/Search/Custom/FullText.php create mode 100644 CRM/Contact/Form/Search/Custom/Group.php create mode 100644 CRM/Contact/Form/Search/Custom/MultipleValues.php create mode 100644 CRM/Contact/Form/Search/Custom/PostalMailing.php create mode 100644 CRM/Contact/Form/Search/Custom/PriceSet.php create mode 100644 CRM/Contact/Form/Search/Custom/Proximity.php create mode 100644 CRM/Contact/Form/Search/Custom/RandomSegment.php create mode 100644 CRM/Contact/Form/Search/Custom/Sample.php create mode 100644 CRM/Contact/Form/Search/Custom/TagContributions.php create mode 100644 CRM/Contact/Form/Search/Custom/ZipCodeRange.php create mode 100644 CRM/Contact/Form/Search/Interface.php create mode 100644 CRM/Contact/Form/Search/Simple.php create mode 100644 CRM/Contact/Form/Task.php create mode 100644 CRM/Contact/Form/Task/AddToGroup.php create mode 100644 CRM/Contact/Form/Task/AddToHousehold.php create mode 100644 CRM/Contact/Form/Task/AddToOrganization.php create mode 100644 CRM/Contact/Form/Task/AddToTag.php create mode 100644 CRM/Contact/Form/Task/AlterPreferences.php create mode 100644 CRM/Contact/Form/Task/Batch.php create mode 100644 CRM/Contact/Form/Task/Delete.php create mode 100644 CRM/Contact/Form/Task/Email.php create mode 100644 CRM/Contact/Form/Task/EmailCommon.php create mode 100644 CRM/Contact/Form/Task/HookSample.php create mode 100644 CRM/Contact/Form/Task/Label.php create mode 100644 CRM/Contact/Form/Task/Map.php create mode 100644 CRM/Contact/Form/Task/Map/Event.php create mode 100644 CRM/Contact/Form/Task/Merge.php create mode 100644 CRM/Contact/Form/Task/PDF.php create mode 100644 CRM/Contact/Form/Task/PDFLetterCommon.php create mode 100644 CRM/Contact/Form/Task/PickProfile.php create mode 100644 CRM/Contact/Form/Task/Print.php create mode 100644 CRM/Contact/Form/Task/ProximityCommon.php create mode 100644 CRM/Contact/Form/Task/RemoveFromGroup.php create mode 100644 CRM/Contact/Form/Task/RemoveFromTag.php create mode 100644 CRM/Contact/Form/Task/Result.php create mode 100644 CRM/Contact/Form/Task/SMS.php create mode 100644 CRM/Contact/Form/Task/SMSCommon.php create mode 100644 CRM/Contact/Form/Task/SaveSearch.php create mode 100644 CRM/Contact/Form/Task/SaveSearch/Update.php create mode 100644 CRM/Contact/Form/Task/Unhold.php create mode 100755 CRM/Contact/Form/Task/Useradd.php create mode 100644 CRM/Contact/Form/Test.php create mode 100644 CRM/Contact/Page/AJAX.php create mode 100644 CRM/Contact/Page/CustomSearch.php create mode 100644 CRM/Contact/Page/DashBoard.php create mode 100644 CRM/Contact/Page/Dashlet.php create mode 100644 CRM/Contact/Page/DedupeException.php create mode 100644 CRM/Contact/Page/DedupeFind.php create mode 100644 CRM/Contact/Page/DedupeRules.php create mode 100644 CRM/Contact/Page/Inline/Actions.php create mode 100644 CRM/Contact/Page/Inline/Address.php create mode 100644 CRM/Contact/Page/Inline/CommunicationPreferences.php create mode 100644 CRM/Contact/Page/Inline/ContactInfo.php create mode 100644 CRM/Contact/Page/Inline/ContactName.php create mode 100644 CRM/Contact/Page/Inline/CustomData.php create mode 100644 CRM/Contact/Page/Inline/Demographics.php create mode 100644 CRM/Contact/Page/Inline/Email.php create mode 100644 CRM/Contact/Page/Inline/IM.php create mode 100644 CRM/Contact/Page/Inline/OpenID.php create mode 100644 CRM/Contact/Page/Inline/Phone.php create mode 100644 CRM/Contact/Page/Inline/Website.php create mode 100644 CRM/Contact/Page/SavedSearch.php create mode 100644 CRM/Contact/Page/Task.php create mode 100644 CRM/Contact/Page/View.php create mode 100644 CRM/Contact/Page/View/CustomData.php create mode 100644 CRM/Contact/Page/View/Email.php create mode 100644 CRM/Contact/Page/View/GroupContact.php create mode 100644 CRM/Contact/Page/View/Log.php create mode 100644 CRM/Contact/Page/View/Note.php create mode 100644 CRM/Contact/Page/View/Print.php create mode 100644 CRM/Contact/Page/View/Relationship.php create mode 100644 CRM/Contact/Page/View/SMS.php create mode 100644 CRM/Contact/Page/View/Summary.php create mode 100644 CRM/Contact/Page/View/Sunlight.php create mode 100644 CRM/Contact/Page/View/Tag.php create mode 100644 CRM/Contact/Page/View/UserDashBoard.php create mode 100644 CRM/Contact/Page/View/UserDashBoard/GroupContact.php create mode 100755 CRM/Contact/Page/View/Useradd.php create mode 100644 CRM/Contact/Page/View/Vcard.php create mode 100644 CRM/Contact/Selector.php create mode 100644 CRM/Contact/Selector/Controller.php create mode 100644 CRM/Contact/Selector/Custom.php create mode 100644 CRM/Contact/StateMachine/Search.php create mode 100644 CRM/Contact/Task.php create mode 100644 CRM/Contribute/BAO/Contribution.php create mode 100644 CRM/Contribute/BAO/Contribution/Utils.php create mode 100644 CRM/Contribute/BAO/ContributionPage.php create mode 100644 CRM/Contribute/BAO/ContributionRecur.php create mode 100644 CRM/Contribute/BAO/ManagePremiums.php create mode 100644 CRM/Contribute/BAO/Premium.php create mode 100644 CRM/Contribute/BAO/Query.php create mode 100644 CRM/Contribute/BAO/Widget.php create mode 100644 CRM/Contribute/Config.php create mode 100644 CRM/Contribute/Controller/Contribution.php create mode 100644 CRM/Contribute/Controller/ContributionPage.php create mode 100644 CRM/Contribute/Controller/Search.php create mode 100644 CRM/Contribute/Form.php create mode 100644 CRM/Contribute/Form/AbstractEditPayment.php create mode 100644 CRM/Contribute/Form/AdditionalInfo.php create mode 100644 CRM/Contribute/Form/CancelSubscription.php create mode 100644 CRM/Contribute/Form/Contribution.php create mode 100644 CRM/Contribute/Form/Contribution/Confirm.php create mode 100644 CRM/Contribute/Form/Contribution/Main.php create mode 100644 CRM/Contribute/Form/Contribution/OnBehalfOf.php create mode 100644 CRM/Contribute/Form/Contribution/ThankYou.php create mode 100644 CRM/Contribute/Form/ContributionBase.php create mode 100644 CRM/Contribute/Form/ContributionCharts.php create mode 100644 CRM/Contribute/Form/ContributionPage.php create mode 100644 CRM/Contribute/Form/ContributionPage/AddProduct.php create mode 100644 CRM/Contribute/Form/ContributionPage/Amount.php create mode 100644 CRM/Contribute/Form/ContributionPage/Custom.php create mode 100644 CRM/Contribute/Form/ContributionPage/Delete.php create mode 100644 CRM/Contribute/Form/ContributionPage/Premium.php create mode 100644 CRM/Contribute/Form/ContributionPage/Settings.php create mode 100644 CRM/Contribute/Form/ContributionPage/TabHeader.php create mode 100644 CRM/Contribute/Form/ContributionPage/ThankYou.php create mode 100644 CRM/Contribute/Form/ContributionPage/Widget.php create mode 100644 CRM/Contribute/Form/ContributionView.php create mode 100644 CRM/Contribute/Form/ManagePremiums.php create mode 100644 CRM/Contribute/Form/Search.php create mode 100644 CRM/Contribute/Form/SearchContribution.php create mode 100644 CRM/Contribute/Form/Task.php create mode 100644 CRM/Contribute/Form/Task/Batch.php create mode 100644 CRM/Contribute/Form/Task/Delete.php create mode 100644 CRM/Contribute/Form/Task/Email.php create mode 100644 CRM/Contribute/Form/Task/PDF.php create mode 100644 CRM/Contribute/Form/Task/PDFLetter.php create mode 100644 CRM/Contribute/Form/Task/PDFLetterCommon.php create mode 100644 CRM/Contribute/Form/Task/PickProfile.php create mode 100644 CRM/Contribute/Form/Task/Print.php create mode 100644 CRM/Contribute/Form/Task/Result.php create mode 100644 CRM/Contribute/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Contribute/Form/Task/Status.php create mode 100644 CRM/Contribute/Form/UpdateBilling.php create mode 100644 CRM/Contribute/Form/UpdateSubscription.php create mode 100644 CRM/Contribute/Import/Controller.php create mode 100644 CRM/Contribute/Import/Field.php create mode 100644 CRM/Contribute/Import/Form/MapField.php create mode 100644 CRM/Contribute/Import/Form/Preview.php create mode 100644 CRM/Contribute/Import/Form/Summary.php create mode 100644 CRM/Contribute/Import/Form/UploadFile.php create mode 100644 CRM/Contribute/Import/Parser.php create mode 100644 CRM/Contribute/Import/Parser/Contribution.php create mode 100644 CRM/Contribute/Import/StateMachine.php create mode 100644 CRM/Contribute/Info.php create mode 100644 CRM/Contribute/Page/ContributionPage.php create mode 100644 CRM/Contribute/Page/ContributionRecur.php create mode 100644 CRM/Contribute/Page/DashBoard.php create mode 100644 CRM/Contribute/Page/ManagePremiums.php create mode 100644 CRM/Contribute/Page/Premium.php create mode 100644 CRM/Contribute/Page/SubscriptionStatus.php create mode 100644 CRM/Contribute/Page/Tab.php create mode 100644 CRM/Contribute/Page/UserDashboard.php create mode 100644 CRM/Contribute/PseudoConstant.php create mode 100644 CRM/Contribute/Selector/Search.php create mode 100644 CRM/Contribute/StateMachine/Contribution.php create mode 100644 CRM/Contribute/StateMachine/ContributionPage.php create mode 100644 CRM/Contribute/StateMachine/Search.php create mode 100644 CRM/Contribute/Task.php create mode 100644 CRM/Contribute/xml/Menu/Contribute.xml create mode 100644 CRM/Contribute/xml/Menu/PCP.xml create mode 100644 CRM/Core/Action.php create mode 100644 CRM/Core/BAO/ActionLog.php create mode 100755 CRM/Core/BAO/ActionSchedule.php create mode 100644 CRM/Core/BAO/Address.php create mode 100644 CRM/Core/BAO/Block.php create mode 100644 CRM/Core/BAO/CMSUser.php create mode 100644 CRM/Core/BAO/Cache.php create mode 100644 CRM/Core/BAO/ConfigSetting.php create mode 100644 CRM/Core/BAO/CustomField.php create mode 100644 CRM/Core/BAO/CustomGroup.php create mode 100644 CRM/Core/BAO/CustomOption.php create mode 100644 CRM/Core/BAO/CustomQuery.php create mode 100644 CRM/Core/BAO/CustomValue.php create mode 100644 CRM/Core/BAO/CustomValueTable.php create mode 100644 CRM/Core/BAO/Dashboard.php create mode 100644 CRM/Core/BAO/Discount.php create mode 100644 CRM/Core/BAO/Domain.php create mode 100644 CRM/Core/BAO/Email.php create mode 100644 CRM/Core/BAO/EntityTag.php create mode 100644 CRM/Core/BAO/Extension.php create mode 100644 CRM/Core/BAO/File.php create mode 100644 CRM/Core/BAO/FinancialTrxn.php create mode 100644 CRM/Core/BAO/IM.php create mode 100644 CRM/Core/BAO/Job.php create mode 100644 CRM/Core/BAO/LabelFormat.php create mode 100644 CRM/Core/BAO/Location.php create mode 100644 CRM/Core/BAO/LocationType.php create mode 100644 CRM/Core/BAO/Log.php create mode 100644 CRM/Core/BAO/MailSettings.php create mode 100644 CRM/Core/BAO/Mapping.php create mode 100644 CRM/Core/BAO/MessageTemplates.php create mode 100644 CRM/Core/BAO/Navigation.php create mode 100644 CRM/Core/BAO/Note.php create mode 100644 CRM/Core/BAO/OpenID.php create mode 100644 CRM/Core/BAO/OptionGroup.php create mode 100644 CRM/Core/BAO/OptionValue.php create mode 100644 CRM/Core/BAO/PaperSize.php create mode 100644 CRM/Core/BAO/PdfFormat.php create mode 100644 CRM/Core/BAO/Persistent.php create mode 100644 CRM/Core/BAO/Phone.php create mode 100644 CRM/Core/BAO/Preferences.php create mode 100644 CRM/Core/BAO/PreferencesDate.php create mode 100644 CRM/Core/BAO/PrevNextCache.php create mode 100644 CRM/Core/BAO/SchemaHandler.php create mode 100644 CRM/Core/BAO/Setting.php create mode 100644 CRM/Core/BAO/Tag.php create mode 100644 CRM/Core/BAO/UFField.php create mode 100644 CRM/Core/BAO/UFGroup.php create mode 100644 CRM/Core/BAO/UFJoin.php create mode 100644 CRM/Core/BAO/UFMatch.php create mode 100644 CRM/Core/BAO/Website.php create mode 100644 CRM/Core/Base.php create mode 100644 CRM/Core/Block.php create mode 100644 CRM/Core/ClassLoader.php create mode 100644 CRM/Core/Component.php create mode 100644 CRM/Core/Component/Config.php create mode 100644 CRM/Core/Component/Info.php create mode 100644 CRM/Core/Config.php create mode 100644 CRM/Core/Config/Defaults.php create mode 100644 CRM/Core/Config/Variables.php create mode 100644 CRM/Core/Controller.php create mode 100644 CRM/Core/Controller/Simple.php create mode 100644 CRM/Core/DAO.php create mode 100644 CRM/Core/DAO/.permissions.php create mode 100644 CRM/Core/DAO/Factory.php create mode 100644 CRM/Core/Error.php create mode 100644 CRM/Core/Exception.php create mode 100644 CRM/Core/Form.php create mode 100644 CRM/Core/Form/Date.php create mode 100644 CRM/Core/Form/Renderer.php create mode 100644 CRM/Core/Form/Tag.php create mode 100644 CRM/Core/HTMLInputCoder.php create mode 100644 CRM/Core/I18n.php create mode 100644 CRM/Core/I18n/Form.php create mode 100644 CRM/Core/I18n/NativeGettext.php create mode 100644 CRM/Core/I18n/PseudoConstant.php create mode 100644 CRM/Core/I18n/Schema.php create mode 100644 CRM/Core/I18n/SchemaStructure_2_2_0.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_0_alpha1.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_0_beta1.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_0_beta4.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_1_alpha1.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_1_beta2.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_2_beta4.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_3_beta1.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_4_0.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_4_beta2.php create mode 100644 CRM/Core/I18n/SchemaStructure_3_4_beta3.php create mode 100644 CRM/Core/I18n/SchemaStructure_4_1_0.php create mode 100644 CRM/Core/I18n/SchemaStructure_4_1_alpha1.php create mode 100644 CRM/Core/I18n/SchemaStructure_4_2_alpha1.php create mode 100644 CRM/Core/IDS.php create mode 100644 CRM/Core/Invoke.php create mode 100644 CRM/Core/JobManager.php create mode 100644 CRM/Core/Joomla.php create mode 100644 CRM/Core/Key.php create mode 100644 CRM/Core/Lock.php create mode 100644 CRM/Core/ManagedEntities.php create mode 100644 CRM/Core/Menu.php create mode 100644 CRM/Core/Module.php create mode 100644 CRM/Core/OptionGroup.php create mode 100644 CRM/Core/OptionValue.php create mode 100644 CRM/Core/Page.php create mode 100644 CRM/Core/Page/AJAX.php create mode 100644 CRM/Core/Page/AJAX/Location.php create mode 100644 CRM/Core/Page/Basic.php create mode 100644 CRM/Core/Page/File.php create mode 100644 CRM/Core/Page/Inline/Help.php create mode 100644 CRM/Core/Page/QUnit.php create mode 100644 CRM/Core/Payment.php create mode 100644 CRM/Core/Payment/AuthorizeNet.php create mode 100644 CRM/Core/Payment/AuthorizeNetIPN.php create mode 100644 CRM/Core/Payment/BaseIPN.php create mode 100644 CRM/Core/Payment/Dummy.php create mode 100644 CRM/Core/Payment/Elavon.php create mode 100644 CRM/Core/Payment/FirstData.php create mode 100644 CRM/Core/Payment/Form.php create mode 100644 CRM/Core/Payment/Google.php create mode 100644 CRM/Core/Payment/GoogleIPN.php create mode 100644 CRM/Core/Payment/IATS.php create mode 100644 CRM/Core/Payment/Moneris.php create mode 100644 CRM/Core/Payment/PayJunction.php create mode 100644 CRM/Core/Payment/PayPalIPN.php create mode 100644 CRM/Core/Payment/PayPalImpl.php create mode 100644 CRM/Core/Payment/PayPalProIPN.php create mode 100644 CRM/Core/Payment/PayflowPro.php create mode 100644 CRM/Core/Payment/PaymentExpress.php create mode 100644 CRM/Core/Payment/PaymentExpressIPN.php create mode 100644 CRM/Core/Payment/PaymentExpressUtils.php create mode 100644 CRM/Core/Payment/ProcessorForm.php create mode 100644 CRM/Core/Payment/Realex.php create mode 100644 CRM/Core/Payment/eWAY.php create mode 100644 CRM/Core/Permission.php create mode 100644 CRM/Core/Permission/Base.php create mode 100644 CRM/Core/Permission/Drupal.php create mode 100644 CRM/Core/Permission/Drupal6.php create mode 100644 CRM/Core/Permission/DrupalBase.php create mode 100644 CRM/Core/Permission/Joomla.php create mode 100644 CRM/Core/Permission/Soap.php create mode 100644 CRM/Core/Permission/UnitTests.php create mode 100644 CRM/Core/Permission/WordPress.php create mode 100644 CRM/Core/PseudoConstant.php create mode 100644 CRM/Core/QuickForm/Action.php create mode 100644 CRM/Core/QuickForm/Action/Back.php create mode 100644 CRM/Core/QuickForm/Action/Cancel.php create mode 100644 CRM/Core/QuickForm/Action/Display.php create mode 100644 CRM/Core/QuickForm/Action/Done.php create mode 100644 CRM/Core/QuickForm/Action/Jump.php create mode 100644 CRM/Core/QuickForm/Action/Next.php create mode 100644 CRM/Core/QuickForm/Action/Process.php create mode 100644 CRM/Core/QuickForm/Action/Refresh.php create mode 100644 CRM/Core/QuickForm/Action/Reload.php create mode 100644 CRM/Core/QuickForm/Action/Submit.php create mode 100644 CRM/Core/QuickForm/Action/Upload.php create mode 100644 CRM/Core/QuickForm/GroupMultiSelect.php create mode 100644 CRM/Core/QuickForm/NestedAdvMultiSelect.php create mode 100644 CRM/Core/Region.php create mode 100644 CRM/Core/Report/Excel.php create mode 100644 CRM/Core/Resources.php create mode 100644 CRM/Core/ScheduledJob.php create mode 100644 CRM/Core/SelectValues.php create mode 100644 CRM/Core/Selector/API.php create mode 100644 CRM/Core/Selector/Base.php create mode 100644 CRM/Core/Selector/Controller.php create mode 100644 CRM/Core/Session.php create mode 100644 CRM/Core/ShowHideBlocks.php create mode 100644 CRM/Core/Smarty.php create mode 100644 CRM/Core/Smarty/plugins/block.crmRegion.php create mode 100644 CRM/Core/Smarty/plugins/block.edit.php create mode 100644 CRM/Core/Smarty/plugins/block.htxt.php create mode 100644 CRM/Core/Smarty/plugins/block.localize.php create mode 100644 CRM/Core/Smarty/plugins/block.serialize.php create mode 100644 CRM/Core/Smarty/plugins/block.ts.php create mode 100644 CRM/Core/Smarty/plugins/compiler.continue.php create mode 100644 CRM/Core/Smarty/plugins/function.crmAPI.php create mode 100644 CRM/Core/Smarty/plugins/function.crmDBTpl.php create mode 100644 CRM/Core/Smarty/plugins/function.crmKey.php create mode 100644 CRM/Core/Smarty/plugins/function.crmNavigationMenu.php create mode 100644 CRM/Core/Smarty/plugins/function.crmResURL.php create mode 100644 CRM/Core/Smarty/plugins/function.crmScript.php create mode 100644 CRM/Core/Smarty/plugins/function.crmSetting.php create mode 100644 CRM/Core/Smarty/plugins/function.crmStyle.php create mode 100644 CRM/Core/Smarty/plugins/function.docURL.php create mode 100644 CRM/Core/Smarty/plugins/function.help.php create mode 100644 CRM/Core/Smarty/plugins/function.isValueChange.php create mode 100644 CRM/Core/Smarty/plugins/function.sectionTotal.php create mode 100644 CRM/Core/Smarty/plugins/function.simpleActivityContacts.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmAddClass.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmBtnType.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmBtnValidate.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmDate.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmDelete.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmFirstWord.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmICalDate.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmICalText.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmInsert.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmMoney.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmNumberFormat.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmReplace.php create mode 100644 CRM/Core/Smarty/plugins/modifier.crmStripAlternatives.php create mode 100644 CRM/Core/Smarty/plugins/modifier.htmlize.php create mode 100644 CRM/Core/Smarty/plugins/modifier.json.php create mode 100644 CRM/Core/Smarty/plugins/modifier.mb_truncate.php create mode 100644 CRM/Core/Smarty/plugins/modifier.substring.php create mode 100644 CRM/Core/Smarty/resources/String.php create mode 100644 CRM/Core/State.php create mode 100644 CRM/Core/StateMachine.php create mode 100644 CRM/Core/TableHierarchy.php create mode 100644 CRM/Core/TemporaryErrorScope.php create mode 100644 CRM/Core/Transaction.php create mode 100644 CRM/Core/xml/Menu/Activity.xml create mode 100644 CRM/Core/xml/Menu/Admin.xml create mode 100644 CRM/Core/xml/Menu/Contact.xml create mode 100644 CRM/Core/xml/Menu/Custom.xml create mode 100644 CRM/Core/xml/Menu/Group.xml create mode 100644 CRM/Core/xml/Menu/Import.xml create mode 100644 CRM/Core/xml/Menu/Location.xml create mode 100644 CRM/Core/xml/Menu/Misc.xml create mode 100644 CRM/Core/xml/Menu/PCP.xml create mode 100644 CRM/Core/xml/Menu/Profile.xml create mode 100644 CRM/Custom/Form/ChangeFieldType.php create mode 100644 CRM/Custom/Form/CustomData.php create mode 100644 CRM/Custom/Form/DeleteField.php create mode 100644 CRM/Custom/Form/DeleteFile.php create mode 100644 CRM/Custom/Form/DeleteGroup.php create mode 100644 CRM/Custom/Form/Field.php create mode 100644 CRM/Custom/Form/Group.php create mode 100644 CRM/Custom/Form/MoveField.php create mode 100644 CRM/Custom/Form/Option.php create mode 100644 CRM/Custom/Form/Preview.php create mode 100644 CRM/Custom/Page/Field.php create mode 100644 CRM/Custom/Page/Group.php create mode 100644 CRM/Custom/Page/Option.php create mode 100644 CRM/Dashlet/Page/Activity.php create mode 100644 CRM/Dashlet/Page/AllCases.php create mode 100644 CRM/Dashlet/Page/Blog.php create mode 100644 CRM/Dashlet/Page/CaseDashboard.php create mode 100644 CRM/Dashlet/Page/MyCases.php create mode 100644 CRM/Dedupe/BAO/QueryBuilder.php create mode 100644 CRM/Dedupe/BAO/QueryBuilder/IndividualGeneral.php create mode 100644 CRM/Dedupe/BAO/QueryBuilder/IndividualSupervised.php create mode 100644 CRM/Dedupe/BAO/QueryBuilder/IndividualUnsupervised.php create mode 100644 CRM/Dedupe/BAO/Rule.php create mode 100644 CRM/Dedupe/BAO/RuleGroup.php create mode 100644 CRM/Dedupe/Finder.php create mode 100644 CRM/Dedupe/Merger.php create mode 100644 CRM/Event/BAO/Event.php create mode 100644 CRM/Event/BAO/Participant.php create mode 100644 CRM/Event/BAO/ParticipantPayment.php create mode 100644 CRM/Event/BAO/ParticipantStatusType.php create mode 100644 CRM/Event/BAO/Query.php create mode 100644 CRM/Event/Badge.php create mode 100644 CRM/Event/Badge/Logo.php create mode 100644 CRM/Event/Badge/Logo5395.php create mode 100644 CRM/Event/Badge/NameTent.php create mode 100644 CRM/Event/Badge/Simple.php create mode 100644 CRM/Event/Cart/BAO/Cart.php create mode 100644 CRM/Event/Cart/BAO/Conference.php create mode 100644 CRM/Event/Cart/BAO/EventInCart.php create mode 100644 CRM/Event/Cart/BAO/MerParticipant.php create mode 100644 CRM/Event/Cart/Controller/Checkout.php create mode 100644 CRM/Event/Cart/Form/Cart.php create mode 100644 CRM/Event/Cart/Form/Checkout/ConferenceEvents.php create mode 100644 CRM/Event/Cart/Form/Checkout/ParticipantsAndPrices.php create mode 100644 CRM/Event/Cart/Form/Checkout/Payment.php create mode 100644 CRM/Event/Cart/Form/Checkout/ThankYou.php create mode 100644 CRM/Event/Cart/Form/MerParticipant.php create mode 100644 CRM/Event/Cart/Page/AddToCart.php create mode 100644 CRM/Event/Cart/Page/CheckoutAJAX.php create mode 100644 CRM/Event/Cart/Page/RemoveFromCart.php create mode 100644 CRM/Event/Cart/Page/ViewCart.php create mode 100644 CRM/Event/Cart/StateMachine/Checkout.php create mode 100644 CRM/Event/Config.php create mode 100644 CRM/Event/Controller/Registration.php create mode 100644 CRM/Event/Controller/Search.php create mode 100644 CRM/Event/Form/EventFees.php create mode 100644 CRM/Event/Form/ManageEvent.php create mode 100644 CRM/Event/Form/ManageEvent/Conference.php create mode 100644 CRM/Event/Form/ManageEvent/Delete.php create mode 100644 CRM/Event/Form/ManageEvent/EventInfo.php create mode 100644 CRM/Event/Form/ManageEvent/Fee.php create mode 100644 CRM/Event/Form/ManageEvent/Location.php create mode 100644 CRM/Event/Form/ManageEvent/Registration.php create mode 100755 CRM/Event/Form/ManageEvent/ScheduleReminders.php create mode 100644 CRM/Event/Form/ManageEvent/TabHeader.php create mode 100644 CRM/Event/Form/Participant.php create mode 100644 CRM/Event/Form/ParticipantView.php create mode 100644 CRM/Event/Form/Registration.php create mode 100644 CRM/Event/Form/Registration/AdditionalParticipant.php create mode 100644 CRM/Event/Form/Registration/Confirm.php create mode 100644 CRM/Event/Form/Registration/ParticipantConfirm.php create mode 100644 CRM/Event/Form/Registration/Register.php create mode 100644 CRM/Event/Form/Registration/ThankYou.php create mode 100644 CRM/Event/Form/Search.php create mode 100644 CRM/Event/Form/SearchEvent.php create mode 100644 CRM/Event/Form/Task.php create mode 100644 CRM/Event/Form/Task/Badge.php create mode 100644 CRM/Event/Form/Task/Batch.php create mode 100644 CRM/Event/Form/Task/Cancel.php create mode 100644 CRM/Event/Form/Task/Delete.php create mode 100644 CRM/Event/Form/Task/Email.php create mode 100644 CRM/Event/Form/Task/ParticipantStatus.php create mode 100644 CRM/Event/Form/Task/PickProfile.php create mode 100644 CRM/Event/Form/Task/Print.php create mode 100644 CRM/Event/Form/Task/Result.php create mode 100644 CRM/Event/Form/Task/SaveSearch.php create mode 100644 CRM/Event/Form/Task/SaveSearch/Update.php create mode 100644 CRM/Event/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Event/Import/Controller.php create mode 100644 CRM/Event/Import/Field.php create mode 100644 CRM/Event/Import/Form/MapField.php create mode 100644 CRM/Event/Import/Form/Preview.php create mode 100644 CRM/Event/Import/Form/Summary.php create mode 100644 CRM/Event/Import/Form/UploadFile.php create mode 100644 CRM/Event/Import/Parser.php create mode 100644 CRM/Event/Import/Parser/Participant.php create mode 100644 CRM/Event/Import/StateMachine.php create mode 100644 CRM/Event/Info.php create mode 100644 CRM/Event/Page/AJAX.php create mode 100644 CRM/Event/Page/DashBoard.php create mode 100644 CRM/Event/Page/EventInfo.php create mode 100644 CRM/Event/Page/ICalendar.php create mode 100644 CRM/Event/Page/ManageEvent.php create mode 100644 CRM/Event/Page/ParticipantListing.php create mode 100644 CRM/Event/Page/ParticipantListing/Name.php create mode 100644 CRM/Event/Page/ParticipantListing/NameAndEmail.php create mode 100644 CRM/Event/Page/ParticipantListing/NameStatusAndDate.php create mode 100644 CRM/Event/Page/ParticipantListing/Simple.php create mode 100644 CRM/Event/Page/Tab.php create mode 100644 CRM/Event/Page/UserDashboard.php create mode 100644 CRM/Event/PseudoConstant.php create mode 100644 CRM/Event/Selector/Search.php create mode 100644 CRM/Event/StateMachine/Registration.php create mode 100644 CRM/Event/StateMachine/Search.php create mode 100644 CRM/Event/Task.php create mode 100644 CRM/Event/xml/Menu/Event.xml create mode 100644 CRM/Event/xml/Menu/PCP.xml create mode 100644 CRM/Export/BAO/Export.php create mode 100644 CRM/Export/Form/Map.php create mode 100644 CRM/Export/Form/Select.php create mode 100644 CRM/Extension/Browser.php create mode 100644 CRM/Extension/Container/Basic.php create mode 100644 CRM/Extension/Container/Collection.php create mode 100644 CRM/Extension/Container/Interface.php create mode 100644 CRM/Extension/Container/Static.php create mode 100644 CRM/Extension/Downloader.php create mode 100644 CRM/Extension/Exception.php create mode 100644 CRM/Extension/Exception/DependencyException.php create mode 100644 CRM/Extension/Exception/MissingException.php create mode 100644 CRM/Extension/Exception/ParseException.php create mode 100644 CRM/Extension/Info.php create mode 100644 CRM/Extension/Manager.php create mode 100644 CRM/Extension/Manager/Base.php create mode 100644 CRM/Extension/Manager/Interface.php create mode 100644 CRM/Extension/Manager/Module.php create mode 100644 CRM/Extension/Manager/Payment.php create mode 100644 CRM/Extension/Manager/Report.php create mode 100644 CRM/Extension/Manager/Search.php create mode 100644 CRM/Extension/Mapper.php create mode 100644 CRM/Extension/System.php create mode 100644 CRM/Extension/Upgrades.php create mode 100644 CRM/Financial/BAO/ExportFormat.php create mode 100644 CRM/Financial/BAO/ExportFormat/CSV.php create mode 100644 CRM/Financial/BAO/ExportFormat/IIF.php create mode 100644 CRM/Financial/BAO/FinancialAccount.php create mode 100644 CRM/Financial/BAO/FinancialItem.php create mode 100644 CRM/Financial/BAO/FinancialType.php create mode 100644 CRM/Financial/BAO/FinancialTypeAccount.php create mode 100644 CRM/Financial/BAO/PaymentProcessor.php create mode 100644 CRM/Financial/BAO/PaymentProcessorType.php create mode 100644 CRM/Financial/Form/BatchTransaction.php create mode 100644 CRM/Financial/Form/Export.php create mode 100644 CRM/Financial/Form/FinancialAccount.php create mode 100644 CRM/Financial/Form/FinancialBatch.php create mode 100644 CRM/Financial/Form/FinancialType.php create mode 100644 CRM/Financial/Form/FinancialTypeAccount.php create mode 100644 CRM/Financial/Form/Search.php create mode 100644 CRM/Financial/Page/AJAX.php create mode 100644 CRM/Financial/Page/Batch.php create mode 100644 CRM/Financial/Page/BatchTransaction.php create mode 100644 CRM/Financial/Page/FinancialAccount.php create mode 100644 CRM/Financial/Page/FinancialBatch.php create mode 100644 CRM/Financial/Page/FinancialType.php create mode 100644 CRM/Financial/Page/FinancialTypeAccount.php create mode 100644 CRM/Friend/BAO/Friend.php create mode 100644 CRM/Friend/Form.php create mode 100644 CRM/Friend/Form/Contribute.php create mode 100644 CRM/Friend/Form/Event.php create mode 100644 CRM/Grant/BAO/Grant.php create mode 100644 CRM/Grant/BAO/Query.php create mode 100644 CRM/Grant/Config.php create mode 100644 CRM/Grant/Controller/PaymentSearch.php create mode 100644 CRM/Grant/Controller/Search.php create mode 100644 CRM/Grant/Form/Grant.php create mode 100644 CRM/Grant/Form/GrantView.php create mode 100644 CRM/Grant/Form/Search.php create mode 100644 CRM/Grant/Form/Task.php create mode 100644 CRM/Grant/Form/Task/Delete.php create mode 100644 CRM/Grant/Form/Task/Print.php create mode 100644 CRM/Grant/Form/Task/Result.php create mode 100644 CRM/Grant/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Grant/Form/Task/Update.php create mode 100644 CRM/Grant/Info.php create mode 100644 CRM/Grant/Page/DashBoard.php create mode 100644 CRM/Grant/Page/GrantProgram.php create mode 100644 CRM/Grant/Page/Payment.php create mode 100644 CRM/Grant/Page/Tab.php create mode 100644 CRM/Grant/PseudoConstant.php create mode 100644 CRM/Grant/Selector/PaymentSearch.php create mode 100644 CRM/Grant/Selector/Search.php create mode 100644 CRM/Grant/StateMachine/Search.php create mode 100644 CRM/Grant/Task.php create mode 100644 CRM/Grant/xml/Menu/Grant.xml create mode 100644 CRM/Group/Controller.php create mode 100644 CRM/Group/Form/Edit.php create mode 100644 CRM/Group/Form/Search.php create mode 100644 CRM/Group/Page/AJAX.php create mode 100644 CRM/Group/Page/Group.php create mode 100644 CRM/Group/StateMachine.php create mode 100644 CRM/Import/Controller.php create mode 100644 CRM/Import/DataSource.php create mode 100644 CRM/Import/DataSource/CSV.php create mode 100644 CRM/Import/DataSource/SQL.php create mode 100644 CRM/Import/Field.php create mode 100644 CRM/Import/Form/DataSource.php create mode 100644 CRM/Import/Form/MapField.php create mode 100644 CRM/Import/Form/Preview.php create mode 100644 CRM/Import/Form/Summary.php create mode 100644 CRM/Import/Form/UploadFile.php create mode 100644 CRM/Import/ImportJob.php create mode 100644 CRM/Import/Importer.php create mode 100644 CRM/Import/Page/AJAX.php create mode 100644 CRM/Import/Parser.php create mode 100644 CRM/Import/Parser/Contact.php create mode 100644 CRM/Import/StateMachine.php create mode 100644 CRM/Logging/Differ.php create mode 100644 CRM/Logging/ReportDetail.php create mode 100644 CRM/Logging/ReportSummary.php create mode 100644 CRM/Logging/Reverter.php create mode 100644 CRM/Logging/Schema.php create mode 100644 CRM/Mailing/BAO/BouncePattern.php create mode 100644 CRM/Mailing/BAO/Component.php create mode 100644 CRM/Mailing/BAO/Job.php create mode 100644 CRM/Mailing/BAO/Mailing.php create mode 100644 CRM/Mailing/BAO/Query.php create mode 100644 CRM/Mailing/BAO/Recipients.php create mode 100644 CRM/Mailing/BAO/Spool.php create mode 100644 CRM/Mailing/BAO/TrackableURL.php create mode 100644 CRM/Mailing/Config.php create mode 100644 CRM/Mailing/Controller/Send.php create mode 100644 CRM/Mailing/Event/BAO/Bounce.php create mode 100644 CRM/Mailing/Event/BAO/Confirm.php create mode 100644 CRM/Mailing/Event/BAO/Delivered.php create mode 100644 CRM/Mailing/Event/BAO/Forward.php create mode 100644 CRM/Mailing/Event/BAO/Opened.php create mode 100644 CRM/Mailing/Event/BAO/Queue.php create mode 100644 CRM/Mailing/Event/BAO/Reply.php create mode 100644 CRM/Mailing/Event/BAO/Resubscribe.php create mode 100644 CRM/Mailing/Event/BAO/Subscribe.php create mode 100644 CRM/Mailing/Event/BAO/TrackableURLOpen.php create mode 100644 CRM/Mailing/Event/BAO/Unsubscribe.php create mode 100644 CRM/Mailing/Form/Approve.php create mode 100644 CRM/Mailing/Form/Browse.php create mode 100644 CRM/Mailing/Form/Component.php create mode 100644 CRM/Mailing/Form/ForwardMailing.php create mode 100644 CRM/Mailing/Form/Group.php create mode 100644 CRM/Mailing/Form/Schedule.php create mode 100644 CRM/Mailing/Form/Search.php create mode 100644 CRM/Mailing/Form/Settings.php create mode 100644 CRM/Mailing/Form/Subscribe.php create mode 100644 CRM/Mailing/Form/Test.php create mode 100644 CRM/Mailing/Form/Upload.php create mode 100644 CRM/Mailing/Info.php create mode 100644 CRM/Mailing/MailStore.php create mode 100644 CRM/Mailing/MailStore/Imap.php create mode 100644 CRM/Mailing/MailStore/Localdir.php create mode 100644 CRM/Mailing/MailStore/Maildir.php create mode 100644 CRM/Mailing/MailStore/Mbox.php create mode 100644 CRM/Mailing/MailStore/Pop3.php create mode 100644 CRM/Mailing/Page/AJAX.php create mode 100644 CRM/Mailing/Page/Browse.php create mode 100644 CRM/Mailing/Page/Common.php create mode 100644 CRM/Mailing/Page/Component.php create mode 100644 CRM/Mailing/Page/Confirm.php create mode 100644 CRM/Mailing/Page/Event.php create mode 100644 CRM/Mailing/Page/Optout.php create mode 100644 CRM/Mailing/Page/Preview.php create mode 100644 CRM/Mailing/Page/Report.php create mode 100644 CRM/Mailing/Page/Resubscribe.php create mode 100644 CRM/Mailing/Page/Unsubscribe.php create mode 100644 CRM/Mailing/Page/View.php create mode 100644 CRM/Mailing/PseudoConstant.php create mode 100644 CRM/Mailing/Selector/Browse.php create mode 100644 CRM/Mailing/Selector/Event.php create mode 100644 CRM/Mailing/StateMachine/Send.php create mode 100644 CRM/Mailing/xml/Menu/Mailing.xml create mode 100644 CRM/Member/BAO/Membership.php create mode 100644 CRM/Member/BAO/MembershipLog.php create mode 100644 CRM/Member/BAO/MembershipStatus.php create mode 100644 CRM/Member/BAO/MembershipType.php create mode 100644 CRM/Member/BAO/Query.php create mode 100644 CRM/Member/Config.php create mode 100644 CRM/Member/Controller/Search.php create mode 100644 CRM/Member/Form.php create mode 100644 CRM/Member/Form/Membership.php create mode 100644 CRM/Member/Form/MembershipBlock.php create mode 100644 CRM/Member/Form/MembershipRenewal.php create mode 100644 CRM/Member/Form/MembershipStatus.php create mode 100644 CRM/Member/Form/MembershipType.php create mode 100644 CRM/Member/Form/MembershipView.php create mode 100644 CRM/Member/Form/Search.php create mode 100644 CRM/Member/Form/Task.php create mode 100644 CRM/Member/Form/Task/Batch.php create mode 100644 CRM/Member/Form/Task/Delete.php create mode 100644 CRM/Member/Form/Task/Email.php create mode 100644 CRM/Member/Form/Task/PickProfile.php create mode 100644 CRM/Member/Form/Task/Print.php create mode 100644 CRM/Member/Form/Task/Result.php create mode 100644 CRM/Member/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Member/Import/Controller.php create mode 100644 CRM/Member/Import/Field.php create mode 100644 CRM/Member/Import/Form/MapField.php create mode 100644 CRM/Member/Import/Form/Preview.php create mode 100644 CRM/Member/Import/Form/Summary.php create mode 100644 CRM/Member/Import/Form/UploadFile.php create mode 100644 CRM/Member/Import/Parser.php create mode 100644 CRM/Member/Import/Parser/Membership.php create mode 100644 CRM/Member/Import/StateMachine.php create mode 100644 CRM/Member/Info.php create mode 100644 CRM/Member/Page/AJAX.php create mode 100644 CRM/Member/Page/DashBoard.php create mode 100644 CRM/Member/Page/MembershipStatus.php create mode 100644 CRM/Member/Page/MembershipType.php create mode 100644 CRM/Member/Page/Tab.php create mode 100644 CRM/Member/Page/UserDashboard.php create mode 100644 CRM/Member/PseudoConstant.php create mode 100644 CRM/Member/Selector/Search.php create mode 100644 CRM/Member/StateMachine/Search.php create mode 100644 CRM/Member/Task.php create mode 100644 CRM/Member/xml/Menu/Member.xml create mode 100644 CRM/Note/Form/Note.php create mode 100644 CRM/PCP/BAO/PCP.php create mode 100644 CRM/PCP/Controller/PCP.php create mode 100644 CRM/PCP/Form/Campaign.php create mode 100644 CRM/PCP/Form/Contribute.php create mode 100644 CRM/PCP/Form/Event.php create mode 100644 CRM/PCP/Form/PCP.php create mode 100644 CRM/PCP/Form/PCPAccount.php create mode 100644 CRM/PCP/Page/PCP.php create mode 100644 CRM/PCP/Page/PCPInfo.php create mode 100644 CRM/PCP/PseudoConstant.php create mode 100644 CRM/PCP/StateMachine/PCP.php create mode 100644 CRM/Pledge/BAO/Pledge.php create mode 100644 CRM/Pledge/BAO/PledgeBlock.php create mode 100644 CRM/Pledge/BAO/PledgePayment.php create mode 100644 CRM/Pledge/BAO/Query.php create mode 100644 CRM/Pledge/Config.php create mode 100644 CRM/Pledge/Controller/Search.php create mode 100644 CRM/Pledge/Form/Payment.php create mode 100644 CRM/Pledge/Form/Pledge.php create mode 100644 CRM/Pledge/Form/PledgeView.php create mode 100644 CRM/Pledge/Form/Search.php create mode 100644 CRM/Pledge/Form/Task.php create mode 100644 CRM/Pledge/Form/Task/Delete.php create mode 100644 CRM/Pledge/Form/Task/Print.php create mode 100644 CRM/Pledge/Form/Task/Result.php create mode 100644 CRM/Pledge/Form/Task/SearchTaskHookSample.php create mode 100644 CRM/Pledge/Info.php create mode 100644 CRM/Pledge/Page/AJAX.php create mode 100644 CRM/Pledge/Page/DashBoard.php create mode 100644 CRM/Pledge/Page/Payment.php create mode 100644 CRM/Pledge/Page/Tab.php create mode 100644 CRM/Pledge/Page/UserDashboard.php create mode 100644 CRM/Pledge/Selector/Search.php create mode 100644 CRM/Pledge/StateMachine/Search.php create mode 100644 CRM/Pledge/Task.php create mode 100644 CRM/Pledge/xml/Menu/Pledge.xml create mode 100644 CRM/Price/BAO/Field.php create mode 100644 CRM/Price/BAO/FieldValue.php create mode 100644 CRM/Price/BAO/LineItem.php create mode 100644 CRM/Price/BAO/Set.php create mode 100644 CRM/Price/Form/DeleteField.php create mode 100644 CRM/Price/Form/DeleteSet.php create mode 100644 CRM/Price/Form/Field.php create mode 100644 CRM/Price/Form/Option.php create mode 100644 CRM/Price/Form/Preview.php create mode 100644 CRM/Price/Form/Set.php create mode 100644 CRM/Price/Page/Field.php create mode 100644 CRM/Price/Page/Option.php create mode 100644 CRM/Price/Page/Set.php create mode 100644 CRM/Profile/Form.php create mode 100644 CRM/Profile/Form/Dynamic.php create mode 100644 CRM/Profile/Form/Edit.php create mode 100644 CRM/Profile/Form/Search.php create mode 100644 CRM/Profile/Page/Dynamic.php create mode 100644 CRM/Profile/Page/Listings.php create mode 100644 CRM/Profile/Page/MultipleRecordFieldsListing.php create mode 100644 CRM/Profile/Page/View.php create mode 100644 CRM/Profile/Selector/Listings.php create mode 100644 CRM/Project/BAO/TaskStatus.php create mode 100644 CRM/Queue/BAO/QueueItem.php create mode 100644 CRM/Queue/ErrorPolicy.php create mode 100644 CRM/Queue/Menu.php create mode 100644 CRM/Queue/Page/AJAX.php create mode 100644 CRM/Queue/Page/Runner.php create mode 100644 CRM/Queue/Queue.php create mode 100644 CRM/Queue/Queue/Memory.php create mode 100644 CRM/Queue/Queue/Sql.php create mode 100644 CRM/Queue/Runner.php create mode 100644 CRM/Queue/Service.php create mode 100644 CRM/Queue/Task.php create mode 100644 CRM/Queue/TaskContext.php create mode 100644 CRM/Report/BAO/Instance.php create mode 100644 CRM/Report/Config.php create mode 100644 CRM/Report/Form.php create mode 100644 CRM/Report/Form/Activity.php create mode 100644 CRM/Report/Form/ActivitySummary.php create mode 100644 CRM/Report/Form/Campaign/SurveyDetails.php create mode 100644 CRM/Report/Form/Case/Demographics.php create mode 100644 CRM/Report/Form/Case/Detail.php create mode 100644 CRM/Report/Form/Case/Summary.php create mode 100644 CRM/Report/Form/Case/TimeSpent.php create mode 100644 CRM/Report/Form/Contact/CurrentEmployer.php create mode 100644 CRM/Report/Form/Contact/Detail.php create mode 100644 CRM/Report/Form/Contact/Log.php create mode 100644 CRM/Report/Form/Contact/LoggingDetail.php create mode 100644 CRM/Report/Form/Contact/LoggingSummary.php create mode 100644 CRM/Report/Form/Contact/Relationship.php create mode 100644 CRM/Report/Form/Contact/Summary.php create mode 100644 CRM/Report/Form/Contribute/Bookkeeping.php create mode 100644 CRM/Report/Form/Contribute/Detail.php create mode 100644 CRM/Report/Form/Contribute/History.php create mode 100644 CRM/Report/Form/Contribute/HouseholdSummary.php create mode 100644 CRM/Report/Form/Contribute/LoggingDetail.php create mode 100644 CRM/Report/Form/Contribute/LoggingSummary.php create mode 100644 CRM/Report/Form/Contribute/Lybunt.php create mode 100644 CRM/Report/Form/Contribute/OrganizationSummary.php create mode 100644 CRM/Report/Form/Contribute/PCP.php create mode 100644 CRM/Report/Form/Contribute/Repeat.php create mode 100644 CRM/Report/Form/Contribute/SoftCredit.php create mode 100644 CRM/Report/Form/Contribute/Summary.php create mode 100644 CRM/Report/Form/Contribute/Sybunt.php create mode 100644 CRM/Report/Form/Contribute/TopDonor.php create mode 100644 CRM/Report/Form/Event.php create mode 100644 CRM/Report/Form/Event/Income.php create mode 100644 CRM/Report/Form/Event/IncomeCountSummary.php create mode 100644 CRM/Report/Form/Event/ParticipantListCount.php create mode 100644 CRM/Report/Form/Event/ParticipantListing.php create mode 100644 CRM/Report/Form/Event/Summary.php create mode 100644 CRM/Report/Form/Extended.php create mode 100644 CRM/Report/Form/Grant/Detail.php create mode 100644 CRM/Report/Form/Grant/Statistics.php create mode 100644 CRM/Report/Form/Instance.php create mode 100644 CRM/Report/Form/Mailing/Bounce.php create mode 100644 CRM/Report/Form/Mailing/Clicks.php create mode 100644 CRM/Report/Form/Mailing/Detail.php create mode 100644 CRM/Report/Form/Mailing/Opened.php create mode 100644 CRM/Report/Form/Mailing/Summary.php create mode 100644 CRM/Report/Form/Member/ContributionDetail.php create mode 100644 CRM/Report/Form/Member/Detail.php create mode 100644 CRM/Report/Form/Member/Lapse.php create mode 100644 CRM/Report/Form/Member/Summary.php create mode 100644 CRM/Report/Form/Membership/Summary.php create mode 100644 CRM/Report/Form/Pledge/Detail.php create mode 100644 CRM/Report/Form/Pledge/Pbnp.php create mode 100644 CRM/Report/Form/Pledge/Summary.php create mode 100644 CRM/Report/Form/Register.php create mode 100644 CRM/Report/Form/Walklist/Walklist.php create mode 100644 CRM/Report/Info.php create mode 100644 CRM/Report/Interface.php create mode 100644 CRM/Report/Page/Instance.php create mode 100644 CRM/Report/Page/InstanceList.php create mode 100644 CRM/Report/Page/List.php create mode 100644 CRM/Report/Page/Options.php create mode 100644 CRM/Report/Page/Report.php create mode 100644 CRM/Report/Page/TemplateList.php create mode 100644 CRM/Report/Utils/Get.php create mode 100644 CRM/Report/Utils/Report.php create mode 100644 CRM/Report/xml/Menu/Report.xml create mode 100644 CRM/SMS/BAO/Provider.php create mode 100644 CRM/SMS/Controller/Send.php create mode 100644 CRM/SMS/Form/Group.php create mode 100644 CRM/SMS/Form/Provider.php create mode 100644 CRM/SMS/Form/Schedule.php create mode 100644 CRM/SMS/Form/Upload.php create mode 100644 CRM/SMS/Page/Callback.php create mode 100644 CRM/SMS/Page/Provider.php create mode 100644 CRM/SMS/Provider.php create mode 100644 CRM/SMS/StateMachine/Send.php create mode 100644 CRM/Tag/Form/Tag.php create mode 100644 CRM/UF/Form/AbstractPreview.php create mode 100644 CRM/UF/Form/AdvanceSetting.php create mode 100644 CRM/UF/Form/Field.php create mode 100644 CRM/UF/Form/Group.php create mode 100644 CRM/UF/Form/Inline/Preview.php create mode 100644 CRM/UF/Form/Inline/PreviewById.php create mode 100644 CRM/UF/Form/Preview.php create mode 100644 CRM/UF/Page/AJAX.php create mode 100644 CRM/UF/Page/Field.php create mode 100644 CRM/UF/Page/Group.php create mode 100644 CRM/UF/Page/ProfileEditor.php create mode 100644 CRM/Upgrade/3.1.5.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.1.5.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.5.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/case_activity_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/case_activity_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/case_activity_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_dupalert_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_dupalert_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_dupalert_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_offline_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_online_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_recurring_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_recurring_notify_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/contribution_recurring_notify_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/event_offline_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/event_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/event_online_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/friend_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/friend_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/friend_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/membership_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/membership_offline_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/membership_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/membership_online_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_cancelled_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_cancelled_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_cancelled_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_confirm_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_confirm_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_confirm_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_expired_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_expired_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/participant_expired_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_notify_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_notify_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_status_change_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_status_change_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_status_change_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_supporter_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_supporter_notify_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pcp_supporter_notify_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pledge_acknowledge_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pledge_acknowledge_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pledge_acknowledge_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pledge_reminder_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pledge_reminder_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/pledge_reminder_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/test_preview_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/test_preview_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/test_preview_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/uf_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/uf_notify_subject.tpl create mode 100644 CRM/Upgrade/3.1.alpha1.msg_template/message_templates/uf_notify_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/case_activity_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/contribution_dupalert_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/contribution_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/contribution_recurring_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/friend_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/membership_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/participant_cancelled_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/participant_confirm_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/participant_confirm_text.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/participant_expired_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/pcp_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/pcp_status_change_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/pcp_supporter_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/pledge_acknowledge_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/pledge_reminder_html.tpl create mode 100644 CRM/Upgrade/3.1.alpha2.msg_template/message_templates/uf_notify_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/event_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/participant_cancelled_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/participant_cancelled_text.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/participant_expired_html.tpl create mode 100644 CRM/Upgrade/3.1.beta1.msg_template/message_templates/participant_expired_text.tpl create mode 100644 CRM/Upgrade/3.1.beta2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.1.beta2.msg_template/message_templates/contribution_offline_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.beta2.msg_template/message_templates/membership_offline_receipt_subject.tpl create mode 100644 CRM/Upgrade/3.1.beta4.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.1.beta4.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.1.beta4.msg_template/message_templates/pcp_status_change_html.tpl create mode 100644 CRM/Upgrade/3.1.beta4.msg_template/message_templates/pcp_status_change_text.tpl create mode 100755 CRM/Upgrade/3.2.1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.2.1.msg_template/message_templates/contribution_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.2.1.msg_template/message_templates/contribution_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.2.1.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.2.1.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100755 CRM/Upgrade/3.2.alpha1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.2.alpha1.msg_template/message_templates/case_activity_subject.tpl create mode 100755 CRM/Upgrade/3.2.alpha1.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100755 CRM/Upgrade/3.2.alpha1.msg_template/message_templates/event_offline_receipt_text.tpl create mode 100755 CRM/Upgrade/3.2.alpha1.msg_template/message_templates/event_online_receipt_html.tpl create mode 100755 CRM/Upgrade/3.2.alpha1.msg_template/message_templates/event_online_receipt_text.tpl create mode 100755 CRM/Upgrade/3.2.alpha2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.2.alpha2.msg_template/message_templates/contribution_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.2.alpha2.msg_template/message_templates/contribution_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.2.alpha3.languages/languages.tpl create mode 100755 CRM/Upgrade/3.2.alpha3.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.2.alpha3.msg_template/message_templates/case_activity_html.tpl create mode 100644 CRM/Upgrade/3.2.alpha3.msg_template/message_templates/case_activity_text.tpl create mode 100755 CRM/Upgrade/3.3.2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.3.2.msg_template/message_templates/case_activity_html.tpl create mode 100644 CRM/Upgrade/3.3.2.msg_template/message_templates/case_activity_text.tpl create mode 100644 CRM/Upgrade/3.3.2.msg_template/message_templates/contribution_recurring_notify_html.tpl create mode 100644 CRM/Upgrade/3.3.2.msg_template/message_templates/contribution_recurring_notify_text.tpl create mode 100644 CRM/Upgrade/3.3.2.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.3.2.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100755 CRM/Upgrade/3.3.3.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.3.3.msg_template/message_templates/contribution_recurring_notify_html.tpl create mode 100644 CRM/Upgrade/3.3.3.msg_template/message_templates/contribution_recurring_notify_text.tpl create mode 100755 CRM/Upgrade/3.3.beta1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.3.beta1.msg_template/message_templates/petition_confirmation_needed_html.tpl create mode 100644 CRM/Upgrade/3.3.beta1.msg_template/message_templates/petition_confirmation_needed_subject.tpl create mode 100644 CRM/Upgrade/3.3.beta1.msg_template/message_templates/petition_confirmation_needed_text.tpl create mode 100644 CRM/Upgrade/3.3.beta1.msg_template/message_templates/petition_sign_html.tpl create mode 100644 CRM/Upgrade/3.3.beta1.msg_template/message_templates/petition_sign_subject.tpl create mode 100644 CRM/Upgrade/3.3.beta1.msg_template/message_templates/petition_sign_text.tpl create mode 100755 CRM/Upgrade/3.3.beta2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/contribution_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/contribution_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/event_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.3.beta2.msg_template/message_templates/petition_confirmation_needed_text.tpl create mode 100644 CRM/Upgrade/3.4.3.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.4.3.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.3.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.3.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.3.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.5.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.4.5.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.5.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.5.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.5.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.6.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.4.6.msg_template/message_templates/membership_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.6.msg_template/message_templates/membership_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.6.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.6.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.7.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.4.7.msg_template/message_templates/membership_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.7.msg_template/message_templates/membership_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.7.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.7.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/petition_confirmation_needed_html.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/petition_confirmation_needed_subject.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/petition_confirmation_needed_text.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/petition_sign_html.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/petition_sign_subject.tpl create mode 100644 CRM/Upgrade/3.4.beta2.msg_template/message_templates/petition_sign_text.tpl create mode 100644 CRM/Upgrade/4.1.alpha1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.1.alpha1.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.1.alpha1.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.1.alpha1.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_billing_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_billing_subject.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_billing_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_cancelled_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_cancelled_subject.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_cancelled_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_edit_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_edit_subject.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_edit_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_notify_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/contribution_recurring_notify_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_autorenew_billing_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_autorenew_billing_subject.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_autorenew_billing_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_autorenew_cancelled_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_autorenew_cancelled_subject.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_autorenew_cancelled_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/pledge_acknowledge_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/pledge_acknowledge_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/pledge_reminder_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha1.msg_template/message_templates/pledge_reminder_text.tpl create mode 100755 CRM/Upgrade/4.2.alpha2.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.2.alpha2.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha2.msg_template/message_templates/event_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha2.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.2.alpha2.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.2.alpha2.msg_template/message_templates/membership_offline_receipt_text.tpl create mode 100755 CRM/Upgrade/4.2.alpha3.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.2.alpha3.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100755 CRM/Upgrade/4.2.beta3.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.2.beta3.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.2.beta3.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/contribution_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/contribution_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/event_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/event_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/membership_offline_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/membership_offline_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.alpha1.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha3.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.3.alpha3.msg_template/message_templates/event_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.alpha3.msg_template/message_templates/event_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.alpha3.msg_template/message_templates/pcp_notify_html.tpl create mode 100644 CRM/Upgrade/4.3.beta1.msg_template/civicrm_msg_template.tpl create mode 100644 CRM/Upgrade/4.3.beta1.msg_template/message_templates/contribution_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.beta1.msg_template/message_templates/contribution_online_receipt_text.tpl create mode 100644 CRM/Upgrade/4.3.beta1.msg_template/message_templates/membership_online_receipt_html.tpl create mode 100644 CRM/Upgrade/4.3.beta1.msg_template/message_templates/membership_online_receipt_text.tpl create mode 100644 CRM/Upgrade/Controller.php create mode 100644 CRM/Upgrade/Form.php create mode 100644 CRM/Upgrade/Headless.php create mode 100644 CRM/Upgrade/Incremental/Legacy.php create mode 100644 CRM/Upgrade/Incremental/php/FourOne.php create mode 100644 CRM/Upgrade/Incremental/php/FourThree.php create mode 100644 CRM/Upgrade/Incremental/php/FourTwo.php create mode 100644 CRM/Upgrade/Incremental/php/FourZero.php create mode 100644 CRM/Upgrade/Incremental/php/ThreeFour.php create mode 100644 CRM/Upgrade/Incremental/php/ThreeThree.php create mode 100644 CRM/Upgrade/Incremental/php/ThreeTwo.php create mode 100644 CRM/Upgrade/Incremental/sql/2.1.2.mysql create mode 100644 CRM/Upgrade/Incremental/sql/2.2.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.6.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.7.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.alpha3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/2.2.beta4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.alpha3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.beta4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.0.beta5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.beta4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.beta5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.1.beta6.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.alpha3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.alpha4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.beta4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.2.beta5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.4.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.6.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.7.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.3.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.6.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.7.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.alpha3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/3.4.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.1.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.0.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.6.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.7.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.8.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.9.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.alpha3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.beta2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.beta3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.beta5.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.2.beta6.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.3.alpha1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.3.alpha2.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.3.alpha3.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/4.3.beta1.mysql.tpl create mode 100644 CRM/Upgrade/Incremental/sql/README.txt create mode 100644 CRM/Upgrade/Page/Cleanup.php create mode 100644 CRM/Upgrade/Page/Upgrade.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/BAO/Field.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/BAO/FieldValue.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/BAO/LineItem.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/BAO/Set.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/DAO/Field.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/DAO/FieldValue.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/DAO/LineItem.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/DAO/Set.php create mode 100644 CRM/Upgrade/Snapshot/V4p2/Price/DAO/SetEntity.php create mode 100644 CRM/Upgrade/StateMachine.php create mode 100644 CRM/Upgrade/ThreeOne/ThreeOne.php create mode 100644 CRM/Upgrade/ThreeZero/ThreeZero.php create mode 100644 CRM/Upgrade/TwoOne/Controller.php create mode 100644 CRM/Upgrade/TwoOne/Form/Step1.php create mode 100644 CRM/Upgrade/TwoOne/Form/Step2.php create mode 100644 CRM/Upgrade/TwoOne/Form/Step3.php create mode 100644 CRM/Upgrade/TwoOne/Form/Step4.php create mode 100644 CRM/Upgrade/TwoOne/Form/TwoOneTwo.php create mode 100644 CRM/Upgrade/TwoOne/Page/Upgrade.php create mode 100644 CRM/Upgrade/TwoOne/sql/domain_ids.mysql create mode 100644 CRM/Upgrade/TwoOne/sql/group_values.mysql create mode 100644 CRM/Upgrade/TwoOne/sql/misc.mysql create mode 100644 CRM/Upgrade/TwoOne/sql/two_one_two.mysql create mode 100644 CRM/Upgrade/TwoTwo/Controller.php create mode 100644 CRM/Upgrade/TwoTwo/Form/Step1.php create mode 100644 CRM/Upgrade/TwoTwo/Form/Step2.php create mode 100644 CRM/Upgrade/TwoTwo/Form/Step3.php create mode 100644 CRM/Upgrade/TwoTwo/Form/Step4.php create mode 100644 CRM/Utils/Address.php create mode 100644 CRM/Utils/Address/BatchUpdate.php create mode 100644 CRM/Utils/Address/USPS.php create mode 100644 CRM/Utils/Array.php create mode 100644 CRM/Utils/Cache.php create mode 100644 CRM/Utils/Cache/APCcache.php create mode 100644 CRM/Utils/Cache/ArrayCache.php create mode 100644 CRM/Utils/Cache/Interface.php create mode 100644 CRM/Utils/Cache/Memcache.php create mode 100644 CRM/Utils/Cache/Memcached.php create mode 100644 CRM/Utils/Cache/NoCache.php create mode 100644 CRM/Utils/Cache/SerializeCache.php create mode 100644 CRM/Utils/Cache/SqlGroup.php create mode 100644 CRM/Utils/Constant.php create mode 100644 CRM/Utils/Crypt.php create mode 100644 CRM/Utils/Date.php create mode 100644 CRM/Utils/DeprecatedUtils.php create mode 100644 CRM/Utils/File.php create mode 100644 CRM/Utils/Geocode/Google.php create mode 100644 CRM/Utils/Geocode/Yahoo.php create mode 100644 CRM/Utils/Hook.php create mode 100644 CRM/Utils/Hook/Drupal.php create mode 100644 CRM/Utils/Hook/Drupal6.php create mode 100644 CRM/Utils/Hook/Joomla.php create mode 100644 CRM/Utils/Hook/Soap.php create mode 100644 CRM/Utils/Hook/UnitTests.php create mode 100644 CRM/Utils/Hook/WordPress.php create mode 100644 CRM/Utils/HttpClient.php create mode 100644 CRM/Utils/ICalendar.php create mode 100644 CRM/Utils/JS.php create mode 100644 CRM/Utils/JSON.php create mode 100644 CRM/Utils/Mail.php create mode 100644 CRM/Utils/Mail/EmailProcessor.php create mode 100644 CRM/Utils/Mail/Incoming.php create mode 100644 CRM/Utils/Migrate/Export.php create mode 100644 CRM/Utils/Migrate/ExportJSON.php create mode 100644 CRM/Utils/Migrate/Import.php create mode 100644 CRM/Utils/Migrate/ImportJSON.php create mode 100644 CRM/Utils/Money.php create mode 100644 CRM/Utils/OpenFlashChart.php create mode 100644 CRM/Utils/PDF/Label.php create mode 100644 CRM/Utils/PDF/Utils.php create mode 100644 CRM/Utils/Pager.php create mode 100644 CRM/Utils/PagerAToZ.php create mode 100644 CRM/Utils/PseudoConstant.php create mode 100644 CRM/Utils/REST.php create mode 100644 CRM/Utils/ReCAPTCHA.php create mode 100644 CRM/Utils/Recent.php create mode 100644 CRM/Utils/Request.php create mode 100644 CRM/Utils/Rule.php create mode 100644 CRM/Utils/Signer.php create mode 100644 CRM/Utils/SoapServer.php create mode 100644 CRM/Utils/Sort.php create mode 100644 CRM/Utils/String.php create mode 100644 CRM/Utils/Sunlight.php create mode 100644 CRM/Utils/System.php create mode 100644 CRM/Utils/System/Base.php create mode 100644 CRM/Utils/System/Drupal.php create mode 100644 CRM/Utils/System/Drupal6.php create mode 100644 CRM/Utils/System/Joomla.php create mode 100644 CRM/Utils/System/Soap.php create mode 100644 CRM/Utils/System/UnitTests.php create mode 100644 CRM/Utils/System/WordPress.php create mode 100644 CRM/Utils/Time.php create mode 100644 CRM/Utils/Token.php create mode 100644 CRM/Utils/Tree.php create mode 100644 CRM/Utils/Type.php create mode 100644 CRM/Utils/Verp.php create mode 100644 CRM/Utils/VersionCheck.php create mode 100644 CRM/Utils/Weight.php create mode 100644 CRM/Utils/Wrapper.php create mode 100644 CRM/Utils/XML.php create mode 100644 CRM/Utils/Zip.php create mode 100644 CRM/Widget/Widget.php create mode 100644 README.txt create mode 100644 Sponsors.txt create mode 100644 agpl-3.0.exception.txt create mode 100644 agpl-3.0.txt create mode 100644 api/Exception.php create mode 100644 api/Wrapper.php create mode 100644 api/api.php create mode 100644 api/class.api.php create mode 100644 api/v2/Activity.php create mode 100644 api/v2/ActivityContact.php create mode 100644 api/v2/ActivityType.php create mode 100644 api/v2/Case.php create mode 100644 api/v2/Constant.php create mode 100644 api/v2/Contact.php create mode 100644 api/v2/Contribute.php create mode 100644 api/v2/Contribution.php create mode 100644 api/v2/CustomGroup.php create mode 100644 api/v2/Domain.php create mode 100644 api/v2/EntityTag.php create mode 100644 api/v2/Event.php create mode 100644 api/v2/File.php create mode 100644 api/v2/Group.php create mode 100644 api/v2/GroupContact.php create mode 100644 api/v2/GroupNesting.php create mode 100644 api/v2/GroupOrganization.php create mode 100644 api/v2/Location.php create mode 100644 api/v2/Mailer.php create mode 100644 api/v2/Membership.php create mode 100644 api/v2/MembershipContact.php create mode 100644 api/v2/MembershipContributionLink.php create mode 100644 api/v2/MembershipStatus.php create mode 100644 api/v2/MembershipType.php create mode 100644 api/v2/Note.php create mode 100644 api/v2/Participant.php create mode 100644 api/v2/ParticipantPayment.php create mode 100644 api/v2/Pledge.php create mode 100644 api/v2/PledgePayment.php create mode 100644 api/v2/Relationship.php create mode 100644 api/v2/RelationshipType.php create mode 100644 api/v2/SurveyRespondant.php create mode 100644 api/v2/Tag.php create mode 100644 api/v2/UFGroup.php create mode 100644 api/v2/UFJoin.php create mode 100644 api/v2/utils.php create mode 100644 api/v2/utils.v2.php create mode 100644 api/v3/Activity.php create mode 100644 api/v3/ActivityType.php create mode 100644 api/v3/Address.php create mode 100644 api/v3/Batch.php create mode 100644 api/v3/Campaign.php create mode 100644 api/v3/Case.php create mode 100644 api/v3/Constant.php create mode 100644 api/v3/Contact.php create mode 100644 api/v3/ContactType.php create mode 100644 api/v3/Contribution.php create mode 100644 api/v3/ContributionPage.php create mode 100644 api/v3/ContributionRecur.php create mode 100644 api/v3/CustomField.php create mode 100644 api/v3/CustomGroup.php create mode 100644 api/v3/CustomSearch.php create mode 100644 api/v3/CustomValue.php create mode 100644 api/v3/Domain.php create mode 100644 api/v3/Email.php create mode 100644 api/v3/Entity.php create mode 100644 api/v3/EntityTag.php create mode 100644 api/v3/Event.php create mode 100644 api/v3/Extension.php create mode 100644 api/v3/File.php create mode 100644 api/v3/Generic.php create mode 100644 api/v3/Generic/Getactions.php create mode 100644 api/v3/Generic/Setvalue.php create mode 100644 api/v3/Generic/Update.php create mode 100644 api/v3/Grant.php create mode 100644 api/v3/Group.php create mode 100644 api/v3/GroupContact.php create mode 100644 api/v3/GroupNesting.php create mode 100644 api/v3/GroupOrganization.php create mode 100644 api/v3/Im.php create mode 100644 api/v3/Job.php create mode 100644 api/v3/LineItem.php create mode 100644 api/v3/LocBlock.php create mode 100644 api/v3/Location.php create mode 100644 api/v3/LocationType.php create mode 100644 api/v3/MailSettings.php create mode 100644 api/v3/Mailing.php create mode 100644 api/v3/MailingEventConfirm.php create mode 100644 api/v3/MailingEventResubscribe.php create mode 100644 api/v3/MailingEventSubscribe.php create mode 100644 api/v3/MailingEventUnsubscribe.php create mode 100644 api/v3/MailingGroup.php create mode 100644 api/v3/MailingJob.php create mode 100644 api/v3/MailingRecipients.php create mode 100644 api/v3/Membership.php create mode 100644 api/v3/MembershipPayment.php create mode 100644 api/v3/MembershipStatus.php create mode 100644 api/v3/MembershipType.php create mode 100644 api/v3/Note.php create mode 100644 api/v3/OptionGroup.php create mode 100644 api/v3/OptionValue.php create mode 100644 api/v3/Participant.php create mode 100644 api/v3/ParticipantPayment.php create mode 100644 api/v3/ParticipantStatusType.php create mode 100644 api/v3/PaymentProcessorType.php create mode 100644 api/v3/Phone.php create mode 100644 api/v3/Phone/Get.php create mode 100644 api/v3/Pledge.php create mode 100644 api/v3/PledgePayment.php create mode 100644 api/v3/PriceField.php create mode 100644 api/v3/PriceFieldValue.php create mode 100644 api/v3/PriceSet.php create mode 100644 api/v3/Profile.php create mode 100644 api/v3/Relationship.php create mode 100644 api/v3/RelationshipType.php create mode 100644 api/v3/ReportTemplate.php create mode 100644 api/v3/Setting.php create mode 100644 api/v3/Survey.php create mode 100644 api/v3/SurveyRespondant.php create mode 100644 api/v3/System.php create mode 100644 api/v3/Tag.php create mode 100644 api/v3/UFField.php create mode 100644 api/v3/UFGroup.php create mode 100644 api/v3/UFJoin.php create mode 100644 api/v3/UFMatch.php create mode 100644 api/v3/Website.php create mode 100644 api/v3/examples/Activity/ContactRefCustomField.php create mode 100644 api/v3/examples/Activity/ContactRefCustomFieldGet.php create mode 100644 api/v3/examples/Activity/DateTimeHigh.php create mode 100644 api/v3/examples/Activity/DateTimeLow.php create mode 100644 api/v3/examples/Activity/GetTargetandAssignee.php create mode 100644 api/v3/examples/Activity/ReturnAssigneeContact.php create mode 100644 api/v3/examples/ActivityCreate.php create mode 100644 api/v3/examples/ActivityDelete.php create mode 100644 api/v3/examples/ActivityGet.php create mode 100644 api/v3/examples/ActivityGetFields.php create mode 100644 api/v3/examples/ActivityTypeCreate.php create mode 100644 api/v3/examples/ActivityTypeDelete.php create mode 100644 api/v3/examples/ActivityTypeGet.php create mode 100644 api/v3/examples/Address/AddressLike.php create mode 100644 api/v3/examples/Address/AddressParse.php create mode 100644 api/v3/examples/Address/AddressSort.php create mode 100644 api/v3/examples/AddressCreate.php create mode 100644 api/v3/examples/AddressDelete.php create mode 100644 api/v3/examples/AddressGet.php create mode 100644 api/v3/examples/BatchCreate.php create mode 100644 api/v3/examples/BatchDelete.php create mode 100644 api/v3/examples/BatchGet.php create mode 100644 api/v3/examples/BatchUpdate.php create mode 100644 api/v3/examples/CampaignCreate.php create mode 100644 api/v3/examples/CampaignDelete.php create mode 100644 api/v3/examples/CampaignGet.php create mode 100644 api/v3/examples/ConstantGet.php create mode 100644 api/v3/examples/Contact/APIChainedArray.php create mode 100644 api/v3/examples/Contact/APIChainedArrayFormats.php create mode 100644 api/v3/examples/Contact/APIChainedArrayMultipleCustom.php create mode 100644 api/v3/examples/Contact/APIChainedArrayValuesFromSiblingFunction.php create mode 100644 api/v3/examples/Contact/ChainTwoWebsites.php create mode 100644 api/v3/examples/Contact/ChainTwoWebsitesSyntax2.php create mode 100644 api/v3/examples/Contact/CustomFieldCreate.php create mode 100644 api/v3/examples/Contact/CustomFieldGet.php create mode 100644 api/v3/examples/Contact/CustomFieldGetReturnSyntaxVariation.php create mode 100644 api/v3/examples/Contact/FormatIsSuccess_Fail.php create mode 100644 api/v3/examples/Contact/FormatIsSuccess_True.php create mode 100644 api/v3/examples/Contact/FormatOnlyID.php create mode 100644 api/v3/examples/Contact/FormatSingleValue.php create mode 100644 api/v3/examples/Contact/GetCountContact.php create mode 100644 api/v3/examples/Contact/GetFieldsOptions.php create mode 100644 api/v3/examples/Contact/GetSingleContact.php create mode 100644 api/v3/examples/Contact/GroupFilterUsingContactAPI.php create mode 100644 api/v3/examples/ContactCreate.php create mode 100644 api/v3/examples/ContactDelete.php create mode 100644 api/v3/examples/ContactGet.php create mode 100644 api/v3/examples/ContactGetoptions.php create mode 100644 api/v3/examples/Contribution/ContributionCreateWithNote.php create mode 100644 api/v3/examples/Contribution/ContributionCreateWithSoftCredit.php create mode 100644 api/v3/examples/Contribution/CreateWithNestedLineItems.php create mode 100644 api/v3/examples/ContributionCreate.php create mode 100644 api/v3/examples/ContributionDelete.php create mode 100644 api/v3/examples/ContributionGet.php create mode 100644 api/v3/examples/ContributionPageCreate.php create mode 100644 api/v3/examples/ContributionPageDelete.php create mode 100644 api/v3/examples/ContributionPageGet.php create mode 100644 api/v3/examples/ContributionRecurCreate.php create mode 100644 api/v3/examples/ContributionRecurDelete.php create mode 100644 api/v3/examples/ContributionRecurGet.php create mode 100644 api/v3/examples/CustomFieldCreate.php create mode 100644 api/v3/examples/CustomFieldDelete.php create mode 100644 api/v3/examples/CustomGroupCreate.php create mode 100644 api/v3/examples/CustomGroupDelete.php create mode 100644 api/v3/examples/CustomGroupGet.php create mode 100644 api/v3/examples/CustomValue/formatFieldName.php create mode 100644 api/v3/examples/CustomValueCreate.php create mode 100644 api/v3/examples/CustomValueGet.php create mode 100644 api/v3/examples/DomainCreate.php create mode 100644 api/v3/examples/DomainGet.php create mode 100644 api/v3/examples/Email/NestedReplaceEmail.php create mode 100644 api/v3/examples/EmailCreate.php create mode 100644 api/v3/examples/EmailDelete.php create mode 100644 api/v3/examples/EmailReplace.php create mode 100644 api/v3/examples/EntityTagCreate.php create mode 100644 api/v3/examples/EntityTagDelete.php create mode 100644 api/v3/examples/EntityTagGet.php create mode 100644 api/v3/examples/Event/IsCurrentOption.php create mode 100644 api/v3/examples/Event/IsFullOption.php create mode 100644 api/v3/examples/EventCreate.php create mode 100644 api/v3/examples/EventDelete.php create mode 100644 api/v3/examples/EventGet.php create mode 100644 api/v3/examples/EventUpdate.php create mode 100644 api/v3/examples/GrantCreate.php create mode 100644 api/v3/examples/GrantDelete.php create mode 100644 api/v3/examples/GrantGet.php create mode 100644 api/v3/examples/Group/getfields.php create mode 100644 api/v3/examples/GroupContact.php create mode 100644 api/v3/examples/GroupContact/GetWithGroupID.php create mode 100644 api/v3/examples/GroupContactCreate.php create mode 100644 api/v3/examples/GroupContactDelete.php create mode 100644 api/v3/examples/GroupContactGet.php create mode 100644 api/v3/examples/GroupGet.php create mode 100644 api/v3/examples/GroupNestingCreate.php create mode 100644 api/v3/examples/GroupNestingDelete.php create mode 100644 api/v3/examples/GroupNestingGet.php create mode 100644 api/v3/examples/GroupOrganizationCreate.php create mode 100644 api/v3/examples/GroupOrganizationDelete.php create mode 100644 api/v3/examples/GroupOrganizationGet.php create mode 100644 api/v3/examples/ImCreate.php create mode 100644 api/v3/examples/ImDelete.php create mode 100644 api/v3/examples/ImGet.php create mode 100644 api/v3/examples/JobCreate.php create mode 100644 api/v3/examples/JobDelete.php create mode 100644 api/v3/examples/LineItemCreate.php create mode 100644 api/v3/examples/LineItemDelete.php create mode 100644 api/v3/examples/LineItemGet.php create mode 100644 api/v3/examples/LocBlockCreate.php create mode 100644 api/v3/examples/LocBlockCreateEntities.php create mode 100644 api/v3/examples/LocBlockGet.php create mode 100644 api/v3/examples/MailSettings/ChainedGetDelete.php create mode 100644 api/v3/examples/MailSettingsCreate.php create mode 100644 api/v3/examples/MailSettingsDelete.php create mode 100644 api/v3/examples/MailSettingsGet.php create mode 100644 api/v3/examples/MailingCreate.php create mode 100644 api/v3/examples/MailingGroupSubscribe.php create mode 100644 api/v3/examples/Membership/filterIsCurrent.php create mode 100644 api/v3/examples/MembershipCreate.php create mode 100644 api/v3/examples/MembershipDelete.php create mode 100644 api/v3/examples/MembershipGet.php create mode 100644 api/v3/examples/MembershipPaymentCreate.php create mode 100644 api/v3/examples/MembershipPaymentGet.php create mode 100644 api/v3/examples/MembershipStatusCreate.php create mode 100644 api/v3/examples/MembershipStatusGet.php create mode 100644 api/v3/examples/MembershipTypeCreate.php create mode 100644 api/v3/examples/MembershipTypeDelete.php create mode 100644 api/v3/examples/MembershipTypeGet.php create mode 100644 api/v3/examples/MembershipUpdate.php create mode 100644 api/v3/examples/NoteCreate.php create mode 100644 api/v3/examples/NoteDelete.php create mode 100644 api/v3/examples/NoteGet.php create mode 100644 api/v3/examples/OptionGroupCreate.php create mode 100644 api/v3/examples/OptionGroupGet.php create mode 100644 api/v3/examples/OptionValue/SortOption.php create mode 100644 api/v3/examples/OptionValueGet.php create mode 100644 api/v3/examples/Participant/CreateParticipantPayment.php create mode 100644 api/v3/examples/Participant/NestedDelete.php create mode 100644 api/v3/examples/Participant/NestedEventGet.php create mode 100644 api/v3/examples/ParticipantCreate.php create mode 100644 api/v3/examples/ParticipantGet.php create mode 100644 api/v3/examples/ParticipantPaymentCreate.php create mode 100644 api/v3/examples/ParticipantPaymentDelete.php create mode 100644 api/v3/examples/ParticipantPaymentGet.php create mode 100644 api/v3/examples/ParticipantStatusTypeCreate.php create mode 100644 api/v3/examples/ParticipantStatusTypeDelete.php create mode 100644 api/v3/examples/ParticipantStatusTypeGet.php create mode 100644 api/v3/examples/PaymentProcessorTypeCreate.php create mode 100644 api/v3/examples/PaymentProcessorTypeDelete.php create mode 100644 api/v3/examples/PhoneCreate.php create mode 100644 api/v3/examples/PhoneDelete.php create mode 100644 api/v3/examples/PhoneGet.php create mode 100644 api/v3/examples/Pledge/GetFilterHighDate.php create mode 100644 api/v3/examples/PledgeCreate.php create mode 100644 api/v3/examples/PledgeDelete.php create mode 100644 api/v3/examples/PledgeGet.php create mode 100644 api/v3/examples/PledgePaymentCreate.php create mode 100644 api/v3/examples/PledgePaymentDelete.php create mode 100644 api/v3/examples/PledgePaymentGet.php create mode 100644 api/v3/examples/PledgePaymentUpdate.php create mode 100644 api/v3/examples/PriceFieldCreate.php create mode 100644 api/v3/examples/PriceFieldDelete.php create mode 100644 api/v3/examples/PriceFieldGet.php create mode 100644 api/v3/examples/PriceFieldValueCreate.php create mode 100644 api/v3/examples/PriceFieldValueDelete.php create mode 100644 api/v3/examples/PriceFieldValueGet.php create mode 100644 api/v3/examples/PriceSetCreate.php create mode 100644 api/v3/examples/PriceSetDelete.php create mode 100644 api/v3/examples/PriceSetGet.php create mode 100644 api/v3/examples/PriceSetSet.php create mode 100644 api/v3/examples/ProfileApply.php create mode 100644 api/v3/examples/ProfileGet.php create mode 100644 api/v3/examples/ProfileSet.php create mode 100644 api/v3/examples/Relationship/BetweenRelationshipType.php create mode 100644 api/v3/examples/Relationship/INRelationshipType.php create mode 100644 api/v3/examples/Relationship/NotBetweenRelationshipType.php create mode 100644 api/v3/examples/Relationship/NotInRelationshipType.php create mode 100644 api/v3/examples/Relationship/filterIsCurrent.php create mode 100644 api/v3/examples/RelationshipCreate.php create mode 100644 api/v3/examples/RelationshipDelete.php create mode 100644 api/v3/examples/RelationshipGet.php create mode 100644 api/v3/examples/RelationshipTypeCreate.php create mode 100644 api/v3/examples/RelationshipTypeDelete.php create mode 100644 api/v3/examples/Setting/CreateAllDomains.php create mode 100644 api/v3/examples/Setting/CreateSettingCurrentDomain.php create mode 100644 api/v3/examples/Setting/CreateSpecifiedDomains.php create mode 100644 api/v3/examples/Setting/GetAllDomains.php create mode 100644 api/v3/examples/Setting/GetDefaults.php create mode 100644 api/v3/examples/Setting/GetSettingCurrentDomain.php create mode 100644 api/v3/examples/Setting/GetSpecifiedDomains.php create mode 100644 api/v3/examples/SettingCreate.php create mode 100644 api/v3/examples/SettingGet.php create mode 100644 api/v3/examples/SettingGetValue.php create mode 100644 api/v3/examples/SettingGetfields.php create mode 100644 api/v3/examples/SettingRevert.php create mode 100644 api/v3/examples/Survey/ChainedGetDelete.php create mode 100644 api/v3/examples/SurveyCreate.php create mode 100644 api/v3/examples/SurveyDelete.php create mode 100644 api/v3/examples/SurveyGet.php create mode 100644 api/v3/examples/SurveyRespondantGet.php create mode 100644 api/v3/examples/System/Flush.php create mode 100644 api/v3/examples/Tag/getReturnArray.php create mode 100644 api/v3/examples/TagCreate.php create mode 100644 api/v3/examples/TagDelete.php create mode 100644 api/v3/examples/TagGet.php create mode 100644 api/v3/examples/UFFieldCreate.php create mode 100644 api/v3/examples/UFFieldDelete.php create mode 100644 api/v3/examples/UFFieldGet.php create mode 100644 api/v3/examples/UFFieldReplace.php create mode 100644 api/v3/examples/UFGroupCreate.php create mode 100644 api/v3/examples/UFGroupDelete.php create mode 100644 api/v3/examples/UFGroupGet.php create mode 100644 api/v3/examples/UFJoinCreate.php create mode 100644 api/v3/examples/UFJoinGet.php create mode 100644 api/v3/examples/UFMatchGet.php create mode 100644 api/v3/examples/WebsiteCreate.php create mode 100644 api/v3/examples/WebsiteDelete.php create mode 100644 api/v3/examples/WebsiteGet.php create mode 100644 api/v3/utils.php create mode 100644 bin/ContributionProcessor.php create mode 100644 bin/cleanup42.php create mode 100644 bin/cli.class.php create mode 100644 bin/cli.php create mode 100644 bin/cron.php create mode 100644 bin/csv/delete.php create mode 100644 bin/csv/export.php create mode 100644 bin/csv/import.php create mode 100644 bin/deprecated/CiviReportMail.php create mode 100644 bin/deprecated/EmailProcessor.php create mode 100644 bin/deprecated/ParticipantProcessor.php create mode 100644 bin/deprecated/RespondentProcessor.php create mode 100644 bin/deprecated/UpdateAddress.php create mode 100644 bin/deprecated/UpdateGreeting.php create mode 100644 bin/deprecated/UpdateMembershipRecord.php create mode 100644 bin/deprecated/UpdateMembershipReminderDate.php create mode 100644 bin/deprecated/UpdatePledgeRecord.php create mode 100644 bin/deprecated/action.cronjob.php create mode 100644 bin/deprecated/civimail.cronjob.php create mode 100644 bin/encryptDB.php create mode 100644 bin/migrate/export.php create mode 100644 bin/migrate/exportJSON.php create mode 100644 bin/migrate/import.php create mode 100644 bin/migrate/importJSON.php create mode 100644 bin/migrate/move.php create mode 100755 bin/regen.sh create mode 100755 bin/regen.sh.txt create mode 100644 bin/setup.conf.txt create mode 100755 bin/setup.sh create mode 100755 bin/setup.sh.txt create mode 100644 css/Audit/style.css create mode 100644 css/arrow.png create mode 100644 css/bg_button_a.gif create mode 100644 css/bg_button_span.gif create mode 100644 css/bluemarine.css create mode 100644 css/civicrm-new.css create mode 100644 css/civicrm.css create mode 100644 css/crm.designer.css create mode 100644 css/drupal.css create mode 100644 css/extras.css create mode 100644 css/joomla.css create mode 100644 css/joomla_frontend.css create mode 100644 css/menu-collapsed.png create mode 100644 css/menu-expanded.png create mode 100644 css/menu-leaf.png create mode 100644 css/print.css create mode 100644 distmaker/distmaker.conf.dist create mode 100755 distmaker/distmaker.sh create mode 100755 distmaker/dists/drupal6_php5.sh create mode 100755 distmaker/dists/drupal_php5.sh create mode 100755 distmaker/dists/drupal_sk_php5.sh create mode 100755 distmaker/dists/joomla_php5.sh create mode 100644 distmaker/dists/l10n.sh create mode 100644 distmaker/dists/wordpress_php5.sh create mode 100644 distmaker/utils/joomlaxml.php create mode 100644 extern/authorizeIPN.php create mode 100644 extern/googleNotify.php create mode 100644 extern/ipn.php create mode 100644 extern/open.php create mode 100644 extern/pxIPN.php create mode 100644 extern/rest.php create mode 100644 extern/soap.php create mode 100644 extern/url.php create mode 100644 extern/widget.php create mode 100644 gpl.txt create mode 100644 header-afl.txt create mode 100644 header-agpl.txt create mode 100644 header.sql create mode 100644 header.tpl create mode 100644 header.txt create mode 100644 i/BarGraph.png create mode 100644 i/Bulb.png create mode 100644 i/EnvelopeIn.gif create mode 100644 i/Error.gif create mode 100644 i/Eyeball.gif create mode 100644 i/Inform.gif create mode 100644 i/TreeMinus.gif create mode 100644 i/TreeMinusWhite.gif create mode 100644 i/TreePlus.gif create mode 100644 i/TreePlusWhite.gif create mode 100644 i/admin/01.png create mode 100644 i/admin/02.png create mode 100644 i/admin/03.png create mode 100644 i/admin/04.png create mode 100644 i/admin/05.png create mode 100644 i/admin/06.png create mode 100644 i/admin/07.png create mode 100644 i/admin/08.png create mode 100644 i/admin/09.png create mode 100644 i/admin/10.png create mode 100644 i/admin/11.png create mode 100644 i/admin/12.png create mode 100644 i/admin/13.png create mode 100644 i/admin/14.png create mode 100644 i/admin/36.png create mode 100644 i/admin/DataStore.gif create mode 100644 i/admin/PayPal_mark_37x23.gif create mode 100644 i/admin/Premiums.png create mode 100644 i/admin/Profile.png create mode 100644 i/admin/Synch_user.png create mode 100644 i/admin/accepted_creditcards.png create mode 100644 i/admin/communication.png create mode 100644 i/admin/contribution_types.png create mode 100644 i/admin/custm_data.png create mode 100644 i/admin/domain.png create mode 100644 i/admin/duplicate_matching.png create mode 100644 i/admin/event_manage.png create mode 100644 i/admin/event_type.png create mode 100644 i/admin/import_export_map.png create mode 100644 i/admin/membership_status.png create mode 100644 i/admin/membership_type.png create mode 100644 i/admin/online_contribution_pages.png create mode 100644 i/admin/option.png create mode 100644 i/admin/parti_role.png create mode 100644 i/admin/parti_status.png create mode 100644 i/admin/payment_instruments.png create mode 100644 i/admin/price_sets.png create mode 100644 i/admin/rela_type.png create mode 100644 i/admin/small/01.png create mode 100644 i/admin/small/02.png create mode 100644 i/admin/small/03.png create mode 100644 i/admin/small/04.png create mode 100644 i/admin/small/05.png create mode 100644 i/admin/small/06.png create mode 100644 i/admin/small/07.png create mode 100644 i/admin/small/08.png create mode 100644 i/admin/small/09.png create mode 100644 i/admin/small/10.png create mode 100644 i/admin/small/11.png create mode 100644 i/admin/small/12.png create mode 100644 i/admin/small/13.png create mode 100644 i/admin/small/36.png create mode 100644 i/admin/small/Premiums.png create mode 100644 i/admin/small/Profile.png create mode 100644 i/admin/small/Synch_user.png create mode 100644 i/admin/small/accepted_creditcards.png create mode 100644 i/admin/small/case_type.gif create mode 100644 i/admin/small/case_type.png create mode 100644 i/admin/small/communication.png create mode 100644 i/admin/small/contribution_types.png create mode 100644 i/admin/small/custm_data.png create mode 100644 i/admin/small/domain.png create mode 100644 i/admin/small/duplicate_matching.png create mode 100644 i/admin/small/event_manage.png create mode 100644 i/admin/small/event_type.png create mode 100644 i/admin/small/grant_type.png create mode 100644 i/admin/small/import_export_map.png create mode 100644 i/admin/small/membership_status.png create mode 100644 i/admin/small/membership_type.png create mode 100644 i/admin/small/online_contribution_pages.png create mode 100644 i/admin/small/option.png create mode 100644 i/admin/small/parti_role.png create mode 100644 i/admin/small/parti_status.png create mode 100644 i/admin/small/payment_instruments.png create mode 100644 i/admin/small/price_sets.png create mode 100644 i/admin/small/redaction_type.png create mode 100644 i/admin/small/rela_type.png create mode 100644 i/admin/small/report_list.gif create mode 100644 i/admin/small/report_template.gif create mode 100644 i/admin/small/template.png create mode 100644 i/admin/small/title.png create mode 100644 i/admin/small/updatepath.png create mode 100644 i/admin/template.png create mode 100644 i/admin/title.png create mode 100644 i/applications-internet.png create mode 100644 i/arrow.gif create mode 100644 i/arrow/down.gif create mode 100644 i/arrow/first.gif create mode 100644 i/arrow/last.gif create mode 100644 i/arrow/spacer.gif create mode 100644 i/arrow/up.gif create mode 100644 i/binocular.gif create mode 100644 i/block_small.png create mode 100644 i/cal.gif create mode 100644 i/check.gif create mode 100644 i/close.png create mode 100644 i/collapsable.gif create mode 100644 i/contact_all.ico create mode 100644 i/contact_house.png create mode 100644 i/contact_ind.gif create mode 100644 i/contact_ind_medium.gif create mode 100644 i/contact_org.gif create mode 100644 i/contribute/default_premium.jpg create mode 100644 i/contribute/default_premium_thumb.jpg create mode 100644 i/contribute/incomplete.gif create mode 100644 i/contribute/pcp_achieve.gif create mode 100644 i/contribute/pcp_remain.gif create mode 100644 i/contribute/premium_sample_mug.jpg create mode 100644 i/contribute/premium_sample_mug_thumb.jpg create mode 100644 i/copy.png create mode 100644 i/crm-button-bg.gif create mode 100644 i/crm-button-black.gif create mode 100644 i/crm-button-blue.gif create mode 100644 i/crm-button-dark-blue.gif create mode 100644 i/crm-button-dark.gif create mode 100644 i/crm-button.gif create mode 100644 i/custom_activity.gif create mode 100644 i/dataTable/sort_sprites.acorn create mode 100644 i/dataTable/sort_sprites.png create mode 100644 i/delete.png create mode 100644 i/draggable.png create mode 100644 i/dropdown-pointer.gif create mode 100644 i/edit.png create mode 100644 i/expandable.gif create mode 100644 i/fblike.png create mode 100644 i/fbshare.png create mode 100644 i/feed-icon.png create mode 100644 i/geotag_16.png create mode 100644 i/grippie.png create mode 100644 i/group.png create mode 100644 i/ical_feed.gif create mode 100644 i/icons/jquery-ui-2786C2.png create mode 100644 i/icons/jquery-ui-3E3E3E.png create mode 100644 i/icons/jquery-ui-52534D.png create mode 100644 i/icons/jquery-ui-8A1F11.png create mode 100644 i/icons/jquery-ui-91CE00.png create mode 100644 i/icons/jquery-ui-F5F6F1.png create mode 100644 i/icons/jquery-ui-FFFFFF.png create mode 100644 i/icons/jquery-ui-b0d730.png create mode 100644 i/item_sprites.png create mode 100644 i/langs.png create mode 100644 i/loading-2f2f2e.gif create mode 100644 i/loading-E6E6DC.gif create mode 100644 i/loading.gif create mode 100644 i/logo16px.png create mode 100644 i/logo_words_small.png create mode 100644 i/magnify.gif create mode 100644 i/meeting.gif create mode 100644 i/menu-collapsed.png create mode 100644 i/menu-expanded.png create mode 100644 i/message-icons.png create mode 100644 i/mini_cvv2.gif create mode 100644 i/notes.png create mode 100644 i/office-calendar.png create mode 100644 i/openid-icon-small.gif create mode 100644 i/overlay-pointer.png create mode 100644 i/popupMenuBg.gif create mode 100644 i/powered_by.png create mode 100644 i/print-icon.png create mode 100644 i/print_pdf.gif create mode 100644 i/quiz.png create mode 100644 i/rss2.png create mode 100644 i/smallLogo.png create mode 100644 i/spacer.gif create mode 100644 i/stop-icon.png create mode 100644 i/tel.gif create mode 100644 i/tracker.gif create mode 100644 i/traffic_green.gif create mode 100644 i/traffic_red.gif create mode 100644 i/tweet.png create mode 100644 i/vcard-icon.png create mode 100644 i/widget/favicon.png create mode 100644 i/widget/logo.png create mode 100644 install/block_small.png create mode 100644 install/civicrm.php create mode 100644 install/error.html create mode 100644 install/index.php create mode 100644 install/network-save.gif create mode 100644 install/template.css create mode 100644 install/template.html create mode 100644 js/Audit/audit.js create mode 100644 js/Common.js create mode 100644 js/crm.backbone.js create mode 100644 js/crm.designerapp.js create mode 100644 js/jquery.conflict.js create mode 100644 js/jquery/jquery.crmProfileSelector.js create mode 100644 js/jquery/jquery.crmasmselect.js create mode 100644 js/jquery/jquery.crmeditable.js create mode 100644 js/jquery/jquery.crmtemplate.js create mode 100644 js/model/crm.designer.js create mode 100644 js/model/crm.profile-selector.js create mode 100644 js/model/crm.schema-mapped.js create mode 100644 js/model/crm.schema.js create mode 100644 js/model/crm.uf.js create mode 100644 js/rest.js create mode 100644 js/view/crm.designer.js create mode 100644 js/view/crm.profile-selector.js create mode 100644 settings/Address.setting.php create mode 100644 settings/Campaign.setting.php create mode 100644 settings/Contribute.setting.php create mode 100644 settings/Core.setting.php create mode 100644 settings/Developer.setting.php create mode 100644 settings/Directory.setting.php create mode 100644 settings/Event.setting.php create mode 100644 settings/Localization.setting.php create mode 100644 settings/Mailing.setting.php create mode 100644 settings/Member.setting.php create mode 100644 settings/Multisite.setting.php create mode 100644 settings/Search.setting.php create mode 100644 settings/Url.setting.php create mode 100644 sql/GenerateData.README create mode 100644 sql/GenerateData.php create mode 100644 sql/GenerateGroups.php create mode 100644 sql/GenerateMailing.php create mode 100644 sql/GenerateReportData.php create mode 100644 sql/README.txt create mode 100644 sql/case_sample.mysql create mode 100644 sql/case_sample1.mysql create mode 100644 sql/civicrm_arms_sample_data.sql create mode 100644 sql/civicrm_case_sql.mysql create mode 100644 sql/civicrm_demo_processor.mysql create mode 100644 sql/civicrm_devel_config.mysql create mode 100644 sql/civicrm_generated.mysql create mode 100644 sql/civicrm_generated_report.mysql create mode 100644 sql/civicrm_queue_item.mysql create mode 100644 sql/civicrm_sample_custom_data.mysql create mode 100644 sql/civicrm_upgradedb_v1.1_v1.2_40.mysql create mode 100644 sql/civicrm_upgradedb_v1.1_v1.2_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.2_v1.3_40.mysql create mode 100644 sql/civicrm_upgradedb_v1.2_v1.3_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.3_v1.4_40.mysql create mode 100644 sql/civicrm_upgradedb_v1.3_v1.4_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.4_v1.5_40.mysql create mode 100644 sql/civicrm_upgradedb_v1.4_v1.5_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.5_v1.6_40.mysql create mode 100644 sql/civicrm_upgradedb_v1.5_v1.6_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.6_v1.7_40.mysql create mode 100644 sql/civicrm_upgradedb_v1.6_v1.7_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.7_v1.8_41.mysql create mode 100644 sql/civicrm_upgradedb_v1.8_v1.9_41.mysql create mode 100644 sql/counties.US.sql.gz create mode 100644 sql/sample_data.xml create mode 100644 sql/sample_data_pl.xml create mode 100644 sql/test_data.mysql create mode 100644 sql/test_data_second_domain.mysql create mode 100644 sql/trigger.mysql create mode 100644 sql/upgrade_pcm.mysql create mode 100644 sql/webtest_data.mysql create mode 100644 sql/zipcodes.mysql create mode 100644 templates/CRM/ACL/Form/ACL.tpl create mode 100644 templates/CRM/ACL/Form/ACLBasic.tpl create mode 100644 templates/CRM/ACL/Form/EntityRole.tpl create mode 100644 templates/CRM/ACL/Form/WordPress/Permissions.tpl create mode 100644 templates/CRM/ACL/Page/ACL.tpl create mode 100644 templates/CRM/ACL/Page/ACLBasic.tpl create mode 100644 templates/CRM/ACL/Page/EntityRole.tpl create mode 100644 templates/CRM/Activity/Calendar/ICal.tpl create mode 100644 templates/CRM/Activity/Form/Activity.tpl create mode 100644 templates/CRM/Activity/Form/ActivityLinks.tpl create mode 100644 templates/CRM/Activity/Form/ActivityView.tpl create mode 100644 templates/CRM/Activity/Form/Search.tpl create mode 100644 templates/CRM/Activity/Form/Search/Common.tpl create mode 100644 templates/CRM/Activity/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Activity/Form/Selector.tpl create mode 100755 templates/CRM/Activity/Form/Task.tpl create mode 100755 templates/CRM/Activity/Form/Task/Batch.tpl create mode 100755 templates/CRM/Activity/Form/Task/Delete.tpl create mode 100644 templates/CRM/Activity/Form/Task/Email.tpl create mode 100644 templates/CRM/Activity/Form/Task/FileOnCase.tpl create mode 100644 templates/CRM/Activity/Form/Task/PickOption.tpl create mode 100755 templates/CRM/Activity/Form/Task/PickProfile.tpl create mode 100644 templates/CRM/Activity/Form/Task/Print.tpl create mode 100644 templates/CRM/Activity/Form/Task/SMS.tpl create mode 100644 templates/CRM/Activity/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Activity/Import/Form/MapField.tpl create mode 100644 templates/CRM/Activity/Import/Form/MapTable.tpl create mode 100644 templates/CRM/Activity/Import/Form/Preview.tpl create mode 100644 templates/CRM/Activity/Import/Form/Summary.tpl create mode 100644 templates/CRM/Activity/Import/Form/UploadFile.hlp create mode 100644 templates/CRM/Activity/Import/Form/UploadFile.tpl create mode 100644 templates/CRM/Activity/Page/Tab.tpl create mode 100644 templates/CRM/Activity/Page/UserDashboard.tpl create mode 100644 templates/CRM/Activity/Selector/Activity.tpl create mode 100644 templates/CRM/Activity/Selector/Selector.tpl create mode 100644 templates/CRM/Admin/Form/ActivityType.tpl create mode 100644 templates/CRM/Admin/Form/CMSUser.tpl create mode 100644 templates/CRM/Admin/Form/ContactType.tpl create mode 100644 templates/CRM/Admin/Form/DomainDump.tpl create mode 100644 templates/CRM/Admin/Form/Extensions.tpl create mode 100644 templates/CRM/Admin/Form/Job.tpl create mode 100644 templates/CRM/Admin/Form/LabelFormats.tpl create mode 100644 templates/CRM/Admin/Form/LocationType.tpl create mode 100644 templates/CRM/Admin/Form/MailSettings.tpl create mode 100644 templates/CRM/Admin/Form/Mapping.tpl create mode 100644 templates/CRM/Admin/Form/MessageTemplates.tpl create mode 100644 templates/CRM/Admin/Form/Navigation.hlp create mode 100644 templates/CRM/Admin/Form/Navigation.tpl create mode 100644 templates/CRM/Admin/Form/OptionGroup.tpl create mode 100644 templates/CRM/Admin/Form/OptionValue.tpl create mode 100644 templates/CRM/Admin/Form/Options.tpl create mode 100644 templates/CRM/Admin/Form/ParticipantStatus.tpl create mode 100644 templates/CRM/Admin/Form/PaymentProcessor.tpl create mode 100644 templates/CRM/Admin/Form/PaymentProcessorType.tpl create mode 100644 templates/CRM/Admin/Form/PdfFormats.tpl create mode 100644 templates/CRM/Admin/Form/Persistent.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Address.hlp create mode 100644 templates/CRM/Admin/Form/Preferences/Address.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Campaign.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Display.hlp create mode 100644 templates/CRM/Admin/Form/Preferences/Display.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Event.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Mailing.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Member.tpl create mode 100644 templates/CRM/Admin/Form/Preferences/Multisite.tpl create mode 100644 templates/CRM/Admin/Form/PreferencesDate.tpl create mode 100644 templates/CRM/Admin/Form/RelationshipType.tpl create mode 100644 templates/CRM/Admin/Form/ScheduleReminders.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Component.hlp create mode 100644 templates/CRM/Admin/Form/Setting/Component.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Date.hlp create mode 100644 templates/CRM/Admin/Form/Setting/Date.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Debugging.hlp create mode 100644 templates/CRM/Admin/Form/Setting/Debugging.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Event.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Localization.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Mail.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Mapping.hlp create mode 100644 templates/CRM/Admin/Form/Setting/Mapping.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Miscellaneous.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Path.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Search.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Smtp.tpl create mode 100644 templates/CRM/Admin/Form/Setting/UF.tpl create mode 100644 templates/CRM/Admin/Form/Setting/UpdateConfigBackend.tpl create mode 100644 templates/CRM/Admin/Form/Setting/Url.hlp create mode 100644 templates/CRM/Admin/Form/Setting/Url.tpl create mode 100644 templates/CRM/Admin/Form/Tag.tpl create mode 100644 templates/CRM/Admin/Form/WordReplacements.hlp create mode 100644 templates/CRM/Admin/Form/WordReplacements.tpl create mode 100644 templates/CRM/Admin/Page/Access.tpl create mode 100644 templates/CRM/Admin/Page/Admin.tpl create mode 100644 templates/CRM/Admin/Page/CMSUser.tpl create mode 100644 templates/CRM/Admin/Page/ConfigTaskList.tpl create mode 100644 templates/CRM/Admin/Page/ContactType.hlp create mode 100644 templates/CRM/Admin/Page/ContactType.tpl create mode 100644 templates/CRM/Admin/Page/DomainDump.tpl create mode 100644 templates/CRM/Admin/Page/EventTemplate.tpl create mode 100644 templates/CRM/Admin/Page/ExtensionDetails.tpl create mode 100644 templates/CRM/Admin/Page/Extensions.tpl create mode 100644 templates/CRM/Admin/Page/Extensions/About.tpl create mode 100644 templates/CRM/Admin/Page/Extensions/AddNew.tpl create mode 100644 templates/CRM/Admin/Page/Extensions/AddNewReq.tpl create mode 100644 templates/CRM/Admin/Page/Extensions/Main.tpl create mode 100644 templates/CRM/Admin/Page/Extensions/Refresh.tpl create mode 100644 templates/CRM/Admin/Page/Job.tpl create mode 100644 templates/CRM/Admin/Page/JobLog.tpl create mode 100644 templates/CRM/Admin/Page/LabelFormats.tpl create mode 100644 templates/CRM/Admin/Page/LocationType.tpl create mode 100644 templates/CRM/Admin/Page/MailSettings.tpl create mode 100644 templates/CRM/Admin/Page/Mapping.tpl create mode 100644 templates/CRM/Admin/Page/MessageTemplates.hlp create mode 100644 templates/CRM/Admin/Page/MessageTemplates.tpl create mode 100644 templates/CRM/Admin/Page/Navigation.hlp create mode 100644 templates/CRM/Admin/Page/Navigation.tpl create mode 100644 templates/CRM/Admin/Page/OptionGroup.tpl create mode 100644 templates/CRM/Admin/Page/OptionValue.tpl create mode 100644 templates/CRM/Admin/Page/Options.hlp create mode 100644 templates/CRM/Admin/Page/Options.tpl create mode 100644 templates/CRM/Admin/Page/ParticipantStatus.hlp create mode 100644 templates/CRM/Admin/Page/ParticipantStatus.tpl create mode 100644 templates/CRM/Admin/Page/PaymentProcessor.hlp create mode 100644 templates/CRM/Admin/Page/PaymentProcessor.tpl create mode 100644 templates/CRM/Admin/Page/PaymentProcessorType.tpl create mode 100644 templates/CRM/Admin/Page/PdfFormats.tpl create mode 100644 templates/CRM/Admin/Page/Persistent.tpl create mode 100644 templates/CRM/Admin/Page/PreferencesDate.tpl create mode 100644 templates/CRM/Admin/Page/RelationshipType.hlp create mode 100644 templates/CRM/Admin/Page/RelationshipType.tpl create mode 100755 templates/CRM/Admin/Page/Reminders.tpl create mode 100644 templates/CRM/Admin/Page/ScheduleReminders.tpl create mode 100644 templates/CRM/Admin/Page/Setting.tpl create mode 100644 templates/CRM/Admin/Page/Tag.tpl create mode 100644 templates/CRM/Batch/Form/Batch.tpl create mode 100644 templates/CRM/Batch/Form/Entry.tpl create mode 100644 templates/CRM/Batch/Form/Search.tpl create mode 100644 templates/CRM/Batch/Page/Batch.tpl create mode 100644 templates/CRM/Block/Add.tpl create mode 100644 templates/CRM/Block/CreateNew.tpl create mode 100644 templates/CRM/Block/Dashboard.tpl create mode 100644 templates/CRM/Block/Event.tpl create mode 100644 templates/CRM/Block/FullTextSearch.tpl create mode 100644 templates/CRM/Block/Gcc.tpl create mode 100644 templates/CRM/Block/LangSwitch.tpl create mode 100644 templates/CRM/Block/Mail.tpl create mode 100644 templates/CRM/Block/RecentlyViewed.tpl create mode 100644 templates/CRM/Block/Subject.tpl create mode 100644 templates/CRM/Block/blocks.tpl create mode 100644 templates/CRM/Campaign/Form/Campaign.tpl create mode 100755 templates/CRM/Campaign/Form/Gotv.tpl create mode 100644 templates/CRM/Campaign/Form/Petition.tpl create mode 100644 templates/CRM/Campaign/Form/Petition/Block.tpl create mode 100644 templates/CRM/Campaign/Form/Petition/Signature.tpl create mode 100644 templates/CRM/Campaign/Form/ResultOptions.tpl create mode 100755 templates/CRM/Campaign/Form/Search.tpl create mode 100755 templates/CRM/Campaign/Form/Search/Campaign.tpl create mode 100755 templates/CRM/Campaign/Form/Search/Common.tpl create mode 100755 templates/CRM/Campaign/Form/Search/EmptyResults.tpl create mode 100755 templates/CRM/Campaign/Form/Search/Petition.tpl create mode 100755 templates/CRM/Campaign/Form/Search/Survey.tpl create mode 100755 templates/CRM/Campaign/Form/Selector.tpl create mode 100644 templates/CRM/Campaign/Form/Survey/Delete.tpl create mode 100644 templates/CRM/Campaign/Form/Survey/Main.tpl create mode 100644 templates/CRM/Campaign/Form/Survey/Questions.tpl create mode 100644 templates/CRM/Campaign/Form/Survey/Results.tpl create mode 100644 templates/CRM/Campaign/Form/Survey/Tab.tpl create mode 100644 templates/CRM/Campaign/Form/SurveyType.tpl create mode 100644 templates/CRM/Campaign/Form/Task/Interview.tpl create mode 100755 templates/CRM/Campaign/Form/Task/Print.tpl create mode 100644 templates/CRM/Campaign/Form/Task/Release.tpl create mode 100755 templates/CRM/Campaign/Form/Task/Reserve.tpl create mode 100755 templates/CRM/Campaign/Form/Task/Result.tpl create mode 100644 templates/CRM/Campaign/Form/addCampaignToComponent.hlp create mode 100644 templates/CRM/Campaign/Form/addCampaignToComponent.tpl create mode 100644 templates/CRM/Campaign/Page/Campaign.tpl create mode 100644 templates/CRM/Campaign/Page/DashBoard.tpl create mode 100644 templates/CRM/Campaign/Page/Petition.tpl create mode 100644 templates/CRM/Campaign/Page/Petition/Confirm.tpl create mode 100644 templates/CRM/Campaign/Page/Petition/SocialNetwork.drupal create mode 100644 templates/CRM/Campaign/Page/Petition/SocialNetwork.tpl create mode 100644 templates/CRM/Campaign/Page/Petition/ThankYou.tpl create mode 100644 templates/CRM/Campaign/Page/Survey.tpl create mode 100644 templates/CRM/Campaign/Page/SurveyType.tpl create mode 100644 templates/CRM/Campaign/Page/Vote.tpl create mode 100644 templates/CRM/Case/Audit/Audit.tpl create mode 100644 templates/CRM/Case/Audit/Report.tpl create mode 100644 templates/CRM/Case/Form/Activity.tpl create mode 100644 templates/CRM/Case/Form/Activity/ChangeCaseStartDate.tpl create mode 100644 templates/CRM/Case/Form/Activity/ChangeCaseStatus.tpl create mode 100644 templates/CRM/Case/Form/Activity/ChangeCaseType.tpl create mode 100644 templates/CRM/Case/Form/Activity/LinkCases.tpl create mode 100644 templates/CRM/Case/Form/Activity/OpenCase.tpl create mode 100644 templates/CRM/Case/Form/ActivityChangeStatus.tpl create mode 100644 templates/CRM/Case/Form/ActivityToCase.tpl create mode 100644 templates/CRM/Case/Form/ActivityView.tpl create mode 100644 templates/CRM/Case/Form/Case.hlp create mode 100644 templates/CRM/Case/Form/Case.tpl create mode 100644 templates/CRM/Case/Form/CaseView.tpl create mode 100644 templates/CRM/Case/Form/CustomData.tpl create mode 100644 templates/CRM/Case/Form/EditClient.tpl create mode 100644 templates/CRM/Case/Form/Report.tpl create mode 100644 templates/CRM/Case/Form/Search.tpl create mode 100644 templates/CRM/Case/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Case/Form/Search/Common.tpl create mode 100644 templates/CRM/Case/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Case/Form/Selector.tpl create mode 100644 templates/CRM/Case/Form/Task.tpl create mode 100644 templates/CRM/Case/Form/Task/Delete.tpl create mode 100644 templates/CRM/Case/Form/Task/Print.tpl create mode 100644 templates/CRM/Case/Form/Task/Restore.tpl create mode 100644 templates/CRM/Case/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Case/Page/CaseDetails.tpl create mode 100644 templates/CRM/Case/Page/ConfigureError.tpl create mode 100644 templates/CRM/Case/Page/CustomDataView.tpl create mode 100644 templates/CRM/Case/Page/DashBoard.tpl create mode 100644 templates/CRM/Case/Page/DashboardSelector.tpl create mode 100644 templates/CRM/Case/Page/Tab.tpl create mode 100644 templates/CRM/Case/XMLProcessor/Report.tpl create mode 100644 templates/CRM/Contact/Form/Contact.hlp create mode 100644 templates/CRM/Contact/Form/Contact.tpl create mode 100644 templates/CRM/Contact/Form/CurrentEmployer.tpl create mode 100644 templates/CRM/Contact/Form/CustomData.tpl create mode 100644 templates/CRM/Contact/Form/DedupeFind.tpl create mode 100644 templates/CRM/Contact/Form/DedupeRules.tpl create mode 100644 templates/CRM/Contact/Form/Domain.hlp create mode 100644 templates/CRM/Contact/Form/Domain.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/CustomData.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/CustomField.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/address_name.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/city_postal_code.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/country_state_province.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/county.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/geo_code.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/street_address.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/supplemental_address_1.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Address/supplemental_address_2.tpl create mode 100644 templates/CRM/Contact/Form/Edit/CommunicationPreferences.tpl create mode 100644 templates/CRM/Contact/Form/Edit/CustomData.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Demographics.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Email.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Household.tpl create mode 100644 templates/CRM/Contact/Form/Edit/IM.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Individual.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Lock.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Notes.tpl create mode 100644 templates/CRM/Contact/Form/Edit/OpenID.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Organization.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Phone.tpl create mode 100644 templates/CRM/Contact/Form/Edit/TagsAndGroups.tpl create mode 100644 templates/CRM/Contact/Form/Edit/Website.tpl create mode 100644 templates/CRM/Contact/Form/GroupContact.tpl create mode 100644 templates/CRM/Contact/Form/Inline/Address.tpl create mode 100644 templates/CRM/Contact/Form/Inline/CommunicationPreferences.tpl create mode 100644 templates/CRM/Contact/Form/Inline/ContactInfo.tpl create mode 100644 templates/CRM/Contact/Form/Inline/ContactName.tpl create mode 100644 templates/CRM/Contact/Form/Inline/CustomData.tpl create mode 100644 templates/CRM/Contact/Form/Inline/Demographics.tpl create mode 100644 templates/CRM/Contact/Form/Inline/Email.tpl create mode 100644 templates/CRM/Contact/Form/Inline/IM.tpl create mode 100644 templates/CRM/Contact/Form/Inline/OpenID.tpl create mode 100644 templates/CRM/Contact/Form/Inline/Phone.tpl create mode 100644 templates/CRM/Contact/Form/Inline/Website.tpl create mode 100644 templates/CRM/Contact/Form/Merge.hlp create mode 100644 templates/CRM/Contact/Form/Merge.tpl create mode 100644 templates/CRM/Contact/Form/NewContact.tpl create mode 100644 templates/CRM/Contact/Form/OnBehalfOf.tpl create mode 100644 templates/CRM/Contact/Form/RelatedContact.tpl create mode 100644 templates/CRM/Contact/Form/Relationship.tpl create mode 100644 templates/CRM/Contact/Form/Search/Advanced.hlp create mode 100644 templates/CRM/Contact/Form/Search/Advanced.tpl create mode 100644 templates/CRM/Contact/Form/Search/AdvancedCriteria.tpl create mode 100644 templates/CRM/Contact/Form/Search/Basic.hlp create mode 100644 templates/CRM/Contact/Form/Search/Basic.tpl create mode 100644 templates/CRM/Contact/Form/Search/BasicCriteria.tpl create mode 100644 templates/CRM/Contact/Form/Search/Builder.hlp create mode 100644 templates/CRM/Contact/Form/Search/Builder.js create mode 100644 templates/CRM/Contact/Form/Search/Builder.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Activity.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Basic.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/ChangeLog.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Custom.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Demographics.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Location.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Notes.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Quest.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Relationship.tpl create mode 100644 templates/CRM/Contact/Form/Search/Criteria/Task.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/ActivitySearch.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/ContribSYBNT.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/ContributionAggregate.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/EmptyResults.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/EventDetails.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/FullText.hlp create mode 100644 templates/CRM/Contact/Form/Search/Custom/FullText.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/MultipleValues.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/MultipleValuesCriteria.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/Proximity.tpl create mode 100644 templates/CRM/Contact/Form/Search/Custom/Sample.tpl create mode 100644 templates/CRM/Contact/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Contact/Form/Search/Intro.tpl create mode 100644 templates/CRM/Contact/Form/Search/ResultTasks.tpl create mode 100644 templates/CRM/Contact/Form/Search/Simple.tpl create mode 100644 templates/CRM/Contact/Form/Search/table.tpl create mode 100644 templates/CRM/Contact/Form/Selector.tpl create mode 100644 templates/CRM/Contact/Form/ShareAddress.tpl create mode 100644 templates/CRM/Contact/Form/Task.tpl create mode 100644 templates/CRM/Contact/Form/Task/AddToGroup.tpl create mode 100644 templates/CRM/Contact/Form/Task/AddToHousehold.tpl create mode 100644 templates/CRM/Contact/Form/Task/AddToOrganization.tpl create mode 100644 templates/CRM/Contact/Form/Task/AddToTag.tpl create mode 100644 templates/CRM/Contact/Form/Task/AlterPreferences.tpl create mode 100644 templates/CRM/Contact/Form/Task/Batch.tpl create mode 100644 templates/CRM/Contact/Form/Task/Delete.tpl create mode 100644 templates/CRM/Contact/Form/Task/Email.hlp create mode 100644 templates/CRM/Contact/Form/Task/Email.tpl create mode 100644 templates/CRM/Contact/Form/Task/EmailCommon.tpl create mode 100644 templates/CRM/Contact/Form/Task/GMapsInput.tpl create mode 100644 templates/CRM/Contact/Form/Task/HookSample.tpl create mode 100644 templates/CRM/Contact/Form/Task/Label.hlp create mode 100644 templates/CRM/Contact/Form/Task/Label.tpl create mode 100644 templates/CRM/Contact/Form/Task/Map.tpl create mode 100644 templates/CRM/Contact/Form/Task/Map/Google.tpl create mode 100644 templates/CRM/Contact/Form/Task/Map/OpenStreetMaps.tpl create mode 100644 templates/CRM/Contact/Form/Task/PDF.tpl create mode 100644 templates/CRM/Contact/Form/Task/PDFLetterCommon.hlp create mode 100644 templates/CRM/Contact/Form/Task/PDFLetterCommon.tpl create mode 100644 templates/CRM/Contact/Form/Task/PickProfile.tpl create mode 100644 templates/CRM/Contact/Form/Task/Print.tpl create mode 100644 templates/CRM/Contact/Form/Task/ProximityCommon.tpl create mode 100644 templates/CRM/Contact/Form/Task/RemoveFromGroup.tpl create mode 100644 templates/CRM/Contact/Form/Task/RemoveFromTag.tpl create mode 100644 templates/CRM/Contact/Form/Task/Result.tpl create mode 100644 templates/CRM/Contact/Form/Task/SMS.hlp create mode 100644 templates/CRM/Contact/Form/Task/SMS.tpl create mode 100644 templates/CRM/Contact/Form/Task/SMSCommon.tpl create mode 100644 templates/CRM/Contact/Form/Task/SaveSearch.tpl create mode 100644 templates/CRM/Contact/Form/Task/SaveSearch/Update.tpl create mode 100644 templates/CRM/Contact/Form/Task/Unhold.tpl create mode 100644 templates/CRM/Contact/Form/Test.tpl create mode 100644 templates/CRM/Contact/Page/ContactImage.tpl create mode 100644 templates/CRM/Contact/Page/CustomSearch.hlp create mode 100644 templates/CRM/Contact/Page/CustomSearch.tpl create mode 100644 templates/CRM/Contact/Page/DashBoard.tpl create mode 100644 templates/CRM/Contact/Page/DashBoardDashlet.tpl create mode 100644 templates/CRM/Contact/Page/Dashboard.hlp create mode 100644 templates/CRM/Contact/Page/Dashlet.tpl create mode 100644 templates/CRM/Contact/Page/DedupeException.tpl create mode 100644 templates/CRM/Contact/Page/DedupeFind.tpl create mode 100644 templates/CRM/Contact/Page/DedupeRules.hlp create mode 100644 templates/CRM/Contact/Page/DedupeRules.tpl create mode 100644 templates/CRM/Contact/Page/Inline/Actions.tpl create mode 100644 templates/CRM/Contact/Page/Inline/Address.tpl create mode 100644 templates/CRM/Contact/Page/Inline/CommunicationPreferences.tpl create mode 100644 templates/CRM/Contact/Page/Inline/ContactInfo.tpl create mode 100644 templates/CRM/Contact/Page/Inline/ContactName.tpl create mode 100644 templates/CRM/Contact/Page/Inline/CustomData.tpl create mode 100644 templates/CRM/Contact/Page/Inline/Demographics.tpl create mode 100644 templates/CRM/Contact/Page/Inline/Email.tpl create mode 100644 templates/CRM/Contact/Page/Inline/IM.tpl create mode 100644 templates/CRM/Contact/Page/Inline/OpenID.tpl create mode 100644 templates/CRM/Contact/Page/Inline/Phone.tpl create mode 100644 templates/CRM/Contact/Page/Inline/Website.tpl create mode 100644 templates/CRM/Contact/Page/SavedSearch.tpl create mode 100644 templates/CRM/Contact/Page/View/CustomData.tpl create mode 100644 templates/CRM/Contact/Page/View/CustomDataFieldView.tpl create mode 100644 templates/CRM/Contact/Page/View/CustomDataView.tpl create mode 100644 templates/CRM/Contact/Page/View/Delete.tpl create mode 100644 templates/CRM/Contact/Page/View/Email.tpl create mode 100644 templates/CRM/Contact/Page/View/Group.tpl create mode 100644 templates/CRM/Contact/Page/View/GroupContact.tpl create mode 100644 templates/CRM/Contact/Page/View/Log.tpl create mode 100644 templates/CRM/Contact/Page/View/Note.tpl create mode 100644 templates/CRM/Contact/Page/View/Print.tpl create mode 100644 templates/CRM/Contact/Page/View/Relationship.tpl create mode 100644 templates/CRM/Contact/Page/View/SMS.tpl create mode 100644 templates/CRM/Contact/Page/View/Summary.hlp create mode 100644 templates/CRM/Contact/Page/View/Summary.js create mode 100644 templates/CRM/Contact/Page/View/Summary.tpl create mode 100644 templates/CRM/Contact/Page/View/SummaryHook.tpl create mode 100644 templates/CRM/Contact/Page/View/Sunlight.tpl create mode 100644 templates/CRM/Contact/Page/View/Tag.tpl create mode 100644 templates/CRM/Contact/Page/View/UserDashBoard.tpl create mode 100644 templates/CRM/Contact/Page/View/UserDashBoard/GroupContact.tpl create mode 100755 templates/CRM/Contact/Page/View/Useradd.tpl create mode 100644 templates/CRM/Contact/Selector.tpl create mode 100644 templates/CRM/Contribute/Form/AcceptCreditCard.tpl create mode 100644 templates/CRM/Contribute/Form/AdditionalInfo/AdditionalDetail.tpl create mode 100644 templates/CRM/Contribute/Form/AdditionalInfo/CreditCard.tpl create mode 100644 templates/CRM/Contribute/Form/AdditionalInfo/Honoree.tpl create mode 100644 templates/CRM/Contribute/Form/AdditionalInfo/PaymentReminders.tpl create mode 100644 templates/CRM/Contribute/Form/AdditionalInfo/Premium.tpl create mode 100644 templates/CRM/Contribute/Form/CancelSubscription.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/Confirm.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/Honor.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/Main.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/OnBehalfOf.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/PremiumBlock.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/PreviewHeader.tpl create mode 100644 templates/CRM/Contribute/Form/Contribution/ThankYou.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionCharts.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/AddProduct.hlp create mode 100644 templates/CRM/Contribute/Form/ContributionPage/AddProduct.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Amount.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Custom.hlp create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Custom.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Delete.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/PCP.hlp create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Premium.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Settings.hlp create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Settings.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Tab.hlp create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Tab.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/ThankYou.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Widget.hlp create mode 100644 templates/CRM/Contribute/Form/ContributionPage/Widget.tpl create mode 100644 templates/CRM/Contribute/Form/ContributionView.tpl create mode 100644 templates/CRM/Contribute/Form/ManagePremiums.tpl create mode 100644 templates/CRM/Contribute/Form/PCP/Campaign.tpl create mode 100644 templates/CRM/Contribute/Form/PCP/Delete.tpl create mode 100644 templates/CRM/Contribute/Form/PCP/PCP.tpl create mode 100644 templates/CRM/Contribute/Form/PCP/PCPAccount.tpl create mode 100644 templates/CRM/Contribute/Form/PaymentInstrument.tpl create mode 100644 templates/CRM/Contribute/Form/Preview.tpl create mode 100644 templates/CRM/Contribute/Form/Search.tpl create mode 100644 templates/CRM/Contribute/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Contribute/Form/Search/Common.tpl create mode 100644 templates/CRM/Contribute/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Contribute/Form/SearchContribution.tpl create mode 100644 templates/CRM/Contribute/Form/Selector.tpl create mode 100644 templates/CRM/Contribute/Form/Task.tpl create mode 100644 templates/CRM/Contribute/Form/Task/Batch.tpl create mode 100644 templates/CRM/Contribute/Form/Task/Delete.tpl create mode 100644 templates/CRM/Contribute/Form/Task/Email.tpl create mode 100644 templates/CRM/Contribute/Form/Task/PDF.tpl create mode 100644 templates/CRM/Contribute/Form/Task/PDFLetter.tpl create mode 100644 templates/CRM/Contribute/Form/Task/PickProfile.tpl create mode 100644 templates/CRM/Contribute/Form/Task/Print.tpl create mode 100644 templates/CRM/Contribute/Form/Task/Result.tpl create mode 100644 templates/CRM/Contribute/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Contribute/Form/Task/Status.tpl create mode 100644 templates/CRM/Contribute/Form/UpdateBilling.tpl create mode 100644 templates/CRM/Contribute/Form/UpdateSubscription.tpl create mode 100644 templates/CRM/Contribute/Import/Form/MapField.tpl create mode 100644 templates/CRM/Contribute/Import/Form/MapTable.tpl create mode 100644 templates/CRM/Contribute/Import/Form/Preview.tpl create mode 100644 templates/CRM/Contribute/Import/Form/Summary.tpl create mode 100644 templates/CRM/Contribute/Import/Form/UploadFile.hlp create mode 100644 templates/CRM/Contribute/Import/Form/UploadFile.tpl create mode 100644 templates/CRM/Contribute/Page/ContributionHonor.tpl create mode 100644 templates/CRM/Contribute/Page/ContributionPage.hlp create mode 100644 templates/CRM/Contribute/Page/ContributionPage.tpl create mode 100644 templates/CRM/Contribute/Page/ContributionRecur.tpl create mode 100644 templates/CRM/Contribute/Page/ContributionSoft.tpl create mode 100644 templates/CRM/Contribute/Page/ContributionTotals.tpl create mode 100644 templates/CRM/Contribute/Page/ContributionType.tpl create mode 100644 templates/CRM/Contribute/Page/DashBoard.hlp create mode 100644 templates/CRM/Contribute/Page/DashBoard.tpl create mode 100644 templates/CRM/Contribute/Page/ManagePremiums.tpl create mode 100644 templates/CRM/Contribute/Page/PcpUserDashboard.tpl create mode 100644 templates/CRM/Contribute/Page/Premium.tpl create mode 100644 templates/CRM/Contribute/Page/SubscriptionStatus.tpl create mode 100644 templates/CRM/Contribute/Page/Tab.hlp create mode 100644 templates/CRM/Contribute/Page/Tab.tpl create mode 100644 templates/CRM/Contribute/Page/UserDashboard.tpl create mode 100644 templates/CRM/Contribute/Page/Widget.tpl create mode 100644 templates/CRM/Core/APIDoc.tpl create mode 100644 templates/CRM/Core/AjaxDoc.tpl create mode 100644 templates/CRM/Core/BillingBlock.tpl create mode 100644 templates/CRM/Core/Calendar/GData.tpl create mode 100644 templates/CRM/Core/Calendar/ICal.tpl create mode 100644 templates/CRM/Core/Calendar/Rss.tpl create mode 100644 templates/CRM/Core/Date.tpl create mode 100644 templates/CRM/Core/DateRange.tpl create mode 100644 templates/CRM/Core/I18n/Dialog.tpl create mode 100644 templates/CRM/Core/I18n/Form.tpl create mode 100644 templates/CRM/Core/Page/QUnit.tpl create mode 100644 templates/CRM/Custom/Form/AutoComplete.tpl create mode 100644 templates/CRM/Custom/Form/ChangeFieldType.tpl create mode 100644 templates/CRM/Custom/Form/ContactReference.tpl create mode 100644 templates/CRM/Custom/Form/CustomData.tpl create mode 100644 templates/CRM/Custom/Form/CustomField.tpl create mode 100644 templates/CRM/Custom/Form/DeleteField.tpl create mode 100644 templates/CRM/Custom/Form/DeleteFile.tpl create mode 100644 templates/CRM/Custom/Form/DeleteGroup.tpl create mode 100644 templates/CRM/Custom/Form/Field.tpl create mode 100644 templates/CRM/Custom/Form/Group.tpl create mode 100644 templates/CRM/Custom/Form/MoveField.tpl create mode 100644 templates/CRM/Custom/Form/Option.tpl create mode 100644 templates/CRM/Custom/Form/Optionfields.tpl create mode 100644 templates/CRM/Custom/Form/Preview.tpl create mode 100644 templates/CRM/Custom/Form/Search.tpl create mode 100644 templates/CRM/Custom/Page/CustomDataView.tpl create mode 100644 templates/CRM/Custom/Page/Field.tpl create mode 100644 templates/CRM/Custom/Page/Group.hlp create mode 100644 templates/CRM/Custom/Page/Group.tpl create mode 100644 templates/CRM/Custom/Page/Option.tpl create mode 100644 templates/CRM/Dashlet/Page/Activity.tpl create mode 100644 templates/CRM/Dashlet/Page/AllCases.tpl create mode 100644 templates/CRM/Dashlet/Page/Blog.tpl create mode 100644 templates/CRM/Dashlet/Page/CaseDashboard.tpl create mode 100644 templates/CRM/Dashlet/Page/MyCases.tpl create mode 100644 templates/CRM/Event/Badge/CRM_Event_Badge_Logo.png create mode 100644 templates/CRM/Event/Badge/CRM_Event_Badge_Logo5395.png create mode 100644 templates/CRM/Event/Cart/Form/Checkout/ConferenceEvents.tpl create mode 100644 templates/CRM/Event/Cart/Form/Checkout/Participant.tpl create mode 100644 templates/CRM/Event/Cart/Form/Checkout/ParticipantsAndPrices.tpl create mode 100644 templates/CRM/Event/Cart/Form/Checkout/Payment.tpl create mode 100644 templates/CRM/Event/Cart/Form/Checkout/ThankYou.tpl create mode 100644 templates/CRM/Event/Cart/Form/viewCartLink.tpl create mode 100644 templates/CRM/Event/Cart/Page/AddToCart.tpl create mode 100644 templates/CRM/Event/Cart/Page/ViewCart.tpl create mode 100644 templates/CRM/Event/Form/EventFees.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/Conference.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/Delete.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/EventInfo.hlp create mode 100644 templates/CRM/Event/Form/ManageEvent/EventInfo.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/Fee.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/Location.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/Registration.hlp create mode 100644 templates/CRM/Event/Form/ManageEvent/Registration.tpl create mode 100755 templates/CRM/Event/Form/ManageEvent/ScheduleReminders.tpl create mode 100644 templates/CRM/Event/Form/ManageEvent/Tab.hlp create mode 100644 templates/CRM/Event/Form/ManageEvent/Tab.tpl create mode 100644 templates/CRM/Event/Form/Participant.tpl create mode 100644 templates/CRM/Event/Form/ParticipantView.tpl create mode 100644 templates/CRM/Event/Form/Registration/AdditionalParticipant.tpl create mode 100644 templates/CRM/Event/Form/Registration/Confirm.tpl create mode 100644 templates/CRM/Event/Form/Registration/DisplayProfile.tpl create mode 100644 templates/CRM/Event/Form/Registration/EventInfoBlock.tpl create mode 100644 templates/CRM/Event/Form/Registration/ParticipantConfirm.tpl create mode 100644 templates/CRM/Event/Form/Registration/PreviewHeader.tpl create mode 100644 templates/CRM/Event/Form/Registration/Register.tpl create mode 100644 templates/CRM/Event/Form/Registration/ThankYou.tpl create mode 100644 templates/CRM/Event/Form/Search.tpl create mode 100644 templates/CRM/Event/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Event/Form/Search/Common.tpl create mode 100644 templates/CRM/Event/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Event/Form/Search/Results.hlp create mode 100644 templates/CRM/Event/Form/SearchEvent.tpl create mode 100644 templates/CRM/Event/Form/Selector.tpl create mode 100644 templates/CRM/Event/Form/Task.tpl create mode 100644 templates/CRM/Event/Form/Task/Badge.tpl create mode 100644 templates/CRM/Event/Form/Task/Batch.tpl create mode 100644 templates/CRM/Event/Form/Task/Cancel.tpl create mode 100644 templates/CRM/Event/Form/Task/Delete.tpl create mode 100644 templates/CRM/Event/Form/Task/Email.tpl create mode 100644 templates/CRM/Event/Form/Task/ParticipantStatus.hlp create mode 100644 templates/CRM/Event/Form/Task/ParticipantStatus.tpl create mode 100644 templates/CRM/Event/Form/Task/PickProfile.tpl create mode 100644 templates/CRM/Event/Form/Task/Print.tpl create mode 100644 templates/CRM/Event/Form/Task/Result.tpl create mode 100644 templates/CRM/Event/Form/Task/SaveSearch.tpl create mode 100644 templates/CRM/Event/Form/Task/SaveSearch/Update.tpl create mode 100644 templates/CRM/Event/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Event/Import/Form/MapField.tpl create mode 100644 templates/CRM/Event/Import/Form/MapTable.tpl create mode 100644 templates/CRM/Event/Import/Form/Preview.tpl create mode 100644 templates/CRM/Event/Import/Form/Summary.tpl create mode 100644 templates/CRM/Event/Import/Form/UploadFile.hlp create mode 100644 templates/CRM/Event/Import/Form/UploadFile.tpl create mode 100644 templates/CRM/Event/Page/DashBoard.hlp create mode 100644 templates/CRM/Event/Page/DashBoard.tpl create mode 100644 templates/CRM/Event/Page/EventInfo.tpl create mode 100644 templates/CRM/Event/Page/ICalendar.tpl create mode 100644 templates/CRM/Event/Page/ManageEvent.hlp create mode 100644 templates/CRM/Event/Page/ManageEvent.tpl create mode 100644 templates/CRM/Event/Page/ParticipantListing/Name.tpl create mode 100644 templates/CRM/Event/Page/ParticipantListing/NameAndEmail.tpl create mode 100644 templates/CRM/Event/Page/ParticipantListing/NameStatusAndDate.tpl create mode 100644 templates/CRM/Event/Page/Tab.tpl create mode 100644 templates/CRM/Event/Page/UserDashboard.tpl create mode 100644 templates/CRM/Event/Page/iCalLinks.tpl create mode 100644 templates/CRM/Export/Form/Map.tpl create mode 100644 templates/CRM/Export/Form/Select.hlp create mode 100644 templates/CRM/Export/Form/Select.tpl create mode 100644 templates/CRM/Export/Form/table.tpl create mode 100644 templates/CRM/Financial/ExportFormat/IIF.tpl create mode 100644 templates/CRM/Financial/Form/BatchTransaction.tpl create mode 100644 templates/CRM/Financial/Form/Export.tpl create mode 100644 templates/CRM/Financial/Form/FinancialAccount.tpl create mode 100644 templates/CRM/Financial/Form/FinancialBatch.tpl create mode 100644 templates/CRM/Financial/Form/FinancialType.tpl create mode 100644 templates/CRM/Financial/Form/FinancialTypeAccount.tpl create mode 100644 templates/CRM/Financial/Form/Search.tpl create mode 100644 templates/CRM/Financial/Page/Batch.tpl create mode 100644 templates/CRM/Financial/Page/BatchTransaction.tpl create mode 100644 templates/CRM/Financial/Page/FinancialAccount.tpl create mode 100644 templates/CRM/Financial/Page/FinancialBatch.hlp create mode 100644 templates/CRM/Financial/Page/FinancialBatch.tpl create mode 100644 templates/CRM/Financial/Page/FinancialType.tpl create mode 100644 templates/CRM/Financial/Page/FinancialTypeAccount.tpl create mode 100644 templates/CRM/Form/attachment.tpl create mode 100644 templates/CRM/Form/basicForm.tpl create mode 100644 templates/CRM/Form/body.tpl create mode 100644 templates/CRM/Form/default.tpl create mode 100644 templates/CRM/Form/element.tpl create mode 100644 templates/CRM/Form/error.tpl create mode 100644 templates/CRM/Form/label.tpl create mode 100644 templates/CRM/Form/quest.tpl create mode 100644 templates/CRM/Form/validate.tpl create mode 100644 templates/CRM/Friend/Form.tpl create mode 100644 templates/CRM/Friend/Form/Contribute.tpl create mode 100644 templates/CRM/Friend/Form/Event.tpl create mode 100644 templates/CRM/Friend/Form/Friend.tpl create mode 100644 templates/CRM/Friend/Form/Pledge.tpl create mode 100644 templates/CRM/Grant/Form/Grant.tpl create mode 100644 templates/CRM/Grant/Form/GrantView.tpl create mode 100644 templates/CRM/Grant/Form/Search.tpl create mode 100644 templates/CRM/Grant/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Grant/Form/Search/Common.tpl create mode 100644 templates/CRM/Grant/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Grant/Form/Selector.tpl create mode 100644 templates/CRM/Grant/Form/Task.tpl create mode 100644 templates/CRM/Grant/Form/Task/Delete.tpl create mode 100644 templates/CRM/Grant/Form/Task/Print.tpl create mode 100644 templates/CRM/Grant/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Grant/Form/Task/Update.tpl create mode 100644 templates/CRM/Grant/Page/DashBoard.tpl create mode 100644 templates/CRM/Grant/Page/Payment.tpl create mode 100644 templates/CRM/Grant/Page/Tab.tpl create mode 100644 templates/CRM/Group/Form/Delete.tpl create mode 100644 templates/CRM/Group/Form/Edit.tpl create mode 100644 templates/CRM/Group/Form/Search.tpl create mode 100644 templates/CRM/Group/Page/Group.hlp create mode 100644 templates/CRM/Group/Page/Group.tpl create mode 100644 templates/CRM/Group/Page/GroupRows.tpl create mode 100644 templates/CRM/HRDCase/Form/Case.tpl create mode 100644 templates/CRM/HRDCase/Form/CaseActivity.tpl create mode 100644 templates/CRM/HRDCase/Form/CaseView.tpl create mode 100644 templates/CRM/Import/Form/CSV.tpl create mode 100644 templates/CRM/Import/Form/DataSource.hlp create mode 100644 templates/CRM/Import/Form/DataSource.tpl create mode 100644 templates/CRM/Import/Form/MapField.tpl create mode 100644 templates/CRM/Import/Form/MapTable.tpl create mode 100644 templates/CRM/Import/Form/Mapper.tpl create mode 100644 templates/CRM/Import/Form/Preview.tpl create mode 100644 templates/CRM/Import/Form/SQL.tpl create mode 100644 templates/CRM/Import/Form/Summary.tpl create mode 100644 templates/CRM/Logging/ReportDetail.tpl create mode 100644 templates/CRM/Logging/ReportSummary.tpl create mode 100644 templates/CRM/Mailing/Form/Approve.tpl create mode 100644 templates/CRM/Mailing/Form/Component.tpl create mode 100644 templates/CRM/Mailing/Form/Count.tpl create mode 100644 templates/CRM/Mailing/Form/ForwardMailing.tpl create mode 100644 templates/CRM/Mailing/Form/Group.hlp create mode 100644 templates/CRM/Mailing/Form/Group.tpl create mode 100644 templates/CRM/Mailing/Form/InsertTokens.tpl create mode 100644 templates/CRM/Mailing/Form/Schedule.hlp create mode 100644 templates/CRM/Mailing/Form/Schedule.tpl create mode 100644 templates/CRM/Mailing/Form/Search.tpl create mode 100644 templates/CRM/Mailing/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Mailing/Form/Search/Common.tpl create mode 100644 templates/CRM/Mailing/Form/Settings.hlp create mode 100644 templates/CRM/Mailing/Form/Settings.tpl create mode 100644 templates/CRM/Mailing/Form/Subscribe.tpl create mode 100644 templates/CRM/Mailing/Form/Test.hlp create mode 100644 templates/CRM/Mailing/Form/Test.tpl create mode 100644 templates/CRM/Mailing/Form/Upload.hlp create mode 100644 templates/CRM/Mailing/Form/Upload.tpl create mode 100644 templates/CRM/Mailing/Page/Browse.hlp create mode 100644 templates/CRM/Mailing/Page/Browse.tpl create mode 100644 templates/CRM/Mailing/Page/Component.tpl create mode 100644 templates/CRM/Mailing/Page/Confirm.tpl create mode 100644 templates/CRM/Mailing/Page/Event.tpl create mode 100644 templates/CRM/Mailing/Page/Optout.tpl create mode 100644 templates/CRM/Mailing/Page/Report.tpl create mode 100644 templates/CRM/Mailing/Page/Resubscribe.tpl create mode 100644 templates/CRM/Mailing/Page/Unsubscribe.tpl create mode 100644 templates/CRM/Member/Form/Membership.hlp create mode 100644 templates/CRM/Member/Form/Membership.tpl create mode 100644 templates/CRM/Member/Form/MembershipBlock.hlp create mode 100644 templates/CRM/Member/Form/MembershipBlock.tpl create mode 100644 templates/CRM/Member/Form/MembershipRelated.tpl create mode 100644 templates/CRM/Member/Form/MembershipRenewal.tpl create mode 100644 templates/CRM/Member/Form/MembershipStatus.tpl create mode 100644 templates/CRM/Member/Form/MembershipType.tpl create mode 100644 templates/CRM/Member/Form/MembershipView.tpl create mode 100644 templates/CRM/Member/Form/Search.hlp create mode 100644 templates/CRM/Member/Form/Search.tpl create mode 100644 templates/CRM/Member/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Member/Form/Search/Common.tpl create mode 100644 templates/CRM/Member/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Member/Form/Selector.tpl create mode 100644 templates/CRM/Member/Form/Task.tpl create mode 100644 templates/CRM/Member/Form/Task/Batch.tpl create mode 100644 templates/CRM/Member/Form/Task/Delete.tpl create mode 100644 templates/CRM/Member/Form/Task/Email.tpl create mode 100644 templates/CRM/Member/Form/Task/PickProfile.tpl create mode 100644 templates/CRM/Member/Form/Task/Print.tpl create mode 100644 templates/CRM/Member/Form/Task/Result.tpl create mode 100644 templates/CRM/Member/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Member/Import/Form/MapField.tpl create mode 100644 templates/CRM/Member/Import/Form/MapTable.tpl create mode 100644 templates/CRM/Member/Import/Form/Preview.tpl create mode 100644 templates/CRM/Member/Import/Form/Summary.tpl create mode 100644 templates/CRM/Member/Import/Form/UploadFile.hlp create mode 100644 templates/CRM/Member/Import/Form/UploadFile.tpl create mode 100644 templates/CRM/Member/Page/DashBoard.hlp create mode 100644 templates/CRM/Member/Page/DashBoard.tpl create mode 100644 templates/CRM/Member/Page/MembershipStatus.tpl create mode 100644 templates/CRM/Member/Page/MembershipType.hlp create mode 100644 templates/CRM/Member/Page/MembershipType.tpl create mode 100644 templates/CRM/Member/Page/Tab.hlp create mode 100644 templates/CRM/Member/Page/Tab.tpl create mode 100644 templates/CRM/Member/Page/UserDashboard.tpl create mode 100644 templates/CRM/Note/Form/Note.tpl create mode 100644 templates/CRM/PCP/Form/Campaign.tpl create mode 100644 templates/CRM/PCP/Form/Contribute.hlp create mode 100644 templates/CRM/PCP/Form/Contribute.tpl create mode 100644 templates/CRM/PCP/Form/Event.hlp create mode 100644 templates/CRM/PCP/Form/Event.tpl create mode 100644 templates/CRM/PCP/Form/PCP.tpl create mode 100644 templates/CRM/PCP/Form/PCP/Delete.tpl create mode 100644 templates/CRM/PCP/Form/PCP/PCP.tpl create mode 100644 templates/CRM/PCP/Form/PCPAccount.tpl create mode 100644 templates/CRM/PCP/Page/Contribute.tpl create mode 100644 templates/CRM/PCP/Page/Event.tpl create mode 100644 templates/CRM/PCP/Page/PCP.hlp create mode 100644 templates/CRM/PCP/Page/PCP.tpl create mode 100644 templates/CRM/PCP/Page/PCPInfo.tpl create mode 100644 templates/CRM/Pledge/Form/Payment.tpl create mode 100644 templates/CRM/Pledge/Form/Pledge.tpl create mode 100644 templates/CRM/Pledge/Form/PledgeView.tpl create mode 100644 templates/CRM/Pledge/Form/Search.tpl create mode 100644 templates/CRM/Pledge/Form/Search/AdvancedSearchPane.tpl create mode 100644 templates/CRM/Pledge/Form/Search/Common.tpl create mode 100644 templates/CRM/Pledge/Form/Search/EmptyResults.tpl create mode 100644 templates/CRM/Pledge/Form/Selector.tpl create mode 100644 templates/CRM/Pledge/Form/Task.tpl create mode 100644 templates/CRM/Pledge/Form/Task/Delete.tpl create mode 100644 templates/CRM/Pledge/Form/Task/Print.tpl create mode 100644 templates/CRM/Pledge/Form/Task/Result.tpl create mode 100644 templates/CRM/Pledge/Form/Task/SaveSearch.tpl create mode 100644 templates/CRM/Pledge/Form/Task/SaveSearch/Update.tpl create mode 100644 templates/CRM/Pledge/Form/Task/SearchTaskHookSample.tpl create mode 100644 templates/CRM/Pledge/Page/DashBoard.tpl create mode 100644 templates/CRM/Pledge/Page/Payment.hlp create mode 100644 templates/CRM/Pledge/Page/Payment.tpl create mode 100644 templates/CRM/Pledge/Page/Tab.hlp create mode 100644 templates/CRM/Pledge/Page/Tab.tpl create mode 100644 templates/CRM/Pledge/Page/UserDashboard.tpl create mode 100644 templates/CRM/Price/Form/Calculate.tpl create mode 100644 templates/CRM/Price/Form/DeleteField.tpl create mode 100644 templates/CRM/Price/Form/DeleteSet.tpl create mode 100644 templates/CRM/Price/Form/Field.tpl create mode 100644 templates/CRM/Price/Form/LineItem.tpl create mode 100644 templates/CRM/Price/Form/Option.tpl create mode 100644 templates/CRM/Price/Form/OptionFields.tpl create mode 100644 templates/CRM/Price/Form/ParticipantCount.tpl create mode 100644 templates/CRM/Price/Form/Preview.tpl create mode 100644 templates/CRM/Price/Form/PriceSet.tpl create mode 100644 templates/CRM/Price/Form/Set.tpl create mode 100644 templates/CRM/Price/Page/Field.hlp create mode 100644 templates/CRM/Price/Page/Field.tpl create mode 100644 templates/CRM/Price/Page/LineItem.tpl create mode 100644 templates/CRM/Price/Page/Option.tpl create mode 100644 templates/CRM/Price/Page/Set.tpl create mode 100644 templates/CRM/Price/Page/table.tpl create mode 100644 templates/CRM/Profile/Form/Dynamic.tpl create mode 100644 templates/CRM/Profile/Form/Edit.tpl create mode 100644 templates/CRM/Profile/Form/GreetingType.tpl create mode 100644 templates/CRM/Profile/Form/Search.tpl create mode 100644 templates/CRM/Profile/Page/Dynamic.tpl create mode 100644 templates/CRM/Profile/Page/Listings.tpl create mode 100644 templates/CRM/Profile/Page/MultipleRecordFieldsListing.tpl create mode 100644 templates/CRM/Profile/Page/Overlay.tpl create mode 100644 templates/CRM/Profile/Page/View.tpl create mode 100644 templates/CRM/Queue/Page/Runner.tpl create mode 100644 templates/CRM/Report/Form.tpl create mode 100644 templates/CRM/Report/Form/Actions.tpl create mode 100644 templates/CRM/Report/Form/Activity.tpl create mode 100644 templates/CRM/Report/Form/ActivitySummary.tpl create mode 100644 templates/CRM/Report/Form/Campaign/SurveyCoverSheet.tpl create mode 100644 templates/CRM/Report/Form/Campaign/SurveyDetails.tpl create mode 100644 templates/CRM/Report/Form/Case/Demographics.tpl create mode 100644 templates/CRM/Report/Form/Case/Detail.tpl create mode 100644 templates/CRM/Report/Form/Case/Summary.tpl create mode 100644 templates/CRM/Report/Form/Case/TimeSpent.tpl create mode 100644 templates/CRM/Report/Form/Contact/CurrentEmployer.tpl create mode 100644 templates/CRM/Report/Form/Contact/Detail.tpl create mode 100644 templates/CRM/Report/Form/Contact/Log.tpl create mode 100644 templates/CRM/Report/Form/Contact/LoggingDetail.tpl create mode 100644 templates/CRM/Report/Form/Contact/LoggingSummary.tpl create mode 100644 templates/CRM/Report/Form/Contact/Relationship.tpl create mode 100644 templates/CRM/Report/Form/Contact/Summary.tpl create mode 100644 templates/CRM/Report/Form/Contribute/Bookkeeping.tpl create mode 100644 templates/CRM/Report/Form/Contribute/Detail.tpl create mode 100644 templates/CRM/Report/Form/Contribute/History.tpl create mode 100644 templates/CRM/Report/Form/Contribute/HouseholdSummary.tpl create mode 100644 templates/CRM/Report/Form/Contribute/LoggingDetail.tpl create mode 100644 templates/CRM/Report/Form/Contribute/LoggingSummary.tpl create mode 100644 templates/CRM/Report/Form/Contribute/Lybunt.tpl create mode 100644 templates/CRM/Report/Form/Contribute/OrganizationSummary.tpl create mode 100644 templates/CRM/Report/Form/Contribute/PCP.tpl create mode 100644 templates/CRM/Report/Form/Contribute/Repeat.tpl create mode 100644 templates/CRM/Report/Form/Contribute/SoftCredit.tpl create mode 100644 templates/CRM/Report/Form/Contribute/Summary.tpl create mode 100644 templates/CRM/Report/Form/Contribute/Sybunt.tpl create mode 100644 templates/CRM/Report/Form/Contribute/TopDonor.tpl create mode 100644 templates/CRM/Report/Form/Criteria.tpl create mode 100644 templates/CRM/Report/Form/ErrorMessage.tpl create mode 100644 templates/CRM/Report/Form/Event/Income.tpl create mode 100644 templates/CRM/Report/Form/Event/IncomeCountSummary.tpl create mode 100644 templates/CRM/Report/Form/Event/ParticipantListCount.tpl create mode 100644 templates/CRM/Report/Form/Event/ParticipantListing.tpl create mode 100644 templates/CRM/Report/Form/Event/Summary.tpl create mode 100644 templates/CRM/Report/Form/Fields.tpl create mode 100644 templates/CRM/Report/Form/Grant/Detail.tpl create mode 100644 templates/CRM/Report/Form/Grant/Statistics.tpl create mode 100644 templates/CRM/Report/Form/Instance.tpl create mode 100644 templates/CRM/Report/Form/Layout/Graph.tpl create mode 100644 templates/CRM/Report/Form/Layout/Overlay.tpl create mode 100644 templates/CRM/Report/Form/Layout/Table.tpl create mode 100644 templates/CRM/Report/Form/Mailing/Bounce.tpl create mode 100644 templates/CRM/Report/Form/Mailing/Clicks.tpl create mode 100644 templates/CRM/Report/Form/Mailing/Detail.tpl create mode 100644 templates/CRM/Report/Form/Mailing/Opened.tpl create mode 100644 templates/CRM/Report/Form/Mailing/Summary.tpl create mode 100644 templates/CRM/Report/Form/Member/ContributionDetail.tpl create mode 100644 templates/CRM/Report/Form/Member/Detail.tpl create mode 100644 templates/CRM/Report/Form/Member/Lapse.tpl create mode 100644 templates/CRM/Report/Form/Member/Summary.tpl create mode 100644 templates/CRM/Report/Form/Membership/Summary.tpl create mode 100644 templates/CRM/Report/Form/Pledge/Detail.tpl create mode 100644 templates/CRM/Report/Form/Pledge/Pbnp.tpl create mode 100644 templates/CRM/Report/Form/Pledge/Summary.tpl create mode 100644 templates/CRM/Report/Form/Register.tpl create mode 100644 templates/CRM/Report/Form/Settings.hlp create mode 100644 templates/CRM/Report/Form/Statistics.tpl create mode 100644 templates/CRM/Report/Form/Walklist/Walklist.tpl create mode 100644 templates/CRM/Report/Page/InstanceList.tpl create mode 100644 templates/CRM/Report/Page/List.tpl create mode 100644 templates/CRM/Report/Page/Options.tpl create mode 100644 templates/CRM/Report/Page/TemplateList.tpl create mode 100644 templates/CRM/SMS/Form/Group.hlp create mode 100644 templates/CRM/SMS/Form/Group.tpl create mode 100644 templates/CRM/SMS/Form/Provider.tpl create mode 100644 templates/CRM/SMS/Form/Schedule.hlp create mode 100644 templates/CRM/SMS/Form/Schedule.tpl create mode 100644 templates/CRM/SMS/Form/Task/SMS.tpl create mode 100644 templates/CRM/SMS/Form/Upload.hlp create mode 100644 templates/CRM/SMS/Form/Upload.tpl create mode 100644 templates/CRM/SMS/Page/Provider.tpl create mode 100644 templates/CRM/Tag/Form/Search.tpl create mode 100644 templates/CRM/Tag/Form/Tag.tpl create mode 100644 templates/CRM/UF/Form/AdvanceSetting.tpl create mode 100644 templates/CRM/UF/Form/Block.tpl create mode 100644 templates/CRM/UF/Form/Field.hlp create mode 100644 templates/CRM/UF/Form/Field.tpl create mode 100644 templates/CRM/UF/Form/Group.hlp create mode 100644 templates/CRM/UF/Form/Group.tpl create mode 100644 templates/CRM/UF/Form/Preview.tpl create mode 100644 templates/CRM/UF/Page/Field.tpl create mode 100644 templates/CRM/UF/Page/Group.hlp create mode 100644 templates/CRM/UF/Page/Group.tpl create mode 100644 templates/CRM/UF/Page/ProfileTemplates.tpl create mode 100644 templates/CRM/Upgrade/Base.tpl create mode 100644 templates/CRM/Widget/Page/Inline/Example.tpl create mode 100644 templates/CRM/Widget/widget.tpl create mode 100644 templates/CRM/common/CMSUser.tpl create mode 100644 templates/CRM/common/Filter.tpl create mode 100644 templates/CRM/common/Navigation.tpl create mode 100644 templates/CRM/common/ReCAPTCHA.tpl create mode 100644 templates/CRM/common/SectionNav.tpl create mode 100644 templates/CRM/common/SocialNetwork.tpl create mode 100644 templates/CRM/common/TabHeader.tpl create mode 100644 templates/CRM/common/Tag.tpl create mode 100644 templates/CRM/common/TrackingFields.tpl create mode 100644 templates/CRM/common/WizardHeader.tpl create mode 100644 templates/CRM/common/accesskeys.hlp create mode 100644 templates/CRM/common/accesskeys.tpl create mode 100644 templates/CRM/common/activityView.tpl create mode 100644 templates/CRM/common/additionalBlocks.tpl create mode 100644 templates/CRM/common/batchCopy.tpl create mode 100644 templates/CRM/common/buildProfileLink.tpl create mode 100644 templates/CRM/common/checkUsernameAvailable.tpl create mode 100644 templates/CRM/common/civicrm.settings.php.tpl create mode 100644 templates/CRM/common/civicrm_variables.tpl create mode 100644 templates/CRM/common/commonCSS.tpl create mode 100644 templates/CRM/common/contactFooter.tpl create mode 100644 templates/CRM/common/crmeditable.tpl create mode 100644 templates/CRM/common/customData.tpl create mode 100644 templates/CRM/common/dashboard.tpl create mode 100644 templates/CRM/common/debug.tpl create mode 100644 templates/CRM/common/dedupe.tpl create mode 100644 templates/CRM/common/displaySearchCriteria.tpl create mode 100644 templates/CRM/common/drupal.tpl create mode 100644 templates/CRM/common/drupal6.tpl create mode 100644 templates/CRM/common/enableDisable.tpl create mode 100644 templates/CRM/common/fatal.tpl create mode 100644 templates/CRM/common/footer.tpl create mode 100644 templates/CRM/common/formButtons.tpl create mode 100644 templates/CRM/common/formNavigate.tpl create mode 100644 templates/CRM/common/highLightImport.tpl create mode 100644 templates/CRM/common/info.tpl create mode 100644 templates/CRM/common/jcalendar.tpl create mode 100644 templates/CRM/common/joomla.tpl create mode 100644 templates/CRM/common/jquery.files.tpl create mode 100644 templates/CRM/common/jsortable.tpl create mode 100644 templates/CRM/common/langSwitch.tpl create mode 100644 templates/CRM/common/localNav.tpl create mode 100644 templates/CRM/common/notifications.tpl create mode 100644 templates/CRM/common/openFlashChart.tpl create mode 100644 templates/CRM/common/overlay.tpl create mode 100644 templates/CRM/common/pager.tpl create mode 100644 templates/CRM/common/pagerAToZ.tpl create mode 100644 templates/CRM/common/paymentBlock.tpl create mode 100644 templates/CRM/common/print.tpl create mode 100644 templates/CRM/common/printBody.tpl create mode 100644 templates/CRM/common/recentlyViewed.tpl create mode 100644 templates/CRM/common/redirectJS.tpl create mode 100644 templates/CRM/common/scripts.tpl create mode 100644 templates/CRM/common/searchResultTasks.tpl create mode 100644 templates/CRM/common/showHide.tpl create mode 100644 templates/CRM/common/showHideByFieldValue.tpl create mode 100644 templates/CRM/common/snippet.tpl create mode 100644 templates/CRM/common/stateCountry.tpl create mode 100644 templates/CRM/common/status.tpl create mode 100644 templates/CRM/common/success.tpl create mode 100644 templates/CRM/common/upgradeCleanup.tpl create mode 100644 templates/CRM/common/wordpress.tpl create mode 100644 templates/CRM/common/wysiwyg.tpl create mode 100644 tests/README.txt create mode 100644 tests/bin/api3.php create mode 100644 tests/bin/run.php create mode 100644 tests/extensions/README.txt create mode 100644 tests/extensions/test.extension.manager.moduletest/info.xml create mode 100644 tests/extensions/test.extension.manager.moduletest/moduletest.php create mode 100644 tests/extensions/test.extension.manager.paymenttest/info.xml create mode 100644 tests/extensions/test.extension.manager.paymenttest/main.php create mode 100644 tests/extensions/test.extension.manager.reporttest/info.xml create mode 100644 tests/extensions/test.extension.manager.reporttest/main.php create mode 100644 tests/extensions/test.extension.manager.searchtest/info.xml create mode 100644 tests/extensions/test.extension.manager.searchtest/main.php create mode 100644 tests/phpunit/AllTests.php create mode 100644 tests/phpunit/CRM/Activity/AllTests.php create mode 100644 tests/phpunit/CRM/Activity/BAO/ActivityAssignmentTest.php create mode 100644 tests/phpunit/CRM/Activity/BAO/ActivityTargetTest.php create mode 100644 tests/phpunit/CRM/Activity/BAO/ActivityTest.php create mode 100644 tests/phpunit/CRM/Activity/BAO/activities_for_dashboard_count.xml create mode 100644 tests/phpunit/CRM/AllTests.php create mode 100644 tests/phpunit/CRM/Bridge/OG/DrupalTest.php create mode 100644 tests/phpunit/CRM/Contact/AllTests.php create mode 100644 tests/phpunit/CRM/Contact/BAO/ContactTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/ContactType/ContactSearchTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/ContactType/ContactTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/ContactType/ContactTypeTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/ContactType/RelationshipTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/DupeContactTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/GroupContactCacheTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/GroupContactTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/GroupTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/QueryTest.php create mode 100644 tests/phpunit/CRM/Contact/BAO/QueryTestDataProvider.php create mode 100644 tests/phpunit/CRM/Contact/BAO/queryDataset.xml create mode 100644 tests/phpunit/CRM/Contact/Form/Search/Custom/GroupTest.php create mode 100644 tests/phpunit/CRM/Contact/Form/Search/Custom/GroupTestDataProvider.php create mode 100644 tests/phpunit/CRM/Contact/Form/Search/Custom/dataset.xml create mode 100644 tests/phpunit/CRM/Contribute/AllTests.php create mode 100644 tests/phpunit/CRM/Contribute/BAO/ContributionPageTest.php create mode 100644 tests/phpunit/CRM/Contribute/BAO/ContributionTest.php create mode 100644 tests/phpunit/CRM/Contribute/BAO/ContributionTypeTest.php create mode 100644 tests/phpunit/CRM/Contribute/BAO/ManagePremiumsTest.php create mode 100644 tests/phpunit/CRM/Core/AllTests.php create mode 100644 tests/phpunit/CRM/Core/BAO/ActionScheduleTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/AddressTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/CustomFieldTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/CustomGroupTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/CustomValueTableMultipleTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/CustomValueTableSetGetTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/CustomValueTableTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/CustomValueTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/EmailTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/FinancialTrxnTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/IMTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/LocationTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/OpenIDTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/PhoneTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/PreferencesTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/SettingTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/UFFieldTest.php create mode 100644 tests/phpunit/CRM/Core/BAO/dataset/im_test.xml create mode 100644 tests/phpunit/CRM/Core/ErrorTest.php create mode 100644 tests/phpunit/CRM/Core/JobManagerTest.php create mode 100644 tests/phpunit/CRM/Core/ManagedEntitiesTest.php create mode 100644 tests/phpunit/CRM/Core/Page/AJAXTest.php create mode 100644 tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php create mode 100644 tests/phpunit/CRM/Core/Payment/BaseIPNTest.php create mode 100644 tests/phpunit/CRM/Core/RegionTest.php create mode 100644 tests/phpunit/CRM/Core/ResourcesTest.php create mode 100644 tests/phpunit/CRM/Event/AllTests.php create mode 100644 tests/phpunit/CRM/Event/BAO/ParticipantStatusTest.php create mode 100644 tests/phpunit/CRM/Event/BAO/ParticipantTest.php create mode 100644 tests/phpunit/CRM/Extension/AllTests.php create mode 100644 tests/phpunit/CRM/Extension/BrowserTest.php create mode 100644 tests/phpunit/CRM/Extension/Container/AllTests.php create mode 100644 tests/phpunit/CRM/Extension/Container/BasicTest.php create mode 100644 tests/phpunit/CRM/Extension/Container/CollectionTest.php create mode 100644 tests/phpunit/CRM/Extension/Container/StaticTest.php create mode 100644 tests/phpunit/CRM/Extension/InfoTest.php create mode 100644 tests/phpunit/CRM/Extension/Manager/AllTests.php create mode 100644 tests/phpunit/CRM/Extension/Manager/ModuleTest.php create mode 100644 tests/phpunit/CRM/Extension/Manager/PaymentTest.php create mode 100644 tests/phpunit/CRM/Extension/Manager/ReportTest.php create mode 100644 tests/phpunit/CRM/Extension/Manager/SearchTest.php create mode 100644 tests/phpunit/CRM/Extension/ManagerTest.php create mode 100644 tests/phpunit/CRM/Extension/MapperTest.php create mode 100644 tests/phpunit/CRM/Extension/dataset/good-repository/index.html create mode 100644 tests/phpunit/CRM/Extension/dataset/good-repository/test.crm.extension.browsertest.a.xml create mode 100644 tests/phpunit/CRM/Extension/dataset/good-repository/test.crm.extension.browsertest.b.xml create mode 100644 tests/phpunit/CRM/Financial/BAO/FinancialAccountTest.php create mode 100755 tests/phpunit/CRM/Financial/BAO/FinancialItemTest.php create mode 100755 tests/phpunit/CRM/Financial/BAO/FinancialTypeAccountTest.php create mode 100755 tests/phpunit/CRM/Financial/BAO/FinancialTypeTest.php create mode 100755 tests/phpunit/CRM/Financial/BAO/PaymentProcessorTypeTest.php create mode 100644 tests/phpunit/CRM/Mailing/BAO/QueryTest.php create mode 100644 tests/phpunit/CRM/Mailing/BAO/QueryTestDataProvider.php create mode 100644 tests/phpunit/CRM/Mailing/BAO/SpoolTest.php create mode 100644 tests/phpunit/CRM/Mailing/BAO/queryDataset.xml create mode 100644 tests/phpunit/CRM/Member/AllTests.php create mode 100644 tests/phpunit/CRM/Member/BAO/MembershipLogTest.php create mode 100644 tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php create mode 100644 tests/phpunit/CRM/Member/BAO/MembershipTest.php create mode 100644 tests/phpunit/CRM/Member/BAO/MembershipTypeTest.php create mode 100644 tests/phpunit/CRM/Member/Form/AllTests.php create mode 100644 tests/phpunit/CRM/Member/Form/MembershipTest.php create mode 100644 tests/phpunit/CRM/Member/Form/dataset/data.xml create mode 100644 tests/phpunit/CRM/PCP/BAO/PCPTest.php create mode 100644 tests/phpunit/CRM/Pledge/AllTests.php create mode 100644 tests/phpunit/CRM/Pledge/BAO/PaymentTest.php create mode 100644 tests/phpunit/CRM/Pledge/BAO/PledgeBlockTest.php create mode 100644 tests/phpunit/CRM/Pledge/BAO/PledgeTest.php create mode 100644 tests/phpunit/CRM/Queue/AllTests.php create mode 100644 tests/phpunit/CRM/Queue/Queue/AllTests.php create mode 100644 tests/phpunit/CRM/Queue/Queue/SqlTest.php create mode 100644 tests/phpunit/CRM/Queue/QueueTest.php create mode 100644 tests/phpunit/CRM/Queue/RunnerTest.php create mode 100644 tests/phpunit/CRM/UF/Page/ProfileEditorTest.php create mode 100644 tests/phpunit/CRM/Utils/ArrayTest.php create mode 100644 tests/phpunit/CRM/Utils/Cache/AllTests.php create mode 100644 tests/phpunit/CRM/Utils/Cache/SqlGroupTest.php create mode 100644 tests/phpunit/CRM/Utils/DeprecatedUtilsTest.php create mode 100644 tests/phpunit/CRM/Utils/FileTest.php create mode 100644 tests/phpunit/CRM/Utils/HttpClientTest.php create mode 100644 tests/phpunit/CRM/Utils/JSTest.php create mode 100644 tests/phpunit/CRM/Utils/MailTest.php create mode 100644 tests/phpunit/CRM/Utils/SignerTest.php create mode 100644 tests/phpunit/CRM/Utils/StringTest.php create mode 100644 tests/phpunit/CRM/Utils/SystemTest.php create mode 100644 tests/phpunit/CRM/Utils/ZipTest.php create mode 100644 tests/phpunit/CiviTest/AuthorizeNet.php create mode 100644 tests/phpunit/CiviTest/CiviDBAssert.php create mode 100644 tests/phpunit/CiviTest/CiviMailUtils.php create mode 100644 tests/phpunit/CiviTest/CiviSeleniumSettings.php.txt create mode 100644 tests/phpunit/CiviTest/CiviSeleniumTestCase.php create mode 100644 tests/phpunit/CiviTest/CiviTestCase.php create mode 100644 tests/phpunit/CiviTest/CiviTestSuite.php create mode 100644 tests/phpunit/CiviTest/CiviUnitTestCase.php create mode 100644 tests/phpunit/CiviTest/Contact.php create mode 100644 tests/phpunit/CiviTest/ContributionPage.php create mode 100644 tests/phpunit/CiviTest/Custom.php create mode 100644 tests/phpunit/CiviTest/Event.php create mode 100644 tests/phpunit/CiviTest/Membership.php create mode 100644 tests/phpunit/CiviTest/PCP.php create mode 100644 tests/phpunit/CiviTest/Participant.php create mode 100644 tests/phpunit/CiviTest/PaypalPro.php create mode 100644 tests/phpunit/CiviTest/ReleaseTestSettings.php.txt create mode 100644 tests/phpunit/CiviTest/civicrm.settings.dist.php create mode 100644 tests/phpunit/CiviTest/civicrm.settings.local.php.txt create mode 100644 tests/phpunit/CiviTest/truncate-option.xml create mode 100644 tests/phpunit/CiviTest/truncate-tag.xml create mode 100644 tests/phpunit/CiviTest/truncate-ufgroup.xml create mode 100644 tests/phpunit/CiviTest/truncate.xml create mode 100644 tests/phpunit/HelloTest.php create mode 100644 tests/phpunit/Utils.php create mode 100755 tests/phpunit/WebTest/ACL/AssignUsersToRolesTest.php create mode 100644 tests/phpunit/WebTest/Activity/ContactContextAddTest.php create mode 100644 tests/phpunit/WebTest/Activity/IcalTest.php create mode 100644 tests/phpunit/WebTest/Activity/StandaloneAddTest.php create mode 100644 tests/phpunit/WebTest/Admin/CustomAddTest.php create mode 100644 tests/phpunit/WebTest/Admin/Form/ScheduleReminderTest.php create mode 100644 tests/phpunit/WebTest/Admin/Form/Setting/LocalizationTest.php create mode 100644 tests/phpunit/WebTest/Admin/MoveCustomDataTest.php create mode 100644 tests/phpunit/WebTest/Admin/RelationshipTypeAddTest.php create mode 100644 tests/phpunit/WebTest/AllTests.php create mode 100644 tests/phpunit/WebTest/Campaign/ActivityTest.php create mode 100644 tests/phpunit/WebTest/Campaign/CampaignDescriptionTest.php create mode 100644 tests/phpunit/WebTest/Campaign/MailingTest.php create mode 100644 tests/phpunit/WebTest/Campaign/MembershipTest.php create mode 100644 tests/phpunit/WebTest/Campaign/OfflineContributionTest.php create mode 100644 tests/phpunit/WebTest/Campaign/OfflineEventRegistrationTest.php create mode 100644 tests/phpunit/WebTest/Campaign/OnlineContributionTest.php create mode 100644 tests/phpunit/WebTest/Campaign/OnlineEventRegistrationTest.php create mode 100644 tests/phpunit/WebTest/Campaign/PetitionUsageScenarioTest.php create mode 100644 tests/phpunit/WebTest/Campaign/PledgeTest.php create mode 100644 tests/phpunit/WebTest/Campaign/SurveyUsageScenarioTest.php create mode 100644 tests/phpunit/WebTest/Case/ActivityToCaseTest.php create mode 100644 tests/phpunit/WebTest/Case/AddCaseTest.php create mode 100644 tests/phpunit/WebTest/Case/CaseCustomFieldsTest.php create mode 100644 tests/phpunit/WebTest/Case/CaseDashboardTest.php create mode 100644 tests/phpunit/WebTest/Contact/AddCmsUserTest.php create mode 100644 tests/phpunit/WebTest/Contact/AddContactsToEventAdvancedSearchTest.php create mode 100644 tests/phpunit/WebTest/Contact/AddTest.php create mode 100644 tests/phpunit/WebTest/Contact/AddViaProfileTest.php create mode 100644 tests/phpunit/WebTest/Contact/AddressParsingTest.php create mode 100644 tests/phpunit/WebTest/Contact/AdvanceSearchPaneTest.php create mode 100644 tests/phpunit/WebTest/Contact/AdvanceSearchPrivacyOptionsTest.php create mode 100644 tests/phpunit/WebTest/Contact/AdvancedSearchTest.php create mode 100644 tests/phpunit/WebTest/Contact/AdvancedSearchedRelatedContactTest.php create mode 100644 tests/phpunit/WebTest/Contact/ContactReferenceFieldTest.php create mode 100644 tests/phpunit/WebTest/Contact/ContactTagTest.php create mode 100644 tests/phpunit/WebTest/Contact/CreateCmsUserFromContactTest.php create mode 100644 tests/phpunit/WebTest/Contact/CustomDataAddTest.php create mode 100644 tests/phpunit/WebTest/Contact/DeceasedContactsAdvancedSearchTest.php create mode 100644 tests/phpunit/WebTest/Contact/DupeContactTest.php create mode 100644 tests/phpunit/WebTest/Contact/GroupAddTest.php create mode 100644 tests/phpunit/WebTest/Contact/InlineFieldsEditTest.php create mode 100644 tests/phpunit/WebTest/Contact/MergeContactsTest.php create mode 100644 tests/phpunit/WebTest/Contact/MultipleContactSubTypes.php create mode 100644 tests/phpunit/WebTest/Contact/PrevNextTest.php create mode 100644 tests/phpunit/WebTest/Contact/PrivacyOptionSearchTest.php create mode 100644 tests/phpunit/WebTest/Contact/ProfileChecksumTest.php create mode 100644 tests/phpunit/WebTest/Contact/RelationshipAddTest.php create mode 100644 tests/phpunit/WebTest/Contact/SearchBuilderTest.php create mode 100644 tests/phpunit/WebTest/Contact/SearchTest.php create mode 100644 tests/phpunit/WebTest/Contact/SearchbyDateFilterTest.php create mode 100644 tests/phpunit/WebTest/Contact/SignatureTest.php create mode 100644 tests/phpunit/WebTest/Contact/TagAddTest.php create mode 100644 tests/phpunit/WebTest/Contact/TagSetSearchTest.php create mode 100644 tests/phpunit/WebTest/Contact/TaskActionAddToGroupTest.php create mode 100644 tests/phpunit/WebTest/Contact/TaskActionSendMassMailing.php create mode 100644 tests/phpunit/WebTest/Contact/TaskActionSendSMS.php create mode 100644 tests/phpunit/WebTest/Contact/UpdateProfileTest.php create mode 100644 tests/phpunit/WebTest/Contribute/AddBatchesTest.php create mode 100644 tests/phpunit/WebTest/Contribute/AddPricesetTest.php create mode 100644 tests/phpunit/WebTest/Contribute/ConfirmOptionalTest.php create mode 100644 tests/phpunit/WebTest/Contribute/ContactContextAddTest.php create mode 100644 tests/phpunit/WebTest/Contribute/ContributionPageAddTest.php create mode 100644 tests/phpunit/WebTest/Contribute/OfflineContributionTest.php create mode 100644 tests/phpunit/WebTest/Contribute/OfflineRecurContributionTest.php create mode 100644 tests/phpunit/WebTest/Contribute/OnBehalfOfOrganization.php create mode 100644 tests/phpunit/WebTest/Contribute/OnlineContributionTest.php create mode 100644 tests/phpunit/WebTest/Contribute/OnlineMultiplePaymentProcessorTest.php create mode 100644 tests/phpunit/WebTest/Contribute/OnlineRecurContributionTest.php create mode 100755 tests/phpunit/WebTest/Contribute/PCPAddTest.php create mode 100644 tests/phpunit/WebTest/Contribute/StandaloneAddTest.php create mode 100644 tests/phpunit/WebTest/Contribute/UpdateBatchPendingContributionTest.php create mode 100644 tests/phpunit/WebTest/Contribute/UpdateContributionTest.php create mode 100644 tests/phpunit/WebTest/Contribute/UpdatePendingContributionTest.php create mode 100644 tests/phpunit/WebTest/Contribute/VerifySSLContributionTest.php create mode 100644 tests/phpunit/WebTest/Event/AddEventTest.php create mode 100644 tests/phpunit/WebTest/Event/AddParticipationTest.php create mode 100644 tests/phpunit/WebTest/Event/AddPricesetTest.php create mode 100644 tests/phpunit/WebTest/Event/ChangeParticipantStatus.php create mode 100644 tests/phpunit/WebTest/Event/EventListingTest.php create mode 100644 tests/phpunit/WebTest/Event/EventWaitListTest.php create mode 100755 tests/phpunit/WebTest/Event/MultipleEventRegistrationbyCartTest.php create mode 100644 tests/phpunit/WebTest/Event/MultiprofileEventTest.php create mode 100644 tests/phpunit/WebTest/Event/PCPAddTest.php create mode 100644 tests/phpunit/WebTest/Event/ParticipantCountTest.php create mode 100644 tests/phpunit/WebTest/Event/ParticipantSearchTest.php create mode 100644 tests/phpunit/WebTest/Event/PricesetMaxCountTest.php create mode 100644 tests/phpunit/WebTest/Event/TellAFriendTest.php create mode 100644 tests/phpunit/WebTest/Export/ContactTest.php create mode 100644 tests/phpunit/WebTest/Export/ExportCiviSeleniumTestCase.php create mode 100644 tests/phpunit/WebTest/Financial/FinancialAccountTest.php create mode 100644 tests/phpunit/WebTest/Financial/FinancialAccountTypeTest.php create mode 100644 tests/phpunit/WebTest/Financial/FinancialBatchExport.php create mode 100644 tests/phpunit/WebTest/Generic/CheckActivityTest.php create mode 100644 tests/phpunit/WebTest/Generic/CheckDashboardTest.php create mode 100644 tests/phpunit/WebTest/Generic/CheckFindTest.php create mode 100644 tests/phpunit/WebTest/Generic/GeneralClickAroundTest.php create mode 100644 tests/phpunit/WebTest/Grant/ContactContextAddTest.php create mode 100644 tests/phpunit/WebTest/Grant/CustomFieldsetTest.php create mode 100644 tests/phpunit/WebTest/Grant/StandaloneAddTest.php create mode 100644 tests/phpunit/WebTest/Import/ActivityTest.php create mode 100644 tests/phpunit/WebTest/Import/AddressImportTest.php create mode 100644 tests/phpunit/WebTest/Import/AddressParsingTest.php create mode 100644 tests/phpunit/WebTest/Import/ContactCustomDataTest.php create mode 100644 tests/phpunit/WebTest/Import/ContactSubtypeTest.php create mode 100644 tests/phpunit/WebTest/Import/ContactTest.php create mode 100644 tests/phpunit/WebTest/Import/ContributionTest.php create mode 100644 tests/phpunit/WebTest/Import/CustomDataTest.php create mode 100644 tests/phpunit/WebTest/Import/DateFormatTest.php create mode 100644 tests/phpunit/WebTest/Import/DuplicateMatchingTest.php create mode 100644 tests/phpunit/WebTest/Import/GroupTest.php create mode 100644 tests/phpunit/WebTest/Import/ImportCiviSeleniumTestCase.php create mode 100644 tests/phpunit/WebTest/Import/MatchExternalIdTest.php create mode 100644 tests/phpunit/WebTest/Import/MemberTest.php create mode 100644 tests/phpunit/WebTest/Import/MultipleRelationshipTest.php create mode 100644 tests/phpunit/WebTest/Import/ParticipantTest.php create mode 100644 tests/phpunit/WebTest/Import/SavedMappingTest.php create mode 100644 tests/phpunit/WebTest/Import/TagTest.php create mode 100644 tests/phpunit/WebTest/Mailing/AddMessageTemplateTest.php create mode 100644 tests/phpunit/WebTest/Mailing/AddNewMailingComponentTest.php create mode 100644 tests/phpunit/WebTest/Mailing/MailingTest.php create mode 100644 tests/phpunit/WebTest/Mailing/SpoolTest.php create mode 100644 tests/phpunit/WebTest/Member/BatchUpdateViaProfileTest.php create mode 100644 tests/phpunit/WebTest/Member/ContactContextAddTest.php create mode 100755 tests/phpunit/WebTest/Member/DefaultMembershipPricesetTest.php create mode 100644 tests/phpunit/WebTest/Member/EditMembershipTest.php create mode 100644 tests/phpunit/WebTest/Member/FixedMembershipTypeTest.php create mode 100644 tests/phpunit/WebTest/Member/InheritedMembershipTest.php create mode 100644 tests/phpunit/WebTest/Member/OfflineAutoRenewMembershipTest.php create mode 100644 tests/phpunit/WebTest/Member/OfflineMembershipAddPricesetTest.php create mode 100644 tests/phpunit/WebTest/Member/OfflineMembershipRenewTest.php create mode 100644 tests/phpunit/WebTest/Member/OnlineAutoRenewMembershipGCTest.php create mode 100644 tests/phpunit/WebTest/Member/OnlineAutoRenewMembershipTest.php create mode 100644 tests/phpunit/WebTest/Member/OnlineMembershipAddPricesetTest.php create mode 100644 tests/phpunit/WebTest/Member/OnlineMembershipCreateTest.php create mode 100644 tests/phpunit/WebTest/Member/OnlineMembershipRenewTest.php create mode 100644 tests/phpunit/WebTest/Member/SeperateMembershipPaymentTest.php create mode 100644 tests/phpunit/WebTest/Member/StandaloneAddTest.php create mode 100644 tests/phpunit/WebTest/Member/UpdateMembershipScriptTest.php create mode 100644 tests/phpunit/WebTest/Pledge/ContactContextAddTest.php create mode 100644 tests/phpunit/WebTest/Pledge/ContactContextPledgePaymentAddTest.php create mode 100644 tests/phpunit/WebTest/Pledge/StandaloneAddDeleteTest.php create mode 100644 tests/phpunit/WebTest/Pledge/StandaloneAddTest.php create mode 100644 tests/phpunit/WebTest/Profile/BatchUpdateTest.php create mode 100644 tests/phpunit/WebTest/Profile/DedupeTest.php create mode 100644 tests/phpunit/WebTest/Profile/MultiRecordProfileAddTest.php create mode 100644 tests/phpunit/WebTest/Profile/ProfileAddTest.php create mode 100644 tests/phpunit/WebTest/Profile/ProfileGroupSubscriptionTest.php create mode 100644 tests/phpunit/WebTest/Profile/SearchTest.php create mode 100644 tests/phpunit/WebTest/README create mode 100644 tests/phpunit/WebTest/Release/InstallScript.php create mode 100644 tests/phpunit/WebTest/Release/ReleaseTestCase.php create mode 100644 tests/phpunit/WebTest/Release/UpgradeScript.php create mode 100644 tests/phpunit/WebTest/Report/AddTest.php create mode 100644 tests/phpunit/WebTest/Report/DonarReportTest.php create mode 100644 tests/phpunit/WebTest/Report/LoggingReportTest.php create mode 100644 tests/phpunit/WebTest/Report/RolePermissionReportTest.php create mode 100644 tests/phpunit/WebTest/resources/import/ImportActivityTestWHdrs.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportContactTestWHdrs.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportContribs1.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportContribs2.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportContribsExtID.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportContribs_custom.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportHouse_Update.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportHouseholds_WHdrs.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportIndiv_Update.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportOrgs_Update.csv create mode 100644 tests/phpunit/WebTest/resources/import/ImportOrgs_WHdrs.csv create mode 100644 tests/phpunit/WebTest/resources/import/Import_Participants.csv create mode 100644 tests/phpunit/api/v3/ACLPermissionTest.php create mode 100644 tests/phpunit/api/v3/APIStandardsTest.php create mode 100644 tests/phpunit/api/v3/APITest.php create mode 100644 tests/phpunit/api/v3/ActivityTest.php create mode 100644 tests/phpunit/api/v3/ActivityTypeTest.php create mode 100644 tests/phpunit/api/v3/AddressTest.php create mode 100644 tests/phpunit/api/v3/AllTests.php create mode 100644 tests/phpunit/api/v3/BatchTest.php create mode 100644 tests/phpunit/api/v3/CRM11793Test.php create mode 100644 tests/phpunit/api/v3/CampaignTest.php create mode 100644 tests/phpunit/api/v3/CaseTest.php create mode 100644 tests/phpunit/api/v3/ConstantTest.php create mode 100644 tests/phpunit/api/v3/ContactTest.php create mode 100644 tests/phpunit/api/v3/ContactTypeTest.php create mode 100644 tests/phpunit/api/v3/ContributionPageTest.php create mode 100644 tests/phpunit/api/v3/ContributionRecurTest.php create mode 100644 tests/phpunit/api/v3/ContributionTest.php create mode 100644 tests/phpunit/api/v3/CustomFieldTest.php create mode 100644 tests/phpunit/api/v3/CustomGroupTest.php create mode 100644 tests/phpunit/api/v3/CustomSearchTest.php create mode 100644 tests/phpunit/api/v3/CustomValueContactTypeTest.php create mode 100644 tests/phpunit/api/v3/CustomValueTest.php create mode 100644 tests/phpunit/api/v3/DomainTest.php create mode 100644 tests/phpunit/api/v3/EmailTest.php create mode 100644 tests/phpunit/api/v3/EntityTagTest.php create mode 100644 tests/phpunit/api/v3/EventTest.php create mode 100644 tests/phpunit/api/v3/GrantTest.php create mode 100644 tests/phpunit/api/v3/GroupContactTest.php create mode 100644 tests/phpunit/api/v3/GroupNestingTest.php create mode 100644 tests/phpunit/api/v3/GroupOrganizationTest.php create mode 100644 tests/phpunit/api/v3/GroupTest.php create mode 100644 tests/phpunit/api/v3/ImTest.php create mode 100644 tests/phpunit/api/v3/JobTest.php create mode 100644 tests/phpunit/api/v3/LineItemTest.php create mode 100644 tests/phpunit/api/v3/LocBlockTest.php create mode 100644 tests/phpunit/api/v3/MailSettingsTest.php create mode 100644 tests/phpunit/api/v3/MailingGroupTest.php create mode 100644 tests/phpunit/api/v3/MailingTest.php create mode 100644 tests/phpunit/api/v3/MembershipPaymentTest.php create mode 100644 tests/phpunit/api/v3/MembershipStatusTest.php create mode 100644 tests/phpunit/api/v3/MembershipTest.php create mode 100644 tests/phpunit/api/v3/MembershipTypeTest.php create mode 100644 tests/phpunit/api/v3/NoteTest.php create mode 100644 tests/phpunit/api/v3/OptionGroupTest.php create mode 100644 tests/phpunit/api/v3/OptionValueTest.php create mode 100644 tests/phpunit/api/v3/ParticipantPaymentTest.php create mode 100644 tests/phpunit/api/v3/ParticipantStatusTypeTest.php create mode 100644 tests/phpunit/api/v3/ParticipantTest.php create mode 100644 tests/phpunit/api/v3/PaymentProcessorTypeTest.php create mode 100644 tests/phpunit/api/v3/PhoneTest.php create mode 100644 tests/phpunit/api/v3/PledgePaymentTest.php create mode 100644 tests/phpunit/api/v3/PledgeTest.php create mode 100644 tests/phpunit/api/v3/PriceFieldTest.php create mode 100644 tests/phpunit/api/v3/PriceFieldValueTest.php create mode 100644 tests/phpunit/api/v3/PriceSetTest.php create mode 100644 tests/phpunit/api/v3/ProfileTest.php create mode 100644 tests/phpunit/api/v3/RelationshipTest.php create mode 100644 tests/phpunit/api/v3/RelationshipTypeTest.php create mode 100644 tests/phpunit/api/v3/ReportTemplateTest.php create mode 100644 tests/phpunit/api/v3/SettingTest.php create mode 100644 tests/phpunit/api/v3/SurveyRespondantTest.php create mode 100644 tests/phpunit/api/v3/SurveyTest.php create mode 100644 tests/phpunit/api/v3/SyntaxConformanceAllEntitiesTest.php create mode 100644 tests/phpunit/api/v3/SystemTest.php create mode 100644 tests/phpunit/api/v3/TagTest.php create mode 100644 tests/phpunit/api/v3/UFFieldTest.php create mode 100644 tests/phpunit/api/v3/UFGroupTest.php create mode 100644 tests/phpunit/api/v3/UFJoinTest.php create mode 100644 tests/phpunit/api/v3/UFMatchTest.php create mode 100644 tests/phpunit/api/v3/UtilsTest.php create mode 100644 tests/phpunit/api/v3/WebsiteTest.php create mode 100644 tests/phpunit/api/v3/dataset/acl_1_all.xml create mode 100644 tests/phpunit/api/v3/dataset/activity_1_emailed.xml create mode 100644 tests/phpunit/api/v3/dataset/activity_4_created.xml create mode 100644 tests/phpunit/api/v3/dataset/activity_email create mode 100644 tests/phpunit/api/v3/dataset/activity_email_unparseable create mode 100644 tests/phpunit/api/v3/dataset/activity_target_1_emailed.xml create mode 100644 tests/phpunit/api/v3/dataset/activity_type_5.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_1.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_17.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_hld.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_hld_upd.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_ind.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_ind_upd.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_org.xml create mode 100644 tests/phpunit/api/v3/dataset/contact_org_upd.xml create mode 100644 tests/phpunit/api/v3/dataset/contribution_types.xml create mode 100644 tests/phpunit/api/v3/dataset/custom_group_activity_type.xml create mode 100644 tests/phpunit/api/v3/dataset/email_contact_17.xml create mode 100644 tests/phpunit/api/v3/dataset/financial_accounts.xml create mode 100644 tests/phpunit/api/v3/dataset/financial_types.xml create mode 100644 tests/phpunit/api/v3/dataset/financial_types_account.xml create mode 100644 tests/phpunit/api/v3/dataset/group_admins.xml create mode 100644 tests/phpunit/api/v3/dataset/group_contact_admins_1.xml create mode 100644 tests/phpunit/api/v3/dataset/group_nesting.xml create mode 100644 tests/phpunit/api/v3/dataset/group_subscribers.xml create mode 100644 tests/phpunit/api/v3/dataset/location_type_data.xml create mode 100644 tests/phpunit/api/v3/dataset/openid.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_acl_role.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_activity.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_case.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_contribution_status.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_email_greeting.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_from_email_address.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_mail_protocol.xml create mode 100644 tests/phpunit/api/v3/dataset/option_group_phone_type.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_acl_roles.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_activity.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_case.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_case_activity.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_contribution_status.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_email_greeting.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_from_email_address.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_mail_protocol.xml create mode 100644 tests/phpunit/api/v3/dataset/option_value_phone_type.xml create mode 100644 tests/phpunit/api/v3/dataset/resolver/api/v3/Contact/ExampleAction2.php create mode 100644 tests/phpunit/api/v3/dataset/resolver/api/v3/Generic/ExampleAction1.php create mode 100644 tests/phpunit/api/v3/dataset/resolver/api/v3/Generic/ExampleAction2.php create mode 100644 tests/phpunit/api/v3/dataset/resolver/api/v3/TestEntity.php create mode 100644 tests/phpunit/api/v3/dataset/uf_field_uf_group_25.xml create mode 100644 tests/phpunit/api/v3/dataset/uf_group_25.xml create mode 100644 tests/phpunit/api/v3/dataset/uf_group_contact_activity_26.xml create mode 100644 tests/phpunit/api/v3/dataset/uf_group_test.xml create mode 100644 tests/phpunit/custom_directories/templates/CRM/Case/xml/configuration/AdultDayCareReferral.xml create mode 100644 tests/phpunit/custom_directories/templates/CRM/Case/xml/configuration/HousingSupport.xml create mode 100644 tests/phpunit/custom_directories/templates/CRM/Case/xml/configuration/Settings.xml create mode 100644 tests/qunit/README.txt create mode 100644 tests/qunit/example/test.js create mode 100644 tests/qunit/example/test.php create mode 100644 tests/qunit/profile-editor/test.js create mode 100644 tests/qunit/profile-editor/test.php create mode 100644 tests/templates/documentFunction.tpl create mode 100644 tools/CRM/Auction/BAO/Auction.php create mode 100644 tools/CRM/Auction/BAO/Item.php create mode 100644 tools/CRM/Auction/Config.php create mode 100644 tools/CRM/Auction/Controller/Item.php create mode 100644 tools/CRM/Auction/Form/Auction.php create mode 100644 tools/CRM/Auction/Form/Item.php create mode 100644 tools/CRM/Auction/Form/ItemAccount.php create mode 100644 tools/CRM/Auction/Form/SearchAuction.php create mode 100644 tools/CRM/Auction/Form/SearchItem.php create mode 100644 tools/CRM/Auction/Info.php create mode 100644 tools/CRM/Auction/Page/AddItem.php create mode 100644 tools/CRM/Auction/Page/DashBoard.php create mode 100644 tools/CRM/Auction/Page/Item.php create mode 100644 tools/CRM/Auction/Page/Manage.php create mode 100644 tools/CRM/Auction/Page/ManageItem.php create mode 100644 tools/CRM/Auction/StateMachine/Item.php create mode 100644 tools/CRM/Auction/xml/Menu/Auction.xml create mode 100644 tools/CRM/Touchstone/Config.php create mode 100644 tools/CRM/Touchstone/Info.php create mode 100644 tools/CRM/Touchstone/PseudoConstant.php create mode 100644 tools/CRM/Touchstone/Task.php create mode 100644 tools/bin/scripts/ImportTags.php create mode 100644 tools/bin/scripts/NormalizePhone.php create mode 100644 tools/bin/scripts/README.txt create mode 100644 tools/bin/scripts/ajax.php create mode 100644 tools/bin/scripts/cli.php create mode 100755 tools/bin/scripts/createdoc.sh create mode 100644 tools/bin/scripts/delete.sh create mode 100755 tools/bin/scripts/drop-closing-php-tags.sh create mode 100755 tools/bin/scripts/ircbot-civi.py create mode 100644 tools/bin/scripts/memcache.php create mode 100644 tools/bin/scripts/postIPN.sh create mode 100755 tools/bin/scripts/replace.sh create mode 100755 tools/bin/scripts/runCPSTest.sh create mode 100755 tools/bin/scripts/runStressTest.sh.txt create mode 100755 tools/bin/scripts/runTest.sh create mode 100644 tools/bin/scripts/soapClient.php.txt create mode 100755 tools/bin/scripts/syncPackages.sh create mode 100644 tools/bin/scripts/testProcess.php create mode 100755 tools/bin/scripts/test_sandbox.sh create mode 100644 tools/bin/scripts/updateNameCache.php create mode 100644 tools/drupal/modules/ccrm_extensionvalidation/ccrm_extensionvalidation/ccrm_extensionvalidation.info create mode 100644 tools/drupal/modules/ccrm_extensionvalidation/ccrm_extensionvalidation/ccrm_extensionvalidation.module create mode 100644 tools/drupal/modules/ccrm_extensionvalidation/ccrm_extensionvalidation/ccrm_extensionvalidation.test create mode 100644 tools/drupal/modules/ccrm_extensionvalidation/ccrm_extensionvalidation/ccrm_extensionvalidation.version.inc create mode 100644 tools/drupal/modules/civicrm_ICIRR/ICIRR/Form/Profile.php create mode 100644 tools/drupal/modules/civicrm_ICIRR/civicrm_ICIRR.info create mode 100644 tools/drupal/modules/civicrm_ICIRR/civicrm_ICIRR.module create mode 100644 tools/drupal/modules/civicrm_ICIRR/templates/CRM/Activity/Form/Activity.extra.tpl create mode 100644 tools/drupal/modules/civicrm_ICIRR/templates/CRM/Activity/Form/Activity.tpl create mode 100644 tools/drupal/modules/civicrm_ICIRR/templates/ICIRR/Form/Profile.tpl create mode 100644 tools/drupal/modules/civicrm_NYSS/civicrm_NYSS.info create mode 100644 tools/drupal/modules/civicrm_NYSS/civicrm_NYSS.module create mode 100644 tools/drupal/modules/civicrm_NYSS/sql/civicrm_NYSS.mysql create mode 100644 tools/drupal/modules/civicrm_giftaid/CustomGroupData.xml create mode 100644 tools/drupal/modules/civicrm_giftaid/GiftAid/Form/Task/AddToGiftAid.php create mode 100644 tools/drupal/modules/civicrm_giftaid/GiftAid/Report/Form/Contribute/GiftAid.php create mode 100644 tools/drupal/modules/civicrm_giftaid/GiftAid/Utils/Contribution.php create mode 100644 tools/drupal/modules/civicrm_giftaid/GiftAid/Utils/GiftAid.php create mode 100644 tools/drupal/modules/civicrm_giftaid/GiftAid/Utils/Hook.php create mode 100644 tools/drupal/modules/civicrm_giftaid/README create mode 100644 tools/drupal/modules/civicrm_giftaid/civicrm_giftaid.admin.inc create mode 100755 tools/drupal/modules/civicrm_giftaid/civicrm_giftaid.info create mode 100644 tools/drupal/modules/civicrm_giftaid/civicrm_giftaid.install create mode 100644 tools/drupal/modules/civicrm_giftaid/civicrm_giftaid.module create mode 100644 tools/drupal/modules/civicrm_giftaid/templates/GiftAid/Form/Task/AddToGiftAid.tpl create mode 100644 tools/drupal/modules/civicrm_giftaid/templates/GiftAid/Report/Form/Contribute/GiftAid.tpl create mode 100644 tools/drupal/modules/civicrm_giftaid/tests/DeclarationTest.php create mode 100644 tools/drupal/modules/civicrm_giftaid_alpha/CustomGroupData.xml create mode 100755 tools/drupal/modules/civicrm_giftaid_alpha/civicrm_giftaid_alpha.info create mode 100644 tools/drupal/modules/civicrm_giftaid_alpha/civicrm_giftaid_alpha.module create mode 100644 tools/drupal/modules/civicrm_professionals/civicrm_professionals.info create mode 100644 tools/drupal/modules/civicrm_professionals/civicrm_professionals.module create mode 100644 tools/drupal/modules/civicrm_regsite/civicrm_regsite.info create mode 100644 tools/drupal/modules/civicrm_regsite/civicrm_regsite.module create mode 100644 tools/drupal/modules/civicrm_regsite/templates/CRM/Profile/Form/15/Edit.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/CRM/Profile/Form/Survey/Edit.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/CRM/Profile/Page/Regsite/Dynamic.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/CRM/Profile/Page/Survey/Dynamic.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/Mail/RegSite/Message.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/Mail/RegSite/Subject.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/Mail/Survey/Message.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/templates/Mail/Survey/Subject.tpl create mode 100644 tools/drupal/modules/civicrm_regsite/xml/CustomGroupData.xml create mode 100644 tools/drupal/modules/civicrm_van/VAN/Auth.php create mode 100644 tools/drupal/modules/civicrm_van/VAN/Contact.php create mode 100644 tools/drupal/modules/civicrm_van/VAN/Person.php create mode 100644 tools/drupal/modules/civicrm_van/VAN/apiKey.php.txt create mode 100644 tools/drupal/modules/civicrm_van/civicrm_van.info create mode 100644 tools/drupal/modules/civicrm_van/civicrm_van.module create mode 100644 tools/drupal/modules/civicrm_van/run.php create mode 100644 tools/drupal/modules/civicrm_van/xml/CustomGroupData.xml create mode 100644 tools/drupal/modules/civicrm_webtest/civicrm_webtest.info create mode 100644 tools/drupal/modules/civicrm_webtest/civicrm_webtest.install create mode 100644 tools/drupal/modules/civicrm_webtest/civicrm_webtest.module create mode 100644 tools/drupal/modules/extdir/extdir.info create mode 100644 tools/drupal/modules/extdir/extdir.module create mode 100644 tools/drupal/modules/extdir/extdir.pages.inc create mode 100644 tools/drupal/modules/extdir/extdir_list.tpl.php create mode 100755 tools/drupal/modules/multicurrency/multicurrency.info create mode 100644 tools/drupal/modules/multicurrency/multicurrency.module create mode 100644 tools/drupal/modules/multicurrency/multicurrency.module.discount create mode 100644 tools/drupal/modules/multicurrency/multicurrency.module.original create mode 100644 tools/drupal/modules/multicurrency/templates/CRM/Event/Form/Registration/4/Register.tpl create mode 100644 tools/drupal/modules/multicurrency/templates/CRM/Event/Form/Registration/8/Register.tpl create mode 100644 tools/drupal/modules/multicurrency/templates/CRM/Event/Page/4/EventInfo.tpl create mode 100644 tools/drupal/modules/multicurrency/templates/CRM/Event/Page/8/EventInfo.tpl create mode 100644 tools/extensions/org.civicrm.demoqueue/CRM/Demoqueue/Page/DemoQueue.php create mode 100644 tools/extensions/org.civicrm.demoqueue/CRM/Demoqueue/Page/DemoQueueDone.php create mode 100644 tools/extensions/org.civicrm.demoqueue/demoqueue.civix.php create mode 100644 tools/extensions/org.civicrm.demoqueue/demoqueue.php create mode 100644 tools/extensions/org.civicrm.demoqueue/info.xml create mode 100644 tools/extensions/org.civicrm.demoqueue/templates/CRM/Demoqueue/Page/DemoQueue.tpl create mode 100644 tools/extensions/org.civicrm.demoqueue/templates/CRM/Demoqueue/Page/DemoQueueDone.tpl create mode 100644 tools/extensions/org.civicrm.demoqueue/xml/Menu/demoqueue.xml create mode 100644 tools/extensions/org.civicrm.multisite.zip create mode 100644 tools/extensions/org.civicrm.multisite/api/v3/MultisiteDomain/Create.php create mode 100644 tools/extensions/org.civicrm.multisite/info.xml create mode 100644 tools/extensions/org.civicrm.multisite/multisite.civix.php create mode 100644 tools/extensions/org.civicrm.multisite/multisite.php create mode 100644 tools/extensions/org.civicrm.multisite/settings/Multisite.setting.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout.zip create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/GoogleCheckout.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/GoogleIPN.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/googleNotify.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/info.xml create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/README create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/demo/cartdemo.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/demo/responsehandlerdemo.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googlecart.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googleitem.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googlemerchantcalculations.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googleresponse.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googleresult.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googleshipping.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googletaxrule.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/googletaxtable.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/xml-processing/xmlbuilder.php create mode 100644 tools/extensions/org.civicrm.payment.googlecheckout/packages/Google/library/xml-processing/xmlparser.php create mode 100755 tools/extensions/org.civicrm.report.baykeeper/Baykeeper.php create mode 100644 tools/extensions/org.civicrm.report.baykeeper/templates/Baykeeper.tpl create mode 100644 tools/extensions/org.civicrm.report.grant.zip create mode 100644 tools/extensions/org.civicrm.report.grant/Grant.php create mode 100644 tools/extensions/org.civicrm.report.grant/info.xml create mode 100644 tools/extensions/org.civicrm.report.grant/templates/Grant.tpl create mode 100644 tools/extensions/org.civicrm.search.activity.zip create mode 100644 tools/extensions/org.civicrm.search.activity/ActivitySearch.php create mode 100644 tools/extensions/org.civicrm.search.activity/info.xml create mode 100644 tools/extensions/org.civicrm.search.activity/templates/ActivitySearch.tpl create mode 100644 tools/extensions/org.civicrm.search.basic.zip create mode 100644 tools/extensions/org.civicrm.search.basic/Basic.php create mode 100644 tools/extensions/org.civicrm.search.basic/info.xml create mode 100644 tools/extensions/org.civicrm.search.multivalue.zip create mode 100644 tools/extensions/org.civicrm.search.multivalue/MultiValue.php create mode 100644 tools/extensions/org.civicrm.search.multivalue/info.xml create mode 100644 tools/extensions/org.civicrm.search.multivalue/templates/MultipleValues.tpl create mode 100644 tools/extensions/org.civicrm.sms.clickatell.zip create mode 100644 tools/extensions/org.civicrm.sms.clickatell/clickatell.civix.php create mode 100644 tools/extensions/org.civicrm.sms.clickatell/clickatell.php create mode 100644 tools/extensions/org.civicrm.sms.clickatell/info.xml create mode 100644 tools/extensions/org.civicrm.sms.clickatell/org_civicrm_sms_clickatell.php create mode 100644 tools/extensions/org.civicrm.sms.twilio.zip create mode 100644 tools/extensions/org.civicrm.sms.twilio/info.xml create mode 100644 tools/extensions/org.civicrm.sms.twilio/org_civicrm_sms_twilio.php create mode 100644 tools/extensions/org.civicrm.sms.twilio/twilio.civix.php create mode 100644 tools/extensions/org.civicrm.sms.twilio/twilio.php create mode 100644 tools/scripts/build.xml create mode 100644 tools/scripts/civimail-spooler/civimail-spooler.php create mode 100644 tools/scripts/csv-generator/csv_generator.php create mode 100755 tools/scripts/mk-drupal-test-site create mode 100755 tools/scripts/phpdoc create mode 100755 tools/scripts/phpunit create mode 100755 tools/scripts/phpunit-jenkins create mode 100644 tools/scripts/phpunit-xslt/coverage-frames.xsl create mode 100644 tools/scripts/phpunit-xslt/log.xsl create mode 100644 tools/scripts/phpunit-xslt/phpunit-frames.xsl create mode 100644 tools/scripts/phpunit-xslt/phpunit-noframes.xsl create mode 100644 tools/scripts/phpunit-xslt/str.replace.function.xsl create mode 100644 tools/scripts/phpunit.xml create mode 100755 tools/scripts/procmail/original-to.pl create mode 100644 tools/scripts/release-testing/schemaverificationtest.sh create mode 100644 tools/scripts/release-testing/simpleupgradetest.sh create mode 100644 tools/scripts/release-testing/upgrader.sh.txt create mode 100755 tools/scripts/releaser/build-tarballs create mode 100755 tools/scripts/runTests.sh.txt create mode 100644 tools/scripts/solr/createMigrationTable.sql create mode 100644 tools/scripts/solr/createSolrJSON.php create mode 100644 tools/scripts/solr/createSolrXML.php create mode 100644 tools/scripts/solr/createSyncJSON.php create mode 100644 tools/scripts/solr/database.xml create mode 100644 tools/scripts/solr/schema.xml create mode 100644 tools/scripts/solr/solrconfig.xml create mode 100755 tools/scripts/upgrade-test/run-upgrade-test.sh create mode 100644 tools/sites/latest/robots.txt create mode 100644 tools/sites/latest/stable.php create mode 100644 tools/sites/stats/graphs.php create mode 100644 tools/sites/stats/index.php create mode 100644 tools/sites/stats/robots.txt create mode 100644 tools/sites/stats/stats.php create mode 100644 tools/sql/civiauction_sample.mysql create mode 100644 tools/templates/CRM/Auction/Form/Auction.tpl create mode 100644 tools/templates/CRM/Auction/Form/Item.tpl create mode 100644 tools/templates/CRM/Auction/Form/ItemAccount.tpl create mode 100644 tools/templates/CRM/Auction/Form/SearchAuction.tpl create mode 100644 tools/templates/CRM/Auction/Form/SearchItem.tpl create mode 100644 tools/templates/CRM/Auction/Page/DashBoard.tpl create mode 100644 tools/templates/CRM/Auction/Page/Item.tpl create mode 100644 tools/templates/CRM/Auction/Page/Manage.tpl create mode 100644 tools/templates/CRM/Auction/Page/ManageItem.tpl create mode 100644 tools/templates/CRM/Touchstone/Form/Search/AdvancedSearchPane.tpl create mode 100644 tools/tests/reports/index.html create mode 100644 tools/xml/schema/Auction/Auction.xml create mode 100644 tools/xml/schema/Auction/Bid.xml create mode 100644 tools/xml/schema/Auction/Item.xml create mode 100644 tools/xml/schema/Auction/files.xml create mode 100644 xml/GenCode.php create mode 100644 xml/configuration/AdultDayCareReferral.xml create mode 100644 xml/configuration/HousingSupport.xml create mode 100644 xml/configuration/Settings.xml create mode 100644 xml/plugins/block.ts.php create mode 100644 xml/schema/ACL/ACL.xml create mode 100644 xml/schema/ACL/Cache.xml create mode 100644 xml/schema/ACL/EntityRole.xml create mode 100644 xml/schema/ACL/files.xml create mode 100644 xml/schema/Activity/Activity.xml create mode 100644 xml/schema/Activity/ActivityAssignment.xml create mode 100644 xml/schema/Activity/ActivityContact.xml create mode 100644 xml/schema/Activity/ActivityTarget.xml create mode 100644 xml/schema/Activity/files.xml create mode 100644 xml/schema/Batch/Batch.xml create mode 100644 xml/schema/Batch/EntityBatch.xml create mode 100644 xml/schema/Batch/files.xml create mode 100644 xml/schema/Bridge/OG.xml create mode 100644 xml/schema/Bridge/Role.xml create mode 100644 xml/schema/Bridge/files.xml create mode 100644 xml/schema/Campaign/Campaign.xml create mode 100644 xml/schema/Campaign/CampaignGroup.xml create mode 100644 xml/schema/Campaign/Survey.xml create mode 100644 xml/schema/Campaign/files.xml create mode 100644 xml/schema/Case/Case.xml create mode 100644 xml/schema/Case/CaseActivity.xml create mode 100644 xml/schema/Case/CaseContact.xml create mode 100644 xml/schema/Case/files.xml create mode 100644 xml/schema/Contact/ACLContactCache.xml create mode 100644 xml/schema/Contact/Contact.xml create mode 100644 xml/schema/Contact/ContactType.xml create mode 100644 xml/schema/Contact/DashboardContact.xml create mode 100644 xml/schema/Contact/Group.xml create mode 100644 xml/schema/Contact/GroupContact.xml create mode 100644 xml/schema/Contact/GroupContactCache.xml create mode 100644 xml/schema/Contact/GroupNesting.xml create mode 100644 xml/schema/Contact/GroupOrganization.xml create mode 100644 xml/schema/Contact/Household.xml create mode 100644 xml/schema/Contact/Individual.xml create mode 100644 xml/schema/Contact/Organization.xml create mode 100644 xml/schema/Contact/Relationship.xml create mode 100644 xml/schema/Contact/RelationshipType.xml create mode 100644 xml/schema/Contact/SavedSearch.xml create mode 100644 xml/schema/Contact/SubscriptionHistory.xml create mode 100644 xml/schema/Contact/files.xml create mode 100644 xml/schema/Contribute/Contribution.xml create mode 100644 xml/schema/Contribute/ContributionPage.xml create mode 100644 xml/schema/Contribute/ContributionProduct.xml create mode 100644 xml/schema/Contribute/ContributionRecur.xml create mode 100644 xml/schema/Contribute/ContributionSoft.xml create mode 100644 xml/schema/Contribute/Premium.xml create mode 100644 xml/schema/Contribute/PremiumsProduct.xml create mode 100644 xml/schema/Contribute/Product.xml create mode 100644 xml/schema/Contribute/Widget.xml create mode 100644 xml/schema/Contribute/files.xml create mode 100644 xml/schema/Core/ActionLog.xml create mode 100644 xml/schema/Core/ActionMapping.xml create mode 100644 xml/schema/Core/ActionSchedule.xml create mode 100644 xml/schema/Core/Address.xml create mode 100644 xml/schema/Core/AddressFormat.xml create mode 100644 xml/schema/Core/Cache.xml create mode 100644 xml/schema/Core/Component.xml create mode 100644 xml/schema/Core/Country.xml create mode 100644 xml/schema/Core/County.xml create mode 100644 xml/schema/Core/CustomField.xml create mode 100644 xml/schema/Core/CustomGroup.xml create mode 100644 xml/schema/Core/Dashboard.xml create mode 100644 xml/schema/Core/Discount.xml create mode 100644 xml/schema/Core/Domain.xml create mode 100644 xml/schema/Core/Email.xml create mode 100644 xml/schema/Core/EntityFile.xml create mode 100644 xml/schema/Core/EntityTag.xml create mode 100644 xml/schema/Core/Extension.xml create mode 100644 xml/schema/Core/File.xml create mode 100644 xml/schema/Core/IM.xml create mode 100644 xml/schema/Core/Job.xml create mode 100644 xml/schema/Core/JobLog.xml create mode 100644 xml/schema/Core/LocBlock.xml create mode 100644 xml/schema/Core/LocationType.xml create mode 100644 xml/schema/Core/Log.xml create mode 100644 xml/schema/Core/MailSettings.xml create mode 100644 xml/schema/Core/Managed.xml create mode 100644 xml/schema/Core/Mapping.xml create mode 100644 xml/schema/Core/MappingField.xml create mode 100644 xml/schema/Core/Menu.xml create mode 100644 xml/schema/Core/MessageTemplate.xml create mode 100644 xml/schema/Core/Navigation.xml create mode 100644 xml/schema/Core/Note.xml create mode 100644 xml/schema/Core/OpenID.xml create mode 100644 xml/schema/Core/OptionGroup.xml create mode 100644 xml/schema/Core/OptionValue.xml create mode 100644 xml/schema/Core/Persistent.xml create mode 100644 xml/schema/Core/Phone.xml create mode 100644 xml/schema/Core/Preferences.xml create mode 100644 xml/schema/Core/PreferencesDate.xml create mode 100644 xml/schema/Core/PrevNextCache.xml create mode 100644 xml/schema/Core/Setting.xml create mode 100644 xml/schema/Core/StateProvince.xml create mode 100644 xml/schema/Core/Tag.xml create mode 100644 xml/schema/Core/Timezone.xml create mode 100644 xml/schema/Core/UFField.xml create mode 100644 xml/schema/Core/UFGroup.xml create mode 100644 xml/schema/Core/UFJoin.xml create mode 100644 xml/schema/Core/UFMatch.xml create mode 100644 xml/schema/Core/Website.xml create mode 100644 xml/schema/Core/Worldregion.xml create mode 100644 xml/schema/Core/files.xml create mode 100644 xml/schema/Dedupe/Exception.xml create mode 100644 xml/schema/Dedupe/Rule.xml create mode 100644 xml/schema/Dedupe/RuleGroup.xml create mode 100644 xml/schema/Dedupe/files.xml create mode 100644 xml/schema/Event/Cart/Cart.xml create mode 100644 xml/schema/Event/Cart/EventInCart.xml create mode 100644 xml/schema/Event/Cart/files.xml create mode 100644 xml/schema/Event/Event.xml create mode 100644 xml/schema/Event/EventPage.xml create mode 100644 xml/schema/Event/Participant.xml create mode 100644 xml/schema/Event/ParticipantPayment.xml create mode 100644 xml/schema/Event/ParticipantStatusType.xml create mode 100644 xml/schema/Event/files.xml create mode 100644 xml/schema/Financial/Currency.xml create mode 100755 xml/schema/Financial/EntityFinancialAccount.xml create mode 100755 xml/schema/Financial/EntityFinancialTrxn.xml create mode 100644 xml/schema/Financial/FinancialAccount.xml create mode 100644 xml/schema/Financial/FinancialItem.xml create mode 100755 xml/schema/Financial/FinancialTrxn.xml create mode 100644 xml/schema/Financial/FinancialType.xml create mode 100644 xml/schema/Financial/PaymentProcessor.xml create mode 100644 xml/schema/Financial/PaymentProcessorType.xml create mode 100755 xml/schema/Financial/Receipt.xml create mode 100644 xml/schema/Financial/files.xml create mode 100644 xml/schema/Friend/Friend.xml create mode 100644 xml/schema/Friend/files.xml create mode 100644 xml/schema/GccSchema.xml create mode 100644 xml/schema/Grant/Grant.xml create mode 100644 xml/schema/Grant/files.xml create mode 100644 xml/schema/Mailing/BouncePattern.xml create mode 100644 xml/schema/Mailing/BounceType.xml create mode 100644 xml/schema/Mailing/Component.xml create mode 100644 xml/schema/Mailing/Event/Bounce.xml create mode 100644 xml/schema/Mailing/Event/Confirm.xml create mode 100644 xml/schema/Mailing/Event/Delivered.xml create mode 100644 xml/schema/Mailing/Event/Forward.xml create mode 100644 xml/schema/Mailing/Event/Opened.xml create mode 100644 xml/schema/Mailing/Event/Queue.xml create mode 100644 xml/schema/Mailing/Event/Reply.xml create mode 100644 xml/schema/Mailing/Event/Subscribe.xml create mode 100644 xml/schema/Mailing/Event/TrackableURLOpen.xml create mode 100644 xml/schema/Mailing/Event/Unsubscribe.xml create mode 100644 xml/schema/Mailing/Event/files.xml create mode 100644 xml/schema/Mailing/Group.xml create mode 100644 xml/schema/Mailing/Job.xml create mode 100644 xml/schema/Mailing/Mailing.xml create mode 100644 xml/schema/Mailing/Recipients.xml create mode 100644 xml/schema/Mailing/Spool.xml create mode 100644 xml/schema/Mailing/TrackableURL.xml create mode 100644 xml/schema/Mailing/files.xml create mode 100644 xml/schema/Member/Membership.xml create mode 100644 xml/schema/Member/MembershipBlock.xml create mode 100644 xml/schema/Member/MembershipLog.xml create mode 100644 xml/schema/Member/MembershipPayment.xml create mode 100644 xml/schema/Member/MembershipStatus.xml create mode 100644 xml/schema/Member/MembershipType.xml create mode 100644 xml/schema/Member/files.xml create mode 100644 xml/schema/PCP/PCP.xml create mode 100644 xml/schema/PCP/PCPBlock.xml create mode 100644 xml/schema/PCP/files.xml create mode 100644 xml/schema/Pledge/Pledge.xml create mode 100644 xml/schema/Pledge/PledgeBlock.xml create mode 100644 xml/schema/Pledge/PledgePayment.xml create mode 100644 xml/schema/Pledge/files.xml create mode 100644 xml/schema/Price/Field.xml create mode 100644 xml/schema/Price/FieldValue.xml create mode 100644 xml/schema/Price/LineItem.xml create mode 100644 xml/schema/Price/Set.xml create mode 100644 xml/schema/Price/SetEntity.xml create mode 100644 xml/schema/Price/files.xml create mode 100644 xml/schema/Project/Project.xml create mode 100644 xml/schema/Project/Task.xml create mode 100644 xml/schema/Project/TaskStatus.xml create mode 100644 xml/schema/Project/files.xml create mode 100644 xml/schema/QuestSchema.xml create mode 100644 xml/schema/Queue/QueueItem.xml create mode 100644 xml/schema/Queue/files.xml create mode 100644 xml/schema/Report/Instance.xml create mode 100644 xml/schema/Report/files.xml create mode 100644 xml/schema/SMS/History.xml create mode 100644 xml/schema/SMS/Provider.xml create mode 100644 xml/schema/SMS/files.xml create mode 100644 xml/schema/Schema.xml create mode 100644 xml/schema/Standalone/OpenID/Associations.xml create mode 100644 xml/schema/Standalone/OpenID/Nonces.xml create mode 100644 xml/schema/Standalone/OpenID/files.xml create mode 100644 xml/templates/access.tpl create mode 100644 xml/templates/civicrm_acl.tpl create mode 100644 xml/templates/civicrm_country.tpl create mode 100644 xml/templates/civicrm_currency.tpl create mode 100644 xml/templates/civicrm_data.tpl create mode 100644 xml/templates/civicrm_msg_template.tpl create mode 100644 xml/templates/civicrm_navigation.tpl create mode 100644 xml/templates/civicrm_sample.tpl create mode 100644 xml/templates/civicrm_state_province.tpl create mode 100644 xml/templates/civicrm_version.tpl create mode 100644 xml/templates/dao.tpl create mode 100644 xml/templates/drop.tpl create mode 100644 xml/templates/joomla.tpl create mode 100644 xml/templates/languages.tpl create mode 100644 xml/templates/message_templates/case_activity_html.tpl create mode 100644 xml/templates/message_templates/case_activity_subject.tpl create mode 100644 xml/templates/message_templates/case_activity_text.tpl create mode 100644 xml/templates/message_templates/contribution_dupalert_html.tpl create mode 100644 xml/templates/message_templates/contribution_dupalert_subject.tpl create mode 100644 xml/templates/message_templates/contribution_dupalert_text.tpl create mode 100644 xml/templates/message_templates/contribution_offline_receipt_html.tpl create mode 100644 xml/templates/message_templates/contribution_offline_receipt_subject.tpl create mode 100644 xml/templates/message_templates/contribution_offline_receipt_text.tpl create mode 100644 xml/templates/message_templates/contribution_online_receipt_html.tpl create mode 100644 xml/templates/message_templates/contribution_online_receipt_subject.tpl create mode 100644 xml/templates/message_templates/contribution_online_receipt_text.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_billing_html.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_billing_subject.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_billing_text.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_cancelled_html.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_cancelled_subject.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_cancelled_text.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_edit_html.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_edit_subject.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_edit_text.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_notify_html.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_notify_subject.tpl create mode 100644 xml/templates/message_templates/contribution_recurring_notify_text.tpl create mode 100644 xml/templates/message_templates/event_offline_receipt_html.tpl create mode 100644 xml/templates/message_templates/event_offline_receipt_subject.tpl create mode 100644 xml/templates/message_templates/event_offline_receipt_text.tpl create mode 100644 xml/templates/message_templates/event_online_receipt_html.tpl create mode 100644 xml/templates/message_templates/event_online_receipt_subject.tpl create mode 100644 xml/templates/message_templates/event_online_receipt_text.tpl create mode 100644 xml/templates/message_templates/event_registration_receipt_html.tpl create mode 100644 xml/templates/message_templates/event_registration_receipt_subject.tpl create mode 100644 xml/templates/message_templates/event_registration_receipt_text.tpl create mode 100644 xml/templates/message_templates/friend_html.tpl create mode 100644 xml/templates/message_templates/friend_subject.tpl create mode 100644 xml/templates/message_templates/friend_text.tpl create mode 100644 xml/templates/message_templates/grant_approved_html.tpl create mode 100644 xml/templates/message_templates/grant_approved_subject.tpl create mode 100644 xml/templates/message_templates/grant_approved_text.tpl create mode 100644 xml/templates/message_templates/grant_awaiting_info_html.tpl create mode 100644 xml/templates/message_templates/grant_awaiting_info_subject.tpl create mode 100644 xml/templates/message_templates/grant_awaiting_info_text.tpl create mode 100644 xml/templates/message_templates/grant_paid_html.tpl create mode 100644 xml/templates/message_templates/grant_paid_subject.tpl create mode 100644 xml/templates/message_templates/grant_paid_text.tpl create mode 100644 xml/templates/message_templates/grant_rejected_html.tpl create mode 100644 xml/templates/message_templates/grant_rejected_subject.tpl create mode 100644 xml/templates/message_templates/grant_rejected_text.tpl create mode 100644 xml/templates/message_templates/grant_submitted_html.tpl create mode 100644 xml/templates/message_templates/grant_submitted_subject.tpl create mode 100644 xml/templates/message_templates/grant_submitted_text.tpl create mode 100644 xml/templates/message_templates/membership_autorenew_billing_html.tpl create mode 100644 xml/templates/message_templates/membership_autorenew_billing_subject.tpl create mode 100644 xml/templates/message_templates/membership_autorenew_billing_text.tpl create mode 100644 xml/templates/message_templates/membership_autorenew_cancelled_html.tpl create mode 100644 xml/templates/message_templates/membership_autorenew_cancelled_subject.tpl create mode 100644 xml/templates/message_templates/membership_autorenew_cancelled_text.tpl create mode 100644 xml/templates/message_templates/membership_offline_receipt_html.tpl create mode 100644 xml/templates/message_templates/membership_offline_receipt_subject.tpl create mode 100644 xml/templates/message_templates/membership_offline_receipt_text.tpl create mode 100644 xml/templates/message_templates/membership_online_receipt_html.tpl create mode 100644 xml/templates/message_templates/membership_online_receipt_subject.tpl create mode 100644 xml/templates/message_templates/membership_online_receipt_text.tpl create mode 100644 xml/templates/message_templates/participant_cancelled_html.tpl create mode 100644 xml/templates/message_templates/participant_cancelled_subject.tpl create mode 100644 xml/templates/message_templates/participant_cancelled_text.tpl create mode 100644 xml/templates/message_templates/participant_confirm_html.tpl create mode 100644 xml/templates/message_templates/participant_confirm_subject.tpl create mode 100644 xml/templates/message_templates/participant_confirm_text.tpl create mode 100644 xml/templates/message_templates/participant_expired_html.tpl create mode 100644 xml/templates/message_templates/participant_expired_subject.tpl create mode 100644 xml/templates/message_templates/participant_expired_text.tpl create mode 100644 xml/templates/message_templates/pcp_notify_html.tpl create mode 100644 xml/templates/message_templates/pcp_notify_subject.tpl create mode 100644 xml/templates/message_templates/pcp_notify_text.tpl create mode 100644 xml/templates/message_templates/pcp_status_change_html.tpl create mode 100644 xml/templates/message_templates/pcp_status_change_subject.tpl create mode 100644 xml/templates/message_templates/pcp_status_change_text.tpl create mode 100644 xml/templates/message_templates/pcp_supporter_notify_html.tpl create mode 100644 xml/templates/message_templates/pcp_supporter_notify_subject.tpl create mode 100644 xml/templates/message_templates/pcp_supporter_notify_text.tpl create mode 100644 xml/templates/message_templates/petition_confirmation_needed_html.tpl create mode 100644 xml/templates/message_templates/petition_confirmation_needed_subject.tpl create mode 100644 xml/templates/message_templates/petition_confirmation_needed_text.tpl create mode 100644 xml/templates/message_templates/petition_sign_html.tpl create mode 100644 xml/templates/message_templates/petition_sign_subject.tpl create mode 100644 xml/templates/message_templates/petition_sign_text.tpl create mode 100644 xml/templates/message_templates/pledge_acknowledge_html.tpl create mode 100644 xml/templates/message_templates/pledge_acknowledge_subject.tpl create mode 100644 xml/templates/message_templates/pledge_acknowledge_text.tpl create mode 100644 xml/templates/message_templates/pledge_reminder_html.tpl create mode 100644 xml/templates/message_templates/pledge_reminder_subject.tpl create mode 100644 xml/templates/message_templates/pledge_reminder_text.tpl create mode 100644 xml/templates/message_templates/test_preview_html.tpl create mode 100644 xml/templates/message_templates/test_preview_subject.tpl create mode 100644 xml/templates/message_templates/test_preview_text.tpl create mode 100644 xml/templates/message_templates/uf_notify_html.tpl create mode 100644 xml/templates/message_templates/uf_notify_subject.tpl create mode 100644 xml/templates/message_templates/uf_notify_text.tpl create mode 100644 xml/templates/schema.tpl create mode 100644 xml/templates/schema_structure.tpl create mode 100644 xml/version.xml diff --git a/CRM/ACL/API.php b/CRM/ACL/API.php new file mode 100644 index 0000000000..d470c80bca --- /dev/null +++ b/CRM/ACL/API.php @@ -0,0 +1,207 @@ +get('userID'); + } + + if (!$contactID) { + // anonymous user + $contactID = 0; + } + + return CRM_ACL_BAO_ACL::check($str, $contactID); + } + + /** + * Get the permissioned where clause for the user + * + * @param int $type the type of permission needed + * @param array $tables (reference ) add the tables that are needed for the select clause + * @param array $whereTables (reference ) add the tables that are needed for the where clause + * @param int $contactID the contactID for whom the check is made + * @param bool $onlyDeleted whether to include only deleted contacts + * @param bool $skipDeleteClause don't add delete clause if this is true, + * this means it is handled by generating query + * + * @return string the group where clause for this user + * @access public + */ + public static function whereClause($type, + &$tables, + &$whereTables, + $contactID = NULL, + $onlyDeleted = FALSE, + $skipDeleteClause = FALSE + ) { + // the default value which is valid for rhe final AND + $deleteClause = ' ( 1 ) '; + if (!$skipDeleteClause) { + if (CRM_Core_Permission::check('access deleted contacts') and $onlyDeleted) { + $deleteClause = '(contact_a.is_deleted)'; + } + else { + // CRM-6181 + $deleteClause = '(contact_a.is_deleted = 0)'; + } + } + + // first see if the contact has edit / view all contacts + if (CRM_Core_Permission::check('edit all contacts') || + ($type == self::VIEW && + CRM_Core_Permission::check('view all contacts') + ) + ) { + return $skipDeleteClause ? ' ( 1 ) ' : $deleteClause; + } + + if ($contactID == NULL) { + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + } + + if (!$contactID) { + // anonymous user + $contactID = 0; + } + + return implode(' AND ', + array( + CRM_ACL_BAO_ACL::whereClause($type, + $tables, + $whereTables, + $contactID + ), + $deleteClause, + ) + ); + } + + /** + * get all the groups the user has access to for the given operation + * + * @param int $type the type of permission needed + * @param int $contactID the contactID for whom the check is made + * + * @return array the ids of the groups for which the user has permissions + * @access public + */ + public static function group( + $type, + $contactID = NULL, + $tableName = 'civicrm_saved_search', + $allGroups = NULL, + $includedGroups = NULL + ) { + if ($contactID == NULL) { + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + } + + if (!$contactID) { + // anonymous user + $contactID = 0; + } + + return CRM_ACL_BAO_ACL::group($type, $contactID, $tableName, $allGroups, $includedGroups); + } + + /** + * check if the user has access to this group for operation $type + * + * @param int $type the type of permission needed + * @param int $contactID the contactID for whom the check is made + * + * @return array the ids of the groups for which the user has permissions + * @access public + */ + public static function groupPermission( + $type, + $groupID, + $contactID = NULL, + $tableName = 'civicrm_saved_search', + $allGroups = NULL, + $includedGroups = NULL + ) { + static $cache = array(); + + if (!$contactID) { + $session = CRM_Core_Session::singleton(); + $contactID = NULL; + if ($session->get('userID')) { + $contactID = $session->get('userID'); + } + } + + $key = "{$tableName}_{$type}_{$contactID}"; + if (array_key_exists($key, $cache)) { + $groups = &$cache[$key]; + } + else { + $groups = self::group($type, $contactID, $tableName, $allGroups, $includedGroups); + $cache[$key] = $groups; + } + + return in_array($groupID, $groups) ? TRUE : FALSE; + } +} + diff --git a/CRM/ACL/BAO/ACL.php b/CRM/ACL/BAO/ACL.php new file mode 100644 index 0000000000..53e01fa48c --- /dev/null +++ b/CRM/ACL/BAO/ACL.php @@ -0,0 +1,934 @@ + ts('Contact'), + 'civicrm_acl_role' => ts('ACL Role'), + ); + } + return self::$_entityTable; + } + + static function objectTable() { + if (!self::$_objectTable) { + self::$_objectTable = array( + 'civicrm_contact' => ts('Contact'), + 'civicrm_group' => ts('Group'), + 'civicrm_saved_search' => ts('Contact Group'), + 'civicrm_admin' => ts('Administer'), + 'civicrm_admin' => ts('Import'), + ); + } + return self::$_objectTable; + } + + static function operation() { + if (!self::$_operation) { + self::$_operation = array( + 'View' => ts('View'), + 'Edit' => ts('Edit'), + 'Create' => ts('Create'), + 'Delete' => ts('Delete'), + 'Search' => ts('Search'), + 'All' => ts('All'), + ); + } + return self::$_operation; + } + + /** + * Construct a WHERE clause to handle permissions to $object_* + * + * @param array ref $tables - Any tables that may be needed in the FROM + * @param string $operation - The operation being attempted + * @param string $object_table - The table of the object in question + * @param int $object_id - The ID of the object in question + * @param int $acl_id - If it's a grant/revoke operation, the ACL ID + * @param boolean $acl_role - For grant operations, this flag determines if we're granting a single acl (false) or an entire group. + * + * @return string - The WHERE clause, or 0 on failure + * @access public + * @static + */ + public static function permissionClause(&$tables, $operation, + $object_table = NULL, $object_id = NULL, + $acl_id = NULL, $acl_role = FALSE + ) { + $dao = new CRM_ACL_DAO_ACL; + + $t = array( + 'ACL' => self::getTableName(), + 'ACLRole' => 'civicrm_acl_role', + 'ACLEntityRole' => CRM_ACL_DAO_EntityRole::getTableName(), + 'Contact' => CRM_Contact_DAO_Contact::getTableName(), + 'Group' => CRM_Contact_DAO_Group::getTableName(), + 'GroupContact' => CRM_Contact_DAO_GroupContact::getTableName(), + ); + + $session = CRM_Core_Session::singleton(); + $contact_id = $session->get('userID'); + + $where = " {$t['ACL']}.operation = '" . CRM_Utils_Type::escape($operation, 'String') . "'"; + + /* Include clause if we're looking for a specific table/id permission */ + + + if (!empty($object_table)) { + $where .= " AND ( {$t['ACL']}.object_table IS null + OR ({$t['ACL']}.object_table = '" . CRM_Utils_Type::escape($object_table, 'String') . "'"; + if (!empty($object_id)) { + $where .= " AND ({$t['ACL']}.object_id IS null + OR {$t['ACL']}.object_id = " . CRM_Utils_Type::escape($object_id, 'Integer') . ')'; + } + $where .= '))'; + } + + /* Include clause if we're granting an ACL or ACL Role */ + + + if (!empty($acl_id)) { + $where .= " AND ({$t['ACL']}.acl_id IS null + OR {$t['ACL']}.acl_id = " . CRM_Utils_Type::escape($acl_id, 'Integer') . ')'; + if ($acl_role) { + $where .= " AND {$t['ACL']}.acl_table = '{$t['ACLRole']}'"; + } + else { + $where .= " AND {$t['ACL']}.acl_table = '{$t['ACL']}'"; + } + } + + $query = array(); + + /* Query for permissions granted to all contacts in the domain */ + + + $query[] = "SELECT {$t['ACL']}.*, 0 as override + FROM {$t['ACL']} + + WHERE {$t['ACL']}.entity_table = '{$t['Domain']}' + AND ($where)"; + + /* Query for permissions granted to all contacts through an ACL group */ + + + $query[] = "SELECT {$t['ACL']}.*, 0 as override + FROM {$t['ACL']} + + INNER JOIN {$t['ACLEntityRole']} + ON ({$t['ACL']}.entity_table = '{$t['ACLRole']}' + AND {$t['ACL']}.entity_id = + {$t['ACLEntityRole']}.acl_role_id) + + INNER JOIN {$t['ACLRole']} + ON {$t['ACL']}.entity_id = + {$t['ACLRole']}.id + + WHERE {$t['ACLEntityRole']}.entity_table = + '{$t['Domain']}' + AND {$t['ACLRole']}.is_active = 1 + AND ($where)"; + + /* Query for permissions granted directly to the contact */ + + + $query[] = "SELECT {$t['ACL']}.*, 1 as override + FROM {$t['ACL']} + + INNER JOIN {$t['Contact']} + ON ({$t['ACL']}.entity_table = '{$t['Contact']}' + AND {$t['ACL']}.entity_id = {$t['Contact']}.id) + + WHERE {$t['Contact']}.id = $contact_id + AND ($where)"; + + /* Query for permissions granted to the contact through an ACL group */ + + + $query[] = "SELECT {$t['ACL']}.*, 1 as override + FROM {$t['ACL']} + + INNER JOIN {$t['ACLEntityRole']} + ON ({$t['ACL']}.entity_table = '{$t['ACLRole']}' + AND {$t['ACL']}.entity_id = + {$t['ACLEntityRole']}.acl_role_id) + + INNER JOIN {$t['ACLRole']} + ON {$t['ACL']}.entity_id = {$t['ACLRole']}.id + + WHERE {$t['ACLEntityRole']}.entity_table = + '{$t['Contact']}' + AND {$t['ACLRole']}.is_active = 1 + AND {$t['ACLEntityRole']}.entity_id = $contact_id + AND ($where)"; + + /* Query for permissions granted to the contact through a group */ + + + $query[] = "SELECT {$t['ACL']}.*, 0 as override + FROM {$t['ACL']} + + INNER JOIN {$t['GroupContact']} + ON ({$t['ACL']}.entity_table = '{$t['Group']}' + AND {$t['ACL']}.entity_id = + {$t['GroupContact']}.group_id) + + WHERE ($where) + AND {$t['GroupContact']}.contact_id = $contact_id + AND {$t['GroupContact']}.status = 'Added')"; + + + /* Query for permissions granted through an ACL group to a Contact + * group */ + + + $query[] = "SELECT {$t['ACL']}.*, 0 as override + FROM {$t['ACL']} + + INNER JOIN {$t['ACLEntityRole']} + ON ({$t['ACL']}.entity_table = '{$t['ACLRole']}' + AND {$t['ACL']}.entity_id = + {$t['ACLEntityRole']}.acl_role_id) + + INNER JOIN {$t['ACLRole']} + ON {$t['ACL']}.entity_id = {$t['ACLRole']}.id + + INNER JOIN {$t['GroupContact']} + ON ({$t['ACLEntityRole']}.entity_table = + '{$t['Group']}' + AND {$t['ACLEntityRole']}.entity_id = + {$t['GroupContact']}.group_id) + + WHERE ($where) + AND {$t['ACLRole']}.is_active = 1 + AND {$t['GroupContact']}.contact_id = $contact_id + AND {$t['GroupContact']}.status = 'Added'"; + + $union = '(' . implode(') UNION DISTINCT (', $query) . ')'; + + $dao->query($union); + + $allow = array(0); + $deny = array(0); + $override = array(); + + while ($dao->fetch()) { + /* Instant bypass for the following cases: + * 1) the rule governs all tables + * 2) the rule governs all objects in the table in question + * 3) the rule governs the specific object we want + */ + + + if (empty($dao->object_table) || + ($dao->object_table == $object_table + && (empty($dao->object_id) + || $dao->object_id == $object_id + ) + ) + ) { + $clause = 1; + } + else { + /* Otherwise try to generate a clause for this rule */ + + + $clause = self::getClause( + $dao->object_table, $dao->object_id, $tables + ); + + /* If the clause returned is null, then the rule is a blanket + * (id is null) on a table other than the one we're interested + * in. So skip it. */ + + + if (empty($clause)) { + continue; + } + } + + /* Now we figure out if this is an allow or deny rule, and possibly + * a contact-level override */ + + + if ($dao->deny) { + $deny[] = $clause; + } + else { + $allow[] = $clause; + + if ($dao->override) { + $override[] = $clause; + } + } + } + + $allows = '(' . implode(' OR ', $allow) . ')'; + $denies = '(' . implode(' OR ', $deny) . ')'; + if (!empty($override)) { + $denies = '(NOT (' . implode(' OR ', $override) . ") AND $denies)"; + } + + return "($allows AND NOT $denies)"; + } + + /** + * Given a table and id pair, return the filter clause + * + * @param string $table - The table owning the object + * @param int $id - The ID of the object + * @param array ref $tables - Tables that will be needed in the FROM + * + * @return string|null - WHERE-style clause to filter results, + or null if $table or $id is null + * @access public + * @static + */ + public static function getClause($table, $id, &$tables) { + $table = CRM_Utils_Type::escape($table, 'String'); + $id = CRM_Utils_Type::escape($id, 'Integer'); + $whereTables = array(); + + $ssTable = CRM_Contact_BAO_SavedSearch::getTableName(); + + if (empty($table)) { + return NULL; + } + elseif ($table == $ssTable) { + return CRM_Contact_BAO_SavedSearch::whereClause($id, $tables, $whereTables); + } + elseif (!empty($id)) { + $tables[$table] = TRUE; + return "$table.id = $id"; + } + return NULL; + } + + /** + * Construct an associative array of an ACL rule's properties + * + * @param string sprintf format for array + * @param bool empty only return elemnts that have a value set. + * + * @return array - Assoc. array of the ACL rule's properties + * @access public + */ + function toArray($format = '%s', $hideEmpty = false) { + $result = array(); + + if (!self::$_fieldKeys) { + $fields = CRM_ACL_DAO_ACL::fields(); + self::$_fieldKeys = array_keys($fields); + } + + foreach (self::$_fieldKeys as $field) { + $result[$field] = $this->$field; + } + return $result; + } + + /** + * Retrieve ACLs for a contact or group. Note that including a contact id + * without a group id will return those ACL rules which are granted + * directly to the contact, but not those granted to the contact through + * any/all of his group memberships. + * + * @param int $contact_id - ID of a contact to search for + * @param int $group_id - ID of a group to search for + * @param boolean $aclRoles - Should we include ACL Roles + * + * @return array - Array of assoc. arrays of ACL rules + * @access public + * @static + */ + public static function &getACLs($contact_id = NULL, $group_id = NULL, $aclRoles = FALSE) { + $results = array(); + + if (empty($contact_id)) { + return $results; + } + + $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer'); + if ($group_id) { + $group_id = CRM_Utils_Type::escape($group_id, 'Integer'); + } + + $rule = new CRM_ACL_BAO_ACL(); + + + $acl = self::getTableName(); + $contact = CRM_Contact_BAO_Contact::getTableName(); + $c2g = CRM_Contact_BAO_GroupContact::getTableName(); + $group = CRM_Contact_BAO_Group::getTableName(); + + $query = " SELECT $acl.* + FROM $acl "; + + if (!empty($group_id)) { + $query .= " INNER JOIN $c2g + ON $acl.entity_id = $c2g.group_id + WHERE $acl.entity_table = '$group' + AND $acl.is_active = 1 + AND $c2g.group_id = $group_id"; + + if (!empty($contact_id)) { + $query .= " AND $c2g.contact_id = $contact_id + AND $c2g.status = 'Added'"; + } + } + else { + if (!empty($contact_id)) { + $query .= " WHERE $acl.entity_table = '$contact' + AND $acl.entity_id = $contact_id"; + } + } + + $rule->query($query); + + while ($rule->fetch()) { + $results[$rule->id] = $rule->toArray(); + } + + if ($aclRoles) { + $results += self::getACLRoles($contact_id, $group_id); + } + + return $results; + } + + /** + * Get all of the ACLs through ACL groups + * + * @param int $contact_id - ID of a contact to search for + * @param int $group_id - ID of a group to search for + * + * @return array - Array of assoc. arrays of ACL rules + * @access public + * @static + */ + public static function &getACLRoles($contact_id = NULL, $group_id = NULL) { + $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer'); + if ($group_id) { + $group_id = CRM_Utils_Type::escape($group_id, 'Integer'); + } + + $rule = new CRM_ACL_BAO_ACL(); + + $acl = self::getTableName(); + $aclRole = 'civicrm_acl_role'; + $aclRoleJoin = CRM_ACL_DAO_EntityRole::getTableName(); + $contact = CRM_Contact_BAO_Contact::getTableName(); + $c2g = CRM_Contact_BAO_GroupContact::getTableName(); + $group = CRM_Contact_BAO_Group::getTableName(); + + $query = " SELECT $acl.* + FROM $acl + INNER JOIN civicrm_option_group og + ON og.name = 'acl_role' + INNER JOIN civicrm_option_value ov + ON $acl.entity_table = '$aclRole' + AND ov.option_group_id = og.id + AND $acl.entity_id = ov.value"; + + if (!empty($group_id)) { + $query .= " INNER JOIN $c2g + ON $acl.entity_id = $c2g.group_id + WHERE $acl.entity_table = '$group' + AND $acl.is_active = 1 + AND $c2g.group_id = $group_id"; + + if (!empty($contact_id)) { + $query .= " AND $c2g.contact_id = $contact_id + AND $c2g.status = 'Added'"; + } + } + else { + if (!empty($contact_id)) { + $query .= " WHERE $acl.entity_table = '$contact' + AND $acl.is_active = 1 + AND $acl.entity_id = $contact_id"; + } + } + + $results = array(); + + $rule->query($query); + + while ($rule->fetch()) { + $results[$rule->id] = &$rule->toArray(); + } + + return $results; + } + + /** + * Get all ACLs granted to a contact through all group memberships + * + * @param int $contact_id - The contact's ID + * @param boolean $aclRoles - Include ACL Roles? + * + * @return array - Assoc array of ACL rules + * @access public + * @static + */ + public static function &getGroupACLs($contact_id, $aclRoles = FALSE) { + $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer'); + + $rule = new CRM_ACL_BAO_ACL(); + + + $acl = self::getTableName(); + $c2g = CRM_Contact_BAO_GroupContact::getTableName(); + $group = CRM_Contact_BAO_Group::getTableName(); + $results = array(); + + if ($contact_id) { + $query = " +SELECT $acl.* + FROM $acl + INNER JOIN $c2g + ON $acl.entity_id = $c2g.group_id + WHERE $acl.entity_table = '$group' + AND $c2g.contact_id = $contact_id + AND $c2g.status = 'Added'"; + + $rule->query($query); + + while ($rule->fetch()) { + $results[$rule->id] = &$rule->toArray(); + } + } + + if ($aclRoles) { + $results += self::getGroupACLRoles($contact_id); + } + + return $results; + } + + /** + * Get all of the ACLs for a contact through ACL groups owned by Contact + * groups. + * + * @param int $contact_id - ID of a contact to search for + * + * @return array - Array of assoc. arrays of ACL rules + * @access public + * @static + */ + public static function &getGroupACLRoles($contact_id) { + $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer'); + + $rule = new CRM_ACL_BAO_ACL(); + + $acl = self::getTableName(); + $aclRole = 'civicrm_acl_role'; + + + $aclER = CRM_ACL_DAO_EntityRole::getTableName(); + $c2g = CRM_Contact_BAO_GroupContact::getTableName(); + $group = CRM_Contact_BAO_Group::getTableName(); + + $query = " SELECT $acl.* + FROM $acl + INNER JOIN civicrm_option_group og + ON og.name = 'acl_role' + INNER JOIN civicrm_option_value ov + ON $acl.entity_table = '$aclRole' + AND ov.option_group_id = og.id + AND $acl.entity_id = ov.value + AND ov.is_active = 1 + INNER JOIN $aclER + ON $aclER.acl_role_id = $acl.entity_id + AND $aclER.is_active = 1 + INNER JOIN $c2g + ON $aclER.entity_id = $c2g.group_id + AND $aclER.entity_table = 'civicrm_group' + WHERE $acl.entity_table = '$aclRole' + AND $acl.is_active = 1 + AND $c2g.contact_id = $contact_id + AND $c2g.status = 'Added'"; + + $results = array(); + + $rule->query($query); + + while ($rule->fetch()) { + $results[$rule->id] = &$rule->toArray(); + } + + // also get all acls for "Any Role" case + // and authenticated User Role if present + $roles = "0"; + $session = CRM_Core_Session::singleton(); + if ($session->get('ufID') > 0) { + $roles .= ",2"; + } + + $query = " +SELECT $acl.* + FROM $acl + WHERE $acl.entity_id IN ( $roles ) + AND $acl.entity_table = 'civicrm_acl_role' +"; + + $rule->query($query); + while ($rule->fetch()) { + $results[$rule->id] = $rule->toArray(); + } + + return $results; + } + + /** + * Get all ACLs owned by a given contact, including domain and group-level. + * + * @param int $contact_id - The contact ID + * + * @return array - Assoc array of ACL rules + * @access public + * @static + */ + public static function &getAllByContact($contact_id) { + $result = array(); + + /* First, the contact-specific ACLs, including ACL Roles */ + $result += self::getACLs($contact_id, NULL, TRUE); + + /* Then, all ACLs granted through group membership */ + $result += self::getGroupACLs($contact_id, TRUE); + + return $result; + } + + static function create(&$params) { + $dao = new CRM_ACL_DAO_ACL(); + $dao->copyValues($params); + $dao->save(); + } + + static function retrieve(&$params, &$defaults) { + CRM_Core_DAO::commonRetrieve('CRM_ACL_DAO_ACL', $params, $defaults); + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + // note this also resets any ACL cache + CRM_Core_BAO_Cache::deleteGroup('contact fields'); + + return CRM_Core_DAO::setFieldValue('CRM_ACL_DAO_ACL', $id, 'is_active', $is_active); + } + + static function check($str, $contactID) { + + $acls = CRM_ACL_BAO_Cache::build($contactID); + + $aclKeys = array_keys($acls); + $aclKeys = implode(',', $aclKeys); + + if (empty($aclKeys)) { + return FALSE; + } + + + $query = " +SELECT count( a.id ) + FROM civicrm_acl_cache c, civicrm_acl a + WHERE c.acl_id = a.id + AND a.is_active = 1 + AND a.object_table = %1 + AND a.id IN ( $aclKeys ) +"; + $params = array(1 => array($str, 'String')); + + $count = CRM_Core_DAO::singleValueQuery($query, $params); + return ($count) ? TRUE : FALSE; + } + + public static function whereClause($type, &$tables, &$whereTables, $contactID = NULL) { + + $acls = CRM_ACL_BAO_Cache::build($contactID); + //CRM_Core_Error::debug( "a: $contactID", $acls ); + + $whereClause = NULL; + $clauses = array(); + + if (!empty($acls)) { + $aclKeys = array_keys($acls); + $aclKeys = implode(',', $aclKeys); + + $query = " +SELECT a.operation, a.object_id + FROM civicrm_acl_cache c, civicrm_acl a + WHERE c.acl_id = a.id + AND a.is_active = 1 + AND a.object_table = 'civicrm_saved_search' + AND a.id IN ( $aclKeys ) +ORDER BY a.object_id +"; + + $dao = CRM_Core_DAO::executeQuery($query); + + // do an or of all the where clauses u see + $ids = array(); + while ($dao->fetch()) { + // make sure operation matches the type TODO + if (self::matchType($type, $dao->operation)) { + if (!$dao->object_id) { + $ids = array(); + $whereClause = ' ( 1 ) '; + break; + } + $ids[] = $dao->object_id; + } + } + + if (!empty($ids)) { + $ids = implode(',', $ids); + $query = " +SELECT g.* + FROM civicrm_group g + WHERE g.id IN ( $ids ) + AND g.is_active = 1 +"; + $dao = CRM_Core_DAO::executeQuery($query); + $staticGroupIDs = array(); + $cachedGroupIDs = array(); + while ($dao->fetch()) { + // currently operation is restrcited to VIEW/EDIT + if ($dao->where_clause) { + if ($dao->select_tables) { + $tmpTables = array(); + foreach (unserialize($dao->select_tables) as $tmpName => $tmpInfo) { + if ($tmpName == '`civicrm_group_contact-' . $dao->id . '`') { + $tmpName = '`civicrm_group_contact-ACL`'; + $tmpInfo = str_replace('civicrm_group_contact-' . $dao->id, 'civicrm_group_contact-ACL', $tmpInfo); + } + elseif ($tmpName == '`civicrm_group_contact_cache_' . $dao->id . '`') { + $tmpName = '`civicrm_group_contact_cache-ACL`'; + $tmpInfo = str_replace('civicrm_group_contact_cache_' . $dao->id, 'civicrm_group_contact_cache-ACL', $tmpInfo); + } + $tmpTables[$tmpName] = $tmpInfo; + } + $tables = array_merge($tables, + $tmpTables + ); + } + if ($dao->where_tables) { + $tmpTables = array(); + foreach (unserialize($dao->where_tables) as $tmpName => $tmpInfo) { + if ($tmpName == '`civicrm_group_contact-' . $dao->id . '`') { + $tmpName = '`civicrm_group_contact-ACL`'; + $tmpInfo = str_replace('civicrm_group_contact-' . $dao->id, 'civicrm_group_contact-ACL', $tmpInfo); + $staticGroupIDs[] = $dao->id; + } + elseif ($tmpName == '`civicrm_group_contact_cache_' . $dao->id . '`') { + $tmpName = '`civicrm_group_contact_cache-ACL`'; + $tmpInfo = str_replace('civicrm_group_contact_cache_' . $dao->id, 'civicrm_group_contact_cache-ACL', $tmpInfo); + $cachedGroupIDs[] = $dao->id; + } + $tmpTables[$tmpName] = $tmpInfo; + } + $whereTables = array_merge($whereTables, $tmpTables); + } + } + + if (($dao->saved_search_id || $dao->children || $dao->parents) && + $dao->cache_date == NULL) { + CRM_Contact_BAO_GroupContactCache::load($dao); + } + } + + if ($staticGroupIDs) { + $clauses[] = '( `civicrm_group_contact-ACL`.group_id IN (' . join(', ', $staticGroupIDs) . ') AND `civicrm_group_contact-ACL`.status IN ("Added") )'; + } + + if ($cachedGroupIDs) { + $clauses[] = '`civicrm_group_contact_cache-ACL`.group_id IN (' . join(', ', $cachedGroupIDs) . ')'; + } + } + } + + if (!empty($clauses)) { + $whereClause = ' ( ' . implode(' OR ', $clauses) . ' ) '; + } + + // call the hook to get additional whereClauses + CRM_Utils_Hook::aclWhereClause($type, $tables, $whereTables, $contactID, $whereClause); + + if (empty($whereClause)) { + $whereClause = ' ( 0 ) '; + } + + return $whereClause; + } + + public static function group($type, + $contactID = NULL, + $tableName = 'civicrm_saved_search', + $allGroups = NULL, + $includedGroups = NULL + ) { + + $acls = CRM_ACL_BAO_Cache::build($contactID); + + if (!empty($includedGroups) && + is_array($includedGroups) + ) { + $ids = $includedGroups; + } + else { + $ids = array(); + } + + if (!empty($acls)) { + $aclKeys = array_keys($acls); + $aclKeys = implode(',', $aclKeys); + + $query = " +SELECT a.operation, a.object_id + FROM civicrm_acl_cache c, civicrm_acl a + WHERE c.acl_id = a.id + AND a.is_active = 1 + AND a.object_table = %1 + AND a.id IN ( $aclKeys ) +GROUP BY a.operation,a.object_id +ORDER BY a.object_id +"; + $params = array(1 => array($tableName, 'String')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + while ($dao->fetch()) { + if ($dao->object_id) { + if (self::matchType($type, $dao->operation)) { + $ids[] = $dao->object_id; + } + } + else { + // this user has got the permission for all objects of this type + // check if the type matches + if (self::matchType($type, $dao->operation)) { + foreach ($allGroups as $id => $dontCare) { + $ids[] = $id; + } + } + break; + } + } + } + + CRM_Utils_Hook::aclGroup($type, $contactID, $tableName, $allGroups, $ids); + + return $ids; + } + + static function matchType($type, $operation) { + $typeCheck = FALSE; + switch ($operation) { + case 'All': + $typeCheck = TRUE; + break; + + case 'View': + if ($type == CRM_ACL_API::VIEW) { + $typeCheck = TRUE; + } + break; + + case 'Edit': + if ($type == CRM_ACL_API::VIEW || $type == CRM_ACL_API::EDIT) { + $typeCheck = TRUE; + } + break; + + case 'Create': + if ($type == CRM_ACL_API::CREATE) { + $typeCheck = TRUE; + } + break; + + case 'Delete': + if ($type == CRM_ACL_API::DELETE) { + $typeCheck = TRUE; + } + break; + + case 'Search': + if ($type == CRM_ACL_API::SEARCH) { + $typeCheck = TRUE; + } + break; + } + return $typeCheck; + } + + /** + * Function to delete ACL records + * + * @param int $aclId ID of the ACL record to be deleted. + * + * @access public + * @static + */ + static function del($aclId) { + // delete all entries from the acl cache + CRM_ACL_BAO_Cache::resetCache(); + + $acl = new CRM_ACL_DAO_ACL(); + $acl->id = $aclId; + $acl->delete(); + } +} + diff --git a/CRM/ACL/BAO/Cache.php b/CRM/ACL/BAO/Cache.php new file mode 100644 index 0000000000..7a3313bbf4 --- /dev/null +++ b/CRM/ACL/BAO/Cache.php @@ -0,0 +1,148 @@ + array($id, 'Integer')); + + if ($id == 0) { + $query .= " OR contact_id IS NULL"; + } + + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $cache = array(); + while ($dao->fetch()) { + $cache[$dao->acl_id] = 1; + } + return $cache; + } + + static function store($id, &$cache) { + foreach ($cache as $aclID => $data) { + $dao = new CRM_ACL_DAO_Cache(); + if ($id) { + $dao->contact_id = $id; + } + $dao->acl_id = $aclID; + + $cache[$aclID] = 1; + + $dao->save(); + } + } + + static function deleteEntry($id) { + if (self::$_cache && + array_key_exists($id, self::$_cache) + ) { + unset(self::$_cache[$id]); + } + + $query = " +DELETE FROM civicrm_acl_cache +WHERE contact_id = %1 +"; + $params = array(1 => array($id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + } + + static function updateEntry($id) { + // rebuilds civicrm_acl_cache + self::deleteEntry($id); + self::build($id); + + // rebuilds civicrm_acl_contact_cache + CRM_Contact_BAO_Contact_Permission::cache($id, CRM_Core_Permission::VIEW, TRUE); + } + + // deletes all the cache entries + static function resetCache() { + // reset any static caching + self::$_cache = NULL; + + // reset any db caching + $config = CRM_Core_Config::singleton(); + $smartGroupCacheTimeout = CRM_Contact_BAO_GroupContactCache::smartGroupCacheTimeout(); + + //make sure to give original timezone settings again. + $now = CRM_Utils_Date::getUTCTime(); + + $query = " +DELETE +FROM civicrm_acl_cache +WHERE modified_date IS NULL + OR (TIMESTAMPDIFF(MINUTE, modified_date, $now) >= $smartGroupCacheTimeout) +"; + CRM_Core_DAO::singleValueQuery($query); + + CRM_Core_DAO::singleValueQuery("TRUNCATE TABLE civicrm_acl_contact_cache"); + } +} + diff --git a/CRM/ACL/BAO/EntityRole.php b/CRM/ACL/BAO/EntityRole.php new file mode 100644 index 0000000000..ee6859c3a2 --- /dev/null +++ b/CRM/ACL/BAO/EntityRole.php @@ -0,0 +1,93 @@ + ts('Contact'), + 'civicrm_group' => ts('Group'), + ); + } + return self::$_entityTable; + } + + static function create(&$params) { + $dao = new CRM_ACL_DAO_EntityRole(); + $dao->copyValues($params); + + $dao->save(); + } + + static function retrieve(&$params, &$defaults) { + CRM_Core_DAO::commonRetrieve('CRM_ACL_DAO_EntityRole', $params, $defaults); + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_ACL_DAO_EntityRole', $id, 'is_active', $is_active); + } + + /** + * Function to delete Entity Role records + * + * @param int $entityRoleId ID of the EntityRole record to be deleted. + * + * @access public + * @static + */ + static function del($entityRoleId) { + $entityDAO = new CRM_ACL_DAO_EntityRole(); + $entityDAO->id = $entityRoleId; + $entityDAO->find(TRUE); + $entityDAO->delete(); + } +} + diff --git a/CRM/ACL/Form/ACL.php b/CRM/ACL/Form/ACL.php new file mode 100644 index 0000000000..44de99cb01 --- /dev/null +++ b/CRM/ACL/Form/ACL.php @@ -0,0 +1,312 @@ +_action & CRM_Core_Action::ADD) { + $defaults['object_type'] = 1; + } + + $showHide = new CRM_Core_ShowHideBlocks(); + + if (isset($defaults['object_table'])) { + switch ($defaults['object_table']) { + case 'civicrm_saved_search': + $defaults['group_id'] = $defaults['object_id']; + $defaults['object_type'] = 1; + $showHide->addShow("id-group-acl"); + $showHide->addHide("id-profile-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addHide("id-event-acl"); + break; + + case 'civicrm_uf_group': + $defaults['uf_group_id'] = $defaults['object_id']; + $defaults['object_type'] = 2; + $showHide->addHide("id-group-acl"); + $showHide->addShow("id-profile-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addHide("id-event-acl"); + break; + + case 'civicrm_custom_group': + $defaults['custom_group_id'] = $defaults['object_id']; + $defaults['object_type'] = 3; + $showHide->addHide("id-group-acl"); + $showHide->addHide("id-profile-acl"); + $showHide->addShow("id-custom-acl"); + $showHide->addHide("id-event-acl"); + break; + + case 'civicrm_event': + $defaults['event_id'] = $defaults['object_id']; + $defaults['object_type'] = 4; + $showHide->addHide("id-group-acl"); + $showHide->addHide("id-profile-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addShow("id-event-acl"); + break; + } + } + else { + $showHide->addHide("id-group-acl"); + $showHide->addHide("id-profile-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addHide("id-event-acl"); + } + + // Don't assign showHide elements to template in DELETE mode (fields to be shown and hidden don't exist) + if (!($this->_action & CRM_Core_Action::DELETE)) { + $showHide->addToTemplate(); + } + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_ACL_DAO_ACL'); + + $this->add('text', 'name', ts('Description'), CRM_Core_DAO::getAttribute('CRM_ACL_DAO_ACL', 'name'), TRUE); + + $operations = array('' => ts('- select -')) + CRM_ACL_BAO_ACL::operation(); + $this->add('select', + 'operation', + ts('Operation'), + $operations, TRUE + ); + + $objTypes = array('1' => ts('A group of contacts'), + '2' => ts('A profile'), + '3' => ts('A set of custom data fields'), + ); + + if (CRM_Core_Permission::access('CiviEvent')) { + $objTypes['4'] = ts('Events'); + } + + $extra = array('onclick' => "showObjectSelect();"); + $this->addRadio('object_type', + ts('Type of Data'), + $objTypes, + $extra, + ' ', TRUE + ); + + + $label = ts('Role'); + $role = array('-1' => ts('- select role -'), + '0' => ts('Everyone'), + ) + CRM_Core_OptionGroup::values('acl_role'); + $this->add('select', 'entity_id', $label, $role, TRUE); + + $group = array('-1' => ts('- select -'), + '0' => ts('All Groups'), + ) + CRM_Core_PseudoConstant::group(); + + $customGroup = array('-1' => ts('- select -'), + '0' => ts('All Custom Groups'), + ) + CRM_Core_PseudoConstant::customGroup(); + + $ufGroup = array('-1' => ts('- select -'), + '0' => ts('All Profiles'), + ) + CRM_Core_PseudoConstant::ufGroup(); + + $event = array('-1' => ts('- select -'), + '0' => ts('All Events'), + ) + CRM_Event_PseudoConstant::event(NULL, FALSE, "( is_template IS NULL OR is_template != 1 )"); + + $this->add('select', 'group_id', ts('Group'), $group); + $this->add('select', 'custom_group_id', ts('Custom Data'), $customGroup); + $this->add('select', 'uf_group_id', ts('Profile'), $ufGroup); + $this->add('select', 'event_id', ts('Event'), $event); + + $this->add('checkbox', 'is_active', ts('Enabled?')); + + $this->addFormRule(array('CRM_ACL_Form_ACL', 'formRule')); + } + + static function formRule($params) { + $showHide = new CRM_Core_ShowHideBlocks(); + + // Make sure role is not -1 + if ($params['entity_id'] == -1) { + $errors['entity_id'] = ts('Please assign this permission to a Role.'); + } + + $validOperations = array('View', 'Edit'); + $operationMessage = ts("Only 'View' and 'Edit' operations are valid for this type of data"); + + // Figure out which type of object we're permissioning on and make sure user has selected a value. + switch ($params['object_type']) { + case 1: + if ($params['group_id'] == -1) { + $errors['group_id'] = ts('Please select a Group (or ALL Groups).'); + $showHide->addShow("id-group-acl"); + $showHide->addHide("id-profile-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addHide("id-event-acl"); + } + if (!in_array($params['operation'], $validOperations)) { + $errors['operation'] = $operationMessage; + } + break; + + case 2: + if ($params['uf_group_id'] == -1) { + $errors['uf_group_id'] = ts('Please select a Profile (or ALL Profiles).'); + $showHide->addShow("id-profile-acl"); + $showHide->addHide("id-group-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addHide("id-event-acl"); + } + break; + + case 3: + if ($params['custom_group_id'] == -1) { + $errors['custom_group_id'] = ts('Please select a set of Custom Data (or ALL Custom Data).'); + $showHide->addShow("id-custom-acl"); + $showHide->addHide("id-group-acl"); + $showHide->addHide("id-profile-acl"); + $showHide->addHide("id-event-acl"); + } + if (!in_array($params['operation'], $validOperations)) { + $errors['operation'] = $operationMessage; + } + break; + + case 4: + if ($params['event_id'] == -1) { + $errors['event_id'] = ts('Please select an Event (or ALL Events).'); + $showHide->addShow("id-event-acl"); + $showHide->addHide("id-custom-acl"); + $showHide->addHide("id-group-acl"); + $showHide->addHide("id-profile-acl"); + } + if (!in_array($params['operation'], $validOperations)) { + $errors['operation'] = $operationMessage; + } + break; + } + + $showHide->addToTemplate(); + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // note this also resets any ACL cache + CRM_Core_BAO_Cache::deleteGroup('contact fields'); + + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_ACL_BAO_ACL::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected ACL has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + $params = $this->controller->exportValues($this->_name); + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['deny'] = 0; + $params['entity_table'] = 'civicrm_acl_role'; + + // Figure out which type of object we're permissioning on and set object_table and object_id. + switch ($params['object_type']) { + case 1: + $params['object_table'] = 'civicrm_saved_search'; + $params['object_id'] = $params['group_id']; + break; + + case 2: + $params['object_table'] = 'civicrm_uf_group'; + $params['object_id'] = $params['uf_group_id']; + break; + + case 3: + $params['object_table'] = 'civicrm_custom_group'; + $params['object_id'] = $params['custom_group_id']; + break; + + case 4: + $params['object_table'] = 'civicrm_event'; + $params['object_id'] = $params['event_id']; + break; + } + + if ($this->_id) { + $params['id'] = $this->_id; + } + + CRM_ACL_BAO_ACL::create($params); + } + } +} + diff --git a/CRM/ACL/Form/ACLBasic.php b/CRM/ACL/Form/ACLBasic.php new file mode 100644 index 0000000000..6794c037e8 --- /dev/null +++ b/CRM/ACL/Form/ACLBasic.php @@ -0,0 +1,169 @@ +_id || + $this->_id === '0' + ) { + $defaults['entity_id'] = $this->_id; + + $query = " +SELECT object_table + FROM civicrm_acl + WHERE entity_id = %1 + AND ( object_table NOT IN ( 'civicrm_saved_search', 'civicrm_uf_group', 'civicrm_custom_group' ) ) +"; + $params = array(1 => array($this->_id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $defaults['object_table'] = array(); + while ($dao->fetch()) { + $defaults['object_table'][$dao->object_table] = 1; + } + } + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $permissions = array_flip(CRM_Core_Permission::basicPermissions()); + $this->addCheckBox('object_table', + ts('ACL Type'), + $permissions, + NULL, NULL, TRUE, NULL, + array('', '') + ); + + + $label = ts('Role'); + $role = array('-1' => ts('- select role -'), + '0' => ts('Everyone'), + ) + CRM_Core_OptionGroup::values('acl_role'); + $entityID = &$this->add('select', 'entity_id', $label, $role, TRUE); + + if ($this->_id) { + $entityID->freeze(); + } + $this->add('checkbox', 'is_active', ts('Enabled?')); + + $this->addFormRule(array('CRM_ACL_Form_ACLBasic', 'formRule')); + } + + static function formRule($params) { + if ($params['entity_id'] == -1) { + $errors = array('entity_id' => ts('Role is a required field')); + return $errors; + } + + return TRUE; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_ACL_BAO_Cache::resetCache(); + + $params = $this->controller->exportValues($this->_name); + if ($this->_id || + $this->_id === '0' + ) { + $query = " +DELETE + FROM civicrm_acl + WHERE entity_id = %1 + AND ( object_table NOT IN ( 'civicrm_saved_search', 'civicrm_uf_group', 'civicrm_custom_group' ) ) +"; + $deleteParams = array(1 => array($this->_id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $deleteParams); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_Session::setStatus(ts('Selected ACL has been deleted.'), ts('Record Deleted'), 'success'); + return; + } + } + + $params['operation'] = 'All'; + $params['deny'] = 0; + $params['is_active'] = 1; + $params['entity_table'] = 'civicrm_acl_role'; + $params['name'] = 'Core ACL'; + + foreach ($params['object_table'] as $object_table => $value) { + if ($value) { + $newParams = $params; + unset($newParams['object_table']); + $newParams['object_table'] = $object_table; + CRM_ACL_BAO_ACL::create($newParams); + } + } + } +} + diff --git a/CRM/ACL/Form/EntityRole.php b/CRM/ACL/Form/EntityRole.php new file mode 100644 index 0000000000..055cf60a63 --- /dev/null +++ b/CRM/ACL/Form/EntityRole.php @@ -0,0 +1,101 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_ACL_DAO_EntityRole'); + + $aclRoles = array('' => ts('- select -')) + CRM_Core_OptionGroup::values('acl_role'); + $this->add('select', 'acl_role_id', ts('ACL Role'), + $aclRoles, TRUE + ); + + + + $label = ts('Assigned To'); + $group = array('' => ts('- select group -')) + CRM_Core_PseudoConstant::staticGroup(FALSE, 'Access'); + $this->add('select', 'entity_id', $label, $group, TRUE); + + $this->add('checkbox', 'is_active', ts('Enabled?')); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_ACL_BAO_Cache::resetCache(); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_ACL_BAO_EntityRole::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected Entity Role has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + $params = $this->controller->exportValues($this->_name); + if ($this->_id) { + $params['id'] = $this->_id; + } + + $params['entity_table'] = 'civicrm_group'; + CRM_ACL_BAO_EntityRole::create($params); + } + } +} + diff --git a/CRM/ACL/Form/WordPress/Permissions.php b/CRM/ACL/Form/WordPress/Permissions.php new file mode 100644 index 0000000000..9dccf9204c --- /dev/null +++ b/CRM/ACL/Form/WordPress/Permissions.php @@ -0,0 +1,185 @@ +role_names as $role => $name ) { + // Dont show the permissions options for administrator, as they have all permissions + if ($role !== 'administrator') { + $roleObj = $wp_roles->get_role($role); + if (!empty($roleObj->capabilities)) { + foreach ($roleObj->capabilities as $ckey => $cname) { + if (array_key_exists($ckey , $permissionsArray)) { + $elementName = $role.'['.$ckey.']'; + $defaults[$elementName] = 1; + } + } + } + + // Compose the checkbox array for each role, to assign to form + $rolePerms[$role] = $permissionsArray; + foreach ( $rolePerms[$role] as $key => $value) { + $elementName = $role.'['.$key.']'; + $this->add('checkbox' , $elementName , $value); + } + $roles[$role] = $name; + } + } + + $this->setDefaults($defaults); + + $this->assign('rolePerms', $rolePerms); + $this->assign('roles', $roles); + + $this->addButtons( + array( + array ( + 'type' => 'next', + 'name' => ts('Save'), + 'spacing' => '', + 'isDefault' => false ), + ) + ); + + } + + /** + * Function to process the form + * + * @access public + * @return None + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + + $permissionsArray = self::getPermissionArray(); + + // Function to get Wordpress roles + global $wp_roles; + if (!isset($wp_roles)) { + $wp_roles = new WP_Roles(); + } + foreach ( $wp_roles->role_names as $role => $name ) { + $roleObj = $wp_roles->get_role($role); + + //Remove all civicrm capabilities for the role, as there may be some capabilities checkbox unticked + foreach ($permissionsArray as $key => $capability){ + $roleObj->remove_cap($key); + } + + //Add the selected wordpress capabilities for the role + $rolePermissions = $params[$role]; + if (!empty($rolePermissions)) { + foreach ( $rolePermissions as $key => $capability ) { + $roleObj->add_cap($key); + } + } + } + + // FIXME + // Changed the 'access_civicrm_nav_link' capability in civicrm.php file + // But for some reason, if i remove 'Access CiviCRM' administrator and save, it is showing + // 'You do not have sufficient permissions to access this page' + // which should not happen for Super Admin and Administrators, as checking permissions for Super + // Admin and Administrators always gives TRUE + wp_civicrm_capability(); + + CRM_Core_Session::setStatus("", ts('Wordpress Access Control Updated'), "success"); + + // rebuild the menus to comply with the new permisssions/capabilites + CRM_Core_Invoke::rebuildMenuAndCaches( ); + + CRM_Utils_System::redirect('admin.php?page=CiviCRM&q=civicrm/admin/access&reset=1'); + CRM_Utils_System::civiExit(); + } + + /** + * Get the core civicrm permissions array. + * This function should be shared from a similar one in + * distmaker/utils/joomlaxml.php + * + * @access public + * @return array civicrm permissions + */ + static function getPermissionArray(){ + global $civicrm_root; + + $permissions = CRM_Core_Permission::getCorePermissions(); + $crmFolderDir = $civicrm_root . DIRECTORY_SEPARATOR . 'CRM'; + + $components = CRM_Core_Component::getComponentsFromFile($crmFolderDir); + foreach ($components as $comp) { + $perm = $comp->getPermissions(); + if ($perm) { + $info = $comp->getInfo(); + foreach ($perm as $p) { + $permissions[$p] = $info['translatedName'] . ': ' . $p; + } + } + } + + $perms_array = array(); + foreach ($permissions as $perm => $title) { + //order matters here, but we deal with that later + $perms_array[CRM_Utils_String::munge(strtolower($perm))] = $title; + } + + return $perms_array; + } +} + diff --git a/CRM/ACL/Page/ACL.php b/CRM/ACL/Page/ACL.php new file mode 100644 index 0000000000..c50f4daaa6 --- /dev/null +++ b/CRM/ACL/Page/ACL.php @@ -0,0 +1,275 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/acl', + 'qs' => 'reset=1&action=update&id=%%id%%', + 'title' => ts('Edit ACL'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_ACL_BAO_ACL' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable ACL'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_ACL_BAO_ACL' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable ACL'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/acl', + 'qs' => 'reset=1&action=delete&id=%%id%%', + 'title' => ts('Delete ACL'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // get the requested action + $action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + + // set breadcrumb to append to admin/access + $breadCrumb = array(array('title' => ts('Access Control'), + 'url' => CRM_Utils_System::url('civicrm/admin/access', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + // what action to take ? + if ($action & (CRM_Core_Action::ADD | CRM_Core_Action::DELETE)) { + $this->edit($action, $id); + } + + if ($action & (CRM_Core_Action::UPDATE)) { + $this->edit($action, $id); + + if (isset($id)) { + $aclName = CRM_Core_DAO::getFieldValue('CRM_ACL_DAO_ACL', $id); + CRM_Utils_System::setTitle(ts('Edit ACL - %1', array(1 => $aclName))); + } + } + + + // finally browse the acl's + $this->browse(); + + // parent run + return parent::run(); + } + + /** + * Browse all acls + * + * @return void + * @access public + * @static + */ + function browse() { + + // get all acl's sorted by weight + $acl = array(); + $query = " + SELECT * + FROM civicrm_acl + WHERE ( object_table IN ( 'civicrm_saved_search', 'civicrm_uf_group', 'civicrm_custom_group', 'civicrm_event' ) ) +ORDER BY entity_id +"; + $dao = CRM_Core_DAO::executeQuery($query, + CRM_Core_DAO::$_nullArray + ); + + $roles = CRM_Core_OptionGroup::values('acl_role'); + + $group = array('-1' => ts('- select -'), + '0' => ts('All Groups'), + ) + CRM_Core_PseudoConstant::group(); + $customGroup = array('-1' => ts('- select -'), + '0' => ts('All Custom Groups'), + ) + CRM_Core_PseudoConstant::customGroup(); + $ufGroup = array('-1' => ts('- select -'), + '0' => ts('All Profiles'), + ) + CRM_Core_PseudoConstant::ufGroup(); + + $event = array('-1' => ts('- select -'), + '0' => ts('All Events'), + ) + CRM_Event_PseudoConstant::event(); + + while ($dao->fetch()) { + $acl[$dao->id] = array(); + $acl[$dao->id]['name'] = $dao->name; + $acl[$dao->id]['operation'] = $dao->operation; + $acl[$dao->id]['entity_id'] = $dao->entity_id; + $acl[$dao->id]['entity_table'] = $dao->entity_table; + $acl[$dao->id]['object_table'] = $dao->object_table; + $acl[$dao->id]['object_id'] = $dao->object_id; + $acl[$dao->id]['is_active'] = $dao->is_active; + + + if ($acl[$dao->id]['entity_id']) { + $acl[$dao->id]['entity'] = $roles[$acl[$dao->id]['entity_id']]; + } + else { + $acl[$dao->id]['entity'] = ts('Everyone'); + } + + switch ($acl[$dao->id]['object_table']) { + case 'civicrm_saved_search': + $acl[$dao->id]['object'] = $group[$acl[$dao->id]['object_id']]; + $acl[$dao->id]['object_name'] = ts('Group'); + break; + + case 'civicrm_uf_group': + $acl[$dao->id]['object'] = $ufGroup[$acl[$dao->id]['object_id']]; + $acl[$dao->id]['object_name'] = ts('Profile'); + break; + + case 'civicrm_custom_group': + $acl[$dao->id]['object'] = $customGroup[$acl[$dao->id]['object_id']]; + $acl[$dao->id]['object_name'] = ts('Custom Group'); + break; + + case 'civicrm_event': + $acl[$dao->id]['object'] = $event[$acl[$dao->id]['object_id']]; + $acl[$dao->id]['object_name'] = ts('Event'); + break; + } + + // form all action links + $action = array_sum(array_keys($this->links())); + + if ($dao->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $acl[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $dao->id) + ); + } + $this->assign('rows', $acl); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_ACL_Form_ACL'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'ACL'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/acl'; + } +} + diff --git a/CRM/ACL/Page/ACLBasic.php b/CRM/ACL/Page/ACLBasic.php new file mode 100644 index 0000000000..a9c9fccec0 --- /dev/null +++ b/CRM/ACL/Page/ACLBasic.php @@ -0,0 +1,212 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/acl/basic', + 'qs' => 'reset=1&action=update&id=%%id%%', + 'title' => ts('Edit ACL'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/acl/basic', + 'qs' => 'reset=1&action=delete&id=%%id%%', + 'title' => ts('Delete ACL'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // get the requested action + $action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + + // set breadcrumb to append to admin/access + $breadCrumb = array(array('title' => ts('Access Control'), + 'url' => CRM_Utils_System::url('civicrm/admin/access', 'reset=1'), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + + // what action to take ? + if ($action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::DELETE)) { + $this->edit($action, $id); + } + + // finally browse the acl's + $this->browse(); + + // parent run + return parent::run(); + } + + /** + * Browse all acls + * + * @return void + * @access public + * @static + */ + function browse() { + + // get all acl's sorted by weight + $acl = array(); + $query = " + SELECT * + FROM civicrm_acl + WHERE ( object_table NOT IN ( 'civicrm_saved_search', 'civicrm_uf_group', 'civicrm_custom_group' ) ) +ORDER BY entity_id +"; + $dao = CRM_Core_DAO::executeQuery($query, + CRM_Core_DAO::$_nullArray + ); + + $roles = CRM_Core_OptionGroup::values('acl_role'); + + $permissions = CRM_Core_Permission::basicPermissions(); + while ($dao->fetch()) { + if (!array_key_exists($dao->entity_id, $acl)) { + $acl[$dao->entity_id] = array(); + $acl[$dao->entity_id]['name'] = $dao->name; + $acl[$dao->entity_id]['entity_id'] = $dao->entity_id; + $acl[$dao->entity_id]['entity_table'] = $dao->entity_table; + $acl[$dao->entity_id]['object_table'] = CRM_Utils_Array::value($dao->object_table, $permissions); + $acl[$dao->entity_id]['is_active'] = 1; + + if ($acl[$dao->entity_id]['entity_id']) { + $acl[$dao->entity_id]['entity'] = $roles[$acl[$dao->entity_id]['entity_id']]; + } + else { + $acl[$dao->entity_id]['entity'] = ts('Any Role'); + } + + // form all action links + $action = array_sum(array_keys($this->links())); + + $acl[$dao->entity_id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $dao->entity_id) + ); + } + elseif (CRM_Utils_Array::value($dao->object_table, $permissions)) { + $acl[$dao->entity_id]['object_table'] .= ", {$permissions[$dao->object_table]}"; + } + } + $this->assign('rows', $acl); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_ACL_Form_ACLBasic'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Core ACLs'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/acl/basic'; + } +} + diff --git a/CRM/ACL/Page/EntityRole.php b/CRM/ACL/Page/EntityRole.php new file mode 100644 index 0000000000..9519c0cb25 --- /dev/null +++ b/CRM/ACL/Page/EntityRole.php @@ -0,0 +1,220 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/acl/entityrole', + 'qs' => 'action=update&id=%%id%%', + 'title' => ts('Edit ACL Role Assignment'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_ACL_BAO_EntityRole' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable ACL Role Assignment'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_ACL_BAO_EntityRole' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable ACL Role Assignment'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/acl/entityrole', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete ACL Role Assignment'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // get the requested action + $action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + + // set breadcrumb to append to admin/access + $breadCrumb = array(array('title' => ts('Access Control'), + 'url' => CRM_Utils_System::url('civicrm/admin/access', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + CRM_Utils_System::setTitle(ts('Assign Users to Roles')); + + // what action to take ? + if ($action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::DELETE)) { + $this->edit($action, $id); + } + + // reset cache if enabled/disabled + if ($action & (CRM_Core_Action::DISABLE | CRM_Core_Action::ENABLE)) { + CRM_ACL_BAO_Cache::resetCache(); + } + + // finally browse the acl's + if ($action & CRM_Core_Action::BROWSE) { + $this->browse(); + } + + // parent run + return parent::run(); + } + + /** + * Browse all acls + * + * @return void + * @access public + * @static + */ + function browse() { + + // get all acl's sorted by weight + $entityRoles = array(); + $dao = new CRM_ACL_DAO_EntityRole(); + $dao->find(); + + $aclRoles = CRM_Core_OptionGroup::values('acl_role'); + $groups = CRM_Core_PseudoConstant::staticGroup(); + + while ($dao->fetch()) { + $entityRoles[$dao->id] = array(); + CRM_Core_DAO::storeValues($dao, $entityRoles[$dao->id]); + + $entityRoles[$dao->id]['acl_role'] = $aclRoles[$dao->acl_role_id]; + $entityRoles[$dao->id]['entity'] = $groups[$dao->entity_id]; + + // form all action links + $action = array_sum(array_keys($this->links())); + if ($dao->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $entityRoles[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $dao->id) + ); + } + $this->assign('rows', $entityRoles); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_ACL_Form_EntityRole'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'ACL EntityRole'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/acl/entityrole'; + } +} + diff --git a/CRM/Activity/BAO/Activity.php b/CRM/Activity/BAO/Activity.php new file mode 100644 index 0000000000..f86e7a5935 --- /dev/null +++ b/CRM/Activity/BAO/Activity.php @@ -0,0 +1,2639 @@ +copyValues($params); + + if ($activity->find(TRUE)) { + // TODO: at some stage we'll have to deal + // TODO: with multiple values for assignees and targets, but + // TODO: for now, let's just fetch first row + $defaults['assignee_contact'] = CRM_Activity_BAO_ActivityAssignment::retrieveAssigneeIdsByActivityId($activity->id); + $assignee_contact_names = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($activity->id); + + $defaults['assignee_contact_value'] = implode('; ', $assignee_contact_names); + + if ($activity->activity_type_id != CRM_Core_OptionGroup::getValue('activity_type', 'Bulk Email', 'name')) { + $defaults['target_contact'] = CRM_Activity_BAO_ActivityTarget::retrieveTargetIdsByActivityId($activity->id); + $target_contact_names = CRM_Activity_BAO_ActivityTarget::getTargetNames($activity->id); + + $defaults['target_contact_value'] = implode('; ', $target_contact_names); + } + elseif (CRM_Core_Permission::check('access CiviMail') || + (CRM_Mailing_Info::workflowEnabled() && + CRM_Core_Permission::check('create mailings') + ) + ) { + $defaults['mailingId'] = CRM_Utils_System::url('civicrm/mailing/report', + "mid={$activity->source_record_id}&reset=1&atype={$activity->activity_type_id}&aid={$activity->id}&cid={$activity->source_contact_id}&context=activity" + ); + } + else { + $defaults['target_contact_value'] = ts('(recipients)'); + } + + if ($activity->source_contact_id && + !CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $activity->source_contact_id, + 'is_deleted' + ) + ) { + $defaults['source_contact'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $activity->source_contact_id, + 'sort_name' + ); + } + + //get case subject + $defaults['case_subject'] = CRM_Case_BAO_Case::getCaseSubject($activity->id); + + CRM_Core_DAO::storeValues($activity, $defaults); + + return $activity; + } + return NULL; + } + + /** + * Function to delete the activity + * + * @param array $params associated array + * + * @return void + * @access public + * + */ + public static function deleteActivity(&$params, $moveToTrash = FALSE) { + // CRM-9137 + if (CRM_Utils_Array::value('id', $params) && !is_array($params['id'])) { + CRM_Utils_Hook::pre('delete', 'Activity', $params['id'], $params); + } + else { + CRM_Utils_Hook::pre('delete', 'Activity', NULL, $params); + } + + $transaction = new CRM_Core_Transaction(); + if (is_array(CRM_Utils_Array::value('source_record_id', $params))) { + $sourceRecordIds = implode(',', $params['source_record_id']); + } + else { + $sourceRecordIds = CRM_Utils_Array::value('source_record_id', $params); + } + + $result = NULL; + if (!$moveToTrash) { + if (!isset($params['id'])) { + if (is_array($params['activity_type_id'])) { + $activityTypes = implode(',', $params['activity_type_id']); + } + else { + $activityTypes = $params['activity_type_id']; + } + + $query = "DELETE FROM civicrm_activity WHERE source_record_id IN ({$sourceRecordIds}) AND activity_type_id IN ( {$activityTypes} )"; + $dao = CRM_Core_DAO::executeQuery($query); + } + else { + $activity = new CRM_Activity_DAO_Activity(); + $activity->copyValues($params); + $result = $activity->delete(); + + // CRM-8708 + $activity->case_id = CRM_Case_BAO_Case::getCaseIdByActivityId($activity->id); + } + } + else { + $activity = new CRM_Activity_DAO_Activity(); + $activity->copyValues($params); + + $activity->is_deleted = 1; + $result = $activity->save(); + + //log activty delete.CRM-4525. + $logMsg = 'Case Activity deleted for'; + $msgs = array(); + $sourceContactId = CRM_Core_DAO::getfieldValue('CRM_Activity_DAO_Activity', + $activity->id, 'source_contact_id' + ); + if ($sourceContactId) { + $msgs[] = " source={$sourceContactId}"; + } + //get target contacts. + $targetContactIds = CRM_Activity_BAO_ActivityTarget::getTargetNames($activity->id); + if (!empty($targetContactIds)) { + $msgs[] = " target =" . implode(',', array_keys($targetContactIds)); + } + //get assignee contacts. + $assigneeContactIds = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($activity->id); + if (!empty($assigneeContactIds)) { + $msgs[] = " assignee =" . implode(',', array_keys($assigneeContactIds)); + } + + $logMsg .= implode(', ', $msgs); + + self::logActivityAction($activity, $logMsg); + } + + // delete the recently created Activity + if ($result) { + $activityRecent = array( + 'id' => $activity->id, + 'type' => 'Activity', + ); + CRM_Utils_Recent::del($activityRecent); + } + + $transaction->commit(); + if (isset($activity)) { + // CRM-8708 + $activity->case_id = CRM_Case_BAO_Case::getCaseIdByActivityId($activity->id); + CRM_Utils_Hook::post('delete', 'Activity', $activity->id, $activity); + } + + return $result; + } + + /** + * Delete activity assignment record + * + * @param int $id activity id + * + * @return null + * @access public + */ + public static function deleteActivityAssignment($activityId) { + $assignment = new CRM_Activity_BAO_ActivityAssignment(); + $assignment->activity_id = $activityId; + $assignment->delete(); + } + + /** + * Delete activity target record + * + * @param int $id activity id + * + * @return null + * @access public + */ + public static function deleteActivityTarget($activityId) { + $target = new CRM_Activity_BAO_ActivityTarget(); + $target->activity_id = $activityId; + $target->delete(); + } + + /** + * Create activity target record + * + * @param array activity_id, target_contact_id + * + * @return null + * @access public + */ + static function createActivityTarget($params) { + if (!$params['target_contact_id']) { + return; + } + + $target = new CRM_Activity_BAO_ActivityTarget(); + $target->activity_id = $params['activity_id']; + $target->target_contact_id = $params['target_contact_id']; + // avoid duplicate entries, CRM-7484 + // happens if sending email to the same contact with different email addresses + if (!$target->find(TRUE)) { + $target->save(); + } + } + + /** + * Create activity assignment record + * + * @param array activity_id, assignee_contact_id + * + * @return null + * @access public + */ + static function createActivityAssignment($params) { + if (!$params['assignee_contact_id']) { + return; + } + $assignee = new CRM_Activity_BAO_ActivityAssignment(); + $assignee->activity_id = $params['activity_id']; + $assignee->assignee_contact_id = $params['assignee_contact_id']; + $assignee->save(); + } + + /** + * Function to process the activities + * + * @param object $form form object + * @param array $params associated array of the submitted values + * @param array $ids array of ids + * @param string $activityType activity Type + * @param boolean $record true if it is Record Activity + * @access public + * + * @return + */ + public static function create(&$params) { + // check required params + if (!self::dataExists($params)) { + CRM_Core_Error::fatal('Not enough data to create activity object,'); + } + + $activity = new CRM_Activity_DAO_Activity(); + + if (isset($params['id']) && empty($params['id'])) { + unset($params['id']); + } + + if (!CRM_Utils_Array::value('status_id', $params) && + !CRM_Utils_Array::value('activity_status_id', $params) && + !CRM_Utils_Array::value('id', $params) + ) { + if (isset($params['activity_date_time']) && + strcmp($params['activity_date_time'], CRM_Utils_Date::processDate(date('Ymd')) == -1) + ) { + $params['status_id'] = 2; + } + else { + $params['status_id'] = 1; + } + } + + //set priority to Normal for Auto-populated activities (for Cases) + if (CRM_Utils_Array::value('priority_id', $params) === NULL && + // if not set and not 0 + !CRM_Utils_Array::value('id', $params) + ) { + $priority = CRM_Core_PseudoConstant::priority(); + $params['priority_id'] = array_search('Normal', $priority); + } + + if (!empty($params['target_contact_id']) && is_array($params['target_contact_id'])) { + $params['target_contact_id'] = array_unique($params['target_contact_id']); + } + if (!empty($params['assignee_contact_id']) && is_array($params['assignee_contact_id'])) { + $params['assignee_contact_id'] = array_unique($params['assignee_contact_id']); + } + + // CRM-9137 + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::pre('edit', 'Activity', $activity->id, $params); + } + else { + CRM_Utils_Hook::pre('create', 'Activity', NULL, $params); + } + + $activity->copyValues($params); + if (isset($params['case_id'])) { + // CRM-8708, preserve case ID even though it's not part of the SQL model + $activity->case_id = $params['case_id']; + } + elseif (is_numeric($activity->id)) { + // CRM-8708, preserve case ID even though it's not part of the SQL model + $activity->case_id = CRM_Case_BAO_Case::getCaseIdByActivityId($activity->id); + } + + // start transaction + $transaction = new CRM_Core_Transaction(); + + $result = $activity->save(); + + if (is_a($result, 'CRM_Core_Error')) { + $transaction->rollback(); + return $result; + } + + $activityId = $activity->id; + + // check and attach and files as needed + CRM_Core_BAO_File::processAttachment($params, 'civicrm_activity', $activityId); + + // attempt to save activity assignment + $resultAssignment = NULL; + if (CRM_Utils_Array::value('assignee_contact_id', $params)) { + + $assignmentParams = array('activity_id' => $activityId); + + if (is_array($params['assignee_contact_id'])) { + if (CRM_Utils_Array::value('deleteActivityAssignment', $params, TRUE)) { + // first delete existing assignments if any + self::deleteActivityAssignment($activityId); + } + + $values = array(); + foreach ($params['assignee_contact_id'] as $acID) { + if ($acID) { + $values[] = "( $activityId, $acID )"; + } + } + while (!empty($values)) { + $input = array_splice($values, 0, CRM_Core_DAO::BULK_INSERT_COUNT); + $str = implode(',', $input); + $sql = "INSERT IGNORE INTO civicrm_activity_assignment ( activity_id, assignee_contact_id ) VALUES $str;"; + CRM_Core_DAO::executeQuery($sql); + } + } + else { + $assignmentParams['assignee_contact_id'] = $params['assignee_contact_id']; + + if (CRM_Utils_Array::value('id', $params)) { + $assignment = new CRM_Activity_BAO_ActivityAssignment(); + $assignment->activity_id = $activityId; + $assignment->find(TRUE); + + if ($assignment->assignee_contact_id != $params['assignee_contact_id']) { + $assignmentParams['id'] = $assignment->id; + $resultAssignment = CRM_Activity_BAO_ActivityAssignment::create($assignmentParams); + } + } + else { + $resultAssignment = CRM_Activity_BAO_ActivityAssignment::create($assignmentParams); + } + } + } + else { + if (CRM_Utils_Array::value('deleteActivityAssignment', $params, TRUE)) { + self::deleteActivityAssignment($activityId); + } + } + + if (is_a($resultAssignment, 'CRM_Core_Error')) { + $transaction->rollback(); + return $resultAssignment; + } + + // attempt to save activity targets + $resultTarget = NULL; + if (CRM_Utils_Array::value('target_contact_id', $params)) { + + $targetParams = array('activity_id' => $activityId); + $resultTarget = array(); + if (is_array($params['target_contact_id'])) { + if (CRM_Utils_Array::value('deleteActivityTarget', $params, TRUE)) { + // first delete existing targets if any + self::deleteActivityTarget($activityId); + } + + $values = array(); + foreach ($params['target_contact_id'] as $tid) { + if ($tid) { + $values[] = "( $activityId, $tid )"; + } + } + + while (!empty($values)) { + $input = array_splice($values, 0, CRM_Core_DAO::BULK_INSERT_COUNT); + $str = implode(',', $input); + $sql = "INSERT IGNORE INTO civicrm_activity_target ( activity_id, target_contact_id ) VALUES $str;"; + CRM_Core_DAO::executeQuery($sql); + } + } + else { + $targetParams['target_contact_id'] = $params['target_contact_id']; + + if (CRM_Utils_Array::value('id', $params)) { + $target = new CRM_Activity_BAO_ActivityTarget(); + $target->activity_id = $activityId; + $target->find(TRUE); + + if ($target->target_contact_id != $params['target_contact_id']) { + $targetParams['id'] = $target->id; + $resultTarget = CRM_Activity_BAO_ActivityTarget::create($targetParams); + } + } + else { + $resultTarget = CRM_Activity_BAO_ActivityTarget::create($targetParams); + } + } + } + else { + if (CRM_Utils_Array::value('deleteActivityTarget', $params, TRUE)) { + self::deleteActivityTarget($activityId); + } + } + + // write to changelog before transation is committed/rolled + // back (and prepare status to display) + if (CRM_Utils_Array::value('id', $params)) { + $logMsg = "Activity (id: {$result->id} ) updated with "; + } + else { + $logMsg = "Activity created for "; + } + + $msgs = array(); + if (isset($params['source_contact_id'])) { + $msgs[] = "source={$params['source_contact_id']}"; + } + + if (CRM_Utils_Array::value('target_contact_id', $params)) { + if (is_array($params['target_contact_id']) && !CRM_Utils_array::crmIsEmptyArray($params['target_contact_id'])) { + $msgs[] = "target=" . implode(',', $params['target_contact_id']); + // take only first target + // will be used for recently viewed display + $t = array_slice($params['target_contact_id'], 0, 1); + $recentContactId = $t[0]; + } + elseif (isset($params['target_contact_id'])) { + $msgs[] = "target={$params['target_contact_id']}"; + // will be used for recently viewed display + $recentContactId = $params['target_contact_id']; + } + } + else { + // at worst, take source for recently viewed display + $recentContactId = CRM_Utils_Array::value('source_contact_id',$params); + } + + if (isset($params['assignee_contact_id'])) { + if (is_array($params['assignee_contact_id'])) { + $msgs[] = "assignee=" . implode(',', $params['assignee_contact_id']); + } + else { + $msgs[] = "assignee={$params['assignee_contact_id']}"; + } + } + $logMsg .= implode(', ', $msgs); + + self::logActivityAction($result, $logMsg); + + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_activity', $result->id); + } + + $transaction->commit(); + if (!CRM_Utils_Array::value('skipRecentView', $params)) { + $recentOther = array(); + if (CRM_Utils_Array::value('case_id', $params)) { + $caseContactID = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseContact', $params['case_id'], 'contact_id', 'case_id'); + $url = CRM_Utils_System::url('civicrm/case/activity/view', + "reset=1&aid={$activity->id}&cid={$caseContactID}&caseID={$params['case_id']}&context=home" + ); + } + else { + $q = "action=view&reset=1&id={$activity->id}&atype={$activity->activity_type_id}&cid={$activity->source_contact_id}&context=home"; + if ($activity->activity_type_id != CRM_Core_OptionGroup::getValue('activity_type', 'Email', 'name')) { + $url = CRM_Utils_System::url('civicrm/activity', $q); + if ($activity->activity_type_id == CRM_Core_OptionGroup::getValue('activity_type', 'Print PDF Letter', 'name')) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/activity/pdf/add', + "action=update&reset=1&id={$activity->id}&atype={$activity->activity_type_id}&cid={$activity->source_contact_id}&context=home" + ); + } + else { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/activity/add', + "action=update&reset=1&id={$activity->id}&atype={$activity->activity_type_id}&cid={$activity->source_contact_id}&context=home" + ); + } + + if (CRM_Core_Permission::check("delete activities")) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/activity', + "action=delete&reset=1&id={$activity->id}&atype={$activity->activity_type_id}&cid={$activity->source_contact_id}&context=home" + ); + } + } + else { + $url = CRM_Utils_System::url('civicrm/activity/view', $q); + if (CRM_Core_Permission::check('delete activities')) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/activity', + "action=delete&reset=1&id={$activity->id}&atype={$activity->activity_type_id}&cid={$activity->source_contact_id}&context=home" + ); + } + } + } + + if (!isset($activity->parent_id)) { + $recentContactDisplay = CRM_Contact_BAO_Contact::displayName($recentContactId); + // add the recently created Activity + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE); + $activitySubject = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activity->id, 'subject'); + + $title = ""; + if (isset($activitySubject)) { + $title = $activitySubject . ' - '; + } + + $title = $title . $recentContactDisplay; + if (CRM_Utils_Array::value($activity->activity_type_id, $activityTypes)) { + $title .= ' (' . $activityTypes[$activity->activity_type_id] . ')'; + } + + CRM_Utils_Recent::add($title, + $url, + $activity->id, + 'Activity', + $recentContactId, + $recentContactDisplay, + $recentOther + ); + } + } + + // reset the group contact cache since smart groups might be affected due to this + CRM_Contact_BAO_GroupContactCache::remove(); + + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::post('edit', 'Activity', $activity->id, $activity); + } + else { + CRM_Utils_Hook::post('create', 'Activity', $activity->id, $activity); + } + + // if the subject contains a ‘[case #…]’ string, file that activity on the related case (CRM-5916) + $matches = array(); + if (preg_match('/\[case #([0-9a-h]{7})\]/', CRM_Utils_Array::value('subject', $params), $matches)) { + $key = CRM_Core_DAO::escapeString(CIVICRM_SITE_KEY); + $hash = $matches[1]; + $query = "SELECT id FROM civicrm_case WHERE SUBSTR(SHA1(CONCAT('$key', id)), 1, 7) = '$hash'"; + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => CRM_Core_DAO::singleValueQuery($query), + ); + if ($caseParams['case_id']) { + CRM_Case_BAO_Case::processCaseActivity($caseParams); + } + else { + self::logActivityAction($activity, "unknown case hash encountered: $hash"); + } + } + + return $result; + } + + public static function logActivityAction($activity, $logMessage = NULL) { + $session = CRM_Core_Session::singleton(); + $id = $session->get('userID'); + if (!$id) { + $id = $activity->source_contact_id; + } + $logParams = array( + 'entity_table' => 'civicrm_activity', + 'entity_id' => $activity->id, + 'modified_id' => $id, + 'modified_date' => date('YmdHis'), + 'data' => $logMessage, + ); + CRM_Core_BAO_Log::add($logParams); + return TRUE; + } + + /** + * function to get the list Actvities + * + * @param array $input array of parameters + * Keys include + * - contact_id int contact_id whose activties we want to retrieve + * - offset int which row to start from ? + * - rowCount int how many rows to fetch + * - sort object|array object or array describing sort order for sql query. + * - admin boolean if contact is admin + * - caseId int case ID + * - context string page on which selector is build + * - activity_type_id int|string the activitiy types we want to restrict by + * + * @return array (reference) $values the relevant data object values of open activitie + * + * @access public + * @static + */ + static function &getActivities($input) { + //step 1: Get the basic activity data + $bulkActivityTypeID = CRM_Core_OptionGroup::getValue('activity_type', + 'Bulk Email', + 'name' + ); + + $config = CRM_Core_Config::singleton(); + + $randomNum = md5(uniqid()); + $activityTempTable = "civicrm_temp_activity_details_{$randomNum}"; + + $tableFields = array( + 'activity_id' => 'int unsigned', + 'activity_date_time' => 'datetime', + 'status_id' => 'int unsigned', + 'subject' => 'varchar(255)', + 'source_contact_id' => 'int unsigned', + 'source_record_id' => 'int unsigned', + 'source_contact_name' => 'varchar(255)', + 'activity_type_id' => 'int unsigned', + 'activity_type' => 'varchar(128)', + 'case_id' => 'int unsigned', + 'case_subject' => 'varchar(255)', + 'campaign_id' => 'int unsigned', + ); + + $sql = "CREATE TEMPORARY TABLE {$activityTempTable} ( "; + $insertValueSQL = array(); + foreach ($tableFields as $name => $desc) { + $sql .= "$name $desc,\n"; + $insertValueSQL[] = $name; + } + + $sql .= " + PRIMARY KEY ( activity_id ) + ) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci + "; + + CRM_Core_DAO::executeQuery($sql); + + $insertSQL = "INSERT INTO {$activityTempTable} (" . implode(',', $insertValueSQL) . " ) "; + + $order = $limit = $groupBy = ''; + //$groupBy = " GROUP BY tbl.activity_id"; + + if (!empty($input['sort'])) { + if (is_a($input['sort'], 'CRM_Utils_Sort')) { + $orderBy = $input['sort']->orderBy(); + if (!empty($orderBy)) { + $order = " ORDER BY $orderBy"; + } + } + elseif (trim($input['sort'])) { + $order = " ORDER BY {$input['sort']}"; + } + } + + if (empty($order)) { + $order = (CRM_Utils_Array::value('context', $input) == 'activity') ? " ORDER BY tbl.activity_date_time desc " : " ORDER BY tbl.status_id asc, tbl.activity_date_time asc "; + } + + if (!empty($input['rowCount']) && + $input['rowCount'] > 0 + ) { + $limit = " LIMIT {$input['offset']}, {$input['rowCount']} "; + } + + $input['count'] = FALSE; + list($sqlClause, $params) = self::getActivitySQLClause($input); + + $query = "{$insertSQL} + SELECT DISTINCT tbl.* from ( {$sqlClause} ) +as tbl "; + + //filter case activities - CRM-5761 + $components = self::activityComponents(); + if (!in_array('CiviCase', $components)) { + $query .= " +LEFT JOIN civicrm_case_activity ON ( civicrm_case_activity.activity_id = tbl.activity_id ) + WHERE civicrm_case_activity.id IS NULL"; + } + + $query = $query . $groupBy . $order . $limit; + + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $notbulkActivityClause = ''; + if ($bulkActivityTypeID) { + $notbulkActivityClause = " AND {$activityTempTable}.activity_type_id <> {$bulkActivityTypeID} "; + } + + // step 2: Get target and assignee contacts for above activities + // create temp table for target contacts + $activityTargetContactTempTable = "civicrm_temp_target_contact_{$randomNum}"; + $query = "CREATE TEMPORARY TABLE {$activityTargetContactTempTable} ( + activity_id int unsigned, target_contact_id int unsigned, target_contact_name varchar(255) ) + ENGINE=MYISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci"; + + CRM_Core_DAO::executeQuery($query); + + // note that we ignore bulk email for targets, since we don't show it in selector + $query = "INSERT INTO {$activityTargetContactTempTable} ( activity_id, target_contact_id, target_contact_name ) + SELECT at.activity_id, + at.target_contact_id , + c.sort_name + FROM civicrm_activity_target at + INNER JOIN {$activityTempTable} ON ( at.activity_id = {$activityTempTable}.activity_id + {$notbulkActivityClause} ) + INNER JOIN civicrm_contact c ON c.id = at.target_contact_id + WHERE c.is_deleted = 0"; + + CRM_Core_DAO::executeQuery($query); + + // create temp table for assignee contacts + $activityAssigneetContactTempTable = "civicrm_temp_assignee_contact_{$randomNum}"; + $query = "CREATE TEMPORARY TABLE {$activityAssigneetContactTempTable} ( + activity_id int unsigned, assignee_contact_id int unsigned, assignee_contact_name varchar(255) ) + ENGINE=MYISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci"; + + CRM_Core_DAO::executeQuery($query); + + // note that we ignore bulk email for assignee, since we don't show it in selector + $query = "INSERT INTO {$activityAssigneetContactTempTable} ( activity_id, assignee_contact_id, assignee_contact_name ) + SELECT DISTINCT ( aa.activity_id ) , + aa.assignee_contact_id, + c.sort_name + FROM civicrm_activity_assignment aa + INNER JOIN {$activityTempTable} ON ( aa.activity_id = {$activityTempTable}.activity_id + {$notbulkActivityClause} ) + INNER JOIN civicrm_contact c ON c.id = aa.assignee_contact_id + WHERE c.is_deleted = 0"; + + CRM_Core_DAO::executeQuery($query); + + // step 3: Combine all temp tables to get final query for activity selector + $query = " + SELECT {$activityTempTable}.*, + {$activityTargetContactTempTable}.target_contact_id,{$activityTargetContactTempTable}.target_contact_name, + {$activityAssigneetContactTempTable}.assignee_contact_id, {$activityAssigneetContactTempTable}.assignee_contact_name + FROM {$activityTempTable} + LEFT JOIN {$activityTargetContactTempTable} on {$activityTempTable}.activity_id = {$activityTargetContactTempTable}.activity_id + LEFT JOIN {$activityAssigneetContactTempTable} on {$activityTempTable}.activity_id = {$activityAssigneetContactTempTable}.activity_id + "; + + + $dao = CRM_Core_DAO::executeQuery($query); + + //CRM-3553, need to check user has access to target groups. + $mailingIDs = CRM_Mailing_BAO_Mailing::mailingACLIDs(); + $accessCiviMail = ( + (CRM_Core_Permission::check('access CiviMail')) || + (CRM_Mailing_Info::workflowEnabled() && + CRM_Core_Permission::check('create mailings')) + ); + + //get all campaigns. + $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + + $values = array(); + while ($dao->fetch()) { + $activityID = $dao->activity_id; + $values[$activityID]['activity_id'] = $dao->activity_id; + $values[$activityID]['source_record_id'] = $dao->source_record_id; + $values[$activityID]['activity_type_id'] = $dao->activity_type_id; + $values[$activityID]['activity_type'] = $dao->activity_type; + $values[$activityID]['activity_date_time'] = $dao->activity_date_time; + $values[$activityID]['status_id'] = $dao->status_id; + $values[$activityID]['subject'] = $dao->subject; + $values[$activityID]['source_contact_name'] = $dao->source_contact_name; + $values[$activityID]['source_contact_id'] = $dao->source_contact_id; + $values[$activityID]['campaign_id'] = $dao->campaign_id; + + if ($dao->campaign_id) { + $values[$activityID]['campaign'] = $allCampaigns[$dao->campaign_id]; + } + + if (!CRM_Utils_Array::value('assignee_contact_name', $values[$activityID])) { + $values[$activityID]['assignee_contact_name'] = array(); + } + + if (!CRM_Utils_Array::value('target_contact_name', $values[$activityID])) { + $values[$activityID]['target_contact_name'] = array(); + } + + if (!$bulkActivityTypeID || ($bulkActivityTypeID != $dao->activity_type_id)) { + // build array of target / assignee names + if ($dao->target_contact_id) { + $values[$activityID]['target_contact_name'][$dao->target_contact_id] = $dao->target_contact_name; + } + if ($dao->assignee_contact_id) { + $values[$activityID]['assignee_contact_name'][$dao->assignee_contact_id] = $dao->assignee_contact_name; + } + + // case related fields + $values[$activityID]['case_id'] = $dao->case_id; + $values[$activityID]['case_subject'] = $dao->case_subject; + } + else { + $values[$activityID]['recipients'] = ts('(recipients)'); + $values[$activityID]['mailingId'] = ''; + if ( + $accessCiviMail && + ($mailingIDs === TRUE || in_array($dao->source_record_id, $mailingIDs)) + ) { + $values[$activityID]['mailingId'] = CRM_Utils_System::url('civicrm/mailing/report', + "mid={$dao->source_record_id}&reset=1&cid={$dao->source_contact_id}&context=activitySelector" + ); + } + } + } + + // add info on whether the related contacts are deleted (CRM-5673) + // FIXME: ideally this should be tied to ACLs + + // grab all the related contact ids + $cids = array(); + foreach ($values as $value) { + $cids[] = $value['source_contact_id']; + } + $cids = array_filter(array_unique($cids)); + + // see which of the cids are of deleted contacts + if ($cids) { + $sql = 'SELECT id FROM civicrm_contact WHERE id IN (' . implode(', ', $cids) . ') AND is_deleted = 1'; + $dao = CRM_Core_DAO::executeQuery($sql); + $dels = array(); + while ($dao->fetch()) { + $dels[] = $dao->id; + } + + // hide the deleted contacts + foreach ($values as & $value) { + if (in_array($value['source_contact_id'], $dels)) { + unset($value['source_contact_id'], $value['source_contact_name']); + } + } + } + + return $values; + } + + /** + * Get the component id and name those are enabled and logged in + * user has permission. To decide whether we are going to include + * component related activities w/ core activity retrieve process. + * + * return an array of component id and name. + * @static + **/ + static function activityComponents() { + $components = array(); + $compInfo = CRM_Core_Component::getEnabledComponents(); + foreach ($compInfo as $compObj) { + if (CRM_Utils_Array::value('showActivitiesInCore', $compObj->info)) { + if ($compObj->info['name'] == 'CiviCampaign') { + $componentPermission = "administer {$compObj->name}"; + } + else { + $componentPermission = "access {$compObj->name}"; + } + if ($compObj->info['name'] == 'CiviCase') { + if (CRM_Case_BAO_Case::accessCiviCase()) { + $components[$compObj->componentID] = $compObj->info['name']; + } + } + elseif (CRM_Core_Permission::check($componentPermission)) { + $components[$compObj->componentID] = $compObj->info['name']; + } + } + } + + return $components; + } + + /** + * function to get the activity Count + * + * @param array $input array of parameters + * Keys include + * - contact_id int contact_id whose activties we want to retrieve + * - admin boolean if contact is admin + * - caseId int case ID + * - context string page on which selector is build + * - activity_type_id int|string the activitiy types we want to restrict by + * + * @return int count of activities + * + * @access public + * @static + */ + static function &getActivitiesCount($input) { + $input['count'] = TRUE; + list($sqlClause, $params) = self::getActivitySQLClause($input); + + //filter case activities - CRM-5761 + $components = self::activityComponents(); + if (!in_array('CiviCase', $components)) { + $query = " + SELECT COUNT(DISTINCT(tbl.activity_id)) as count + FROM ( {$sqlClause} ) as tbl +LEFT JOIN civicrm_case_activity ON ( civicrm_case_activity.activity_id = tbl.activity_id ) + WHERE civicrm_case_activity.id IS NULL"; + } + else { + $query = "SELECT COUNT(DISTINCT(activity_id)) as count from ( {$sqlClause} ) as tbl"; + } + + return CRM_Core_DAO::singleValueQuery($query, $params); + } + + /** + * function to get the activity sql clause to pick activities + * + * @param array $input array of parameters + * Keys include + * - contact_id int contact_id whose activties we want to retrieve + * - admin boolean if contact is admin + * - caseId int case ID + * - context string page on which selector is build + * - count boolean are we interested in the count clause only? + * - activity_type_id int|string the activitiy types we want to restrict by + * + * @return int count of activities + * + * @access public + * @static + */ + static function getActivitySQLClause($input) { + $params = array(); + $sourceWhere = $targetWhere = $assigneeWhere = $caseWhere = 1; + + $config = CRM_Core_Config::singleton(); + if (!CRM_Utils_Array::value('admin', $input, FALSE)) { + $sourceWhere = ' source_contact_id = %1 '; + $targetWhere = ' at.target_contact_id = %1 '; + $assigneeWhere = ' aa.assignee_contact_id = %1 '; + $caseWhere = ' civicrm_case_contact.contact_id = %1 '; + + $params = array(1 => array($input['contact_id'], 'Integer')); + } + + $commonClauses = array( + "civicrm_option_group.name = 'activity_type'", + "civicrm_activity.is_deleted = 0", + "civicrm_activity.is_current_revision = 1", + "civicrm_activity.is_test = 0", + ); + + if ($input['context'] != 'activity') { + $commonClauses[] = "civicrm_activity.status_id = 1"; + } + + //Filter on component IDs. + $components = self::activityComponents(); + if (!empty($components)) { + $componentsIn = implode(',', array_keys($components)); + $commonClauses[] = "( civicrm_option_value.component_id IS NULL OR civicrm_option_value.component_id IN ( $componentsIn ) )"; + } + else { + $commonClauses[] = "civicrm_option_value.component_id IS NULL"; + } + + // activity type ID clause + if (!empty($input['activity_type_id'])) { + if (is_array($input['activity_type_id'])) { + foreach ($input['activity_type_id'] as $idx => $value) { + $input['activity_type_id'][$idx] = CRM_Utils_Type::escape($value, 'Positive'); + } + $commonClauses[] = "civicrm_activity.activity_type_id IN ( " . implode(",", $input['activity_type_id']) . " ) "; + } + else { + $activityTypeID = CRM_Utils_Type::escape($input['activity_type_id'], 'Positive'); + $commonClauses[] = "civicrm_activity.activity_type_id = $activityTypeID"; + } + } + + // exclude by activity type clause + if (!empty($input['activity_type_exclude_id'])) { + if (is_array($input['activity_type_exclude_id'])) { + foreach ($input['activity_type_exclude_id'] as $idx => $value) { + $input['activity_type_exclude_id'][$idx] = CRM_Utils_Type::escape($value, 'Positive'); + } + $commonClauses[] = "civicrm_activity.activity_type_id NOT IN ( " . implode(",", $input['activity_type_exclude_id']) . " ) "; + } + else { + $activityTypeID = CRM_Utils_Type::escape($input['activity_type_exclude_id'], 'Positive'); + $commonClauses[] = "civicrm_activity.activity_type_id != $activityTypeID"; + } + } + + $commonClause = implode(' AND ', $commonClauses); + + $includeCaseActivities = FALSE; + if (in_array('CiviCase', $components)) { + $includeCaseActivities = TRUE; + } + + + // build main activity table select clause + $sourceSelect = ''; + $sourceJoin = ''; + + if (!$input['count']) { + $sourceSelect = ', + civicrm_activity.activity_date_time, + civicrm_activity.status_id, + civicrm_activity.subject, + civicrm_activity.source_contact_id, + civicrm_activity.source_record_id, + sourceContact.sort_name as source_contact_name, + civicrm_option_value.value as activity_type_id, + civicrm_option_value.label as activity_type, + null as case_id, null as case_subject, + civicrm_activity.campaign_id as campaign_id + '; + + $sourceJoin = ' + left join civicrm_contact sourceContact on + source_contact_id = sourceContact.id '; + } + + $sourceClause = " + SELECT civicrm_activity.id as activity_id + {$sourceSelect} + from civicrm_activity + left join civicrm_option_value on + civicrm_activity.activity_type_id = civicrm_option_value.value + left join civicrm_option_group on + civicrm_option_group.id = civicrm_option_value.option_group_id + {$sourceJoin} + where + {$sourceWhere} + AND $commonClause + "; + + // build target activity table select clause + $targetAssigneeSelect = ''; + + if (!$input['count']) { + $targetAssigneeSelect = ', + civicrm_activity.activity_date_time, + civicrm_activity.status_id, + civicrm_activity.subject, + civicrm_activity.source_contact_id, + civicrm_activity.source_record_id, + sourceContact.sort_name as source_contact_name, + civicrm_option_value.value as activity_type_id, + civicrm_option_value.label as activity_type, + null as case_id, null as case_subject, + civicrm_activity.campaign_id as campaign_id + '; + } + + $targetClause = " + SELECT civicrm_activity.id as activity_id + {$targetAssigneeSelect} + from civicrm_activity + inner join civicrm_activity_target at on + civicrm_activity.id = at.activity_id and {$targetWhere} + left join civicrm_option_value on + civicrm_activity.activity_type_id = civicrm_option_value.value + left join civicrm_option_group on + civicrm_option_group.id = civicrm_option_value.option_group_id + {$sourceJoin} + where + {$targetWhere} + AND $commonClause + "; + + // build assignee activity table select clause + $assigneeClause = " + SELECT civicrm_activity.id as activity_id + {$targetAssigneeSelect} + from civicrm_activity + inner join civicrm_activity_assignment aa on + civicrm_activity.id = aa.activity_id and {$assigneeWhere} + left join civicrm_option_value on + civicrm_activity.activity_type_id = civicrm_option_value.value + left join civicrm_option_group on + civicrm_option_group.id = civicrm_option_value.option_group_id + {$sourceJoin} + where + {$assigneeWhere} + AND $commonClause + + "; + + // Build case clause + // or else exclude Inbound Emails that have been filed on a case. + $caseClause = ''; + + if ($includeCaseActivities) { + $caseSelect = ''; + if (!$input['count']) { + $caseSelect = ', + civicrm_activity.activity_date_time, + civicrm_activity.status_id, + civicrm_activity.subject, + civicrm_activity.source_contact_id, + civicrm_activity.source_record_id, + sourceContact.sort_name as source_contact_name, + civicrm_option_value.value as activity_type_id, + civicrm_option_value.label as activity_type, + null as case_id, null as case_subject, + civicrm_activity.campaign_id as campaign_id'; + } + + $caseClause = " + union all + + SELECT civicrm_activity.id as activity_id + {$caseSelect} + from civicrm_activity + inner join civicrm_case_activity on + civicrm_case_activity.activity_id = civicrm_activity.id + inner join civicrm_case on + civicrm_case_activity.case_id = civicrm_case.id + inner join civicrm_case_contact on + civicrm_case_contact.case_id = civicrm_case.id and {$caseWhere} + left join civicrm_option_value on + civicrm_activity.activity_type_id = civicrm_option_value.value + left join civicrm_option_group on + civicrm_option_group.id = civicrm_option_value.option_group_id + {$sourceJoin} + where + {$caseWhere} + AND $commonClause + and ( ( civicrm_case_activity.case_id IS NULL ) OR + ( civicrm_option_value.name <> 'Inbound Email' AND + civicrm_option_value.name <> 'Email' AND civicrm_case_activity.case_id + IS NOT NULL ) + ) + "; + } + + $returnClause = " {$sourceClause} union all {$targetClause} union all {$assigneeClause} {$caseClause} "; + + return array($returnClause, $params); + } + + /** + * send the message to all the contacts and also insert a + * contact activity in each contacts record + * + * @param array $contactDetails the array of contact details to send the email + * @param string $subject the subject of the message + * @param string $message the message contents + * @param string $emailAddress use this 'to' email address instead of the default Primary address + * @param int $userID use this userID if set + * @param string $from + * @param array $attachments the array of attachments if any + * @param string $cc cc recepient + * @param string $bcc bcc recepient + * @param array $contactIds contact ids + * + * @return array ( sent, activityId) if any email is sent and activityId + * @access public + * @static + */ + static function sendEmail( + &$contactDetails, + &$subject, + &$text, + &$html, + $emailAddress, + $userID = NULL, + $from = NULL, + $attachments = NULL, + $cc = NULL, + $bcc = NULL, + $contactIds // FIXME a param with no default shouldn't be last + ) { + // get the contact details of logged in contact, which we set as from email + if ($userID == NULL) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + } + + list($fromDisplayName, $fromEmail, $fromDoNotEmail) = CRM_Contact_BAO_Contact::getContactDetails($userID); + if (!$fromEmail) { + return array(count($contactDetails), 0, count($contactDetails)); + } + if (!trim($fromDisplayName)) { + $fromDisplayName = $fromEmail; + } + + // CRM-4575 + // token replacement of addressee/email/postal greetings + // get the tokens added in subject and message + $subjectToken = CRM_Utils_Token::getTokens($subject); + $messageToken = CRM_Utils_Token::getTokens($text); + $messageToken = array_merge($messageToken, CRM_Utils_Token::getTokens($html)); + + if (!$from) { + $from = "$fromDisplayName <$fromEmail>"; + } + + //create the meta level record first ( email activity ) + $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', + 'Email', + 'name' + ); + + // CRM-6265: save both text and HTML parts in details (if present) + if ($html and $text) { + $details = "-ALTERNATIVE ITEM 0-\n$html\n-ALTERNATIVE ITEM 1-\n$text\n-ALTERNATIVE END-\n"; + } + else { + $details = $html ? $html : $text; + } + + $activityParams = array( + 'source_contact_id' => $userID, + 'activity_type_id' => $activityTypeID, + 'activity_date_time' => date('YmdHis'), + 'subject' => $subject, + 'details' => $details, + // FIXME: check for name Completed and get ID from that lookup + 'status_id' => 2, + ); + + // CRM-5916: strip [case #…] before saving the activity (if present in subject) + $activityParams['subject'] = preg_replace('/\[case #([0-9a-h]{7})\] /', '', $activityParams['subject']); + + // add the attachments to activity params here + if ($attachments) { + // first process them + $activityParams = array_merge($activityParams, + $attachments + ); + } + + $activity = self::create($activityParams); + + // get the set of attachments from where they are stored + $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_activity', + $activity->id + ); + $returnProperties = array(); + if (isset($messageToken['contact'])) { + foreach ($messageToken['contact'] as $key => $value) { + $returnProperties[$value] = 1; + } + } + + if (isset($subjectToken['contact'])) { + foreach ($subjectToken['contact'] as $key => $value) { + if (!isset($returnProperties[$value])) { + $returnProperties[$value] = 1; + } + } + } + + + // get token details for contacts, call only if tokens are used + $details = array(); + if (!empty($returnProperties)) { + list($details) = CRM_Utils_Token::getTokenDetails( + $contactIds, + $returnProperties, + NULL, NULL, FALSE, + $messageToken, + 'CRM_Activity_BAO_Activity' + ); + } + + // call token hook + $tokens = array(); + CRM_Utils_Hook::tokens($tokens); + $categories = array_keys($tokens); + + $escapeSmarty = FALSE; + if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) { + $smarty = CRM_Core_Smarty::singleton(); + $escapeSmarty = TRUE; + } + + $sent = $notSent = array(); + foreach ($contactDetails as $values) { + $contactId = $values['contact_id']; + $emailAddress = $values['email']; + + if (!empty($details) && is_array($details["{$contactId}"])) { + // unset email from details since it always returns primary email address + unset($details["{$contactId}"]['email']); + unset($details["{$contactId}"]['email_id']); + $values = array_merge($values, $details["{$contactId}"]); + } + + $tokenSubject = CRM_Utils_Token::replaceContactTokens($subject, $values, FALSE, $subjectToken, FALSE, $escapeSmarty); + $tokenSubject = CRM_Utils_Token::replaceHookTokens($tokenSubject, $values, $categories, FALSE, $escapeSmarty); + + //CRM-4539 + if ($values['preferred_mail_format'] == 'Text' || $values['preferred_mail_format'] == 'Both') { + $tokenText = CRM_Utils_Token::replaceContactTokens($text, $values, FALSE, $messageToken, FALSE, $escapeSmarty); + $tokenText = CRM_Utils_Token::replaceHookTokens($tokenText, $values, $categories, FALSE, $escapeSmarty); + } + else { + $tokenText = NULL; + } + + if ($values['preferred_mail_format'] == 'HTML' || $values['preferred_mail_format'] == 'Both') { + $tokenHtml = CRM_Utils_Token::replaceContactTokens($html, $values, TRUE, $messageToken, FALSE, $escapeSmarty); + $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $values, $categories, TRUE, $escapeSmarty); + } + else { + $tokenHtml = NULL; + } + + if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) { + // also add the contact tokens to the template + $smarty->assign_by_ref('contact', $values); + + $tokenSubject = $smarty->fetch("string:$tokenSubject"); + $tokenText = $smarty->fetch("string:$tokenText"); + $tokenHtml = $smarty->fetch("string:$tokenHtml"); + } + + $sent = FALSE; + if (self::sendMessage( + $from, + $userID, + $contactId, + $tokenSubject, + $tokenText, + $tokenHtml, + $emailAddress, + $activity->id, + $attachments, + $cc, + $bcc + )) { + $sent = TRUE; + } + } + + return array($sent, $activity->id); + } + + static function sendSMS(&$contactDetails, + &$activityParams, + &$smsParams = array(), + &$contactIds, + $userID = NULL + ) { + if ($userID == NULL) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + } + + $text = &$activityParams['text_message']; + $html = &$activityParams['html_message']; + + // CRM-4575 + // token replacement of addressee/email/postal greetings + // get the tokens added in subject and message + $messageToken = CRM_Utils_Token::getTokens($text); + $messageToken = array_merge($messageToken, + CRM_Utils_Token::getTokens($html) + ); + + //create the meta level record first ( sms activity ) + $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', + 'SMS', + 'name' + ); + + // CRM-6265: save both text and HTML parts in details (if present) + if ($html and $text) { + $details = "-ALTERNATIVE ITEM 0-\n$html\n-ALTERNATIVE ITEM 1-\n$text\n-ALTERNATIVE END-\n"; + } + else { + $details = $html ? $html : $text; + } + + $activitySubject = $activityParams['activity_subject']; + $activityParams = array( + 'source_contact_id' => $userID, + 'activity_type_id' => $activityTypeID, + 'activity_date_time' => date('YmdHis'), + 'subject' => $activitySubject, + 'details' => $details, + // FIXME: check for name Completed and get ID from that lookup + 'status_id' => 2, + ); + + $activity = self::create($activityParams); + $activityID = $activity->id; + + $returnProperties = array(); + + if (isset($messageToken['contact'])) { + foreach ($messageToken['contact'] as $key => $value) { + $returnProperties[$value] = 1; + } + } + + // call token hook + $tokens = array(); + CRM_Utils_Hook::tokens($tokens); + $categories = array_keys($tokens); + + // get token details for contacts, call only if tokens are used + $details = array(); + if (!empty($returnProperties) || !empty($tokens)) { + list($details) = CRM_Utils_Token::getTokenDetails($contactIds, + $returnProperties, + NULL, NULL, FALSE, + $messageToken, + 'CRM_Activity_BAO_Activity' + ); + } + + $escapeSmarty = $sent = FALSE; + foreach ($contactDetails as $values) { + $contactId = $values['contact_id']; + + if (!empty($details) && is_array($details["{$contactId}"])) { + // unset email from details since it always returns primary email address + unset($details["{$contactId}"]['email']); + unset($details["{$contactId}"]['email_id']); + $values = array_merge($values, $details["{$contactId}"]); + } + + $tokenText = CRM_Utils_Token::replaceContactTokens($text, $values, FALSE, $messageToken, FALSE, $escapeSmarty); + $tokenText = CRM_Utils_Token::replaceHookTokens($tokenText, $values, $categories, FALSE, $escapeSmarty); + + $tokenHtml = CRM_Utils_Token::replaceContactTokens($html, $values, TRUE, $messageToken, FALSE, $escapeSmarty); + $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $values, $categories, TRUE, $escapeSmarty); + + $smsParams['To'] = $values['phone']; + + if (self::sendSMSMessage($contactId, + $tokenText, + $tokenHtml, + $smsParams, + $activityID + )) { + // even a single successful delivery should set this falg to true + $sent = TRUE; + } + } + + return array($sent, $activity->id); + } + + /** + * send the sms message to a specific contact + * + * @param int $toID the contact id of the recipient + * @param int $activityID the activity ID that tracks the message + * @param array $smsParams the params used for sending sms + * + * @return boolean true if successfull else false. + * @access public + * @static + */ + static function sendSMSMessage($toID, + &$tokenText, + &$tokenHtml, + $smsParams = array(), + $activityID + ) { + $toDoNotSms = ""; + $toPhoneNumber = ""; + + if ($smsParams['To']) { + $toPhoneNumber = trim($smsParams['To']); + } + elseif ($toID) { + $filters = array('is_deceased' => 0, 'is_deleted' => 0, 'do_not_sms' => 0); + $toPhoneNumbers = CRM_Core_BAO_Phone::allPhones($toID, FALSE, 'Mobile', $filters); + //to get primary mobile ph,if not get a first mobile ph + if (!empty($toPhoneNumbers)) { + $toPhoneNumerDetails = reset($toPhoneNumbers); + $toPhoneNumber = CRM_Utils_Array::value('phone', $toPhoneNumerDetails); + //contact allows to send sms + $toDoNotSms = 0; + } + } + + // make sure both phone are valid + // and that the recipient wants to receive sms + if (empty($toPhoneNumber) or $toDoNotSms) { + return FALSE; + } + + $message = $tokenHtml ? $tokenHtml : $tokenText; + $recipient = $smsParams['To']; + $smsParams['contact_id'] = $toID; + $smsParams['parent_activity_id'] = $activityID; + + $providerObj = CRM_SMS_Provider::singleton(array('provider_id' => $smsParams['provider_id'])); + if (!$providerObj->send($recipient, $smsParams, $message, NULL)) { + return FALSE; + } + + // add activity target record for every sms that is send + $activityTargetParams = array( + 'activity_id' => $activityID, + 'target_contact_id' => $toID, + ); + self::createActivityTarget($activityTargetParams); + + return TRUE; + } + + /** + * send the message to a specific contact + * + * @param string $from the name and email of the sender + * @param int $toID the contact id of the recipient + * @param string $subject the subject of the message + * @param string $message the message contents + * @param string $emailAddress use this 'to' email address instead of the default Primary address + * @param int $activityID the activity ID that tracks the message + * + * @return boolean true if successfull else false. + * @access public + * @static + */ + static function sendMessage($from, + $fromID, + $toID, + &$subject, + &$text_message, + &$html_message, + $emailAddress, + $activityID, + $attachments = NULL, + $cc = NULL, + $bcc = NULL + ) { + list($toDisplayName, $toEmail, $toDoNotEmail) = CRM_Contact_BAO_Contact::getContactDetails($toID); + if ($emailAddress) { + $toEmail = trim($emailAddress); + } + + // make sure both email addresses are valid + // and that the recipient wants to receive email + if (empty($toEmail) or $toDoNotEmail) { + return FALSE; + } + if (!trim($toDisplayName)) { + $toDisplayName = $toEmail; + } + + // create the params array + $mailParams = array( + 'groupName' => 'Activity Email Sender', + 'from' => $from, + 'toName' => $toDisplayName, + 'toEmail' => $toEmail, + 'subject' => $subject, + 'cc' => $cc, + 'bcc' => $bcc, + 'text' => $text_message, + 'html' => $html_message, + 'attachments' => $attachments, + ); + + if (!CRM_Utils_Mail::send($mailParams)) { + return FALSE; + } + + // add activity target record for every mail that is send + $activityTargetParams = array( + 'activity_id' => $activityID, + 'target_contact_id' => $toID, + ); + self::createActivityTarget($activityTargetParams); + return TRUE; + } + + /** + * combine all the importable fields from the lower levels object + * + * The ordering is important, since currently we do not have a weight + * scheme. Adding weight is super important and should be done in the + * next week or so, before this can be called complete. + * + * @param NULL + * + * @return array array of importable Fields + * @access public + * @static + */ + static function &importableFields($status = FALSE) { + if (!self::$_importableFields) { + if (!self::$_importableFields) { + self::$_importableFields = array(); + } + if (!$status) { + $fields = array('' => array('title' => ts('- do not import -'))); + } + else { + $fields = array('' => array('title' => ts('- Activity Fields -'))); + } + + $tmpFields = CRM_Activity_DAO_Activity::import(); + $contactFields = CRM_Contact_BAO_Contact::importableFields('Individual', NULL); + + // Using new Dedupe rule. + $ruleParams = array( + 'contact_type' => 'Individual', + 'used' => 'Unsupervised', + ); + $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); + + $tmpConatctField = array(); + if (is_array($fieldsArray)) { + foreach ($fieldsArray as $value) { + $customFieldId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', + $value, + 'id', + 'column_name' + ); + $value = $customFieldId ? 'custom_' . $customFieldId : $value; + $tmpConatctField[trim($value)] = $contactFields[trim($value)]; + $tmpConatctField[trim($value)]['title'] = $tmpConatctField[trim($value)]['title'] . " (match to contact)"; + } + } + $tmpConatctField['external_identifier'] = $contactFields['external_identifier']; + $tmpConatctField['external_identifier']['title'] = $contactFields['external_identifier']['title'] . " (match to contact)"; + $fields = array_merge($fields, $tmpConatctField); + $fields = array_merge($fields, $tmpFields); + $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Activity')); + self::$_importableFields = $fields; + } + return self::$_importableFields; + } + + /** + * To get the Activities of a target contact + * + * @param $contactId Integer ContactId of the contact whose activities + * need to find + * + * @return array array of activity fields + * @access public + */ + static function getContactActivity($contactId) { + $activities = array(); + + // First look for activities where contactId is one of the targets + $query = "SELECT activity_id FROM civicrm_activity_target + WHERE target_contact_id = $contactId"; + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + while ($dao->fetch()) { + $activities[$dao->activity_id]['targets'][$contactId] = $contactId; + } + + // Then get activities where contactId is an asignee + $query = "SELECT activity_id FROM civicrm_activity_assignment + WHERE assignee_contact_id = $contactId"; + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + while ($dao->fetch()) { + $activities[$dao->activity_id]['asignees'][$contactId] = $contactId; + } + + // Then get activities that contactId created + $query = "SELECT id AS activity_id FROM civicrm_activity + WHERE source_contact_id = $contactId"; + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + while ($dao->fetch()) { + $activities[$dao->activity_id]['source_contact_id'][] = $contactId; + } + $activityIds = array(); + // Then look up the activity details for each activity_id we saw above + foreach ($activities as $activityId => $dummy) { + $activityIds[] = $activityId; + } + if (count($activityIds) < 1) { + return array(); + } + $activityIds = implode(',', $activityIds); + $query = "SELECT activity.id as activity_id, source_contact_id, target_contact_id, assignee_contact_id, activity_type_id, + subject, location, activity_date_time, details, status_id + FROM civicrm_activity activity + LEFT JOIN civicrm_activity_target target ON activity.id = target.activity_id + LEFT JOIN civicrm_activity_assignment assignment ON activity.id = assignment.activity_id + WHERE activity.id IN ($activityIds)"; + + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + + $activityTypes = CRM_Core_OptionGroup::values('activity_type'); + $activityStatuses = CRM_Core_OptionGroup::values('activity_status'); + + while ($dao->fetch()) { + $activities[$dao->activity_id]['source_contact_id'] = $dao->source_contact_id; + $activities[$dao->activity_id]['id'] = $dao->activity_id; + if ($dao->target_contact_id) { + $activities[$dao->activity_id]['targets'][$dao->target_contact_id] = $dao->target_contact_id; + } + if (isset($dao->assignee_contact_id)) { + $activities[$dao->activity_id]['asignees'][$dao->assignee_contact_id] = $dao->assignee_contact_id; + } + $activities[$dao->activity_id]['activity_type_id'] = $dao->activity_type_id; + $activities[$dao->activity_id]['subject'] = $dao->subject; + $activities[$dao->activity_id]['location'] = $dao->location; + $activities[$dao->activity_id]['activity_date_time'] = $dao->activity_date_time; + $activities[$dao->activity_id]['details'] = $dao->details; + $activities[$dao->activity_id]['status_id'] = $dao->status_id; + $activities[$dao->activity_id]['activity_name'] = $activityTypes[$dao->activity_type_id]; + $activities[$dao->activity_id]['status'] = $activityStatuses[$dao->status_id]; + } + return $activities; + } + + /** + * Function to add activity for Membership/Event/Contribution + * + * @param object $activity (reference) perticular component object + * @param string $activityType for Membership Signup or Renewal + * + * + * @static + * @access public + */ + static function addActivity(&$activity, + $activityType = 'Membership Signup', + $targetContactID = NULL + ) { + if ($activity->__table == 'civicrm_membership') { + $membershipType = CRM_Member_PseudoConstant::membershipType($activity->membership_type_id); + + if (!$membershipType) { + $membershipType = ts('Membership'); + } + + $subject = "{$membershipType}"; + + if (!empty($activity->source) && $activity->source != 'null') { + $subject .= " - {$activity->source}"; + } + + if ($activity->owner_membership_id) { + $query = " +SELECT display_name + FROM civicrm_contact, civicrm_membership + WHERE civicrm_contact.id = civicrm_membership.contact_id + AND civicrm_membership.id = $activity->owner_membership_id +"; + $displayName = CRM_Core_DAO::singleValueQuery($query); + $subject .= " (by {$displayName})"; + } + + $subject .= " - Status: " . CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', $activity->status_id); + // CRM-72097 changed from start date to today + $date = date('YmdHis'); + $component = 'Membership'; + } + elseif ($activity->__table == 'civicrm_participant') { + $event = CRM_Event_BAO_Event::getEvents(TRUE, $activity->event_id, TRUE, FALSE); + + $roles = CRM_Event_PseudoConstant::participantRole(); + $status = CRM_Event_PseudoConstant::participantStatus(); + + $subject = $event[$activity->event_id]; + if (CRM_Utils_Array::value($activity->role_id, $roles)) { + $subject .= ' - ' . $roles[$activity->role_id]; + } + if (CRM_Utils_Array::value($activity->status_id, $status)) { + $subject .= ' - ' . $status[$activity->status_id]; + } + $date = date('YmdHis'); + if ($activityType != 'Email') { + $activityType = 'Event Registration'; + } + $component = 'Event'; + } + elseif ($activity->__table == 'civicrm_contribution') { + //create activity record only for Completed Contributions + if ($activity->contribution_status_id != 1) { + return; + } + + $subject = NULL; + + $subject .= CRM_Utils_Money::format($activity->total_amount, $activity->currency); + if (!empty($activity->source) && $activity->source != 'null') { + $subject .= " - {$activity->source}"; + } + $date = CRM_Utils_Date::isoToMysql($activity->receive_date); + $activityType = $component = 'Contribution'; + } + $activityParams = array( + 'source_contact_id' => $activity->contact_id, + 'source_record_id' => $activity->id, + 'activity_type_id' => CRM_Core_OptionGroup::getValue('activity_type', + $activityType, + 'name' + ), + 'subject' => $subject, + 'activity_date_time' => $date, + 'is_test' => $activity->is_test, + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + 'Completed', + 'name' + ), + 'skipRecentView' => TRUE, + 'campaign_id' => $activity->campaign_id, + ); + + // create activity with target contacts + $session = CRM_Core_Session::singleton(); + $id = $session->get('userID'); + if ($id) { + $activityParams['source_contact_id'] = $id; + $activityParams['target_contact_id'][] = $activity->contact_id; + } + + //CRM-4027 + if ($targetContactID) { + $activityParams['target_contact_id'][] = $targetContactID; + } + if (is_a(self::create($activityParams), 'CRM_Core_Error')) { + CRM_Core_Error::fatal("Failed creating Activity for $component of id {$activity->id}"); + return FALSE; + } + } + + /** + * Function to get Parent activity for currently viewd activity + * + * @param int $activityId current activity id + * + * @return int $parentId Id of parent acyivity otherwise false. + * @access public + */ + static function getParentActivity($activityId) { + static $parentActivities = array(); + + $activityId = CRM_Utils_Type::escape($activityId, 'Integer'); + + if (!array_key_exists($activityId, $parentActivities)) { + $parentActivities[$activityId] = array(); + + $parentId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', + $activityId, + 'parent_id' + ); + + $parentActivities[$activityId] = $parentId ? $parentId : FALSE; + } + + return $parentActivities[$activityId]; + } + + /** + * Function to get total count of prior revision of currently viewd activity + * + * @param int $activityId current activity id + * + * @return int $params count of prior acyivities otherwise false. + * @access public + */ + static function getPriorCount($activityID) { + static $priorCounts = array(); + + $activityID = CRM_Utils_Type::escape($activityID, 'Integer'); + + if (!array_key_exists($activityID, $priorCounts)) { + $priorCounts[$activityID] = array(); + $originalID = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', + $activityID, + 'original_id' + ); + $count = 0; + if ($originalID) { + $query = " +SELECT count( id ) AS cnt +FROM civicrm_activity +WHERE ( id = {$originalID} OR original_id = {$originalID} ) +AND is_current_revision = 0 +AND id < {$activityID} +"; + $params = array(1 => array($originalID, 'Integer')); + $count = CRM_Core_DAO::singleValueQuery($query, $params); + } + $priorCounts[$activityID] = $count ? $count : 0; + } + + return $priorCounts[$activityID]; + } + + /** + * Function to get all prior activities of currently viewd activity + * + * @param int $activityId current activity id + * + * @return array $result prior acyivities info. + * @access public + */ + static function getPriorAcitivities($activityID, $onlyPriorRevisions = FALSE) { + static $priorActivities = array(); + + $activityID = CRM_Utils_Type::escape($activityID, 'Integer'); + $index = $activityID . '_' . (int) $onlyPriorRevisions; + + if (!array_key_exists($index, $priorActivities)) { + $priorActivities[$index] = array(); + + $originalID = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', + $activityID, + 'original_id' + ); + if ($originalID) { + $query = " +SELECT c.display_name as name, cl.modified_date as date, ca.id as activityID +FROM civicrm_log cl, civicrm_contact c, civicrm_activity ca +WHERE (ca.id = %1 OR ca.original_id = %1) +AND cl.entity_table = 'civicrm_activity' +AND cl.entity_id = ca.id +AND cl.modified_id = c.id +"; + if ($onlyPriorRevisions) { + $query .= " AND ca.id < {$activityID}"; + } + $query .= " ORDER BY ca.id DESC"; + + $params = array(1 => array($originalID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + while ($dao->fetch()) { + $priorActivities[$index][$dao->activityID]['id'] = $dao->activityID; + $priorActivities[$index][$dao->activityID]['name'] = $dao->name; + $priorActivities[$index][$dao->activityID]['date'] = $dao->date; + $priorActivities[$index][$dao->activityID]['link'] = 'javascript:viewActivity( $dao->activityID );'; + } + $dao->free(); + } + } + return $priorActivities[$index]; + } + + /** + * Function to find the latest revision of a given activity + * + * @param int $activityId prior activity id + * + * @return int $params current activity id. + * @access public + */ + static function getLatestActivityId($activityID) { + static $latestActivityIds = array(); + + $activityID = CRM_Utils_Type::escape($activityID, 'Integer'); + + if (!array_key_exists($activityID, $latestActivityIds)) { + $latestActivityIds[$activityID] = array(); + + $originalID = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', + $activityID, + 'original_id' + ); + if ($originalID) { + $activityID = $originalID; + } + $params = array(1 => array($activityID, 'Integer')); + $query = "SELECT id from civicrm_activity where original_id = %1 and is_current_revision = 1"; + + $latestActivityIds[$activityID] = CRM_Core_DAO::singleValueQuery($query, $params); + } + + return $latestActivityIds[$activityID]; + } + + /** + * Function to create a follow up a given activity + * + * @activityId int activity id of parent activity + * + * @param array $activity details + * + * @access public + */ + static function createFollowupActivity($activityId, $params) { + if (!$activityId) { + return; + } + + $session = CRM_Core_Session::singleton(); + + $followupParams = array(); + $followupParams['parent_id'] = $activityId; + $followupParams['source_contact_id'] = $session->get('userID'); + $followupParams['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Scheduled', 'name'); + + $followupParams['activity_type_id'] = $params['followup_activity_type_id']; + // Get Subject of Follow-up Activiity, CRM-4491 + $followupParams['subject'] = CRM_Utils_Array::value('followup_activity_subject', $params); + + //create target contact for followup + if (CRM_Utils_Array::value('target_contact_id', $params)) { + $followupParams['target_contact_id'] = $params['target_contact_id']; + } + + $followupParams['activity_date_time'] = CRM_Utils_Date::processDate($params['followup_date'], + $params['followup_date_time'] + ); + $followupActivity = self::create($followupParams); + + return $followupActivity; + } + + /** + * Function to get Activity specific File according activity type Id. + * + * @param int $activityTypeId activity id + * + * @return if file exists returns $activityTypeFile activity filename otherwise false. + * + * @static + */ + static function getFileForActivityTypeId($activityTypeId, $crmDir = 'Activity') { + $activityTypes = CRM_Case_PseudoConstant::caseActivityType(FALSE, TRUE); + + if ($activityTypes[$activityTypeId]['name']) { + $activityTypeFile = CRM_Utils_String::munge(ucwords($activityTypes[$activityTypeId]['name']), '', 0); + } + else { + return FALSE; + } + + global $civicrm_root; + $config = CRM_Core_Config::singleton(); + if (!file_exists(rtrim($civicrm_root, '/') . "/CRM/{$crmDir}/Form/Activity/{$activityTypeFile}.php")) { + if (empty($config->customPHPPathDir)) { + return FALSE; + } + elseif (!file_exists(rtrim($config->customPHPPathDir, '/') . "/CRM/{$crmDir}/Form/Activity/{$activityTypeFile}.php")) { + return FALSE; + } + } + + return $activityTypeFile; + } + + /** + * Function to restore the activity + * + * @param array $params associated array + * + * @return void + * @access public + * + */ + public static function restoreActivity(&$params) { + $activity = new CRM_Activity_DAO_Activity(); + $activity->copyValues($params); + + $activity->is_deleted = 0; + $result = $activity->save(); + + return $result; + } + + /** + * Get the exportable fields for Activities + * + * @param string $name if it is called by case $name = Case else $name = Activity + * + * @return array array of exportable Fields + * @access public + * @static + */ + static function &exportableFields($name = 'Activity') { + if (!isset(self::$_exportableFields[$name])) { + self::$_exportableFields[$name] = array(); + + // TO DO, ideally we should retrieve all fields from xml, in this case since activity processing is done + // my case hence we have defined fields as case_* + if ($name == 'Activity') { + $exportableFields = CRM_Activity_DAO_Activity::export(); + if (isset($exportableFields['activity_campaign_id'])) { + $exportableFields['activity_campaign'] = array('title' => ts('Campaign Title')); + } + $exportableFields['source_contact_id']['title'] = ts('Source Contact ID'); + $exportableFields['source_contact'] = array( + 'title' => ts('Source Contact'), + 'type' => CRM_Utils_Type::T_STRING, + ); + + + $Activityfields = array( + 'activity_type' => array('title' => ts('Activity Type'), 'type' => CRM_Utils_Type::T_STRING), + 'activity_status' => array('title' => ts('Activity Status'), 'type' => CRM_Utils_Type::T_STRING), + ); + $fields = array_merge($Activityfields, $exportableFields); + } + else { + //set title to activity fields + $fields = array( + 'case_activity_subject' => array('title' => ts('Activity Subject'), 'type' => CRM_Utils_Type::T_STRING), + 'case_source_contact_id' => array('title' => ts('Activity Reporter'), 'type' => CRM_Utils_Type::T_STRING), + 'case_recent_activity_date' => array('title' => ts('Activity Actual Date'), 'type' => CRM_Utils_Type::T_DATE), + 'case_scheduled_activity_date' => array('title' => ts('Activity Scheduled Date'), 'type' => CRM_Utils_Type::T_DATE), + 'case_recent_activity_type' => array('title' => ts('Activity Type'), 'type' => CRM_Utils_Type::T_STRING), + 'case_activity_status' => array('title' => ts('Activity Status'), 'type' => CRM_Utils_Type::T_STRING), + 'case_activity_duration' => array('title' => ts('Activity Duration'), 'type' => CRM_Utils_Type::T_INT), + 'case_activity_medium_id' => array('title' => ts('Activity Medium'), 'type' => CRM_Utils_Type::T_INT), + 'case_activity_details' => array('title' => ts('Activity Details'), 'type' => CRM_Utils_Type::T_TEXT), + 'case_activity_is_auto' => array('title' => ts('Activity Auto-generated?'), 'type' => CRM_Utils_Type::T_BOOLEAN), + ); + + // add custom data for cases + $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Case')); + } + + // add custom data for case activities + $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Activity')); + + self::$_exportableFields[$name] = $fields; + } + return self::$_exportableFields[$name]; + } + + /** + * Get the allowed profile fields for Activities + * + * @return array array of activity profile Fields + * @access public + */ + static function getProfileFields() { + $exportableFields = self::exportableFields('Activity'); + $skipFields = array('activity_id', 'activity_type', 'source_contact_id', 'activity_campaign', 'activity_is_test', 'is_current_revision', 'activity_is_deleted',); + $config = CRM_Core_Config::singleton(); + if (!in_array('CiviCampaign', $config->enableComponents)) { + $skipFields[] = 'activity_engagement_level'; + } + + foreach ($skipFields as $field) { + if (isset($exportableFields[$field])) { + unset($exportableFields[$field]); + } + } + + // hack to use 'activity_type_id' instead of 'activity_type' + $exportableFields['activity_status_id'] = $exportableFields['activity_status']; + unset($exportableFields['activity_status']); + + return $exportableFields; + } + + /** + * This function delete activity record related to contact record, + * when there are no target and assignee record w/ other contact. + * + * @param int $contactId contactId + * + * @return true/null + * @access public + */ + public static function cleanupActivity($contactId) { + $result = NULL; + if (!$contactId) { + return $result; + } + + $transaction = new CRM_Core_Transaction(); + + // delete activity if there are no record in + // civicrm_activity_assignment or civicrm_activity_target + // pointing to any other contact record. + + + $activity = new CRM_Activity_DAO_Activity(); + $activity->source_contact_id = $contactId; + $activity->find(); + + while ($activity->fetch()) { + $noTarget = $noAssignee = TRUE; + + // check for target activity record. + $target = new CRM_Activity_DAO_ActivityTarget(); + $target->activity_id = $activity->id; + $target->find(); + while ($target->fetch()) { + if ($target->target_contact_id != $contactId) { + $noTarget = FALSE; + break; + } + } + $target->free(); + + // check for assignee activity record. + $assignee = new CRM_Activity_DAO_ActivityAssignment(); + $assignee->activity_id = $activity->id; + $assignee->find(); + while ($assignee->fetch()) { + if ($assignee->assignee_contact_id != $contactId) { + $noAssignee = FALSE; + break; + } + } + $assignee->free(); + + // finally delete activity. + if ($noTarget && $noAssignee) { + $activityParams = array('id' => $activity->id); + $result = self::deleteActivity($activityParams); + } + } + $activity->free(); + + $transaction->commit(); + + return $result; + } + + /** + * Does user has sufficient permission for view/edit activity record. + * + * @param int $activityId activity record id. + * @param int $action edit/view + * + * @return boolean $allow true/false + * @access public + */ + public static function checkPermission($activityId, $action) { + $allow = FALSE; + if (!$activityId || + !in_array($action, array(CRM_Core_Action::UPDATE, CRM_Core_Action::VIEW)) + ) { + return $allow; + } + + $activity = new CRM_Activity_DAO_Activity(); + $activity->id = $activityId; + if (!$activity->find(TRUE)) { + return $allow; + } + + //component related permissions. + $compPermissions = array( + 'CiviCase' => array('administer CiviCase', + 'access my cases and activities', + 'access all cases and activities', + ), + 'CiviMail' => array('access CiviMail'), + 'CiviEvent' => array('access CiviEvent'), + 'CiviGrant' => array('access CiviGrant'), + 'CiviPledge' => array('access CiviPledge'), + 'CiviMember' => array('access CiviMember'), + 'CiviReport' => array('access CiviReport'), + 'CiviContribute' => array('access CiviContribute'), + 'CiviCampaign' => array('administer CiviCampaign'), + ); + + //return early when it is case activity. + $isCaseActivity = CRM_Case_BAO_Case::isCaseActivity($activityId); + //check for civicase related permission. + if ($isCaseActivity) { + $allow = FALSE; + foreach ($compPermissions['CiviCase'] as $per) { + if (CRM_Core_Permission::check($per)) { + $allow = TRUE; + break; + } + } + + //check for case specific permissions. + if ($allow) { + $oper = 'view'; + if ($action == CRM_Core_Action::UPDATE) { + $oper = 'edit'; + } + $allow = CRM_Case_BAO_Case::checkPermission($activityId, + $oper, + $activity->activity_type_id + ); + } + + return $allow; + } + + + //first check the component permission. + $sql = " + SELECT component_id + FROM civicrm_option_value val +INNER JOIN civicrm_option_group grp ON ( grp.id = val.option_group_id AND grp.name = %1 ) + WHERE val.value = %2"; + $params = array(1 => array('activity_type', 'String'), + 2 => array($activity->activity_type_id, 'Integer'), + ); + $componentId = CRM_Core_DAO::singleValueQuery($sql, $params); + + if ($componentId) { + $componentName = CRM_Core_Component::getComponentName($componentId); + $compPermission = CRM_Utils_Array::value($componentName, $compPermissions); + + //here we are interesting in any single permission. + if (is_array($compPermission)) { + foreach ($compPermission as $per) { + if (CRM_Core_Permission::check($per)) { + $allow = TRUE; + break; + } + } + } + } + + //check for this permission related to contact. + $permission = CRM_Core_Permission::VIEW; + if ($action == CRM_Core_Action::UPDATE) { + $permission = CRM_Core_Permission::EDIT; + } + + //check for source contact. + if (!$componentId || $allow) { + $allow = CRM_Contact_BAO_Contact_Permission::allow($activity->source_contact_id, $permission); + } + + //check for target and assignee contacts. + if ($allow) { + //first check for supper permission. + $supPermission = 'view all contacts'; + if ($action == CRM_Core_Action::UPDATE) { + $supPermission = 'edit all contacts'; + } + $allow = CRM_Core_Permission::check($supPermission); + + //user might have sufficient permission, through acls. + if (!$allow) { + $allow = TRUE; + //get the target contacts. + $targetContacts = CRM_Activity_BAO_ActivityTarget::retrieveTargetIdsByActivityId($activity->id); + foreach ($targetContacts as $cnt => $contactId) { + if (!CRM_Contact_BAO_Contact_Permission::allow($contactId, $permission)) { + $allow = FALSE; + break; + } + } + + //get the assignee contacts. + if ($allow) { + $assigneeContacts = CRM_Activity_BAO_ActivityAssignment::retrieveAssigneeIdsByActivityId($activity->id); + foreach ($assigneeContacts as $cnt => $contactId) { + if (!CRM_Contact_BAO_Contact_Permission::allow($contactId, $permission)) { + $allow = FALSE; + break; + } + } + } + } + } + + return $allow; + } + + /** + * This function is a wrapper for ajax activity selector + * + * @param array $params associated array for params record id. + * + * @return array $contactActivities associated array of contact activities + * @access public + */ + public static function getContactActivitySelector(&$params) { + // format the params + $params['offset'] = ($params['page'] - 1) * $params['rp']; + $params['rowCount'] = $params['rp']; + $params['sort'] = CRM_Utils_Array::value('sortBy', $params); + $params['caseId'] = NULL; + $context = CRM_Utils_Array::value('context', $params); + + // get contact activities + $activities = CRM_Activity_BAO_Activity::getActivities($params); + + // add total + $params['total'] = CRM_Activity_BAO_Activity::getActivitiesCount($params); + + // format params and add links + $contactActivities = array(); + + if (!empty($activities)) { + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + + // check logged in user for permission + $page = new CRM_Core_Page(); + CRM_Contact_Page_View::checkUserPermission($page, $params['contact_id']); + $permissions = array($page->_permission); + if (CRM_Core_Permission::check('delete activities')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + + $mask = CRM_Core_Action::mask($permissions); + + foreach ($activities as $activityId => $values) { + $contactActivities[$activityId]['activity_type'] = $values['activity_type']; + $contactActivities[$activityId]['subject'] = $values['subject']; + if ($params['contact_id'] == $values['source_contact_id']) { + $contactActivities[$activityId]['source_contact'] = $values['source_contact_name']; + } + elseif ($values['source_contact_id']) { + $contactActivities[$activityId]['source_contact'] = CRM_Utils_System::href($values['source_contact_name'], 'civicrm/contact/view', "reset=1&cid={$values['source_contact_id']}"); + } + else { + $contactActivities[$activityId]['source_contact'] = 'n/a'; + } + + if (isset($values['mailingId']) && !empty($values['mailingId'])) { + $contactActivities[$activityId]['target_contact'] = CRM_Utils_System::href($values['recipients'], 'civicrm/mailing/report', "mid={$values['source_record_id']}&reset=1&cid={$values['source_contact_id']}&context=activitySelector"); + } + elseif (CRM_Utils_Array::value('recipients', $values)) { + $contactActivities[$activityId]['target_contact'] = $values['recipients']; + } + elseif (!$values['target_contact_name']) { + $contactActivities[$activityId]['target_contact'] = 'n/a'; + } + elseif (!empty($values['target_contact_name'])) { + $count = 0; + $contactActivities[$activityId]['target_contact'] = ''; + foreach ($values['target_contact_name'] as $tcID => $tcName) { + if ($tcID && $count < 5) { + $contactActivities[$activityId]['target_contact'] .= CRM_Utils_System::href($tcName, 'civicrm/contact/view', "reset=1&cid={$tcID}"); + $count++; + if ($count) { + $contactActivities[$activityId]['target_contact'] .= "; "; + } + + if ($count == 4) { + $contactActivities[$activityId]['target_contact'] .= "(" . ts('more') . ")"; + break; + } + } + } + } + + if (empty($values['assignee_contact_name'])) { + $contactActivities[$activityId]['assignee_contact'] = 'n/a'; + } + elseif (!empty($values['assignee_contact_name'])) { + $count = 0; + $contactActivities[$activityId]['assignee_contact'] = ''; + foreach ($values['assignee_contact_name'] as $acID => $acName) { + if ($acID && $count < 5) { + $contactActivities[$activityId]['assignee_contact'] .= CRM_Utils_System::href($acName, 'civicrm/contact/view', "reset=1&cid={$acID}"); + $count++; + if ($count) { + $contactActivities[$activityId]['assignee_contact'] .= "; "; + } + + if ($count == 4) { + $contactActivities[$activityId]['assignee_contact'] .= "(" . ts('more') . ")"; + break; + } + } + } + } + if ( $values['activity_type'] == 'Bulk Email'){ + $contactActivities[$activityId]['openstats'] = "Opens: ". + count(CRM_Mailing_Event_BAO_Opened::getRows( + CRM_Utils_Array::value('source_record_id', $values), NULL, FALSE, NULL, NULL, NULL, $params['contact_id'] + ) + )."
Clicks:" . + count(CRM_Mailing_Event_BAO_TrackableURLOpen::getRows( + CRM_Utils_Array::value('source_record_id', $values), NULL, FALSE, NULL, NULL, NULL, NULL, $params['contact_id'] + ) ); + }else { + $contactActivities[$activityId]['openstats'] = ''; + } + + $contactActivities[$activityId]['activity_date'] = CRM_Utils_Date::customFormat($values['activity_date_time']); + $contactActivities[$activityId]['status'] = $activityStatus[$values['status_id']]; + + // add class to this row if overdue + $contactActivities[$activityId]['class'] = ''; + if (CRM_Utils_Date::overdue(CRM_Utils_Array::value('activity_date_time', $values)) + && CRM_Utils_Array::value('status_id', $values) == 1 + ) { + $contactActivities[$activityId]['class'] = 'status-overdue'; + } + else { + $contactActivities[$activityId]['class'] = 'status-ontime'; + } + + // build links + $contactActivities[$activityId]['links'] = ''; + $accessMailingReport = FALSE; + if (CRM_Utils_Array::value('mailingId', $values)) { + $accessMailingReport = TRUE; + } + + $actionLinks = CRM_Activity_Selector_Activity::actionLinks( + CRM_Utils_Array::value('activity_type_id', $values), + CRM_Utils_Array::value('source_record_id', $values), + $accessMailingReport, + CRM_Utils_Array::value('activity_id', $values) + ); + + $actionMask = array_sum(array_keys($actionLinks)) & $mask; + + $contactActivities[$activityId]['links'] = CRM_Core_Action::formLink($actionLinks, + $actionMask, + array( + 'id' => $values['activity_id'], + 'cid' => $params['contact_id'], + 'cxt' => $context, + 'caseid' => CRM_Utils_Array::value('case_id', $values), + ) + ); + } + } + + return $contactActivities; + } + + /* + * Used to copy custom fields and attachments from an existing activity to another. + * see CRM_Case_Page_AJAX::_convertToCaseActivity() for example + */ + static function copyExtendedActivityData($params) { + // attach custom data to the new activity + $customParams = $htmlType = array(); + $customValues = CRM_Core_BAO_CustomValueTable::getEntityValues($params['activityID'], 'Activity'); + + if (!empty($customValues)) { + $fieldIds = implode(', ', array_keys($customValues)); + $sql = "SELECT id FROM civicrm_custom_field WHERE html_type = 'File' AND id IN ( {$fieldIds} )"; + $result = CRM_Core_DAO::executeQuery($sql); + + while ($result->fetch()) { + $htmlType[] = $result->id; + } + + foreach ($customValues as $key => $value) { + if ($value !== NULL) { // CRM-10542 + if (in_array($key, $htmlType)) { + $fileValues = CRM_Core_BAO_File::path($value, $params['activityID']); + $customParams["custom_{$key}_-1"] = array( + 'name' => $fileValues[0], + 'path' => $fileValues[1], + ); + } + else { + $customParams["custom_{$key}_-1"] = $value; + } + } + } + CRM_Core_BAO_CustomValueTable::postProcess($customParams, CRM_Core_DAO::$_nullArray, 'civicrm_activity', + $params['mainActivityId'], 'Activity' + ); + } + + // copy activity attachments ( if any ) + CRM_Core_BAO_File::copyEntityFile('civicrm_activity', $params['activityID'], 'civicrm_activity', $params['mainActivityId']); + } +} + diff --git a/CRM/Activity/BAO/ActivityAssignment.php b/CRM/Activity/BAO/ActivityAssignment.php new file mode 100644 index 0000000000..161ae9e121 --- /dev/null +++ b/CRM/Activity/BAO/ActivityAssignment.php @@ -0,0 +1,151 @@ +copyValues($params); + return $assignment->save(); + } + + /** + * Retrieve assignee_id by activity_id + * + * @param int $id ID of the activity + * + * @return void + * + * @access public + * + */ + static function retrieveAssigneeIdsByActivityId($activity_id) { + $assigneeArray = array(); + if (!CRM_Utils_Rule::positiveInteger($activity_id)) { + return $assigneeArray; + } + + $sql = ' + SELECT assignee_contact_id + FROM civicrm_activity_assignment + JOIN civicrm_contact ON assignee_contact_id = civicrm_contact.id + WHERE activity_id = %1 AND civicrm_contact.is_deleted = 0 + '; + $assignment = CRM_Core_DAO::executeQuery($sql, array(1 => array($activity_id, 'Integer'))); + while ($assignment->fetch()) { + $assigneeArray[] = $assignment->assignee_contact_id; + } + + return $assigneeArray; + } + + /** + * Retrieve assignee names by activity_id + * + * @param int $id ID of the activity + * @param boolean $isDisplayName if set returns display names of assignees + * @param boolean $skipDetails if false returns all details of assignee contact. + * + * @return array + * + * @access public + * + */ + static function getAssigneeNames($activityID, $isDisplayName = FALSE, $skipDetails = TRUE) { + $assigneeNames = array(); + if (empty($activityID)) { + return $assigneeNames; + } + + $whereClause = ""; + if (!$skipDetails) { + $whereClause = " AND ce.is_primary= 1"; + } + + $query = "SELECT contact_a.id, contact_a.sort_name, contact_a.display_name, ce.email + FROM civicrm_contact contact_a + LEFT JOIN civicrm_activity_assignment + ON civicrm_activity_assignment.assignee_contact_id = contact_a.id + LEFT JOIN civicrm_email ce + ON ce.contact_id = contact_a.id + WHERE civicrm_activity_assignment.activity_id = %1 + AND contact_a.is_deleted = 0 + {$whereClause}"; + + $queryParam = array(1 => array($activityID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $queryParam); + while ($dao->fetch()) { + if (!$isDisplayName) { + $assigneeNames[$dao->id] = $dao->sort_name; + } + else { + if ($skipDetails) { + $assigneeNames[$dao->id] = $dao->display_name; + } + else { + $assigneeNames[$dao->id]['contact_id'] = $dao->id; + $assigneeNames[$dao->id]['display_name'] = $dao->display_name; + $assigneeNames[$dao->id]['sort_name'] = $dao->sort_name; + $assigneeNames[$dao->id]['email'] = $dao->email; + $assigneeNames[$dao->id]['role'] = ts('Activity Assignee'); + } + } + } + return $assigneeNames; + } +} + diff --git a/CRM/Activity/BAO/ActivityTarget.php b/CRM/Activity/BAO/ActivityTarget.php new file mode 100644 index 0000000000..25842fc5e4 --- /dev/null +++ b/CRM/Activity/BAO/ActivityTarget.php @@ -0,0 +1,127 @@ +copyValues($params); + return $target->save(); + } + + /** + * function to retrieve id of target contact by activity_id + * + * @param int $id ID of the activity + * + * @return mixed + * + * @access public + * + */ + static function retrieveTargetIdsByActivityId($activity_id) { + $targetArray = array(); + if (!CRM_Utils_Rule::positiveInteger($activity_id)) { + return $targetArray; + } + + $sql = ' + SELECT target_contact_id + FROM civicrm_activity_target + JOIN civicrm_contact ON target_contact_id = civicrm_contact.id + WHERE activity_id = %1 AND civicrm_contact.is_deleted = 0 + '; + $target = CRM_Core_DAO::executeQuery($sql, array(1 => array($activity_id, 'Integer'))); + while ($target->fetch()) { + $targetArray[] = $target->target_contact_id; + } + return $targetArray; + } + + /** + * function to retrieve names of target contact by activity_id + * + * @param int $id ID of the activity + * + * @return array + * + * @access public + * + */ + static function getTargetNames($activityID) { + $targetNames = array(); + + if (empty($activityID)) { + return $targetNames; + } + + $query = "SELECT contact_a.id, contact_a.sort_name + FROM civicrm_contact contact_a + LEFT JOIN civicrm_activity_target + ON civicrm_activity_target.target_contact_id = contact_a.id + WHERE civicrm_activity_target.activity_id = %1 AND contact_a.is_deleted = 0"; + $queryParam = array(1 => array($activityID, 'Integer')); + + $dao = CRM_Core_DAO::executeQuery($query, $queryParam); + while ($dao->fetch()) { + $targetNames[$dao->id] = $dao->sort_name; + } + + return $targetNames; + } +} + diff --git a/CRM/Activity/BAO/ICalendar.php b/CRM/Activity/BAO/ICalendar.php new file mode 100644 index 0000000000..e0f7c5192e --- /dev/null +++ b/CRM/Activity/BAO/ICalendar.php @@ -0,0 +1,133 @@ +activity = $act; + } + + /** + * Add an ics attachment to the input array + * + * @param array $attachments Reference to array in same format returned from CRM_Core_BAO_File::getEntityFile() + * @param array $contacts Array of contacts (attendees) + * + * @return string Array index of the added attachment in the $attachments array, or else null. + * @access public + */ + function addAttachment( &$attachments, $contacts ) { + // Check preferences setting + if ( CRM_Core_BAO_Setting::getItem( CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'activity_assignee_notification_ics' ) ) { + $config = &CRM_Core_Config::singleton(); + $this->icsfile = tempnam( $config->customFileUploadDir, 'ics' ); + if ( $this->icsfile !== FALSE ) { + rename( $this->icsfile, $this->icsfile . '.ics' ); + $this->icsfile .= '.ics'; + $icsFileName = basename( $this->icsfile ); + + // get logged in user's primary email + // TODO: Is there a better way to do this? + $organizer = $this->getPrimaryEmail(); + + $template = CRM_Core_Smarty::singleton(); + $template->assign('activity', $this->activity); + $template->assign('organizer', $organizer); + $template->assign('contacts', $contacts); + $template->assign('timezone', date_default_timezone_get()); + $calendar = $template->fetch('CRM/Activity/Calendar/ICal.tpl'); + if ( file_put_contents( $this->icsfile, $calendar ) !== FALSE ) { + if ( empty( $attachments ) ) { + $attachments = array(); + } + $attachments['activity_ics'] = array( + 'mime_type' => 'text/calendar', + 'fileName' => $icsFileName, + 'cleanName' => $icsFileName, + 'fullPath' => $this->icsfile, + ); + return 'activity_ics'; + } + } + } + return null; + } + + function cleanup() { + if ( !empty ( $this->icsfile ) ) { + @unlink( $this->icsfile ); + } + } + + // TODO: Is there a better way to do this? + private function getPrimaryEmail() { + $session = &CRM_Core_Session::singleton(); + $uid = $session->get('userID'); + $primary = ''; + $emails = CRM_Core_BAO_Email::allEmails( $uid ); + foreach ( $emails as $eid => $e ) { + if ( $e['is_primary'] ) { + if ( $e['email'] ) { + $primary = $e['email']; + break; + } + } + + if ( count($emails) == 1 ) { + $primary = $e['email']; + break; + } + } + return $primary; + } +} + diff --git a/CRM/Activity/BAO/Query.php b/CRM/Activity/BAO/Query.php new file mode 100644 index 0000000000..585a8019b2 --- /dev/null +++ b/CRM/Activity/BAO/Query.php @@ -0,0 +1,607 @@ +_returnProperties)) { + $query->_select['activity_id'] = "civicrm_activity.id as activity_id"; + $query->_element['activity_id'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_type_id', $query->_returnProperties)) { + $query->_select['activity_type_id'] = "activity_type.id as activity_type_id"; + $query->_element['activity_type_id'] = 1; + $query->_tables['civicrm_activity'] = 1; + $query->_tables['activity_type'] = 1; + $query->_whereTables['civicrm_activity'] = 1; + $query->_whereTables['activity_type'] = 1; + } + + if (CRM_Utils_Array::value('activity_type', $query->_returnProperties)) { + $query->_select['activity_type'] = "activity_type.label as activity_type"; + $query->_element['activity_type'] = 1; + $query->_tables['civicrm_activity'] = 1; + $query->_tables['activity_type'] = 1; + $query->_whereTables['civicrm_activity'] = 1; + $query->_whereTables['activity_type'] = 1; + } + + if (CRM_Utils_Array::value('activity_subject', $query->_returnProperties)) { + $query->_select['activity_subject'] = "civicrm_activity.subject as activity_subject"; + $query->_element['activity_subject'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_date_time', $query->_returnProperties)) { + $query->_select['activity_date_time'] = "civicrm_activity.activity_date_time as activity_date_time"; + $query->_element['activity_date_time'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_status_id', $query->_returnProperties)) { + $query->_select['activity_status_id'] = "activity_status.value as activity_status_id"; + $query->_element['activity_status_id'] = 1; + $query->_tables['civicrm_activity'] = 1; + $query->_tables['activity_status'] = 1; + $query->_whereTables['civicrm_activity'] = 1; + $query->_whereTables['activity_status'] = 1; + } + + if (CRM_Utils_Array::value('activity_status', $query->_returnProperties)) { + $query->_select['activity_status'] = "activity_status.label as activity_status"; + $query->_element['activity_status'] = 1; + $query->_tables['civicrm_activity'] = 1; + $query->_tables['activity_status'] = 1; + $query->_whereTables['civicrm_activity'] = 1; + $query->_whereTables['activity_status'] = 1; + } + + if (CRM_Utils_Array::value('activity_duration', $query->_returnProperties)) { + $query->_select['activity_duration'] = "civicrm_activity.duration as activity_duration"; + $query->_element['activity_duration'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_location', $query->_returnProperties)) { + $query->_select['activity_location'] = "civicrm_activity.location as activity_location"; + $query->_element['activity_location'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_details', $query->_returnProperties)) { + $query->_select['activity_details'] = "civicrm_activity.details as activity_details"; + $query->_element['activity_details'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('source_record_id', $query->_returnProperties)) { + $query->_select['source_record_id'] = "civicrm_activity.source_record_id as source_record_id"; + $query->_element['source_record_id'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_is_test', $query->_returnProperties)) { + $query->_select['activity_is_test'] = "civicrm_activity.is_test as activity_is_test"; + $query->_element['activity_is_test'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_campaign_id', $query->_returnProperties)) { + $query->_select['activity_campaign_id'] = 'civicrm_activity.campaign_id as activity_campaign_id'; + $query->_element['activity_campaign_id'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('activity_engagement_level', $query->_returnProperties)) { + $query->_select['activity_engagement_level'] = 'civicrm_activity.engagement_level as activity_engagement_level'; + $query->_element['activity_engagement_level'] = 1; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + } + + if (CRM_Utils_Array::value('source_contact', $query->_returnProperties)) { + $query->_select['source_contact'] = 'source_contact.display_name as source_contact'; + $query->_element['source_contact'] = 1; + $query->_tables['source_contact'] = $query->_whereTables['source_contact'] = 1; + } + } + + /** + * Given a list of conditions in query generate the required + * where clause + * + * @return void + * @access public + */ + static function where(&$query) { + $grouping = $testCondition = NULL; + foreach (array_keys($query->_params) as $id) { + if (substr($query->_params[$id][0], 0, 9) == 'activity_') { + if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) { + $query->_useDistinct = TRUE; + } + if ($query->_params[$id][0] == 'activity_test') { + $testCondition = $id; + continue; + } + $grouping = $query->_params[$id][3]; + self::whereClauseSingle($query->_params[$id], $query); + } + } + // Only add test condition if other fields are selected + if ($grouping !== NULL && $testCondition && + // we dont want to include all tests for sql OR CRM-7827 + $query->getOperator() != 'OR' + ) { + self::whereClauseSingle($query->_params[$testCondition], $query); + } + } + + /** + * where clause for a single field + * + * @return void + * @access public + */ + static function whereClauseSingle(&$values, &$query) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + $query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1; + if ($query->_mode & CRM_Contact_BAO_Query::MODE_ACTIVITY) { + $query->_skipDeleteClause = TRUE; + } + + switch ($name) { + case 'activity_type_id': + $types = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE); + + //get the component activity types. + $compActTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE, TRUE); + + $clause = array(); + if (is_array($value)) { + foreach ($value as $id => $dontCare) { + if (array_key_exists($id, $types) && $dontCare) { + $clause[] = "'" . CRM_Utils_Type::escape($types[$id], 'String') . "'"; + if (array_key_exists($id, $compActTypes)) { + CRM_Contact_BAO_Query::$_considerCompActivities = TRUE; + } + } + } + $activityTypes = implode(',', array_keys($value)); + } + else { + $clause[] = "'" . CRM_Utils_Type::escape($value, 'String') . "'"; + $activityTypes = $value; + if (array_key_exists($value, $compActTypes)) { + CRM_Contact_BAO_Query::$_considerCompActivities = TRUE; + } + } + $query->_where[$grouping][] = ' civicrm_activity.activity_type_id IN (' . $activityTypes . ')'; + $query->_qill[$grouping][] = ts('Activity Type') . ' ' . implode(' ' . ts('or') . ' ', $clause); + break; + + case 'activity_survey_id': + if (!$value) { + break; + } + $value = CRM_Utils_Type::escape($value, 'Integer'); + $query->_where[$grouping][] = " source_record_id = $value"; + $query->_qill[$grouping][] = ts('Survey') . ' - ' . CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $value, 'title'); + break; + + case 'activity_engagement_level': + if (!$value) { + break; + } + + $value = CRM_Utils_Type::escape($value, 'Integer'); + $query->_where[$grouping][] = " engagement_level = $value"; + $query->_qill[$grouping][] = ts('Engagement Index') . ' - ' . CRM_Core_OptionGroup::getLabel('engagement_index', $value); + break; + + case 'activity_role': + CRM_Contact_BAO_Query::$_activityRole = $values[2]; + + //for activity target name + $activityTargetName = $query->getWhereValues('activity_contact_name', $grouping); + if (!$activityTargetName[2]) { + $name = NULL; + } + else { + $name = trim($activityTargetName[2]); + $name = strtolower(CRM_Core_DAO::escapeString($name)); + } + + $query->_where[$grouping][] = " contact_activity_source.is_deleted = 0 AND contact_activity_source.sort_name LIKE '%{$name}%'"; + if ($values[2] == 1) { + $query->_where[$grouping][] = " civicrm_activity.source_contact_id = contact_activity_source.id"; + $query->_qill[$grouping][] = ts('Activity created by') . " '$name'"; + $query->_tables['civicrm_activity_contact'] = $query->_whereTables['civicrm_activity_contact'] = 1; + } + elseif ($values[2] == 2) { + $query->_where[$grouping][] = " civicrm_activity_assignment.activity_id = civicrm_activity.id AND civicrm_activity_assignment.assignee_contact_id = contact_activity_source.id"; + $query->_tables['civicrm_activity_assignment'] = $query->_whereTables['civicrm_activity_assignment'] = 1; + $query->_tables['civicrm_activity_contact'] = $query->_whereTables['civicrm_activity_contact'] = 1; + $query->_qill[$grouping][] = ts('Activity assigned to') . " '$name'"; + } + break; + + case 'activity_status': + $status = CRM_Core_PseudoConstant::activityStatus(); + $clause = array(); + if (is_array($value)) { + foreach ($value as $k => $v) { + if ($k) { + $clause[] = "'" . CRM_Utils_Type::escape($status[$k], 'String') . "'"; + } + } + } + else { + $clause[] = "'" . CRM_Utils_Type::escape($value, 'String') . "'"; + } + $query->_where[$grouping][] = ' civicrm_activity.status_id IN (' . implode(',', array_keys($value)) . ')'; + $query->_qill[$grouping][] = ts('Activity Status') . ' - ' . implode(' ' . ts('or') . ' ', $clause); + break; + + case 'activity_subject': + $n = trim($value); + $value = strtolower(CRM_Core_DAO::escapeString($n)); + if ($wildcard) { + if (strpos($value, '%') !== FALSE) { + // only add wild card if not there + $value = "'$value'"; + } + else { + $value = "'%$value%'"; + } + $op = 'LIKE'; + } + else { + $value = "'$value'"; + } + $wc = ($op != 'LIKE') ? "LOWER(civicrm_activity.subject)" : "civicrm_activity.subject"; + $query->_where[$grouping][] = " $wc $op $value"; + $query->_qill[$grouping][] = ts('Subject') . " $op - '$n'"; + break; + + case 'activity_test': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_activity.is_test", $op, $value, "Boolean"); + if ($value) { + $query->_qill[$grouping][] = ts('Activity is a Test'); + } + break; + + case 'activity_date': + case 'activity_date_low': + case 'activity_date_high': + $query->dateQueryBuilder($values, + 'civicrm_activity', 'activity_date', 'activity_date_time', ts('Activity Date') + ); + break; + + case 'activity_id': + if (empty($value)) { + break; + } + + if (is_array($value)) { + foreach ($value as $k => $v) { + $value[$k] = CRM_Utils_Type::escape($v, 'Integer'); + } + } + else { + $value = array(CRM_Utils_Type::escape($value, 'Integer')); + } + $query->_where[$grouping][] = "civicrm_activity.id IN (" . implode(",", $value) . ")"; + $query->_qill[$grouping][] = ts('Activity Id(s) %1', array(1 => implode($value))); + break; + + case 'activity_taglist': + $taglist = $value; + $value = array(); + foreach ($taglist as $val) { + if ($val) { + $val = explode(',', $val); + foreach ($val as $tId) { + if (is_numeric($tId)) { + $value[$tId] = 1; + } + } + } + } + case 'activity_tags': + $value = array_keys($value); + $activityTags = CRM_Core_PseudoConstant::tag(); + + $names = array(); + $val = array(); + if (is_array($value)) { + foreach ($value as $k => $v) { + $names[] = $activityTags[$v]; + } + } + $query->_where[$grouping][] = "civicrm_activity_tag.tag_id IN (" . implode(",", $value) . ")"; + $query->_qill[$grouping][] = ts('Activity Tag %1', array(1 => $op)) . ' ' . implode(' ' . ts('OR') . ' ', $names); + $query->_tables['civicrm_activity_tag'] = $query->_whereTables['civicrm_activity_tag'] = 1; + break; + + case 'activity_campaign_id': + $campParams = array( + 'op' => $op, + 'campaign' => $value, + 'grouping' => $grouping, + 'tableName' => 'civicrm_activity', + ); + CRM_Campaign_BAO_Query::componentSearchClause($campParams, $query); + return; + } + } + + static function from($name, $mode, $side) { + $from = NULL; + switch ($name) { + case 'civicrm_activity': + //CRM-7480 we are going to civicrm_activitty table either + //from civicrm_activity_target or civicrm_activity_assignment. + //as component specific activities does not have entry in + //activity target table so lets consider civicrm_activity_assignment. + if (CRM_Contact_BAO_Query::$_considerCompActivities) { + $from .= " $side JOIN civicrm_activity_target + ON ( civicrm_activity_target.target_contact_id = contact_a.id ) "; + + $from .= " $side JOIN civicrm_activity_assignment activity_assignment + ON ( activity_assignment.assignee_contact_id = contact_a.id )"; + + $from .= " $side JOIN civicrm_activity + ON ( civicrm_activity.id = civicrm_activity_target.activity_id + AND civicrm_activity.is_deleted = 0 AND civicrm_activity.is_current_revision = 1 )"; + } + elseif (CRM_Contact_BAO_Query::$_withContactActivitiesOnly) { + //force the civicrm_activity_target table. + $from .= " $side JOIN civicrm_activity_target ON civicrm_activity_target.target_contact_id = contact_a.id "; + $from .= " $side JOIN civicrm_activity ON ( civicrm_activity.id = civicrm_activity_target.activity_id + AND civicrm_activity.is_deleted = 0 + AND civicrm_activity.is_current_revision = 1 )"; + } + else { + $activityRole = CRM_Contact_BAO_Query::$_activityRole; + switch ($activityRole) { + case 1: + $from .= " $side JOIN civicrm_activity ON ( civicrm_activity.source_contact_id = contact_a.id + AND civicrm_activity.is_deleted = 0 + AND civicrm_activity.is_current_revision = 1 )"; + break; + + case 2: + $from .= " $side JOIN civicrm_activity_assignment activity_assignment ON ( activity_assignment.assignee_contact_id = contact_a.id )"; + $from .= " $side JOIN civicrm_activity ON ( civicrm_activity.id = activity_assignment.activity_id + AND civicrm_activity.is_deleted = 0 + AND civicrm_activity.is_current_revision = 1 )"; + break; + + default: + $from .= " $side JOIN civicrm_activity_target ON civicrm_activity_target.target_contact_id = contact_a.id "; + $from .= " $side JOIN civicrm_activity ON ( civicrm_activity.id = civicrm_activity_target.activity_id + AND civicrm_activity.is_deleted = 0 + AND civicrm_activity.is_current_revision = 1 )"; + } + } + break; + + case 'civicrm_activity_contact': + $activityRole = CRM_Contact_BAO_Query::$_activityRole; + if ($activityRole == 1) { + $from .= " $side JOIN civicrm_contact contact_activity_source ON civicrm_activity.source_contact_id = contact_activity_source.id + LEFT JOIN civicrm_email email_activity_source ON (contact_activity_source.id = email_activity_source.contact_id AND email_activity_source.is_primary = 1)"; + } + elseif ($activityRole == 2) { + $from .= " $side JOIN civicrm_activity_assignment ON civicrm_activity.id = civicrm_activity_assignment.activity_id "; + $from .= " $side JOIN civicrm_contact contact_activity_source ON civicrm_activity_assignment.assignee_contact_id = contact_activity_source.id + LEFT JOIN civicrm_email email_activity_source ON (contact_activity_source.id = email_activity_source.contact_id AND email_activity_source.is_primary = 1)"; + } + break; + + case 'activity_status': + $from = " $side JOIN civicrm_option_group option_group_activity_status ON (option_group_activity_status.name = 'activity_status')"; + $from .= " $side JOIN civicrm_option_value activity_status ON (civicrm_activity.status_id = activity_status.value + AND option_group_activity_status.id = activity_status.option_group_id ) "; + break; + + case 'activity_type': + $from = " $side JOIN civicrm_option_group option_group_activity_type ON (option_group_activity_type.name = 'activity_type')"; + $from .= " $side JOIN civicrm_option_value activity_type ON (civicrm_activity.activity_type_id = activity_type.value + AND option_group_activity_type.id = activity_type.option_group_id ) "; + break; + + case 'civicrm_activity_tag': + $from .= " $side JOIN civicrm_entity_tag as civicrm_activity_tag ON ( civicrm_activity_tag.entity_table = 'civicrm_activity' AND civicrm_activity_tag.entity_id = civicrm_activity.id ) "; + break; + + case 'source_contact': + $from = " $side JOIN civicrm_contact source_contact ON source_contact.id = civicrm_activity.source_contact_id"; + break; + } + + return $from; + } + + /** + * getter for the qill object + * + * @return string + * @access public + */ + function qill() { + return (isset($this->_qill)) ? $this->_qill : ""; + } + + /** + * add all the elements shared between case activity search and advanaced search + * + * @access public + * + * @return void + * @static + */ + static function buildSearchForm(&$form) { + $activityOptions = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE); + asort($activityOptions); + foreach ($activityOptions as $activityID => $activity) { + $form->_activityElement =& + $form->addElement( + 'checkbox', + "activity_type_id[$activityID]", + NULL, + $activity, + array('onClick' => 'showCustomData( this.id );') + ); + } + + CRM_Core_Form_Date::buildDateRange($form, 'activity_date', 1, '_low', '_high', ts('From'), FALSE, FALSE); + + $activityRoles = array(1 => ts('Created by'), 2 => ts('Assigned to')); + $form->addRadio('activity_role', NULL, $activityRoles); + + $form->addElement('text', 'activity_contact_name', ts('Contact Name'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + foreach ($activityStatus as $activityStatusID => $activityStatusName) { + $activity_status[] = $form->createElement('checkbox', $activityStatusID, NULL, $activityStatusName); + } + $form->addGroup($activity_status, 'activity_status', ts('Activity Status')); + $form->setDefaults(array('activity_status[1]' => 1, 'activity_status[2]' => 1)); + $form->addElement('text', 'activity_subject', ts('Subject'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + $form->addYesNo('activity_test', ts('Activity is a Test?')); + $activity_tags = CRM_Core_BAO_Tag::getTags('civicrm_activity'); + if ($activity_tags) { + foreach ($activity_tags as $tagID => $tagName) { + $form->_tagElement = &$form->addElement('checkbox', "activity_tags[$tagID]", + NULL, $tagName + ); + } + } + + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_activity'); + CRM_Core_Form_Tag::buildQuickForm($form, $parentNames, 'civicrm_activity', NULL, TRUE, FALSE, TRUE); + + $surveys = CRM_Campaign_BAO_Survey::getSurveys(); + if ($surveys) $form->add('select', 'activity_survey_id', ts('Survey'), + array( + '' => ts('- none -')) + $surveys, FALSE + ); + + $extends = array('Activity'); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, $extends); + if ($groupDetails) { + $form->assign('activityGroupTree', $groupDetails); + foreach ($groupDetails as $group) { + foreach ($group['fields'] as $field) { + $fieldId = $field['id']; + $elementName = 'custom_' . $fieldId; + CRM_Core_BAO_CustomField::addQuickFormElement($form, $elementName, $fieldId, FALSE, FALSE, TRUE); + } + } + } + + CRM_Campaign_BAO_Campaign::addCampaignInComponentSearch($form, 'activity_campaign_id'); + + //add engagement level CRM-7775 + $buildEngagementLevel = FALSE; + if (CRM_Campaign_BAO_Campaign::isCampaignEnable() && + CRM_Campaign_BAO_Campaign::accessCampaign() + ) { + $buildEngagementLevel = TRUE; + $form->add('select', 'activity_engagement_level', + ts('Engagement Index'), + array('' => ts('- any -')) + CRM_Campaign_PseudoConstant::engagementLevel() + ); + } + + $form->assign('buildEngagementLevel', $buildEngagementLevel); + $form->setDefaults(array('activity_test' => 0)); + } + + static function addShowHide(&$showHide) { + $showHide->addHide('caseActivityForm'); + $showHide->addShow('caseActivityForm_show'); + } + + static function defaultReturnProperties($mode, $includeCustomFields = TRUE) { + $properties = NULL; + if ($mode & CRM_Contact_BAO_Query::MODE_ACTIVITY) { + $properties = array( + 'activity_id' => 1, + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'sort_name' => 1, + 'display_name' => 1, + 'activity_type' => 1, + 'activity_subject' => 1, + 'activity_date_time' => 1, + 'activity_duration' => 1, + 'activity_location' => 1, + 'activity_details' => 1, + 'activity_status' => 1, + 'source_contact_id' => 1, + 'source_record_id' => 1, + 'activity_is_test' => 1, + 'activity_campaign_id' => 1, + 'activity_engagement_level' => 1, + ); + + if ($includeCustomFields) { + // also get all the custom activity properties + $fields = CRM_Core_BAO_CustomField::getFieldsForImport('Activity'); + if (!empty($fields)) { + foreach ($fields as $name => $dontCare) { + $properties[$name] = 1; + } + } + } + } + + return $properties; + } +} + diff --git a/CRM/Activity/Controller/Search.php b/CRM/Activity/Controller/Search.php new file mode 100644 index 0000000000..3d2123edb2 --- /dev/null +++ b/CRM/Activity/Controller/Search.php @@ -0,0 +1,68 @@ +_stateMachine = new CRM_Activity_StateMachine_Search($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $this->addActions(); + } + + public function selectorName() { + return $this->get('selectorName'); + } +} + diff --git a/CRM/Activity/Form/Activity.php b/CRM/Activity/Form/Activity.php new file mode 100644 index 0000000000..24338aa987 --- /dev/null +++ b/CRM/Activity/Form/Activity.php @@ -0,0 +1,1170 @@ +_fields = array( + 'subject' => array( + 'type' => 'text', + 'label' => ts('Subject'), + 'attributes' => CRM_Core_DAO::getAttribute('CRM_Activity_DAO_Activity', + 'subject' + ), + ), + 'duration' => array( + 'type' => 'text', + 'label' => ts('Duration'), + 'attributes' => array('size' => 4, 'maxlength' => 8), + 'required' => FALSE, + ), + 'location' => array( + 'type' => 'text', + 'label' => ts('Location'), + 'attributes' => + CRM_Core_DAO::getAttribute('CRM_Activity_DAO_Activity', + 'location' + ), + 'required' => FALSE + ), + 'details' => array( + 'type' => 'wysiwyg', + 'label' => ts('Details'), + // forces a smaller edit window + 'attributes' => array('rows' => 4, 'cols' => 60), + 'required' => FALSE + ), + 'status_id' => array( + 'type' => 'select', + 'label' => ts('Status'), + 'attributes' => + CRM_Core_PseudoConstant::activityStatus(), + 'required' => TRUE + ), + 'priority_id' => array( + 'type' => 'select', + 'label' => ts('Priority'), + 'attributes' => + CRM_Core_PseudoConstant::priority(), + 'required' => TRUE + ), + 'source_contact_id' => array( + 'type' => 'text', + 'label' => ts('Added By'), + 'required' => FALSE + ), + 'followup_activity_type_id' => array( + 'type' => 'select', + 'label' => ts('Followup Activity'), + 'attributes' => array( + '' => '- ' . ts('select activity') . ' -') + + CRM_Core_PseudoConstant::ActivityType(FALSE) + ), + // Add optional 'Subject' field for the Follow-up Activiity, CRM-4491 + 'followup_activity_subject' => array( + 'type' => 'text', + 'label' => ts('Subject'), + 'attributes' => CRM_Core_DAO::getAttribute('CRM_Activity_DAO_Activity', + 'subject' + ) + ) + ); + + if (($this->_context == 'standalone') && + ($printPDF = CRM_Utils_Array::key('Print PDF Letter', $this->_fields['followup_activity_type_id']['attributes'])) + ) { + unset($this->_fields['followup_activity_type_id']['attributes'][$printPDF]); + } + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + function preProcess() { + $this->_cdType = CRM_Utils_Array::value('type', $_GET); + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + return CRM_Custom_Form_CustomData::preProcess($this); + } + + $this->_atypefile = CRM_Utils_Array::value('atypefile', $_GET); + $this->assign('atypefile', FALSE); + if ($this->_atypefile) { + $this->assign('atypefile', TRUE); + } + + $session = CRM_Core_Session::singleton(); + $this->_currentUserId = $session->get('userID'); + + $this->_currentlyViewedContactId = $this->get('contactId'); + if (!$this->_currentlyViewedContactId) { + $this->_currentlyViewedContactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + } + $this->assign('contactId', $this->_currentlyViewedContactId); + + if ($this->_currentlyViewedContactId) { + CRM_Contact_Page_View::setTitle($this->_currentlyViewedContactId); + } + + //give the context. + if (!isset($this->_context)) { + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + if (CRM_Contact_Form_Search::isSearchContext($this->_context)) { + $this->_context = 'search'; + } + elseif (!in_array($this->_context, array('dashlet', 'dashletFullscreen')) + && $this->_currentlyViewedContactId + ) { + $this->_context = 'activity'; + } + $this->_compContext = CRM_Utils_Request::retrieve('compContext', 'String', $this); + } + + $this->assign('context', $this->_context); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this); + + if ($this->_action & CRM_Core_Action::DELETE) { + if (!CRM_Core_Permission::check('delete activities')) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + } + + //CRM-6957 + //when we come from contact search, activity id never comes. + //so don't try to get from object, it might gives you wrong one. + + // if we're not adding new one, there must be an id to + // an activity we're trying to work on. + if ($this->_action != CRM_Core_Action::ADD && + get_class($this->controller) != 'CRM_Contact_Controller_Search' + ) { + $this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this); + } + + $this->_activityTypeId = CRM_Utils_Request::retrieve('atype', 'Positive', $this); + $this->assign('atype', $this->_activityTypeId); + + //check for required permissions, CRM-6264 + if ($this->_activityId && + in_array($this->_action, array( + CRM_Core_Action::UPDATE, CRM_Core_Action::VIEW)) && + !CRM_Activity_BAO_Activity::checkPermission($this->_activityId, $this->_action) + ) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page.')); + } + if (($this->_action & CRM_Core_Action::VIEW) && + CRM_Activity_BAO_Activity::checkPermission($this->_activityId, CRM_Core_Action::UPDATE) + ) { + $this->assign('permission', 'edit'); + } + + if (!$this->_activityTypeId && $this->_activityId) { + $this->_activityTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', + $this->_activityId, + 'activity_type_id' + ); + } + + //Assigning Activity type name + if ($this->_activityTypeId) { + $activityTName = CRM_Core_OptionGroup::values('activity_type', FALSE, FALSE, FALSE, 'AND v.value = ' . $this->_activityTypeId, 'name'); + if ($activityTName[$this->_activityTypeId]) { + $this->_activityTypeName = $activityTName[$this->_activityTypeId]; + $this->assign('activityTName', $activityTName[$this->_activityTypeId]); + } + } + + // Assign pageTitle to be "Activity - "+ activity name + if (isset($activityTName)) { + $pageTitle = 'Activity - ' . CRM_Utils_Array::value($this->_activityTypeId, $activityTName); + $this->assign('pageTitle', $pageTitle); + } + + //check the mode when this form is called either single or as + //search task action + if ($this->_activityTypeId || + $this->_context == 'standalone' || + $this->_currentlyViewedContactId + ) { + $this->_single = TRUE; + $this->assign('urlPath', 'civicrm/activity'); + } + else { + //set the appropriate action + $url = CRM_Utils_System::currentPath(); + $urlArray = explode('/', $url); + $seachPath = array_pop($urlArray); + $searchType = 'basic'; + $this->_action = CRM_Core_Action::BASIC; + switch ($seachPath) { + case 'basic': + $searchType = $seachPath; + $this->_action = CRM_Core_Action::BASIC; + break; + + case 'advanced': + $searchType = $seachPath; + $this->_action = CRM_Core_Action::ADVANCED; + break; + + case 'builder': + $searchType = $seachPath; + $this->_action = CRM_Core_Action::PROFILE; + break; + + case 'custom': + $this->_action = CRM_Core_Action::COPY; + $searchType = $seachPath; + break; + } + + parent::preProcess(); + $this->_single = FALSE; + + $this->assign('urlPath', "civicrm/contact/search/$searchType"); + $this->assign('urlPathVar', "_qf_Activity_display=true&qfKey={$this->controller->_key}"); + } + + $this->assign('single', $this->_single); + $this->assign('action', $this->_action); + + if ($this->_action & CRM_Core_Action::VIEW) { + // get the tree of custom fields + $this->_groupTree = &CRM_Core_BAO_CustomGroup::getTree('Activity', $this, + $this->_activityId, 0, $this->_activityTypeId + ); + } + + if ($this->_activityTypeId) { + //set activity type name and description to template + list($this->_activityTypeName, $activityTypeDescription) = CRM_Core_BAO_OptionValue::getActivityTypeDetails($this->_activityTypeId); + $this->assign('activityTypeName', $this->_activityTypeName); + $this->assign('activityTypeDescription', $activityTypeDescription); + } + + // set user context + $urlParams = $urlString = NULL; + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + + //validate the qfKey + if (!CRM_Utils_Rule::qfKey($qfKey)) { + $qfKey = NULL; + } + + if ($this->_context == 'fulltext') { + $keyName = '&qfKey'; + $urlParams = 'force=1'; + $urlString = 'civicrm/contact/search/custom'; + if ($this->_action == CRM_Core_Action::UPDATE) { + $keyName = '&key'; + $urlParams .= '&context=fulltext&action=view'; + $urlString = 'civicrm/contact/view/activity'; + } + if ($qfKey) { + $urlParams .= "$keyName=$qfKey"; + } + $this->assign('searchKey', $qfKey); + } + elseif (in_array($this->_context, array( + 'standalone', 'home', 'dashlet', 'dashletFullscreen'))) { + $urlParams = 'reset=1'; + $urlString = 'civicrm/dashboard'; + } + elseif ($this->_context == 'search') { + $urlParams = 'force=1'; + if ($qfKey) { + $urlParams .= "&qfKey=$qfKey"; + } + if ($this->_compContext == 'advanced') { + $urlString = 'civicrm/contact/search/advanced'; + } + else { + $urlString = 'civicrm/activity/search'; + } + $this->assign('searchKey', $qfKey); + } + elseif ($this->_context != 'caseActivity') { + $urlParams = "action=browse&reset=1&cid={$this->_currentlyViewedContactId}&selectedChild=activity"; + $urlString = 'civicrm/contact/view'; + } + + if ($urlString) { + $session->pushUserContext(CRM_Utils_System::url($urlString, $urlParams)); + } + + // hack to retrieve activity type id from post variables + if (!$this->_activityTypeId) { + $this->_activityTypeId = CRM_Utils_Array::value('activity_type_id', $_POST); + } + + // when custom data is included in this page + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + // we need to set it in the session for the below code to work + // CRM-3014 + //need to assign custom data subtype to the template + $this->set('type', 'Activity'); + $this->set('subType', $this->_activityTypeId); + $this->set('entityId', $this->_activityId); + CRM_Custom_Form_CustomData::preProcess($this); + CRM_Custom_Form_CustomData::buildQuickForm($this); + CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + // add attachments part + CRM_Core_BAO_File::buildAttachment($this, 'civicrm_activity', $this->_activityId, NULL, TRUE); + + // figure out the file name for activity type, if any + if ($this->_activityTypeId && + $this->_activityTypeFile = + CRM_Activity_BAO_Activity::getFileForActivityTypeId($this->_activityTypeId, $this->_crmDir) + ) { + $this->assign('activityTypeFile', $this->_activityTypeFile); + $this->assign('crmDir', $this->_crmDir); + } + + $this->setFields(); + + if ($this->_activityTypeFile) { + eval("CRM_{$this->_crmDir}_Form_Activity_{$this->_activityTypeFile}::preProcess( \$this );"); + } + + $this->_values = $this->get('values'); + if (!is_array($this->_values)) { + $this->_values = array(); + if (isset($this->_activityId) && $this->_activityId) { + $params = array('id' => $this->_activityId); + CRM_Activity_BAO_Activity::retrieve($params, $this->_values); + } + $this->set('values', $this->_values); + } + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + $defaults = $this->_values; + + // if we're editing... + if (isset($this->_activityId)) { + $defaults['source_contact_qid'] = CRM_Utils_Array::value( 'source_contact_id', + $defaults ); + $defaults['source_contact_id'] = CRM_Utils_Array::value( 'source_contact', + $defaults ); + + if (!CRM_Utils_Array::crmIsEmptyArray($defaults['target_contact'])) { + $target_contact_value = explode(';', trim($defaults['target_contact_value'])); + $target_contact = array_combine(array_unique($defaults['target_contact']), $target_contact_value); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->assign('target_contact', $target_contact); + } + else { + //this assigned variable is used by newcontact creation widget to set defaults + $this->assign('prePopulateData', $this->formatContactValues($target_contact)); + } + } + + if (!CRM_Utils_Array::crmIsEmptyArray($defaults['assignee_contact'])) { + $assignee_contact_value = explode(';', trim($defaults['assignee_contact_value'])); + $assignee_contact = array_combine($defaults['assignee_contact'], $assignee_contact_value); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->assign('assignee_contact', $assignee_contact); + } + else { + $this->assign('assignee_contact', $this->formatContactValues($assignee_contact)); + } + } + + if (!CRM_Utils_Array::value('activity_date_time', $defaults)) { + list($defaults['activity_date_time'], $defaults['activity_date_time_time']) = CRM_Utils_Date::setDateDefaults(NULL, 'activityDateTime'); + } + elseif ($this->_action & CRM_Core_Action::UPDATE) { + $this->assign('current_activity_date_time', $defaults['activity_date_time']); + list($defaults['activity_date_time'], + $defaults['activity_date_time_time'] + ) = CRM_Utils_Date::setDateDefaults($defaults['activity_date_time'], 'activityDateTime'); + } + + //set the assigneed contact count to template + if (!empty($defaults['assignee_contact'])) { + $this->assign('assigneeContactCount', count($defaults['assignee_contact'])); + } + else { + $this->assign('assigneeContactCount', 1); + } + + //set the target contact count to template + if (!empty($defaults['target_contact'])) { + $this->assign('targetContactCount', count($defaults['target_contact'])); + } + else { + $this->assign('targetContactCount', 1); + } + + if ($this->_context != 'standalone') { + $this->assign('target_contact_value', + CRM_Utils_Array::value('target_contact_value', $defaults) + ); + $this->assign('assignee_contact_value', + CRM_Utils_Array::value('assignee_contact_value', $defaults) + ); + $this->assign('source_contact_value', + CRM_Utils_Array::value('source_contact', $defaults) + ); + } + + // set default tags if exists + $defaults['tag'] = CRM_Core_BAO_EntityTag::getTag($this->_activityId, 'civicrm_activity'); + } + else { + // if it's a new activity, we need to set default values for associated contact fields + // since those are jQuery fields, unfortunately we cannot use defaults directly + $this->_sourceContactId = $this->_currentUserId; + $this->_targetContactId = $this->_currentlyViewedContactId; + $target_contact = array(); + + $defaults['source_contact_id'] = self::_getDisplayNameById($this->_sourceContactId); + $defaults['source_contact_qid'] = $this->_sourceContactId; + if ($this->_context != 'standalone' && isset($this->_targetContactId)) { + $target_contact[$this->_targetContactId] = self::_getDisplayNameById($this->_targetContactId); + } + + //this assigned variable is used by newcontact creation widget to set defaults + $this->assign('prePopulateData', $this->formatContactValues($target_contact)); + + list($defaults['activity_date_time'], $defaults['activity_date_time_time']) = + CRM_Utils_Date::setDateDefaults(NULL, 'activityDateTime'); + } + + if ($this->_activityTypeId) { + $defaults['activity_type_id'] = $this->_activityTypeId; + } + + if ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::RENEW)) { + $this->assign('delName', CRM_Utils_Array::value('subject', $defaults)); + } + + if ($this->_activityTypeFile) { + eval('$defaults += CRM_' . $this->_crmDir . '_Form_Activity_' . + $this->_activityTypeFile . '::setDefaultValues($this);' + ); + } + if (!CRM_Utils_Array::value('priority_id', $defaults)) { + $priority = CRM_Core_PseudoConstant::priority(); + $defaults['priority_id'] = array_search('Normal', $priority); + } + return $defaults; + } + + /** + * Function to format contact values before assigning to autocomplete widget + * + * @param array $contactNames associated array of contact name and ids + * + * @return json encoded object + * @private + */ + function formatContactValues(&$contactNames) { + //format target/assignee contact + $formatContacts = array(); + foreach ($contactNames as $id => $name) { + $formatContacts[] = array( + 'id' => $id, + 'name' => $name + ); + } + + return json_encode($formatContacts); + } + + public function buildQuickForm() { + if ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::RENEW)) { + //enable form element (ActivityLinks sets this true) + $this->assign('suppressForm', FALSE); + + $button = ts('Delete'); + if ($this->_action & CRM_Core_Action::RENEW) { + $button = ts('Restore'); + } + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => $button, + 'spacing' => '         ', + 'isDefault' => TRUE + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel') + ) + )); + return; + } + + if (!$this->_single && !empty($this->_contactIds)) { + $withArray = array(); + foreach ($this->_contactIds as $contactId) { + $withDisplayName = self::_getDisplayNameById($contactId); + $withArray[] = "\"$withDisplayName\" "; + } + $this->assign('with', implode(', ', $withArray)); + } + + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + //build other activity links + CRM_Activity_Form_ActivityLinks::buildQuickForm(); + + //enable form element (ActivityLinks sets this true) + $this->assign('suppressForm', FALSE); + + $element = &$this->add('select', 'activity_type_id', ts('Activity Type'), + $this->_fields['followup_activity_type_id']['attributes'], + FALSE, array( + 'onchange' => + "CRM.buildCustomData( 'Activity', this.value );", + ) + ); + + //freeze for update mode. + if ($this->_action & CRM_Core_Action::UPDATE) { + $element->freeze(); + } + + foreach ($this->_fields as $field => $values) { + if (CRM_Utils_Array::value($field, $this->_fields)) { + $attribute = NULL; + if (CRM_Utils_Array::value('attributes', $values)) { + $attribute = $values['attributes']; + } + + $required = FALSE; + if (CRM_Utils_Array::value('required', $values)) { + $required = TRUE; + } + if ($values['type'] == 'wysiwyg') { + $this->addWysiwyg($field, $values['label'], $attribute, $required); + } + else { + $this->add($values['type'], $field, $values['label'], $attribute, $required); + } + } + } + + //CRM-7362 --add campaigns. + CRM_Campaign_BAO_Campaign::addCampaign($this, CRM_Utils_Array::value('campaign_id', $this->_values)); + + //add engagement level CRM-7775 + $buildEngagementLevel = FALSE; + if (CRM_Campaign_BAO_Campaign::isCampaignEnable() && + CRM_Campaign_BAO_Campaign::accessCampaign() + ) { + $buildEngagementLevel = TRUE; + $this->add('select', 'engagement_level', + ts('Engagement Index'), + array('' => ts('- select -')) + CRM_Campaign_PseudoConstant::engagementLevel() + ); + $this->addRule('engagement_level', + ts('Please enter the engagement index as a number (integers only).'), + 'positiveInteger' + ); + } + $this->assign('buildEngagementLevel', $buildEngagementLevel); + + // check for survey activity + $this->_isSurveyActivity = FALSE; + + if ($this->_activityId && CRM_Campaign_BAO_Campaign::isCampaignEnable() && + CRM_Campaign_BAO_Campaign::accessCampaign() + ) { + + $this->_isSurveyActivity = CRM_Campaign_BAO_Survey::isSurveyActivity($this->_activityId); + if ($this->_isSurveyActivity) { + $surveyId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', + $this->_activityId, + 'source_record_id' + ); + $responseOptions = CRM_Campaign_BAO_Survey::getResponsesOptions($surveyId); + if ($responseOptions) { + $this->add('select', 'result', ts('Result'), + array('' => ts('- select -')) + array_combine($responseOptions, $responseOptions) + ); + } + $surveyTitle = NULL; + if ($surveyId) { + $surveyTitle = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $surveyId, 'title'); + } + $this->assign('surveyTitle', $surveyTitle); + } + } + $this->assign('surveyActivity', $this->_isSurveyActivity); + + $this->addRule('duration', + ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger' + ); + $this->addDateTime('activity_date_time', ts('Date'), TRUE, array('formatType' => 'activityDateTime')); + + //add followup date + $this->addDateTime('followup_date', ts('in')); + + //autocomplete url + $dataUrl = CRM_Utils_System::url("civicrm/ajax/rest", + "className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&context=activity&reset=1", + FALSE, NULL, FALSE + ); + $this->assign('dataUrl', $dataUrl); + + //tokeninput url + $tokenUrl = CRM_Utils_System::url("civicrm/ajax/checkemail", + "noemail=1", + FALSE, NULL, FALSE + ); + $this->assign('tokenUrl', $tokenUrl); + + $admin = CRM_Core_Permission::check('administer CiviCRM'); + //allow to edit sourcecontactfield field if context is civicase. + if ($this->_context == 'caseActivity') { + $admin = TRUE; + } + + $this->assign('admin', $admin); + + $sourceContactField = &$this->add($this->_fields['source_contact_id']['type'], + 'source_contact_id', + $this->_fields['source_contact_id']['label'], + NULL, + $admin + ); + + $this->add('hidden', 'source_contact_qid', '', array('id' => 'source_contact_qid')); + CRM_Contact_Form_NewContact::buildQuickForm($this); + + $this->add('text', 'assignee_contact_id', ts('assignee')); + + if ($sourceContactField->getValue()) { + $this->assign('source_contact', $sourceContactField->getValue()); + } + elseif ($this->_currentUserId) { + // we're setting currently LOGGED IN user as source for this activity + $this->assign('source_contact_value', self::_getDisplayNameById($this->_currentUserId)); + } + + //need to assign custom data type and subtype to the template + $this->assign('customDataType', 'Activity'); + $this->assign('customDataSubType', $this->_activityTypeId); + $this->assign('entityID', $this->_activityId); + + $tags = CRM_Core_BAO_Tag::getTags('civicrm_activity'); + + if (!empty($tags)) { + $this->add('select', 'tag', ts('Tags'), $tags, FALSE, + array('id' => 'tags', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + + // we need to hide activity tagset for special activities + $specialActivities = array('Open Case'); + + if (!in_array($this->_activityTypeName, $specialActivities)) { + // build tag widget + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_activity'); + CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_activity', $this->_activityId, FALSE, TRUE); + } + + // if we're viewing, we're assigning different buttons than for adding/editing + if ($this->_action & CRM_Core_Action::VIEW) { + if (isset($this->_groupTree)) { + CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $this->_groupTree); + } + $buttons = array(); + // do check for permissions + if (CRM_Case_BAO_Case::checkPermission($this->_activityId, 'File On Case', $this->_activityTypeId)) { + $buttons[] = array( + 'type' => 'cancel', + 'name' => ts('File on case'), + 'subName' => 'file_on_case', + 'js' => array('onClick' => "javascript:fileOnCase( \"file\", $this->_activityId ); return false;") + ); + } + // form should be frozen for view mode + $this->freeze(); + + $buttons[] = array( + 'type' => 'cancel', + 'name' => ts('Done') + ); + + $this->addButtons($buttons); + } + else { + $message = array('completed' => ts('Are you sure? This is a COMPLETED activity with the DATE in the FUTURE. Click Cancel to change the date / status. Otherwise, click OK to save.'), + 'scheduled' => ts('Are you sure? This is a SCHEDULED activity with the DATE in the PAST. Click Cancel to change the date / status. Otherwise, click OK to save.'), + ); + $js = array('onclick' => "return activityStatus(" . json_encode($message) . ");"); + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'js' => $js, + 'isDefault' => TRUE + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel') + ) + ) + ); + } + + if ($this->_activityTypeFile) { + eval("CRM_{$this->_crmDir}_Form_Activity_{$this->_activityTypeFile}::buildQuickForm( \$this );"); + } + + if ($this->_activityTypeFile) { + eval('$this->addFormRule' . + "(array( + 'CRM_{$this->_crmDir}_Form_Activity_{$this->_activityTypeFile}', 'formrule'), \$this);" + ); + } + + $this->addFormRule(array('CRM_Activity_Form_Activity', 'formRule'), $this); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + // skip form rule if deleting + if (CRM_Utils_Array::value('_qf_Activity_next_', $fields) == 'Delete') { + return TRUE; + } + $errors = array(); + if (!$self->_single && !$fields['activity_type_id']) { + $errors['activity_type_id'] = ts('Activity Type is a required field'); + } + + //Activity type is mandatory if creating new activity, CRM-4515 + if (array_key_exists('activity_type_id', $fields) && + !CRM_Utils_Array::value('activity_type_id', $fields) + ) { + $errors['activity_type_id'] = ts('Activity Type is required field.'); + } + //FIX me temp. comment + // make sure if associated contacts exist + + if ($fields['source_contact_id'] && !is_numeric($fields['source_contact_qid'])) { + $errors['source_contact_id'] = ts('Source Contact non-existent!'); + } + + if (CRM_Utils_Array::value('activity_type_id', $fields) == 3 && + CRM_Utils_Array::value('status_id', $fields) == 1 + ) { + $errors['status_id'] = ts('You cannot record scheduled email activity.'); + } + elseif (CRM_Utils_Array::value('activity_type_id', $fields) == 4 && + CRM_Utils_Array::value('status_id', $fields) == 1 + ) { + $errors['status_id'] = ts('You cannot record scheduled SMS activity.'); + } + + if (CRM_Utils_Array::value('followup_activity_type_id', $fields) && !CRM_Utils_Array::value('followup_date', $fields)) { + $errors['followup_date_time'] = ts('Followup date is a required field.'); + } + //Activity type is mandatory if subject or follow-up date is specified for an Follow-up activity, CRM-4515 + if ((CRM_Utils_Array::value('followup_activity_subject', $fields) || CRM_Utils_Array::value('followup_date', $fields)) && + !CRM_Utils_Array::value('followup_activity_type_id', $fields) + ) { + $errors['followup_activity_subject'] = ts('Follow-up Activity type is a required field.'); + } + return $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess($params = NULL) { + if ($this->_action & CRM_Core_Action::DELETE) { + $deleteParams = array('id' => $this->_activityId); + $moveToTrash = CRM_Case_BAO_Case::isCaseActivity($this->_activityId); + CRM_Activity_BAO_Activity::deleteActivity($deleteParams, $moveToTrash); + + // delete tags for the entity + $tagParams = array( + 'entity_table' => 'civicrm_activity', + 'entity_id' => $this->_activityId + ); + + CRM_Core_BAO_EntityTag::del($tagParams); + + CRM_Core_Session::setStatus(ts("Selected Activity has been deleted successfully."), ts('Record Deleted'), 'success'); + return; + } + + // store the submitted values in an array + if (!$params) { + $params = $this->controller->exportValues($this->_name); + } + + //set activity type id + if (!CRM_Utils_Array::value('activity_type_id', $params)) { + $params['activity_type_id'] = $this->_activityTypeId; + } + + if (CRM_Utils_Array::value('hidden_custom', $params) && + !isset($params['custom']) + ) { + $customFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, + $this->_activityTypeId + ); + $customFields = CRM_Utils_Array::crmArrayMerge($customFields, + CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, + NULL, NULL, TRUE + ) + ); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_activityId, + 'Activity' + ); + } + + // store the date with proper format + $params['activity_date_time'] = CRM_Utils_Date::processDate($params['activity_date_time'], $params['activity_date_time_time']); + + // format with contact (target contact) values + if (isset($params['contact'][1])) { + $params['target_contact_id'] = explode(',', $params['contact'][1]); + } + else { + $params['target_contact_id'] = array(); + } + + // assigning formated value to related variable + if (CRM_Utils_Array::value('assignee_contact_id', $params)) { + $params['assignee_contact_id'] = explode(',', $params['assignee_contact_id']); + } + else { + $params['assignee_contact_id'] = array(); + } + + // get ids for associated contacts + if (!$params['source_contact_id']) { + $params['source_contact_id'] = $this->_currentUserId; + } + else { + $params['source_contact_id'] = $this->_submitValues['source_contact_qid']; + } + + if (isset($this->_activityId)) { + $params['id'] = $this->_activityId; + } + + // add attachments as needed + CRM_Core_BAO_File::formatAttachment($params, + $params, + 'civicrm_activity', + $this->_activityId + ); + + // format target params + if (!$this->_single) { + $params['target_contact_id'] = $this->_contactIds; + } + + $activityAssigned = array(); + // format assignee params + if (!CRM_Utils_Array::crmIsEmptyArray($params['assignee_contact_id'])) { + //skip those assignee contacts which are already assigned + //while sending a copy.CRM-4509. + $activityAssigned = array_flip($params['assignee_contact_id']); + if ($this->_activityId) { + $assigneeContacts = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($this->_activityId); + $activityAssigned = array_diff_key($activityAssigned, $assigneeContacts); + } + } + + // call begin post process. Idea is to let injecting file do + // any processing before the activity is added/updated. + $this->beginPostProcess($params); + + $activity = CRM_Activity_BAO_Activity::create($params); + + // add tags if exists + $tagParams = array(); + if (!empty($params['tag'])) { + foreach ($params['tag'] as $tag) { + $tagParams[$tag] = 1; + } + } + + //save static tags + CRM_Core_BAO_EntityTag::create($tagParams, 'civicrm_activity', $activity->id); + + //save free tags + if (isset($params['activity_taglist']) && !empty($params['activity_taglist'])) { + CRM_Core_Form_Tag::postProcess($params['activity_taglist'], $activity->id, 'civicrm_activity', $this); + } + + // call end post process. Idea is to let injecting file do any + // processing needed, after the activity has been added/updated. + $this->endPostProcess($params, $activity); + + // CRM-9590 + $this->_activityId = $activity->id; + + // create follow up activity if needed + $followupStatus = ''; + if (CRM_Utils_Array::value('followup_activity_type_id', $params)) { + $followupActivity = CRM_Activity_BAO_Activity::createFollowupActivity($activity->id, $params); + $followupStatus = ts('A followup activity has been scheduled.'); + } + + // send copy to assignee contacts.CRM-4509 + $mailStatus = ''; + + if (!CRM_Utils_Array::crmIsEmptyArray($params['assignee_contact_id']) && + CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'activity_assignee_notification' + ) + ) { + $mailToContacts = array(); + $assigneeContacts = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($activity->id, TRUE, FALSE); + + //build an associative array with unique email addresses. + foreach ($activityAssigned as $id => $dnc) { + if (isset($id) && array_key_exists($id, $assigneeContacts)) { + $mailToContacts[$assigneeContacts[$id]['email']] = $assigneeContacts[$id]; + } + } + + if (!CRM_Utils_array::crmIsEmptyArray($mailToContacts)) { + //include attachments while sendig a copy of activity. + $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_activity', $activity->id); + + $ics = new CRM_Activity_BAO_ICalendar( $activity ); + $ics->addAttachment( $attachments, $mailToContacts ); + + // CRM-8400 add param with _currentlyViewedContactId for URL link in mail + $result = CRM_Case_BAO_Case::sendActivityCopy(NULL, $activity->id, $mailToContacts, $attachments, NULL); + + $ics->cleanup(); + + $mailStatus .= ts("A copy of the activity has also been sent to assignee contacts(s)."); + } + } + + // set status message + if (CRM_Utils_Array::value('subject', $params)) { + $params['subject'] = "'" . $params['subject'] . "'"; + } + + CRM_Core_Session::setStatus(ts('Activity %1 has been saved. %2. %3', + array( + 1 => $params['subject'], + 2 => $followupStatus, + 3 => $mailStatus + ) + ), ts('Saved'), 'success'); + + return array('activity' => $activity); + } + + /** + * Shorthand for getting id by display name (makes code more readable) + * + * @access protected + */ + protected function _getIdByDisplayName($displayName) { + return CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $displayName, + 'id', + 'sort_name' + ); + } + + /** + * Shorthand for getting display name by id (makes code more readable) + * + * @access protected + */ + protected function _getDisplayNameById($id) { + return CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $id, + 'sort_name', + 'id' + ); + } + + /** + * Function to let injecting activity type file do any processing + * needed, before the activity is added/updated + * + */ + function beginPostProcess(&$params) { + if ($this->_activityTypeFile) { + eval("CRM_{$this->_crmDir}_Form_Activity_{$this->_activityTypeFile}" . + "::beginPostProcess( \$this, \$params );" + ); + } + } + + /** + * Function to let injecting activity type file do any processing + * needed, after the activity has been added/updated + * + */ + function endPostProcess(&$params, &$activity) { + if ($this->_activityTypeFile) { + eval("CRM_{$this->_crmDir}_Form_Activity_{$this->_activityTypeFile}" . + "::endPostProcess( \$this, \$params, \$activity );" + ); + } + } +} + diff --git a/CRM/Activity/Form/ActivityFilter.php b/CRM/Activity/Form/ActivityFilter.php new file mode 100644 index 0000000000..d0c561100c --- /dev/null +++ b/CRM/Activity/Form/ActivityFilter.php @@ -0,0 +1,67 @@ +add('select', 'activity_type_filter_id', ts('Include'), array('' => ts('- all activity type(s) -')) + $activityOptions); + $this->add('select', 'activity_type_exclude_filter_id', ts('Exclude'), array('' => ts('- select activity type -')) + $activityOptions); + $this->assign('suppressForm', TRUE); + } + + function setDefaultValues() { + // CRM-11761 retrieve user's activity filter preferences + $defaults = array(); + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + if ($userID) { + $defaults = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME, + 'activity_tab_filter', + NULL, + NULL, + $userID + ); + } + return $defaults; + } +} + diff --git a/CRM/Activity/Form/ActivityLinks.php b/CRM/Activity/Form/ActivityLinks.php new file mode 100644 index 0000000000..38c9a282b6 --- /dev/null +++ b/CRM/Activity/Form/ActivityLinks.php @@ -0,0 +1,115 @@ + ts('Send an Email')); + } + } + + if ($contactId && CRM_SMS_BAO_Provider::activeProviderCount()) { + // Check for existence of a mobile phone and ! do not SMS privacy setting + $mobileTypeID = CRM_Core_OptionGroup::getValue('phone_type', 'Mobile', 'name'); + list($name, $phone, $doNotSMS) = CRM_Contact_BAO_Contact_Location::getPhoneDetails($contactId, $mobileTypeID); + + if (!$doNotSMS && $phone) { + $sendSMS = array($SMSId => ts('Send SMS')); + $activityTypes += $sendSMS; + } + } + // this returns activity types sorted by weight + $otherTypes = CRM_Core_PseudoConstant::activityType(FALSE); + + $activityTypes += $otherTypes; + + foreach (array_keys($activityTypes) as $typeId) { + if ($typeId == $emailTypeId) { + $urls[$typeId] = CRM_Utils_System::url('civicrm/activity/email/add', + "{$urlParams}{$typeId}", FALSE, NULL, FALSE + ); + } + elseif ($typeId == $SMSId) { + $urls[$typeId] = CRM_Utils_System::url('civicrm/activity/sms/add', + "{$urlParams}{$typeId}", FALSE, NULL, FALSE + ); + } + elseif ($typeId == $letterTypeId) { + $urls[$typeId] = CRM_Utils_System::url('civicrm/activity/pdf/add', + "{$urlParams}{$typeId}", FALSE, NULL, FALSE + ); + } + else { + $urls[$typeId] = CRM_Utils_System::url('civicrm/activity/add', + "{$urlParams}{$typeId}", FALSE, NULL, FALSE + ); + } + } + + $this->assign('activityTypes', $activityTypes); + $this->assign('urls', $urls); + + $this->assign('suppressForm', TRUE); + } +} + diff --git a/CRM/Activity/Form/ActivityView.php b/CRM/Activity/Form/ActivityView.php new file mode 100644 index 0000000000..d17b1b0eda --- /dev/null +++ b/CRM/Activity/Form/ActivityView.php @@ -0,0 +1,133 @@ +pushUserContext($url); + $defaults = array(); + $params = array('id' => $activityId); + CRM_Activity_BAO_Activity::retrieve($params, $defaults); + + //set activity type name and description to template + list($activityTypeName, $activityTypeDescription) = CRM_Core_BAO_OptionValue::getActivityTypeDetails($defaults['activity_type_id']); + + $this->assign('activityTypeName', $activityTypeName); + $this->assign('activityTypeDescription', $activityTypeDescription); + + if (CRM_Utils_Array::value('mailingId', $defaults)) { + $this->_mailing_id = CRM_Utils_Array::value('source_record_id', $defaults); + $mailingReport = CRM_Mailing_BAO_Mailing::report($this->_mailing_id, TRUE); + CRM_Mailing_BAO_Mailing::getMailingContent($mailingReport, $this); + $this->assign('mailingReport', $mailingReport); + + $full_open_report = CRM_Mailing_Event_BAO_Opened::getRows( + $this->_mailing_id, NULL, FALSE, NULL, NULL, NULL, $cid); + $this->assign('openreport',$full_open_report); + + $click_thru_report = CRM_Mailing_Event_BAO_TrackableURLOpen::getRows( $this->_mailing_id, NULL, FALSE, NULL, NULL, NULL, NULL, $cid); + $this->assign('clickreport',$click_thru_report); + } + + foreach ($defaults as $key => $value) { + if (substr($key, -3) != '_id') { + $values[$key] = $value; + } + } + + //get the campaign + if ($campaignId = CRM_Utils_Array::value('campaign_id', $defaults)) { + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns($campaignId); + $values['campaign'] = $campaigns[$campaignId]; + } + if ($engagementLevel = CRM_Utils_Array::value('engagement_level', $defaults)) { + $engagementLevels = CRM_Campaign_PseudoConstant::engagementLevel(); + $values['engagement_level'] = CRM_Utils_Array::value($engagementLevel, $engagementLevels, $engagementLevel); + } + + $values['attachment'] = CRM_Core_BAO_File::attachmentInfo('civicrm_activity', $activityId); + $this->assign('values', $values); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Done'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Activity/Form/Search.php b/CRM/Activity/Form/Search.php new file mode 100644 index 0000000000..1bd3853073 --- /dev/null +++ b/CRM/Activity/Form/Search.php @@ -0,0 +1,499 @@ +set('searchFormName', 'Search'); + + /** + * set the button names + */ + $this->_searchButtonName = $this->getButtonName('refresh'); + $this->_printButtonName = $this->getButtonName('next', 'print'); + $this->_actionButtonName = $this->getButtonName('next', 'action'); + + $this->_done = FALSE; + $this->defaults = array(); + + /* + * we allow the controller to set force/reset externally, useful when we are being + * driven by the wizard framework + */ + $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean', CRM_Core_DAO::$_nullObject); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE); + $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'search'); + + $this->assign("context", $this->_context); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST) && !$this->controller->isModal()) { + $this->_formValues = $this->controller->exportValues($this->_name); + } + else { + $this->_formValues = $this->get('formValues'); + } + + if (empty($this->_formValues)) { + if (isset($this->_ssID)) { + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + } + } + + if ($this->_force) { + $this->postProcess(); + $this->set('force', 0); + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $selector = new CRM_Activity_Selector_Search($this->_queryParams, + $this->_action, + NULL, + $this->_single, + $this->_limit, + $this->_context + ); + $prefix = NULL; + if ($this->_context == 'user') { + $prefix = $this->_prefix; + } + + $this->assign("{$prefix}limit", $this->_limit); + $this->assign("{$prefix}single", $this->_single); + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::TRANSFER, + $prefix + ); + $controller->setEmbedded(TRUE); + $controller->moveFromSessionToTemplate(); + + $this->assign('summary', $this->get('summary')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->addElement('text', 'sort_name', ts('With (name or email)'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + + CRM_Activity_BAO_Query::buildSearchForm($this); + + /* + * add form checkboxes for each row. This is needed out here to conform to QF protocol + * of all elements being declared in builQuickForm + */ + + $rows = $this->get('rows'); + if (is_array($rows)) { + if (!$this->_single) { + $this->addElement('checkbox', 'toggleSelect', NULL, NULL, + array('onclick' => "toggleTaskAction( true ); return toggleCheckboxVals('mark_x_',this);") + ); + foreach ($rows as $row) { + $this->addElement('checkbox', $row['checkbox'], + NULL, NULL, + array('onclick' => "toggleTaskAction( true ); return checkSelectedBox('" . $row['checkbox'] . "');") + ); + } + } + + $total = $cancel = 0; + + $permission = CRM_Core_Permission::getPermission(); + + $tasks = array('' => ts('- actions -')) + CRM_Activity_Task::permissionedTaskTitles($permission); + + $this->add('select', 'task', ts('Actions:') . ' ', $tasks); + $this->add('submit', $this->_actionButtonName, ts('Go'), + array( + 'class' => 'form-submit', + 'id' => 'Go', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 0);", + ) + ); + + $this->add('submit', $this->_printButtonName, ts('Print'), + array( + 'class' => 'form-submit', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 1);", + ) + ); + + // need to perform tasks on all or selected items ? using radio_ts(task selection) for it + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_sel', array('checked' => 'checked')); + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_all', + array('onchange' => $this->getName() . ".toggleSelect.checked = false; toggleCheckboxVals('mark_x_',this); toggleTaskAction( true );") + ); + } + + // add buttons + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + )); + } + + /** + * The post processing of the form gets done here. + * + * Key things done during post processing are + * - check for reset or next request. if present, skip post procesing. + * - now check if user requested running a saved search, if so, then + * the form values associated with the saved search are used for searching. + * - if user has done a submit with new values the regular post submissing is + * done. + * The processing consists of using a Selector / Controller framework for getting the + * search results. + * + * @param + * + * @return void + * @access public + */ + function postProcess() { + if ($this->_done) { + return; + } + + $this->_done = TRUE; + + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + } + + $this->fixFormValues(); + + if (isset($this->_ssID) && empty($_POST)) { + // if we are editing / running a saved search and the form has not been posted + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + } + if (CRM_Utils_Array::value('activity_survey_id', $this->_formValues)) { + // if the user has choosen a survey but not any activity type, we force the activity type + $sid = CRM_Utils_Array::value('activity_survey_id', $this->_formValues); + $activity_type_id = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $sid, 'activity_type_id'); + + $this->_formValues['activity_type_id'][$activity_type_id] = 1; + } + + if (!CRM_Utils_Array::value('activity_test', $this->_formValues)) { + $this->_formValues["activity_test"] = 0; + } + if (!CRM_Utils_Array::value('activity_contact_name', $this->_formValues) && !CRM_Utils_Array::value('contact_id', $this->_formValues)) { + $this->_formValues['activity_role'] = NULL; + } + CRM_Core_BAO_CustomValue::fixFieldValueOfTypeMemo($this->_formValues); + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $this->set('formValues', $this->_formValues); + $this->set('queryParams', $this->_queryParams); + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->_actionButtonName || $buttonName == $this->_printButtonName) { + // check actionName and if next, then do not repeat a search, since we are going to the next page + // hack, make sure we reset the task values + $stateMachine = &$this->controller->getStateMachine(); + $formName = $stateMachine->getTaskFormName(); + $this->controller->resetPage($formName); + return; + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $selector = new CRM_Activity_Selector_Search($this->_queryParams, + $this->_action, + NULL, + $this->_single, + $this->_limit, + $this->_context + ); + $selector->setKey($this->controller->_key); + + $prefix = NULL; + if ($this->_context == 'basic' || $this->_context == 'user') { + $prefix = $this->_prefix; + } + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::SESSION, + $prefix + ); + $controller->setEmbedded(TRUE); + $query = &$selector->getQuery(); + + if ($this->_context == 'user') { + $query->setSkipPermission(TRUE); + } + $controller->run(); + } + + /** + * This function is used to add the rules (mainly global rules) for form. + * All local rules are added near the element + * + * @return None + * @access public + * @see valid_date + */ + function addRules() { + $this->addFormRule(array('CRM_Activity_Form_Search', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * + * @return void + * @static + * @access public + */ + static function formRule($fields) { + $errors = array(); + + if (!empty($errors)) { + return $errors; + } + + return TRUE; + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { // TODO test? + $defaults = array(); + $defaults = $this->_formValues; + return $defaults; + } + + function fixFormValues() { + if (!$this->_force) { + return; + } + $status = CRM_Utils_Request::retrieve('status', 'String', $this); + if ($status) { + $this->_formValues['activity_status'] = $status; + $this->_defaults['activity_status'] = $status; + } + + $survey = CRM_Utils_Request::retrieve('survey', 'Positive', + CRM_Core_DAO::$_nullObject + ); + if ($survey) { + $this->_formValues['activity_survey_id'] = $survey; + } + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + if ($cid) { + $cid = CRM_Utils_Type::escape($cid, 'Integer'); + if ($cid > 0) { + $this->_formValues['contact_id'] = $cid; + + $activity_role = CRM_Utils_Request::retrieve('activity_role', 'Positive', $this); + + if ($activity_role) { + $this->_formValues['activity_role'] = $activity_role; + } + else { + list($display, $image) = CRM_Contact_BAO_Contact::getDisplayAndImage($cid); + $this->_defaults['sort_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'sort_name'); + } + // also assign individual mode to the template + $this->_single = TRUE; + } + } + } + + function getFormValues() { + return NULL; + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Find Activities'); + } +} + diff --git a/CRM/Activity/Form/Task.php b/CRM/Activity/Form/Task.php new file mode 100644 index 0000000000..dbe9b61942 --- /dev/null +++ b/CRM/Activity/Form/Task.php @@ -0,0 +1,191 @@ +_activityHolderIds = array(); + + $values = $form->controller->exportValues($form->get('searchFormName')); + + $form->_task = $values['task']; + $activityTasks = CRM_Activity_Task::tasks(); + $form->assign('taskName', $activityTasks[$form->_task]); + + $ids = array(); + if ($values['radio_ts'] == 'ts_sel') { + foreach ($values as $name => $value) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + } + } + } + else { + $queryParams = $form->get('queryParams'); + $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_ACTIVITY + ); + $query->_distinctComponentClause = '( civicrm_activity.id )'; + $query->_groupByComponentClause = " GROUP BY civicrm_activity.id "; + $result = $query->searchQuery(0, 0, NULL); + + while ($result->fetch()) { + if(!empty($result->activity_id)) { + $ids[] = $result->activity_id; + } + } + } + + if (!empty($ids)) { + $form->_componentClause = ' civicrm_activity.id IN ( ' . implode(',', $ids) . ' ) '; + $form->assign('totalSelectedActivities', count($ids)); + } + + $form->_activityHolderIds = $form->_componentIds = $ids; + + //set the context for redirection for any task actions + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + + $session = CRM_Core_Session::singleton(); + $searchFormName = strtolower($form->get('searchFormName')); + if ($searchFormName == 'search') { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/activity/search', $urlParams)); + } + else { + $session->replaceUserContext(CRM_Utils_System::url("civicrm/contact/search/$searchFormName", + $urlParams + )); + } + } + + /** + * Given the membership id, compute the contact id + * since its used for things like send email + */ + public function setContactIDs() { + $IDs = implode(',', $this->_activityHolderIds); + $query = " +SELECT source_contact_id + FROM civicrm_activity + WHERE id IN ( $IDs ) +"; + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $contactIDs[] = $dao->source_contact_id; + } + $this->_contactIds = $contactIDs; + } + + /** + * simple shell that derived classes can call to add buttons to + * the form with a customized title for the main Submit + * + * @param string $title title of the main button + * @param string $type button type for the form after processing + * + * @return void + * @access public + */ + function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) { + $this->addButtons(array( + array( + 'type' => $nextType, + 'name' => $title, + 'isDefault' => TRUE, + ), + array( + 'type' => $backType, + 'name' => ts('Cancel'), + ), + ) + ); + } +} + diff --git a/CRM/Activity/Form/Task/Batch.php b/CRM/Activity/Form/Task/Batch.php new file mode 100755 index 0000000000..6a41ef7963 --- /dev/null +++ b/CRM/Activity/Form/Task/Batch.php @@ -0,0 +1,293 @@ + ts('Added By'), 'target_sort_name' => ts('With Contact')), + CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_autocomplete_options', + TRUE, NULL, FALSE, 'name', TRUE + ) + ); + + //get the read only field data. + $returnProperties = array_fill_keys(array_keys($readOnlyFields), 1); + $contactDetails = CRM_Contact_BAO_Contact_Utils::contactDetails($this->_activityHolderIds, + 'Activity', $returnProperties + ); + $this->assign('contactDetails', $contactDetails); + $this->assign('readOnlyFields', $readOnlyFields); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $ufGroupId = $this->get('ufGroupId'); + + if (!$ufGroupId) { + CRM_Core_Error::fatal('ufGroupId is missing'); + } + $this->_title = ts('Batch Update for Activities') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId); + CRM_Utils_System::setTitle($this->_title); + + $this->addDefaultButtons(ts('Save')); + $this->_fields = array(); + $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW); + + // remove file type field and then limit fields + $suppressFields = FALSE; + $removehtmlTypes = array('File', 'Autocomplete-Select'); + foreach ($this->_fields as $name => $field) { + if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) && + in_array($this->_fields[$name]['html_type'], $removehtmlTypes) + ) { + $suppressFields = TRUE; + unset($this->_fields[$name]); + } + + //fix to reduce size as we are using this field in grid + if (is_array($field['attributes']) && $this->_fields[$name]['attributes']['size'] > 19) { + //shrink class to "form-text-medium" + $this->_fields[$name]['attributes']['size'] = 19; + } + } + + $this->_fields = array_slice($this->_fields, 0, $this->_maxFields); + + $this->addButtons(array( + array( + 'type' => 'submit', + 'name' => ts('Update Activities'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + + $this->assign('profileTitle', $this->_title); + $this->assign('componentIds', $this->_activityHolderIds); + $fileFieldExists = FALSE; + + //load all campaigns. + if (array_key_exists('activity_campaign_id', $this->_fields)) { + $this->_componentCampaigns = array(); + CRM_Core_PseudoConstant::populate($this->_componentCampaigns, + 'CRM_Activity_DAO_Activity', + TRUE, 'campaign_id', 'id', + ' id IN (' . implode(' , ', array_values($this->_activityHolderIds)) . ' ) ' + ); + } + + $customFields = CRM_Core_BAO_CustomField::getFields('Activity'); + + foreach ($this->_activityHolderIds as $activityId) { + $typeId = CRM_Core_DAO::getFieldValue("CRM_Activity_DAO_Activity", $activityId, 'activity_type_id'); + foreach ($this->_fields as $name => $field) { + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) { + $customValue = CRM_Utils_Array::value($customFieldID, $customFields); + if (CRM_Utils_Array::value('extends_entity_column_value', $customValue)) { + $entityColumnValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, + $customValue['extends_entity_column_value'] + ); + } + if (CRM_Utils_Array::value($typeId, $entityColumnValue) || + CRM_Utils_System::isNull($entityColumnValue[$typeId]) + ) { + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $activityId); + } + } + else { + // handle non custom fields + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $activityId); + } + } + } + + $this->assign('fields', $this->_fields); + + // don't set the status message when form is submitted. + // $buttonName = $this->controller->getButtonName('submit'); + + if ($suppressFields) { + CRM_Core_Session::setStatus(ts("FILE or Autocomplete Select type field(s) in the selected profile are not supported for Batch Update."), ts("Some fields have been excluded"), "info"); + } + + $this->addDefaultButtons(ts('Update Activities')); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if (empty($this->_fields)) { + return; + } + + $defaults = array(); + foreach ($this->_activityHolderIds as $activityId) { + $details[$activityId] = array(); + CRM_Core_BAO_UFGroup::setProfileDefaults(NULL, $this->_fields, $defaults, FALSE, $activityId, 'Activity'); + } + + return $defaults; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->exportValues(); + + if (isset($params['field'])) { + foreach ($params['field'] as $key => $value) { + + $value['custom'] = CRM_Core_BAO_CustomField::postProcess($value, + CRM_Core_DAO::$_nullObject, + $key, 'Activity' + ); + $value['id'] = $key; + + if ($value['activity_date_time']) { + $value['activity_date_time'] = CRM_Utils_Date::processDate($value['activity_date_time'], $value['activity_date_time_time']); + } + + if (CRM_Utils_Array::value('activity_status_id', $value)) { + $value['status_id'] = $value['activity_status_id']; + } + + if (CRM_Utils_Array::value('activity_details', $value)) { + $value['details'] = $value['activity_details']; + } + + if (CRM_Utils_Array::value('activity_duration', $value)) { + $value['duration'] = $value['activity_duration']; + } + + if (CRM_Utils_Array::value('activity_location', $value)) { + $value['location'] = $value['activity_location']; + } + + if (CRM_Utils_Array::value('activity_subject', $value)) { + $value['subject'] = $value['activity_subject']; + } + + $query = " +SELECT activity_type_id , source_contact_id +FROM civicrm_activity +WHERE id = %1"; + $params = array(1 => array($key, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $dao->fetch(); + + // Get Activity Type ID + $value['activity_type_id'] = $dao->activity_type_id; + + // Get Conatct ID + $value['source_contact_id'] = $dao->source_contact_id; + + // make call use API 3 + $value['version'] = 3; + + $activityId = civicrm_api('activity', 'update', $value); + + // add custom field values + if (CRM_Utils_Array::value('custom', $value) && + is_array($value['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($value['custom'], 'civicrm_activity', $activityId['id']); + } + } + CRM_Core_Session::setStatus("", ts("Updates Saved"), "success"); + } + else { + CRM_Core_Session::setStatus("", ts("No Updates Saved"), "info"); + } + } + //end of function +} + diff --git a/CRM/Activity/Form/Task/Delete.php b/CRM/Activity/Form/Task/Delete.php new file mode 100755 index 0000000000..a5fdaedf5b --- /dev/null +++ b/CRM/Activity/Form/Task/Delete.php @@ -0,0 +1,92 @@ +addDefaultButtons(ts('Delete Activites'), 'done'); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $deletedActivities = 0; + foreach ($this->_activityHolderIds as $activityId['id']) { + $moveToTrash = CRM_Case_BAO_Case::isCaseActivity($activityId['id']); + if (CRM_Activity_BAO_Activity::deleteActivity($activityId, $moveToTrash)) { + $deletedActivities++; + } + } + + CRM_Core_Session::setStatus($deletedActivities, ts('Deleted Activities'), "success"); + CRM_Core_Session::setStatus("", ts('Total Selected Activities: %1', array(1 => count($this->_activityHolderIds))), "info"); + } +} + diff --git a/CRM/Activity/Form/Task/Email.php b/CRM/Activity/Form/Task/Email.php new file mode 100644 index 0000000000..0b5d75d28e --- /dev/null +++ b/CRM/Activity/Form/Task/Email.php @@ -0,0 +1,99 @@ +assign('single', $this->_single); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('emailTask', TRUE); + + CRM_Contact_Form_Task_EmailCommon::buildQuickForm($this); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Contact_Form_Task_EmailCommon::postProcess($this); + } +} + diff --git a/CRM/Activity/Form/Task/FileOnCase.php b/CRM/Activity/Form/Task/FileOnCase.php new file mode 100644 index 0000000000..ff8a35033f --- /dev/null +++ b/CRM/Activity/Form/Task/FileOnCase.php @@ -0,0 +1,181 @@ +_userContext = $session->readUserContext(); + + CRM_Utils_System::setTitle(ts('File on Case')); + + $validationFailed = FALSE; + + // insert validations here + + // then redirect + if ($validationFailed) { + CRM_Utils_System::redirect($this->_userContext); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->addElement('text', 'unclosed_cases', ts('Select Case')); + $this->add('hidden', 'unclosed_case_id', '', array('id' => 'unclosed_case_id')); + $this->addDefaultButtons(ts('Continue >>')); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Activity_Form_Task_FileOnCase', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static + function formRule($fields) { + $errors = array(); + if (empty($fields['unclosed_case_id'])) { + $errors['unclosed_case_id'] = ts('Case is a required field.'); + } + return $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + + public function postProcess() { + $formparams = $this->exportValues(); + $caseId = $formparams['unclosed_case_id']; + $filedActivities = 0; + foreach ($this->_activityHolderIds as $key => $id) { + $targetContactValues = $defaults = array(); + $params = array('id' => $id); + CRM_Activity_BAO_Activity::retrieve($params, $defaults); + if (CRM_Case_BAO_Case::checkPermission($id, 'File On Case', $defaults['activity_type_id'])) { + + if (!CRM_Utils_Array::crmIsEmptyArray($defaults['target_contact'])) { + $targetContactValues = array_combine(array_unique($defaults['target_contact']), + explode(';', trim($defaults['target_contact_value'])) + ); + $targetContactValues = implode(',', array_keys($targetContactValues)); + } + + $params = array( + 'caseID' => $caseId, + 'activityID' => $id, + 'newSubject' => empty($defaults['subject']) ? '' : $defaults['subject'], + 'targetContactIds' => $targetContactValues, + 'mode' => 'file', + ); + + $error_msg = CRM_Activity_Page_AJAX::_convertToCaseActivity($params); + if (empty($error_msg['error_msg'])) { + $filedActivities++; + } + else { + CRM_Core_Session::setStatus($error_msg['error_msg'], ts("Error"), "error"); + } + } + else { + CRM_Core_Session::setStatus(ts('Not permitted to file activity %1 %2.', array( + 1 => empty($defaults['subject']) ? '' : $defaults['subject'], + 2 => $defaults['activity_date_time'])), + ts("Error"), "error"); + } + } + + CRM_Core_Session::setStatus($filedActivities, ts("Filed Activities"), "success"); + CRM_Core_Session::setStatus("", ts('Total Selected Activities: %1', array(1 => count($this->_activityHolderIds))), "info"); + } +} + diff --git a/CRM/Activity/Form/Task/PickOption.php b/CRM/Activity/Form/Task/PickOption.php new file mode 100644 index 0000000000..b80b85883d --- /dev/null +++ b/CRM/Activity/Form/Task/PickOption.php @@ -0,0 +1,188 @@ +_userContext = $session->readUserContext(); + + CRM_Utils_System::setTitle(ts('Send Email to Contacts')); + + $validate = FALSE; + //validations + if (count($this->_activityHolderIds) > $this->_maxActivities) { + CRM_Core_Session::setStatus(ts("The maximum number of Activities you can select to send an email is %1. You have selected %2. Please select fewer Activities from your search results and try again.", array(1 => $this->_maxActivities, 2 => count($this->_activityHolderIds))), ts("Maximum Exceeded"), "error"); + $validate = TRUE; + } + // then redirect + if ($validate) { + CRM_Utils_System::redirect($this->_userContext); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->addElement('checkbox', 'with_contact', ts('With Contact')); + $this->addElement('checkbox', 'assigned_to', ts('Assigned to Contact')); + $this->addElement('checkbox', 'created_by', ts('Created by')); + $this->setDefaults(array('with_contact' => 1)); + $this->addDefaultButtons(ts('Continue >>')); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Activity_Form_Task_PickOption', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + if ( !isset($fields['with_contact']) && + !isset($fields['assigned_to']) && + !isset($fields['created_by']) + ) { + return array('with_contact' => ts('You must select at least one email recipient type.')); + } + return TRUE; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + // Clear any formRule errors from Email form in case they came back here via Cancel button + $this->controller->resetPage('Email'); + $params = $this->exportValues(); + $this->_contacts = array(); + //get assignee contacts + if (!empty($params['assigned_to'])) { + foreach ($this->_activityHolderIds as $key => $id) { + $ids = array_keys(CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($id)); + $this->_contacts = array_merge($this->_contacts, $ids); + } + } + //get target contacts + if (!empty($params['with_contact'])) { + foreach ($this->_activityHolderIds as $key => $id) { + $ids = array_keys(CRM_Activity_BAO_ActivityTarget::getTargetNames($id)); + $this->_contacts = array_merge($this->_contacts, $ids); + } + } + //get 'Added by' contacts + if (!empty($params['created_by'])) { + parent::setContactIDs(); + if (!empty($this->_contactIds)) { + $this->_contacts = array_merge($this->_contacts, $this->_contactIds); + } + } + $this->_contacts = array_unique($this->_contacts); + + //bounce to pick option if no contacts to send to + if ( empty($this->_contacts) ) { + $urlParams = "_qf_PickOption_display=true&qfKey={$params['qfKey']}"; + $urlRedirect = CRM_Utils_System::url('civicrm/activity/search', $urlParams); + CRM_Core_Error::statusBounce( + ts('It appears you have no contacts with emails from the selected recipients.'), + $urlRedirect + ); + } + + $this->set('contacts', $this->_contacts); + } +} + diff --git a/CRM/Activity/Form/Task/PickProfile.php b/CRM/Activity/Form/Task/PickProfile.php new file mode 100755 index 0000000000..2ca7ada305 --- /dev/null +++ b/CRM/Activity/Form/Task/PickProfile.php @@ -0,0 +1,179 @@ +_userContext = $session->readUserContext(); + + CRM_Utils_System::setTitle(ts('Batch Profile Update for Activities')); + + $validate = FALSE; + //validations + if (count($this->_activityHolderIds) > $this->_maxActivities) { + CRM_Core_Session::setStatus(ts("The maximum number of Activities you can select for Batch Update is %1. You have selected %2. Please select fewer Activities from your search results and try again.", array(1 => $this->_maxActivities, 2 => count($this->_activityHolderIds))), ts('Maximum Exceeded'), 'error'); + $validate = TRUE; + } + + // than redirect + if ($validate) { + CRM_Utils_System::redirect($this->_userContext); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $types = array('Activity'); + $profiles = CRM_Core_BAO_UFGroup::getProfiles($types, TRUE); + + $activityTypeIds = array_flip(CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name')); + $nonEditableActivityTypeIds = array( + $activityTypeIds['Email'], + $activityTypeIds['Bulk Email'], + $activityTypeIds['Contribution'], + $activityTypeIds['Inbound Email'], + $activityTypeIds['Pledge Reminder'], + $activityTypeIds['Membership Signup'], + $activityTypeIds['Membership Renewal'], + $activityTypeIds['Event Registration'], + $activityTypeIds['Pledge Acknowledgment'], + ); + $notEditable = FALSE; + foreach ($this->_activityHolderIds as $activityId) { + $typeId = CRM_Core_DAO::getFieldValue("CRM_Activity_DAO_Activity", $activityId, 'activity_type_id'); + if (in_array($typeId, $nonEditableActivityTypeIds)) { + $notEditable = TRUE; + break; + } + } + + if (empty($profiles)) { + CRM_Core_Session::setStatus(ts("You will need to create a Profile containing the %1 fields you want to edit before you can use Batch Update via Profile. Navigate to Administer CiviCRM >> CiviCRM Profile to configure a Profile. Consult the online Administrator documentation for more information.", array(1 => $types[0])), ts("No Profile Configured"), "alert"); + CRM_Utils_System::redirect($this->_userContext); + } + elseif ($notEditable) { + CRM_Core_Session::setStatus("", ts("Some of the selected activities are not editable."), "alert"); + CRM_Utils_System::redirect($this->_userContext); + } + + $ufGroupElement = $this->add('select', 'uf_group_id', ts('Select Profile'), + array( + '' => ts('- select profile -')) + $profiles, TRUE + ); + $this->addDefaultButtons(ts('Continue >>')); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Activity_Form_Task_PickProfile', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + return TRUE; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->exportValues(); + + $this->set('ufGroupId', $params['uf_group_id']); + + // also reset the batch page so it gets new values from the db + $this->controller->resetPage('Batch'); + } + //end of function +} + diff --git a/CRM/Activity/Form/Task/Print.php b/CRM/Activity/Form/Task/Print.php new file mode 100644 index 0000000000..9d631b9a9d --- /dev/null +++ b/CRM/Activity/Form/Task/Print.php @@ -0,0 +1,108 @@ +controller->setPrint(1); + + // get the formatted params + $queryParams = $this->get('queryParams'); + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $selector = new CRM_Activity_Selector_Search($queryParams, $this->_action, $this->_componentClause); + $controller = new CRM_Core_Selector_Controller($selector, NULL, $sortID, CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::SCREEN); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + /** + * Build the form - it consists of + * - displaying the QILL (query in local language) + * - displaying elements for saving the search + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // + // just need to add a javacript to popup the window for printing + // + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Print Activities'), + 'js' => array('onclick' => 'window.print()'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Done'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + // redirect to the main search page after printing is over + } +} + diff --git a/CRM/Activity/Form/Task/SMS.php b/CRM/Activity/Form/Task/SMS.php new file mode 100644 index 0000000000..bd6676f5ee --- /dev/null +++ b/CRM/Activity/Form/Task/SMS.php @@ -0,0 +1,85 @@ +assign('single', $this->_single); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('SMSTask', TRUE); + CRM_Contact_Form_Task_SMSCommon::buildQuickForm($this); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Contact_Form_Task_SMSCommon::postProcess($this); + } +} + diff --git a/CRM/Activity/Form/Task/SearchTaskHookSample.php b/CRM/Activity/Form/Task/SearchTaskHookSample.php new file mode 100644 index 0000000000..04589056e5 --- /dev/null +++ b/CRM/Activity/Form/Task/SearchTaskHookSample.php @@ -0,0 +1,95 @@ +_activityHolderIds); + $query = " + SELECT at.subject as subject, + ov.label as activity_type, + at.activity_date_time as activity_date, + ct.display_name as display_name + FROM civicrm_activity at +INNER JOIN civicrm_contact ct ON ( at.source_contact_id = ct.id ) + LEFT JOIN civicrm_option_group og ON ( og.name = 'activity_type' ) + LEFT JOIN civicrm_option_value ov ON (at.activity_type_id = ov.value AND og.id = ov.option_group_id ) + WHERE at.id IN ( $activityIDs )"; + + $dao = CRM_Core_DAO::executeQuery($query, + CRM_Core_DAO::$_nullArray + ); + + while ($dao->fetch()) { + $rows[] = array( + 'subject' => $dao->subject, + 'activity_type' => $dao->activity_type, + 'activity_date' => $dao->activity_date, + 'display_name' => $dao->display_name, + ); + } + $this->assign('rows', $rows); + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Activity/Import/Controller.php b/CRM/Activity/Import/Controller.php new file mode 100644 index 0000000000..b85b021a8a --- /dev/null +++ b/CRM/Activity/Import/Controller.php @@ -0,0 +1,53 @@ +_stateMachine = new CRM_Activity_Import_StateMachine($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $config = CRM_Core_Config::singleton(); + $this->addActions($config->uploadDir, array('uploadFile')); + } +} + diff --git a/CRM/Activity/Import/Field.php b/CRM/Activity/Import/Field.php new file mode 100644 index 0000000000..a5594746ad --- /dev/null +++ b/CRM/Activity/Import/Field.php @@ -0,0 +1,117 @@ +_name = $name; + $this->_title = $title; + $this->_type = $type; + $this->_headerPattern = $headerPattern; + $this->_dataPattern = $dataPattern; + + $this->_value = NULL; + } + + function resetValue() { + $this->_value = NULL; + } + + /** + * the value is in string format. convert the value to the type of this field + * and set the field value with the appropriate type + */ + function setValue($value) { + $this->_value = $value; + } + + function validate() { + + if (CRM_Utils_System::isNull($this->_value)) { + return TRUE; + } + return TRUE; + } +} + diff --git a/CRM/Activity/Import/Form/MapField.php b/CRM/Activity/Import/Form/MapField.php new file mode 100644 index 0000000000..bf591b03c1 --- /dev/null +++ b/CRM/Activity/Import/Form/MapField.php @@ -0,0 +1,608 @@ + $re) { + // Skip empty key/patterns + if (!$key || !$re || strlen("$re") < 5) { + continue; + } + + // Scan through the headerPatterns defined in the schema for a match + if (preg_match($re, $header)) { + $this->_fieldUsed[$key] = TRUE; + return $key; + } + } + return ''; + } + + /** + * Guess at the field names given the data and patterns from the schema + * + * @param patterns + * @param index + * + * @return string + * @access public + */ + public function defaultFromData(&$patterns, $index) { + $best = ''; + $bestHits = 0; + $n = count($this->_dataValues); + + foreach ($patterns as $key => $re) { + // Skip empty key/patterns + if (!$key || !$re || strlen("$re") < 5) { + continue; + } + + // if ($this->_fieldUsed[$key]) + // continue; + + /* Take a vote over the preview data set */ + + $hits = 0; + for ($i = 0; $i < $n; $i++) { + if (preg_match($re, $this->_dataValues[$i][$index])) { + $hits++; + } + } + + if ($hits > $bestHits) { + $bestHits = $hits; + $best = $key; + } + } + + if ($best != '') { + $this->_fieldUsed[$best] = TRUE; + } + return $best; + } + + /** + * Function to set variables up before form is built + * + * @return void + * @access public + */ + public function preProcess() { + $this->_mapperFields = $this->get('fields'); + unset($this->_mapperFields['id']); + asort($this->_mapperFields); + + $this->_columnCount = $this->get('columnCount'); + $this->assign('columnCount', $this->_columnCount); + $this->_dataValues = $this->get('dataValues'); + $this->assign('dataValues', $this->_dataValues); + + $skipColumnHeader = $this->controller->exportValue('UploadFile', 'skipColumnHeader'); + + if ($skipColumnHeader) { + $this->assign('skipColumnHeader', $skipColumnHeader); + $this->assign('rowDisplayCount', 3); + /* if we had a column header to skip, stash it for later */ + + $this->_columnHeaders = $this->_dataValues[0]; + } + else { + $this->assign('rowDisplayCount', 2); + } + $highlightedFields = array(); + $requiredFields = array('activity_date_time', 'activity_type_id', 'activity_label', 'target_contact_id', 'activity_subject'); + foreach ($requiredFields as $val) { + $highlightedFields[] = $val; + } + $this->assign('highlightedFields', $highlightedFields); + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + //to save the current mappings + if (!$this->get('savedMapping')) { + $saveDetailsName = ts('Save this field mapping'); + $this->applyFilter('saveMappingName', 'trim'); + $this->add('text', 'saveMappingName', ts('Name')); + $this->add('text', 'saveMappingDesc', ts('Description')); + } + else { + $savedMapping = $this->get('savedMapping'); + //mapping is to be loaded from database + + list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingRelation) = CRM_Core_BAO_Mapping::getMappingFields($savedMapping); + + //get loaded Mapping Fields + $mappingName = CRM_Utils_Array::value('1', $mappingName); + $mappingContactType = CRM_Utils_Array::value('1', $mappingContactType); + $mappingLocation = CRM_Utils_Array::value('1', $mappingLocation); + $mappingPhoneType = CRM_Utils_Array::value('1', $mappingPhoneType); + $mappingRelation = CRM_Utils_Array::value('1', $mappingRelation); + + $this->assign('loadedMapping', $savedMapping); + $this->set('loadedMapping', $savedMapping); + + $params = array('id' => $savedMapping); + $temp = array(); + $mappingDetails = CRM_Core_BAO_Mapping::retrieve($params, $temp); + + $this->assign('savedName', $mappingDetails->name); + + $this->add('hidden', 'mappingId', $savedMapping); + + $this->addElement('checkbox', 'updateMapping', ts('Update this field mapping'), NULL); + $saveDetailsName = ts('Save as a new field mapping'); + $this->add('text', 'saveMappingName', ts('Name')); + $this->add('text', 'saveMappingDesc', ts('Description')); + } + + $this->addElement('checkbox', 'saveMapping', $saveDetailsName, NULL, array('onclick' => "showSaveDetails(this)")); + + $this->addFormRule(array('CRM_Activity_Import_Form_MapField', 'formRule')); + + //-------- end of saved mapping stuff --------- + + $defaults = array(); + $mapperKeys = array_keys($this->_mapperFields); + + $hasHeaders = !empty($this->_columnHeaders); + $headerPatterns = $this->get('headerPatterns'); + $dataPatterns = $this->get('dataPatterns'); + $hasLocationTypes = $this->get('fieldTypes'); + + + /* Initialize all field usages to false */ + + foreach ($mapperKeys as $key) { + $this->_fieldUsed[$key] = FALSE; + } + $this->_location_types = CRM_Core_PseudoConstant::locationType(); + $sel1 = $this->_mapperFields; + + $sel2[''] = NULL; + + $js = "\n"; + $this->assign('initHideBoxes', $js); + + //set warning if mismatch in more than + if (isset($mappingName)) { + if (($this->_columnCount != count($mappingName))) { + $warning++; + } + } + if ($warning != 0 && $this->get('savedMapping')) { + $session = CRM_Core_Session::singleton(); + $session->setStatus(ts('The data columns in this import file appear to be different from the saved mapping. Please verify that you have selected the correct saved mapping before continuing.')); + } + else { + $session = CRM_Core_Session::singleton(); + $session->setStatus(NULL); + } + + $this->setDefaults($defaults); + + $this->addButtons(array( + array( + 'type' => 'back', + 'name' => ts('<< Previous'), + ), + array( + 'type' => 'next', + 'name' => ts('Continue >>'), + 'spacing' => '          ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + $errors = array(); + // define so we avoid notices below + $errors['_qf_default'] = ''; + + $fieldMessage = NULL; + if (!array_key_exists('savedMapping', $fields)) { + $importKeys = array(); + foreach ($fields['mapper'] as $mapperPart) { + $importKeys[] = $mapperPart[0]; + } + // FIXME: should use the schema titles, not redeclare them + $requiredFields = array( + 'target_contact_id' => ts('Contact ID'), + 'activity_date_time' => ts('Activity Date'), + 'activity_subject' => ts('Activity Subject'), + 'activity_type_id' => ts('Activity Type Id'), + ); + + $params = array( + 'used' => 'Unsupervised', + 'contact_type' => 'Individual', + ); + list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); + $weightSum = 0; + foreach ($importKeys as $key => $val) { + if (array_key_exists($val, $ruleFields)) { + $weightSum += $ruleFields[$val]; + } + } + foreach ($ruleFields as $field => $weight) { + $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; + } + foreach ($requiredFields as $field => $title) { + if (!in_array($field, $importKeys)) { + if ($field == 'target_contact_id') { + if ($weightSum >= $threshold || in_array('external_identifier', $importKeys)) { + continue; + } + else { + $errors['_qf_default'] .= ts('Missing required contact matching fields.') + . $fieldMessage . ' ' + . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array(1 => $threshold)) + . '
'; + } + } + elseif ($field == 'activity_type_id') { + if (in_array('activity_label', $importKeys)) { + continue; + } + else { + $errors['_qf_default'] .= ts('Missing required field: Provide %1 or %2', + array( + 1 => $title, + 2 => 'Activity Type Label' + )) . '
'; + } + } + else { + $errors['_qf_default'] .= ts('Missing required field: %1', array(1 => $title)) . '
'; + } + } + } + } + + if (CRM_Utils_Array::value('saveMapping', $fields)) { + $nameField = CRM_Utils_Array::value('saveMappingName', $fields); + if (empty($nameField)) { + $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); + } + else { + $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Activity', 'name'); + if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { + $errors['saveMappingName'] = ts('Duplicate Import Mapping Name'); + } + } + } + + if (empty($errors['_qf_default'])) { + unset($errors['_qf_default']); + } + if (!empty($errors)) { + if (!empty($errors['saveMappingName'])) { + $_flag = 1; + $assignError = new CRM_Core_Page(); + $assignError->assign('mappingDetailsError', $_flag); + } + return $errors; + } + + return TRUE; + } + + /** + * Process the mapped fields and map it into the uploaded file + * preview the file and extract some summary statistics + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->controller->exportValues('MapField'); + //reload the mapfield if load mapping is pressed + if (!empty($params['savedMapping'])) { + $this->set('savedMapping', $params['savedMapping']); + $this->controller->resetPage($this->_name); + return; + } + + $fileName = $this->controller->exportValue('UploadFile', 'uploadFile'); + $skipColumnHeader = $this->controller->exportValue('UploadFile', 'skipColumnHeader'); + + $config = CRM_Core_Config::singleton(); + $seperator = $config->fieldSeparator; + + $mapperKeys = array(); + $mapper = array(); + $mapperKeys = $this->controller->exportValue($this->_name, 'mapper'); + $mapperKeysMain = array(); + $mapperLocType = array(); + $mapperPhoneType = array(); + + for ($i = 0; $i < $this->_columnCount; $i++) { + $mapper[$i] = $this->_mapperFields[$mapperKeys[$i][0]]; + $mapperKeysMain[$i] = $mapperKeys[$i][0]; + + if ((CRM_Utils_Array::value(1, $mapperKeys[$i])) && (is_numeric($mapperKeys[$i][1]))) { + $mapperLocType[$i] = $mapperKeys[$i][1]; + } + else { + $mapperLocType[$i] = NULL; + } + + if ((CRM_Utils_Array::value(2, $mapperKeys[$i])) && (!is_numeric($mapperKeys[$i][2]))) { + $mapperPhoneType[$i] = $mapperKeys[$i][2]; + } + else { + $mapperPhoneType[$i] = NULL; + } + } + + $this->set('mapper', $mapper); + // store mapping Id to display it in the preview page + if (CRM_Utils_Array::value('mappingId', $params)) { + $this->set('loadMappingId', $params['mappingId']); + } + + //Updating Mapping Records + if (CRM_Utils_Array::value('updateMapping', $params)) { + + $mappingFields = new CRM_Core_DAO_MappingField(); + $mappingFields->mapping_id = $params['mappingId']; + $mappingFields->find(); + + $mappingFieldsId = array(); + while ($mappingFields->fetch()) { + if ($mappingFields->id) { + $mappingFieldsId[$mappingFields->column_number] = $mappingFields->id; + } + } + + for ($i = 0; $i < $this->_columnCount; $i++) { + $updateMappingFields = new CRM_Core_DAO_MappingField(); + $updateMappingFields->id = $mappingFieldsId[$i]; + $updateMappingFields->mapping_id = $params['mappingId']; + $updateMappingFields->column_number = $i; + + $updateMappingFields->name = $mapper[$i]; + $updateMappingFields->save(); + } + } + + //Saving Mapping Details and Records + if (CRM_Utils_Array::value('saveMapping', $params)) { + $mappingParams = array( + 'name' => $params['saveMappingName'], + 'description' => $params['saveMappingDesc'], + 'mapping_type_id' => CRM_Core_OptionGroup::getValue('mapping_type', + 'Import Activity', + 'name' + ), + ); + $saveMapping = CRM_Core_BAO_Mapping::add($mappingParams); + + for ($i = 0; $i < $this->_columnCount; $i++) { + $saveMappingFields = new CRM_Core_DAO_MappingField(); + $saveMappingFields->mapping_id = $saveMapping->id; + $saveMappingFields->column_number = $i; + + $saveMappingFields->name = $mapper[$i]; + $saveMappingFields->save(); + } + $this->set('savedMapping', $saveMappingFields->mapping_id); + } + + + $parser = new CRM_Activity_Import_Parser_Activity($mapperKeysMain, $mapperLocType, $mapperPhoneType); + $parser->run($fileName, $seperator, $mapper, $skipColumnHeader, + CRM_Activity_Import_Parser::MODE_PREVIEW + ); + + // add all the necessary variables to the form + $parser->set($this); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Match Fields'); + } +} + diff --git a/CRM/Activity/Import/Form/Preview.php b/CRM/Activity/Import/Form/Preview.php new file mode 100644 index 0000000000..5ce3ff47af --- /dev/null +++ b/CRM/Activity/Import/Form/Preview.php @@ -0,0 +1,232 @@ +controller->exportValue('UploadFile', 'skipColumnHeader'); + + //get the data from the session + $dataValues = $this->get('dataValues'); + $mapper = $this->get('mapper'); + $invalidRowCount = $this->get('invalidRowCount'); + $conflictRowCount = $this->get('conflictRowCount'); + $mismatchCount = $this->get('unMatchCount'); + + //get the mapping name displayed if the mappingId is set + $mappingId = $this->get('loadMappingId'); + if ($mappingId) { + $mapDAO = new CRM_Core_DAO_Mapping(); + $mapDAO->id = $mappingId; + $mapDAO->find(TRUE); + $this->assign('loadedMapping', $mappingId); + $this->assign('savedName', $mapDAO->name); + } + + if ($skipColumnHeader) { + $this->assign('skipColumnHeader', $skipColumnHeader); + $this->assign('rowDisplayCount', 3); + } + else { + $this->assign('rowDisplayCount', 2); + } + + if ($invalidRowCount) { + $urlParams = 'type=' . CRM_Activity_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + + if ($conflictRowCount) { + $urlParams = 'type=' . CRM_Activity_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + + if ($mismatchCount) { + $urlParams = 'type=' . CRM_Activity_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + + $properties = array( + 'mapper', + 'dataValues', 'columnCount', + 'totalRowCount', 'validRowCount', + 'invalidRowCount', 'conflictRowCount', + 'downloadErrorRecordsUrl', + 'downloadConflictRecordsUrl', + 'downloadMismatchRecordsUrl', + ); + + foreach ($properties as $property) { + $this->assign($property, $this->get($property)); + } + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + $this->addButtons(array( + array( + 'type' => 'back', + 'name' => ts('<< Previous'), + ), + array( + 'type' => 'next', + 'name' => ts('Import Now >>'), + 'spacing' => '          ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Preview'); + } + + /** + * Process the mapped fields and map it into the uploaded file + * preview the file and extract some summary statistics + * + * @return void + * @access public + */ + public function postProcess() { + $fileName = $this->controller->exportValue('UploadFile', 'uploadFile'); + $skipColumnHeader = $this->controller->exportValue('UploadFile', 'skipColumnHeader'); + $invalidRowCount = $this->get('invalidRowCount'); + $conflictRowCount = $this->get('conflictRowCount'); + $onDuplicate = $this->get('onDuplicate'); + + $config = CRM_Core_Config::singleton(); + $seperator = $config->fieldSeparator; + + $mapper = $this->controller->exportValue('MapField', 'mapper'); + $mapperKeys = array(); + $mapperLocType = array(); + $mapperPhoneType = array(); + + foreach ($mapper as $key => $value) { + $mapperKeys[$key] = $mapper[$key][0]; + + if (CRM_Utils_Array::value(1, $mapper[$key]) && is_numeric($mapper[$key][1])) { + $mapperLocType[$key] = $mapper[$key][1]; + } + else { + $mapperLocType[$key] = NULL; + } + + if (CRM_Utils_Array::value(2, $mapper[$key]) && (!is_numeric($mapper[$key][2]))) { + $mapperPhoneType[$key] = $mapper[$key][2]; + } + else { + $mapperPhoneType[$key] = NULL; + } + } + + $parser = new CRM_Activity_Import_Parser_Activity($mapperKeys, $mapperLocType, $mapperPhoneType); + + $mapFields = $this->get('fields'); + + foreach ($mapper as $key => $value) { + $header = array(); + if (isset($mapFields[$mapper[$key][0]])) { + $header[] = $mapFields[$mapper[$key][0]]; + } + $mapperFields[] = implode(' - ', $header); + } + $parser->run($fileName, $seperator, + $mapperFields, + $skipColumnHeader, + CRM_Activity_Import_Parser::MODE_IMPORT, + $onDuplicate + ); + + // add all the necessary variables to the form + $parser->set($this, CRM_Activity_Import_Parser::MODE_IMPORT); + + // check if there is any error occured + + $errorStack = CRM_Core_Error::singleton(); + $errors = $errorStack->getErrors(); + $errorMessage = array(); + + if (is_array($errors)) { + foreach ($errors as $key => $value) { + $errorMessage[] = $value['message']; + } + + $errorFile = $fileName['name'] . '.error.log'; + + if ($fd = fopen($errorFile, 'w')) { + fwrite($fd, implode('\n', $errorMessage)); + } + fclose($fd); + + $this->set('errorFile', $errorFile); + $urlParams = 'type=' . CRM_Activity_Import_Parser::ERROR . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + $urlParams = 'type=' . CRM_Activity_Import_Parser::CONFLICT . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + $urlParams = 'type=' . CRM_Activity_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + } +} + diff --git a/CRM/Activity/Import/Form/Summary.php b/CRM/Activity/Import/Form/Summary.php new file mode 100644 index 0000000000..38b9ca5f29 --- /dev/null +++ b/CRM/Activity/Import/Form/Summary.php @@ -0,0 +1,131 @@ +assign('errorFile', $this->get('errorFile')); + + $totalRowCount = $this->get('totalRowCount'); + $relatedCount = $this->get('relatedCount'); + $totalRowCount += $relatedCount; + $this->set('totalRowCount', $totalRowCount); + + $invalidRowCount = $this->get('invalidRowCount'); + $conflictRowCount = $this->get('conflictRowCount'); + $duplicateRowCount = $this->get('duplicateRowCount'); + $onDuplicate = $this->get('onDuplicate'); + $mismatchCount = $this->get('unMatchCount'); + if ($duplicateRowCount > 0) { + $urlParams = 'type=' . CRM_Activity_Import_Parser::DUPLICATE . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadDuplicateRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + elseif ($mismatchCount) { + $urlParams = 'type=' . CRM_Activity_Import_Parser::NO_MATCH . '&parser=CRM_Activity_Import_Parser'; + $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + else { + $duplicateRowCount = 0; + $this->set('duplicateRowCount', $duplicateRowCount); + } + + $this->assign('dupeError', FALSE); + + if ($onDuplicate == CRM_Activity_Import_Parser::DUPLICATE_UPDATE) { + $dupeActionString = ts('These records have been updated with the imported data.'); + } + elseif ($onDuplicate == CRM_Activity_Import_Parser::DUPLICATE_FILL) { + $dupeActionString = ts('These records have been filled in with the imported data.'); + } + else { + /* Skip by default */ + + $dupeActionString = ts('These records have not been imported.'); + + $this->assign('dupeError', TRUE); + + /* only subtract dupes from succesful import if we're skipping */ + + $this->set('validRowCount', $totalRowCount - $invalidRowCount - + $conflictRowCount - $duplicateRowCount - $mismatchCount + ); + } + $this->assign('dupeActionString', $dupeActionString); + + $properties = array('totalRowCount', 'validRowCount', 'invalidRowCount', 'conflictRowCount', 'downloadConflictRecordsUrl', 'downloadErrorRecordsUrl', 'duplicateRowCount', 'downloadDuplicateRecordsUrl', 'downloadMismatchRecordsUrl', 'groupAdditions', 'unMatchCount'); + foreach ($properties as $property) { + $this->assign($property, $this->get($property)); + } + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Summary'); + } +} + diff --git a/CRM/Activity/Import/Form/UploadFile.php b/CRM/Activity/Import/Form/UploadFile.php new file mode 100644 index 0000000000..2ff9dfef4f --- /dev/null +++ b/CRM/Activity/Import/Form/UploadFile.php @@ -0,0 +1,180 @@ +pushUserContext(CRM_Utils_System::url('civicrm/import/activity', 'reset=1')); + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + //Setting Upload File Size + $config = CRM_Core_Config::singleton(); + if ($config->maxImportFileSize >= 8388608) { + $uploadFileSize = 8388608; + } + else { + $uploadFileSize = $config->maxImportFileSize; + } + $uploadSize = round(($uploadFileSize / (1024 * 1024)), 2); + + $this->assign('uploadSize', $uploadSize); + + $this->add('file', 'uploadFile', ts('Import Data File'), 'size=30 maxlength=255', TRUE); + + $this->addRule('uploadFile', ts('A valid file must be uploaded.'), 'uploadedfile'); + $this->addRule('uploadFile', ts('File size should be less than %1 MBytes (%2 bytes)', array(1 => $uploadSize, 2 => $uploadFileSize)), 'maxfilesize', $uploadFileSize); + $this->setMaxFileSize($uploadFileSize); + $this->addRule('uploadFile', ts('Input file must be in CSV format'), 'utf8File'); + + $this->addElement('checkbox', 'skipColumnHeader', ts('First row contains column headers')); + + $duplicateOptions = array(); + $duplicateOptions[] = $this->createElement('radio', + NULL, NULL, ts('Skip'), CRM_Activity_Import_Parser::DUPLICATE_SKIP + ); + $duplicateOptions[] = $this->createElement('radio', + NULL, NULL, ts('Update'), CRM_Activity_Import_Parser::DUPLICATE_UPDATE + ); + $duplicateOptions[] = $this->createElement('radio', + NULL, NULL, ts('Fill'), CRM_Activity_Import_Parser::DUPLICATE_FILL + ); + + $this->addGroup($duplicateOptions, 'onDuplicate', + ts('On duplicate entries') + ); + + //get the saved mapping details + $mappingArray = CRM_Core_BAO_Mapping::getMappings(CRM_Core_OptionGroup::getValue('mapping_type', + 'Import Activity', + 'name' + )); + $this->assign('savedMapping', $mappingArray); + $this->add('select', 'savedMapping', ts('Mapping Option'), array('' => ts('- select -')) + $mappingArray); + + if ($loadeMapping = $this->get('loadedMapping')) { + $this->assign('loadedMapping', $loadeMapping); + $this->setDefaults(array('savedMapping' => $loadeMapping)); + } + + $this->setDefaults(array( + 'onDuplicate' => + CRM_Activity_Import_Parser::DUPLICATE_SKIP, + )); + + //build date formats + CRM_Core_Form_Date::buildAllowedDateFormats($this); + + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Continue >>'), + 'spacing' => '          ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Process the uploaded file + * + * @return void + * @access public + */ + public function postProcess() { + $this->controller->resetPage('MapField'); + + $fileName = $this->controller->exportValue($this->_name, 'uploadFile'); + $skipColumnHeader = $this->controller->exportValue($this->_name, 'skipColumnHeader'); + $onDuplicate = $this->controller->exportValue($this->_name, 'onDuplicate'); + $dateFormats = $this->controller->exportValue($this->_name, 'dateFormats'); + $savedMapping = $this->controller->exportValue($this->_name, 'savedMapping'); + + $this->set('onDuplicate', $onDuplicate); + $this->set('dateFormats', $dateFormats); + $this->set('savedMapping', $savedMapping); + + $session = CRM_Core_Session::singleton(); + $session->set("dateTypes", $dateFormats); + + $config = CRM_Core_Config::singleton(); + $seperator = $config->fieldSeparator; + + $mapper = array(); + + $parser = new CRM_Activity_Import_Parser_Activity($mapper); + $parser->setMaxLinesToProcess(100); + $parser->run($fileName, $seperator, + $mapper, + $skipColumnHeader, + CRM_Activity_Import_Parser::MODE_MAPFIELD + ); + + // add all the necessary variables to the form + $parser->set($this); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Upload Data'); + } +} + diff --git a/CRM/Activity/Import/Parser.php b/CRM/Activity/Import/Parser.php new file mode 100644 index 0000000000..6b5d261510 --- /dev/null +++ b/CRM/Activity/Import/Parser.php @@ -0,0 +1,651 @@ +_maxLinesToProcess = 0; + $this->_maxErrorCount = self::MAX_ERRORS; + } + + abstract function init(); + function run($fileName, + $seperator = ',', + &$mapper, + $skipColumnHeader = FALSE, + $mode = self::MODE_PREVIEW, + $onDuplicate = self::DUPLICATE_SKIP + ) { + if (!is_array($fileName)) { + CRM_Core_Error::fatal(); + } + $fileName = $fileName['name']; + + $this->init(); + + $this->_haveColumnHeader = $skipColumnHeader; + + $this->_seperator = $seperator; + + $fd = fopen($fileName, "r"); + if (!$fd) { + return FALSE; + } + + $this->_lineCount = $this->_warningCount = 0; + $this->_invalidRowCount = $this->_validCount = 0; + $this->_totalCount = $this->_conflictCount = 0; + + $this->_errors = array(); + $this->_warnings = array(); + $this->_conflicts = array(); + + $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2); + + if ($mode == self::MODE_MAPFIELD) { + $this->_rows = array(); + } + else { + $this->_activeFieldCount = count($this->_activeFields); + } + + while (!feof($fd)) { + $this->_lineCount++; + + $values = fgetcsv($fd, 8192, $seperator); + if (!$values) { + continue; + } + + self::encloseScrub($values); + + // skip column header if we're not in mapfield mode + if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) { + $skipColumnHeader = FALSE; + continue; + } + + /* trim whitespace around the values */ + + $empty = TRUE; + foreach ($values as $k => $v) { + $values[$k] = trim($v, " \t\r\n"); + } + + if (CRM_Utils_System::isNull($values)) { + continue; + } + + $this->_totalCount++; + + if ($mode == self::MODE_MAPFIELD) { + $returnCode = $this->mapField($values); + } + elseif ($mode == self::MODE_PREVIEW) { + $returnCode = $this->preview($values); + } + elseif ($mode == self::MODE_SUMMARY) { + $returnCode = $this->summary($values); + } + elseif ($mode == self::MODE_IMPORT) { + $returnCode = $this->import($onDuplicate, $values); + } + else { + $returnCode = self::ERROR; + } + + // note that a line could be valid but still produce a warning + if ($returnCode & self::VALID) { + $this->_validCount++; + if ($mode == self::MODE_MAPFIELD) { + $this->_rows[] = $values; + $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); + } + } + + if ($returnCode & self::WARNING) { + $this->_warningCount++; + if ($this->_warningCount < $this->_maxWarningCount) { + $this->_warningCount[] = $line; + } + } + + if ($returnCode & self::ERROR) { + $this->_invalidRowCount++; + if ($this->_invalidRowCount < $this->_maxErrorCount) { + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_errors[] = $values; + } + } + + if ($returnCode & self::CONFLICT) { + $this->_conflictCount++; + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_conflicts[] = $values; + } + + if ($returnCode & self::DUPLICATE) { + if ($returnCode & self::MULTIPLE_DUPE) { + /* TODO: multi-dupes should be counted apart from singles + * on non-skip action */ + } + $this->_duplicateCount++; + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_duplicates[] = $values; + if ($onDuplicate != self::DUPLICATE_SKIP) { + $this->_validCount++; + } + } + + // we give the derived class a way of aborting the process + // note that the return code could be multiple code or'ed together + if ($returnCode & self::STOP) { + break; + } + + // if we are done processing the maxNumber of lines, break + if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) { + break; + } + } + + fclose($fd); + + + if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) { + $customHeaders = $mapper; + + $customfields = CRM_Core_BAO_CustomField::getFields('Activity'); + foreach ($customHeaders as $key => $value) { + if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) { + $customHeaders[$key] = $customfields[$id][0]; + } + } + if ($this->_invalidRowCount) { + // removed view url for invlaid contacts + $headers = array_merge(array(ts('Line Number'), + ts('Reason'), + ), + $customHeaders + ); + $this->_errorFileName = self::errorFileName(self::ERROR); + self::exportCSV($this->_errorFileName, $headers, $this->_errors); + } + if ($this->_conflictCount) { + $headers = array_merge(array(ts('Line Number'), + ts('Reason'), + ), + $customHeaders + ); + $this->_conflictFileName = self::errorFileName(self::CONFLICT); + self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts); + } + if ($this->_duplicateCount) { + $headers = array_merge(array(ts('Line Number'), + ts('View Activity History URL'), + ), + $customHeaders + ); + + $this->_duplicateFileName = self::errorFileName(self::DUPLICATE); + self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates); + } + } + //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount"; + return $this->fini(); + } + + abstract function mapField(&$values); + abstract function preview(&$values); + abstract function summary(&$values); + abstract function import($onDuplicate, &$values); + + abstract function fini(); + + /** + * Given a list of the importable field keys that the user has selected + * set the active fields array to this list + * + * @param array mapped array of values + * + * @return void + * @access public + */ + function setActiveFields($fieldKeys) { + $this->_activeFieldCount = count($fieldKeys); + foreach ($fieldKeys as $key) { + if (empty($this->_fields[$key])) { + $this->_activeFields[] = new CRM_Activity_Import_Field('', ts('- do not import -')); + } + else { + $this->_activeFields[] = clone($this->_fields[$key]); + } + } + } + + /*function setActiveFieldLocationTypes( $elements ) + { + for ($i = 0; $i < count( $elements ); $i++) { + $this->_activeFields[$i]->_hasLocationType = $elements[$i]; + } + } + + function setActiveFieldPhoneTypes( $elements ) + { + for ($i = 0; $i < count( $elements ); $i++) { + $this->_activeFields[$i]->_phoneType = $elements[$i]; + } + }*/ + function setActiveFieldValues($elements, &$erroneousField) { + $maxCount = count($elements) < $this->_activeFieldCount ? count($elements) : $this->_activeFieldCount; + for ($i = 0; $i < $maxCount; $i++) { + $this->_activeFields[$i]->setValue($elements[$i]); + } + + // reset all the values that we did not have an equivalent import element + for (; $i < $this->_activeFieldCount; $i++) { + $this->_activeFields[$i]->resetValue(); + } + + // now validate the fields and return false if error + $valid = self::VALID; + for ($i = 0; $i < $this->_activeFieldCount; $i++) { + if (!$this->_activeFields[$i]->validate()) { + // no need to do any more validation + $erroneousField = $i; + $valid = self::ERROR; + break; + } + } + return $valid; + } + + /** + * function to format the field values for input to the api + * + * @return array (reference ) associative array of name/value pairs + * @access public + */ + function &getActiveFieldParams() { + $params = array(); + for ($i = 0; $i < $this->_activeFieldCount; $i++) { + if (isset($this->_activeFields[$i]->_value) + && !isset($params[$this->_activeFields[$i]->_name]) + && !isset($this->_activeFields[$i]->_related) + ) { + + $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value; + } + } + return $params; + } + + function getSelectValues() { + $values = array(); + foreach ($this->_fields as $name => $field) { + $values[$name] = $field->_title; + } + return $values; + } + + function getSelectTypes() { + $values = array(); + foreach ($this->_fields as $name => $field) { + if (isset($field->_hasLocationType)) { + $values[$name] = $field->_hasLocationType; + } + } + return $values; + } + + function getHeaderPatterns() { + $values = array(); + foreach ($this->_fields as $name => $field) { + $values[$name] = $field->_headerPattern; + } + return $values; + } + + function getDataPatterns() { + $values = array(); + foreach ($this->_fields as $name => $field) { + $values[$name] = $field->_dataPattern; + } + return $values; + } + + function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') { + if (empty($name)) { + $this->_fields['doNotImport'] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern); + } + else { + + $tempField = CRM_Contact_BAO_Contact::importableFields('Individual', NULL); + if (!array_key_exists($name, $tempField)) { + $this->_fields[$name] = new CRM_Activity_Import_Field($name, $title, $type, $headerPattern, $dataPattern); + } + else { + $this->_fields[$name] = new CRM_Import_Field($name, $title, $type, $headerPattern, $dataPattern, CRM_Utils_Array::value('hasLocationType', $tempField[$name])); + } + } + } + + /** + * setter function + * + * @param int $max + * + * @return void + * @access public + */ + function setMaxLinesToProcess($max) { + $this->_maxLinesToProcess = $max; + } + + /** + * Store parser values + * + * @param CRM_Core_Session $store + * + * @return void + * @access public + */ + function set($store, $mode = self::MODE_SUMMARY) { + $store->set('fileSize', $this->_fileSize); + $store->set('lineCount', $this->_lineCount); + $store->set('seperator', $this->_seperator); + $store->set('fields', $this->getSelectValues()); + $store->set('fieldTypes', $this->getSelectTypes()); + + $store->set('headerPatterns', $this->getHeaderPatterns()); + $store->set('dataPatterns', $this->getDataPatterns()); + $store->set('columnCount', $this->_activeFieldCount); + + $store->set('totalRowCount', $this->_totalCount); + $store->set('validRowCount', $this->_validCount); + $store->set('invalidRowCount', $this->_invalidRowCount); + $store->set('conflictRowCount', $this->_conflictCount); + + if ($this->_invalidRowCount) { + $store->set('errorsFileName', $this->_errorFileName); + } + if ($this->_conflictCount) { + $store->set('conflictsFileName', $this->_conflictFileName); + } + if (isset($this->_rows) && !empty($this->_rows)) { + $store->set('dataValues', $this->_rows); + } + + if ($mode == self::MODE_IMPORT) { + $store->set('duplicateRowCount', $this->_duplicateCount); + if ($this->_duplicateCount) { + $store->set('duplicatesFileName', $this->_duplicateFileName); + } + } + //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount"; + } + + /** + * Export data to a CSV file + * + * @param string $filename + * @param array $header + * @param data $data + * + * @return void + * @access public + */ + static function exportCSV($fileName, $header, $data) { + $output = array(); + $fd = fopen($fileName, 'w'); + + foreach ($header as $key => $value) { + $header[$key] = "\"$value\""; + } + $config = CRM_Core_Config::singleton(); + $output[] = implode($config->fieldSeparator, $header); + + foreach ($data as $datum) { + foreach ($datum as $key => $value) { + $datum[$key] = "\"$value\""; + } + $output[] = implode($config->fieldSeparator, $datum); + } + fwrite($fd, implode("\n", $output)); + fclose($fd); + } + + /** + * Remove single-quote enclosures from a value array (row) + * + * @param array $values + * @param string $enclosure + * + * @return void + * @static + * @access public + */ + static function encloseScrub(&$values, $enclosure = "'") { + if (empty($values)) { + return; + } + + foreach ($values as $k => $v) { + $values[$k] = preg_replace("/^$enclosure(.*) $enclosure$/", '$1', $v); + } + } + + function errorFileName($type) { + $fileName = CRM_Import_Parser::errorFileName($type); + return $fileName; + } + + function saveFileName($type) { + $fileName = CRM_Import_Parser::saveFileName($type); + return $fileName; + } +} + diff --git a/CRM/Activity/Import/Parser/Activity.php b/CRM/Activity/Import/Parser/Activity.php new file mode 100644 index 0000000000..1bffc07834 --- /dev/null +++ b/CRM/Activity/Import/Parser/Activity.php @@ -0,0 +1,389 @@ +_mapperKeys = &$mapperKeys; + } + + /** + * the initializer code, called before the processing + * + * @return void + * @access public + */ + function init() { + $fields = array_merge(CRM_Activity_BAO_Activity::importableFields(), + CRM_Activity_BAO_ActivityTarget::import() + ); + + $fields = array_merge($fields, array('activity_label' => array('title' => ts('Activity Type Label'), + 'headerPattern' => '/(activity.)?type label?/i', + ))); + + foreach ($fields as $name => $field) { + $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT); + $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//'); + $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//'); + $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']); + } + + $this->_newActivity = array(); + + $this->setActiveFields($this->_mapperKeys); + + // FIXME: we should do this in one place together with Form/MapField.php + $this->_contactIdIndex = -1; + $this->_activityTypeIndex = -1; + $this->_activityLabelIndex = -1; + $this->_activityDateIndex = -1; + + $index = 0; + foreach ($this->_mapperKeys as $key) { + switch ($key) { + case 'target_contact_id': + case 'external_identifier': + $this->_contactIdIndex = $index; + break; + + case 'activity_label': + $this->_activityLabelIndex = $index; + break; + + case 'activity_type_id': + $this->_activityTypeIndex = $index; + break; + + case 'activity_date_time': + $this->_activityDateIndex = $index; + break; + } + $index++; + } + } + + /** + * handle the values in mapField mode + * + * @param array $values the array of values belonging to this line + * + * @return boolean + * @access public + */ + function mapField(&$values) { + return CRM_Activity_Import_Parser::VALID; + } + + /** + * handle the values in preview mode + * + * @param array $values the array of values belonging to this line + * + * @return boolean the result of this processing + * @access public + */ + function preview(&$values) { + return $this->summary($values); + } + + /** + * handle the values in summary mode + * + * @param array $values the array of values belonging to this line + * + * @return boolean the result of this processing + * @access public + */ + function summary(&$values) { + $erroneousField = NULL; + $response = $this->setActiveFieldValues($values, $erroneousField); + $index = -1; + $errorRequired = FALSE; + + if ($this->_activityTypeIndex > -1 && $this->_activityLabelIndex > -1) { + array_unshift($values, ts('Please select either Activity Type ID OR Activity Type Label.')); + return CRM_Activity_Import_Parser::ERROR; + } + elseif ($this->_activityLabelIndex > -1) { + $index = $this->_activityLabelIndex; + } + elseif ($this->_activityTypeIndex > -1) { + $index = $this->_activityTypeIndex; + } + + if ($index < 0 or $this->_activityDateIndex < 0) { + $errorRequired = TRUE; + } + else { + $errorRequired = !CRM_Utils_Array::value($index, $values) || !CRM_Utils_Array::value($this->_activityDateIndex, $values); + } + + if ($errorRequired) { + array_unshift($values, ts('Missing required fields')); + return CRM_Activity_Import_Parser::ERROR; + } + + $params = &$this->getActiveFieldParams(); + + $errorMessage = NULL; + + //for date-Formats + $session = CRM_Core_Session::singleton(); + $dateType = $session->get('dateTypes'); + if (!isset($params['source_contact_id'])) { + $params['source_contact_id'] = $session->get('userID'); + } + foreach ($params as $key => $val) { + if ($key == 'activity_date_time') { + if ($val) { + $dateValue = CRM_Utils_Date::formatDate($val, $dateType); + if ($dateValue) { + $params[$key] = $dateValue; + } + else { + CRM_Import_Parser_Contact::addToErrorMsg('Activity date', $errorMessage); + } + } + } + elseif ($key == 'activity_engagement_level' && $val && + !CRM_Utils_Rule::positiveInteger($val) + ) { + CRM_Import_Parser_Contact::addToErrorMsg('Activity Engagement Index', $errorMessage); + } + } + //date-Format part ends + + //checking error in custom data + $params['contact_type'] = isset($this->_contactType) ? $this->_contactType : 'Activity'; + + CRM_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage); + + if ($errorMessage) { + $tempMsg = "Invalid value for field(s) : $errorMessage"; + array_unshift($values, $tempMsg); + $errorMessage = NULL; + return CRM_Import_Parser::ERROR; + } + + return CRM_Activity_Import_Parser::VALID; + } + + /** + * handle the values in import mode + * + * @param int $onDuplicate the code for what action to take on duplicates + * @param array $values the array of values belonging to this line + * + * @return boolean the result of this processing + * @access public + */ + function import($onDuplicate, &$values) { + // first make sure this is a valid line + $response = $this->summary($values); + + if ($response != CRM_Activity_Import_Parser::VALID) { + return $response; + } + $params = &$this->getActiveFieldParams(); + $activityLabel = array_search('activity_label', $this->_mapperKeys); + if ($activityLabel) { + $params = array_merge($params, array('activity_label' => $values[$activityLabel])); + } + //for date-Formats + $session = CRM_Core_Session::singleton(); + $dateType = $session->get('dateTypes'); + if (!isset($params['source_contact_id'])) { + $params['source_contact_id'] = $session->get('userID'); + } + $formatted = array(); + $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $params)); + + foreach ($params as $key => $val) { + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { + if ($customFields[$customFieldID]['data_type'] == 'Date') { + CRM_Import_Parser_Contact::formatCustomDate($params, $params, $dateType, $key); + } + elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { + $params[$key] = CRM_Utils_String::strtoboolstr($val); + } + } + elseif ($key == 'activity_subject') { + $params['subject'] = $val; + } + } + //date-Format part ends + require_once 'CRM/Utils/DeprecatedUtils.php'; + $formatError = _civicrm_api3_deprecated_activity_formatted_param($params, $params, TRUE); + + if ($formatError) { + array_unshift($values, $formatError['error_message']); + return CRM_Activity_Import_Parser::ERROR; + } + + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + CRM_Core_DAO::$_nullObject, + NULL, + 'Activity' + ); + + if ($this->_contactIdIndex < 0) { + + //retrieve contact id using contact dedupe rule. + //since we are support only individual's activity import. + $params['contact_type'] = 'Individual'; + $params['version'] = 3; + $error = _civicrm_api3_deprecated_duplicate_formatted_contact($params); + + if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) { + $matchedIDs = explode(',', $error['error_message']['params'][0]); + if (count($matchedIDs) > 1) { + array_unshift($values, 'Multiple matching contact records detected for this row. The activity was not imported'); + return CRM_Activity_Import_Parser::ERROR; + } + else { + $cid = $matchedIDs[0]; + $params['target_contact_id'] = $cid; + $params['version'] = 3; + $newActivity = civicrm_api('activity', 'create', $params); + if (CRM_Utils_Array::value('is_error', $newActivity)) { + array_unshift($values, $newActivity['error_message']); + return CRM_Activity_Import_Parser::ERROR; + } + + $this->_newActivity[] = $newActivity['id']; + return CRM_Activity_Import_Parser::VALID; + } + } + else { + // Using new Dedupe rule. + $ruleParams = array( + 'contact_type' => 'Individual', + 'used' => 'Unsupervised', + ); + $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); + + $disp = NULL; + foreach ($fieldsArray as $value) { + if (array_key_exists(trim($value), $params)) { + $paramValue = $params[trim($value)]; + if (is_array($paramValue)) { + $disp .= $params[trim($value)][0][trim($value)] . " "; + } + else { + $disp .= $params[trim($value)] . " "; + } + } + } + + if (CRM_Utils_Array::value('external_identifier', $params)) { + if ($disp) { + $disp .= "AND {$params['external_identifier']}"; + } + else { + $disp = $params['external_identifier']; + } + } + + array_unshift($values, 'No matching Contact found for (' . $disp . ')'); + return CRM_Activity_Import_Parser::ERROR; + } + } + else { + if (CRM_Utils_Array::value('external_identifier', $params)) { + $targetContactId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $params['external_identifier'], 'id', 'external_identifier' + ); + + if (CRM_Utils_Array::value('target_contact_id', $params) && + $params['target_contact_id'] != $targetContactId + ) { + array_unshift($values, 'Mismatch of External identifier :' . $params['external_identifier'] . ' and Contact Id:' . $params['target_contact_id']); + return CRM_Activity_Import_Parser::ERROR; + } + elseif ($targetContactId) { + $params['target_contact_id'] = $targetContactId; + } + else { + array_unshift($values, 'No Matching Contact for External identifier :' . $params['external_identifier']); + return CRM_Activity_Import_Parser::ERROR; + } + } + + $params['version'] = 3; + $newActivity = civicrm_api('activity', 'create', $params); + if (CRM_Utils_Array::value('is_error', $newActivity)) { + array_unshift($values, $newActivity['error_message']); + return CRM_Activity_Import_Parser::ERROR; + } + + $this->_newActivity[] = $newActivity['id']; + return CRM_Activity_Import_Parser::VALID; + } + } + + /** + * the initializer code, called before the processing + * + * @return void + * @access public + */ + function fini() {} + +} + diff --git a/CRM/Activity/Import/StateMachine.php b/CRM/Activity/Import/StateMachine.php new file mode 100644 index 0000000000..e5d2986fea --- /dev/null +++ b/CRM/Activity/Import/StateMachine.php @@ -0,0 +1,63 @@ +_pages = array( + 'CRM_Activity_Import_Form_UploadFile' => NULL, + 'CRM_Activity_Import_Form_MapField' => NULL, + 'CRM_Activity_Import_Form_Preview' => NULL, + 'CRM_Activity_Import_Form_Summary' => NULL, + ); + + $this->addSequentialPages($this->_pages, $action); + } +} + diff --git a/CRM/Activity/Page/AJAX.php b/CRM/Activity/Page/AJAX.php new file mode 100644 index 0000000000..2cc9e18e91 --- /dev/null +++ b/CRM/Activity/Page/AJAX.php @@ -0,0 +1,455 @@ + 'display_date', 1 => 'ca.subject', 2 => 'ca.activity_type_id', + 3 => 'acc.sort_name', 4 => 'cc.sort_name', 5 => 'ca.status_id', + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $params = $_POST; + if ($sort && $sortOrder) { + $params['sortname'] = $sort; + $params['sortorder'] = $sortOrder; + } + $params['page'] = ($offset / $rowCount) + 1; + $params['rp'] = $rowCount; + + // get the activities related to given case + $activities = CRM_Case_BAO_Case::getCaseActivity($caseID, $params, $contactID, $context, $userID); + + $iFilteredTotal = $iTotal = $params['total']; + $selectorElements = array('display_date', 'subject', 'type', 'with_contacts', 'reporter', 'status', 'links', 'class'); + + echo CRM_Utils_JSON::encodeDataTableSelector($activities, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + static function getCaseGlobalRelationships() { + $sortMapper = array( + 0 => 'sort_name', 1 => 'phone', 2 => 'email', + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $params = $_POST; + if ($sort && $sortOrder) { + $sortSQL = $sort .' '.$sortOrder; + } + + // get the activities related to given case + $globalGroupInfo = array(); + + // get the total row count + $relGlobalTotalCount = CRM_Case_BAO_Case::getGlobalContacts($globalGroupInfo, NULL, FALSE, TRUE, NULL, NULL); + // limit the rows + $relGlobal = CRM_Case_BAO_Case::getGlobalContacts($globalGroupInfo, $sortSQL, $showLinks = TRUE, FALSE, $offset, $rowCount); + + $iFilteredTotal = $iTotal = $relGlobalTotalCount; + $selectorElements = array('sort_name', 'phone', 'email'); + + echo CRM_Utils_JSON::encodeDataTableSelector($relGlobal, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + static function getCaseClientRelationships() { + $caseID = CRM_Utils_Type::escape($_GET['caseID'], 'Integer'); + $contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer'); + + $sortMapper = array( + 0 => 'relation', 1 => 'name', 2 => 'phone', 3 => 'email' + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : 'relation'; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $params = $_POST; + if ($sort && $sortOrder) { + $sortSQL = $sort .' '.$sortOrder; + } + + // Retrieve ALL client relationships + $relClient = CRM_Contact_BAO_Relationship::getRelationship($contactID, + CRM_Contact_BAO_Relationship::CURRENT, + 0, 0, 0, NULL, NULL, FALSE + ); + + $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($contactID, $caseID); + + // Now build 'Other Relationships' array by removing relationships that are already listed under Case Roles + // so they don't show up twice. + $clientRelationships = array(); + foreach ($relClient as $r) { + if (!array_key_exists($r['id'], $caseRelationships)) { + $clientRelationships[] = $r; + } + } + + // sort clientRelationships array using jquery call params + foreach ($clientRelationships as $key => $row) { + $sortArray[$key] = $row[$sort]; + } + $sort_type = "SORT_".strtoupper($sortOrder); + $sort_function = "array_multisort(\$sortArray, ".$sort_type.", \$clientRelationships);"; + eval($sort_function); + + //limit the rows + $allClientRelationships = $clientRelationships; + $clientRelationships = array_slice($allClientRelationships, $offset, $rowCount, TRUE); + + // after sort we can update username fields to be a url + foreach($clientRelationships as $key => $value) { + $clientRelationships[$key]['name'] = ''.$clientRelationships[$key]['name'].''; + } + + $iFilteredTotal = $iTotal = $params['total'] = count($allClientRelationships); + $selectorElements = array('relation', 'name', 'phone', 'email'); + + echo CRM_Utils_JSON::encodeDataTableSelector($clientRelationships, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + + static function getCaseRoles() { + $caseID = CRM_Utils_Type::escape($_GET['caseID'], 'Integer'); + $contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer'); + + $sortMapper = array( + 0 => 'relation', 1 => 'name', 2 => 'phone', 3 => 'email', 4 => 'actions' + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : 'relation'; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $params = $_POST; + if ($sort && $sortOrder) { + $sortSQL = $sort .' '.$sortOrder; + } + + $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($contactID, $caseID); + $caseTypeName = CRM_Case_BAO_Case::getCaseType($caseID, 'name'); + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $caseRoles = $xmlProcessor->get($caseTypeName, 'CaseRoles'); + + $hasAccessToAllCases = CRM_Core_Permission::check('access all cases and activities'); + + $managerRoleId = $xmlProcessor->getCaseManagerRoleId($caseTypeName); + if (!empty($managerRoleId)) { + $caseRoles[$managerRoleId] = $caseRoles[$managerRoleId] . '
' . '(' . ts('Case Manager') . ')'; + } + + foreach ($caseRelationships as $key => $value) { + //calculate roles that don't have relationships + if (CRM_Utils_Array::value($value['relation_type'], $caseRoles)) { + //keep naming from careRoles array + $caseRelationships[$key]['relation'] = $caseRoles[$value['relation_type']]; + unset($caseRoles[$value['relation_type']]); + } + // mark orginal case relationships record to use on setting edit links below + $caseRelationships[$key]['source'] = 'caseRel'; + } + + $caseRoles['client'] = CRM_Case_BAO_Case::getContactNames($caseID); + + // move/transform caseRoles array data to caseRelationships + // for sorting and display + foreach($caseRoles as $id => $value) { + if ($id != "client") { + $rel = array(); + $rel['relation'] = $value; + $rel['relation_type'] = $id; + $rel['name'] = '(not assigned)'; + $rel['phone'] = ''; + $rel['email'] = ''; + $rel['source'] = 'caseRoles'; + $caseRelationships[] = $rel; + } else { + foreach($value as $clientRole) { + $relClient = array(); + $relClient['relation'] = 'Client'; + $relClient['name'] = $clientRole['sort_name']; + $relClient['phone'] = $clientRole['phone']; + $relClient['email'] = $clientRole['email']; + $relClient['cid'] = $clientRole['contact_id']; + $relClient['source'] = 'contact'; + $caseRelationships[] = $relClient; + } + } + } + + // sort clientRelationships array using jquery call params + foreach ($caseRelationships as $key => $row) { + $sortArray[$key] = $row[$sort]; + } + + $sort_type = "SORT_".strtoupper($sortOrder); + + $sort_function = "array_multisort(\$sortArray, ".$sort_type.", \$caseRelationships);"; + eval($sort_function); + + //limit rows display + $allCaseRelationships = $caseRelationships; + $caseRelationships = array_slice($allCaseRelationships, $offset, $rowCount, TRUE); + + // set user name, email and edit columns links + // idx will count number of current row / needed by edit links + $idx = 1; + foreach ($caseRelationships as $key => $row) { + // view user links + if ($caseRelationships[$key]['cid']) { + $caseRelationships[$key]['name'] = ''.$caseRelationships[$key]['name'].''; + } + // email column links/icon + if ($caseRelationships[$key]['email']) { + $caseRelationships[$key]['email'] = ' + '; + } + // edit links + if ($hasAccessToAllCases) { + switch($caseRelationships[$key]['source']){ + case 'caseRel': + $caseRelationships[$key]['actions'] = + '
  
'; + break; + + case 'caseRoles': + $caseRelationships[$key]['actions'] = + '
'; + break; + } + } else { + $caseRelationships[$key]['actions'] = ''; + } + $idx++; + } + $iFilteredTotal = $iTotal = $params['total'] = count($allCaseRelationships); + $selectorElements = array('relation', 'name', 'phone', 'email', 'actions'); + + echo CRM_Utils_JSON::encodeDataTableSelector($caseRelationships, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + static function convertToCaseActivity() { + $params = array('caseID', 'activityID', 'contactID', 'newSubject', 'targetContactIds', 'mode'); + foreach ($params as $param) { + $vals[$param] = CRM_Utils_Array::value($param, $_POST); + } + + $retval = self::_convertToCaseActivity($vals); + + echo json_encode($retval); + CRM_Utils_System::civiExit(); + } + + static function _convertToCaseActivity($params) { + if (!$params['activityID'] || !$params['caseID']) { + return (array('error_msg' => 'required params missing.')); + } + + $otherActivity = new CRM_Activity_DAO_Activity(); + $otherActivity->id = $params['activityID']; + if (!$otherActivity->find(TRUE)) { + return (array('error_msg' => 'activity record is missing.')); + } + $actDateTime = CRM_Utils_Date::isoToMysql($otherActivity->activity_date_time); + + //create new activity record. + $mainActivity = new CRM_Activity_DAO_Activity(); + $mainActVals = array(); + CRM_Core_DAO::storeValues($otherActivity, $mainActVals); + + //get new activity subject. + if (!empty($params['newSubject'])) { + $mainActVals['subject'] = $params['newSubject']; + } + + $mainActivity->copyValues($mainActVals); + $mainActivity->id = NULL; + $mainActivity->activity_date_time = $actDateTime; + //make sure this is current revision. + $mainActivity->is_current_revision = TRUE; + //drop all relations. + $mainActivity->parent_id = $mainActivity->original_id = NULL; + + $mainActivity->save(); + $mainActivityId = $mainActivity->id; + CRM_Activity_BAO_Activity::logActivityAction($mainActivity); + $mainActivity->free(); + + /* Mark previous activity as deleted. If it was a non-case activity + * then just change the subject. + */ + + if (in_array($params['mode'], array( + 'move', 'file'))) { + $caseActivity = new CRM_Case_DAO_CaseActivity(); + $caseActivity->case_id = $params['caseID']; + $caseActivity->activity_id = $otherActivity->id; + if ($params['mode'] == 'move' || $caseActivity->find(TRUE)) { + $otherActivity->is_deleted = 1; + } + else { + $otherActivity->subject = ts('(Filed on case %1)', array( + 1 => $params['caseID'])) . ' ' . $otherActivity->subject; + } + $otherActivity->activity_date_time = $actDateTime; + $otherActivity->save(); + + $caseActivity->free(); + } + $otherActivity->free(); + + $targetContacts = array(); + if (!empty($params['targetContactIds'])) { + $targetContacts = array_unique(explode(',', $params['targetContactIds'])); + } + foreach ($targetContacts as $key => $value) { + $targ_params = array( + 'activity_id' => $mainActivityId, + 'target_contact_id' => $value, + ); + CRM_Activity_BAO_Activity::createActivityTarget($targ_params); + } + + // typically this will be empty, since assignees on another case may be completely different + $assigneeContacts = array(); + if (!empty($params['assigneeContactIds'])) { + $assigneeContacts = array_unique(explode(',', $params['assigneeContactIds'])); + } + foreach ($assigneeContacts as $key => $value) { + $assigneeParams = array( + 'activity_id' => $mainActivityId, + 'assignee_contact_id' => $value, + ); + CRM_Activity_BAO_Activity::createActivityAssignment($assigneeParams); + } + + //attach newly created activity to case. + $caseActivity = new CRM_Case_DAO_CaseActivity(); + $caseActivity->case_id = $params['caseID']; + $caseActivity->activity_id = $mainActivityId; + $caseActivity->save(); + $error_msg = $caseActivity->_lastError; + $caseActivity->free(); + + $params['mainActivityId'] = $mainActivityId; + CRM_Activity_BAO_Activity::copyExtendedActivityData($params); + + return (array('error_msg' => $error_msg, 'newId' => $mainActivity->id)); + } + + static function getContactActivity() { + $contactID = CRM_Utils_Type::escape($_POST['contact_id'], 'Integer'); + $context = CRM_Utils_Type::escape(CRM_Utils_Array::value('context', $_GET), 'String'); + + $sortMapper = array( + 0 => 'activity_type', 1 => 'subject', 2 => 'source_contact_name', + 3 => '', 4 => '', 5 => 'activity_date_time', 6 => 'status_id', + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $params = $_POST; + if ($sort && $sortOrder) { + $params['sortBy'] = $sort . ' ' . $sortOrder; + } + + $params['page'] = ($offset / $rowCount) + 1; + $params['rp'] = $rowCount; + + $params['contact_id'] = $contactID; + $params['context'] = $context; + + // get the contact activities + $activities = CRM_Activity_BAO_Activity::getContactActivitySelector($params); + + // store the activity filter preference CRM-11761 + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + if ($userID) { + $activityFilter = + array('activity_type_filter_id' => CRM_Utils_Array::value('activity_type_id', $params), + 'activity_type_exclude_filter_id' => CRM_Utils_Array::value('activity_type_exclude_id', $params)); + CRM_Core_BAO_Setting::setItem($activityFilter, + CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME, + 'activity_tab_filter', + NULL, + $userID, + $userID + ); + } + + $iFilteredTotal = $iTotal = $params['total']; + $selectorElements = array( + 'activity_type', 'subject', 'source_contact', + 'target_contact', 'assignee_contact', + 'activity_date', 'status', 'openstats','links', 'class', + ); + + echo CRM_Utils_JSON::encodeDataTableSelector($activities, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Activity/Page/Tab.php b/CRM/Activity/Page/Tab.php new file mode 100644 index 0000000000..a84e2eb43f --- /dev/null +++ b/CRM/Activity/Page/Tab.php @@ -0,0 +1,223 @@ +assign('admin', FALSE); + $this->assign('context', 'activity'); + + // also create the form element for the activity filter box + $controller = new CRM_Core_Controller_Simple('CRM_Activity_Form_ActivityFilter', + ts('Activity Filter'), NULL + ); + $controller->set('contactId', $this->_contactId); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + function edit() { + // used for ajax tabs + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $this->assign('context', $context); + + $this->_id = CRM_Utils_Request::retrieve('id', 'Integer', $this); + + $this->_caseId = CRM_Utils_Request::retrieve('caseid', 'Integer', $this); + + $activityTypeId = CRM_Utils_Request::retrieve('atype', 'Positive', $this); + + // Email and Create Letter activities use a different form class + $emailTypeValue = CRM_Core_OptionGroup::getValue('activity_type', + 'Email', + 'name' + ); + + $letterTypeValue = CRM_Core_OptionGroup::getValue('activity_type', + 'Print PDF Letter', + 'name' + ); + + + switch ($activityTypeId) { + case $emailTypeValue: + $wrapper = new CRM_Utils_Wrapper(); + $arguments = array('attachUpload' => 1); + return $wrapper->run('CRM_Contact_Form_Task_Email', ts('Email a Contact'), $arguments); + + case $letterTypeValue: + $wrapper = new CRM_Utils_Wrapper(); + $arguments = array('attachUpload' => 1); + return $wrapper->run('CRM_Contact_Form_Task_PDF', ts('Create PDF Letter'), $arguments); + + default: + $controller = new CRM_Core_Controller_Simple('CRM_Activity_Form_Activity', + ts('Contact Activities'), + $this->_action, + FALSE, FALSE, FALSE, TRUE + ); + } + + $controller->setEmbedded(TRUE); + + $controller->set('contactId', $this->_contactId); + $controller->set('atype', $activityTypeId); + $controller->set('id', $this->_id); + $controller->set('pid', $this->get('pid')); + $controller->set('action', $this->_action); + $controller->set('context', $context); + + $controller->process(); + $controller->run(); + } + + /** + * Heart of the viewing process. The runner gets all the meta data for + * the contact and calls the appropriate type of page to view. + * + * @return void + * @access public + * + */ + function preProcess() { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + //FIX ME: need to fix this conflict + $this->assign('contactID', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + // set page title + CRM_Contact_Page_View::setTitle($this->_contactId); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + + // also create the form element for the activity links box + $controller = new CRM_Core_Controller_Simple('CRM_Activity_Form_ActivityLinks', + ts('Activity Links'), NULL + ); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + function delete() { + $controller = new CRM_Core_Controller_Simple('CRM_Activity_Form_Activity', + ts('Activity Record'), + $this->_action + ); + $controller->set('id', $this->_id); + $controller->setEmbedded(TRUE); + $controller->process(); + $controller->run(); + } + + /** + * perform actions and display for activities. + * + * @return none + * + * @access public + */ + function run() { + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + $action = CRM_Utils_Request::retrieve('action', 'String', $this); + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + + //do check for view/edit operation. + if ($this->_id && + in_array($action, array(CRM_Core_Action::UPDATE, CRM_Core_Action::VIEW)) + ) { + if (!CRM_Activity_BAO_Activity::checkPermission($this->_id, $action)) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + } + + if ($context == 'standalone' || (!$contactId && ($action != CRM_Core_Action::DELETE) && !$this->_id)) { + $this->_action = CRM_Core_Action::ADD; + $this->assign('action', $this->_action); + } + else { + // we should call contact view, preprocess only for activity in contact summary + $this->preProcess(); + } + + // route behaviour of contact/view/activity based on action defined + if ($this->_action & + (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::VIEW) + ) { + $this->edit(); + $activityTypeId = CRM_Utils_Request::retrieve('atype', 'Positive', $this); + + // Email and Create Letter activities use a different form class + $emailTypeValue = CRM_Core_OptionGroup::getValue('activity_type', + 'Email', + 'name' + ); + + $letterTypeValue = CRM_Core_OptionGroup::getValue('activity_type', + 'Print PDF Letter', + 'name' + ); + + if (in_array($activityTypeId, array( + $emailTypeValue, $letterTypeValue))) { + return; + } + } + elseif ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::DETACH)) { + $this->delete(); + } + else { + $this->browse(); + } + + return parent::run(); + } +} + diff --git a/CRM/Activity/Page/UserDashboard.php b/CRM/Activity/Page/UserDashboard.php new file mode 100644 index 0000000000..745b5337bf --- /dev/null +++ b/CRM/Activity/Page/UserDashboard.php @@ -0,0 +1,76 @@ +setEmbedded(TRUE); + $controller->reset(); + $controller->set('context', 'user'); + $controller->set('cid', $this->_contactId); + $controller->set('status', array(1 => 'on')); + $controller->set('activity_role', 2); + $controller->set('activity_contact_name', 'd6'); + $controller->set('force', 1); + $controller->process(); + $controller->run(); + + return; + } + + /** + * This function is the main function that is called when the page + * loads, it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + parent::preProcess(); + $this->listActivities(); + } +} + diff --git a/CRM/Activity/Selector/Activity.php b/CRM/Activity/Selector/Activity.php new file mode 100644 index 0000000000..ff5c3c3d0c --- /dev/null +++ b/CRM/Activity/Selector/Activity.php @@ -0,0 +1,485 @@ +_contactId = $contactId; + $this->_permission = $permission; + $this->_admin = $admin; + $this->_context = $context; + $this->_activityTypeIDs = $activityTypeIDs; + + // get all enabled view componentc (check if case is enabled) + $this->_viewOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_view_options', TRUE, NULL, TRUE + ); + } + + /** + * This method returns the action links that are given for each search row. + * currently the action links added for each row are + * + * - View + * + * @param string $activityType type of activity + * + * @return array + * @access public + * + */ + public static function actionLinks($activityTypeId, + $sourceRecordId = NULL, + $accessMailingReport = FALSE, + $activityId = NULL, + $key = NULL, + $compContext = NULL) { + static $activityActTypes = NULL; + + $extraParams = ($key) ? "&key={$key}" : NULL; + if ($compContext) { + $extraParams .= "&compContext={$compContext}"; + } + + $showView = TRUE; + $showUpdate = $showDelete = FALSE; + $qsUpdate = NULL; + + if (!$activityActTypes) { + $activeActTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name', TRUE); + } + $activityTypeName = CRM_Utils_Array::value($activityTypeId, $activeActTypes); + + //CRM-7607 + //lets allow to have normal operation for only activity types. + //when activity type is disabled or no more exists give only delete. + switch ($activityTypeName) { + case 'Event Registration': + $url = 'civicrm/contact/view/participant'; + $qsView = "action=view&reset=1&id={$sourceRecordId}&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + break; + + case 'Contribution': + $url = 'civicrm/contact/view/contribution'; + $qsView = "action=view&reset=1&id={$sourceRecordId}&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + break; + + case 'Membership Signup': + case 'Membership Renewal': + case 'Change Membership Status': + case 'Change Membership Type': + $url = 'civicrm/contact/view/membership'; + $qsView = "action=view&reset=1&id={$sourceRecordId}&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + break; + + case 'Pledge Reminder': + case 'Pledge Acknowledgment': + $url = 'civicrm/contact/view/activity'; + $qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + break; + + case 'Email': + case 'Bulk Email': + $url = 'civicrm/activity/view'; + $delUrl = 'civicrm/activity'; + $qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + if ($activityTypeName == 'Email') { + $showDelete = TRUE; + } + break; + + case 'Inbound Email': + $url = 'civicrm/contact/view/activity'; + $qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + break; + + case 'Open Case': + case 'Change Case Type': + case 'Change Case Status': + case 'Change Case Start Date': + $showUpdate = $showDelete = FALSE; + $url = 'civicrm/activity'; + $qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + $qsUpdate = "atype={$activityTypeId}&action=update&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + break; + + default: + $url = 'civicrm/activity'; + $showView = $showDelete = $showUpdate = TRUE; + $qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + $qsUpdate = "atype={$activityTypeId}&action=update&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + + //when type is not available lets hide view and update. + if (empty($activityTypeName)) { + $showView = $showUpdate = FALSE; + } + break; + } + + $qsDelete = "atype={$activityTypeId}&action=delete&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}"; + + $actionLinks = array(); + + if ($showView) { + $actionLinks += array(CRM_Core_Action::VIEW => array('name' => ts('View'), + 'url' => $url, + 'qs' => $qsView, + 'title' => ts('View Activity'), + )); + } + + if ($showUpdate) { + $updateUrl = 'civicrm/activity/add'; + if ($activityTypeName == 'Email') { + $updateUrl = 'civicrm/activity/email/add'; + } + elseif ($activityTypeName == 'Print PDF Letter') { + $updateUrl = 'civicrm/activity/pdf/add'; + } + $actionLinks += array(CRM_Core_Action::UPDATE => array('name' => ts('Edit'), + 'url' => $updateUrl, + 'qs' => $qsUpdate, + 'title' => ts('Update Activity'), + )); + } + + if ( + $activityTypeName && + CRM_Case_BAO_Case::checkPermission($activityId, 'File On Case', $activityTypeId) + ) { + $actionLinks += array(CRM_Core_Action::ADD => array('name' => ts('File On Case'), + 'url' => '#', + 'extra' => 'onclick="javascript:fileOnCase( \'file\', \'%%id%%\' ); return false;"', + 'title' => ts('File On Case'), + )); + } + + if ($showDelete) { + if (!isset($delUrl) || !$delUrl) { + $delUrl = $url; + } + $actionLinks += array(CRM_Core_Action::DELETE => array('name' => ts('Delete'), + 'url' => $delUrl, + 'qs' => $qsDelete, + 'title' => ts('Delete Activity'), + )); + } + + if ($accessMailingReport) { + $actionLinks += array(CRM_Core_Action::BROWSE => array('name' => ts('Mailing Report'), + 'url' => 'civicrm/mailing/report', + 'qs' => "mid={$sourceRecordId}&reset=1&cid=%%cid%%&context=activitySelector", + 'title' => ts('View Mailing Report'), + )); + } + + return $actionLinks; + } + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['status'] = ts('Activities %%StatusMessage%%'); + $params['csvString'] = NULL; + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + function &getColumnHeaders($action = NULL, $output = NULL) { + if ($output == CRM_Core_Selector_Controller::EXPORT || $output == CRM_Core_Selector_Controller::SCREEN) { + $csvHeaders = array(ts('Activity Type'), ts('Description'), ts('Activity Date')); + foreach (self::_getColumnHeaders() as $column) { + if (array_key_exists('name', $column)) { + $csvHeaders[] = $column['name']; + } + } + return $csvHeaders; + } + else { + return self::_getColumnHeaders(); + } + } + + /** + * Returns total number of rows for the query. + * + * @param string $action - action being performed + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action, $case = NULL) { + $params = array( + 'contact_id' => $this->_contactId, + 'admin' => $this->_admin, + 'caseId' => $case, + 'context' => $this->_context, + 'activity_type_id' => $this->_activityTypeIDs, + 'offset' => 0, + 'rowCount' => 0, + 'sort' => NULL, + ); + return CRM_Activity_BAO_Activity::getActivitiesCount($params); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return int the total number of rows for this action + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL, $case = NULL) { + $params = array( + 'contact_id' => $this->_contactId, + 'admin' => $this->_admin, + 'caseId' => $case, + 'context' => $this->_context, + 'activity_type_id' => $this->_activityTypeIDs, + 'offset' => $offset, + 'rowCount' => $rowCount, + 'sort' => $sort, + ); + $config = CRM_Core_Config::singleton(); + $rows = CRM_Activity_BAO_Activity::getActivities($params); + + if (empty($rows)) { + return $rows; + } + + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + + $engagementLevels = CRM_Campaign_PseudoConstant::engagementLevel(); + + //CRM-4418 + $permissions = array($this->_permission); + if (CRM_Core_Permission::check('delete activities')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + foreach ($rows as $k => $row) { + $row = &$rows[$k]; + + // DRAFTING: provide a facility for db-stored strings + // localize the built-in activity names for display + // (these are not enums, so we can't use any automagic here) + switch ($row['activity_type']) { + case 'Meeting': + $row['activity_type'] = ts('Meeting'); + break; + + case 'Phone Call': + $row['activity_type'] = ts('Phone Call'); + break; + + case 'Email': + $row['activity_type'] = ts('Email'); + break; + + case 'SMS': + $row['activity_type'] = ts('SMS'); + break; + + case 'Event': + $row['activity_type'] = ts('Event'); + break; + } + + // add class to this row if overdue + if (CRM_Utils_Date::overdue(CRM_Utils_Array::value('activity_date_time', $row)) + && CRM_Utils_Array::value('status_id', $row) == 1 + ) { + $row['overdue'] = 1; + $row['class'] = 'status-overdue'; + } + else { + $row['overdue'] = 0; + $row['class'] = 'status-ontime'; + } + + $row['status'] = $row['status_id'] ? $activityStatus[$row['status_id']] : NULL; + + if ($engagementLevel = CRM_Utils_Array::value('engagement_level', $row)) { + $row['engagement_level'] = CRM_Utils_Array::value($engagementLevel, $engagementLevels, $engagementLevel); + } + + //CRM-3553 + $accessMailingReport = FALSE; + if (CRM_Utils_Array::value('mailingId', $row)) { + $accessMailingReport = TRUE; + } + + $actionLinks = $this->actionLinks(CRM_Utils_Array::value('activity_type_id', $row), + CRM_Utils_Array::value('source_record_id', $row), + $accessMailingReport, + CRM_Utils_Array::value('activity_id', $row), + $this->_key + ); + + $actionMask = array_sum(array_keys($actionLinks)) & $mask; + + if ($output != CRM_Core_Selector_Controller::EXPORT && $output != CRM_Core_Selector_Controller::SCREEN) { + $row['action'] = CRM_Core_Action::formLink($actionLinks, + $actionMask, + array( + 'id' => $row['activity_id'], + 'cid' => $this->_contactId, + 'cxt' => $this->_context, + 'caseid' => CRM_Utils_Array::value('case_id', $row), + ) + ); + } + + unset($row); + } + + return $rows; + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('CiviCRM Activity'); + } + + /** + * get colunmn headers for search selector + * + * + * @return array $_columnHeaders + * @access private + */ + private static function &_getColumnHeaders() { + if (!isset(self::$_columnHeaders)) { + self::$_columnHeaders = array( + array('name' => ts('Type'), + 'sort' => 'activity_type', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('name' => ts('Subject'), + 'sort' => 'subject', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('name' => ts('Added By'), + 'sort' => 'source_contact_name', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('name' => ts('With')), + array('name' => ts('Assigned')), + array( + 'name' => ts('Date'), + 'sort' => 'activity_date_time', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Status'), + 'sort' => 'status_id', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('desc' => ts('Actions')), + ); + } + + return self::$_columnHeaders; + } +} + diff --git a/CRM/Activity/Selector/Search.php b/CRM/Activity/Selector/Search.php new file mode 100644 index 0000000000..353c3bf26c --- /dev/null +++ b/CRM/Activity/Selector/Search.php @@ -0,0 +1,416 @@ +_queryParams = &$queryParams; + + $this->_single = $single; + $this->_limit = $limit; + $this->_context = $context; + $this->_compContext = $compContext; + + $this->_activityClause = $activityClause; + + // type of selector + $this->_action = $action; + $this->_query = new CRM_Contact_BAO_Query($this->_queryParams, + CRM_Activity_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_ACTIVITY, + FALSE + ), + NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_ACTIVITY + ); + $this->_query->_distinctComponentClause = '( civicrm_activity.id )'; + $this->_query->_groupByComponentClause = " GROUP BY civicrm_activity.id "; + //CRM_Core_Error::debug( $this->_query ); exit(); + } + //end of constructor + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['status'] = ts('Activities %%StatusMessage%%'); + $params['csvString'] = NULL; + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + //end of function + + /** + * Returns total number of rows for the query. + * + * @param + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action) { + return $this->_query->searchQuery(0, 0, NULL, + TRUE, FALSE, + FALSE, FALSE, + FALSE, + $this->_activityClause + ); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return array rows in the given offset and rowCount + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { + + $result = $this->_query->searchQuery($offset, $rowCount, $sort, + FALSE, FALSE, + FALSE, FALSE, + FALSE, + $this->_activityClause + ); + $rows = array(); + $mailingIDs = CRM_Mailing_BAO_Mailing::mailingACLIDs(); + $accessCiviMail = CRM_Core_Permission::check('access CiviMail'); + + //get all campaigns. + $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + + $engagementLevels = CRM_Campaign_PseudoConstant::engagementLevel(); + + while ($result->fetch()) { + $row = array(); + + // ignore rows where we dont have an activity id + if (empty($result->activity_id)) { + continue; + } + + // the columns we are interested in + foreach (self::$_properties as $property) { + if (isset($result->$property)) { + $row[$property] = $result->$property; + } + } + + $contactId = CRM_Utils_Array::value('contact_id', $row); + if (!$contactId) { + $contactId = CRM_Utils_Array::value('source_contact_id', $row); + } + + $row['target_contact_name'] = CRM_Activity_BAO_ActivityTarget::getTargetNames($row['activity_id']); + $row['assignee_contact_name'] = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($row['activity_id']); + + if (CRM_Utils_Array::value('source_contact_id', $row)) { + $row['source_contact_name'] = CRM_Contact_BAO_Contact::displayName($row['source_contact_id']); + } + if ($this->_context == 'search') { + $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->activity_id; + } + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type, FALSE, $result->contact_id + ); + $accessMailingReport = FALSE; + $activityType = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name', TRUE); + $activityTypeId = CRM_Utils_Array::key($row['activity_type'], $activityType); + if ($row['activity_is_test']) { + $row['activity_type'] = $row['activity_type'] . " (test)"; + } + $bulkActivityTypeID = CRM_Utils_Array::key('Bulk Email', $activityType); + $row['mailingId'] = ''; + if ( + $accessCiviMail && + ($mailingIDs === TRUE || in_array($result->source_record_id, $mailingIDs)) && + ($bulkActivityTypeID == $activityTypeId) + ) { + $row['mailingId'] = CRM_Utils_System::url('civicrm/mailing/report', + "mid={$result->source_record_id}&reset=1&cid={$result->source_contact_id}&context=activitySelector" + ); + $row['recipients'] = ts('(recipients)'); + $row['target_contact_name'] = ''; + $row['assignee_contact_name'] = ''; + $accessMailingReport = TRUE; + } + $activityActions = new CRM_Activity_Selector_Activity($result->contact_id, NULL); + $actionLinks = $activityActions->actionLinks($activityTypeId, + CRM_Utils_Array::value('source_record_id', $row), + $accessMailingReport, + CRM_Utils_Array::value('activity_id', $row), + $this->_key, + $this->_compContext + ); + $row['action'] = CRM_Core_Action::formLink($actionLinks, NULL, + array( + 'id' => $result->activity_id, + 'cid' => $contactId, + 'cxt' => $this->_context, + ) + ); + + //carry campaign to selector. + $row['campaign'] = CRM_Utils_Array::value($result->activity_campaign_id, $allCampaigns); + $row['campaign_id'] = $result->activity_campaign_id; + + if ($engagementLevel = CRM_Utils_Array::value('activity_engagement_level', $row)) { + $row['activity_engagement_level'] = CRM_Utils_Array::value($engagementLevel, + $engagementLevels, $engagementLevel + ); + } + + $rows[] = $row; + } + + return $rows; + } + + /** + * + * @return array $qill which contains an array of strings + * @access public + */ + public function getQILL() { + return $this->_query->qill(); + } + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + public function &getColumnHeaders($action = NULL, $output = NULL) { + if (!isset(self::$_columnHeaders)) { + self::$_columnHeaders = array( + array( + 'name' => ts('Type'), + 'sort' => 'activity_type_id', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Subject'), + 'sort' => 'subject', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Added By'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('name' => ts('With')), + array('name' => ts('Assigned')), + array( + 'name' => ts('Date'), + 'sort' => 'activity_date_time', + 'direction' => CRM_Utils_Sort::DESCENDING, + ), + array( + 'name' => ts('Status'), + 'sort' => 'status_id', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'desc' => ts('Actions'), + ), + ); + } + return self::$_columnHeaders; + } + + function alphabetQuery() { + return $this->_query->searchQuery(NULL, NULL, NULL, FALSE, FALSE, TRUE); + } + + function &getQuery() { + return $this->_query; + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('CiviCRM Activity Search'); + } +} +//end of class + diff --git a/CRM/Activity/StateMachine/Search.php b/CRM/Activity/StateMachine/Search.php new file mode 100644 index 0000000000..e1d54855cc --- /dev/null +++ b/CRM/Activity/StateMachine/Search.php @@ -0,0 +1,108 @@ +_pages = array(); + + $this->_pages['CRM_Activity_Form_Search'] = NULL; + list($task, $result) = $this->taskName($controller, 'Search'); + $this->_task = $task; + + if (is_array($task)) { + foreach ($task as $t) { + $this->_pages[$t] = NULL; + } + } + else { + $this->_pages[$task] = NULL; + } + + $this->addSequentialPages($this->_pages, $action); + } + + /** + * Determine the form name based on the action. This allows us + * to avoid using conditional state machine, much more efficient + * and simpler + * + * @param CRM_Core_Controller $controller the controller object + * + * @return string the name of the form that will handle the task + * @access protected + */ + function taskName($controller, $formName = 'Search') { + // total hack, check POST vars and then session to determine stuff + // fix value if print button is pressed + if (CRM_Utils_Array::value('_qf_' . $formName . '_next_print', $_POST)) { + $value = CRM_Activity_Task::PRINT_ACTIVITIES; + } + else { + $value = CRM_Utils_Array::value('task', $_POST); + } + if (!isset($value)) { + $value = $this->_controller->get('task'); + } + $this->_controller->set('task', $value); + return CRM_Activity_Task::getTask($value); + } + + /** + * return the form name of the task + * + * @return string + * @access public + */ + function getTaskFormName() { + return CRM_Utils_String::getClassName($this->_task); + } + + function shouldReset() { + return FALSE; + } +} + diff --git a/CRM/Activity/Task.php b/CRM/Activity/Task.php new file mode 100644 index 0000000000..09745c23d3 --- /dev/null +++ b/CRM/Activity/Task.php @@ -0,0 +1,198 @@ + array('title' => ts('Delete Activities'), + 'class' => 'CRM_Activity_Form_Task_Delete', + 'result' => FALSE, + ), + 2 => array('title' => ts('Print Activities'), + 'class' => 'CRM_Activity_Form_Task_Print', + 'result' => FALSE, + ), + 3 => array('title' => ts('Export Activities'), + 'class' => array( + 'CRM_Export_Form_Select', + 'CRM_Export_Form_Map', + ), + 'result' => FALSE, + ), + 4 => array('title' => ts('Batch Update Activities Via Profile'), + 'class' => array( + 'CRM_Activity_Form_Task_PickProfile', + 'CRM_Activity_Form_Task_Batch', + ), + 'result' => FALSE, + ), + 5 => array('title' => ts('Send Email to Contacts'), + 'class' => array( + 'CRM_Activity_Form_Task_PickOption', + 'CRM_Activity_Form_Task_Email', + ), + 'result' => FALSE, + ), + 6 => array('title' => ts('Send Reply SMS To Contacts'), + 'class' => 'CRM_Activity_Form_Task_SMS', + 'result' => FALSE, + ), + ); + + $config = CRM_Core_Config::singleton(); + if (in_array('CiviCase', $config->enableComponents)) { + self::$_tasks[6] = array('title' => ts('File on Case'), + 'class' => 'CRM_Activity_Form_Task_FileOnCase', + 'result' => FALSE, + ); + } + + //CRM-4418, check for delete + if (!CRM_Core_Permission::check('delete activities')) { + unset(self::$_tasks[1]); + } + } + CRM_Utils_Hook::searchTasks('activity', self::$_tasks); + asort(self::$_tasks); + return self::$_tasks; + } + + /** + * These tasks are the core set of task titles + * on activity + * + * @return array the set of task titles + * @static + * @access public + */ + static function &taskTitles() { + self::tasks(); + $titles = array(); + foreach (self::$_tasks as $id => $value) { + // skip Print Activity task + if ($id != 2) { + $titles[$id] = $value['title']; + } + } + return $titles; + } + + /** + * show tasks selectively based on the permission level + * of the user + * + * @param int $permission + * + * @return array set of tasks that are valid for the user + * @access public + */ + static function &permissionedTaskTitles($permission) { + $tasks = array(); + if ($permission == CRM_Core_Permission::EDIT) { + $tasks = self::taskTitles(); + } + else { + $tasks = array( + 3 => self::$_tasks[3]['title'], + ); + + //CRM-4418, + if (CRM_Core_Permission::check('delete activities')) { + $tasks[1] = self::$_tasks[1]['title']; + } + } + return $tasks; + } + + /** + * These tasks are the core set of tasks that the user can perform + * on activity + * + * @param int $value + * + * @return array the set of tasks for a group of activity + * @static + * @access public + */ + static function getTask($value) { + self::tasks(); + if (!$value || !CRM_Utils_Array::value($value, self::$_tasks)) { + // make the print task by default + $value = 2; + } + return array( + self::$_tasks[$value]['class'], + self::$_tasks[$value]['result'], + ); + } +} + diff --git a/CRM/Admin/Form.php b/CRM/Admin/Form.php new file mode 100644 index 0000000000..8e89aad39c --- /dev/null +++ b/CRM/Admin/Form.php @@ -0,0 +1,143 @@ +_id = $this->get('id'); + $this->_BAOName = $this->get('BAOName'); + $this->_values = array(); + if (isset($this->_id)) { + $params = array('id' => $this->_id); + // this is needed if the form is outside the CRM name space + require_once (str_replace('_', DIRECTORY_SEPARATOR, $this->_BAOName) . ".php"); + eval($this->_BAOName . '::retrieve( $params, $this->_values );'); + } + } + + /** + * This function sets the default values for the form. MobileProvider that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if (isset($this->_id) && empty($this->_values)) { + $this->_values = array(); + $params = array('id' => $this->_id); + require_once (str_replace('_', DIRECTORY_SEPARATOR, $this->_BAOName) . ".php"); + eval($this->_BAOName . '::retrieve( $params, $this->_values );'); + } + $defaults = $this->_values; + + if ($this->_action == CRM_Core_Action::DELETE && + isset($defaults['name']) + ) { + $this->assign('delName', $defaults['name']); + } + + // its ok if there is no element called is_active + $defaults['is_active'] = ($this->_id) ? CRM_Utils_Array::value('is_active', $defaults) : 1; + if (CRM_Utils_Array::value('parent_id', $defaults)) { + $this->assign('is_parent', TRUE); + } + return $defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + if ($this->_action & CRM_Core_Action::DELETE) { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + else { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + } +} + diff --git a/CRM/Admin/Form/CMSUser.php b/CRM/Admin/Form/CMSUser.php new file mode 100644 index 0000000000..c4588344bb --- /dev/null +++ b/CRM/Admin/Form/CMSUser.php @@ -0,0 +1,75 @@ +addButtons(array( + array( + 'type' => 'next', + 'name' => ts('OK'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Core_BAO_CMSUser::synchronize(); + } +} + diff --git a/CRM/Admin/Form/ContactType.php b/CRM/Admin/Form/ContactType.php new file mode 100644 index 0000000000..48591e8b23 --- /dev/null +++ b/CRM/Admin/Form/ContactType.php @@ -0,0 +1,154 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', 'label', ts('Name'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_ContactType', 'label'), + TRUE + ); + $contactType = $this->add('select', 'parent_id', ts('Basic Contact Type'), + CRM_Contact_BAO_ContactType::basicTypePairs(FALSE, 'id') + ); + $enabled = $this->add('checkbox', 'is_active', ts('Enabled?')); + if ($this->_action & CRM_Core_Action::UPDATE) { + $contactType->freeze(); + // We'll display actual "name" for built-in types (for reference) when editing their label / image_URL + $contactTypeName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_ContactType', $this->_id, 'name'); + $this->assign('contactTypeName', $contactTypeName); + + $this->_parentId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_ContactType', $this->_id, 'parent_id'); + // Freeze Enabled field for built-in contact types (parent_id is NULL for these) + if (is_null($this->_parentId)) { + $enabled->freeze(); + } + } + $this->addElement('text', 'image_URL', ts('Image URL')); + $this->add('text', 'description', ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_ContactType', 'description') + ); + + $this->assign('cid', $this->_id); + $this->addFormRule(array('CRM_Admin_Form_ContactType', 'formRule'), $this); + } + + /** + * global form rule + * + * @param array $fields the input form values + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + + $errors = array(); + + if ($self->_id) { + $contactName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_ContactType', $self->_id, 'name'); + } + else { + $contactName = ucfirst(CRM_Utils_String::munge($fields['label'])); + } + + if (!CRM_Core_DAO::objectExists($contactName, 'CRM_Contact_DAO_ContactType', $self->_id)) { + $errors['label'] = ts('This contact type name already exists in database. Contact type names must be unique.'); + } + + $reservedKeyWords = CRM_Core_SelectValues::customGroupExtends(); + //restrict "name" from being a reserved keyword when a new contact subtype is created + if (!$self->_id && in_array($contactName, array_keys($reservedKeyWords))) { + $errors['label'] = ts('Contact type names should not use reserved keywords.'); + } + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Utils_System::flushCache(); + + if ($this->_action & CRM_Core_Action::DELETE) { + $isDelete = CRM_Contact_BAO_ContactType::del($this->_id); + if ($isDelete) { + CRM_Core_Session::setStatus(ts('Selected contact type has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + CRM_Core_Session::setStatus(ts("Selected contact type can not be deleted. Make sure contact type doesn't have any associated custom data or group."), ts('Sorry'), 'error'); + } + return; + } + // store the submitted values in an array + $params = $this->exportValues(); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $params['id'] = $this->_id; + // Force Enabled = true for built-in contact types to fix problems caused by CRM-6471 (parent_id is NULL for these types) + if (is_null($this->_parentId)) { + $params['is_active'] = 1; + } + } + if ($this->_action & CRM_Core_Action::ADD) { + $params['name'] = ucfirst(CRM_Utils_String::munge($params['label'])); + } + $contactType = CRM_Contact_BAO_ContactType::add($params); + CRM_Core_Session::setStatus(ts("The Contact Type '%1' has been saved.", + array(1 => $contactType->label) + ), ts('Saved'), 'success'); + } +} + diff --git a/CRM/Admin/Form/Extensions.php b/CRM/Admin/Form/Extensions.php new file mode 100644 index 0000000000..2ff6340e91 --- /dev/null +++ b/CRM/Admin/Form/Extensions.php @@ -0,0 +1,222 @@ +_key = CRM_Utils_Request::retrieve('key', 'String', + $this, FALSE, 0 + ); + + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1&action=browse'); + $session->pushUserContext($url); + $this->assign('id', $this->_id); + $this->assign('key', $this->_key); + + + switch ($this->_action) { + case CRM_Core_Action::ADD: + case CRM_Core_Action::DELETE: + case CRM_Core_Action::ENABLE: + case CRM_Core_Action::DISABLE: + $info = CRM_Extension_System::singleton()->getMapper()->keyToInfo($this->_key); + $extInfo = CRM_Admin_Page_Extensions::createExtendedInfo($info); + $this->assign('extension', $extInfo); + break; + + case CRM_Core_Action::UPDATE: + if (! CRM_Extension_System::singleton()->getBrowser()->isEnabled()) { + CRM_Core_Error::fatal(ts('The system administrator has disabled this feature.')); + } + $info = CRM_Extension_System::singleton()->getBrowser()->getExtension($this->_key); + $extInfo = CRM_Admin_Page_Extensions::createExtendedInfo($info); + $this->assign('extension', $extInfo); + break; + + default: + CRM_Core_Error::fatal(ts('Unsupported action')); + } + + } + + /** + * This function sets the default values for the form. + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + switch ($this->_action) { + case CRM_Core_Action::ADD: + $buttonName = ts('Install'); + $title = ts('Install Extension'); + break; + + case CRM_Core_Action::UPDATE: + $buttonName = ts('Download and Install'); + $title = ts('Download and Install Extension'); + break; + + case CRM_Core_Action::DELETE: + $buttonName = ts('Uninstall'); + $title = ts('Uninstall Extension'); + break; + + case CRM_Core_Action::ENABLE: + $buttonName = ts('Enable'); + $title = ts('Enable Extension'); + break; + + case CRM_Core_Action::DISABLE: + $buttonName = 'Disable'; + $title = ts('Disable Extension'); + break; + } + + $this->assign('title', $title); + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => $buttonName, + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $self this object. + * + * @return true if no errors, else an array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + $errors = array(); + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Utils_System::flushCache(); + + if ($this->_action & CRM_Core_Action::DELETE) { + try { + CRM_Extension_System::singleton()->getManager()->uninstall(array($this->_key)); + CRM_Core_Session::setStatus("", ts('Extension Uninstalled'), "success"); + } catch (CRM_Extension_Exception_DependencyException $e) { + // currently only thrown for payment-processor dependencies + CRM_Core_Session::setStatus(ts('Cannot uninstall this extension - there is at least one payment processor using the payment processor type provided by it.'), ts('Uninstall Error'), 'error'); + } + } + + if ($this->_action & CRM_Core_Action::ADD) { + CRM_Extension_System::singleton()->getManager()->install(array($this->_key)); + CRM_Core_Session::setStatus("", ts('Extension Installed'), "success"); + } + + if ($this->_action & CRM_Core_Action::ENABLE) { + CRM_Extension_System::singleton()->getManager()->enable(array($this->_key)); + CRM_Core_Session::setStatus("", ts('Extension Enabled'), "success"); + } + + if ($this->_action & CRM_Core_Action::DISABLE) { + CRM_Extension_System::singleton()->getManager()->disable(array($this->_key)); + CRM_Core_Session::setStatus("", ts('Extension Disabled'), "success"); + } + + if ($this->_action & CRM_Core_Action::UPDATE) { + $result = civicrm_api('Extension', 'download', array( + 'version' => 3, + 'key' => $this->_key, + )); + if (! CRM_Utils_Array::value('is_error', $result, FALSE)) { + CRM_Core_Session::setStatus("", ts('Extension Upgraded'), "success"); + } else { + CRM_Core_Session::setStatus($result['error_message'], ts('Extension Upgrade Failed'), "error"); + } + } + + CRM_Utils_System::redirect( + CRM_Utils_System::url( + 'civicrm/admin/extensions', + 'reset=1&action=browse' + ) + ); + } +} + diff --git a/CRM/Admin/Form/Job.php b/CRM/Admin/Form/Job.php new file mode 100644 index 0000000000..ddd4b2bf25 --- /dev/null +++ b/CRM/Admin/Form/Job.php @@ -0,0 +1,207 @@ +_id) { + $refreshURL = CRM_Utils_System::url('civicrm/admin/job', + "reset=1&action=update&id={$this->_id}", + FALSE, NULL, FALSE + ); + } + else { + $refreshURL = CRM_Utils_System::url('civicrm/admin/job', + "reset=1&action=add", + FALSE, NULL, FALSE + ); + } + + $this->assign('refreshURL', $refreshURL); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm($check = FALSE) { + parent::buildQuickForm(); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_Job'); + + $this->add('text', 'name', ts('Name'), + $attributes['name'], TRUE + ); + + $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array('CRM_Core_DAO_Job', $this->_id)); + + $this->add('text', 'description', ts('Description'), + $attributes['description'] + ); + + $this->add('text', 'api_entity', ts('API Call Entity'), + $attributes['api_entity'], TRUE + ); + + $this->add('text', 'api_action', ts('API Call Action'), + $attributes['api_action'], TRUE + ); + + $this->add('select', 'run_frequency', ts('Run frequency'), + array('Daily' => ts('Daily'), 'Hourly' => ts('Hourly'), 'Always' => ts('Every time cron job is run')) + ); + + + $this->add('textarea', 'parameters', ts('Command parameters'), + "cols=50 rows=6" + ); + + // is this job active ? + $this->add('checkbox', 'is_active', ts('Is this Scheduled Job active?')); + + $this->addFormRule(array('CRM_Admin_Form_Job', 'formRule')); + } + + static function formRule($fields) { + + $errors = array(); + + require_once 'api/api.php'; + + $apiRequest = array(); + $apiRequest['entity'] = CRM_Utils_String::munge($fields['api_entity']); + $apiRequest['action'] = CRM_Utils_String::munge($fields['api_action']); + $apiRequest['version'] = 3; + $apiRequest += _civicrm_api_resolve($apiRequest); // look up function, file, is_generic + + if( !$apiRequest['function'] ) { + $errors['api_action'] = ts('Given API command is not defined.'); + } + + if (!empty($errors)) { + return $errors; + } + + return empty($errors) ? TRUE : $errors; + } + + function setDefaultValues() { + $defaults = array(); + + if (!$this->_id) { + $defaults['is_active'] = $defaults['is_default'] = 1; + return $defaults; + } + $domainID = CRM_Core_Config::domainID(); + + $dao = new CRM_Core_DAO_Job(); + $dao->id = $this->_id; + $dao->domain_id = $domainID; + if (!$dao->find(TRUE)) { + return $defaults; + } + + CRM_Core_DAO::storeValues($dao, $defaults); + + // CRM-10708 + // job entity thats shipped with core is all lower case. + // this makes sure camel casing is followed for proper working of default population. + if (CRM_Utils_Array::value('api_entity', $defaults)) { + $defaults['api_entity'] = ucfirst($defaults['api_entity']); + } + + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + + CRM_Utils_System::flushCache('CRM_Core_DAO_Job'); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_BAO_Job::del($this->_id); + CRM_Core_Session::setStatus("", ts('Scheduled Job Deleted.'), "success"); + return; + } + + $values = $this->controller->exportValues($this->_name); + $domainID = CRM_Core_Config::domainID(); + + $dao = new CRM_Core_DAO_Job(); + + $dao->id = $this->_id; + $dao->domain_id = $domainID; + $dao->run_frequency = $values['run_frequency']; + $dao->parameters = $values['parameters']; + $dao->name = $values['name']; + $dao->api_entity = $values['api_entity']; + $dao->api_action = $values['api_action']; + $dao->description = $values['description']; + $dao->is_active = CRM_Utils_Array::value('is_active', $values, 0); + + $dao->save(); + + // CRM-11143 - Give warning message if update_greetings is Enabled (is_active) since it generally should not be run automatically via execute action or runjobs url. + if ($values['api_action'] == 'update_greeting' && CRM_Utils_Array::value('is_active', $values) == 1) { + // pass "wiki" as 6th param to docURL2 if you are linking to a page in wiki.civicrm.org + $docLink = CRM_Utils_System::docURL2("Managing Scheduled Jobs", NULL, NULL, NULL, NULL, "wiki"); + $msg = ts('The update greeting job can be very resource intensive and is typically not necessary to run on a regular basis. If you do choose to enable the job, we recommend you do not run it with the force=1 option, which would rebuild greetings on all records. Leaving that option absent, or setting it to force=0, will only rebuild greetings for contacts that do not currently have a value stored. %1', array(1 => $docLink)); + CRM_Core_Session::setStatus($msg, ts('Warning: Update Greeting job enabled'), 'alert'); + } + + + } + //end of function +} + diff --git a/CRM/Admin/Form/LabelFormats.php b/CRM/Admin/Form/LabelFormats.php new file mode 100644 index 0000000000..328d5315f0 --- /dev/null +++ b/CRM/Admin/Form/LabelFormats.php @@ -0,0 +1,209 @@ +_action & (CRM_Core_Action::DELETE | CRM_Core_Action::COPY)) { + $formatName = CRM_Core_BAO_LabelFormat::getFieldValue('CRM_Core_BAO_LabelFormat', $this->_id, 'label'); + $this->assign('formatName', $formatName); + return; + } + + $disabled = array(); + $required = TRUE; + $is_reserved = $this->_id ? CRM_Core_BAO_LabelFormat::getFieldValue('CRM_Core_BAO_LabelFormat', $this->_id, 'is_reserved') : FALSE; + if ($is_reserved) { + $disabled['disabled'] = 'disabled'; + $required = FALSE; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_BAO_LabelFormat'); + $this->add('text', 'label', ts('Name'), $attributes['label'] + $disabled, $required); + $this->add('text', 'description', ts('Description'), array('size' => CRM_Utils_Type::HUGE)); + $this->add('checkbox', 'is_default', ts('Is this Label Format the default?')); + $this->add('select', 'paper_size', ts('Sheet Size'), + array( + 0 => ts('- default -')) + CRM_Core_BAO_PaperSize::getList(TRUE), FALSE, + array( + 'onChange' => "selectPaper( this.value );") + $disabled + ); + $this->add('static', 'paper_dimensions', NULL, ts('Sheet Size (w x h)')); + $this->add('select', 'orientation', ts('Orientation'), CRM_Core_BAO_LabelFormat::getPageOrientations(), FALSE, + array( + 'onChange' => "updatePaperDimensions();") + $disabled + ); + $this->add('select', 'font_name', ts('Font Name'), CRM_Core_BAO_LabelFormat::getFontNames()); + $this->add('select', 'font_size', ts('Font Size'), CRM_Core_BAO_LabelFormat::getFontSizes()); + $this->add('static', 'font_style', ts('Font Style')); + $this->add('checkbox', 'bold', ts('Bold')); + $this->add('checkbox', 'italic', ts('Italic')); + $this->add('select', 'metric', ts('Unit of Measure'), CRM_Core_BAO_LabelFormat::getUnits(), FALSE, + array('onChange' => "selectMetric( this.value );") + ); + $this->add('text', 'width', ts('Label Width'), array('size' => 8, 'maxlength' => 8) + $disabled, $required); + $this->add('text', 'height', ts('Label Height'), array('size' => 8, 'maxlength' => 8) + $disabled, $required); + $this->add('text', 'NX', ts('Labels Per Row'), array('size' => 3, 'maxlength' => 3) + $disabled, $required); + $this->add('text', 'NY', ts('Labels Per Column'), array('size' => 3, 'maxlength' => 3) + $disabled, $required); + $this->add('text', 'tMargin', ts('Top Margin'), array('size' => 8, 'maxlength' => 8) + $disabled, $required); + $this->add('text', 'lMargin', ts('Left Margin'), array('size' => 8, 'maxlength' => 8) + $disabled, $required); + $this->add('text', 'SpaceX', ts('Horizontal Spacing'), array('size' => 8, 'maxlength' => 8) + $disabled, $required); + $this->add('text', 'SpaceY', ts('Vertical Spacing'), array('size' => 8, 'maxlength' => 8) + $disabled, $required); + $this->add('text', 'lPadding', ts('Left Padding'), array('size' => 8, 'maxlength' => 8), $required); + $this->add('text', 'tPadding', ts('Top Padding'), array('size' => 8, 'maxlength' => 8), $required); + $this->add('text', 'weight', ts('Weight'), CRM_Core_DAO::getAttribute('CRM_Core_BAO_LabelFormat', 'weight'), TRUE); + + $this->addRule('label', ts('Name already exists in Database.'), 'objectExists', array('CRM_Core_BAO_LabelFormat', $this->_id)); + $this->addRule('NX', ts('Must be an integer'), 'integer'); + $this->addRule('NY', ts('Must be an integer'), 'integer'); + $this->addRule('tMargin', ts('Must be numeric'), 'numeric'); + $this->addRule('lMargin', ts('Must be numeric'), 'numeric'); + $this->addRule('SpaceX', ts('Must be numeric'), 'numeric'); + $this->addRule('SpaceY', ts('Must be numeric'), 'numeric'); + $this->addRule('lPadding', ts('Must be numeric'), 'numeric'); + $this->addRule('tPadding', ts('Must be numeric'), 'numeric'); + $this->addRule('width', ts('Must be numeric'), 'numeric'); + $this->addRule('height', ts('Must be numeric'), 'numeric'); + $this->addRule('weight', ts('Weight must be integer'), 'integer'); + } + + function setDefaultValues() { + if ($this->_action & CRM_Core_Action::ADD) { + $defaults['weight'] = CRM_Utils_Array::value('weight', CRM_Core_BAO_LabelFormat::getDefaultValues(), 0); + } + else { + $defaults = $this->_values; + // Convert field names that are illegal PHP/SMARTY variable names + $defaults['paper_size'] = $defaults['paper-size']; + unset($defaults['paper-size']); + $defaults['font_name'] = $defaults['font-name']; + unset($defaults['font-name']); + $defaults['font_size'] = $defaults['font-size']; + unset($defaults['font-size']); + + $defaults['bold'] = (stripos($defaults['font-style'], 'B') !== FALSE); + $defaults['italic'] = (stripos($defaults['font-style'], 'I') !== FALSE); + unset($defaults['font-style']); + } + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + // delete Label Format + CRM_Core_BAO_LabelFormat::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected Label Format has been deleted.'), ts('Record Deleted'), 'success'); + return; + } + if ($this->_action & CRM_Core_Action::COPY) { + // make a copy of the Label Format + $labelFormat = CRM_Core_BAO_LabelFormat::getById($this->_id); + $list = CRM_Core_BAO_LabelFormat::getList(TRUE); + $count = 1; + $prefix = ts('Copy of '); + while (in_array($prefix . $labelFormat['label'], $list)) { + $prefix = ts('Copy') . ' (' . ++$count . ') ' . ts('of '); + } + $labelFormat['label'] = $prefix . $labelFormat['label']; + $labelFormat['grouping'] = CRM_Core_BAO_LabelFormat::customGroupName(); + $labelFormat['is_default'] = 0; + $labelFormat['is_reserved'] = 0; + $bao = new CRM_Core_BAO_LabelFormat(); + $bao->saveLabelFormat($labelFormat); + CRM_Core_Session::setStatus($labelFormat['label'] . ts(' has been created.'), ts('Saved'), 'success'); + return; + } + + $values = $this->controller->exportValues($this->getName()); + $values['is_default'] = isset($values['is_default']); + + // Restore field names that were converted because they are illegal PHP/SMARTY variable names + if (isset($values['paper_size'])) { + $values['paper-size'] = $values['paper_size']; + unset($values['paper_size']); + } + if (isset($values['font_name'])) { + $values['font-name'] = $values['font_name']; + unset($values['font_name']); + } + if (isset($values['font_size'])) { + $values['font-size'] = $values['font_size']; + unset($values['font_size']); + } + + $style = ''; + if (isset($values['bold'])) { + $style .= 'B'; + } + if (isset($values['italic'])) { + $style .= 'I'; + } + $values['font-style'] = $style; + + $bao = new CRM_Core_BAO_LabelFormat(); + $bao->saveLabelFormat($values, $this->_id); + + $status = ts('Your new Label Format titled %1 has been saved.', array(1 => $values['label'])); + if ($this->_action & CRM_Core_Action::UPDATE) { + $status = ts('Your Label Format titled %1 has been updated.', array(1 => $values['label'])); + } + CRM_Core_Session::setStatus($status, ts('Saved'), 'success'); + } +} diff --git a/CRM/Admin/Form/LocationType.php b/CRM/Admin/Form/LocationType.php new file mode 100644 index 0000000000..3428be3cc2 --- /dev/null +++ b/CRM/Admin/Form/LocationType.php @@ -0,0 +1,130 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', + 'name', + ts('Name'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_LocationType', 'name'), + TRUE + ); + $this->addRule('name', + ts('Name already exists in Database.'), + 'objectExists', + array('CRM_Core_DAO_LocationType', $this->_id) + ); + $this->addRule('name', + ts('Name can only consist of alpha-numeric characters'), + 'variable' + ); + + $this->add('text', 'display_name', ts('Display Name'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_LocationType', 'display_name')); + $this->add('text', 'vcard_name', ts('vCard Name'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_LocationType', 'vcard_name')); + + $this->add('text', 'description', ts('Description'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_LocationType', 'description')); + + $this->add('checkbox', 'is_active', ts('Enabled?')); + $this->add('checkbox', 'is_default', ts('Default?')); + if ($this->_action == CRM_Core_Action::UPDATE && CRM_Core_DAO::getFieldValue('CRM_Core_DAO_LocationType', $this->_id, 'is_reserved')) { + $this->freeze(array('name', 'description', 'is_active')); + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Utils_System::flushCache('CRM_Core_DAO_LocationType'); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_BAO_LocationType::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected Location type has been deleted.'), ts('Record Deleted'), 'success'); + return; + } + + // store the submitted values in an array + $params = $this->exportValues(); + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE); + + // action is taken depending upon the mode + $locationType = new CRM_Core_DAO_LocationType(); + $locationType->name = $params['name']; + $locationType->display_name = $params['display_name']; + $locationType->vcard_name = $params['vcard_name']; + $locationType->description = $params['description']; + $locationType->is_active = $params['is_active']; + $locationType->is_default = $params['is_default']; + + if ($params['is_default']) { + $query = "UPDATE civicrm_location_type SET is_default = 0"; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + + if ($this->_action & CRM_Core_Action::UPDATE) { + $locationType->id = $this->_id; + } + + $locationType->save(); + + CRM_Core_Session::setStatus(ts("The location type '%1' has been saved.", + array(1 => $locationType->name) + ), ts('Saved'), 'success'); + } +} diff --git a/CRM/Admin/Form/MailSettings.php b/CRM/Admin/Form/MailSettings.php new file mode 100644 index 0000000000..3973a96c0d --- /dev/null +++ b/CRM/Admin/Form/MailSettings.php @@ -0,0 +1,186 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + + $this->applyFilter('__ALL__', 'trim'); + + //get the attributes. + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_MailSettings'); + + //build setting form + $this->add('text', 'name', ts('Name'), $attributes['name'], TRUE); + + $this->add('text', 'domain', ts('Email Domain'), $attributes['domain'], TRUE); + $this->addRule('domain', ts('Email domain must use a valid internet domain format (e.g. \'example.org\').'), 'domain'); + + $this->add('text', 'localpart', ts('Localpart'), $attributes['localpart']); + + $this->add('text', 'return_path', ts('Return-Path'), $attributes['return_path']); + $this->addRule('return_path', ts('Return-Path must use a valid email address format.'), 'email'); + + $this->add('select', 'protocol', + ts('Protocol'), + array('' => ts('- select -')) + CRM_Core_PseudoConstant::mailProtocol(), + TRUE + ); + + $this->add('text', 'server', ts('Server'), $attributes['server']); + + $this->add('text', 'username', ts('Username'), array('autocomplete' => 'off')); + + $this->add('password', 'password', ts('Password'), array('autocomplete' => 'off')); + + $this->add('text', 'source', ts('Source'), $attributes['source']); + + $this->add('checkbox', 'is_ssl', ts('Use SSL?')); + + $usedfor = array(1 => ts('Bounce Processing'), + 0 => ts('Email-to-Activity Processing'), + ); + $this->add('select', 'is_default', ts('Used For?'), $usedfor); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Admin_Form_MailSettings', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + $errors = array(); + // Check for default from email address and organization (domain) name. Force them to change it. + if ($fields['domain'] == 'EXAMPLE.ORG') { + $errors['domain'] = ts('Please enter a valid domain for this mailbox account (the part after @).'); + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_BAO_MailSettings::deleteMailSettings($this->_id); + CRM_Core_Session::setStatus("", ts('Mail Setting Deleted.'), "success"); + return; + } + + //get the submitted form values. + $formValues = $this->controller->exportValues($this->_name); + + //form fields. + $fields = array( + 'name', + 'domain', + 'localpart', + 'server', + 'return_path', + 'protocol', + 'port', + 'username', + 'password', + 'source', + 'is_ssl', + 'is_default', + ); + + $params = array(); + foreach ($fields as $f) { + if (in_array($f, array( + 'is_default', 'is_ssl'))) { + $params[$f] = CRM_Utils_Array::value($f, $formValues, FALSE); + } + else { + $params[$f] = CRM_Utils_Array::value($f, $formValues); + } + } + + $params['domain_id'] = CRM_Core_Config::domainID(); + + // assign id only in update mode + $status = ts('Your New Email Settings have been saved.'); + if ($this->_action & CRM_Core_Action::UPDATE) { + $params['id'] = $this->_id; + $status = ts('Your Email Settings have been updated.'); + } + + $mailSettings = CRM_Core_BAO_MailSettings::create($params); + + if ($mailSettings->id) { + CRM_Core_Session::setStatus($status, ts("Saved"), "success"); + } + else { + CRM_Core_Session::setStatus("", ts('Changes Not Saved.'), "info"); + } + } +} + diff --git a/CRM/Admin/Form/Mapping.php b/CRM/Admin/Form/Mapping.php new file mode 100644 index 0000000000..9fe11f20e5 --- /dev/null +++ b/CRM/Admin/Form/Mapping.php @@ -0,0 +1,112 @@ +id = $this->_id; + $mapping->find(TRUE); + $this->assign('mappingName', $mapping->name); + } + + public function buildQuickForm() { + parent::buildQuickForm(); + if ($this->_action == CRM_Core_Action::DELETE) { + return; + } + else { + $this->applyFilter('__ALL__', 'trim'); + + $this->add('text', 'name', ts('Name'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Mapping', 'name'), TRUE + ); + $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array('CRM_Core_DAO_Mapping', $this->_id)); + + $this->addElement('text', 'description', ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Mapping', 'description') + ); + + $mappingType = $this->addElement('select', 'mapping_type_id', ts('Mapping Type'), CRM_Core_PseudoConstant::mappingTypes()); + + if ($this->_action == CRM_Core_Action::UPDATE) { + $mappingType->freeze(); + } + } + } + + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->exportValues(); + + if ($this->_action == CRM_Core_Action::DELETE) { + if ($this->_id) { + CRM_Core_BAO_Mapping::del($this->_id); + } + } + else { + if ($this->_id) { + $params['id'] = $this->_id; + } + + CRM_Core_BAO_Mapping::add($params); + } + } + //end of function +} + diff --git a/CRM/Admin/Form/MessageTemplates.php b/CRM/Admin/Form/MessageTemplates.php new file mode 100644 index 0000000000..a37243019e --- /dev/null +++ b/CRM/Admin/Form/MessageTemplates.php @@ -0,0 +1,269 @@ +_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 'add' + ); + $this->assign('action', $this->_action); + + $this->_BAOName = 'CRM_Core_BAO_MessageTemplates'; + $this->set('BAOName', $this->_BAOName); + parent::preProcess(); + } + + /** + * This function sets the default values for the form. + * The default values are retrieved from the database. + * + * @access public + * + * @return None + */ + public function setDefaultValues() { + $defaults = $this->_values; + + if (!CRM_Utils_Array::value('pdf_format_id', $defaults)) { + $defaults['pdf_format_id'] = 'null'; + } + + $this->_workflow_id = CRM_Utils_Array::value('workflow_id', $defaults); + $this->assign('workflow_id', $this->_workflow_id); + if ($this->_action & CRM_Core_Action::ADD) { + $defaults['is_active'] = 1; + //set the context for redirection after form submit or cancel + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/messageTemplates', + 'selectedChild=user&reset=1' + )); + } + + // FIXME: we need to fix the Cancel button here as we don’t know whether it’s a workflow template in buildQuickForm() + if ($this->_action & CRM_Core_Action::UPDATE) { + if ($this->_workflow_id) { + $selectedChild = 'workflow'; + } + else { + $selectedChild = 'user'; + } + $cancelURL = CRM_Utils_System::url('civicrm/admin/messageTemplates', "selectedChild={$selectedChild}&reset=1"); + $cancelURL = str_replace('&', '&', $cancelURL); + $this->addButtons( + array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"), + ), + ) + ); + } + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + // For VIEW we only want Done button + if ($this->_action & CRM_Core_Action::VIEW) { + // currently, the above action is used solely for previewing default workflow templates + $cancelURL = CRM_Utils_System::url('civicrm/admin/messageTemplates', 'selectedChild=workflow&reset=1'); + $cancelURL = str_replace('&', '&', $cancelURL); + $this->addButtons(array( + array( + 'type' => 'cancel', + 'name' => ts('Done'), + 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"), + 'isDefault' => TRUE, + ), + ) + ); + } + else { + parent::buildQuickForm(); + } + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $breadCrumb = array(array('title' => ts('Message Templates'), + 'url' => CRM_Utils_System::url('civicrm/admin/messageTemplates', + 'action=browse&reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', 'msg_title', ts('Message Title'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_MessageTemplates', 'msg_title'), TRUE); + + $this->add('text', 'msg_subject', + ts('Message Subject'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_MessageTemplates', 'msg_subject') + ); + + //get the tokens. + $tokens = CRM_Core_SelectValues::contactTokens(); + + //sorted in ascending order tokens by ignoring word case + natcasesort($tokens); + $this->assign('tokens', json_encode($tokens)); + + $this->add('select', 'token1', ts('Insert Tokens'), + $tokens, FALSE, + array( + 'size' => "5", + 'multiple' => TRUE, + 'onchange' => "return tokenReplText(this);", + ) + ); + + $this->add('select', 'token2', ts('Insert Tokens'), + $tokens, FALSE, + array( + 'size' => "5", + 'multiple' => TRUE, + 'onchange' => "return tokenReplHtml(this);", + ) + ); + + $this->add('select', 'token3', ts('Insert Tokens'), + $tokens, FALSE, + array( + 'size' => "5", + 'multiple' => TRUE, + 'onchange' => "return tokenReplText(this);", + ) + ); + + $this->add('textarea', 'msg_text', ts('Text Message'), + "cols=50 rows=6" + ); + + // if not a system message use a wysiwyg editor, CRM-5971 + if ($this->_id && + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_MessageTemplates', + $this->_id, + 'workflow_id' + ) + ) { + $this->add('textarea', 'msg_html', ts('HTML Message'), + "cols=50 rows=6" + ); + } + else { + $this->addWysiwyg('msg_html', ts('HTML Message'), + array( + 'cols' => '80', 'rows' => '8', + 'onkeyup' => "return verify(this)", + ) + ); + } + + $this->add('select', 'pdf_format_id', ts('PDF Page Format'), + array( + 'null' => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE), FALSE + ); + + $this->add('checkbox', 'is_active', ts('Enabled?')); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->freeze(); + CRM_Utils_System::setTitle(ts('View System Default Message Template')); + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_BAO_MessageTemplates::del($this->_id); + } + elseif ($this->_action & CRM_Core_Action::VIEW) { + // currently, the above action is used solely for previewing default workflow templates + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/messageTemplates', 'selectedChild=workflow&reset=1')); + } + else { + $params = array(); + + // store the submitted values in an array + $params = $this->exportValues(); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $params['id'] = $this->_id; + } + + if ($this->_workflow_id) { + $params['workflow_id'] = $this->_workflow_id; + $params['is_active'] = TRUE; + } + + $messageTemplate = CRM_Core_BAO_MessageTemplates::add($params); + CRM_Core_Session::setStatus(ts('The Message Template \'%1\' has been saved.', array(1 => $messageTemplate->msg_title)), ts('Saved'), 'success'); + + if ($this->_workflow_id) { + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/messageTemplates', 'selectedChild=workflow&reset=1')); + } + else { + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/messageTemplates', 'selectedChild=user&reset=1')); + } + } + } +} + diff --git a/CRM/Admin/Form/Navigation.php b/CRM/Admin/Form/Navigation.php new file mode 100644 index 0000000000..3f57bcd66e --- /dev/null +++ b/CRM/Admin/Form/Navigation.php @@ -0,0 +1,167 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + + if (isset($this->_id)) { + $params = array('id' => $this->_id); + CRM_Core_BAO_Navigation::retrieve($params, $this->_defaults); + } + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', + 'label', + ts('Title'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Navigation', 'label'), + TRUE + ); + + $this->add('text', 'url', ts('Url'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Navigation', 'url')); + $permissions = CRM_Core_Permission::basicPermissions(TRUE); + $include = &$this->addElement('advmultiselect', 'permission', + ts('Permission') . ' ', $permissions, + array( + 'size' => 5, + 'style' => 'width:auto', + 'class' => 'advmultiselect', + ) + ); + + $include->setButtonAttributes('add', array('value' => ts('Add >>'))); + $include->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $operators = array('AND' => 'AND', 'OR' => 'OR'); + $this->add('select', 'permission_operator', ts('Operator'), $operators); + + //make separator location configurable + $separator = array(0 => 'None', 1 => 'After Menu Element', 2 => 'Before Menu Element'); + $this->add('select', 'has_separator', ts('Separator?'), $separator); + + $active = $this->add('checkbox', 'is_active', ts('Enabled?')); + + if (CRM_Utils_Array::value('name', $this->_defaults) == 'Home') { + $active->freeze(); + } + else { + $parentMenu = CRM_Core_BAO_Navigation::getNavigationList(); + + if (isset($this->_id)) { + unset($parentMenu[$this->_id]); + } + + // also unset home. + $homeMenuId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Navigation', 'Home', 'id', 'name'); + unset($parentMenu[$homeMenuId]); + + $parent = $this->add('select', 'parent_id', ts('Parent'), array('' => ts('-- select --')) + $parentMenu); + } + } + + public function setDefaultValues() { + $defaults = $this->_defaults; + if (isset($this->_id)) { + if (CRM_Utils_Array::value('permission', $this->_defaults)) { + foreach (explode(',', $this->_defaults['permission']) as $value) { + $components[$value] = $value; + } + $defaults['permission'] = $components; + } + //Take parent id in object variable to calculate the menu + //weight if menu parent id changed + $this->_currentParentID = CRM_Utils_Array::value('parent_id', $this->_defaults); + } + else { + $defaults['permission'] = "access CiviCRM"; + } + + // its ok if there is no element called is_active + $defaults['is_active'] = ($this->_id) ? $this->_defaults['is_active'] : 1; + + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + if (isset($this->_id)) { + $params['id'] = $this->_id; + $params['current_parent_id'] = $this->_currentParentID; + } + + $navigation = CRM_Core_BAO_Navigation::add($params); + + // also reset navigation + CRM_Core_BAO_Navigation::resetNavigation(); + + CRM_Core_Session::setStatus(ts('Menu \'%1\' has been saved.', + array(1 => $navigation->label) + ), ts('Saved'), 'success'); + } +} diff --git a/CRM/Admin/Form/OptionGroup.php b/CRM/Admin/Form/OptionGroup.php new file mode 100644 index 0000000000..8e5d8698cc --- /dev/null +++ b/CRM/Admin/Form/OptionGroup.php @@ -0,0 +1,130 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + CRM_Utils_System::setTitle(ts('Dropdown Options')); + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', + 'name', + ts('Name'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionGroup', 'name'), + TRUE + ); + $this->addRule('name', + ts('Name already exists in Database.'), + 'objectExists', + array('CRM_Core_DAO_OptionGroup', $this->_id) + ); + + $this->add('text', + 'title', + ts('Group Title'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionGroup', 'title') + ); + + $this->add('text', + 'description', + ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionGroup', 'description') + ); + + $element = $this->add('checkbox', 'is_active', ts('Enabled?')); + if ($this->_action & CRM_Core_Action::UPDATE) { + if (in_array($this->_values['name'], array( + 'encounter_medium', 'case_type', 'case_status'))) { + static $caseCount = NULL; + if (!isset($caseCount)) { + $caseCount = CRM_Case_BAO_Case::caseCount(NULL, FALSE); + } + + if ($caseCount > 0) { + $element->freeze(); + } + } + if (CRM_Utils_Array::value('is_reserved', $this->_values)) { + $this->freeze(array('name', 'is_active')); + } + } + + $this->assign('id', $this->_id); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Utils_System::flushCache(); + + $params = $this->exportValues(); + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_BAO_OptionGroup::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected option group has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + + $params = $ids = array(); + // store the submitted values in an array + $params = $this->exportValues(); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $ids['optionGroup'] = $this->_id; + } + + $optionGroup = CRM_Core_BAO_OptionGroup::add($params, $ids); + CRM_Core_Session::setStatus(ts('The Option Group \'%1\' has been saved.', array(1 => $optionGroup->name)), ts('Saved'), 'success'); + } + } +} diff --git a/CRM/Admin/Form/OptionValue.php b/CRM/Admin/Form/OptionValue.php new file mode 100644 index 0000000000..9cd7e54a4f --- /dev/null +++ b/CRM/Admin/Form/OptionValue.php @@ -0,0 +1,287 @@ +_gid = CRM_Utils_Request::retrieve('gid', 'Positive', + $this, FALSE, 0 + ); + //get optionGroup name in case of email/postal greeting or addressee, CRM-4575 + if (!empty($this->_gid)) { + $this->_gName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_gid, 'name'); + } + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/admin/optionValue', 'reset=1&action=browse&gid=' . $this->_gid); + $session->replaceUserContext($url); + + $this->assign('id', $this->_id); + + if ($this->_id && in_array($this->_gName, CRM_Core_OptionGroup::$_domainIDGroups)) { + $domainID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'domain_id', 'id'); + if (CRM_Core_Config::domainID() != $domainID) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + } + } + + /** + * This function sets the default values for the form. + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + $defaults = parent::setDefaultValues(); + if (!CRM_Utils_Array::value('weight', $defaults)) { + $query = "SELECT max( `weight` ) as weight FROM `civicrm_option_value` where option_group_id=" . $this->_gid; + $dao = new CRM_Core_DAO(); + $dao->query($query); + $dao->fetch(); + $defaults['weight'] = ($dao->weight + 1); + } + + // CRM-11516 + if ($this->_gName == 'payment_instrument' && $this->_id) { + $defaults['financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($this->_id, 'civicrm_option_value', 'financial_account_id'); + } + //setDefault of contact types for email greeting, postal greeting, addressee, CRM-4575 + if (in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee'))) { + $defaults['contactOptions'] = CRM_Utils_Array::value('filter', $defaults); + } + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + //CRM-4575 + $isReserved = FALSE; + if ($this->_id) { + $isReserved = (bool) CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'is_reserved'); + } + parent::buildQuickForm(); + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', 'label', ts('Title'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'label'), TRUE); + $this->add('text', 'value', ts('Value'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'value'), TRUE); + $this->add('text', 'name', ts('Name'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'name')); + if ($this->_gName == 'custom_search') { + $this->add('text', + 'description', + ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'description') + ); + } + else { + $this->addWysiwyg('description', + ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'description') + ); + } + + if ($this->_gName == 'case_status') { + $grouping = $this->add('select', 'grouping', ts('Option Grouping Name'), array('Opened' => ts('Opened'), + 'Closed' => ts('Closed'), + )); + if ($isReserved) { + $grouping->freeze(); + } + } + else { + $this->add('text', 'grouping', ts('Grouping'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'grouping')); + } + + $this->add('text', 'weight', ts('Weight'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'weight'), TRUE); + $this->add('checkbox', 'is_active', ts('Enabled?')); + $this->add('checkbox', 'is_default', ts('Default Option?')); + $this->add('checkbox', 'is_optgroup', ts('Is OptGroup?')); + + // CRM-11516 + if ($this->_gName == 'payment_instrument') { + $accountType = CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "); + $financialAccount = CRM_Contribute_PseudoConstant::financialAccount(NULL, key($accountType)); + + $this->add('select', 'financial_account_id', ts('Financial Account'), + array('' => ts('- select -')) + $financialAccount + ); + } + // CRM-9953 + // we dont display this in the template, but the form sets the default values which are then saved + // this allow us to retain the previous values + $this->add('text', 'filter', ts('Filter')); + + if ($this->_action & CRM_Core_Action::UPDATE && $isReserved) { + $this->freeze(array('name', 'description', 'is_active')); + } + //get contact type for which user want to create a new greeting/addressee type, CRM-4575 + if (in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee')) && !$isReserved) { + $values = array(1 => ts('Individual'), + 2 => ts('Household'), + 3 => ts('Organization'), + 4 => ts('Multiple Contact Merge'), + ); + + $this->add('select', 'contactOptions', ts('Contact Type'), array('' => '-select-') + $values, TRUE); + } + + $this->addFormRule(array('CRM_Admin_Form_OptionValue', 'formRule'), $this); + $cancelURL = CRM_Utils_System::url('civicrm/admin/optionValue', "gid={$this->_gid}&reset=1"); + $cancelURL = str_replace('&', '&', $cancelURL); + $this->addButtons( + array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"), + ), + ) + ); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $self this object. + * + * @return true if no errors, else an array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + $errors = array(); + + //don't allow duplicate value within group. + $optionValues = array(); + CRM_Core_OptionValue::getValues(array('id' => $self->_gid), $optionValues); + foreach ($optionValues as $values) { + if ($values['id'] != $self->_id) { + if ($fields['value'] == $values['value']) { + $errors['value'] = ts('Value already exist in database.'); + break; + } + } + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Utils_System::flushCache(); + + $params = $this->exportValues(); + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_BAO_OptionValue::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected option value has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + + $params = $ids = array(); + // store the submitted values in an array + $params = $this->exportValues(); + $params['option_group_id'] = $this->_gid; + + if ($this->_action & CRM_Core_Action::UPDATE) { + $ids['optionValue'] = $this->_id; + } + + //set defaultGreeting option in params to save default value as per contactOption-defaultValue mapping + if (CRM_Utils_Array::value('contactOptions', $params)) { + $params['filter'] = CRM_Utils_Array::value('contactOptions', $params); + $params['defaultGreeting'] = 1; + } + + $optionValue = CRM_Core_BAO_OptionValue::add($params, $ids); + // CRM-11516 + if (CRM_Utils_Array::value('financial_account_id', $params)) { + $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' ")); + $params = array( + 'entity_table' => 'civicrm_option_value', + 'entity_id' => $optionValue->id, + 'account_relationship' => $relationTypeId, + 'financial_account_id' => $params['financial_account_id'] + ); + CRM_Financial_BAO_FinancialTypeAccount::add($params); + } + CRM_Core_Session::setStatus(ts('The Option Value \'%1\' has been saved.', array(1 => $optionValue->label)), ts('Saved'), 'success'); + } + } +} diff --git a/CRM/Admin/Form/Options.php b/CRM/Admin/Form/Options.php new file mode 100644 index 0000000000..32ae6c12f8 --- /dev/null +++ b/CRM/Admin/Form/Options.php @@ -0,0 +1,421 @@ +_gName) { + $this->_gName = CRM_Utils_Request::retrieve('group', 'String', $this, FALSE, 0); + $this->_gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', + $this->_gName, + 'id', + 'name' + ); + } + if ($this->_gName) { + $this->set('gName', $this->_gName); + } + else { + $this->_gName = $this->get('gName'); + } + $this->_GName = ucwords(str_replace('_', ' ', $this->_gName)); + $url = "civicrm/admin/options/{$this->_gName}"; + $params = "group={$this->_gName}&reset=1"; + + if (($this->_action & CRM_Core_Action::DELETE) && + in_array($this->_gName, array('email_greeting', 'postal_greeting', 'addressee')) + ) { + // Don't allow delete if the option value belongs to addressee, postal or email greetings and is in use. + $findValue = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'value'); + $queryParam = array(1 => array($findValue, 'Integer')); + $columnName = $this->_gName . "_id"; + $sql = "SELECT count(id) FROM civicrm_contact WHERE " . $columnName . " = %1"; + $isInUse = CRM_Core_DAO::singleValueQuery($sql, $queryParam); + if ($isInUse) { + $scriptURL = "" . ts('Learn more about a script that can automatically update contact addressee and greeting options.') . ""; + CRM_Core_Session::setStatus(ts('The selected %1 option has not been deleted because it is currently in use. Please update these contacts to use a different format before deleting this option. %2', array(1 => $this->_GName, 2 => $scriptURL)), ts('Sorry'), 'error'); + $redirect = CRM_Utils_System::url($url, $params); + CRM_Utils_System::redirect($redirect); + } + } + + + $session->pushUserContext(CRM_Utils_System::url($url, $params)); + $this->assign('id', $this->_id); + + if ($this->_id && in_array($this->_gName, CRM_Core_OptionGroup::$_domainIDGroups)) { + $domainID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'domain_id', 'id'); + if (CRM_Core_Config::domainID() != $domainID) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + } + } + + /** + * This function sets the default values for the form. + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + + if (!isset($defaults['weight']) || !$defaults['weight']) { + $fieldValues = array('option_group_id' => $this->_gid); + $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', $fieldValues); + } + + //setDefault of contact types for email greeting, postal greeting, addressee, CRM-4575 + if (in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee'))) { + $defaults['contactOptions'] = (CRM_Utils_Array::value('filter', $defaults)) ? $defaults['filter'] : NULL; + } + // CRM-11516 + if ($this->_gName == 'payment_instrument' && $this->_id) { + $defaults['financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($this->_id, 'civicrm_option_value', 'financial_account_id'); + } + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $this->applyFilter('__ALL__', 'trim'); + + $isReserved = FALSE; + if ($this->_id) { + $isReserved = (bool) CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'is_reserved'); + } + + $this->add('text', + 'label', + ts('Label'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'label'), + TRUE + ); + + if (!in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee')) && !$isReserved) { + $this->addRule('label', + ts('This Label already exists in the database for this option group. Please select a different Value.'), + 'optionExists', + array('CRM_Core_DAO_OptionValue', $this->_id, $this->_gid, 'label') + ); + } + + if ($this->_gName == 'case_status') { + $classes = array('Opened' => ts('Opened'), + 'Closed' => ts('Closed'), + ); + + $grouping = $this->add('select', + 'grouping', + ts('Status Class'), + $classes + ); + if ($isReserved) { + $grouping->freeze(); + } + } + // CRM-11516 + if ($this->_gName == 'payment_instrument') { + $accountType = CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "); + $financialAccount = CRM_Contribute_PseudoConstant::financialAccount(NULL, key($accountType)); + + $this->add('select', 'financial_account_id', ts('Financial Account'), + array('' => ts('- select -')) + $financialAccount + ); + } + + $required = FALSE; + if ($this->_gName == 'custom_search') { + $required = TRUE; + } + elseif ($this->_gName == 'redaction_rule' || $this->_gName == 'engagement_index') { + $this->add('text', + 'value', + ts('Value'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'value'), + TRUE + ); + if ($this->_gName == 'redaction_rule') { + $this->add('checkbox', + 'filter', + ts('Regular Expression?') + ); + } + } + if ($this->_gName == 'participant_listing') { + $this->add('text', + 'description', + ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'description') + ); + } + else { + // Hard-coding attributes here since description is still stored as varchar and not text in the schema. dgg + $this->addWysiwyg('description', + ts('Description'), + array('rows' => 4, 'cols' => 80), + $required + ); + } + + if ($this->_gName == 'event_badge') { + $this->add('text', + 'name', + ts('Class Name'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'name') + ); + } + + $this->add('text', + 'weight', + ts('Weight'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'weight'), + TRUE + ); + $this->addRule('weight', ts('is a numeric field'), 'numeric'); + + // If CiviCase enabled AND "Add" mode OR "edit" mode for non-reserved activities, only allow user to pick Core or CiviCase component. + // FIXME: Each component should define whether adding new activity types is allowed. + $config = CRM_Core_Config::singleton(); + if ($this->_gName == 'activity_type' && in_array("CiviCase", $config->enableComponents) && + (($this->_action & CRM_Core_Action::ADD) || !$isReserved) + ) { + $caseID = CRM_Core_Component::getComponentID('CiviCase'); + $components = array('' => ts('Contact'), $caseID => 'CiviCase'); + $this->add('select', + 'component_id', + ts('Component'), + $components, FALSE + ); + } + + $enabled = $this->add('checkbox', 'is_active', ts('Enabled?')); + + if ($isReserved) { + $enabled->freeze(); + } + + //fix for CRM-3552, CRM-4575 + if (in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee', 'from_email_address', 'case_status', 'encounter_medium', 'case_type'))) { + $this->assign('showDefault', TRUE); + $this->add('checkbox', 'is_default', ts('Default Option?')); + } + + //get contact type for which user want to create a new greeting/addressee type, CRM-4575 + if (in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee')) && !$isReserved) { + $values = array(1 => ts('Individual'), + 2 => ts('Household'), + 3 => ts('Organization'), + 4 => ts('Multiple Contact Merge'), + ); + $this->add('select', 'contactOptions', ts('Contact Type'), array('' => '-select-') + $values, TRUE); + $this->assign('showContactFilter', TRUE); + } + + if ($this->_gName == 'participant_status') { + // For Participant Status options, expose the 'filter' field to track which statuses are "Counted", and the Visibility field + $element = $this->add('checkbox', 'filter', ts('Counted?')); + $this->add('select', 'visibility_id', ts('Visibility'), CRM_Core_PseudoConstant::visibility()); + } + if ($this->_gName == 'participant_role') { + // For Participant Role options, expose the 'filter' field to track which statuses are "Counted" + $this->add('checkbox', 'filter', ts('Counted?')); + } + + $this->addFormRule(array('CRM_Admin_Form_Options', 'formRule'), $this); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $self current form object. + * + * @return array array of errors / empty array. + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + $errors = array(); + if ($self->_gName == 'case_status' && !CRM_Utils_Array::value('grouping', $fields)) { + $errors['grouping'] = ts('Status class is a required field'); + } + + if (in_array($self->_gName, array('email_greeting', 'postal_greeting', 'addressee')) + && !CRM_Utils_Array::value('is_reserved', $self->_defaultValues) + ) { + $label = $fields['label']; + $condition = " AND v.label = '{$label}' "; + $values = CRM_Core_OptionGroup::values($self->_gName, FALSE, FALSE, FALSE, $condition, 'filter'); + $checkContactOptions = TRUE; + + if ($self->_id && ($self->_defaultValues['contactOptions'] == $fields['contactOptions'])) { + $checkContactOptions = FALSE; + } + + if ($checkContactOptions && in_array($fields['contactOptions'], $values)) { + $errors['label'] = ts('This Label already exists in the database for the selected contact type.'); + } + } + + if ($self->_gName == 'from_email_address') { + $formEmail = CRM_Utils_Mail::pluckEmailFromHeader($fields['label']); + if (!CRM_Utils_Rule::email($formEmail)) { + $errors['label'] = ts('Please enter the valid email address.'); + } + + $formName = explode('"', $fields['label']); + if (!CRM_Utils_Array::value(1, $formName) || count($formName) != 3) { + $errors['label'] = ts('Please follow the proper format for From Email Address'); + } + } + + return $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + $fieldValues = array('option_group_id' => $this->_gid); + $wt = CRM_Utils_Weight::delWeight('CRM_Core_DAO_OptionValue', $this->_id, $fieldValues); + + if (CRM_Core_BAO_OptionValue::del($this->_id)) { + if ($this->_gName == 'phone_type') { + CRM_Core_BAO_Phone::setOptionToNull(CRM_Utils_Array::value('value', $this->_defaultValues)); + } + + CRM_Core_Session::setStatus(ts('Selected %1 type has been deleted.', array(1 => $this->_GName)), ts('Record Deleted'), 'success'); + } + else { + CRM_Core_Session::setStatus(ts('Selected %1 type has not been deleted.', array(1 => $this->_GName)), ts('Sorry'), 'error'); + CRM_Utils_Weight::correctDuplicateWeights('CRM_Core_DAO_OptionValue', $fieldValues); + } + } + else { + $params = $ids = array(); + $params = $this->exportValues(); + + // allow multiple defaults within group. + $allowMultiDefaults = array('email_greeting', 'postal_greeting', 'addressee', 'from_email_address'); + if (in_array($this->_gName, $allowMultiDefaults)) { + if ($this->_gName == 'from_email_address') { + $params['reset_default_for'] = array('domain_id' => CRM_Core_Config::domainID()); + } + elseif ($filter = CRM_Utils_Array::value('contactOptions', $params)) { + $params['filter'] = $filter; + $params['reset_default_for'] = array('filter' => "0, " . $params['filter']); + } + + //make sure we should has to have space, CRM-6977 + if ($this->_gName == 'from_email_address') { + $params['label'] = str_replace('"<', '" <', $params['label']); + } + } + + // set db value of filter in params if filter is non editable + if ($this->_id && !array_key_exists('filter', $params) && !$this->_gName == 'participant_role') { + $params['filter'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'filter', 'id'); + } + + $groupParams = array('name' => ($this->_gName)); + $optionValue = CRM_Core_OptionValue::addOptionValue($params, $groupParams, $this->_action, $this->_id); + + // CRM-11516 + if (CRM_Utils_Array::value('financial_account_id', $params)) { + $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' ")); + $params = array( + 'entity_table' => 'civicrm_option_value', + 'entity_id' => $optionValue->id, + 'account_relationship' => $relationTypeId, + 'financial_account_id' => $params['financial_account_id'] + ); + CRM_Financial_BAO_FinancialTypeAccount::add($params); + } + + CRM_Core_Session::setStatus(ts('The %1 \'%2\' has been saved.', array(1 => $this->_GName, 2 => $optionValue->label)), ts('Saved'), 'success'); + } + } +} diff --git a/CRM/Admin/Form/ParticipantStatus.php b/CRM/Admin/Form/ParticipantStatus.php new file mode 100644 index 0000000000..6be8d2cc71 --- /dev/null +++ b/CRM/Admin/Form/ParticipantStatus.php @@ -0,0 +1,135 @@ +_action & CRM_Core_Action::DELETE) { + + return; + + } + + $this->applyFilter('__ALL__', 'trim'); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_ParticipantStatusType'); + + $this->add('text', 'name', ts('Name'), NULL, TRUE); + + $this->add('text', 'label', ts('Label'), $attributes['label'], TRUE); + + $classes = array(); + foreach (array( + 'Positive', 'Pending', 'Waiting', 'Negative') as $class) { + $classes[$class] = CRM_Event_DAO_ParticipantStatusType::tsEnum('class', $class); + } + $this->add('select', 'class', ts('Class'), $classes, TRUE); + + $this->add('checkbox', 'is_active', ts('Active?')); + $this->add('checkbox', 'is_counted', ts('Counted?')); + + $this->add('text', 'weight', ts('Weight'), $attributes['weight'], TRUE); + + $this->add('select', 'visibility_id', ts('Visibility'), CRM_Core_PseudoConstant::visibility(), TRUE); + } + + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + if (!CRM_Utils_Array::value('weight', $defaults)) { + $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Event_DAO_ParticipantStatusType'); + } + $this->_isReserved = CRM_Utils_Array::value('is_reserved', $defaults); + if ($this->_isReserved) { + $this->freeze(array('name', 'class', 'is_active')); + } + return $defaults; + } + + function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + if (CRM_Event_BAO_ParticipantStatusType::deleteParticipantStatusType($this->_id)) { + CRM_Core_Session::setStatus(ts('Selected participant status has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + CRM_Core_Session::setStatus(ts('Selected participant status has NOT been deleted; there are still participants with this status.'), ts('Sorry'), 'error'); + } + return; + } + + $formValues = $this->controller->exportValues($this->_name); + + $params = array( + 'name' => CRM_Utils_Array::value('name', $formValues), + 'label' => CRM_Utils_Array::value('label', $formValues), + 'class' => CRM_Utils_Array::value('class', $formValues), + 'is_active' => CRM_Utils_Array::value('is_active', $formValues, FALSE), + 'is_counted' => CRM_Utils_Array::value('is_counted', $formValues, FALSE), + 'weight' => CRM_Utils_Array::value('weight', $formValues), + 'visibility_id' => CRM_Utils_Array::value('visibility_id', $formValues), + ); + + // make sure a malicious POST does not change these on reserved statuses + if ($this->_isReserved)unset($params['name'], $params['class'], $params['is_active']); + + if ($this->_action & CRM_Core_Action::UPDATE) { + + $params['id'] = $this->_id; + + } + + if ($this->_id) { + $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantStatusType', $this->_id, 'weight', 'id'); + } + else { + $oldWeight = 0; + } + $params['weight'] = CRM_Utils_Weight::updateOtherWeights('CRM_Event_DAO_ParticipantStatusType', $oldWeight, $params['weight']); + + $participantStatus = CRM_Event_BAO_ParticipantStatusType::create($params); + + if ($participantStatus->id) { + if ($this->_action & CRM_Core_Action::UPDATE) { + CRM_Core_Session::setStatus(ts('The Participant Status has been updated.'), ts('Saved'), 'success'); + } + else { + CRM_Core_Session::setStatus(ts('The new Participant Status has been saved.'), ts('Saved'), 'success'); + } + } + else { + CRM_Core_Session::setStatus(ts('The changes have not been saved.'), ts('Saved'), 'success'); + } + } +} + diff --git a/CRM/Admin/Form/PaymentProcessor.php b/CRM/Admin/Form/PaymentProcessor.php new file mode 100644 index 0000000000..bc34146d0e --- /dev/null +++ b/CRM/Admin/Form/PaymentProcessor.php @@ -0,0 +1,392 @@ +_id) { + $this->_ppType = CRM_Utils_Request::retrieve('pp', 'String', $this, FALSE, NULL); + if (!$this->_ppType) { + $this->_ppType = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_PaymentProcessor', + $this->_id, + 'payment_processor_type_id' + ); + } + $this->set('pp', $this->_ppType); + } + else { + $this->_ppType = CRM_Utils_Request::retrieve('pp', 'String', $this, TRUE, NULL); + } + + $this->assign('ppType', $this->_ppType); + $ppTypeName = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_PaymentProcessorType', + $this->_ppType, + 'name' + ); + $this->assign('ppTypeName', $ppTypeName ); + + $this->_ppDAO = new CRM_Financial_DAO_PaymentProcessorType( ); + $this->_ppDAO->id = $this->_ppType; + + if (!$this->_ppDAO->find(TRUE)) { + CRM_Core_Error::fatal(ts('Could not find payment processor meta information')); + } + + if ($this->_id) { + $refreshURL = CRM_Utils_System::url('civicrm/admin/paymentProcessor', + "reset=1&action=update&id={$this->_id}", + FALSE, NULL, FALSE + ); + } + else { + $refreshURL = CRM_Utils_System::url('civicrm/admin/paymentProcessor', + "reset=1&action=add", + FALSE, NULL, FALSE + ); + } + + //CRM-4129 + $destination = CRM_Utils_Request::retrieve('civicrmDestination', 'String', $this); + if ($destination) { + $destination = urlencode($destination); + $refreshURL .= "&civicrmDestination=$destination"; + } + + $this->assign('refreshURL', $refreshURL); + + $this->assign('is_recur', $this->_ppDAO->is_recur); + + $this->_fields = array( + array( + 'name' => 'user_name', + 'label' => $this->_ppDAO->user_name_label, + ), + array( + 'name' => 'password', + 'label' => $this->_ppDAO->password_label, + ), + array( + 'name' => 'signature', + 'label' => $this->_ppDAO->signature_label, + ), + array( + 'name' => 'subject', + 'label' => $this->_ppDAO->subject_label, + ), + array( + 'name' => 'url_site', + 'label' => ts('Site URL'), + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + ); + + if ($this->_ppDAO->is_recur) { + $this->_fields[] = array( + 'name' => 'url_recur', + 'label' => ts('Recurring Payments URL'), + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ); + } + + if (!empty($this->_ppDAO->url_button_default)) { + $this->_fields[] = array( + 'name' => 'url_button', + 'label' => ts('Button URL'), + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ); + } + + if (!empty($this->_ppDAO->url_api_default)) { + $this->_fields[] = array( + 'name' => 'url_api', + 'label' => ts('API URL'), + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ); + } + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm($check = FALSE) { + parent::buildQuickForm(); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Financial_DAO_PaymentProcessor'); + + $this->add('text', 'name', ts('Name'), + $attributes['name'], TRUE + ); + + $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array('CRM_Financial_DAO_PaymentProcessor', $this->_id)); + + $this->add('text', 'description', ts('Description'), + $attributes['description'] + ); + + $types = CRM_Core_PseudoConstant::paymentProcessorType(); + $this->add( 'select', 'payment_processor_type_id', ts('Payment Processor Type'), $types, true, + array('onchange' => "reload(true)") + ); + + // Financial Account of account type asset CRM-11515 + $accountType = CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name = 'Asset' "); + $financialAccount = CRM_Contribute_PseudoConstant::financialAccount(NULL, key($accountType)); + if ($fcount = count($financialAccount)) { + $this->assign('financialAccount', $fcount); + } + $this->add('select', 'financial_account_id', ts('Financial Account'), + array('' => ts('- select -')) + $financialAccount, + true + ); + // is this processor active ? + $this->add('checkbox', 'is_active', ts('Is this Payment Processor active?')); + $this->add('checkbox', 'is_default', ts('Is this Payment Processor the default?')); + + + foreach ($this->_fields as $field) { + if (empty($field['label'])) { + continue; + } + + $this->add('text', $field['name'], + $field['label'], $attributes[$field['name']] + ); + $this->add('text', "test_{$field['name']}", + $field['label'], $attributes[$field['name']] + ); + if (CRM_Utils_Array::value('rule', $field)) { + $this->addRule($field['name'], $field['msg'], $field['rule']); + $this->addRule("test_{$field['name']}", $field['msg'], $field['rule']); + } + } + + $this->addFormRule(array('CRM_Admin_Form_PaymentProcessor', 'formRule')); + } + + static function formRule($fields) { + + // make sure that at least one of live or test is present + // and we have at least name and url_site + // would be good to make this processor specific + $errors = array(); + + if (!(self::checkSection($fields, $errors) || + self::checkSection($fields, $errors, 'test') + )) { + $errors['_qf_default'] = ts('You must have at least the test or live section filled'); + } + + if (!empty($errors)) { + return $errors; + } + + return empty($errors) ? TRUE : $errors; + } + + static function checkSection(&$fields, &$errors, $section = NULL) { + $names = array('user_name'); + + $present = FALSE; + $allPresent = TRUE; + foreach ($names as $name) { + if ($section) { + $name = "{$section}_$name"; + } + if (!empty($fields[$name])) { + $present = TRUE; + } + else { + $allPresent = FALSE; + } + } + + if ($present) { + if (!$allPresent) { + $errors['_qf_default'] = ts('You must have at least the user_name specified'); + } + } + return $present; + } + + function setDefaultValues() { + $defaults = array(); + if ($this->_ppType) { + $defaults['payment_processor_type_id'] = $this->_ppType; + } + if (!$this->_id) { + $defaults['is_active'] = $defaults['is_default'] = 1; + $defaults['url_site'] = $this->_ppDAO->url_site_default; + $defaults['url_api'] = $this->_ppDAO->url_api_default; + $defaults['url_recur'] = $this->_ppDAO->url_recur_default; + $defaults['url_button'] = $this->_ppDAO->url_button_default; + $defaults['test_url_site'] = $this->_ppDAO->url_site_test_default; + $defaults['test_url_api'] = $this->_ppDAO->url_api_test_default; + $defaults['test_url_recur'] = $this->_ppDAO->url_recur_test_default; + $defaults['test_url_button'] = $this->_ppDAO->url_button_test_default; + return $defaults; + } + $domainID = CRM_Core_Config::domainID(); + + $dao = new CRM_Financial_DAO_PaymentProcessor( ); + $dao->id = $this->_id; + $dao->domain_id = $domainID; + if (!$dao->find(TRUE)) { + return $defaults; + } + + CRM_Core_DAO::storeValues($dao, $defaults); + + // now get testID + $testDAO = new CRM_Financial_DAO_PaymentProcessor(); + $testDAO->name = $dao->name; + $testDAO->is_test = 1; + $testDAO->domain_id = $domainID; + if ($testDAO->find(TRUE)) { + $this->_testID = $testDAO->id; + + foreach ($this->_fields as $field) { + $testName = "test_{$field['name']}"; + $defaults[$testName] = $testDAO->{$field['name']}; + } + } + $defaults['financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($dao->id, 'civicrm_payment_processor', 'financial_account_id'); + + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return Void + */ + public function postProcess() { + CRM_Utils_System::flushCache( 'CRM_Financial_DAO_PaymentProcessor' ); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Financial_BAO_PaymentProcessor::del($this->_id); + CRM_Core_Session::setStatus("", ts('Payment Processor Deleted.'), "success"); + return; + } + + $values = $this->controller->exportValues($this->_name); + $domainID = CRM_Core_Config::domainID(); + + if (CRM_Utils_Array::value('is_default', $values)) { + $query = "UPDATE civicrm_payment_processor SET is_default = 0 WHERE domain_id = $domainID"; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + + $this->updatePaymentProcessor($values, $domainID, FALSE); + $this->updatePaymentProcessor($values, $domainID, TRUE); + CRM_Core_Session::setStatus(ts('Payment processor %1 has been saved.', array(1 => "{$values['name']}")), ts('Saved'), 'success'); + } + + /** + * Save a payment processor + * + * @return Void + */ + function updatePaymentProcessor(&$values, $domainID, $test) { + $dao = new CRM_Financial_DAO_PaymentProcessor( ); + + $dao->id = $test ? $this->_testID : $this->_id; + $dao->domain_id = $domainID; + $dao->is_test = $test; + $dao->is_default = CRM_Utils_Array::value('is_default', $values, 0); + + $dao->is_active = CRM_Utils_Array::value('is_active', $values, 0); + + $dao->name = $values['name']; + $dao->description = $values['description']; + $dao->payment_processor_type_id = $values['payment_processor_type_id']; + + foreach ($this->_fields as $field) { + $fieldName = $test ? "test_{$field['name']}" : $field['name']; + $dao->{$field['name']} = trim(CRM_Utils_Array::value($fieldName, $values)); + if (empty($dao->{$field['name']})) { + $dao->{$field['name']} = 'null'; + } + } + + // also copy meta fields from the info DAO + $dao->is_recur = $this->_ppDAO->is_recur; + $dao->billing_mode = $this->_ppDAO->billing_mode; + $dao->class_name = $this->_ppDAO->class_name; + $dao->payment_type = $this->_ppDAO->payment_type; + + $dao->save(); + + //CRM-11515 + + $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' ")); + $params = array( + 'entity_table' => 'civicrm_payment_processor', + 'entity_id' => $dao->id, + 'account_relationship' => $relationTypeId, + 'financial_account_id' => $values['financial_account_id'] + ); + CRM_Financial_BAO_FinancialTypeAccount::add($params); + } +} diff --git a/CRM/Admin/Form/PaymentProcessorType.php b/CRM/Admin/Form/PaymentProcessorType.php new file mode 100644 index 0000000000..b3dd0a02f0 --- /dev/null +++ b/CRM/Admin/Form/PaymentProcessorType.php @@ -0,0 +1,245 @@ +_fields = array( + array( + 'name' => 'name', + 'label' => ts('Name'), + 'required' => TRUE, + ), + array( + 'name' => 'title', + 'label' => ts('Title'), + 'required' => TRUE, + ), + array( + 'name' => 'billing_mode', + 'label' => ts('Billing Mode'), + 'required' => TRUE, + 'rule' => 'positiveInteger', + 'msg' => ts('Enter a positive integer'), + ), + array( + 'name' => 'description', + 'label' => ts('Description'), + ), + array( + 'name' => 'user_name_label', + 'label' => ts('User Name Label'), + ), + array( + 'name' => 'password_label', + 'label' => ts('Password Label'), + ), + array( + 'name' => 'signature_label', + 'label' => ts('Signature Label'), + ), + array( + 'name' => 'subject_label', + 'label' => ts('Subject Label'), + ), + array( + 'name' => 'class_name', + 'label' => ts('PHP class name'), + 'required' => TRUE, + ), + array( + 'name' => 'url_site_default', + 'label' => ts('Live Site URL'), + 'required' => TRUE, + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_api_default', + 'label' => ts('Live API URL'), + 'required' => FALSE, + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_recur_default', + 'label' => ts('Live Recurring Payments URL'), + 'required' => TRUE, + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_button_default', + 'label' => ts('Live Button URL'), + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_site_test_default', + 'label' => ts('Test Site URL'), + 'required' => TRUE, + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_api_test_default', + 'label' => ts('Test API URL'), + 'required' => FALSE, + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_recur_test_default', + 'label' => ts('Test Recurring Payments URL'), + 'required' => TRUE, + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + array( + 'name' => 'url_button_test_default', + 'label' => ts('Test Button URL'), + 'rule' => 'url', + 'msg' => ts('Enter a valid URL'), + ), + ); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm($check = FALSE) { + parent::buildQuickForm(); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute( 'CRM_Financial_DAO_PaymentProcessorType' ); + + foreach ($this->_fields as $field) { + $required = CRM_Utils_Array::value('required', $field, FALSE); + $this->add('text', $field['name'], + $field['label'], $attributes['name'], $required + ); + if (CRM_Utils_Array::value('rule', $field)) { + $this->addRule($field['name'], $field['msg'], $field['rule']); + } + } + + // is this processor active ? + $this->add('checkbox', 'is_active', ts('Is this Payment Processor Type active?')); + $this->add('checkbox', 'is_default', ts('Is this Payment Processor Type the default?')); + $this->add('checkbox', 'is_recur', ts('Does this Payment Processor Type support recurring donations?')); + } + + function setDefaultValues() { + $defaults = array(); + + if (!$this->_id) { + $defaults['is_active'] = $defaults['is_default'] = 1; + $defaults['user_name_label'] = ts('User Name'); + $defaults['password_label'] = ts('Password'); + $defaults['signature_label'] = ts('Signature'); + $defaults['subject_label'] = ts('Subject'); + return $defaults; + } + + $dao = new CRM_Financial_DAO_PaymentProcessorType( ); + $dao->id = $this->_id; + + if (!$dao->find(TRUE)) { + return $defaults; + } + + CRM_Core_DAO::storeValues($dao, $defaults); + + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Utils_System::flushCache( 'CRM_Financial_DAO_PaymentProcessorType' ); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Financial_BAO_PaymentProcessorType::del($this->_id); + return; + } + + $values = $this->controller->exportValues($this->_name); + + if (CRM_Utils_Array::value('is_default', $values)) { + $query = " +UPDATE civicrm_payment_processor SET is_default = 0"; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + + $dao = new CRM_Financial_DAO_PaymentProcessorType( ); + + $dao->id = $this->_id; + $dao->is_default = CRM_Utils_Array::value('is_default', $values, 0); + $dao->is_active = CRM_Utils_Array::value('is_active', $values, 0); + $dao->is_recur = CRM_Utils_Array::value('is_recur', $values, 0); + + $dao->name = $values['name']; + $dao->description = $values['description']; + + foreach ($this->_fields as $field) { + $dao->{$field['name']} = trim($values[$field['name']]); + if (empty($dao->{$field['name']})) { + $dao->{$field['name']} = 'null'; + } + } + $dao->save(); + } +} + diff --git a/CRM/Admin/Form/PdfFormats.php b/CRM/Admin/Form/PdfFormats.php new file mode 100644 index 0000000000..4805513bfd --- /dev/null +++ b/CRM/Admin/Form/PdfFormats.php @@ -0,0 +1,131 @@ +_action & CRM_Core_Action::DELETE) { + $formatName = CRM_Core_BAO_PdfFormat::getFieldValue('CRM_Core_BAO_PdfFormat', $this->_id, 'name'); + $this->assign('formatName', $formatName); + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_BAO_PdfFormat'); + $this->add('text', 'name', ts('Name'), $attributes['name'], TRUE); + $this->add('text', 'description', ts('Description'), array('size' => CRM_Utils_Type::HUGE)); + $this->add('checkbox', 'is_default', ts('Is this PDF Page Format the default?')); + + $this->add('select', 'paper_size', ts('Paper Size'), + array( + 0 => ts('- default -')) + CRM_Core_BAO_PaperSize::getList(TRUE), FALSE, + array('onChange' => "selectPaper( this.value );") + ); + + $this->add('static', 'paper_dimensions', NULL, ts('Width x Height')); + $this->add('select', 'orientation', ts('Orientation'), CRM_Core_BAO_PdfFormat::getPageOrientations(), FALSE, + array('onChange' => "updatePaperDimensions();") + ); + $this->add('select', 'metric', ts('Unit of Measure'), CRM_Core_BAO_PdfFormat::getUnits(), FALSE, + array('onChange' => "selectMetric( this.value );") + ); + $this->add('text', 'margin_left', ts('Left Margin'), array('size' => 8, 'maxlength' => 8), TRUE); + $this->add('text', 'margin_right', ts('Right Margin'), array('size' => 8, 'maxlength' => 8), TRUE); + $this->add('text', 'margin_top', ts('Top Margin'), array('size' => 8, 'maxlength' => 8), TRUE); + $this->add('text', 'margin_bottom', ts('Bottom Margin'), array('size' => 8, 'maxlength' => 8), TRUE); + $this->add('text', 'weight', ts('Weight'), CRM_Core_DAO::getAttribute('CRM_Core_BAO_PdfFormat', 'weight'), TRUE); + + $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array('CRM_Core_BAO_PdfFormat', $this->_id)); + $this->addRule('margin_left', ts('Margin must be numeric'), 'numeric'); + $this->addRule('margin_right', ts('Margin must be numeric'), 'numeric'); + $this->addRule('margin_top', ts('Margin must be numeric'), 'numeric'); + $this->addRule('margin_bottom', ts('Margin must be numeric'), 'numeric'); + $this->addRule('weight', ts('Weight must be integer'), 'integer'); + } + + function setDefaultValues() { + if ($this->_action & CRM_Core_Action::ADD) { + $defaults['weight'] = CRM_Utils_Array::value('weight', CRM_Core_BAO_PdfFormat::getDefaultValues(), 0); + } + else { + $defaults = $this->_values; + } + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + // delete PDF Page Format + CRM_Core_BAO_PdfFormat::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected PDF Page Format has been deleted.'), ts('Record Deleted'), 'success'); + return; + } + + $values = $this->controller->exportValues($this->getName()); + $values['is_default'] = isset($values['is_default']); + $bao = new CRM_Core_BAO_PdfFormat(); + $bao->savePdfFormat($values, $this->_id); + + $status = ts('Your new PDF Page Format titled %1 has been saved.', array(1 => $values['name']), ts('Saved'), 'success'); + if ($this->_action & CRM_Core_Action::UPDATE) { + $status = ts('Your PDF Page Format titled %1 has been updated.', array(1 => $values['name']), ts('Saved'), 'success'); + } + CRM_Core_Session::setStatus($status); + } +} diff --git a/CRM/Admin/Form/Persistent.php b/CRM/Admin/Form/Persistent.php new file mode 100644 index 0000000000..b7fb778770 --- /dev/null +++ b/CRM/Admin/Form/Persistent.php @@ -0,0 +1,101 @@ +_indexID = CRM_Utils_Request::retrieve('id', 'Integer', $this, FALSE); + $this->_config = CRM_Utils_Request::retrieve('config', 'Integer', $this, 0); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE); + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin/tplstrings', 'reset=1')); + CRM_Utils_System::setTitle(ts('DB Template Strings')); + parent::preProcess(); + } + + public function setDefaultValues() { + $defaults = array(); + + if ($this->_indexID && ($this->_action & (CRM_Core_Action::UPDATE))) { + $params = array('id' => $this->_indexID); + CRM_Core_BAO_Persistent::retrieve($params, $defaults); + if (CRM_Utils_Array::value('is_config', $defaults) == 1) { + $defaults['data'] = implode(',', $defaults['data']); + } + } + return $defaults; + } + + public function buildQuickForm() { + $this->add('text', 'context', ts('Context:'), NULL, TRUE); + $this->add('text', 'name', ts('Name:'), NULL, TRUE); + $this->add('textarea', 'data', ts('Data:'), array('rows' => 4, 'cols' => 50), TRUE); + $this->addButtons(array( + array( + 'type' => 'submit', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + public function postProcess() { + $params = $ids = array(); + $params = $this->controller->exportValues($this->_name); + + $params['is_config'] = $this->_config; + + if ($this->_action & CRM_Core_Action::ADD) { + CRM_Core_Session::setStatus(ts('DB Template has been added successfully.'), ts("Saved"), "success"); + } + if ($this->_action & CRM_Core_Action::UPDATE) { + $ids['persistent'] = $this->_indexID; + CRM_Core_Session::setStatus(ts('DB Template has been updated successfully.'), ts("Saved"), "success"); + } + CRM_Core_BAO_Persistent::add($params, $ids); + + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/tplstrings', "reset=1")); + } +} + diff --git a/CRM/Admin/Form/Preferences.php b/CRM/Admin/Form/Preferences.php new file mode 100644 index 0000000000..d96d6d74ee --- /dev/null +++ b/CRM/Admin/Form/Preferences.php @@ -0,0 +1,296 @@ +_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', + $this, FALSE + ); + $this->_system = CRM_Utils_Request::retrieve('system', 'Boolean', + $this, FALSE, TRUE + ); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 'update' + ); + if (isset($action)) { + $this->assign('action', $action); + } + + $session = CRM_Core_Session::singleton(); + + $this->_config = new CRM_Core_DAO(); + + if ($this->_system) { + if (CRM_Core_Permission::check('administer CiviCRM')) { + $this->_contactID = NULL; + } + else { + CRM_Utils_System::fatal('You do not have permission to edit preferences'); + } + $this->_config->contact_id = NULL; + } + else { + if (!$this->_contactID) { + $this->_contactID = $session->get('userID'); + if (!$this->_contactID) { + CRM_Utils_System::fatal('Could not retrieve contact id'); + } + $this->set('cid', $this->_contactID); + } + $this->_config->contact_id = $this->_contactID; + } + + foreach ($this->_varNames as $groupName => $settingNames) { + $values = CRM_Core_BAO_Setting::getItem($groupName); + foreach ($values as $name => $value) { + $this->_config->$name = $value; + } + } + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + } + + function setDefaultValues() { + $defaults = array(); + + foreach ($this->_varNames as $groupName => $settings) { + foreach ($settings as $settingName => $settingDetails) { + $defaults[$settingName] = isset($this->_config->$settingName) ? $this->_config->$settingName : CRM_Utils_Array::value('default', $settingDetails, NULL); + } + } + + return $defaults; + } + + function cbsDefaultValues(&$defaults) { + + foreach ($this->_varNames as $groupName => $groupValues) { + foreach ($groupValues as $settingName => $fieldValue) { + if ($fieldValue['html_type'] == 'checkboxes') { + if (isset($this->_config->$settingName) && + $this->_config->$settingName + ) { + $value = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($this->_config->$settingName, 1, -1) + ); + if (!empty($value)) { + $defaults[$settingName] = array(); + foreach ($value as $n => $v) { + $defaults[$settingName][$v] = 1; + } + } + } + } + } + } + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + + if (!empty($this->_varNames)) { + foreach ($this->_varNames as $groupName => $groupValues) { + $formName = CRM_Utils_String::titleToVar($groupName); + $this->assign('formName', $formName); + $fields = array(); + foreach ($groupValues as $fieldName => $fieldValue) { + $fields[$fieldName] = $fieldValue; + + switch ($fieldValue['html_type']) { + case 'text': + $this->addElement('text', + $fieldName, + $fieldValue['title'], + array( + 'maxlength' => 64, + 'size' => 32, + ) + ); + break; + + case 'textarea': + $this->addElement('textarea', + $fieldName, + $fieldValue['title'] + ); + break; + + case 'checkbox': + $this->addElement('checkbox', + $fieldName, + $fieldValue['title'] + ); + break; + + case 'checkboxes': + $options = array_flip(CRM_Core_OptionGroup::values($fieldName, FALSE, FALSE, TRUE)); + $newOptions = array(); + foreach ($options as $key => $val) { + $newOptions[$key] = $val; + } + $this->addCheckBox($fieldName, + $fieldValue['title'], + $newOptions, + NULL, NULL, NULL, NULL, + array('  ', '  ', '
') + ); + break; + } + } + + $fields = CRM_Utils_Array::crmArraySortByField($fields, 'weight'); + $this->assign('fields', $fields); + } + } + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + if ($this->_action == CRM_Core_Action::VIEW) { + $this->freeze(); + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $config = CRM_Core_Config::singleton(); + if ($this->_action == CRM_Core_Action::VIEW) { + return; + } + + $this->_params = $this->controller->exportValues($this->_name); + + $this->postProcessCommon(); + } + //end of function + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcessCommon() { + foreach ($this->_varNames as $groupName => $groupValues) { + foreach ($groupValues as $settingName => $fieldValue) { + switch ($fieldValue['html_type']) { + case 'checkboxes': + if (CRM_Utils_Array::value($settingName, $this->_params) && + is_array($this->_params[$settingName]) + ) { + $this->_config->$settingName = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($this->_params[$settingName]) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + } + else { + $this->_config->$settingName = NULL; + } + break; + + case 'checkbox': + $this->_config->$settingName = CRM_Utils_Array::value($settingName, $this->_params) ? 1 : 0; + break; + + case 'text': + case 'select': + $this->_config->$settingName = CRM_Utils_Array::value($settingName, $this->_params); + break; + + case 'textarea': + $value = CRM_Utils_Array::value($settingName, $this->_params); + if ($value) { + $value = trim($value); + $value = str_replace(array("\r\n", "\r"), "\n", $value); + } + $this->_config->$settingName = $value; + break; + } + } + } + + foreach ($this->_varNames as $groupName => $groupValues) { + foreach ($groupValues as $settingName => $fieldValue) { + $settingValue = isset($this->_config->$settingName) ? $this->_config->$settingName : NULL; + CRM_Core_BAO_Setting::setItem($settingValue, + $groupName, + $settingName + ); + } + } + + CRM_Core_Session::setStatus(ts('Your changes have been saved.'), ts('Saved'), 'success'); + } + +} + diff --git a/CRM/Admin/Form/Preferences/Address.php b/CRM/Admin/Form/Preferences/Address.php new file mode 100644 index 0000000000..76d3a70761 --- /dev/null +++ b/CRM/Admin/Form/Preferences/Address.php @@ -0,0 +1,237 @@ +_varNames = array( + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME => + array( + 'address_options' => array( + 'html_type' => 'checkboxes', + 'title' => ts('Address Fields'), + 'weight' => 1, + ), + 'address_format' => array( + 'html_type' => 'textarea', + 'title' => ts('Display Format'), + 'description' => NULL, + 'weight' => 2, + ), + 'mailing_format' => array( + 'html_type' => 'textarea', + 'title' => ts('Mailing Label Format'), + 'description' => NULL, + 'weight' => 3, + ), + ), + CRM_Core_BAO_Setting::ADDRESS_STANDARDIZATION_PREFERENCES_NAME => + array( + 'address_standardization_provider' => array( + 'html_type' => 'select', + 'weight' => 4, + ), + 'address_standardization_userid' => array( + 'html_type' => 'text', + 'title' => ts('User ID'), + 'description' => NULL, + 'weight' => 5, + ), + 'address_standardization_url' => array( + 'html_type' => 'text', + 'title' => ts('Web Service URL'), + 'description' => NULL, + 'weight' => 6, + ), + ), + ); + + parent::preProcess(); + } + + function setDefaultValues() { + $defaults = array(); + $defaults['address_standardization_provider'] = $this->_config->address_standardization_provider; + $defaults['address_standardization_userid'] = $this->_config->address_standardization_userid; + $defaults['address_standardization_url'] = $this->_config->address_standardization_url; + + + $this->addressSequence = isset($newSequence) ? $newSequence : ""; + + if (empty($this->_config->address_format)) { + $defaults['address_format'] = " +{contact.street_address} +{contact.supplemental_address_1} +{contact.supplemental_address_2} +{contact.city}{, }{contact.state_province}{ }{contact.postal_code} +{contact.country} +"; + } + else { + $defaults['address_format'] = $this->_config->address_format; + } + + if (empty($this->_config->mailing_format)) { + $defaults['mailing_format'] = " +{contact.addressee} +{contact.street_address} +{contact.supplemental_address_1} +{contact.supplemental_address_2} +{contact.city}{, }{contact.state_province}{ }{contact.postal_code} +{contact.country} +"; + } + else { + $defaults['mailing_format'] = $this->_config->mailing_format; + } + + + parent::cbsDefaultValues($defaults); + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->applyFilter('__ALL__', 'trim'); + + // Address Standardization + $addrProviders = CRM_Core_SelectValues::addressProvider(); + $this->addElement('select', + 'address_standardization_provider', + ts('Address Provider'), + array( + '' => '- select -') + $addrProviders + ); + + $this->addFormRule(array('CRM_Admin_Form_Preferences_Address', 'formRule')); + + //get the tokens for Mailing Label field + $tokens = CRM_Core_SelectValues::contactTokens(); + natcasesort($tokens); + $this->assign('tokens', json_encode($tokens)); + + $this->add('select', 'token1', ts('Insert Token'), + $tokens, FALSE, + array( + 'size' => "5", + 'multiple' => TRUE, + 'onclick' => "return tokenReplText(this);", + ) + ); + + parent::buildQuickForm(); + } + + static function formRule($fields) { + $p = $fields['address_standardization_provider']; + $u = $fields['address_standardization_userid']; + $w = $fields['address_standardization_url']; + + // make sure that there is a value for all of them + // if any of them are set + if ($p || $u || $w) { + if (!CRM_Utils_System::checkPHPVersion(5, FALSE)) { + $errors['_qf_default'] = ts('Address Standardization features require PHP version 5 or greater.'); + return $errors; + } + + if (!($p && $u && $w)) { + $errors['_qf_default'] = ts('You must provide values for all three Address Standarization fields.'); + return $errors; + } + } + + return TRUE; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action == CRM_Core_Action::VIEW) { + return; + } + + $this->_params = $this->controller->exportValues($this->_name); + + + // check if county option has been set + $options = CRM_Core_OptionGroup::values('address_options', FALSE, FALSE, TRUE); + foreach ($options as $key => $title) { + if ($title == ts('County')) { + // check if the $key is present in $this->_params + if (isset($this->_params['address_options']) && + !empty($this->_params['address_options'][$key]) + ) { + // print a status message to the user if county table seems small + $sql = " +SELECT count(*) +FROM civicrm_county +"; + $countyCount = CRM_Core_DAO::singleValueQuery($sql); + if ($countyCount < 10) { + global $civicrm_root; + $sqlFilePath = $civicrm_root . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR . 'counties.US.sql.gz'; + + CRM_Core_Session::setStatus("", ts('You have enabled the County option. Please ensure you populate the county table in your CiviCRM Database. You can find a list of US counties (in gzip format) in your distribution at: %1', + array(1 => $sqlFilePath)), + "info" + ); + } + } + } + } + + $this->postProcessCommon(); + } + //end of function +} + diff --git a/CRM/Admin/Form/Preferences/Campaign.php b/CRM/Admin/Form/Preferences/Campaign.php new file mode 100644 index 0000000000..aa1eb4c52c --- /dev/null +++ b/CRM/Admin/Form/Preferences/Campaign.php @@ -0,0 +1,64 @@ +_varNames = array( + CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME => + array( + 'tag_unconfirmed' => array( + 'html_type' => 'text', + 'title' => ts('Tag for Unconfirmed Petition Signers'), + 'weight' => 1, + 'description' => ts('If set, new contacts that are created when signing a petition are assigned a tag of this name.'), + ), + 'petition_contacts' => array( + 'html_type' => 'text', + 'title' => ts('Petition Signers Group'), + 'weight' => 2, + 'description' => ts('All contacts that have signed a CiviCampaign petition will be added to this group. The group will be created if it does not exist (it is required for email verification).'), + ), + ), + ); + + parent::preProcess(); + } +} + diff --git a/CRM/Admin/Form/Preferences/Display.php b/CRM/Admin/Form/Preferences/Display.php new file mode 100644 index 0000000000..5c30a2891e --- /dev/null +++ b/CRM/Admin/Form/Preferences/Display.php @@ -0,0 +1,230 @@ +_varNames = array( + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME => + array( + 'contact_view_options' => array( + 'html_type' => 'checkboxes', + 'title' => ts('Viewing Contacts'), + 'weight' => 1, + ), + 'contact_edit_options' => array( + 'html_type' => 'checkboxes', + 'title' => ts('Editing Contacts'), + 'weight' => 2, + ), + 'advanced_search_options' => array( + 'html_type' => 'checkboxes', + 'title' => ts('Contact Search'), + 'weight' => 3, + ), + 'activity_assignee_notification' => array( + 'html_type' => 'checkbox', + 'title' => ts('Notify Activity Assignees'), + 'weight' => 5, + ), + 'activity_assignee_notification_ics' => array( + 'html_type' => 'checkbox', + 'title' => ts('Include ICal Invite to Activity Assignees'), + 'weight' => 5, + ), + 'contact_ajax_check_similar' => array( + 'html_type' => 'checkbox', + 'title' => ts('Check for Similar Contacts'), + 'weight' => 5, + ), + 'user_dashboard_options' => array( + 'html_type' => 'checkboxes', + 'title' => ts('Contact Dashboard'), + 'weight' => 6, + ), + 'display_name_format' => array( + 'html_type' => 'textarea', + 'title' => ts('Individual Display Name Format'), + 'weight' => 7, + ), + 'sort_name_format' => array( + 'html_type' => 'textarea', + 'title' => ts('Individual Sort Name Format'), + 'weight' => 8, + ), + 'editor_id' => array( + 'html_type' => NULL, + 'weight' => 9, + ), + ), + ); + + + parent::preProcess(); + } + + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + parent::cbsDefaultValues($defaults); + + if ($this->_config->editor_id) { + $defaults['editor_id'] = $this->_config->editor_id; + } + if (empty($this->_config->display_name_format)) { + $defaults['display_name_format'] = "{contact.individual_prefix}{ }{contact.first_name}{ }{contact.last_name}{ }{contact.individual_suffix}"; + } + else { + $defaults['display_name_format'] = $this->_config->display_name_format; + } + + if (empty($this->_config->sort_name_format)) { + $defaults['sort_name_format'] = "{contact.last_name}{, }{contact.first_name}"; + } + else { + $defaults['sort_name_format'] = $this->_config->sort_name_format; + } + + $config = CRM_Core_Config::singleton(); + if ($config->userSystem->is_drupal == '1' && + module_exists("wysiwyg") + ) { + $defaults['wysiwyg_input_format'] = variable_get('civicrm_wysiwyg_input_format', 0); + } + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $drupal_wysiwyg = FALSE; + $wysiwyg_options = array('' => ts('Textarea')) + CRM_Core_PseudoConstant::wysiwygEditor(); + + $config = CRM_Core_Config::singleton(); + $extra = array(); + + //if not using Joomla, remove Joomla default editor option + if ($config->userFramework != 'Joomla') { + unset($wysiwyg_options[3]); + } + + $drupal_wysiwyg = FALSE; + if (!$config->userSystem->is_drupal || + !module_exists("wysiwyg") + ) { + unset($wysiwyg_options[4]); + } + else { + $extra['onchange'] = 'if (this.value==4) { cj("#crm-preferences-display-form-block-wysiwyg_input_format").show(); } else { cj("#crm-preferences-display-form-block-wysiwyg_input_format").hide() }'; + + $formats = filter_formats(); + $format_options = array(); + foreach ($formats as $id => $format) { + $format_options[$id] = $format->name; + } + $drupal_wysiwyg = TRUE; + } + $this->addElement('select', 'editor_id', ts('WYSIWYG Editor'), $wysiwyg_options, $extra); + + if ($drupal_wysiwyg) { + $this->addElement('select', 'wysiwyg_input_format', ts('Input Format'), $format_options, NULL); + } + $editOptions = CRM_Core_OptionGroup::values('contact_edit_options', FALSE, FALSE, FALSE, 'AND v.filter = 0'); + $this->assign('editOptions', $editOptions); + + $contactBlocks = CRM_Core_OptionGroup::values('contact_edit_options', FALSE, FALSE, FALSE, 'AND v.filter = 1'); + $this->assign('contactBlocks', $contactBlocks); + + $this->addElement('hidden', 'contact_edit_preferences', NULL, array('id' => 'contact_edit_preferences')); + + parent::buildQuickForm(); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action == CRM_Core_Action::VIEW) { + return; + } + + $this->_params = $this->controller->exportValues($this->_name); + + if (CRM_Utils_Array::value('contact_edit_preferences', $this->_params)) { + $preferenceWeights = explode(',', $this->_params['contact_edit_preferences']); + foreach ($preferenceWeights as $key => $val) { + if (!$val) { + unset($preferenceWeights[$key]); + } + } + $opGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'contact_edit_options', 'id', 'name'); + CRM_Core_BAO_OptionValue::updateOptionWeights($opGroupId, array_flip($preferenceWeights)); + } + + $config = CRM_Core_Config::singleton(); + if ($config->userSystem->is_drupal == '1' && + module_exists("wysiwyg") + ) { + variable_set('civicrm_wysiwyg_input_format', $this->_params['wysiwyg_input_format']); + } + + $this->_config->editor_id = $this->_params['editor_id']; + + // set default editor to session if changed + $session = CRM_Core_Session::singleton(); + $session->set('defaultWysiwygEditor', $this->_params['editor_id']); + + $this->postProcessCommon(); + } + //end of function +} + diff --git a/CRM/Admin/Form/Preferences/Event.php b/CRM/Admin/Form/Preferences/Event.php new file mode 100644 index 0000000000..24341fa30d --- /dev/null +++ b/CRM/Admin/Form/Preferences/Event.php @@ -0,0 +1,61 @@ +_varNames = array( + CRM_Core_BAO_Setting::EVENT_PREFERENCES_NAME => + array( + 'enable_cart' => array( + 'html_type' => 'checkbox', + 'title' => ts('Use Shopping Cart Style Event Registration'), + 'weight' => 1, + 'description' => ts('This feature allows users to register for more than one event at a time. When enabled, users will add event(s) to a "cart" and then pay for them all at once. Enabling this setting will affect online registration for all active events. The code is an alpha state, and you will potentially need to have developer resources to debug and fix sections of the codebase while testing and deploying it. %1', + array(1 => $docLink)), + ), + ), + ); + + parent::preProcess(); + } +} + diff --git a/CRM/Admin/Form/Preferences/Mailing.php b/CRM/Admin/Form/Preferences/Mailing.php new file mode 100644 index 0000000000..1154bdddae --- /dev/null +++ b/CRM/Admin/Form/Preferences/Mailing.php @@ -0,0 +1,101 @@ +_varNames = array( + CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME => + array( + 'profile_double_optin' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Enable Double Opt-in for Profile Group(s) field'), + 'weight' => 1, + 'description' => ts('When CiviMail is enabled, users who "subscribe" to a group from a profile Group(s) checkbox will receive a confirmation email. They must respond (opt-in) before they are added to the group.'), + ), + 'profile_add_to_group_double_optin' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Enable Double Opt-in for Profiles which use the "Add to Group" setting'), + 'weight' => 2, + 'description' => ts('When CiviMail is enabled and a profile uses the "Add to Group" setting, users who complete the profile form will receive a confirmation email. They must respond (opt-in) before they are added to the group.'), + ), + 'track_civimail_replies' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Track replies using VERP in Reply-To header'), + 'weight' => 3, + 'description' => ts('If checked, mailings will default to tracking replies using VERP-ed Reply-To.'), + ), + 'civimail_workflow' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Enable workflow support for CiviMail'), + 'weight' => 4, + 'description' => ts('Drupal-only. Rules module must be enabled (beta feature - use with caution).'), + ), + 'civimail_multiple_bulk_emails' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Enable multiple bulk email address for a contact.'), + 'weight' => 5, + 'description' => ts('CiviMail will deliver a copy of the email to each bulk email listed for the contact.'), + ), + 'civimail_server_wide_lock' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Enable global server wide lock for CiviMail'), + 'weight' => 6, + 'description' => NULL, + ), + 'include_message_id' => + array( + 'html_type' => 'checkbox', + 'title' => ts('Enable CiviMail to generate Message-ID header'), + 'weight' => 7, + 'description' => NULL, + ), + ), + ); + + parent::preProcess(); + } +} + diff --git a/CRM/Admin/Form/Preferences/Member.php b/CRM/Admin/Form/Preferences/Member.php new file mode 100644 index 0000000000..6be059899b --- /dev/null +++ b/CRM/Admin/Form/Preferences/Member.php @@ -0,0 +1,76 @@ +_varNames = array( + CRM_Core_BAO_Setting::MEMBER_PREFERENCES_NAME => + array( + 'default_renewal_contribution_page' => array( + 'html_type' => 'select', + 'title' => ts('Default online membership renewal page'), + 'weight' => 1, + 'description' => ts('If you select a default online contribution page for self-service membership renewals, a "renew" link pointing to that page will be displayed on the Contact Dashboard for memberships which were entered offline. You will need to ensure that the membership block for the selected online contribution page includes any currently available memberships.'), + ), + ), + ); + + parent::preProcess(); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + function buildQuickForm() { + + $this->add('select', 'default_renewal_contribution_page', + ts('Default Online Membership Renewal Page'), + array( + '' => ts('- select -')) + + CRM_Contribute_PseudoConstant::contributionPage() + ); + + parent::buildQuickForm(); + } +} + diff --git a/CRM/Admin/Form/Preferences/Multisite.php b/CRM/Admin/Form/Preferences/Multisite.php new file mode 100644 index 0000000000..63c35f2ef6 --- /dev/null +++ b/CRM/Admin/Form/Preferences/Multisite.php @@ -0,0 +1,77 @@ +_varNames = array( + CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME => + array( + 'is_enabled' => array( + 'html_type' => 'checkbox', + 'title' => ts('Enable Multi Site Configuration'), + 'weight' => 1, + 'description' => ts('Multi Site provides support for sharing a single CiviCRM database among multiple sites.') . ' ' . $msDoc, + ), + 'uniq_email_per_site' => array( + 'html_type' => 'checkbox', + 'title' => ts('Ensure multi sites have a unique email per site'), + 'weight' => 2, + 'description' => NULL, + ), + 'domain_group_id' => array( + 'html_type' => 'text', + 'title' => ts('Parent group for this domain'), + 'weight' => 3, + 'description' => ts('Enter the group ID (civicrm_group.id).'), + ), + 'event_price_set_domain_id' => array( + 'html_type' => 'text', + 'title' => ts('Domain for event price sets'), + 'weight' => 4, + 'description' => NULL, + ), + ), + ); + + parent::preProcess(); + } +} + diff --git a/CRM/Admin/Form/PreferencesDate.php b/CRM/Admin/Form/PreferencesDate.php new file mode 100644 index 0000000000..1223878f98 --- /dev/null +++ b/CRM/Admin/Form/PreferencesDate.php @@ -0,0 +1,142 @@ +_action & CRM_Core_Action::DELETE) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_PreferencesDate'); + + $this->applyFilter('__ALL__', 'trim'); + $name = &$this->add('text', + 'name', + ts('Name'), + $attributes['name'], + TRUE + ); + $name->freeze(); + + $this->add('text', 'description', ts('Description'), $attributes['description'], FALSE); + $this->add('text', 'start', ts('Start Offset'), $attributes['start'], TRUE); + $this->add('text', 'end', ts('End Offset'), $attributes['end'], TRUE); + + $formatType = CRM_Core_Dao::getFieldValue('CRM_Core_DAO_PreferencesDate', $this->_id, 'name'); + + if ($formatType == 'creditCard') { + $this->add('text', 'date_format', ts('Format'), $attributes['date_format'], TRUE); + } + else { + $this->add('select', 'date_format', ts('Format'), + array('' => ts('- default input format -')) + CRM_Core_SelectValues::getDatePluginInputFormats() + ); + $this->add('select', 'time_format', ts('Time'), + array('' => ts('- none -')) + CRM_Core_SelectValues::getTimeFormats() + ); + } + $this->addRule('start', ts('Value must be an integer.'), 'integer'); + $this->addRule('end', ts('Value must be an integer.'), 'integer'); + + // add a form rule + $this->addFormRule(array('CRM_Admin_Form_PreferencesDate', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields (referance) posted values of the form + * + * @return array if errors then list of errors to be posted back to the form, + * true otherwise + * @static + * @access public + */ + static function formRule($fields) { + $errors = array(); + + if ($fields['name'] == 'activityDateTime' && !$fields['time_format']) { + $errors['time_format'] = ts('Time is required for this format.'); + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if (!($this->_action & CRM_Core_Action::UPDATE)) { + CRM_Core_Session::setStatus(ts('Preferences Date Options can only be updated'), ts('Sorry'), 'error'); + return; + } + + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + // action is taken depending upon the mode + $dao = new CRM_Core_DAO_PreferencesDate(); + $dao->id = $this->_id; + $dao->description = $params['description']; + $dao->start = $params['start']; + $dao->end = $params['end']; + $dao->date_format = $params['date_format']; + $dao->time_format = $params['time_format']; + + $dao->save(); + + CRM_Core_Session::setStatus(ts("The date type '%1' has been saved.", + array(1 => $params['name']) + ), ts('Saved'), 'success'); + } +} diff --git a/CRM/Admin/Form/RelationshipType.php b/CRM/Admin/Form/RelationshipType.php new file mode 100644 index 0000000000..55422790ab --- /dev/null +++ b/CRM/Admin/Form/RelationshipType.php @@ -0,0 +1,177 @@ +_action & CRM_Core_Action::DELETE) { + + return; + } + + $this->applyFilter('__ALL__', 'trim'); + + $this->add('text', 'label_a_b', ts('Relationship Label-A to B'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_RelationshipType', 'label_a_b'), TRUE + ); + $this->addRule('label_a_b', ts('Label already exists in Database.'), + 'objectExists', array('CRM_Contact_DAO_RelationshipType', $this->_id, 'label_a_b') + ); + + $this->add('text', 'label_b_a', ts('Relationship Label-B to A'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_RelationshipType', 'label_b_a') + ); + + $this->addRule('label_b_a', ts('Label already exists in Database.'), + 'objectExists', array('CRM_Contact_DAO_RelationshipType', $this->_id, 'label_b_a') + ); + + $this->add('text', 'description', ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_RelationshipType', 'description') + ); + + + + $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(); + + // add select for contact type + $contactTypeA = &$this->add('select', 'contact_types_a', ts('Contact Type A') . ' ', + array( + '' => ts('All Contacts')) + $contactTypes + ); + $contactTypeB = &$this->add('select', 'contact_types_b', ts('Contact Type B') . ' ', + array( + '' => ts('All Contacts')) + $contactTypes + ); + + $isActive = &$this->add('checkbox', 'is_active', ts('Enabled?')); + + //only selected field should be allow for edit, CRM-4888 + if ($this->_id && + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', $this->_id, 'is_reserved') + ) { + foreach (array('contactTypeA', 'contactTypeB', 'isActive') as $field)$$field->freeze(); + } + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->freeze(); + $url = CRM_Utils_System::url('civicrm/admin/reltype&reset=1'); + $location = "window.location='$url'"; + $this->addElement('button', 'done', ts('Done'), array('onclick' => $location)); + } + } + + function setDefaultValues() { + if ($this->_action != CRM_Core_Action::DELETE && + isset($this->_id) + ) { + $defaults = $params = array(); + $params = array('id' => $this->_id); + eval($this->_BAOName . '::retrieve( $params, $defaults );'); + $defaults['contact_types_a'] = CRM_Utils_Array::value('contact_type_a', $defaults); + if (CRM_Utils_Array::value('contact_sub_type_a', $defaults)) { + $defaults['contact_types_a'] .= CRM_Core_DAO::VALUE_SEPARATOR . $defaults['contact_sub_type_a']; + } + + $defaults['contact_types_b'] = $defaults['contact_type_b']; + if (CRM_Utils_Array::value('contact_sub_type_b', $defaults)) { + $defaults['contact_types_b'] .= CRM_Core_DAO::VALUE_SEPARATOR . $defaults['contact_sub_type_b']; + } + return $defaults; + } + else { + return parent::setDefaultValues(); + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Contact_BAO_RelationshipType::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected Relationship type has been deleted.'), ts('Record Deleted'), 'success'); + } + else { + $params = array(); + $ids = array(); + + // store the submitted values in an array + $params = $this->exportValues(); + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $ids['relationshipType'] = $this->_id; + } + + $cTypeA = CRM_Utils_System::explode(CRM_Core_DAO::VALUE_SEPARATOR, + $params['contact_types_a'], + 2 + ); + $cTypeB = CRM_Utils_System::explode(CRM_Core_DAO::VALUE_SEPARATOR, + $params['contact_types_b'], + 2 + ); + + $params['contact_type_a'] = $cTypeA[0]; + $params['contact_type_b'] = $cTypeB[0]; + + $params['contact_sub_type_a'] = $cTypeA[1] ? $cTypeA[1] : 'NULL'; + $params['contact_sub_type_b'] = $cTypeB[1] ? $cTypeB[1] : 'NULL'; + + CRM_Contact_BAO_RelationshipType::add($params, $ids); + + CRM_Core_Session::setStatus(ts('The Relationship Type has been saved.'), ts('Saved'), 'success'); + } + } + //end of function +} + diff --git a/CRM/Admin/Form/ScheduleReminders.php b/CRM/Admin/Form/ScheduleReminders.php new file mode 100644 index 0000000000..aa7bfa5606 --- /dev/null +++ b/CRM/Admin/Form/ScheduleReminders.php @@ -0,0 +1,486 @@ +_mappingID = $mappingID = NULL; + + if ($this->_action & (CRM_Core_Action::DELETE)) { + $reminderName = + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionSchedule', $this->_id, 'title'); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + if ($this->_context == 'event') { + $this->_eventId = CRM_Utils_Request::retrieve('eventId', 'Integer', $this); + } + $this->assign('reminderName', $reminderName); + return; + } + elseif ($this->_action & (CRM_Core_Action::UPDATE)) { + $this->_mappingID = + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionSchedule', $this->_id, 'mapping_id'); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + if ($this->_context == 'event') { + $this->_eventId = CRM_Utils_Request::retrieve('eventId', 'Integer', $this); + } + } + + if (!empty($_POST) && CRM_Utils_Array::value('entity', $_POST)) { + $mappingID = $_POST['entity'][0]; + } + elseif ($this->_mappingID) { + $mappingID = $this->_mappingID; + } + + $this->add( + 'text', + 'title', + ts('Title'), + array('size' => 45, 'maxlength' => 128), + TRUE + ); + + $selectionOptions = CRM_Core_BAO_ActionSchedule::getSelection($mappingID); + extract($selectionOptions); + + if (empty($sel1)) { + CRM_Core_Error::fatal('Could not find mapping for scheduled reminders.'); + } + $this->assign('entityMapping', json_encode($entityMapping)); + $this->assign('recipientMapping', json_encode($recipientMapping)); + + $sel = &$this->add( + 'hierselect', + 'entity', + ts('Entity'), + array( + 'name' => 'entity[0]', + 'style' => 'vertical-align: top;', + ), + TRUE + ); + $sel->setOptions(array($sel1, $sel2, $sel3)); + + if (is_a($sel->_elements[1], 'HTML_QuickForm_select')) { + // make second selector a multi-select - + $sel->_elements[1]->setMultiple(TRUE); + $sel->_elements[1]->setSize(5); + } + + if (is_a($sel->_elements[2], 'HTML_QuickForm_select')) { + // make third selector a multi-select - + $sel->_elements[2]->setMultiple(TRUE); + $sel->_elements[2]->setSize(5); + } + + //get the frequency units. + $this->_freqUnits = array('hour' => 'hour') + CRM_Core_OptionGroup::values('recur_frequency_units'); + + //pass the mapping ID in UPDATE mode + $mappings = CRM_Core_BAO_ActionSchedule::getMapping($mappingID); + + $numericOptions = CRM_Core_SelectValues::getNumericOptions(0, 30); + + //reminder_interval + $this->add('select', 'start_action_offset', ts('When'), $numericOptions); + + foreach ($this->_freqUnits as $val => $label) { + $freqUnitsDisplay[$val] = ts('%1(s)', array(1 => $label)); + } + + $this->addDate('absolute_date', ts('Start Date'), FALSE, array('formatType' => 'mailing')); + + //reminder_frequency + $this->add('select', 'start_action_unit', ts('Frequency'), $freqUnitsDisplay, TRUE); + + $condition = array('before' => ts('before'), + 'after' => ts('after'), + ); + //reminder_action + $this->add('select', 'start_action_condition', ts('Action Condition'), $condition); + + $this->add('select', 'start_action_date', ts('Date Field'), $sel4, TRUE); + + $this->addElement('checkbox', 'record_activity', ts('Record activity for automated email')); + + $this->addElement('checkbox', 'is_repeat', ts('Repeat'), + NULL, array('onclick' => "return showHideByValue('is_repeat',true,'repeatFields','table-row','radio',false);") + ); + + $this->add('select', 'repetition_frequency_unit', ts('every'), $freqUnitsDisplay); + $this->add('select', 'repetition_frequency_interval', ts('every'), $numericOptions); + $this->add('select', 'end_frequency_unit', ts('until'), $freqUnitsDisplay); + $this->add('select', 'end_frequency_interval', ts('until'), $numericOptions); + $this->add('select', 'end_action', ts('Repetition Condition'), $condition, TRUE); + $this->add('select', 'end_date', ts('Date Field'), $sel4, TRUE); + + $recipient = 'activity_contacts'; + $recipientListingOptions = array(); + + if ($mappingID) { + $recipient = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionMapping', + $mappingID, + 'entity_recipient' + ); + } + + $this->add('select', 'recipient', ts('Recipient(s)'), $sel5[$recipient], + FALSE, array('onClick' => "showHideByValue('recipient','manual','recipientManual','table-row','select',false); showHideByValue('recipient','group','recipientGroup','table-row','select',false);") + ); + + if (CRM_Utils_Array::value('is_recipient_listing', $_POST)) { + $recipientListingOptions = CRM_Core_BAO_ActionSchedule::getRecipientListing($_POST['entity'][0], $_POST['recipient']); + } + elseif (CRM_Utils_Array::value('recipient_listing', $this->_values)) { + $recipientListingOptions = CRM_Core_BAO_ActionSchedule::getRecipientListing($this->_values['mapping_id'], $this->_values['recipient']); + } + $recipientListing = $this->add('select', 'recipient_listing', ts('Recipient Listing'), $recipientListingOptions); + $recipientListing->setMultiple(TRUE); + $this->add('hidden', 'is_recipient_listing', empty($recipientListingOptions) ? FALSE : TRUE, array('id' => 'is_recipient_listing')); + + //autocomplete url + $dataUrl = CRM_Utils_System::url('civicrm/ajax/rest', + 'className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&context=activity&reset=1', + FALSE, NULL, FALSE + ); + + $this->assign('dataUrl', $dataUrl); + //tokeninput url + $tokenUrl = CRM_Utils_System::url('civicrm/ajax/checkemail', + 'noemail=1', + FALSE, NULL, FALSE + ); + $this->assign('tokenUrl', $tokenUrl); + $this->add('text', 'recipient_manual_id', ts('Manual Recipients')); + + $this->addElement('select', 'group_id', ts('Group'), + CRM_Core_PseudoConstant::staticGroup() + ); + + CRM_Mailing_BAO_Mailing::commonCompose($this); + + $this->add('text', 'subject', ts('Subject'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_ActionSchedule', 'subject') + ); + + $this->add('checkbox', 'is_active', ts('Send email')); + + $this->addFormRule(array('CRM_Admin_Form_ScheduleReminders', 'formRule')); + } + /** + * global form rule + * + * @param array $fields the input form values + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields) { + $errors = array(); + if ((array_key_exists(1, $fields['entity']) && $fields['entity'][1][0] == 0) || + (array_key_exists(2, $fields['entity']) && $fields['entity'][2][0] == 0) + ) { + $errors['entity'] = ts('Please select appropriate value'); + } + + if (CRM_Utils_Array::value('is_active', $fields) && + CRM_Utils_System::isNull($fields['subject']) + ) { + $errors['subject'] = ts('Subject is a required field.'); + } + + if (CRM_Utils_System::isNull(CRM_Utils_Array::value(1, $fields['entity']))) { + $errors['entity'] = ts('Please select entity value'); + } + + if (!CRM_Utils_System::isNull($fields['absolute_date'])) { + if (CRM_Utils_Date::format(CRM_Utils_Date::processDate($fields['absolute_date'], NULL)) < CRM_Utils_Date::format(date('YmdHi00'))) { + $errors['absolute_date'] = ts('Absolute date cannot be earlier than the current time.'); + } + } + + if (!empty($errors)) { + return $errors; + } + + return empty($errors) ? TRUE : $errors; + } + + function setDefaultValues() { + if ($this->_action & CRM_Core_Action::ADD) { + $defaults['is_active'] = 1; + $defaults['record_activity'] = 1; + } + else { + $defaults = $this->_values; + $entityValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, + CRM_Utils_Array::value('entity_value', $defaults) + ); + $entityStatus = explode(CRM_Core_DAO::VALUE_SEPARATOR, + CRM_Utils_Array::value('entity_status', $defaults) + ); + $defaults['entity'][0] = CRM_Utils_Array::value('mapping_id', $defaults); + $defaults['entity'][1] = $entityValue; + $defaults['entity'][2] = $entityStatus; + if ($absoluteDate = CRM_Utils_Array::value('absolute_date', $defaults)) { + list($date, $time) = CRM_Utils_Date::setDateDefaults($absoluteDate); + $defaults['absolute_date'] = $date; + } + + if ($recipientListing = CRM_Utils_Array::value('recipient_listing', $defaults)) { + $defaults['recipient_listing'] = explode(CRM_Core_DAO::VALUE_SEPARATOR, + $recipientListing + ); + } + $defaults['text_message'] = CRM_Utils_Array::value('body_text', $defaults); + $defaults['html_message'] = CRM_Utils_Array::value('body_html', $defaults); + $defaults['template'] = CRM_Utils_Array::value('msg_template_id', $defaults); + if (CRM_Utils_Array::value('group_id', $defaults)) { + $defaults['recipient'] = 'group'; + } + elseif (CRM_Utils_Array::value('recipient_manual', $defaults)) { + $defaults['recipient'] = 'manual'; + $recipients = array(); + foreach (explode(',', $defaults['recipient_manual']) as $cid) { + $recipients[$cid] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $cid, + 'sort_name' + ); + } + $this->assign('recipients', $recipients); + } + } + + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + if ($this->_action & CRM_Core_Action::DELETE) { + // delete reminder + CRM_Core_BAO_ActionSchedule::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected Reminder has been deleted.'), ts('Record Deleted'), 'success'); + if ($this->_context == 'event' && $this->_eventId) { + $url = CRM_Utils_System::url('civicrm/event/manage/reminder', + "reset=1&action=update&id={$this->_eventId}" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + return; + } + $values = $this->controller->exportValues($this->getName()); + + $keys = array( + 'title', + 'subject', + 'absolute_date', + 'group_id', + 'record_activity' + ); + foreach ($keys as $key) { + $params[$key] = CRM_Utils_Array::value($key, $values); + } + + $moreKeys = array( + 'start_action_offset', 'start_action_unit', + 'start_action_condition', 'start_action_date', + 'repetition_frequency_unit', + 'repetition_frequency_interval', + 'end_frequency_unit', + 'end_frequency_interval', + 'end_action', 'end_date', + ); + + if ($absoluteDate = CRM_Utils_Array::value('absolute_date', $params)) { + $params['absolute_date'] = CRM_Utils_Date::processDate($absoluteDate); + foreach ($moreKeys as $mkey) { + $params[$mkey] = 'null'; + } + } + else { + $params['absolute_date'] = 'null'; + foreach ($moreKeys as $mkey) { + $params[$mkey] = CRM_Utils_Array::value($mkey, $values); + } + } + + $params['body_text'] = CRM_Utils_Array::value('text_message', $values); + $params['body_html'] = CRM_Utils_Array::value('html_message', $values); + + if (CRM_Utils_Array::value('recipient', $values) == 'manual') { + $params['recipient_manual'] = CRM_Utils_Array::value('recipient_manual_id', $values); + $params['group_id'] = $params['recipient'] = $params['recipient_listing'] = 'null'; + } + elseif (CRM_Utils_Array::value('recipient', $values) == 'group') { + $params['group_id'] = $values['group_id']; + $params['recipient_manual'] = $params['recipient'] = $params['recipient_listing'] = 'null'; + } + elseif (!CRM_Utils_System::isNull($values['recipient_listing'])) { + $params['recipient'] = CRM_Utils_Array::value('recipient', $values); + $params['recipient_listing'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, + CRM_Utils_Array::value('recipient_listing', $values) + ); + $params['group_id'] = $params['recipient_manual'] = 'null'; + } + else { + $params['recipient'] = CRM_Utils_Array::value('recipient', $values); + $params['group_id'] = $params['recipient_manual'] = $params['recipient_listing'] = 'null'; + } + + $params['mapping_id'] = $values['entity'][0]; + $entity_value = $values['entity'][1]; + $entity_status = $values['entity'][2]; + + foreach (array( + 'entity_value', 'entity_status') as $key) { + $params[$key] = implode(CRM_Core_DAO::VALUE_SEPARATOR, $$key); + } + + $params['is_active'] = CRM_Utils_Array::value('is_active', $values, 0); + $params['is_repeat'] = CRM_Utils_Array::value('is_repeat', $values, 0); + + if (CRM_Utils_Array::value('is_repeat', $values) == 0) { + $params['repetition_frequency_unit'] = 'null'; + $params['repetition_frequency_interval'] = 'null'; + $params['end_frequency_unit'] = 'null'; + $params['end_frequency_interval'] = 'null'; + $params['end_action'] = 'null'; + $params['end_date'] = 'null'; + } + + if ($this->_action & CRM_Core_Action::UPDATE) { + $params['id'] = $this->_id; + } + elseif ($this->_action & CRM_Core_Action::ADD) { + // we do this only once, so name never changes + $params['name'] = CRM_Utils_String::munge($params['title'], '_', 64); + } + + $composeFields = array( + 'template', 'saveTemplate', + 'updateTemplate', 'saveTemplateName', + ); + $msgTemplate = NULL; + //mail template is composed + + $composeParams = array(); + foreach ($composeFields as $key) { + if (CRM_Utils_Array::value($key, $values)) { + $composeParams[$key] = $values[$key]; + } + } + + if (CRM_Utils_Array::value('updateTemplate', $composeParams)) { + $templateParams = array( + 'msg_text' => $params['body_text'], + 'msg_html' => $params['body_html'], + 'msg_subject' => $params['subject'], + 'is_active' => TRUE, + ); + + $templateParams['id'] = $values['template']; + + $msgTemplate = CRM_Core_BAO_MessageTemplates::add($templateParams); + } + + if (CRM_Utils_Array::value('saveTemplate', $composeParams)) { + $templateParams = array( + 'msg_text' => $params['body_text'], + 'msg_html' => $params['body_html'], + 'msg_subject' => $params['subject'], + 'is_active' => TRUE, + ); + + $templateParams['msg_title'] = $composeParams['saveTemplateName']; + + $msgTemplate = CRM_Core_BAO_MessageTemplates::add($templateParams); + } + + if (isset($msgTemplate->id)) { + $params['msg_template_id'] = $msgTemplate->id; + } + else { + $params['msg_template_id'] = CRM_Utils_Array::value('template', $values); + } + + CRM_Core_BAO_ActionSchedule::add($params, $ids); + + $status = ts("Your new Reminder titled %1 has been saved.", + array(1 => "{$values['title']}") + ); + if ($this->_action & CRM_Core_Action::UPDATE) { + $status = ts("Your Reminder titled %1 has been updated.", + array(1 => "{$values['title']}") + ); + + if ($this->_context == 'event' && $this->_eventId) { + $url = CRM_Utils_System::url('civicrm/event/manage/reminder', + "reset=1&action=update&id={$this->_eventId}" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + } + CRM_Core_Session::setStatus($status, ts('Saved'), 'success'); + } +} + diff --git a/CRM/Admin/Form/Setting.php b/CRM/Admin/Form/Setting.php new file mode 100644 index 0000000000..16b9db876b --- /dev/null +++ b/CRM/Admin/Form/Setting.php @@ -0,0 +1,283 @@ +_defaults) { + $this->_defaults = array(); + $formArray = array('Component', 'Localization'); + $formMode = FALSE; + if (in_array($this->_name, $formArray)) { + $formMode = TRUE; + } + + CRM_Core_BAO_ConfigSetting::retrieve($this->_defaults); + + CRM_Core_Config_Defaults::setValues($this->_defaults, $formMode); + + $list = array_flip(CRM_Core_OptionGroup::values('contact_autocomplete_options', + FALSE, FALSE, TRUE, NULL, 'name' + )); + + $cRlist = array_flip(CRM_Core_OptionGroup::values('contact_reference_options', + FALSE, FALSE, TRUE, NULL, 'name' + )); + + $listEnabled = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_autocomplete_options' + ); + $cRlistEnabled = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_reference_options' + ); + + $autoSearchFields = array(); + if (!empty($list) && !empty($listEnabled)) { + $autoSearchFields = array_combine($list, $listEnabled); + } + + $cRSearchFields = array(); + if (!empty($cRlist) && !empty($cRlistEnabled)) { + $cRSearchFields = array_combine($cRlist, $cRlistEnabled); + } + + //Set defaults for autocomplete and contact reference options + $this->_defaults['autocompleteContactSearch'] = array( + '1' => 1) + $autoSearchFields; + $this->_defaults['autocompleteContactReference'] = array( + '1' => 1) + $cRSearchFields; + + // we can handle all the ones defined in the metadata here. Others to be converted + foreach ($this->_settings as $setting => $group){ + $settingMetaData = civicrm_api('setting', 'getfields', array('version' => 3, 'name' => $setting)); + $this->_defaults[$setting] = civicrm_api('setting', 'getvalue', array( + 'version' => 3, + 'name' => $setting, + 'group' => $group, + 'default_value' => CRM_Utils_Array::value('default', $settingMetaData['values'][$setting]) + ) + ); + } + + $this->_defaults['enableSSL'] = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enableSSL', NULL, 0); + $this->_defaults['verifySSL'] = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL', NULL, 1); + + $sql = " +SELECT time_format +FROM civicrm_preferences_date +WHERE time_format IS NOT NULL +AND time_format <> '' +LIMIT 1 +"; + $this->_defaults['timeInputFormat'] = CRM_Core_DAO::singleValueQuery($sql); + } + + return $this->_defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + $args = func_get_args(); + $check = reset($args); + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + foreach ($this->_settings as $setting => $group){ + $settingMetaData = civicrm_api('setting', 'getfields', array('version' => 3, 'name' => $setting)); + if(isset($settingMetaData['values'][$setting]['quick_form_type'])){ + $add = 'add' . $settingMetaData['values'][$setting]['quick_form_type']; + if($add == 'addElement'){ + $this->$add( + $settingMetaData['values'][$setting]['html_type'], + $setting, + ts($settingMetaData['values'][$setting]['title']), + CRM_Utils_Array::value('html_attributes', $settingMetaData['values'][$setting], array()) + ); + } + else{ + $this->$add($setting, ts($settingMetaData['values'][$setting]['title'])); + } + $this->assign("{$setting}_description", ts($settingMetaData['values'][$setting]['description'])); + if($setting == 'max_attachments'){ + //temp hack @todo fix to get from metadata + $this->addRule('max_attachments', ts('Value should be a positive number'), 'positiveInteger'); + } + if($setting == 'maxFileSize'){ + //temp hack + $this->addRule('maxFileSize', ts('Value should be a positive number'), 'positiveInteger'); + } + + } + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + self::commonProcess($params); + } + + public function commonProcess(&$params) { + + // save autocomplete search options + if (CRM_Utils_Array::value('autocompleteContactSearch', $params)) { + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($params['autocompleteContactSearch']) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + + CRM_Core_BAO_Setting::setItem($value, + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_autocomplete_options' + ); + + unset($params['autocompleteContactSearch']); + } + + // save autocomplete contact reference options + if (CRM_Utils_Array::value('autocompleteContactReference', $params)) { + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($params['autocompleteContactReference']) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + + CRM_Core_BAO_Setting::setItem($value, + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_reference_options' + ); + + unset($params['autocompleteContactReference']); + } + + // save checksum timeout + if (CRM_Utils_Array::value('checksumTimeout', $params)) { + CRM_Core_BAO_Setting::setItem($params['checksumTimeout'], + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'checksum_timeout' + ); + } + + // update time for date formats when global time is changed + if (CRM_Utils_Array::value('timeInputFormat', $params)) { + $query = " +UPDATE civicrm_preferences_date +SET time_format = %1 +WHERE time_format IS NOT NULL +AND time_format <> '' +"; + $sqlParams = array(1 => array($params['timeInputFormat'], 'String')); + CRM_Core_DAO::executeQuery($query, $sqlParams); + + unset($params['timeInputFormat']); + } + + // verify ssl peer option + if (isset($params['verifySSL'])) { + CRM_Core_BAO_Setting::setItem($params['verifySSL'], + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'verifySSL' + ); + unset($params['verifySSL']); + } + + // force secure URLs + if (isset($params['enableSSL'])) { + CRM_Core_BAO_Setting::setItem($params['enableSSL'], + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'enableSSL' + ); + unset($params['enableSSL']); + } + $settings = array_intersect_key($params, $this->_settings); + $result = civicrm_api('setting', 'create', $settings + array('version' => 3)); + foreach ($settings as $setting => $settingGroup){ + //@todo array_diff this + unset($params[$setting]); + } + CRM_Core_BAO_ConfigSetting::create($params); + CRM_Core_Session::setStatus(" ", ts('Changes Saved.'), "success"); + } + + public function rebuildMenu() { + // ensure config is set with new values + $config = CRM_Core_Config::singleton(TRUE, TRUE); + + // rebuild menu items + CRM_Core_Menu::store(); + + // also delete the IDS file so we can write a new correct one on next load + $configFile = $config->uploadDir . 'Config.IDS.ini'; + @unlink($configFile); + } +} + diff --git a/CRM/Admin/Form/Setting/Component.php b/CRM/Admin/Form/Setting/Component.php new file mode 100644 index 0000000000..c09a68ef9e --- /dev/null +++ b/CRM/Admin/Form/Setting/Component.php @@ -0,0 +1,181 @@ +_getComponentSelectValues(); + $include = &$this->addElement('advmultiselect', 'enableComponents', + ts('Components') . ' ', $components, + array( + 'size' => 5, + 'style' => 'width:150px', + 'class' => 'advmultiselect', + ) + ); + + $include->setButtonAttributes('add', array('value' => ts('Enable >>'))); + $include->setButtonAttributes('remove', array('value' => ts('<< Disable'))); + + $this->addFormRule(array('CRM_Admin_Form_Setting_Component', 'formRule'), $this); + + parent::buildQuickForm(); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields) { + $errors = array(); + + if (is_array($fields['enableComponents'])) { + if (in_array('CiviPledge', $fields['enableComponents']) && + !in_array('CiviContribute', $fields['enableComponents']) + ) { + $errors['enableComponents'] = ts('You need to enable CiviContribute before enabling CiviPledge.'); + } + if (in_array('CiviCase', $fields['enableComponents']) && + !CRM_Core_DAO::checkTriggerViewPermission(TRUE, FALSE) + ) { + $errors['enableComponents'] = ts('CiviCase requires CREATE VIEW and DROP VIEW permissions for the database.'); + } + } + + return $errors; + } + + private function _getComponentSelectValues() { + $ret = array(); + $this->_components = CRM_Core_Component::getComponents(); + foreach ($this->_components as $name => $object) { + $ret[$name] = $object->info['translatedName']; + } + + return $ret; + } + + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + + $params['enableComponentIDs'] = array(); + foreach ($params['enableComponents'] as $name) { + $params['enableComponentIDs'][] = $this->_components[$name]->componentID; + } + + // if CiviCase is being enabled, + // load the case related sample data + if (in_array('CiviCase', $params['enableComponents']) && + !in_array('CiviCase', $this->_defaults['enableComponents']) + ) { + $config = CRM_Core_Config::singleton(); + CRM_Admin_Form_Setting_Component::loadCaseSampleData($config->dsn, $config->sqlDir . 'case_sample.mysql'); + CRM_Admin_Form_Setting_Component::loadCaseSampleData($config->dsn, $config->sqlDir . 'case_sample1.mysql'); + if (!CRM_Case_BAO_Case::createCaseViews()) { + CRM_Core_Error::fatal('Could not create Case views.'); + } + } + parent::commonProcess($params); + + // reset navigation when components are enabled / disabled + CRM_Core_BAO_Navigation::resetNavigation(); + } + + public function loadCaseSampleData($dsn, $fileName, $lineMode = FALSE) { + global $crmPath; + + $db = &DB::connect($dsn); + if (PEAR::isError($db)) { + die("Cannot open $dsn: " . $db->getMessage()); + } + + if (!$lineMode) { + $string = file_get_contents($fileName); + + // change \r\n to fix windows issues + $string = str_replace("\r\n", "\n", $string); + + //get rid of comments starting with # and -- + + $string = preg_replace("/^#[^\n]*$/m", "\n", $string); + $string = preg_replace("/^(--[^-]).*/m", "\n", $string); + + $queries = preg_split('/;$/m', $string); + foreach ($queries as $query) { + $query = trim($query); + if (!empty($query)) { + $res = &$db->query($query); + if (PEAR::isError($res)) { + die("Cannot execute $query: " . $res->getMessage()); + } + } + } + } + else { + $fd = fopen($fileName, "r"); + while ($string = fgets($fd)) { + $string = preg_replace("/^#[^\n]*$/m", "\n", $string); + $string = preg_replace("/^(--[^-]).*/m", "\n", $string); + + $string = trim($string); + if (!empty($string)) { + $res = &$db->query($string); + if (PEAR::isError($res)) { + die("Cannot execute $string: " . $res->getMessage()); + } + } + } + } + } +} + diff --git a/CRM/Admin/Form/Setting/Date.php b/CRM/Admin/Form/Setting/Date.php new file mode 100644 index 0000000000..ec0d6cb412 --- /dev/null +++ b/CRM/Admin/Form/Setting/Date.php @@ -0,0 +1,70 @@ +addElement('text', 'dateformatDatetime', ts('Complete Date and Time')); + $this->addElement('text', 'dateformatFull', ts('Complete Date')); + $this->addElement('text', 'dateformatPartial', ts('Month and Year')); + $this->addElement('text', 'dateformatYear', ts('Year Only')); + $this->addElement('text', 'dateformatTime', ts('Time Only')); + $this->add('select', 'dateInputFormat', ts('Complete Date'), + CRM_Core_SelectValues::getDatePluginInputFormats() + ); + $this->add('select', 'timeInputFormat', ts('Time'), + CRM_Core_SelectValues::getTimeFormats() + ); + + $this->add('date', 'fiscalYearStart', ts('Fiscal Year Start'), + CRM_Core_SelectValues::date(NULL, 'M d') + ); + + parent::buildQuickForm(); + } +} + diff --git a/CRM/Admin/Form/Setting/Debugging.php b/CRM/Admin/Form/Setting/Debugging.php new file mode 100644 index 0000000000..bbc78e71e3 --- /dev/null +++ b/CRM/Admin/Form/Setting/Debugging.php @@ -0,0 +1,64 @@ +addYesNo('debug', ts('Enable Debugging')); + if ($config->userSystem->is_drupal == '1') { + $this->addYesNo('userFrameworkLogging', ts('Enable Drupal Watchdog Logging')); + } + $this->addYesNo('backtrace', ts('Display Backtrace')); + $this->addElement('text', 'fatalErrorTemplate', ts('Fatal Error Template')); + $this->addElement('text', 'fatalErrorHandler', ts('Fatal Error Handler')); + + parent::buildQuickForm(); + } +} + diff --git a/CRM/Admin/Form/Setting/Localization.php b/CRM/Admin/Form/Setting/Localization.php new file mode 100644 index 0000000000..a3ec2fc794 --- /dev/null +++ b/CRM/Admin/Form/Setting/Localization.php @@ -0,0 +1,336 @@ +find(TRUE); + if ($domain->locales) { + // for multi-lingual sites, populate default language drop-down with available languages + $lcMessages = array(); + foreach ($locales as $loc => $lang) { + if (substr_count($domain->locales, $loc)) { + $lcMessages[$loc] = $lang; + } + } + $this->addElement('select', 'lcMessages', ts('Default Language'), $lcMessages); + + // add language limiter and language adder + $this->addCheckBox('languageLimit', ts('Available Languages'), array_flip($lcMessages), NULL, NULL, NULL, NULL, '   '); + $this->addElement('select', 'addLanguage', ts('Add Language'), array_merge(array('' => ts('- select -')), array_diff($locales, $lcMessages))); + + // add the ability to return to single language + $warning = ts('WARNING: This will make your CiviCRM installation a single-language one again. THIS WILL DELETE ALL DATA RELATED TO LANGUAGES OTHER THAN THE DEFAULT ONE SELECTED ABOVE (and only that language will be preserved).'); + $this->assign('warning', $warning); + $this->addElement('checkbox', 'makeSinglelingual', ts('Return to Single Language'), + NULL, array('onChange' => "if (this.checked) alert('$warning')") + ); + } + else { + // for single-lingual sites, populate default language drop-down with all languages + $this->addElement('select', 'lcMessages', ts('Default Language'), $locales); + + $warning = ts('WARNING: Enabling multiple languages changes the schema of your database, so make sure you know what you are doing when enabling this function; making a database backup is strongly recommended.'); + $this->assign('warning', $warning); + + $validTriggerPermission = CRM_Core_DAO::checkTriggerViewPermission(TRUE); + + if ($validTriggerPermission && + !$config->logging + ) { + $this->addElement('checkbox', 'makeMultilingual', ts('Enable Multiple Languages'), + NULL, array('onChange' => "if (this.checked) alert('$warning')") + ); + } + } + + $this->addElement('checkbox', 'inheritLocale', ts('Inherit CMS Language')); + $this->addElement('text', 'monetaryThousandSeparator', ts('Thousands Separator'), array('size' => 2)); + $this->addElement('text', 'monetaryDecimalPoint', ts('Decimal Delimiter'), array('size' => 2)); + $this->addElement('text', 'moneyformat', ts('Monetary Amount Display')); + $this->addElement('text', 'moneyvalueformat', ts('Monetary Value Display')); + + $country = array(); + CRM_Core_PseudoConstant::populate($country, 'CRM_Core_DAO_Country', TRUE, 'name', 'is_active'); + $i18n->localizeArray($country, array('context' => 'country')); + asort($country); + + $includeCountry = &$this->addElement('advmultiselect', 'countryLimit', + ts('Available Countries') . ' ', $country, + array( + 'size' => 5, + 'style' => 'width:150px', + 'class' => 'advmultiselect', + ) + ); + + $includeCountry->setButtonAttributes('add', array('value' => ts('Add >>'))); + $includeCountry->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $includeState = &$this->addElement('advmultiselect', 'provinceLimit', + ts('Available States and Provinces') . ' ', $country, + array( + 'size' => 5, + 'style' => 'width:150px', + 'class' => 'advmultiselect', + ) + ); + + $includeState->setButtonAttributes('add', array('value' => ts('Add >>'))); + $includeState->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $this->addElement('select', 'defaultContactCountry', ts('Default Country'), array('' => ts('- select -')) + $country); + + /***Default State/Province***/ + $stateCountryMap = array(); + $stateCountryMap[] = array( + 'state_province' => 'defaultContactStateProvince', + 'country' => 'defaultContactCountry', + ); + + $countryDefault = isset($this->_submitValues['defaultContactCountry']) ? $this->_submitValues['defaultContactCountry'] : $config->defaultContactCountry; + + if ($countryDefault) { + $selectStateProvinceOptions = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($countryDefault); + } + else { + $selectStateProvinceOptions = array('' => ts('- select a country -')); + } + + $i18n->localizeArray($selectStateProvinceOptions, array('context' => 'state_province')); + asort($selectStateProvinceOptions); + + $this->addElement('select', 'defaultContactStateProvince', ts('Default State/Province'), $selectStateProvinceOptions); + + // state country js + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + CRM_Core_BAO_Address::fixAllStateSelects($form, $defaults); + /***Default State/Province***/ + + // we do this only to initialize currencySymbols, kinda hackish but works! + $config->defaultCurrencySymbol(); + + $symbol = $config->currencySymbols; + foreach ($symbol as $key => $value) { + $this->_currencySymbols[$key] = "$key"; + if ($value) { + $this->_currencySymbols[$key] .= " ($value)"; + } + } + $this->addElement('select', 'defaultCurrency', ts('Default Currency'), $this->_currencySymbols); + + $includeCurrency = &$this->addElement('advmultiselect', 'currencyLimit', + ts('Available Currencies') . ' ', $this->_currencySymbols, + array( + 'size' => 5, + 'style' => 'width:150px', + 'class' => 'advmultiselect', + ) + ); + + $includeCurrency->setButtonAttributes('add', array('value' => ts('Add >>'))); + $includeCurrency->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $this->addElement('text', 'legacyEncoding', ts('Legacy Encoding')); + $this->addElement('text', 'customTranslateFunction', ts('Custom Translate Function')); + $this->addElement('text', 'fieldSeparator', ts('Import / Export Field Separator'), array('size' => 2)); + + $this->addFormRule(array('CRM_Admin_Form_Setting_Localization', 'formRule')); + + parent::buildQuickForm(); + } + + static function formRule($fields) { + $errors = array(); + if (CRM_Utils_Array::value('monetaryThousandSeparator', $fields) == + CRM_Utils_Array::value('monetaryDecimalPoint', $fields) + ) { + $errors['monetaryThousandSeparator'] = ts('Thousands Separator and Decimal Delimiter can not be the same.'); + } + + if (strlen($fields['monetaryThousandSeparator']) == 0) { + $errors['monetaryThousandSeparator'] = ts('Thousands Separator can not be empty. You can use a space character instead.'); + } + + if (strlen($fields['monetaryThousandSeparator']) > 1) { + $errors['monetaryThousandSeparator'] = ts('Thousands Separator can not have more than 1 character.'); + } + + if (strlen($fields['monetaryDecimalPoint']) > 1) { + $errors['monetaryDecimalPoint'] = ts('Decimal Delimiter can not have more than 1 character.'); + } + + if (trim($fields['customTranslateFunction']) && + !function_exists(trim($fields['customTranslateFunction'])) + ) { + $errors['customTranslateFunction'] = ts('Please define the custom translation function first.'); + } + + // CRM-7962, CRM-7713, CRM-9004 + if (!empty($fields['defaultContactCountry']) && + (CRM_Utils_Array::value('countryLimit', $fields) && + (!in_array($fields['defaultContactCountry'], $fields['countryLimit'])) + ) + ) { + $errors['defaultContactCountry'] = ts('Please select a default country that is in the list of available countries.'); + } + + return empty($errors) ? TRUE : $errors; + } + + function setDefaultValues() { + parent::setDefaultValues(); + + // CRM-1496 + // retrieve default values for currencyLimit + $this->_defaults['currencyLimit'] = array_keys(CRM_Core_OptionGroup::values('currencies_enabled')); + + // CRM-5111: unset these two unconditionally, we don’t want them to stick – ever + unset($this->_defaults['makeMultilingual']); + unset($this->_defaults['makeSinglelingual']); + return $this->_defaults; + } + + public function postProcess() { + $values = $this->exportValues(); + + // FIXME: stupid QF not submitting unchecked checkboxen… + if (!isset($values['inheritLocale'])) { + $values['inheritLocale'] = 0; + } + + //cache contact fields retaining localized titles + //though we changed localization, so reseting cache. + CRM_Core_BAO_Cache::deleteGroup('contact fields'); + + //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache. + CRM_Core_BAO_Cache::deleteGroup('navigation'); + + // we do this only to initialize monetary decimal point and thousand separator + $config = CRM_Core_Config::singleton(); + + // set default Currency Symbol + $values['defaultCurrencySymbol'] = $config->defaultCurrencySymbol($values['defaultCurrency']); + + // save enabled currencies and defaul currency in option group 'currencies_enabled' + // CRM-1496 + if (empty($values['currencyLimit'])) { + $values['currencyLimit'] = array($values['defaultCurrency']); + } + elseif (!in_array($values['defaultCurrency'], + $values['currencyLimit'] + )) { + $values['currencyLimit'][] = $values['defaultCurrency']; + } + + // sort so that when we display drop down, weights have right value + sort($values['currencyLimit']); + + // get labels for all the currencies + $options = array(); + + for ($i = 0; $i < count($values['currencyLimit']); $i++) { + $options[] = array( + 'label' => $this->_currencySymbols[$values['currencyLimit'][$i]], + 'value' => $values['currencyLimit'][$i], + 'weight' => $i + 1, + 'is_active' => 1, + 'is_default' => $values['currencyLimit'][$i] == $values['defaultCurrency'], + ); + } + + $dontCare = NULL; + CRM_Core_OptionGroup::createAssoc('currencies_enabled', + $options, + $dontCare + ); + + // unset currencyLimit so we dont store there + unset($values['currencyLimit']); + + // make the site multi-lang if requested + if (CRM_Utils_Array::value('makeMultilingual', $values)) { + CRM_Core_I18n_Schema::makeMultilingual($values['lcMessages']); + $values['languageLimit'][$values['lcMessages']] = 1; + // make the site single-lang if requested + } + elseif (CRM_Utils_Array::value('makeSinglelingual', $values)) { + CRM_Core_I18n_Schema::makeSinglelingual($values['lcMessages']); + $values['languageLimit'] = ''; + } + + // add a new db locale if the requested language is not yet supported by the db + if (!CRM_Utils_Array::value('makeSinglelingual', $values) and CRM_Utils_Array::value('addLanguage', $values)) { + $domain = new CRM_Core_DAO_Domain(); + $domain->find(TRUE); + if (!substr_count($domain->locales, $values['addLanguage'])) { + CRM_Core_I18n_Schema::addLocale($values['addLanguage'], $values['lcMessages']); + } + $values['languageLimit'][$values['addLanguage']] = 1; + } + + // if we manipulated the language list, return to the localization admin screen + $return = (bool)(CRM_Utils_Array::value('makeMultilingual', $values) or CRM_Utils_Array::value('addLanguage', $values)); + + // save all the settings + parent::commonProcess($values); + + if ($return) { + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/setting/localization', 'reset=1')); + } + } +} + diff --git a/CRM/Admin/Form/Setting/Mail.php b/CRM/Admin/Form/Setting/Mail.php new file mode 100644 index 0000000000..6440da05c9 --- /dev/null +++ b/CRM/Admin/Form/Setting/Mail.php @@ -0,0 +1,64 @@ +addElement('text', 'verpSeparator', ts('VERP Separator')); + $this->addElement('text', 'mailerBatchLimit', ts('Mailer Batch Limit')); + $this->addElement('text', 'mailThrottleTime', ts('Mailer Throttle Time')); + $this->addElement('text', 'mailerJobSize', ts('Mailer Job Size')); + $this->addElement('advcheckbox', 'replyTo', ts('Enable Custom Reply-To')); + $this->addElement('text', 'mailerJobsMax', ts('Mailer CRON job limit')); + $check = TRUE; + + // redirect to Administer Section After hitting either Save or Cancel button. + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + + parent::buildQuickForm($check); + } +} + diff --git a/CRM/Admin/Form/Setting/Mapping.php b/CRM/Admin/Form/Setting/Mapping.php new file mode 100644 index 0000000000..27ef0fd069 --- /dev/null +++ b/CRM/Admin/Form/Setting/Mapping.php @@ -0,0 +1,101 @@ +addElement('select', 'mapProvider', ts('Mapping Provider'), array('' => '- select -') + $map, array('onChange' => 'showHideMapAPIkey( this.value );')); + $this->add('text', 'mapAPIKey', ts('Map Provider Key'), NULL); + $this->addElement('select', 'geoProvider', ts('Geocoding Provider'), array('' => '- select -') + $geo); + $this->add('text', 'geoAPIKey', ts('Geo Provider Key'), NULL); + + parent::buildQuickForm(); + } + + /** + * global form rule + * + * @param array $fields the input form values + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields) { + $errors = array(); + + if (!CRM_Utils_System::checkPHPVersion(5, FALSE)) { + $errors['_qf_default'] = ts('Mapping features require PHP version 5 or greater'); + } + + if (!$fields['mapAPIKey'] && ($fields['mapProvider'] != '' && $fields['mapProvider'] == 'Yahoo')) { + $errors['mapAPIKey'] = "Map Provider key is a required field."; + } + + if ($fields['mapProvider'] == 'OpenStreetMaps' && $fields['geoProvider'] == '') { + $errors['geoProvider'] = "Please select a Geocoding Provider - Open Street Maps does not provide geocoding."; + } + + return $errors; + } + + /** + * This function is used to add the rules (mainly global rules) for form. + * All local rules are added near the element + * + * @param null + * + * @return void + * @access public + */ + function addRules() { + $this->addFormRule(array('CRM_Admin_Form_Setting_Mapping', 'formRule')); + } +} + diff --git a/CRM/Admin/Form/Setting/Miscellaneous.php b/CRM/Admin/Form/Setting/Miscellaneous.php new file mode 100644 index 0000000000..e15c20636e --- /dev/null +++ b/CRM/Admin/Form/Setting/Miscellaneous.php @@ -0,0 +1,130 @@ + CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_undelete' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'versionCheck' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'maxFileSize' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'doNotAttachPDFReceipt' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + ); + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + CRM_Utils_System::setTitle(ts('Settings - Undelete, Logging and ReCAPTCHA')); + + + // also check if we can enable triggers + $validTriggerPermission = CRM_Core_DAO::checkTriggerViewPermission(FALSE); + + // FIXME: for now, disable logging for multilingual sites OR if triggers are not permittted + $domain = new CRM_Core_DAO_Domain; + $domain->find(TRUE); + $attribs = $domain->locales || !$validTriggerPermission ? array( + 'disabled' => 'disabled') : NULL; + + $this->assign('validTriggerPermission', $validTriggerPermission); + $this->addYesNo('logging', ts('Logging'), NULL, NULL, $attribs); + + $this->addElement('text', 'wkhtmltopdfPath', ts('Path to wkhtmltopdf executable'), + array('size' => 64, 'maxlength' => 256) + ); + + $this->addElement('text', 'recaptchaPublicKey', ts('Public Key'), + array('size' => 64, 'maxlength' => 64) + ); + $this->addElement('text', 'recaptchaPrivateKey', ts('Private Key'), + array('size' => 64, 'maxlength' => 64) + ); + + $this->addElement('text', 'dashboardCacheTimeout', ts('Dashboard cache timeout'), + array('size' => 3, 'maxlength' => 5) + ); + $this->addElement('text', 'checksumTimeout', ts('CheckSum Lifespan'), + array('size' => 2, 'maxlength' => 8) + ); + $this->addElement('text', 'recaptchaOptions', ts('Recaptcha Options'), + array('size' => 64, 'maxlength' => 64) + ); + + $this->addRule('checksumTimeout', ts('Value should be a positive number'), 'positiveInteger'); + + parent::buildQuickForm(); + } + + function setDefaultValues() { + parent::setDefaultValues(); + + $this->_defaults['checksumTimeout'] = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'checksum_timeout', + NULL, + 7 + ); + return $this->_defaults; + } + + public function postProcess() { + // store the submitted values in an array + $config = CRM_Core_Config::singleton(); + $params = $this->controller->exportValues($this->_name); + + // get current logging status + $values = $this->exportValues(); + + parent::postProcess(); + + if ($config->logging != $values['logging']) { + $logging = new CRM_Logging_Schema; + if ($values['logging']) { + $logging->enableLogging(); + } + else { + $logging->disableLogging(); + } + } + } +} + diff --git a/CRM/Admin/Form/Setting/Path.php b/CRM/Admin/Form/Setting/Path.php new file mode 100644 index 0000000000..4877a12eae --- /dev/null +++ b/CRM/Admin/Form/Setting/Path.php @@ -0,0 +1,77 @@ + ts('Temporary Files'), + 'imageUploadDir' => ts('Images'), + 'customFileUploadDir' => ts('Custom Files'), + 'customTemplateDir' => ts('Custom Templates'), + 'customPHPPathDir' => ts('Custom PHP Path Directory'), + 'extensionsDir' => ts('CiviCRM Extensions Directory'), + ); + foreach ($directories as $name => $title) { + $this->add('text', $name, $title); + $this->addRule($name, + ts("'%1' directory does not exist", + array(1 => $title) + ), + 'fileExists' + ); + } + + parent::buildQuickForm(); + } + + public function postProcess() { + parent::postProcess(); + + parent::rebuildMenu(); + } +} + diff --git a/CRM/Admin/Form/Setting/Search.php b/CRM/Admin/Form/Setting/Search.php new file mode 100644 index 0000000000..cb12b5f05b --- /dev/null +++ b/CRM/Admin/Form/Setting/Search.php @@ -0,0 +1,99 @@ + CRM_Core_BAO_Setting::SEARCH_PREFERENCES_NAME, + ); + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + CRM_Utils_System::setTitle(ts('Settings - Search Preferences')); + + $this->addYesNo('includeWildCardInName', ts('Automatic Wildcard')); + $this->addYesNo('includeEmailInName', ts('Include Email')); + $this->addYesNo('includeNickNameInName', ts('Include Nickname')); + + $this->addYesNo('includeAlphabeticalPager', ts('Include Alphabetical Pager')); + $this->addYesNo('includeOrderByClause', ts('Include Order By Clause')); + + $this->addElement('text', 'smartGroupCacheTimeout', ts('Smart group cache timeout'), + array('size' => 3, 'maxlength' => 5) + ); + + $types = array('Contact', 'Individual', 'Organization', 'Household'); + $profiles = CRM_Core_BAO_UFGroup::getProfiles($types); + + $this->add('select', 'defaultSearchProfileID', ts('Default Contact Search Profile'), + array( + '' => ts('- select -')) + $profiles + ); + + // Autocomplete for Contact Search (quick search etc.) + $options = array( + ts('Contact Name') => 1) + array_flip(CRM_Core_OptionGroup::values('contact_autocomplete_options', + FALSE, FALSE, TRUE + )); + $this->addCheckBox('autocompleteContactSearch', ts('Autocomplete Contact Search'), $options, + NULL, NULL, NULL, NULL, array('  ') + ); + $element = $this->getElement('autocompleteContactSearch'); + $element->_elements[0]->_flagFrozen = TRUE; + + // Autocomplete for Contact Reference (custom fields) + $optionsCR = array( + ts('Contact Name') => 1) + array_flip(CRM_Core_OptionGroup::values('contact_reference_options', + FALSE, FALSE, TRUE + )); + $this->addCheckBox('autocompleteContactReference', ts('Contact Reference Options'), $optionsCR, + NULL, NULL, NULL, NULL, array('  ') + ); + $element = $this->getElement('autocompleteContactReference'); + $element->_elements[0]->_flagFrozen = TRUE; + + parent::buildQuickForm(); + } +} + diff --git a/CRM/Admin/Form/Setting/Smtp.php b/CRM/Admin/Form/Setting/Smtp.php new file mode 100644 index 0000000000..99b8357c76 --- /dev/null +++ b/CRM/Admin/Form/Setting/Smtp.php @@ -0,0 +1,278 @@ + ts('mail()'), + CRM_Mailing_Config::OUTBOUND_OPTION_SMTP => ts('SMTP'), + CRM_Mailing_Config::OUTBOUND_OPTION_SENDMAIL => ts('Sendmail'), + CRM_Mailing_Config::OUTBOUND_OPTION_DISABLED => ts('Disable Outbound Email'), + CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB => ts('Redirect to Database'), + ); + $this->addRadio('outBound_option', ts('Select Mailer'), $outBoundOption); + + CRM_Utils_System::setTitle(ts('Settings - Outbound Mail')); + $this->add('text', 'sendmail_path', ts('Sendmail Path')); + $this->add('text', 'sendmail_args', ts('Sendmail Argument')); + $this->add('text', 'smtpServer', ts('SMTP Server')); + $this->add('text', 'smtpPort', ts('SMTP Port')); + $this->addYesNo('smtpAuth', ts('Authentication?')); + $this->addElement('text', 'smtpUsername', ts('SMTP Username')); + $this->addElement('password', 'smtpPassword', ts('SMTP Password')); + + $this->_testButtonName = $this->getButtonName('refresh', 'test'); + + $this->add('submit', $this->_testButtonName, ts('Save & Send Test Email')); + + $this->addFormRule(array('CRM_Admin_Form_Setting_Smtp', 'formRule')); + parent::buildQuickForm(); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // flush caches so we reload details for future requests + // CRM-11967 + CRM_Utils_System::flushCache(); + + $formValues = $this->controller->exportValues($this->_name); + + $buttonName = $this->controller->getButtonName(); + // check if test button + if ($buttonName == $this->_testButtonName) { + if ($formValues['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_DISABLED) { + CRM_Core_Session::setStatus(ts('You have selected "Disable Outbound Email". A test email can not be sent.'), ts("Email Disabled"), "error"); + } elseif ( $formValues['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB ) { + CRM_Core_Session::setStatus(ts('You have selected "Redirect to Database". A test email can not be sent.'), ts("Email Disabled"), "error"); + } + else { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + list($toDisplayName, $toEmail, $toDoNotEmail) = CRM_Contact_BAO_Contact::getContactDetails($userID); + + //get the default domain email address.CRM-4250 + list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(); + + if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') { + $fixUrl = CRM_Utils_System::url("civicrm/admin/domain", 'action=update&reset=1'); + CRM_Core_Error::fatal(ts('The site administrator needs to enter a valid \'FROM Email Address\' in Administer CiviCRM » Communications » FROM Email Addresses. The email address used may need to be a valid mail account with your email service provider.', array(1 => $fixUrl))); + } + + if (!$toEmail) { + CRM_Core_Error::statusBounce(ts('Cannot send a test email because your user record does not have a valid email address.')); + } + + if (!trim($toDisplayName)) { + $toDisplayName = $toEmail; + } + + $to = '"' . $toDisplayName . '"' . "<$toEmail>"; + $from = '"' . $domainEmailName . '" <' . $domainEmailAddress . '>'; + $testMailStatusMsg = ts('Sending test email. FROM: %1 TO: %2.
', array(1 => $domainEmailAddress, 2 => $toEmail)); + + $params = array(); + if ($formValues['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_SMTP) { + $subject = "Test for SMTP settings"; + $message = "SMTP settings are correct."; + + $params['host'] = $formValues['smtpServer']; + $params['port'] = $formValues['smtpPort']; + + if ($formValues['smtpAuth']) { + $params['username'] = $formValues['smtpUsername']; + $params['password'] = $formValues['smtpPassword']; + $params['auth'] = TRUE; + } + else { + $params['auth'] = FALSE; + } + + // set the localhost value, CRM-3153, CRM-9332 + $params['localhost'] = $_SERVER['SERVER_NAME']; + + // also set the timeout value, lets set it to 30 seconds + // CRM-7510, CRM-9332 + $params['timeout'] = 30; + + $mailerName = 'smtp'; + } + elseif ($formValues['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_SENDMAIL) { + $subject = "Test for Sendmail settings"; + $message = "Sendmail settings are correct."; + $params['sendmail_path'] = $formValues['sendmail_path']; + $params['sendmail_args'] = $formValues['sendmail_args']; + $mailerName = 'sendmail'; + } + elseif ($formValues['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_MAIL) { + $subject = "Test for PHP mail settings"; + $message = "mail settings are correct."; + $mailerName = 'mail'; + } + + $headers = array( + 'From' => $from, + 'To' => $to, + 'Subject' => $subject, + ); + + $mailer = Mail::factory($mailerName, $params); + + CRM_Core_Error::ignoreException(); + $result = $mailer->send($toEmail, $headers, $message); + if (!is_a($result, 'PEAR_Error')) { + CRM_Core_Session::setStatus($testMailStatusMsg . ts('Your %1 settings are correct. A test email has been sent to your email address.', array(1 => strtoupper($mailerName))), ts("Mail Sent"), "success"); + } + else { + $message = CRM_Utils_Mail::errorMessage($mailer, $result); + CRM_Core_Session::setStatus($testMailStatusMsg . ts('Oops. Your %1 settings are incorrect. No test mail has been sent.', array(1 => strtoupper($mailerName))) . $message, ts("Mail Not Sent"), "error"); + } + } + } + + $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, + 'mailing_backend' + ); + + if (!empty($mailingBackend)) { + CRM_Core_BAO_ConfigSetting::formatParams($formValues, $mailingBackend); + } + + // if password is present, encrypt it + if (!empty($formValues['smtpPassword'])) { + $formValues['smtpPassword'] = CRM_Utils_Crypt::encrypt($formValues['smtpPassword']); + } + + CRM_Core_BAO_Setting::setItem($formValues, + CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, + 'mailing_backend' + ); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + if ($fields['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_SMTP) { + if (!CRM_Utils_Array::value('smtpServer', $fields)) { + $errors['smtpServer'] = 'SMTP Server name is a required field.'; + } + if (!CRM_Utils_Array::value('smtpPort', $fields)) { + $errors['smtpPort'] = 'SMTP Port is a required field.'; + } + if (CRM_Utils_Array::value('smtpAuth', $fields)) { + if (!CRM_Utils_Array::value('smtpUsername', $fields)) { + $errors['smtpUsername'] = 'If your SMTP server requires authentication please provide a valid user name.'; + } + if (!CRM_Utils_Array::value('smtpPassword', $fields)) { + $errors['smtpPassword'] = 'If your SMTP server requires authentication, please provide a password.'; + } + } + } + if ($fields['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_SENDMAIL) { + if (!$fields['sendmail_path']) { + $errors['sendmail_path'] = 'Sendmail Path is a required field.'; + } + if (!$fields['sendmail_args']) { + $errors['sendmail_args'] = 'Sendmail Argument is a required field.'; + } + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * This function sets the default values for the form. + * default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if (!$this->_defaults) { + $this->_defaults = array(); + + $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, + 'mailing_backend' + ); + if (!empty($mailingBackend)) { + $this->_defaults = $mailingBackend; + + if (!empty($this->_defaults['smtpPassword'])) { + $this->_defaults['smtpPassword'] = CRM_Utils_Crypt::decrypt($this->_defaults['smtpPassword']); + } + } + else { + if (!isset($this->_defaults['smtpServer'])) { + $this->_defaults['smtpServer'] = 'localhost'; + $this->_defaults['smtpPort'] = 25; + $this->_defaults['smtpAuth'] = 0; + } + + if (!isset($this->_defaults['sendmail_path'])) { + $this->_defaults['sendmail_path'] = '/usr/sbin/sendmail'; + $this->_defaults['sendmail_args'] = '-i'; + } + } + } + return $this->_defaults; + } +} + diff --git a/CRM/Admin/Form/Setting/UF.php b/CRM/Admin/Form/Setting/UF.php new file mode 100644 index 0000000000..b038ba2765 --- /dev/null +++ b/CRM/Admin/Form/Setting/UF.php @@ -0,0 +1,75 @@ +userFramework; + + CRM_Utils_System::setTitle(ts('Settings - %1 Integration', + array(1 => $uf) + )); + + $this->addElement('text', 'userFrameworkUsersTableName', ts('%1 Users Table Name', array(1 => $uf))); + if (function_exists('module_exists') && + module_exists('views') && + $config->dsn != $config->userFrameworkDSN + ) { + $dsnArray = DB::parseDSN($config->dsn); + $tableNames = CRM_Core_DAO::GetStorageValues(NULL, 0, 'Name'); + $tablePrefixes = '$databases[\'default\'][\'default\'][\'prefix\']= array( + '; + foreach ($tableNames as $tableName => $value) { + $tablePrefixes .= "\n '" . str_pad($tableName . "'", 41) . " => '`{$dsnArray['database']}`.',"; + } + $tablePrefixes .= "\n);"; + $this->assign('tablePrefixes', $tablePrefixes); + } + + parent::buildQuickForm(); + } +} + diff --git a/CRM/Admin/Form/Setting/UpdateConfigBackend.php b/CRM/Admin/Form/Setting/UpdateConfigBackend.php new file mode 100644 index 0000000000..ab70e20766 --- /dev/null +++ b/CRM/Admin/Form/Setting/UpdateConfigBackend.php @@ -0,0 +1,152 @@ +_oldBaseURL, + $this->_oldBaseDir, + $this->_oldSiteName + ) = CRM_Core_BAO_ConfigSetting::getConfigSettings(); + + $this->assign('oldBaseURL', $this->_oldBaseURL); + $this->assign('oldBaseDir', $this->_oldBaseDir); + $this->assign('oldSiteName', $this->_oldSiteName); + + $this->addElement('submit', $this->getButtonName('next', 'cleanup'), 'Cleanup Caches', array('class' => 'form-submit', 'id' => 'cleanup-cache')); + + $this->add('text', 'newBaseURL', ts('New Base URL'), NULL, TRUE); + $this->add('text', 'newBaseDir', ts('New Base Directory'), NULL, TRUE); + if ($this->_oldSiteName) { + $this->add('text', 'newSiteName', ts('New Site Name'), NULL, TRUE); + } + $this->addFormRule(array('CRM_Admin_Form_Setting_UpdateConfigBackend', 'formRule')); + + parent::buildQuickForm(); + } + + function setDefaultValues() { + if (!$this->_defaults) { + parent::setDefaultValues(); + + $config = CRM_Core_Config::singleton(); + list($this->_defaults['newBaseURL'], + $this->_defaults['newBaseDir'], + $this->_defaults['newSiteName'] + ) = CRM_Core_BAO_ConfigSetting::getBestGuessSettings(); + } + + return $this->_defaults; + } + + static function formRule($fields) { + $tmpDir = trim($fields['newBaseDir']); + + $errors = array(); + if (!is_writeable($tmpDir)) { + $errors['newBaseDir'] = ts('%1 directory does not exist or cannot be written by webserver', + array(1 => $tmpDir) + ); + } + return $errors; + } + + function postProcess() { + if (CRM_Utils_Array::value('_qf_UpdateConfigBackend_next_cleanup', $_POST)) { + + $config = CRM_Core_Config::singleton(); + + // cleanup templates_c directory + $config->cleanup(1, FALSE); + + // clear db caching + CRM_Core_Config::clearDBCache(); + parent::rebuildMenu(); + + CRM_Core_Session::setStatus(ts('Cache has been cleared and menu has been rebuilt successfully.'), ts("Success"), "success"); + return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/setting/updateConfigBackend', 'reset=1')); + } + + // redirect to admin page after saving + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin')); + + $params = $this->controller->exportValues($this->_name); + + //CRM-5679 + foreach ($params as $name => & $val) { + if ($val && in_array($name, array( + 'newBaseURL', 'newBaseDir', 'newSiteName'))) { + $val = CRM_Utils_File::addTrailingSlash($val); + } + } + + $from = array($this->_oldBaseURL, $this->_oldBaseDir); + $to = array(trim($params['newBaseURL']), + trim($params['newBaseDir']), + ); + if ($this->_oldSiteName && + $params['newSiteName'] + ) { + $from[] = $this->_oldSiteName; + $to[] = $params['newSiteName']; + } + + $newValues = str_replace($from, + $to, + $this->_defaults + ); + + parent::commonProcess($newValues); + + parent::rebuildMenu(); + } +} + diff --git a/CRM/Admin/Form/Setting/Url.php b/CRM/Admin/Form/Setting/Url.php new file mode 100644 index 0000000000..b4432b05d6 --- /dev/null +++ b/CRM/Admin/Form/Setting/Url.php @@ -0,0 +1,99 @@ + CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, + ); + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + CRM_Utils_System::setTitle(ts('Settings - Resource URLs')); + + $this->addElement('text', 'userFrameworkResourceURL', ts('CiviCRM Resource URL')); + $this->addElement('text', 'imageUploadURL', ts('Image Upload URL')); + $this->addElement('text', 'customCSSURL', ts('Custom CiviCRM CSS URL')); + $this->addElement('text', 'extensionsURL', ts('Extension Resource URL')); + $this->addYesNo('enableSSL', ts('Force Secure URLs (SSL)')); + $this->addYesNo('verifySSL', ts('Verify SSL Certs')); + + $this->addFormRule(array('CRM_Admin_Form_Setting_Url', 'formRule')); + + parent::buildQuickForm(); + } + + static function formRule($fields) { + if (isset($fields['enableSSL']) && + $fields['enableSSL'] + ) { + $config = CRM_Core_Config::singleton(); + $url = str_replace('http://', 'https://', + CRM_Utils_System::url('civicrm/dashboard', 'reset=1', TRUE, + NULL, FALSE, FALSE + ) + ); + if (!CRM_Utils_System::checkURL($url, TRUE)) { + $errors = array( + 'enableSSL' => + ts('You need to set up a secure server before you can use the Force Secure URLs option'), + ); + return $errors; + } + } + return TRUE; + } + + public function postProcess() { + // if extensions url is set, lets clear session status messages to avoid + // a potentially spurious message which might already have been set. This + // is a bit hackish + // CRM-10629 + $session = CRM_Core_Session::singleton( ); + $session->getStatus(TRUE); + + parent::postProcess(); + + parent::rebuildMenu(); + } +} + diff --git a/CRM/Admin/Form/Tag.php b/CRM/Admin/Form/Tag.php new file mode 100644 index 0000000000..55f6e0d305 --- /dev/null +++ b/CRM/Admin/Form/Tag.php @@ -0,0 +1,179 @@ +_action == CRM_Core_Action::DELETE) { + if ($this->_id && $tag = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'name', 'parent_id')) { + CRM_Core_Session::setStatus(ts("This tag cannot be deleted. You must delete all its child tags ('%1', etc) prior to deleting this tag.", array(1 => $tag)), ts('Sorry'), 'error'); + $url = CRM_Utils_System::url('civicrm/admin/tag', "reset=1"); + CRM_Utils_System::redirect($url); + return TRUE; + } + else { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + } + else { + $this->_isTagSet = CRM_Utils_Request::retrieve('tagset', 'Positive', $this); + + if (!$this->_isTagSet && + $this->_id && + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'is_tagset') + ) { + $this->_isTagSet = TRUE; + } + + $allTag = array('' => '- ' . ts('select') . ' -') + CRM_Core_BAO_Tag::getTagsNotInTagset(); + + if ($this->_id) { + unset($allTag[$this->_id]); + } + + if (!$this->_isTagSet) { + $this->add('select', 'parent_id', ts('Parent Tag'), $allTag); + } + + $this->assign('isTagSet', $this->_isTagSet); + + $this->applyFilter('__ALL__', 'trim'); + + $this->add('text', 'name', ts('Name'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'name'), TRUE + ); + $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array('CRM_Core_DAO_Tag', $this->_id)); + + $this->add('text', 'description', ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'description') + ); + + //@lobo haven't a clue why the checkbox isn't displayed (it should be checked by default + $this->add('checkbox', 'is_selectable', ts("If it's a tag or a category")); + + $isReserved = $this->add('checkbox', 'is_reserved', ts('Reserved?')); + + $usedFor = $this->add('select', 'used_for', ts('Used For'), + CRM_Core_OptionGroup::values('tag_used_for') + ); + $usedFor->setMultiple(TRUE); + + if ($this->_id && + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'parent_id') + ) { + $usedFor->freeze(); + } + + $adminTagset = TRUE; + if (!CRM_Core_Permission::check('administer Tagsets')) { + $adminTagset = FALSE; + } + $this->assign('adminTagset', $adminTagset); + + $adminReservedTags = TRUE; + if (!CRM_Core_Permission::check('administer reserved tags')) { + $isReserved->freeze(); + $adminReservedTags = FALSE; + } + $this->assign('adminReservedTags', $adminReservedTags); + + parent::buildQuickForm(); + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $ids = array(); + + // store the submitted values in an array + $params = $this->exportValues(); + + $ids['tag'] = $this->_id; + if ($this->_action == CRM_Core_Action::ADD || + $this->_action == CRM_Core_Action::UPDATE + ) { + $params['used_for'] = implode(",", $params['used_for']); + } + + $params['is_tagset'] = 0; + if ($this->_isTagSet) { + $params['is_tagset'] = 1; + } + + if (!isset($params['is_reserved'])) { + $params['is_reserved'] = 0; + } + + if ($this->_action == CRM_Core_Action::DELETE) { + if ($this->_id > 0) { + CRM_Core_BAO_Tag::del($this->_id); + } + } + else { + $tag = CRM_Core_BAO_Tag::add($params, $ids); + CRM_Core_Session::setStatus(ts('The tag \'%1\' has been saved.', array(1 => $tag->name)), ts('Saved'), 'success'); + } + } + //end of function +} + diff --git a/CRM/Admin/Form/WordReplacements.php b/CRM/Admin/Form/WordReplacements.php new file mode 100644 index 0000000000..fc6938895f --- /dev/null +++ b/CRM/Admin/Form/WordReplacements.php @@ -0,0 +1,269 @@ +_soInstance = CRM_Utils_Array::value('instance', $_GET); + $this->assign('soInstance', $this->_soInstance); + $breadCrumbUrl = CRM_Utils_System::url('civicrm/admin/options/wordreplacements', + "reset=1" + ); + $breadCrumb = array(array('title' => ts('Word Replacements'), + 'url' => $breadCrumbUrl, + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + } + + public function setDefaultValues() { + if ($this->_defaults !== NULL) { + return $this->_defaults; + } + + $this->_defaults = array(); + + $config = CRM_Core_Config::singleton(); + + $values = $config->localeCustomStrings[$config->lcMessages]; + $i = 1; + + $enableDisable = array( + 1 => 'enabled', + 0 => 'disabled', + ); + + $cardMatch = array('wildcardMatch', 'exactMatch'); + + foreach ($enableDisable as $key => $val) { + foreach ($cardMatch as $kc => $vc) { + if (!empty($values[$val][$vc])) { + foreach ($values[$val][$vc] as $k => $v) { + $this->_defaults["enabled"][$i] = $key; + $this->_defaults["cb"][$i] = $kc; + $this->_defaults["old"][$i] = $k; + $this->_defaults["new"][$i] = $v; + $i++; + } + } + } + } + + $name = $this->_stringName = "custom_string_override_{$config->lcMessages}"; + if (isset($config->$name) && + is_array($config->$name) + ) { + $this->_numStrings = 1; + foreach ($config->$name as $old => $newValues) { + $this->_numStrings++; + $this->_numStrings += 9; + } + } + else { + $this->_numStrings = 10; + } + + return $this->_defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $config = CRM_Core_Config::singleton(); + $values = $config->localeCustomStrings[$config->lcMessages]; + $instances = (count($values, COUNT_RECURSIVE) - 6); + if ($instances > 10) { + $this->_numStrings = $instances; + } + + $soInstances = range(1, $this->_numStrings, 1); + $stringOverrideInstances = array(); + if ($this->_soInstance) { + $soInstances = array($this->_soInstance); + } + elseif (CRM_Utils_Array::value('old', $_POST)) { + $soInstances = $stringOverrideInstances = array_keys($_POST['old']); + } + elseif (!empty($this->_defaults) && is_array($this->_defaults)) { + $stringOverrideInstances = array_keys($this->_defaults['new']); + if (count($this->_defaults['old']) > count($this->_defaults['new'])) { + $stringOverrideInstances = array_keys($this->_defaults['old']); + } + } + foreach ($soInstances as $instance) { + $this->addElement('checkbox', "enabled[$instance]"); + $this->add('textarea', "old[$instance]", NULL, array('rows' => 1, 'cols' => 40)); + $this->add('textarea', "new[$instance]", NULL, array('rows' => 1, 'cols' => 40)); + $this->addElement('checkbox', "cb[$instance]"); + } + $this->assign('numStrings', $this->_numStrings); + if ($this->_soInstance) { + return; + } + + $this->assign('stringOverrideInstances', empty($stringOverrideInstances) ? FALSE : $stringOverrideInstances); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + $this->addFormRule(array('CRM_Admin_Form_WordReplacements', 'formRule'), $this); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values) { + $errors = array(); + + $oldValues = CRM_Utils_Array::value('old', $values); + $newValues = CRM_Utils_Array::value('new', $values); + $enabled = CRM_Utils_Array::value('enabled', $values); + $exactMatch = CRM_Utils_Array::value('cb', $values); + + foreach ($oldValues as $k => $v) { + if ($v && !$newValues[$k]) { + $errors['new[' . $k . ']'] = ts('Please Enter the value for Replacement Word'); + } + elseif (!$v && $newValues[$k]) { + $errors['old[' . $k . ']'] = ts('Please Enter the value for Original Word'); + } + elseif ((!CRM_Utils_Array::value($k, $newValues) && !CRM_Utils_Array::value($k, $oldValues)) + && (CRM_Utils_Array::value($k, $enabled) || CRM_Utils_Array::value($k, $exactMatch)) + ) { + $errors['old[' . $k . ']'] = ts('Please Enter the value for Original Word'); + $errors['new[' . $k . ']'] = ts('Please Enter the value for Replacement Word'); + } + } + + return $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + $this->_numStrings = sizeof($params['old']); + + $enabled['exactMatch'] = $enabled['wildcardMatch'] = $disabled['exactMatch'] = $disabled['wildcardMatch'] = array(); + for ($i = 1; $i <= $this->_numStrings; $i++) { + if (CRM_Utils_Array::value($i, $params['new']) && + CRM_Utils_Array::value($i, $params['old']) + ) { + if (isset($params['enabled']) && CRM_Utils_Array::value($i, $params['enabled'])) { + if (CRM_Utils_Array::value('cb', $params) && + CRM_Utils_Array::value($i, $params['cb']) + ) { + $enabled['exactMatch'] += array($params['old'][$i] => $params['new'][$i]); + } + else { + $enabled['wildcardMatch'] += array($params['old'][$i] => $params['new'][$i]); + } + } + else { + if (isset($params['cb']) && is_array($params['cb']) && array_key_exists($i, $params['cb'])) { + $disabled['exactMatch'] += array($params['old'][$i] => $params['new'][$i]); + } + else { + $disabled['wildcardMatch'] += array($params['old'][$i] => $params['new'][$i]); + } + } + } + } + + $overrides = array( + 'enabled' => $enabled, + 'disabled' => $disabled, + ); + + $config = CRM_Core_Config::singleton(); + + $domain = new CRM_Core_DAO_Domain(); + $domain->find(TRUE); + + if ($domain->locales && $config->localeCustomStrings) { + // for multilingual + $addReplacements = $config->localeCustomStrings; + $addReplacements[$config->lcMessages] = $overrides; + $stringOverride = serialize($addReplacements); + } + else { + // for single language + $stringOverride = serialize(array($config->lcMessages => $overrides)); + } + + $params = array('locale_custom_strings' => $stringOverride); + $id = CRM_Core_Config::domainID(); + + $wordReplacementSettings = CRM_Core_BAO_Domain::edit($params, $id); + + if ($wordReplacementSettings) { + //reset navigation + CRM_Core_BAO_Navigation::resetNavigation(); + + CRM_Core_Session::setStatus("", ts("Settings Saved"), "success"); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/options/wordreplacements', + "reset=1" + )); + } + } +} + diff --git a/CRM/Admin/Page/AJAX.php b/CRM/Admin/Page/AJAX.php new file mode 100644 index 0000000000..18f0796f73 --- /dev/null +++ b/CRM/Admin/Page/AJAX.php @@ -0,0 +1,523 @@ + implode(', ', $ufJoin))) . '

' . ts('If you disable the profile - it will be removed from these forms and/or modules. Do you want to continue?'); + } + else { + $status = ts('Are you sure you want to disable this profile?'); + } + break; + + case 'CRM_Price_BAO_Set': + require_once (str_replace('_', DIRECTORY_SEPARATOR, $recordBAO) . '.php'); + $usedBy = CRM_Price_BAO_Set::getUsedBy($recordID); + $priceSet = CRM_Price_BAO_Set::getTitle($recordID); + + if (!CRM_Utils_System::isNull($usedBy)) { + $template = CRM_Core_Smarty::singleton(); + $template->assign('usedBy', $usedBy); + $comps = array( + 'Event' => 'civicrm_event', + 'Contribution' => 'civicrm_contribution_page', + ); + $contexts = array(); + foreach ($comps as $name => $table) { + if (array_key_exists($table, $usedBy)) { + $contexts[] = $name; + } + } + $template->assign('contexts', $contexts); + + $show = 'noButton'; + $table = $template->fetch('CRM/Price/Page/table.tpl'); + $status = ts('Unable to disable the \'%1\' price set - it is currently in use by one or more active events, contribution pages or contributions.', array( + 1 => $priceSet)) . "
$table"; + } + else { + $status = ts('Are you sure you want to disable \'%1\' Price Set?', array(1 => $priceSet)); + } + break; + + case 'CRM_Event_BAO_Event': + $status = ts('Are you sure you want to disable this Event?'); + break; + + case 'CRM_Core_BAO_UFField': + $status = ts('Are you sure you want to disable this CiviCRM Profile field?'); + break; + + case 'CRM_Contribute_BAO_ManagePremiums': + $status = ts('Are you sure you want to disable this premium? This action will remove the premium from any contribution pages that currently offer it. However it will not delete the premium record - so you can re-enable it and add it back to your contribution page(s) at a later time.'); + break; + + case 'CRM_Contact_BAO_RelationshipType': + $status = ts('Are you sure you want to disable this relationship type?') . '

' . ts('Users will no longer be able to select this value when adding or editing relationships between contacts.'); + break; + + case 'CRM_Contribute_BAO_FinancialType': + $status = ts('Are you sure you want to disable this financial type?'); + break; + + case 'CRM_Financial_BAO_PaymentProcessor': + $status = ts('Are you sure you want to disable this payment processor?') . '

' . ts('Users will no longer be able to select this value when adding or editing transaction pages.'); + break; + + case 'CRM_Financial_BAO_PaymentProcessorType': + $status = ts('Are you sure you want to disable this payment processor type?'); + break; + + case 'CRM_Core_BAO_LocationType': + $status = ts('Are you sure you want to disable this location type?') . '

' . ts('Users will no longer be able to select this value when adding or editing contact locations.'); + break; + + case 'CRM_Event_BAO_ParticipantStatusType': + $status = ts('Are you sure you want to disable this Participant Status?') . '

' . ts('Users will no longer be able to select this value when adding or editing Participant Status.'); + break; + + case 'CRM_Mailing_BAO_Component': + $status = ts('Are you sure you want to disable this component?'); + break; + + case 'CRM_Core_BAO_CustomField': + $status = ts('Are you sure you want to disable this custom data field?'); + break; + + case 'CRM_Core_BAO_CustomGroup': + $status = ts('Are you sure you want to disable this custom data group? Any profile fields that are linked to custom fields of this group will be disabled.'); + break; + + case 'CRM_Core_BAO_MessageTemplates': + $status = ts('Are you sure you want to disable this message tempate?'); + break; + + case 'CRM_ACL_BAO_ACL': + $status = ts('Are you sure you want to disable this ACL?'); + break; + + case 'CRM_ACL_BAO_EntityRole': + $status = ts('Are you sure you want to disable this ACL Role Assignment?'); + break; + + case 'CRM_Member_BAO_MembershipType': + $status = ts('Are you sure you want to disable this membership type?'); + break; + + case 'CRM_Member_BAO_MembershipStatus': + $status = ts('Are you sure you want to disable this membership status rule?'); + break; + + case 'CRM_Price_BAO_Field': + $status = ts('Are you sure you want to disable this price field?'); + break; + + case 'CRM_Contact_BAO_Group': + $status = ts('Are you sure you want to disable this Group?'); + break; + + case 'CRM_Core_BAO_OptionGroup': + $status = ts('Are you sure you want to disable this Option?'); + break; + + case 'CRM_Contact_BAO_ContactType': + $status = ts('Are you sure you want to disable this Contact Type?'); + break; + + case 'CRM_Core_BAO_OptionValue': + require_once (str_replace('_', DIRECTORY_SEPARATOR, $recordBAO) . '.php'); + $label = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $recordID, 'label'); + $status = ts('Are you sure you want to disable the \'%1\' option ?', array(1 => $label)); + $status .= '

' . ts('WARNING - Disabling an option which has been assigned to existing records will result in that option being cleared when the record is edited.'); + break; + + case 'CRM_Contribute_BAO_ContributionRecur': + $recurDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recordID); + $status = ts('Are you sure you want to mark this recurring contribution as cancelled?'); + $status .= '

' . ts('WARNING - This action sets the CiviCRM recurring contribution status to Cancelled, but does NOT send a cancellation request to the payment processor. You will need to ensure that this recurring payment (subscription) is cancelled by the payment processor.') . ''; + if ($recurDetails->membership_id) { + $status .= '

' . ts('This recurring contribution is linked to an auto-renew membership. If you cancel it, the associated membership will no longer renew automatically. However, the current membership status will not be affected.') . ''; + } + break; + + case 'CRM_Batch_BAO_Batch': + if ($op == 'close') { + $status = ts('Are you sure you want to close this batch?'); + } + elseif ($op == 'open') { + $status = ts('Are you sure you want to reopen this batch?'); + } + elseif ($op == 'delete') { + $status = ts('Are you sure you want to delete this batch?'); + } + elseif ($op == 'remove') { + $status = ts('Are you sure you want to remove this financial transaction?'); + } + elseif ($op == 'export') { + $status = ts('Are you sure you want to close and export this batch?'); + } + else { + $status = ts('Are you sure you want to assign this financial transaction to the batch?'); + } + break; + + default: + $status = ts('Are you sure you want to disable this record?'); + break; + } + } + $statusMessage['status'] = $status; + $statusMessage['show'] = $show; + + echo json_encode($statusMessage); + CRM_Utils_System::civiExit(); + } + + static function getTagList() { + $name = CRM_Utils_Type::escape($_GET['name'], 'String'); + $parentId = CRM_Utils_Type::escape($_GET['parentId'], 'Integer'); + + $isSearch = NULL; + if (isset($_GET['search'])) { + $isSearch = CRM_Utils_Type::escape($_GET['search'], 'Integer'); + } + + $tags = array(); + + // always add current search term as possible tag + // here we append :::value to determine if existing / new tag should be created + if (!$isSearch) { + $tags[] = array( + 'name' => $name, + 'id' => $name . ":::value", + ); + } + + $query = "SELECT id, name FROM civicrm_tag WHERE parent_id = {$parentId} and name LIKE '%{$name}%'"; + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + // make sure we return tag name entered by user only if it does not exists in db + if ($name == $dao->name) { + $tags = array(); + } + // escape double quotes, which break results js + $tags[] = array('name' => addcslashes($dao->name, '"'), + 'id' => $dao->id, + ); + } + + echo json_encode($tags); + CRM_Utils_System::civiExit(); + } + + static function mergeTagList() { + $name = CRM_Utils_Type::escape($_GET['s'], 'String'); + $fromId = CRM_Utils_Type::escape($_GET['fromId'], 'Integer'); + $limit = CRM_Utils_Type::escape($_GET['limit'], 'Integer'); + + // build used-for clause to be used in main query + $usedForTagA = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $fromId, 'used_for'); + $usedForClause = array(); + if ($usedForTagA) { + $usedForTagA = explode(",", $usedForTagA); + foreach ($usedForTagA as $key => $value) { + $usedForClause[] = "t1.used_for LIKE '%{$value}%'"; + } + } + $usedForClause = !empty($usedForClause) ? implode(' OR ', $usedForClause) : '1'; + sort($usedForTagA); + + // query to list mergable tags + $query = " +SELECT t1.name, t1.id, t1.used_for, t2.name as parent +FROM civicrm_tag t1 +LEFT JOIN civicrm_tag t2 ON t1.parent_id = t2.id +WHERE t1.id <> {$fromId} AND + t1.name LIKE '%{$name}%' AND + ({$usedForClause}) +LIMIT $limit"; + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $warning = 0; + if (!empty($dao->used_for)) { + $usedForTagB = explode(',', $dao->used_for); + sort($usedForTagB); + $usedForDiff = array_diff($usedForTagA, $usedForTagB); + if (!empty($usedForDiff)) { + $warning = 1; + } + } + $tag = addcslashes($dao->name, '"') . "|{$dao->id}|{$warning}\n"; + echo $tag = $dao->parent ? (addcslashes($dao->parent, '"') . ' :: ' . $tag) : $tag; + } + CRM_Utils_System::civiExit(); + } + + static function processTags() { + $skipTagCreate = $skipEntityAction = $entityId = NULL; + $action = CRM_Utils_Type::escape($_POST['action'], 'String'); + $parentId = CRM_Utils_Type::escape($_POST['parentId'], 'Integer'); + if ($_POST['entityId']) { + $entityId = CRM_Utils_Type::escape($_POST['entityId'], 'Integer'); + } + + $entityTable = CRM_Utils_Type::escape($_POST['entityTable'], 'String'); + + if ($_POST['skipTagCreate']) { + $skipTagCreate = CRM_Utils_Type::escape($_POST['skipTagCreate'], 'Integer'); + } + + if ($_POST['skipEntityAction']) { + $skipEntityAction = CRM_Utils_Type::escape($_POST['skipEntityAction'], 'Integer'); + } + + // check if user has selected existing tag or is creating new tag + // this is done to allow numeric tags etc. + $tagValue = explode(':::', $_POST['tagID']); + + $createNewTag = FALSE; + $tagID = $tagValue[0]; + if (isset($tagValue[1]) && $tagValue[1] == 'value') { + $createNewTag = TRUE; + } + + $tagInfo = array(); + // if action is select + if ($action == 'select') { + // check the value of tagID + // if numeric that means existing tag + // else create new tag + if (!$skipTagCreate && $createNewTag) { + $params = array( + 'name' => $tagID, + 'parent_id' => $parentId, + ); + + $tagObject = CRM_Core_BAO_Tag::add($params, CRM_Core_DAO::$_nullArray); + + $tagInfo = array( + 'name' => $tagID, + 'id' => $tagObject->id, + 'action' => $action, + ); + $tagID = $tagObject->id; + } + + if (!$skipEntityAction && $entityId) { + // save this tag to contact + $params = array( + 'entity_table' => $entityTable, + 'entity_id' => $entityId, + 'tag_id' => $tagID, + ); + + CRM_Core_BAO_EntityTag::add($params); + } + // if action is delete + } + elseif ($action == 'delete') { + if (!is_numeric($tagID)) { + $tagID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $tagID, 'id', 'name'); + } + if ($entityId) { + // delete this tag entry for the entity + $params = array( + 'entity_table' => $entityTable, + 'entity_id' => $entityId, + 'tag_id' => $tagID, + ); + + CRM_Core_BAO_EntityTag::del($params); + } + $tagInfo = array( + 'id' => $tagID, + 'action' => $action, + ); + } + + echo json_encode($tagInfo); + CRM_Utils_System::civiExit(); + } + + function mappingList() { + $params = array('mappingID'); + foreach ($params as $param) { + $$param = CRM_Utils_Array::value($param, $_POST); + } + + if (!$mappingID) { + echo json_encode(array('error_msg' => 'required params missing.')); + CRM_Utils_System::civiExit(); + } + + $selectionOptions = CRM_Core_BAO_ActionSchedule::getSelection1($mappingID); + extract($selectionOptions); + + $elements = array(); + foreach ($sel4 as $id => $name) { + $elements[] = array( + 'name' => $name, + 'value' => $id, + ); + } + + echo json_encode($elements); + CRM_Utils_System::civiExit(); + } + + function mappingList1() { + $params = array('mappingID'); + foreach ($params as $param) { + $$param = CRM_Utils_Array::value($param, $_POST); + } + + if (!$mappingID) { + echo json_encode(array('error_msg' => 'required params missing.')); + CRM_Utils_System::civiExit(); + } + + $selectionOptions = CRM_Core_BAO_ActionSchedule::getSelection1($mappingID); + extract($selectionOptions); + + $elements = array(); + foreach ($sel5 as $id => $name) { + $elements['sel5'][] = array( + 'name' => $name, + 'value' => $id, + ); + } + $elements['recipientMapping'] = $recipientMapping; + + echo json_encode($elements); + CRM_Utils_System::civiExit(); + } + + static function mergeTags() { + $tagAId = CRM_Utils_Type::escape($_POST['fromId'], 'Integer'); + $tagBId = CRM_Utils_Type::escape($_POST['toId'], 'Integer'); + + $result = CRM_Core_BAO_EntityTag::mergeTags($tagAId, $tagBId); + + if (!empty($result['tagB_used_for'])) { + $usedFor = CRM_Core_OptionGroup::values('tag_used_for'); + foreach ($result['tagB_used_for'] as & $val) { + $val = $usedFor[$val]; + } + $result['tagB_used_for'] = implode(', ', $result['tagB_used_for']); + } + + echo json_encode($result); + CRM_Utils_System::civiExit(); + } + + function recipient() { + $params = array('recipient'); + foreach ($params as $param) { + $$param = CRM_Utils_Array::value($param, $_POST); + } + + if (!$recipient) { + echo json_encode(array('error_msg' => 'required params missing.')); + CRM_Utils_System::civiExit(); + } + + switch ($recipient) { + case 'Participant Status': + $values = CRM_Event_PseudoConstant::participantStatus(); + break; + + case 'Participant Role': + $values = CRM_Event_PseudoConstant::participantRole(); + break; + + default: + exit; + } + + $elements = array(); + foreach ($values as $id => $name) { + $elements[] = array( + 'name' => $name, + 'value' => $id, + ); + } + + echo json_encode($elements); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Admin/Page/APIDoc.php b/CRM/Admin/Page/APIDoc.php new file mode 100644 index 0000000000..b62038a4f6 --- /dev/null +++ b/CRM/Admin/Page/APIDoc.php @@ -0,0 +1,59 @@ +userFramework) { + case 'Drupal': + $this->assign('ufAccessURL', CRM_Utils_System::url('admin/people/permissions')); + break; + + case 'Drupal6': + $this->assign('ufAccessURL', CRM_Utils_System::url('admin/user/permissions')); + break; + + case 'Joomla': + JHTML::_('behavior.modal'); + $url = $config->userFrameworkBaseURL . "index.php?option=com_config&view=component&component=com_civicrm&tmpl=component"; + $jparams = 'rel="{handler: \'iframe\', size: {x: 875, y: 550}, onClose: function() {}}" class="modal"'; + $this->assign('ufAccessURL', $url); + $this->assign('jAccessParams', $jparams); + break; + + case 'WordPress': + $this->assign('ufAccessURL', CRM_Utils_System::url('civicrm/admin/access/wp-permissions', 'reset=1')); + break; + } + return parent::run(); + } +} + diff --git a/CRM/Admin/Page/Admin.php b/CRM/Admin/Page/Admin.php new file mode 100644 index 0000000000..44444dca1c --- /dev/null +++ b/CRM/Admin/Page/Admin.php @@ -0,0 +1,119 @@ + ts('Customize Data and Screens'), + 'Communications' => ts('Communications'), + 'Localization' => ts('Localization'), + 'Users and Permissions' => ts('Users and Permissions'), + 'System Settings' => ts('System Settings'), + ); + + $config = CRM_Core_Config::singleton(); + if (in_array('CiviContribute', $config->enableComponents)) { + $groups['CiviContribute'] = ts('CiviContribute'); + } + + if (in_array('CiviMember', $config->enableComponents)) { + $groups['CiviMember'] = ts('CiviMember'); + } + + if (in_array('CiviEvent', $config->enableComponents)) { + $groups['CiviEvent'] = ts('CiviEvent'); + } + + if (in_array('CiviMail', $config->enableComponents)) { + $groups['CiviMail'] = ts('CiviMail'); + } + + if (in_array('CiviCase', $config->enableComponents)) { + $groups['CiviCase'] = ts('CiviCase'); + } + + if (in_array('CiviReport', $config->enableComponents)) { + $groups['CiviReport'] = ts('CiviReport'); + } + + if (in_array('CiviCampaign', $config->enableComponents)) { + $groups['CiviCampaign'] = ts('CiviCampaign'); + } + + $values = CRM_Core_Menu::getAdminLinks(); + + $this->_showHide = new CRM_Core_ShowHideBlocks(); + foreach ($groups as $group => $title) { + $groupId = str_replace(' ', '_', $group); + + $this->_showHide->addShow("id_{$groupId}_show"); + $this->_showHide->addHide("id_{$groupId}"); + $v = CRM_Core_ShowHideBlocks::links($this, $groupId, '', '', FALSE); + if (isset($values[$group])) { + $adminPanel[$groupId] = $values[$group]; + $adminPanel[$groupId]['show'] = $v['show']; + $adminPanel[$groupId]['hide'] = $v['hide']; + $adminPanel[$groupId]['title'] = $title; + } else { + $adminPanel[$groupId] = array(); + $adminPanel[$groupId]['show'] = ''; + $adminPanel[$groupId]['hide'] = ''; + $adminPanel[$groupId]['title'] = $title; + } + } + $this->assign('adminPanel', $adminPanel); + $this->_showHide->addToTemplate(); + return parent::run(); + } +} + diff --git a/CRM/Admin/Page/CMSUser.php b/CRM/Admin/Page/CMSUser.php new file mode 100644 index 0000000000..aec8a21def --- /dev/null +++ b/CRM/Admin/Page/CMSUser.php @@ -0,0 +1,73 @@ +pushUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + + $controller->setEmbedded(TRUE); + $controller->process(); + $controller->run(); + + return parent::run(); + } +} + diff --git a/CRM/Admin/Page/ConfigTaskList.php b/CRM/Admin/Page/ConfigTaskList.php new file mode 100644 index 0000000000..31ecd8630e --- /dev/null +++ b/CRM/Admin/Page/ConfigTaskList.php @@ -0,0 +1,68 @@ +assign('recentlyViewed', FALSE); + + $destination = CRM_Utils_System::url('civicrm/admin/configtask', + 'reset=1', + FALSE, NULL, FALSE + ); + + $destination = urlencode($destination); + $this->assign('destination', $destination); + + CRM_Core_OptionValue::getValues(array('name' => 'from_email_address'), $optionValue); + if (!empty($optionValue)) { + list($id) = array_keys($optionValue); + $this->assign('fromEmailId', $id); + } + + $payPalProId = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_PaymentProcessorType', + 'PayPal', 'id', 'name' + ); + if ($payPalProId) { + $this->assign('payPalProId', $payPalProId); + } + return parent::run(); + } +} + diff --git a/CRM/Admin/Page/ContactType.php b/CRM/Admin/Page/ContactType.php new file mode 100644 index 0000000000..910f58e962 --- /dev/null +++ b/CRM/Admin/Page/ContactType.php @@ -0,0 +1,163 @@ + + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/options/subtype', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Contact Type'), + ), + CRM_Core_Action::DISABLE => + array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . + 'CRM_Contact_BAO_ContactType' . '\',\'' . 'enable-disable' . + '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Contact Type'), + ), + CRM_Core_Action::ENABLE => + array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . + 'CRM_Contact_BAO_ContactType' . '\',\'' . 'disable-enable' . + '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Contact Type'), + ), + CRM_Core_Action::DELETE => + array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/options/subtype', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Contact Type'), + ), + ); + } + return self::$_links; + } + + function run() { + $action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 0); + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, 0); + if (!$action) { + $this->browse(); + } + return parent::run(); + } + + function browse() { + $rows = CRM_Contact_BAO_ContactType::contactTypeInfo(TRUE); + foreach ($rows as $key => $value) { + $mask = NULL; + if (CRM_Utils_Array::value('is_reserved', $value)) { + $mask = CRM_Core_Action::UPDATE; + } + else { + $mask -= CRM_Core_Action::DELETE - 2; + if (CRM_Utils_Array::value('is_active', $value)) { + $mask -= CRM_Core_Action::ENABLE; + } + else { + $mask -= CRM_Core_Action::DISABLE; + } + } + $rows[$key]['action'] = CRM_Core_Action::formLink(self::links(), $mask, + array('id' => $value['id']) + ); + } + $this->assign('rows', $rows); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_ContactType'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Contact Types'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/options/subtype'; + } +} + diff --git a/CRM/Admin/Page/EventTemplate.php b/CRM/Admin/Page/EventTemplate.php new file mode 100644 index 0000000000..8df7b344d2 --- /dev/null +++ b/CRM/Admin/Page/EventTemplate.php @@ -0,0 +1,164 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/event/manage/settings', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Event Template'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/event/manage', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Event Template'), + ), + ); + } + + return self::$_links; + } + + /** + * Browse all event templates. + * + * @return void + * @access public + * @static + */ + function browse() { + //get all event templates. + $allEventTemplates = array(); + + $eventTemplate = new CRM_Event_DAO_Event(); + + $eventTypes = CRM_Event_PseudoConstant::eventType(); + $participantRoles = CRM_Event_PseudoConstant::participantRole(); + $participantListings = CRM_Event_PseudoConstant::participantListing(); + + //find all event templates. + $eventTemplate->is_template = TRUE; + $eventTemplate->find(); + while ($eventTemplate->fetch()) { + CRM_Core_DAO::storeValues($eventTemplate, $allEventTemplates[$eventTemplate->id]); + + //get listing types. + if ($eventTemplate->participant_listing_id) { + $allEventTemplates[$eventTemplate->id]['participant_listing'] = $participantListings[$eventTemplate->participant_listing_id]; + } + + //get participant role + if ($eventTemplate->default_role_id) { + $allEventTemplates[$eventTemplate->id]['participant_role'] = $participantRoles[$eventTemplate->default_role_id]; + } + + //get event type. + $allEventTemplates[$eventTemplate->id]['event_type'] = $eventTypes[$eventTemplate->event_type_id]; + + //form all action links + $action = array_sum(array_keys($this->links())); + + //add action links. + $allEventTemplates[$eventTemplate->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $eventTemplate->id) + ); + } + $this->assign('rows', $allEventTemplates); + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url(CRM_Utils_System::currentPath(), + 'reset=1&action=browse' + )); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_EventTemplate'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Event Templates'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/eventTemplate'; + } +} + diff --git a/CRM/Admin/Page/Extensions.php b/CRM/Admin/Page/Extensions.php new file mode 100644 index 0000000000..c4999a82e1 --- /dev/null +++ b/CRM/Admin/Page/Extensions.php @@ -0,0 +1,305 @@ +assign( 'destination', $destination ); + } + + /** + * Get BAO Name + * + * @return string Classname of BAO. + */ + function getBAOName() { + return 'CRM_Core_BAO_Extension'; + } + + /** + * Get action Links + * + * @return array (reference) of action links + */ + function &links() { + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::ADD => array( + 'name' => ts('Install'), + 'url' => 'civicrm/admin/extensions', + 'qs' => 'action=add&id=%%id%%&key=%%key%%', + 'title' => ts('Install'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'url' => 'civicrm/admin/extensions', + 'qs' => 'action=enable&id=%%id%%&key=%%key%%', + 'ref' => 'enable-action', + 'title' => ts('Enable'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'url' => 'civicrm/admin/extensions', + 'qs' => 'action=disable&id=%%id%%&key=%%key%%', + 'ref' => 'disable-action', + 'title' => ts('Disable'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Uninstall'), + 'url' => 'civicrm/admin/extensions', + 'qs' => 'action=delete&id=%%id%%&key=%%key%%', + 'title' => ts('Uninstall Extension'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Download'), + 'url' => 'civicrm/admin/extensions', + 'qs' => 'action=update&id=%%id%%&key=%%key%%', + 'title' => ts('Download Extension'), + ), + ); + } + return self::$_links; + } + + /** + * Run the basic page (run essentially starts execution for that page). + * + * @return void + */ + function run() { + $this->preProcess(); + return parent::run(); + } + + /** + * Browse all options + * + * + * @return void + * @access public + * @static + */ + function browse() { + $mapper = CRM_Extension_System::singleton()->getMapper(); + $manager = CRM_Extension_System::singleton()->getManager(); + + // build announcements at the top of the page + $this->assign('extAddNewEnabled', CRM_Extension_System::singleton()->getBrowser()->isEnabled()); + $reqs = CRM_Extension_System::singleton()->getDownloader()->checkRequirements(); + if (empty($reqs)) { + $reqs = CRM_Extension_System::singleton()->getBrowser()->checkRequirements(); + } + $this->assign('extAddNewReqs', $reqs); + + $this->assign('extDbUpgrades', CRM_Extension_Upgrades::hasPending()); + $this->assign('extDbUpgradeUrl', CRM_Utils_System::url('civicrm/admin/extensions/upgrade', 'reset=1')); + + // TODO: Debate whether to immediately detect changes in underlying source tree + // $manager->refresh(); + + // build list of local extensions + $localExtensionRows = array(); // array($pseudo_id => extended_CRM_Extension_Info) + $keys = array_keys($manager->getStatuses()); + sort($keys); + foreach($keys as $key) { + try { + $obj = $mapper->keyToInfo($key); + } catch (CRM_Extension_Exception $ex) { + CRM_Core_Session::setStatus(ts('Failed to read extension (%1). Please refresh the extension list.', array( + 1 => $key, + ))); + continue; + } + + $row = self::createExtendedInfo($obj); + $row['id'] = $obj->key; + + // assign actions + $action = 0; + switch ($row['status']) { + case CRM_Extension_Manager::STATUS_UNINSTALLED: + $action += CRM_Core_Action::ADD; + break; + case CRM_Extension_Manager::STATUS_DISABLED: + $action += CRM_Core_Action::ENABLE; + $action += CRM_Core_Action::DELETE; + break; + case CRM_Extension_Manager::STATUS_DISABLED_MISSING: + $action += CRM_Core_Action::DELETE; + break; + case CRM_Extension_Manager::STATUS_INSTALLED: + case CRM_Extension_Manager::STATUS_INSTALLED_MISSING: + $action += CRM_Core_Action::DISABLE; + break; + default: + } + // TODO if extbrowser is enabled and extbrowser has newer version than extcontainer, + // then $action += CRM_Core_Action::UPDATE + $row['action'] = CRM_Core_Action::formLink(self::links(), + $action, + array( + 'id' => $row['id'], + 'key' => $obj->key, + ) + ); + + $localExtensionRows[$row['id']] = $row; + } + $this->assign('localExtensionRows', $localExtensionRows); + + // build list of availabe downloads + $remoteExtensionRows = array(); + foreach (CRM_Extension_System::singleton()->getBrowser()->getExtensions() as $info) { + $row = (array) $info; + $row['id'] = $info->key; + $action = CRM_Core_Action::UPDATE; + $row['action'] = CRM_Core_Action::formLink(self::links(), + $action, + array( + 'id' => $row['id'], + 'key' => $row['key'], + ) + ); + $remoteExtensionRows[$row['id']] = $row; + } + $this->assign('remoteExtensionRows', $remoteExtensionRows); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_Extensions'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'CRM_Admin_Form_Extensions'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/extensions'; + } + + /** + * function to get userContext params + * + * @param int $mode mode that we are in + * + * @return string + * @access public + */ + function userContextParams($mode = NULL) { + return 'reset=1&action=browse'; + } + + /** + * Take an extension's raw XML info and add information about the + * extension's status on the local system. + * + * The result format resembles the old CRM_Core_Extensions_Extension. + * + * @return array + */ + public static function createExtendedInfo(CRM_Extension_Info $obj) { + $mapper = CRM_Extension_System::singleton()->getMapper(); + $manager = CRM_Extension_System::singleton()->getManager(); + + $extensionRow = (array) $obj; + try { + $extensionRow['path'] = $mapper->keyToBasePath($obj->key); + } catch (CRM_Extension_Exception $e) { + $extensionRow['path'] = ''; + } + $extensionRow['status'] = $manager->getStatus($obj->key); + + switch ($extensionRow['status']) { + case CRM_Extension_Manager::STATUS_UNINSTALLED: + $extensionRow['statusLabel'] = ''; // ts('Uninstalled'); + break; + case CRM_Extension_Manager::STATUS_DISABLED: + $extensionRow['statusLabel'] = ts('Disabled'); + break; + case CRM_Extension_Manager::STATUS_INSTALLED: + $extensionRow['statusLabel'] = ts('Enabled'); // ts('Installed'); + break; + case CRM_Extension_Manager::STATUS_DISABLED_MISSING: + $extensionRow['statusLabel'] = ts('Disabled (Missing)'); + break; + case CRM_Extension_Manager::STATUS_INSTALLED_MISSING: + $extensionRow['statusLabel'] = ts('Enabled (Missing)'); // ts('Installed'); + break; + default: + $extensionRow['statusLabel'] = '(' . $extensionRow['status'] . ')'; + } + return $extensionRow; + } +} + diff --git a/CRM/Admin/Page/ExtensionsUpgrade.php b/CRM/Admin/Page/ExtensionsUpgrade.php new file mode 100644 index 0000000000..3c99d8a02d --- /dev/null +++ b/CRM/Admin/Page/ExtensionsUpgrade.php @@ -0,0 +1,33 @@ + ts('Database Upgrades'), + 'queue' => $queue, + 'errorMode'=> CRM_Queue_Runner::ERROR_ABORT, + 'onEnd' => array('CRM_Admin_Page_ExtensionsUpgrade', 'onEnd'), + 'onEndUrl' => CRM_Utils_System::url(self::END_URL, self::END_PARAMS), + )); + + CRM_Core_Error::debug_log_message('CRM_Admin_Page_ExtensionsUpgrade: Start upgrades'); + $runner->runAllViaWeb(); // does not return + } + + /** + * Handle the final step of the queue + */ + static function onEnd(CRM_Queue_TaskContext $ctx) { + CRM_Core_Error::debug_log_message('CRM_Admin_Page_ExtensionsUpgrade: Finish upgrades'); + } +} diff --git a/CRM/Admin/Page/Job.php b/CRM/Admin/Page/Job.php new file mode 100644 index 0000000000..004fc066f1 --- /dev/null +++ b/CRM/Admin/Page/Job.php @@ -0,0 +1,214 @@ + array( + 'name' => ts('View Job Log'), + 'url' => 'civicrm/admin/joblog', + 'qs' => 'jid=%%id%%&reset=1', + 'title' => ts('See log entries for this Scheduled Job'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/job', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Scheduled Job'), + ), + CRM_Core_Action::EXPORT => array( + 'name' => ts('Execute Now'), + 'url' => 'civicrm/admin/job', + 'qs' => 'action=export&id=%%id%%&reset=1', + 'title' => ts('Execute Scheduled Job Now'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_Job' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Scheduled Job'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_Job' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Scheduled Job'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/job', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Scheduled Job'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // set title and breadcrumb + CRM_Utils_System::setTitle(ts('Settings - Scheduled Jobs')); + $breadCrumb = array(array('title' => ts('Scheduled Jobs'), + 'url' => CRM_Utils_System::url('civicrm/admin', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + + $this->_id = CRM_Utils_Request::retrieve('id', 'String', + $this, FALSE, 0 + ); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 0 + ); + + if ($this->_action == 'export') { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin/job', 'reset=1')); + } + + + return parent::run(); + } + + /** + * Browse all jobs. + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + + // using Export action for Execute. Doh. + if ($this->_action & CRM_Core_Action::EXPORT) { + $jm = new CRM_Core_JobManager(); + $jm->executeJobById($this->_id); + + CRM_Core_Session::setStatus(ts('Selected Scheduled Job has been executed. See the log for details.'), ts("Executed"), "success"); + } + + $sj = new CRM_Core_JobManager(); + $rows = $temp = array(); + foreach ($sj->jobs as $job) { + $action = array_sum(array_keys($this->links())); + + // update enable/disable links. + // CRM-9868- remove enable action for jobs that should never be run automatically via execute action or runjobs url + if ($job->api_action == 'process_membership_reminder_date' || $job->api_action == 'update_greeting') { + $action -= CRM_Core_Action::ENABLE; + $action -= CRM_Core_Action::DISABLE; + } + elseif ($job->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $job->action = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $job->id) + ); + $rows[] = get_object_vars($job); + } + $this->assign('rows', $rows); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_Job'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Scheduled Jobs'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/job'; + } +} + diff --git a/CRM/Admin/Page/JobLog.php b/CRM/Admin/Page/JobLog.php new file mode 100644 index 0000000000..6e35123ba3 --- /dev/null +++ b/CRM/Admin/Page/JobLog.php @@ -0,0 +1,156 @@ + ts('Administration'), + 'url' => CRM_Utils_System::url('civicrm/admin', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + return parent::run(); + } + + /** + * Browse all jobs. + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + + $jid = CRM_Utils_Request::retrieve('jid', 'Positive', $this); + + $sj = new CRM_Core_JobManager(); + + $jobName = NULL; + foreach ($sj->jobs as $i => $job) { + if ($job->id == $jid) { + $jobName = $job->name; + } + } + + $this->assign('jobName', $jobName); + + $dao = new CRM_Core_DAO_JobLog(); + $dao->orderBy('id desc'); + if ($jobName) { + $dao->job_id = $jid; + } + $dao->find(); + $rows = array(); + while ($dao->fetch()) { + unset($row); + CRM_Core_DAO::storeValues($dao, $row); + $rows[$dao->id] = $row; + } + $this->assign('rows', $rows); + + $this->assign('jobId', $jid); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_Job'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Scheduled Jobs'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/job'; + } +} + diff --git a/CRM/Admin/Page/LabelFormats.php b/CRM/Admin/Page/LabelFormats.php new file mode 100644 index 0000000000..0e088ffe62 --- /dev/null +++ b/CRM/Admin/Page/LabelFormats.php @@ -0,0 +1,146 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/labelFormats', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Label Format'), + ), + CRM_Core_Action::COPY => array( + 'name' => ts('Copy'), + 'url' => 'civicrm/admin/labelFormats', + 'qs' => 'action=copy&id=%%id%%', + 'title' => ts('Copy Label Format'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/labelFormats', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Label Format'), + ), + ); + } + + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_LabelFormats'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Mailing Label Formats'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/labelFormats'; + } + + /** + * Browse all Label Format settings. + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + // Get list of configured Label Formats + $labelFormatList = CRM_Core_BAO_LabelFormat::getList(); + + // Add action links to each of the Label Formats + foreach ($labelFormatList as & $format) { + $action = array_sum(array_keys($this->links())); + if (CRM_Utils_Array::value('is_reserved', $format)) { + $action -= CRM_Core_Action::DELETE; + } + $format['action'] = CRM_Core_Action::formLink(self::links(), $action, array('id' => $format['id'])); + } + + // Order Label Formats by weight + $returnURL = CRM_Utils_System::url(self::userContext()); + CRM_Core_BAO_LabelFormat::addOrder($labelFormatList, $returnURL); + + $this->assign('rows', $labelFormatList); + } +} + diff --git a/CRM/Admin/Page/LocationType.php b/CRM/Admin/Page/LocationType.php new file mode 100644 index 0000000000..61511b3d50 --- /dev/null +++ b/CRM/Admin/Page/LocationType.php @@ -0,0 +1,122 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/locationType', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Location Type'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_LocationType' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Location Type'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_LocationType' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Location Type'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/locationType', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Location Type'), + ), + ); + } + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_LocationType'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Location Types'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/locationType'; + } +} + diff --git a/CRM/Admin/Page/MailSettings.php b/CRM/Admin/Page/MailSettings.php new file mode 100644 index 0000000000..2a9c0e674c --- /dev/null +++ b/CRM/Admin/Page/MailSettings.php @@ -0,0 +1,153 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/mailSettings', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Mail Settings'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/mailSettings', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Mail Settings'), + ), + ); + } + + return self::$_links; + } + + /** + * Browse all mail settings. + * + * @return void + * @access public + * @static + */ + function browse() { + //get all mail settings. + $allMailSettings = array(); + $mailSetting = new CRM_Core_DAO_MailSettings(); + + $allProtocols = CRM_Core_PseudoConstant::mailProtocol(); + + //multi-domain support for mail settings. CRM-5244 + $mailSetting->domain_id = CRM_Core_Config::domainID(); + + //find all mail settings. + $mailSetting->find(); + while ($mailSetting->fetch()) { + //replace protocol value with name + $mailSetting->protocol = CRM_Utils_Array::value($mailSetting->protocol, $allProtocols); + CRM_Core_DAO::storeValues($mailSetting, $allMailSettings[$mailSetting->id]); + + //form all action links + $action = array_sum(array_keys($this->links())); + + // disallow the DELETE action for the default set of settings + if ($mailSetting->is_default) { + $action &= ~CRM_Core_Action::DELETE; + } + + //add action links. + $allMailSettings[$mailSetting->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $mailSetting->id) + ); + } + + $this->assign('rows', $allMailSettings); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_MailSettings'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Mail Settings'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/mailSettings'; + } +} + diff --git a/CRM/Admin/Page/Mapping.php b/CRM/Admin/Page/Mapping.php new file mode 100644 index 0000000000..061443618c --- /dev/null +++ b/CRM/Admin/Page/Mapping.php @@ -0,0 +1,140 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/mapping', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Mapping'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/mapping', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Mapping'), + ), + ); + } + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_Mapping'; + } + + /** + * Get form name for edit form + * + * @return string name of this page. + */ + function editName() { + return 'Mapping'; + } + + /** + * Get form name for delete form + * + * @return string name of this page. + */ + function deleteName() { + return 'Mapping'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/mapping'; + } + + /** + * Get name of delete form + * + * @return string Classname of delete form. + */ + function deleteForm() { + return 'CRM_Admin_Form_Mapping'; + } + + /** + * Run the basic page + * + * @return void + */ + function run() { + $sort = 'mapping_type asc'; + return parent::run($sort); + } +} + diff --git a/CRM/Admin/Page/MessageTemplates.php b/CRM/Admin/Page/MessageTemplates.php new file mode 100644 index 0000000000..e0cd1f7a1a --- /dev/null +++ b/CRM/Admin/Page/MessageTemplates.php @@ -0,0 +1,269 @@ +fetch()) { + $this->_revertible[$dao->id] = $dao->orig_id; + } + } + + /** + * Get BAO Name + * + * @return string Classname of BAO. + */ + function getBAOName() { + return 'CRM_Core_BAO_MessageTemplates'; + } + + /** + * Get action Links + * + * @return array (reference) of action links + */ + function &links() { + if (!(self::$_links)) { + $confirm = ts('Are you sure you want to revert this template to the default for this workflow? You will lose any customizations you have made.', array('escape' => 'js')) . '\n\n' . ts('We recommend that you save a copy of the your customized Text and HTML message content to a text file before reverting so you can combine your changes with the system default messages as needed.', array('escape' => 'js')); + self::$_links = array( + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/messageTemplates/add', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit this message template'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_MessageTemplates' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable this message template'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_MessageTemplates' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable this message template'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/messageTemplates', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete this message template'), + ), + CRM_Core_Action::REVERT => array( + 'name' => ts('Revert to Default'), + 'extra' => "onclick = 'return confirm(\"$confirm\");'", + 'url' => 'civicrm/admin/messageTemplates', + 'qs' => 'action=revert&id=%%id%%&selectedChild=workflow', + 'title' => ts('Revert this workflow message template to the system default'), + ), + CRM_Core_Action::VIEW => array( + 'name' => ts('View Default'), + 'url' => 'civicrm/admin/messageTemplates', + 'qs' => 'action=view&id=%%orig_id%%&reset=1', + 'title' => ts('View the system default for this workflow message template'), + ), + ); + } + return self::$_links; + } + + function action(&$object, $action, &$values, &$links, $permission, $forceAction = FALSE) { + if ($object->workflow_id) { + // do not expose action link for reverting to default if the template did not diverge or we just reverted it now + if (!in_array($object->id, array_keys($this->_revertible)) or + ($this->_action & CRM_Core_Action::REVERT and $object->id == $this->_revertedId) + ) { + $action &= ~CRM_Core_Action::REVERT; + $action &= ~CRM_Core_Action::VIEW; + } + + // default workflow templates shouldn’t be deletable + // workflow templates shouldn’t have disable/enable actions (at least for CiviCRM 3.1) + if ($object->workflow_id) { + $action &= ~CRM_Core_Action::DISABLE; + $action &= ~CRM_Core_Action::DELETE; + } + + // rebuild the action links HTML, as we need to handle %%orig_id%% for revertible templates + $values['action'] = CRM_Core_Action::formLink($links, $action, array( + 'id' => $object->id, + 'orig_id' => CRM_Utils_Array::value($object->id, $this->_revertible), + )); + } + else { + $action &= ~CRM_Core_Action::REVERT; + $action &= ~CRM_Core_Action::VIEW; + parent::action($object, $action, $values, $links, $permission); + } + } + + function run($args = NULL, $pageArgs = NULL, $sort = NULL) { + // handle the revert action and offload the rest to parent + if (CRM_Utils_Request::retrieve('action', 'String', $this) & CRM_Core_Action::REVERT) { + + $id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + if (!$this->checkPermission($id, NULL)) { + CRM_Core_Error::fatal(ts('You do not have permission to revert this template.')); + } + + $this->_revertedId = $id; + + CRM_Core_BAO_MessageTemplates::revert($id); + } + + $this->assign('selectedChild', CRM_Utils_Request::retrieve('selectedChild', 'String', $this)); + + return parent::run($args, $pageArgs, $sort); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_MessageTemplates'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return ts('Message Template'); + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/messageTemplates'; + } + + /** + * browse all entities. + * + * @param int $action + * + * @return void + * @access public + */ + function browse() { + $action = func_num_args() ? func_get_arg(0) : NULL; + if ($this->_action & CRM_Core_Action::ADD) { + return; + } + $links = $this->links(); + if ($action == NULL) { + if (!empty($links)) { + $action = array_sum(array_keys($links)); + } + } + + if ($action & CRM_Core_Action::DISABLE) { + $action -= CRM_Core_Action::DISABLE; + } + + if ($action & CRM_Core_Action::ENABLE) { + $action -= CRM_Core_Action::ENABLE; + } + + $messageTemplate = new CRM_Core_BAO_MessageTemplates(); + $messageTemplate->orderBy('msg_title' . ' asc'); + + $userTemplates = array(); + $workflowTemplates = array(); + + // find all objects + $messageTemplate->find(); + while ($messageTemplate->fetch()) { + $values[$messageTemplate->id] = array(); + CRM_Core_DAO::storeValues($messageTemplate, $values[$messageTemplate->id]); + // populate action links + $this->action($messageTemplate, $action, $values[$messageTemplate->id], $links, CRM_Core_Permission::EDIT); + + if (!$messageTemplate->workflow_id) { + $userTemplates[$messageTemplate->id] = $values[$messageTemplate->id]; + } + elseif (!$messageTemplate->is_reserved) { + $workflowTemplates[$messageTemplate->id] = $values[$messageTemplate->id]; + } + } + + $rows = array( + 'userTemplates' => $userTemplates, + 'workflowTemplates' => $workflowTemplates, + ); + + $this->assign('rows', $rows); + } +} + diff --git a/CRM/Admin/Page/Navigation.php b/CRM/Admin/Page/Navigation.php new file mode 100644 index 0000000000..cdd25d3b3c --- /dev/null +++ b/CRM/Admin/Page/Navigation.php @@ -0,0 +1,106 @@ +assign('homeMenuId', $homeMenuId); + + // Add jstree support + CRM_Core_Resources::singleton() + ->addScriptFile('civicrm', 'packages/jquery/plugins/jstree/jquery.jstree.js', 0, 'html-header', FALSE) + ->addStyleFile('civicrm', 'packages/jquery/plugins/jstree/themes/default/style.css', 0, 'html-header'); + } +} + diff --git a/CRM/Admin/Page/OptionGroup.php b/CRM/Admin/Page/OptionGroup.php new file mode 100644 index 0000000000..89d4bfe952 --- /dev/null +++ b/CRM/Admin/Page/OptionGroup.php @@ -0,0 +1,128 @@ + array( + 'name' => ts('Options'), + 'url' => 'civicrm/admin/optionValue', + 'qs' => 'reset=1&action=browse&gid=%%id%%', + 'title' => ts('View and Edit Options'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit Group'), + 'url' => 'civicrm/admin/optionGroup', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Option'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionGroup' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Option'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionGroup' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Option'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/optionGroup', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Option'), + ), + ); + } + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_OptionGroup'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Options'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/optionGroup'; + } +} + diff --git a/CRM/Admin/Page/OptionValue.php b/CRM/Admin/Page/OptionValue.php new file mode 100644 index 0000000000..a8e40ff40d --- /dev/null +++ b/CRM/Admin/Page/OptionValue.php @@ -0,0 +1,242 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/optionValue', + 'qs' => 'action=update&id=%%id%%&gid=%%gid%%&reset=1', + 'title' => ts('Edit Option Value'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionValue' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Option Value'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionValue' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Option Value'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/optionValue', + 'qs' => 'action=delete&id=%%id%%&gid=%%gid%%', + 'title' => ts('Delete Option Value'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + $this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', + $this, FALSE, 0 + ); + $this->assign('gid', $this->_gid); + + if ($this->_gid) { + //get optionGroup name in case of email/postal greeting or addressee, CRM-4575 + $this->_gName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_gid, 'name'); + + $groupTitle = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_gid, 'title', 'id'); + // Some option groups do not have a title set + if (!$groupTitle) { + $groupTitle = $this->_gName; + } + CRM_Utils_System::setTitle(ts('%1 - Option Values', array(1 => $groupTitle))); + } + $breadCrumb = array(array('title' => ts('Option Groups'), + 'url' => CRM_Utils_System::url('civicrm/admin/options', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + + return parent::run(); + } + + /** + * Browse all options value. + * + * + * @return void + * @access public + * @static + */ + function browse() { + $dao = new CRM_Core_DAO_OptionValue(); + + $dao->option_group_id = $this->_gid; + + if (in_array($this->_gName, CRM_Core_OptionGroup::$_domainIDGroups)) { + $dao->domain_id = CRM_Core_Config::domainID(); + } + + if ($this->_gName == 'encounter_medium') { + $mediumIds = CRM_Case_BAO_Case::getUsedEncounterMediums(); + } + elseif ($this->_gName == 'case_status') { + $caseStatusIds = CRM_Case_BAO_Case::getUsedCaseStatuses(); + } + elseif ($this->_gName == 'case_type') { + $caseTypeIds = CRM_Case_BAO_Case::getUsedCaseType(); + } + + $dao->orderBy('name'); + $dao->find(); + + $optionValue = array(); + while ($dao->fetch()) { + $optionValue[$dao->id] = array(); + CRM_Core_DAO::storeValues($dao, $optionValue[$dao->id]); + // form all action links + $action = array_sum(array_keys($this->links())); + if ($dao->is_default) { + $optionValue[$dao->id]['default_value'] = '[x]'; + } + //do not show default option for email/postal greeting and addressee, CRM-4575 + if (!in_array($this->_gName, array( + 'email_greeting', 'postal_greeting', 'addressee'))) { + $this->assign('showIsDefault', TRUE); + } + // update enable/disable links depending on if it is is_reserved or is_active + if ($dao->is_reserved) { + $action = CRM_Core_Action::UPDATE; + } + else { + if ($dao->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + if ((($this->_gName == 'encounter_medium') && in_array($dao->value, $mediumIds)) || + (($this->_gName == 'case_status') && in_array($dao->value, $caseStatusIds)) || + (($this->_gName == 'case_type') && in_array($dao->value, $caseTypeIds)) + ) { + $action -= CRM_Core_Action::DELETE; + } + } + + $optionValue[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $dao->id, 'gid' => $this->_gid) + ); + } + + $this->assign('rows', $optionValue); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_OptionValue'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Options Values'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/optionValue'; + } +} + diff --git a/CRM/Admin/Page/Options.php b/CRM/Admin/Page/Options.php new file mode 100644 index 0000000000..e9ec1ef8c3 --- /dev/null +++ b/CRM/Admin/Page/Options.php @@ -0,0 +1,276 @@ +set('gName', self::$_gName); + } + else { + self::$_gName = $this->get('gName'); + } + if (self::$_gName) { + self::$_gId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', self::$_gName, 'id', 'name'); + } + else { + CRM_Core_Error::fatal(); + } + + self::$_GName = ucwords(str_replace('_', ' ', self::$_gName)); + + $this->assign('gName', self::$_gName); + $this->assign('GName', self::$_GName); + + if (self::$_gName == 'acl_role') { + CRM_Utils_System::setTitle(ts('Manage ACL Roles')); + // set breadcrumb to append to admin/access + $breadCrumb = array(array('title' => ts('Access Control'), + 'url' => CRM_Utils_System::url('civicrm/admin/access', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + } + else { + CRM_Utils_System::setTitle(ts("%1 Options", array(1 => self::$_GName))); + } + if (in_array(self::$_gName, + array( + 'from_email_address', 'email_greeting', + 'postal_greeting', 'addressee', + 'case_status', 'encounter_medium', + 'case_type', + ) + )) { + $this->assign('showIsDefault', TRUE); + } + if (self::$_gName == 'participant_status') { + $this->assign('showCounted', TRUE); + $this->assign('showVisibility', TRUE); + } + + if (self::$_gName == 'participant_role') { + $this->assign('showCounted', TRUE); + } + $config = CRM_Core_Config::singleton(); + if (self::$_gName == 'activity_type') { + $this->assign('showComponent', TRUE); + } + } + + /** + * Get BAO Name + * + * @return string Classname of BAO. + */ + function getBAOName() { + return 'CRM_Core_BAO_OptionValue'; + } + + /** + * Get action Links + * + * @return array (reference) of action links + */ + function &links() { + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/options/' . self::$_gName, + 'qs' => 'group=' . self::$_gName . '&action=update&id=%%id%%&reset=1', + 'title' => ts('Edit %1', array(1 => self::$_gName)), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionValue' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable %1', array(1 => self::$_gName)), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionValue' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable %1', array(1 => self::$_gName)), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/options/' . self::$_gName, + 'qs' => 'group=' . self::$_gName . '&action=delete&id=%%id%%', + 'title' => ts('Delete %1 Type', array(1 => self::$_gName)), + ), + ); + + if (self::$_gName == 'custom_search') { + $runLink = array( + CRM_Core_Action::FOLLOWUP => array( + 'name' => ts('Run'), + 'url' => 'civicrm/contact/search/custom', + 'qs' => 'reset=1&csid=%%value%%', + 'title' => ts('Run %1', array(1 => self::$_gName)), + )); + self::$_links = $runLink + self::$_links; + } + } + return self::$_links; + } + + /** + * Run the basic page (run essentially starts execution for that page). + * + * @return void + */ + function run() { + $this->preProcess(); + return parent::run(); + } + + /** + * Browse all options + * + * + * @return void + * @access public + * @static + */ + function browse() { + + $groupParams = array('name' => self::$_gName); + $optionValue = CRM_Core_OptionValue::getRows($groupParams, $this->links(), 'component_id,weight'); + $gName = self::$_gName; + $returnURL = CRM_Utils_System::url("civicrm/admin/options/$gName", + "reset=1&group=$gName" + ); + $filter = "option_group_id = " . self::$_gId; + CRM_Utils_Weight::addOrder($optionValue, 'CRM_Core_DAO_OptionValue', + 'id', $returnURL, $filter + ); + + // retrieve financial account name for the payment instrument page + if ($gName = "payment_instrument") { + foreach ($optionValue as $key => $option) { + $optionValue[$key]['financial_account'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($key, 'civicrm_option_value'); + } + } + + $this->assign('rows', $optionValue); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_Options'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return self::$_GName; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/options/' . self::$_gName; + } + + /** + * function to get userContext params + * + * @param int $mode mode that we are in + * + * @return string + * @access public + */ + function userContextParams($mode = NULL) { + return 'group=' . self::$_gName . '&reset=1&action=browse'; + } +} + diff --git a/CRM/Admin/Page/ParticipantStatus.php b/CRM/Admin/Page/ParticipantStatus.php new file mode 100644 index 0000000000..129b4a8fee --- /dev/null +++ b/CRM/Admin/Page/ParticipantStatus.php @@ -0,0 +1,113 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/participant_status', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Status'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/participant_status', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Status'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Event_BAO_ParticipantStatusType' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Status'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Event_BAO_ParticipantStatusType' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Status'), + ), + ); + } + return $links; + } + + function browse() { + $statusTypes = array(); + + $dao = new CRM_Event_DAO_ParticipantStatusType; + $dao->orderBy('weight'); + $dao->find(); + + $visibilities = CRM_Core_PseudoConstant::visibility(); + + // these statuses are reserved, but disabled by default - so should be disablable after being enabled + $disablable = array('On waitlist', 'Awaiting approval', 'Pending from waitlist', 'Pending from approval', 'Rejected'); + + while ($dao->fetch()) { + CRM_Core_DAO::storeValues($dao, $statusTypes[$dao->id]); + $action = array_sum(array_keys($this->links())); + if ($dao->is_reserved) { + $action -= CRM_Core_Action::DELETE; + if (!in_array($dao->name, $disablable)) { + $action -= CRM_Core_Action::DISABLE; + } + } + $action -= $dao->is_active ? CRM_Core_Action::ENABLE : CRM_Core_Action::DISABLE; + $statusTypes[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, array('id' => $dao->id)); + $statusTypes[$dao->id]['visibility'] = $visibilities[$dao->visibility_id]; + } + $this->assign('rows', $statusTypes); + } + + function editForm() { + return 'CRM_Admin_Form_ParticipantStatus'; + } + + function editName() { + return 'Participant Status'; + } + + function userContext($mode = NULL) { + return 'civicrm/admin/participant_status'; + } +} + diff --git a/CRM/Admin/Page/PaymentProcessor.php b/CRM/Admin/Page/PaymentProcessor.php new file mode 100644 index 0000000000..9c5d6a261c --- /dev/null +++ b/CRM/Admin/Page/PaymentProcessor.php @@ -0,0 +1,187 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/paymentProcessor', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Payment Processor'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Financial_BAO_PaymentProcessor' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Payment Processor'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Financial_BAO_PaymentProcessor' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Payment Processor'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/paymentProcessor', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Payment Processor'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // set title and breadcrumb + CRM_Utils_System::setTitle(ts('Settings - Payment Processor')); + $breadCrumb = array(array('title' => ts('Administration'), + 'url' => CRM_Utils_System::url('civicrm/admin', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + return parent::run(); + } + + /** + * Browse all payment processors. + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + // get all custom groups sorted by weight + $paymentProcessor = array(); + $dao = new CRM_Financial_DAO_PaymentProcessor(); + $dao->is_test = 0; + $dao->domain_id = CRM_Core_Config::domainID(); + $dao->orderBy('name'); + $dao->find(); + + while ($dao->fetch()) { + $paymentProcessor[$dao->id] = array(); + CRM_Core_DAO::storeValues($dao, $paymentProcessor[$dao->id]); + $paymentProcessor[$dao->id]['payment_processor_type'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType', + $paymentProcessor[$dao->id]['payment_processor_type_id']); + + // form all action links + $action = array_sum(array_keys($this->links())); + + // update enable/disable links. + if ($dao->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $paymentProcessor[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $dao->id) + ); + $paymentProcessor[$dao->id]['financialAccount'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($dao->id, 'civicrm_payment_processor'); + } + + $this->assign('rows', $paymentProcessor); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_PaymentProcessor'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Payment Processors'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/paymentProcessor'; + } +} + diff --git a/CRM/Admin/Page/PaymentProcessorType.php b/CRM/Admin/Page/PaymentProcessorType.php new file mode 100644 index 0000000000..ca50694566 --- /dev/null +++ b/CRM/Admin/Page/PaymentProcessorType.php @@ -0,0 +1,122 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/paymentProcessorType', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Payment ProcessorType'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Financial_BAO_PaymentProcessorType' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Payment ProcessorType'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Financial_BAO_PaymentProcessorType' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Payment ProcessorType'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/paymentProcessorType', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Payment ProcessorType'), + ), + ); + } + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_PaymentProcessorType'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Payment Processor Type'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/paymentProcessorType'; + } +} + diff --git a/CRM/Admin/Page/PdfFormats.php b/CRM/Admin/Page/PdfFormats.php new file mode 100644 index 0000000000..6a68dd9dd3 --- /dev/null +++ b/CRM/Admin/Page/PdfFormats.php @@ -0,0 +1,137 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/pdfFormats', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit PDF Page Format'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/pdfFormats', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete PDF Page Format'), + ), + ); + } + + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_PdfFormats'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'PDF Page Formats'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/pdfFormats'; + } + + /** + * Browse all PDF Page Formats + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + // Get list of configured PDF Page Formats + $pdfFormatList = CRM_Core_BAO_PdfFormat::getList(); + + // Add action links to each of the PDF Page Formats + $action = array_sum(array_keys($this->links())); + foreach ($pdfFormatList as & $format) { + $format['action'] = CRM_Core_Action::formLink(self::links(), $action, array('id' => $format['id'])); + } + + // Order Label Formats by weight + $returnURL = CRM_Utils_System::url(self::userContext()); + CRM_Core_BAO_PdfFormat::addOrder($pdfFormatList, $returnURL); + + $this->assign('rows', $pdfFormatList); + } +} + diff --git a/CRM/Admin/Page/Persistent.php b/CRM/Admin/Page/Persistent.php new file mode 100644 index 0000000000..8562b144e3 --- /dev/null +++ b/CRM/Admin/Page/Persistent.php @@ -0,0 +1,142 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/tplstrings/add', + 'qs' => 'reset=1&action=update&id=%%id%%', + 'title' => ts('Configure'), + ), + ); + } + return self::$_stringActionLinks; + } + + function &customizeActionLinks() { + // check if variable _actionsLinks is populated + if (!isset(self::$_customizeActionLinks)) { + + self::$_customizeActionLinks = array( + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/tplstrings/add', + 'qs' => 'reset=1&action=update&id=%%id%%&config=1', + 'title' => ts('Configure'), + ), + ); + } + return self::$_customizeActionLinks; + } + + /** + * Run the basic page (run essentially starts execution for that page). + * + * @return void + */ + function run() { + CRM_Utils_System::setTitle(ts('DB Template Strings')); + $this->browse(); + return parent::run(); + } + + /** + * Browse all options + * + * + * @return void + * @access public + * @static + */ + function browse() { + $permission = FALSE; + $this->assign('editClass', FALSE); + if (CRM_Core_Permission::check('access CiviCRM')) { + $this->assign('editClass', TRUE); + $permission = TRUE; + } + + $daoResult = new CRM_Core_DAO_Persistent(); + $daoResult->find(); + $schoolValues = array(); + while ($daoResult->fetch()) { + $values[$daoResult->id] = array(); + CRM_Core_DAO::storeValues($daoResult, $values[$daoResult->id]); + if ($daoResult->is_config == 1) { + $values[$daoResult->id]['action'] = CRM_Core_Action::formLink(self::customizeActionLinks(), + NULL, + array('id' => $daoResult->id) + ); + $values[$daoResult->id]['data'] = implode(',', unserialize($daoResult->data)); + $configCustomization[$daoResult->id] = $values[$daoResult->id]; + } + if ($daoResult->is_config == 0) { + $values[$daoResult->id]['action'] = CRM_Core_Action::formLink(self::stringActionLinks(), + NULL, + array('id' => $daoResult->id) + ); + $configStrings[$daoResult->id] = $values[$daoResult->id]; + } + } + $rows = array( + 'configTemplates' => $configStrings, + 'customizeTemplates' => $configCustomization, + ); + $this->assign('rows', $rows); + } +} + diff --git a/CRM/Admin/Page/PreferencesDate.php b/CRM/Admin/Page/PreferencesDate.php new file mode 100644 index 0000000000..276a4c776e --- /dev/null +++ b/CRM/Admin/Page/PreferencesDate.php @@ -0,0 +1,121 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/setting/preferences/date', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Date Type'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // set title and breadcrumb + CRM_Utils_System::setTitle(ts('Settings - Date Preferences')); + return parent::run(); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_PreferencesDate'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Date Preferences'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/setting/preferences/date'; + } +} + diff --git a/CRM/Admin/Page/RelationshipType.php b/CRM/Admin/Page/RelationshipType.php new file mode 100644 index 0000000000..d02959f00c --- /dev/null +++ b/CRM/Admin/Page/RelationshipType.php @@ -0,0 +1,128 @@ + array( + 'name' => ts('View'), + 'url' => 'civicrm/admin/reltype', + 'qs' => 'action=view&id=%%id%%&reset=1', + 'title' => ts('View Relationship Type'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/reltype', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Relationship Type'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contact_BAO_RelationshipType' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Relationship Type'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contact_BAO_RelationshipType' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Relationship Type'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/reltype', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Reletionship Type'), + ), + ); + } + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_RelationshipType'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Relationship Types'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/reltype'; + } +} + diff --git a/CRM/Admin/Page/ScheduleReminders.php b/CRM/Admin/Page/ScheduleReminders.php new file mode 100644 index 0000000000..ef63026348 --- /dev/null +++ b/CRM/Admin/Page/ScheduleReminders.php @@ -0,0 +1,153 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/scheduleReminders', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Schedule Reminders'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_ActionSchedule' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Label Format'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_ActionSchedule' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Label Format'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/scheduleReminders', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Schedule Reminders'), + ), + ); + } + + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_ScheduleReminders'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'ScheduleReminders'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/scheduleReminders'; + } + + /** + * Browse all Scheduled Reminders settings. + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + // Get list of configured reminders + $reminderList = CRM_Core_BAO_ActionSchedule::getList(); + + if (is_array($reminderList)) { + // Add action links to each of the reminders + foreach ($reminderList as & $format) { + $action = array_sum(array_keys($this->links())); + if ($format['is_active']) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + $format['action'] = CRM_Core_Action::formLink(self::links(), $action, array('id' => $format['id'])); + } + } + + $this->assign('rows', $reminderList); + } +} + diff --git a/CRM/Admin/Page/Setting.php b/CRM/Admin/Page/Setting.php new file mode 100644 index 0000000000..ef3ee1b396 --- /dev/null +++ b/CRM/Admin/Page/Setting.php @@ -0,0 +1,47 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/tag', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Tag'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/tag', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Tag'), + ), + CRM_Core_Action::FOLLOWUP => array( + 'name' => ts('Merge'), + 'class' => 'merge_tag', + 'url' => 'javascript:', + 'title' => ts('Merge Tag'), + ), + ); + } + return self::$_links; + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Admin_Form_Tag'; + } + + /** + * Get form name for edit form + * + * @return string name of this page. + */ + function editName() { + return 'Tag'; + } + + /** + * Get form name for delete form + * + * @return string name of this page. + */ + function deleteName() { + return 'Tag'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/tag'; + } + + /** + * Get name of delete form + * + * @return string Classname of delete form. + */ + function deleteForm() { + return 'CRM_Admin_Form_Tag'; + } + + /** + * override function browse() + */ + function browse($action = NULL, $sort = NULL) { + $adminTagSet = FALSE; + if (CRM_Core_Permission::check('administer Tagsets')) { + $adminTagSet = TRUE; + } + $this->assign('adminTagSet', $adminTagSet); + + $reservedClause = !CRM_Core_Permission::check('administer reserved tags') ? "AND t1.is_reserved != 1" : ''; + $query = "SELECT t1.name, t1.id +FROM civicrm_tag t1 LEFT JOIN civicrm_tag t2 ON t1.id = t2.parent_id +WHERE t2.id IS NULL {$reservedClause}"; + $tag = CRM_Core_DAO::executeQuery($query); + + $mergeableTags = array(); + while ($tag->fetch()) { + $mergeableTags[$tag->id] = 1; + } + + $usedFor = CRM_Core_OptionGroup::values('tag_used_for'); + + $query = "SELECT t1.name, t1.id, t2.name as parent, t1.description, t1.used_for, t1.is_tagset, + t1.is_reserved, t1.parent_id, t1.used_for + FROM civicrm_tag t1 LEFT JOIN civicrm_tag t2 ON t1.parent_id = t2.id + GROUP BY t1.parent_id, t1.id"; + + $tag = CRM_Core_DAO::executeQuery($query); + $values = array(); + + $action = CRM_Core_Action::UPDATE + CRM_Core_Action::DELETE; + $permission = CRM_Core_Permission::EDIT; + + while ($tag->fetch()) { + $values[$tag->id] = (array) $tag; + + $used = array(); + if ($values[$tag->id]['used_for']) { + $usedArray = explode(",", $values[$tag->id]['used_for']); + foreach ($usedArray as $key => $value) { + $used[$key] = $usedFor[$value]; + } + } + + if (!empty($used)) { + $values[$tag->id]['used_for'] = implode(", ", $used); + } + + $newAction = $action; + if ($values[$tag->id]['is_reserved']) { + $newAction = CRM_Core_Action::UPDATE; + } + + if ($values[$tag->id]['is_tagset'] && !CRM_Core_Permission::check('administer Tagsets')) { + $newAction = 0; + } + + if (array_key_exists($tag->id, $mergeableTags)) { + $newAction += CRM_Core_Action::FOLLOWUP; + } + + // populate action links + if ($newAction) { + $this->action($tag, $newAction, $values[$tag->id], self::links(), $permission, TRUE); + } + else { + $values[$tag->id]['action'] = ''; + } + } + + $this->assign('rows', $values); + } +} + diff --git a/CRM/Batch/BAO/Batch.php b/CRM/Batch/BAO/Batch.php new file mode 100644 index 0000000000..3f4ffaa98d --- /dev/null +++ b/CRM/Batch/BAO/Batch.php @@ -0,0 +1,779 @@ +copyValues($params); + if ($context == 'financialBatch' && CRM_Utils_Array::value('batchID', $ids)) { + $batch->id = $ids['batchID']; + } + $batch->save(); + + return $batch; + } + + /** + * Retrieve the information about the batch + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return array CRM_Batch_BAO_Batch object on success, null otherwise + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + $batch = new CRM_Batch_DAO_Batch(); + $batch->copyValues($params); + if ($batch->find(TRUE)) { + CRM_Core_DAO::storeValues($batch, $defaults); + return $batch; + } + return NULL; + } + + /** + * Get profile id associated with the batch type + * + * @param int $batchTypeId batch type id + * + * @return int $profileId profile id + * @static + */ + static function getProfileId($batchTypeId) { + //retrieve the profile specific to batch type + switch ($batchTypeId) { + case 1: + //batch profile used for contribution + $profileName = "contribution_batch_entry"; + break; + + case 2: + //batch profile used for memberships + $profileName = "membership_batch_entry"; + } + + // get and return the profile id + return CRM_Core_DAO::getFieldValue('CRM_Core_BAO_UFGroup', $profileName, 'id', 'name'); + } + + /** + * generate batch name + * + * @return batch name + * @static + */ + static function generateBatchName() { + $sql = "SELECT max(id) FROM civicrm_batch"; + $batchNo = CRM_Core_DAO::singleValueQuery($sql) + 1; + return ts('Batch %1', array(1 => $batchNo)) . ': ' . date('Y-m-d'); + } + + /** + * create entity batch entry + * @param array $params associated array + * @return batch array + * @access public + */ + static function addBatchEntity(&$params) { + $entityBatch = new CRM_Batch_DAO_EntityBatch(); + $entityBatch->copyValues($params); + $entityBatch->save(); + return $entityBatch; + } + + /** + * Remove entries from entity batch + * @param array $params associated array + * @return object CRM_Batch_DAO_EntityBatch + */ + static function removeBatchEntity($params) { + $entityBatch = new CRM_Batch_DAO_EntityBatch(); + $entityBatch->copyValues($params); + $entityBatch->delete(); + return $entityBatch; + } + + /** + * function to delete batch entry + * + * @param int $batchId batch id + * + * @return void + * @access public + */ + static function deleteBatch($batchId) { + //delete batch entries from cache + $cacheKeyString = CRM_Batch_BAO_Batch::getCacheKeyForBatch($batchId); + CRM_Core_BAO_Cache::deleteGroup('batch entry', $cacheKeyString, FALSE); + + // delete entry from batch table + $batch = new CRM_Batch_DAO_Batch(); + $batch->id = $batchId; + $batch->delete(); + return true; + } + + /** + * function to get cachekey for batch + * + * @param int $batchId batch id + * + * @retun string $cacheString + * @static + * @access public + */ + static function getCacheKeyForBatch($batchId) { + return "batch-entry-{$batchId}"; + } + + /** + * This function is a wrapper for ajax batch selector + * + * @param array $params associated array for params record id. + * + * @return array $batchList associated array of batch list + * @access public + */ + public function getBatchListSelector(&$params) { + // format the params + $params['offset'] = ($params['page'] - 1) * $params['rp']; + $params['rowCount'] = $params['rp']; + $params['sort'] = CRM_Utils_Array::value('sortBy', $params); + + // get batches + $batches = self::getBatchList($params); + + // get batch totals for open batches + $fetchTotals = array(); + if ($params['context'] == 'financialBatch') { + foreach ($batches as $id => $batch) { + if ($batch['status_id'] == 1) { + $fetchTotals[] = $id; + } + } + } + $totals = self::batchTotals($fetchTotals); + + // add count + $params['total'] = self::getBatchCount($params); + + // format params and add links + $batchList = array(); + + foreach ($batches as $id => $value) { + $batch = array(); + if ($params['context'] == 'financialBatch') { + $batch['check'] = $value['check']; + } + $batch['batch_name'] = $value['title']; + $batch['total'] = $batch['item_count'] = ''; + $batch['payment_instrument'] = $value['payment_instrument']; + $batch['item_count'] = CRM_Utils_Array::value('item_count', $value); + if (CRM_Utils_Array::value('total', $value)) { + $batch['total'] = CRM_Utils_Money::format($value['total']); + } + + // Compare totals with actuals + if (isset($totals[$id])) { + $batch['item_count'] = self::displayTotals($totals[$id]['item_count'], $batch['item_count']); + $batch['total'] = self::displayTotals(CRM_Utils_Money::format($totals[$id]['total']), $batch['total']); + } + $batch['status'] = $value['batch_status']; + $batch['created_by'] = $value['created_by']; + $batch['links'] = $value['action']; + $batchList[$id] = $batch; + } + return $batchList; + } + + /** + * Get list of batches + * + * @param array $params associated array for params + * @access public + */ + static function getBatchList(&$params) { + $whereClause = self::whereClause($params); + + if (!empty($params['rowCount']) && is_numeric($params['rowCount']) + && is_numeric($params['offset']) && $params['rowCount'] > 0 + ) { + $limit = " LIMIT {$params['offset']}, {$params['rowCount']} "; + } + + $orderBy = ' ORDER BY batch.id desc'; + if (!empty($params['sort'])) { + $orderBy = ' ORDER BY ' . $params['sort']; + } + + $query = " + SELECT batch.*, c.sort_name created_by + FROM civicrm_batch batch + INNER JOIN civicrm_contact c ON batch.created_id = c.id + WHERE {$whereClause} + {$orderBy} + {$limit}"; + + $object = CRM_Core_DAO::executeQuery($query, $params, TRUE, 'CRM_Batch_DAO_Batch'); + if (CRM_Utils_Array::value('context', $params)) { + $links = self::links($params['context']); + } + else { + $links = self::links(); + } + + $batchTypes = CRM_Core_PseudoConstant::getBatchType(); + $batchStatus = CRM_Core_PseudoConstant::getBatchStatus(); + $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument(); + + $results = array(); + while ($object->fetch()) { + $values = array(); + $newLinks = $links; + CRM_Core_DAO::storeValues($object, $values); + $action = array_sum(array_keys($newLinks)); + + if ($values['status_id'] == 2 && $params['context'] != 'financialBatch') { + $newLinks = array(); + } + elseif ($params['context'] == 'financialBatch') { + $values['check'] = ""; + + switch ($values['status_id']) { + case '1': + CRM_Utils_Array::remove($newLinks, 'reopen', 'download'); + break; + case '2': + CRM_Utils_Array::remove($newLinks, 'close', 'edit', 'download'); + break; + case '5': + CRM_Utils_Array::remove($newLinks, 'close', 'edit', 'reopen', 'export'); + } + } + if (CRM_Utils_Array::value('type_id', $values)) { + $values['batch_type'] = $batchTypes[$values['type_id']]; + } + $values['batch_status'] = $batchStatus[$values['status_id']]; + $values['created_by'] = $object->created_by; + $values['payment_instrument'] = ''; + if (!empty($object->payment_instrument_id)) { + $values['payment_instrument'] = $paymentInstrument[$object->payment_instrument_id]; + } + $tokens = array('id' => $object->id, 'status' => $values['status_id']); + if ($values['status_id'] == CRM_Core_OptionGroup::getValue('batch_status', 'Exported')) { + $aid = CRM_Core_OptionGroup::getValue('activity_type','Export Accounting Batch'); + $activityParams = array('source_record_id' => $object->id, 'activity_type_id' => $aid ); + $exportActivity = CRM_Activity_BAO_Activity::retrieve($activityParams, $val); + $fid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', $exportActivity->id, 'file_id', 'entity_id' ); + $tokens = array_merge(array('eid' => $exportActivity->id, 'fid' => $fid), $tokens); + } + $values['action'] = CRM_Core_Action::formLink( + $newLinks, + $action, + $tokens + ); + $results[$object->id] = $values; + } + + return $results; + } + + /** + * Get count of batches + * + * @param array $params associated array for params + * @access public + */ + static function getBatchCount(&$params) { + $args = array(); + $whereClause = self::whereClause($params, $args); + $query = " SELECT COUNT(*) FROM civicrm_batch batch + INNER JOIN civicrm_contact c ON batch.created_id = c.id + WHERE {$whereClause}"; + return CRM_Core_DAO::singleValueQuery($query); + } + + /** + * Format where clause for getting lists of batches + * + * @param array $params associated array for params + * @access public + */ + function whereClause($params) { + $clauses = array(); + // Exclude data-entry batches + if (empty($params['status_id'])) { + $clauses[] = 'batch.status_id <> 3'; + } + + $fields = array( + 'title' => 'String', + 'sort_name' => 'String', + 'status_id' => 'Integer', + 'payment_instrument_id' => 'Integer', + 'item_count' => 'Integer', + 'total' => 'Float', + ); + + foreach ($fields as $field => $type) { + $table = $field == 'sort_name' ? 'c' : 'batch'; + if (isset($params[$field])) { + $value = CRM_Utils_Type::escape($params[$field], $type, FALSE); + if ($value && $type == 'String') { + $clauses[] = "$table.$field LIKE '%$value%'"; + } + elseif ($value && $type == 'Float') { + $clauses[] = "$table.$field = '$value'"; + } + elseif ($value) { + $clauses[] = "$table.$field = $value"; + } + } + } + return $clauses ? implode(' AND ', $clauses) : '1'; + } + + /** + * Function to define action links + * + * @return array $links array of action links + * @access public + */ + function links($context = NULL) { + if ($context == 'financialBatch') { + $links = array( + 'transaction' => array( + 'name' => ts('Transactions'), + 'url' => 'civicrm/batchtransaction', + 'qs' => 'reset=1&bid=%%id%%', + 'title' => ts('View/Add Transactions to Batch'), + ), + 'edit' => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/financial/batch', + 'qs' => 'reset=1&action=update&id=%%id%%&context=1', + 'title' => ts('Edit Batch'), + ), + 'close' => array( + 'name' => ts('Close'), + 'title' => ts('Close Batch'), + 'url' => '#', + 'extra' => 'rel="close"', + ), + 'export' => array( + 'name' => ts('Export'), + 'title' => ts('Export Batch'), + 'url' => '#', + 'extra' => 'rel="export"', + ), + 'reopen' => array( + 'name' => ts('Re-open'), + 'title' => ts('Re-open Batch'), + 'url' => '#', + 'extra' => 'rel="reopen"', + ), + 'delete' => array( + 'name' => ts('Delete'), + 'title' => ts('Delete Batch'), + 'url' => '#', + 'extra' => 'rel="delete"', + ), + 'download' => array( + 'name' => ts('Download'), + 'url' => 'civicrm/file', + 'qs' => 'reset=1&id=%%fid%%&eid=%%eid%%', + 'title' => ts('Download Batch'), + ) + ); + } + else { + $links = array( + CRM_Core_Action::COPY => array( + 'name' => ts('Enter records'), + 'url' => 'civicrm/batch/entry', + 'qs' => 'id=%%id%%&reset=1', + 'title' => ts('Batch Data Entry'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/batch', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Batch'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/batch', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Batch'), + ) + ); + } + return $links; + } + + /** + * function to get batch list + * + * @return array array of batches + */ + static function getBatches() { + $query = 'SELECT id, title + FROM civicrm_batch + WHERE type_id IN (1,2) + AND status_id = 2 + ORDER BY id DESC'; + + $batches = array(); + $dao = CRM_Core_DAO::executeQuery($query); + while ( $dao->fetch( ) ) { + $batches[$dao->id] = $dao->title; + } + return $batches; + } + + + + /** + * Calculate sum of all entries in a batch + * Used to validate and update item_count and total when closing an accounting batch + * + * @param array $batchIds + * @return array + */ + static function batchTotals($batchIds) { + $totals = array_fill_keys($batchIds, array('item_count' => 0, 'total' => 0)); + if ($batchIds) { + $sql = "SELECT eb.batch_id, COUNT(tx.id) AS item_count, SUM(tx.total_amount) AS total + FROM civicrm_entity_batch eb + INNER JOIN civicrm_financial_trxn tx ON tx.id = eb.entity_id AND eb.entity_table = 'civicrm_financial_trxn' + WHERE eb.batch_id IN (" . implode(',', $batchIds) . ") + GROUP BY eb.batch_id"; + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $totals[$dao->batch_id] = (array) $dao; + } + $dao->free(); + } + return $totals; + } + + /** + * Format markup for comparing two totals + * + * @param $actual: calculated total + * @param $expected: user-entered total + * @return array + */ + static function displayTotals($actual, $expected) { + $class = 'actual-value'; + if ($expected && $expected != $actual) { + $class .= ' crm-error'; + } + $actualTitle = ts('Current Total'); + $output = "$actual"; + if ($expected) { + $expectedTitle = ts('Expected Total'); + $output .= " / $expected"; + } + return $output; + } + + /** + * Function for exporting financial accounts, currently we support CSV and IIF format + * @see http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Specifications+-++Batches#CiviAccountsSpecifications-Batches-%C2%A0Overviewofimplementation + * + * @param array $batchIds associated array of batch ids + * @param string $exportFormat export format + * + * @return void + * + * @static + * @access public + */ + static function exportFinancialBatch($batchIds, $exportFormat) { + if (empty($batchIds)) { + CRM_Core_Error::fatal(ts('No batches were selected.')); + return; + } + if (empty($exportFormat)) { + CRM_Core_Error::fatal(ts('No export format selected.')); + return; + } + self::$_exportFormat = $exportFormat; + + // Instantiate appropriate exporter based on user-selected format. + $exporterClass = "CRM_Financial_BAO_ExportFormat_" . self::$_exportFormat; + if ( class_exists( $exporterClass ) ) { + $exporter = new $exporterClass(); + } + else { + CRM_Core_Error::fatal("Could not locate exporter: $exporterClass"); + } + switch (self::$_exportFormat) { + case 'CSV': + foreach ($batchIds as $batchId) { + $export[$batchId] = $exporter->generateExportQuery($batchId); + } + $exporter->makeCSV($export); + break; + + case 'IIF': + foreach ($batchIds as $batchId) { + $export[$batchId] = $exporter->generateExportQuery($batchId); + } + $exporter->makeIIF($export); + break; + } + } + + static function closeReOpen($batchIds = array(), $status) { + $batchStatus = CRM_Core_PseudoConstant::accountOptionValues( 'batch_status' ); + $params['status_id'] = CRM_Utils_Array::key( $status, $batchStatus ); + $session = CRM_Core_Session::singleton( ); + $params['modified_date'] = date('YmdHis'); + $params['modified_id'] = $session->get( 'userID' ); + foreach ($batchIds as $key => $value) { + $params['id'] = $ids['batchID'] = $value; + self::create($params, $ids); + } + $url = CRM_Utils_System::url('civicrm/financial/financialbatches',"reset=1&batchStatus={$params['status_id']}"); + CRM_Utils_System::redirect($url); + } + + /** + * Function to retrieve financial items assigned for a batch + * + * @param int $entityID + * @param array $returnValues + * @param null $notPresent + * @param null $params + * @return Object + */ + static function getBatchFinancialItems($entityID, $returnValues, $notPresent = NULL, $params = NULL, $getCount = FALSE) { + if (!$getCount) { + if (!empty($params['rowCount']) && + $params['rowCount'] > 0 + ) { + $limit = " LIMIT {$params['offset']}, {$params['rowCount']} "; + } + } + // action is taken depending upon the mode + $select = 'civicrm_financial_trxn.id '; + if (!empty( $returnValues)) { + $select .= " , ".implode(' , ', $returnValues); + } + + $orderBy = " ORDER BY civicrm_financial_trxn.id"; + if (CRM_Utils_Array::value('sort', $params)) { + $orderBy = ' ORDER BY ' . CRM_Utils_Array::value('sort', $params); + } + + $from = "civicrm_financial_trxn +LEFT JOIN civicrm_entity_financial_trxn ON civicrm_entity_financial_trxn.financial_trxn_id = civicrm_financial_trxn.id +LEFT JOIN civicrm_entity_batch ON civicrm_entity_batch.entity_id = civicrm_financial_trxn.id +LEFT JOIN civicrm_contribution ON civicrm_contribution.id = civicrm_entity_financial_trxn.entity_id +LEFT JOIN civicrm_financial_type ON civicrm_financial_type.id = civicrm_contribution.financial_type_id +LEFT JOIN civicrm_contact contact_a ON contact_a.id = civicrm_contribution.contact_id +LEFT JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id = civicrm_contribution.id +"; + + $searchFields = + array( + 'sort_name', + 'financial_type_id', + 'contribution_page_id', + 'contribution_payment_instrument_id', + 'contribution_transaction_id', + 'contribution_source', + 'contribution_currency_type', + 'contribution_pay_later', + 'contribution_recurring', + 'contribution_test', + 'contribution_thankyou_date_is_not_null', + 'contribution_receipt_date_is_not_null', + 'contribution_pcp_made_through_id', + 'contribution_pcp_display_in_roll', + 'contribution_date_relative', + 'contribution_amount_low', + 'contribution_amount_high', + 'contribution_in_honor_of', + 'contact_tags', + 'group', + 'contribution_date_relative', + 'contribution_date_high', + 'contribution_date_low', + 'contribution_check_number', + 'contribution_status_id', + ); + $values = array(); + foreach ($searchFields as $field) { + if (isset($params[$field])) { + $values[$field] = $params[$field]; + if ($field == 'sort_name') { + $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id + LEFT JOIN civicrm_email ON contact_b.id = civicrm_email.contact_id"; + } + if ($field == 'contribution_in_honor_of') { + $from .= " LEFT JOIN civicrm_contact contact_b ON contact_b.id = civicrm_contribution.contact_id"; + } + if ($field == 'contact_tags') { + $from .= " LEFT JOIN civicrm_entity_tag `civicrm_entity_tag-{$params[$field]}` ON `civicrm_entity_tag-{$params[$field]}`.entity_id = contact_a.id"; + } + if ($field == 'group') { + $from .= " LEFT JOIN civicrm_group_contact `civicrm_group_contact-{$params[$field]}` ON contact_a.id = `civicrm_group_contact-{$params[$field]}`.contact_id "; + } + if ($field == 'contribution_date_relative') { + $relativeDate = explode('.', $params[$field]); + $date = CRM_Utils_Date::relativeToAbsolute($relativeDate[0], $relativeDate[1]); + $values['contribution_date_low'] = $date['from']; + $values['contribution_date_high'] = $date['to']; + } + $searchParams = CRM_Contact_BAO_Query::convertFormValues($values); + $query = new CRM_Contact_BAO_Query($searchParams, + CRM_Contribute_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CONTRIBUTE, + FALSE + ),NULL, FALSE, FALSE,CRM_Contact_BAO_Query::MODE_CONTRIBUTE + ); + if ($field == 'contribution_date_high' || $field == 'contribution_date_low') { + $query->dateQueryBuilder($params[$field], 'civicrm_contribution', 'contribution_date', 'receive_date', 'Contribution Date'); + } + } + } + if (!empty($query->_where[0])) { + $where = implode(' AND ', $query->_where[0])." + AND civicrm_entity_batch.batch_id IS NULL + AND civicrm_entity_financial_trxn.entity_table = 'civicrm_contribution'"; + $searchValue = TRUE; + } + else { + $searchValue = FALSE; + } + + if (!$searchValue) { + if (!$notPresent) { + $where = " ( civicrm_entity_batch.batch_id = {$entityID} + AND civicrm_entity_batch.entity_table = 'civicrm_financial_trxn' + AND civicrm_entity_financial_trxn.entity_table = 'civicrm_contribution') "; + } + else { + $where = " ( civicrm_entity_batch.batch_id IS NULL + AND civicrm_entity_financial_trxn.entity_table = 'civicrm_contribution')"; + } + } + + $sql = "SELECT {$select} +FROM {$from} +WHERE {$where} +{$orderBy} +"; + + if (isset($limit)) { + $sql .= "{$limit}"; + } + + $result = CRM_Core_DAO::executeQuery($sql); + return $result; + } + + /** + * function to get batch names + * @param string $batchIds + * + * @return array array of batches + */ + static function getBatchNames($batchIds) { + $query = 'SELECT id, title + FROM civicrm_batch + WHERE id IN ('.$batchIds.')'; + + $batches = array(); + $dao = CRM_Core_DAO::executeQuery($query); + while ( $dao->fetch( ) ) { + $batches[$dao->id] = $dao->title; + } + return $batches; + } + + /** + * Function get batch statuses + * + * @param string $batchIds + * + * @return array array of batches + */ + static function getBatchStatuses($batchIds) { + $query = 'SELECT id, status_id + FROM civicrm_batch + WHERE id IN ('.$batchIds.')'; + + $batches = array(); + $dao = CRM_Core_DAO::executeQuery($query); + while ( $dao->fetch( ) ) { + $batches[$dao->id] = $dao->status_id; + } + return $batches; + } +} diff --git a/CRM/Batch/Form/Batch.php b/CRM/Batch/Form/Batch.php new file mode 100644 index 0000000000..aa52c54750 --- /dev/null +++ b/CRM/Batch/Form/Batch.php @@ -0,0 +1,142 @@ +replaceUserContext(CRM_Utils_System::url('civicrm/batch', "reset=1")); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $this->applyFilter('__ALL__', 'trim'); + $attributes = CRM_Core_DAO::getAttribute('CRM_Batch_DAO_Batch'); + $this->add('text', 'title', ts('Batch Name'), $attributes['name'], TRUE); + + $batchTypes = CRM_Core_PseudoConstant::getBatchType(); + // unset non-related types + unset($batchTypes[3]); + unset($batchTypes[4]); + $type = $this->add('select', 'type_id', ts('Type'), $batchTypes); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $type->freeze(); + } + + $this->add('textarea', 'description', ts('Description'), $attributes['description']); + $this->add('text', 'item_count', ts('Number of items'), $attributes['item_count'], TRUE); + $this->add('text', 'total', ts('Total Amount'), $attributes['total'], TRUE); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + + if ($this->_action & CRM_Core_Action::ADD) { + // set batch name default + $defaults['title'] = CRM_Batch_BAO_Batch::generateBatchName(); + } + else { + $defaults = $this->_values; + } + + + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Core_Session::setStatus("", ts("Batch Deleted"), "success"); + CRM_Batch_BAO_Batch::deleteBatch($this->_id); + return; + } + + if ($this->_id) { + $params['id'] = $this->_id; + } + else { + $session = CRM_Core_Session::singleton(); + $params['created_id'] = $session->get('userID'); + $params['created_date'] = CRM_Utils_Date::processDate( date( "Y-m-d" ), date( "H:i:s" ) ); + } + + // always create with data entry status + $params['status_id'] = 3; + $batch = CRM_Batch_BAO_Batch::create($params); + + // redirect to batch entry page. + $session = CRM_Core_Session::singleton(); + if ( $this->_action & CRM_Core_Action::ADD ) { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/batch/entry', "id={$batch->id}&reset=1&action=add")); + } + else { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/batch/entry', "id={$batch->id}&reset=1")); + } + } + //end of function +} + diff --git a/CRM/Batch/Form/Entry.php b/CRM/Batch/Form/Entry.php new file mode 100644 index 0000000000..0168618cb9 --- /dev/null +++ b/CRM/Batch/Form/Entry.php @@ -0,0 +1,742 @@ +_batchId = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + + if (empty($this->_batchInfo)) { + $params = array('id' => $this->_batchId); + CRM_Batch_BAO_Batch::retrieve($params, $this->_batchInfo); + + $this->assign('batchTotal', $this->_batchInfo['total']); + $this->assign('batchType', $this->_batchInfo['type_id']); + + // get the profile id associted with this batch type + $this->_profileId = CRM_Batch_BAO_Batch::getProfileId($this->_batchInfo['type_id']); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + if (!$this->_profileId) { + CRM_Core_Error::fatal(ts('Profile for bulk data entry is missing.')); + } + + $this->addElement('hidden', 'batch_id', $this->_batchId); + + // get the profile information + if ($this->_batchInfo['type_id'] == 1) { + CRM_Utils_System::setTitle(ts('Batch Data Entry for Contributions')); + $customFields = CRM_Core_BAO_CustomField::getFields('Contribution'); + } + else { + CRM_Utils_System::setTitle(ts('Batch Data Entry for Memberships')); + $customFields = CRM_Core_BAO_CustomField::getFields('Membership'); + } + + $this->_fields = array(); + $this->_fields = CRM_Core_BAO_UFGroup::getFields($this->_profileId, FALSE, CRM_Core_Action::VIEW); + + // remove file type field and then limit fields + $suppressFields = FALSE; + $removehtmlTypes = array('File', 'Autocomplete-Select'); + foreach ($this->_fields as $name => $field) { + if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) && + in_array($this->_fields[$name]['html_type'], $removehtmlTypes) + ) { + $suppressFields = TRUE; + unset($this->_fields[$name]); + } + + //fix to reduce size as we are using this field in grid + if (is_array($field['attributes']) && $this->_fields[$name]['attributes']['size'] > 19) { + //shrink class to "form-text-medium" + $this->_fields[$name]['attributes']['size'] = 19; + } + } + + $this->addFormRule(array('CRM_Batch_Form_Entry', 'formRule'), $this); + + // add the force save button + $forceSave = $this->getButtonName('upload', 'force'); + + $this->addElement('submit', + $forceSave, + ts('Ignore Mismatch & Process the Batch?') + ); + + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Validate & Process the Batch'), + 'isDefault' => TRUE + ), + array( + 'type' => 'cancel', + 'name' => ts('Save & Continue Later'), + ) + ) + ); + + $this->assign('rowCount', $this->_batchInfo['item_count'] + 1); + + $fileFieldExists = FALSE; + $preserveDefaultsArray = array( + 'first_name', 'last_name', 'middle_name', + 'organization_name', + 'household_name', + ); + + $contactTypes = array('Contact', 'Individual', 'Household', 'Organization'); + for ($rowNumber = 1; $rowNumber <= $this->_batchInfo['item_count']; $rowNumber++) { + CRM_Contact_Form_NewContact::buildQuickForm($this, $rowNumber, NULL, TRUE, 'primary_'); + + // special field specific to membership batch udpate + if ($this->_batchInfo['type_id'] == 2) { + $options = array( + 1 => ts('Add Membership'), + 2 => ts('Renew Membership'), + ); + $this->add('select', "member_option[$rowNumber]", '', $options); + } + + foreach ($this->_fields as $name => $field) { + if (in_array($field['field_type'], $contactTypes)) { + $this->_contactFields[$field['name']] = 1; + } + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, NULL, FALSE, FALSE, $rowNumber); + + if (in_array($field['name'], $preserveDefaultsArray)) { + $this->_preserveDefault = FALSE; + } + } + } + + $this->assign('fields', $this->_fields); + $this->assign('contactFields', $this->_contactFields); + + // don't set the status message when form is submitted. + $buttonName = $this->controller->getButtonName('submit'); + + if ($suppressFields && $buttonName != '_qf_Entry_next') { + CRM_Core_Session::setStatus(ts("FILE or Autocomplete Select type field(s) in the selected profile are not supported for Batch Update."), ts("Some fields have been excluded."), "info"); + } + } + + /** + * form validations + * + * @param array $params posted values of the form + * @param array $files list of errors to be posted back to the form + * @param array $self form object + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($params, $files, $self) { + $errors = array(); + + if (CRM_Utils_Array::value('_qf_Entry_upload_force', $params)) { + return TRUE; + } + + $batchTotal = 0; + foreach ($params['field'] as $key => $value) { + $batchTotal += $value['total_amount']; + + //membership type is required for membership batch entry + if ( $self->_batchInfo['type_id'] == 2 ) { + if ( !CRM_Utils_Array::value( 1, $value['membership_type'] ) ) { + $errors["field[$key][membership_type]"] = ts('Membership type is a required field.'); + } + } + } + + if ($batchTotal != $self->_batchInfo['total']) { + $self->assign('batchAmountMismatch', TRUE); + $errors['_qf_defaults'] = ts('Total for amounts entered below does not match the expected batch total.'); + } + + if (!empty($errors)) { + return $errors; + } + + $self->assign('batchAmountMismatch', FALSE); + return TRUE; + } + + /** + * Override default cancel action + */ + function cancelAction() { + // redirect to batch listing + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/batch', 'reset=1')); + CRM_Utils_System::civiExit(); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if (empty($this->_fields)) { + return; + } + + // for add mode set smart defaults + if ( $this->_action & CRM_Core_Action::ADD ) { + list( $currentDate, $currentTime ) = CRM_Utils_Date::setDateDefaults( NULL, 'activityDateTime' ); + + //get all status + $allStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + $completeStatus = array_search( 'Completed', $allStatus ); + $specialFields = array( + 'join_date' => $currentDate, + 'receive_date' => $currentDate, + 'receive_date_time' => $currentTime, + 'contribution_status_id' => $completeStatus + ); + + for ($rowNumber = 1; $rowNumber <= $this->_batchInfo['item_count']; $rowNumber++) { + foreach ($specialFields as $key => $value ) { + $defaults['field'][$rowNumber][$key] = $value; + } + } + } + else { + // get the existing batch values from cache table + $cacheKeyString = CRM_Batch_BAO_Batch::getCacheKeyForBatch($this->_batchId); + $defaults = CRM_Core_BAO_Cache::getItem('batch entry', $cacheKeyString); + } + return $defaults; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + + $params['actualBatchTotal'] = 0; + + // get the profile information + if ($this->_batchInfo['type_id'] == 1) { + $this->processContribution($params); + } + else { + $this->processMembership($params); + } + + // update batch to close status + $paramValues = array( + 'id' => $this->_batchId, + // close status + 'status_id' => 2, + 'total' => $params['actualBatchTotal'], + ); + + CRM_Batch_BAO_Batch::create($paramValues); + + // delete from cache table + $cacheKeyString = CRM_Batch_BAO_Batch::getCacheKeyForBatch($this->_batchId); + CRM_Core_BAO_Cache::deleteGroup('batch entry', $cacheKeyString, FALSE); + + // set success status + CRM_Core_Session::setStatus("", ts("Batch Processed."), "success"); + + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/batch', 'reset=1')); + } + + /** + * process contribution records + * + * @param array $params associated array of submitted values + * + * @access public + * + * @return None + */ + private function processContribution(&$params) { + $dates = array( + 'receive_date', + 'receipt_date', + 'thankyou_date', + 'cancel_date', + ); + + // get the price set associated with offline contribution record. + $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', 'default_contribution_amount', 'id', 'name'); + $this->_priceSet = current(CRM_Price_BAO_Set::getSetDetail($priceSetId)); + $fieldID = key($this->_priceSet['fields']); + + $assetRelation = key(CRM_CORE_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' ")); + + if (isset($params['field'])) { + foreach ($params['field'] as $key => $value) { + // if contact is not selected we should skip the row + if (!CRM_Utils_Array::value($key, $params['primary_contact_select_id'])) { + continue; + } + + $value['contact_id'] = CRM_Utils_Array::value($key, $params['primary_contact_select_id']); + + // update contact information + $this->updateContactInfo($value); + + // handle soft credit + if (CRM_Utils_Array::value('soft_credit_contact_select_id', $params) && CRM_Utils_Array::value($key, $params['soft_credit_contact_select_id'])) { + $value['soft_credit_to'] = $params['soft_credit_contact_select_id'][$key]; + } + + $value['custom'] = CRM_Core_BAO_CustomField::postProcess($value, + CRM_Core_DAO::$_nullObject, + $key, + 'Contribution' + ); + + foreach ($dates as $val) { + if ( CRM_Utils_Array::value( $val, $value ) ) { + $value[$val] = CRM_Utils_Date::processDate( $value[$val], $value[$val . '_time'], TRUE ); + } + } + + if (CRM_Utils_Array::value('send_receipt', $value)) { + $value['receipt_date'] = date('Y-m-d His'); + } + + if ($value['financial_type']) { + $value['financial_type_id'] = $value['financial_type']; + } + + if (CRM_Utils_Array::value('payment_instrument', $value)) { + $value['payment_instrument_id'] = $value['payment_instrument']; + } + + if (CRM_Utils_Array::value('contribution_source', $value)) { + $value['source'] = $value['contribution_source']; + } + + if (CRM_Utils_Array::value('contribution_note', $value)) { + $value['note'] = $value['contribution_note']; + } + + $params['actualBatchTotal'] += $value['total_amount']; + + unset($value['contribution_note']); + unset($value['financial_type']); + unset($value['contribution_source']); + + $value['batch_id'] = $this->_batchId; + $value['skipRecentView'] = TRUE; + + // build line item params + $this->_priceSet['fields'][$fieldID]['options'][$fieldID]['amount'] = $value['total_amount']; + $value['price_'.$fieldID] = 1; + + $lineItem = array(); + CRM_Price_BAO_Set::processAmount($this->_priceSet['fields'], $value, $lineItem[$priceSetId]); + + //unset amount level since we always use quick config price set + unset($value['amount_level']); + + //CRM-11529 for backoffice transactions + //when financial_type_id is passed in form, update the + //lineitems with the financial type selected in form + if (CRM_Utils_Array::value('financial_type_id', $value) && CRM_Utils_Array::value($priceSetId, $lineItem)) { + foreach ($lineItem[$priceSetId] as &$values) { + $values['financial_type_id'] = $value['financial_type_id']; + } + } + $value['line_item'] = $lineItem; + + //finally call contribution create for all the magic + $contribution = CRM_Contribute_BAO_Contribution::create($value, CRM_Core_DAO::$_nullArray); + + //process premiums + if (CRM_Utils_Array::value('product_name', $value)) { + if ($value['product_name'][0] > 0) { + list($products, $options) = CRM_Contribute_BAO_Premium::getPremiumProductInfo(); + + $value['hidden_Premium'] = 1; + $value['product_option'] = CRM_Utils_Array::value( + $value['product_name'][1], + $options[$value['product_name'][0]] + ); + + $premiumParams = array( + 'product_id' => $value['product_name'][0], + 'contribution_id' => $contribution->id, + 'product_option' => $value['product_option'], + 'quantity' => 1, + ); + CRM_Contribute_BAO_Contribution::addPremium($premiumParams); + } + } + // end of premium + + //send receipt mail. + if ( $contribution->id && + CRM_Utils_Array::value( 'send_receipt', $value ) ) { + // add the domain email id + $domainEmail = CRM_Core_BAO_Domain::getNameAndEmail(); + $domainEmail = "$domainEmail[0] <$domainEmail[1]>"; + + $value['from_email_address'] = $domainEmail; + $value['contribution_id'] = $contribution->id; + CRM_Contribute_Form_AdditionalInfo::emailReceipt( $this, $value ); + } + } + } + } + //end of function + + /** + * process membership records + * + * @param array $params associated array of submitted values + * + * @access public + * + * @return None + */ + private function processMembership(&$params) { + $dateTypes = array( + 'join_date' => 'joinDate', + 'membership_start_date' => 'startDate', + 'membership_end_date' => 'endDate' + ); + + $dates = array( + 'join_date', + 'start_date', + 'end_date', + 'reminder_date' + ); + + // get the price set associated with offline memebership + $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', 'default_membership_type_amount', 'id', 'name'); + $this->_priceSet = $priceSets = current(CRM_Price_BAO_Set::getSetDetail($priceSetId)); + + if (isset($params['field'])) { + $customFields = array(); + foreach ($params['field'] as $key => $value) { + // if contact is not selected we should skip the row + if (!CRM_Utils_Array::value($key, $params['primary_contact_select_id'])) { + continue; + } + + $value['contact_id'] = CRM_Utils_Array::value($key, $params['primary_contact_select_id']); + + // update contact information + $this->updateContactInfo($value); + + $membershipTypeId = $value['membership_type_id'] = $value['membership_type'][1]; + + foreach ($dateTypes as $dateField => $dateVariable) { + $$dateVariable = CRM_Utils_Date::processDate($value[$dateField]); + } + + $calcDates = array(); + $calcDates[$membershipTypeId] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membershipTypeId, + $joinDate, $startDate, $endDate + ); + + foreach ($calcDates as $memType => $calcDate) { + foreach ($dates as $d) { + //first give priority to form values then calDates. + $date = CRM_Utils_Array::value($d, $value); + if (!$date) { + $date = CRM_Utils_Array::value($d, $calcDate); + } + + $value[$d] = CRM_Utils_Date::processDate($date); + } + } + + if (CRM_Utils_Array::value('send_receipt', $value)) { + $value['receipt_date'] = date('Y-m-d His'); + } + + if (CRM_Utils_Array::value('membership_source', $value)) { + $value['source'] = $value['membership_source']; + } + + unset($value['membership_source']); + + //Get the membership status + if ( CRM_Utils_Array::value('membership_status', $value) ) { + $value['status_id'] = $value['membership_status']; + unset($value['membership_status']); + } + + if (empty($customFields)) { + // membership type custom data + $customFields = CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, $membershipTypeId); + + $customFields = CRM_Utils_Array::crmArrayMerge($customFields, + CRM_Core_BAO_CustomField::getFields('Membership', + FALSE, FALSE, NULL, NULL, TRUE + ) + ); + } + + //check for custom data + $value['custom'] = CRM_Core_BAO_CustomField::postProcess($params['field'][$key], + $customFields, + $key, + 'Membership', + $membershipTypeId + ); + + if (CRM_Utils_Array::value('financial_type', $value)) { + $value['financial_type_id'] = $value['financial_type']; + } + + if (CRM_Utils_Array::value('payment_instrument', $value)) { + $value['payment_instrument_id'] = $value['payment_instrument']; + } + + // handle soft credit + if (CRM_Utils_Array::value('soft_credit_contact_select_id', $params) && CRM_Utils_Array::value($key, $params['soft_credit_contact_select_id'])) { + $value['soft_credit_to'] = $params['soft_credit_contact_select_id'][$key]; + } + + if ( CRM_Utils_Array::value('receive_date', $value) ) { + $value['receive_date'] = CRM_Utils_Date::processDate( $value['receive_date'], $value['receive_date_time'] , TRUE ); + } + + $params['actualBatchTotal'] += $value['total_amount']; + + unset($value['financial_type']); + unset($value['payment_instrument']); + + $value['batch_id'] = $this->_batchId; + $value['skipRecentView'] = TRUE; + + // make entry in line item for contribution + + $editedFieldParams = array( + 'price_set_id' => $priceSetId, + 'name' => $value['membership_type'][0] + ); + + $editedResults = array(); + CRM_Price_BAO_Field::retrieve($editedFieldParams, $editedResults); + + if (!empty($editedResults)) { + unset($this->_priceSet['fields']); + $this->_priceSet['fields'][$editedResults['id']] = $priceSets['fields'][$editedResults['id']]; + unset($this->_priceSet['fields'][$editedResults['id']]['options']); + $fid = $editedResults['id']; + $editedFieldParams = array( + 'price_field_id' => $editedResults['id'], + 'membership_type_id' => $value['membership_type_id'] + ); + + $editedResults = array(); + CRM_Price_BAO_FieldValue::retrieve($editedFieldParams, $editedResults); + $this->_priceSet['fields'][$fid]['options'][$editedResults['id']] = $priceSets['fields'][$fid]['options'][$editedResults['id']]; + if (CRM_Utils_Array::value('total_amount', $value)) { + $this->_priceSet['fields'][$fid]['options'][$editedResults['id']]['amount'] = $value['total_amount']; + } + + $fieldID = key($this->_priceSet['fields']); + $value['price_' . $fieldID] = $editedResults['id']; + + $lineItem = array(); + CRM_Price_BAO_Set::processAmount($this->_priceSet['fields'], + $value, $lineItem[$priceSetId] + ); + + //CRM-11529 for backoffice transactions + //when financial_type_id is passed in form, update the + //lineitems with the financial type selected in form + if (CRM_Utils_Array::value('financial_type_id', $value) && CRM_Utils_Array::value($priceSetId, $lineItem)) { + foreach ($lineItem[$priceSetId] as &$values) { + $values['financial_type_id'] = $value['financial_type_id']; + } + } + + $value['lineItems'] = $lineItem; + $value['processPriceSet'] = TRUE; + } + // end of contribution related section + + unset($value['membership_type']); + unset($value['membership_start_date']); + unset($value['membership_end_date']); + + $value['is_renew'] = false; + if ( CRM_Utils_Array::value('member_option', $params) && CRM_Utils_Array::value( $key, $params['member_option'] ) == 2 ) { + $this->_params = $params; + $value['is_renew'] = true; + $membership = CRM_Member_BAO_Membership::renewMembership( + $value['contact_id'], + $value['membership_type_id'], + FALSE, $this, NULL, NULL, + $value['custom'] + ); + + // make contribution entry + CRM_Member_BAO_Membership::recordMembershipContribution( $value, CRM_Core_DAO::$_nullArray, $membership->id ); + } + else { + $membership = CRM_Member_BAO_Membership::create($value, CRM_Core_DAO::$_nullArray); + } + + //process premiums + if (CRM_Utils_Array::value('product_name', $value)) { + if ($value['product_name'][0] > 0) { + list($products, $options) = CRM_Contribute_BAO_Premium::getPremiumProductInfo(); + + $value['hidden_Premium'] = 1; + $value['product_option'] = CRM_Utils_Array::value( + $value['product_name'][1], + $options[$value['product_name'][0]] + ); + + $premiumParams = array( + 'product_id' => $value['product_name'][0], + 'contribution_id' => $value['contribution_id'], + 'product_option' => $value['product_option'], + 'quantity' => 1, + ); + CRM_Contribute_BAO_Contribution::addPremium($premiumParams); + } + } + // end of premium + + //send receipt mail. + if ( $membership->id && + CRM_Utils_Array::value( 'send_receipt', $value ) ) { + + // add the domain email id + $domainEmail = CRM_Core_BAO_Domain::getNameAndEmail(); + $domainEmail = "$domainEmail[0] <$domainEmail[1]>"; + + $value['from_email_address'] = $domainEmail; + $value['membership_id'] = $membership->id; + CRM_Member_Form_Membership::emailReceipt( $this, $value, $membership ); + } + } + } + } + + /** + * update contact information + * + * @param array $value associated array of submitted values + * + * @access public + * + * @return None + */ + private function updateContactInfo(&$value) { + $value['preserveDBName'] = $this->_preserveDefault; + + //parse street address, CRM-7768 + CRM_Contact_Form_Task_Batch::parseStreetAddress($value, $this); + + CRM_Contact_BAO_Contact::createProfileContact($value, $this->_fields, + $value['contact_id'] + ); + } +} + diff --git a/CRM/Batch/Form/Search.php b/CRM/Batch/Form/Search.php new file mode 100644 index 0000000000..c21b5df727 --- /dev/null +++ b/CRM/Batch/Form/Search.php @@ -0,0 +1,64 @@ +add('text', 'title', ts('Find'), + CRM_Core_DAO::getAttribute('CRM_Batch_DAO_Batch', 'title') + ); + + $this->addButtons( + array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + ) + ); + + parent::buildQuickForm(); + $this->assign('suppressForm', TRUE); + } +} + diff --git a/CRM/Batch/Page/AJAX.php b/CRM/Batch/Page/AJAX.php new file mode 100644 index 0000000000..e74a38cc13 --- /dev/null +++ b/CRM/Batch/Page/AJAX.php @@ -0,0 +1,110 @@ + 'batch.title', 1 => 'batch.type_id', 2 => '', + 3 => 'batch.total', 4 => 'batch.status_id', 5 => '', + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + $context = isset($_REQUEST['context']) ? CRM_Utils_Type::escape($_REQUEST['context'], 'String') : NULL; + + $params = $_REQUEST; + if ($sort && $sortOrder) { + $params['sortBy'] = $sort . ' ' . $sortOrder; + } + + $params['page'] = ($offset / $rowCount) + 1; + $params['rp'] = $rowCount; + + if ($context != 'financialBatch') { + // data entry status batches + $params['status_id'] = 3; + } + + $params['context'] = $context; + + // get batch list + $batches = CRM_Batch_BAO_Batch::getBatchListSelector($params); + + $iFilteredTotal = $iTotal = $params['total']; + $selectorElements = array( + 'batch_name', + 'payment_instrument', + 'item_count', + 'total', + 'status', + 'created_by', + 'links', + ); + + if ($context == 'financialBatch') { + $selectorElements = array_merge(array('check'), $selectorElements); + } + echo CRM_Utils_JSON::encodeDataTableSelector($batches, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Batch/Page/Batch.php b/CRM/Batch/Page/Batch.php new file mode 100644 index 0000000000..090a35c689 --- /dev/null +++ b/CRM/Batch/Page/Batch.php @@ -0,0 +1,123 @@ +assign('status', $status); + $this->search(); + } + + function search() { + if ($this->_action & + (CRM_Core_Action::ADD | + CRM_Core_Action::UPDATE | + CRM_Core_Action::DELETE + ) + ) { + return; + } + + $form = new CRM_Core_Controller_Simple('CRM_Batch_Form_Search', ts('Search Batches'), CRM_Core_Action::ADD); + $form->setEmbedded(TRUE); + $form->setParent($this); + $form->process(); + $form->run(); + } +} + diff --git a/CRM/Bridge/OG/CiviCRM.php b/CRM/Bridge/OG/CiviCRM.php new file mode 100644 index 0000000000..2278b9180c --- /dev/null +++ b/CRM/Bridge/OG/CiviCRM.php @@ -0,0 +1,106 @@ +nid = $ogID; + } + + global $user; + $node->uid = $user->uid; + $node->title = $group->title; + $node->type = 'og'; + $node->status = 1; + + // set the og values + $node->og_description = $group->description; + $node->og_selective = OF_OPEN; + $node->og_register = 0; + $node->og_directory = 1; + + node_save($node); + + // also change the source field of the group + CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Group', + $groupID, + 'source', + CRM_Bridge_OG_Utils::ogSyncName($node->nid) + ); + } + + static function groupDelete($groupID, $group) { + $ogID = CRM_Bridge_OG_Utils::ogID($groupID, FALSE); + if (!$ogID) { + return; + } + + node_delete($ogID); + } + + static function groupContact($groupID, $contactIDs, $op) { + $config = CRM_Core_Config::singleton(); + $ogID = CRM_Bridge_OG_Utils::ogID($groupID, FALSE); + + if (!$ogID) { + return; + } + + foreach ($contactIDs as $contactID) { + $drupalID = CRM_Core_BAO_UFMatch::getUFId($contactID); + if ($drupalID) { + if ($op == 'add') { + $group_membership = $config->userSystem->og_membership_create($ogID, $drupalID); + } + else { + $group_membership = $config->userSystem->og_membership_delete($ogID, $drupalID); + } + } + } + } +} + diff --git a/CRM/Bridge/OG/Drupal.php b/CRM/Bridge/OG/Drupal.php new file mode 100644 index 0000000000..ea7a429ea0 --- /dev/null +++ b/CRM/Bridge/OG/Drupal.php @@ -0,0 +1,238 @@ + 1); + self::updateCiviGroup($groupParams, $op); + + if (CRM_Bridge_OG_Utils::aclEnabled()) { + // next create or update the CiviCRM ACL group + $aclParams = $params; + $aclParams['name'] = $aclParams['title'] = "{$aclParams['name']}: Administrator"; + $aclParams['source'] = CRM_Bridge_OG_Utils::ogSyncACLName($params['og_id']); + $aclParams['group_type'] = array('1'); + self::updateCiviGroup($aclParams, $op); + + $aclParams['acl_group_id'] = $aclParams['group_id']; + $aclParams['civicrm_group_id'] = $groupParams['group_id']; + + self::updateCiviACLTables($aclParams, $op); + } + + $transaction->commit(); + } + + static function updateCiviGroup(&$params, $op, $groupType = NULL) { + $abort = false; + $params['version'] = 3; + $params['id'] = CRM_Bridge_OG_Utils::groupID($params['source'], $params['title'], $abort); + + if ($op == 'add') { + if ($groupType) { + $params['group_type'] = $groupType; + } + + $group = civicrm_api('group', 'create', $params); + if (!civicrm_error($group)) { + $params['group_id'] = $group['id']; + } + } + else { + // do this only if we have a valid id + if ($params['id']) { + CRM_Contact_BAO_Group::discard($params['id']); + $params['group_id'] = $params['id']; + } + } + unset($params['id']); + } + + static function updateCiviACLTables($aclParams, $op) { + if ($op == 'delete') { + self::updateCiviACL($aclParams, $op); + self::updateCiviACLEntityRole($aclParams, $op); + self::updateCiviACLRole($aclParams, $op); + } + else { + self::updateCiviACLRole($aclParams, $op); + self::updateCiviACLEntityRole($aclParams, $op); + self::updateCiviACL($aclParams, $op); + } + } + + static function updateCiviACLRole(&$params, $op) { + + $optionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', + 'acl_role', + 'id', + 'name' + ); + + $dao = new CRM_Core_DAO_OptionValue(); + $dao->option_group_id = $optionGroupID; + $dao->description = $params['source']; + + if ($op == 'delete') { + $dao->delete(); + return; + } + + $dao->label = $params['title']; + $dao->is_active = 1; + + $weightParams = array('option_group_id' => $optionGroupID); + $dao->weight = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', + $weightParams + ); + $dao->value = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', + $weightParams, + 'value' + ); + + $query = " +SELECT v.id + FROM civicrm_option_value v + WHERE v.option_group_id = %1 + AND v.description = %2 +"; + $queryParams = array(1 => array($optionGroupID, 'Integer'), + 2 => array($params['source'], 'String'), + ); + $dao->id = CRM_Core_DAO::singleValueQuery($query, $queryParams); + $dao->save(); + $params['acl_role_id'] = $dao->value; + } + + static function updateCiviACLEntityRole(&$params, $op) { + $dao = new CRM_ACL_DAO_EntityRole(); + + $dao->entity_table = 'civicrm_group'; + $dao->entity_id = $params['acl_group_id']; + if ($op == 'delete') { + $dao->delete(); + return; + } + + $dao->acl_role_id = $params['acl_role_id']; + + $dao->find(TRUE); + $dao->is_active = TRUE; + $dao->save(); + $params['acl_entity_role_id'] = $dao->id; + } + + static function updateCiviACL(&$params, $op) { + $dao = new CRM_ACL_DAO_ACL(); + + $dao->object_table = 'civicrm_saved_search'; + $dao->object_id = $params['civicrm_group_id']; + + if ($op == 'delete') { + $dao->delete(); + return; + } + + $dao->find(TRUE); + + $dao->entity_table = 'civicrm_acl_role'; + $dao->entity_id = $params['acl_role_id']; + $dao->operation = 'Edit'; + + $dao->is_active = TRUE; + $dao->save(); + $params['acl_id'] = $dao->id; + } + + static function og(&$params, $op) { + + $contactID = CRM_Bridge_OG_Utils::contactID($params['uf_id']); + if (!$contactID) { + CRM_Core_Error::fatal(); + } + + // get the group id of this OG + $groupID = CRM_Bridge_OG_Utils::groupID(CRM_Bridge_OG_Utils::ogSyncName($params['og_id']), + NULL, TRUE + ); + + $groupParams = array( + 'contact_id' => $contactID, + 'group_id' => $groupID, + 'version' => 3, + ); + + if ($op == 'add') { + $groupParams['status'] = $params['is_active'] ? 'Added' : 'Pending'; + civicrm_api('GroupContact', 'Create', $groupParams); + } + else { + $groupParams['status'] = 'Removed'; + civicrm_api('GroupContact', 'Delete', $groupParams); + } + + if (CRM_Bridge_OG_Utils::aclEnabled() && + $params['is_admin'] !== NULL + ) { + // get the group ID of the acl group + $groupID = CRM_Bridge_OG_Utils::groupID(CRM_Bridge_OG_Utils::ogSyncACLName($params['og_id']), + NULL, TRUE + ); + + $groupParams = array( + 'contact_id' => $contactID, + 'group_id' => $groupID, + 'status' => $params['is_admin'] ? 'Added' : 'Removed', + 'version' => 3, + ); + + if ($params['is_admin']) { + civicrm_api('GroupContact', 'Create', $groupParams); + } + else { + civicrm_api('GroupContact', 'Delete', $groupParams); + } + } + } +} + diff --git a/CRM/Bridge/OG/Utils.php b/CRM/Bridge/OG/Utils.php new file mode 100644 index 0000000000..ec27cb49d4 --- /dev/null +++ b/CRM/Bridge/OG/Utils.php @@ -0,0 +1,119 @@ +mail, 'Drupal'); + $contactID = CRM_Core_BAO_UFMatch::getContactId($ufID); + if (!$contactID) { + CRM_Core_Error::fatal(); + } + return $contactID; + } + + static function groupID($source, $title = NULL, $abort = FALSE) { + $query = " +SELECT id + FROM civicrm_group + WHERE source = %1"; + $params = array(1 => array($source, 'String')); + + if ($title) { + $query .= " OR title = %2"; + $params[2] = array($title, 'String'); + } + + $groupID = CRM_Core_DAO::singleValueQuery($query, $params); + if ($abort && + !$groupID + ) { + CRM_Core_Error::fatal(); + } + + return $groupID; + } +} + diff --git a/CRM/Campaign/BAO/Campaign.php b/CRM/Campaign/BAO/Campaign.php new file mode 100644 index 0000000000..ca4014cfee --- /dev/null +++ b/CRM/Campaign/BAO/Campaign.php @@ -0,0 +1,645 @@ +get('userID'); + } + + if (!(CRM_Utils_Array::value('created_date', $params))) { + $params['created_date'] = date('YmdHis'); + } + + if (!(CRM_Utils_Array::value('name', $params))) { + $params['name'] = CRM_Utils_String::titleToVar($params['title'], 64); + } + } + + $campaign = new CRM_Campaign_DAO_Campaign(); + $campaign->copyValues($params); + $campaign->save(); + + /* Create the campaign group record */ + + $groupTableName = CRM_Contact_BAO_Group::getTableName(); + + if (isset($params['groups']) && CRM_Utils_Array::value('include', $params['groups']) && is_array($params['groups']['include'])) { + foreach ($params['groups']['include'] as $entityId) { + $dao = new CRM_Campaign_DAO_CampaignGroup(); + $dao->campaign_id = $campaign->id; + $dao->entity_table = $groupTableName; + $dao->entity_id = $entityId; + $dao->group_type = 'include'; + $dao->save(); + $dao->free(); + } + } + + //store custom data + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_campaign', $campaign->id); + } + + return $campaign; + } + + /** + * function to delete the campaign + * + * @param int $id id of the campaign + */ + public static function del($id) { + if (!$id) { + return FALSE; + } + $dao = new CRM_Campaign_DAO_Campaign(); + $dao->id = $id; + return $dao->delete(); + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * campaign_id. + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @access public + */ + public function retrieve(&$params, &$defaults) { + $campaign = new CRM_Campaign_DAO_Campaign(); + + $campaign->copyValues($params); + + if ($campaign->find(TRUE)) { + CRM_Core_DAO::storeValues($campaign, $defaults); + return $campaign; + } + return NULL; + } + + /** + * Return the all eligible campaigns w/ cache. + * + * @param int $includeId lets inlcude this campaign by force. + * @param int $excludeId do not include this campaign. + * @param boolean $onlyActive consider only active campaigns. + * + * @return $campaigns a set of campaigns. + * @access public + */ + public static function getCampaigns( + $includeId = NULL, + $excludeId = NULL, + $onlyActive = TRUE, + $onlyCurrent = TRUE, + $appendDatesToTitle = FALSE, + $forceAll = FALSE + ) { + static $campaigns; + $cacheKey = 0; + $cacheKeyParams = array( + 'includeId', 'excludeId', 'onlyActive', + 'onlyCurrent', 'appendDatesToTitle', 'forceAll', + ); + foreach ($cacheKeyParams as $param) { + $cacheParam = $$param; + if (!$cacheParam) { + $cacheParam = 0; + } + $cacheKey .= '_' . $cacheParam; + } + + if (!isset($campaigns[$cacheKey])) { + $where = array('( camp.title IS NOT NULL )'); + if ($excludeId) { + $where[] = "( camp.id != $excludeId )"; + } + if ($onlyActive) { + $where[] = '( camp.is_active = 1 )'; + } + if ($onlyCurrent) { + $where[] = '( camp.end_date IS NULL OR camp.end_date >= NOW() )'; + } + $whereClause = implode(' AND ', $where); + if ($includeId) { + $whereClause .= " OR ( camp.id = $includeId )"; + } + + //lets force all. + if ($forceAll) { + $whereClause = '( 1 )'; + } + + $query = " + SELECT camp.id, + camp.title, + camp.start_date, + camp.end_date + FROM civicrm_campaign camp + WHERE {$whereClause} +Order By camp.title"; + + $campaign = CRM_Core_DAO::executeQuery($query); + $campaigns[$cacheKey] = array(); + $config = CRM_Core_Config::singleton(); + + while ($campaign->fetch()) { + $title = $campaign->title; + if ($appendDatesToTitle) { + $dates = array(); + foreach (array('start_date', 'end_date') as $date) { + if ($campaign->$date) { + $dates[] = CRM_Utils_Date::customFormat($campaign->$date, $config->dateformatFull); + } + } + if (!empty($dates)) { + $title .= ' (' . implode('-', $dates) . ')'; + } + } + $campaigns[$cacheKey][$campaign->id] = $title; + } + } + + return $campaigns[$cacheKey]; + } + + /** + * Wrapper to self::getCampaigns( ) + * w/ permissions and component check. + * + */ + public static function getPermissionedCampaigns($includeId = NULL, + $excludeId = NULL, + $onlyActive = TRUE, + $onlyCurrent = TRUE, + $appendDatesToTitle = FALSE, + $forceAll = FALSE, + $doCheckForComponent = TRUE, + $doCheckForPermissions = TRUE + ) { + $cacheKey = 0; + $cachekeyParams = array( + 'includeId', 'excludeId', 'onlyActive', 'onlyCurrent', + 'appendDatesToTitle', 'doCheckForComponent', 'doCheckForPermissions', 'forceAll', + ); + foreach ($cachekeyParams as $param) { + $cacheKeyParam = $$param; + if (!$cacheKeyParam) { + $cacheKeyParam = 0; + } + $cacheKey .= '_' . $cacheKeyParam; + } + + static $validCampaigns; + if (!isset($validCampaigns[$cacheKey])) { + $isValid = TRUE; + $campaigns = array('campaigns' => array(), + 'hasAccessCampaign' => FALSE, + 'isCampaignEnabled' => FALSE, + ); + + //do check for component. + if ($doCheckForComponent) { + $campaigns['isCampaignEnabled'] = $isValid = self::isCampaignEnable(); + } + + //do check for permissions. + if ($doCheckForPermissions) { + $campaigns['hasAccessCampaign'] = $isValid = self::accessCampaign(); + } + + //finally retrieve campaigns from db. + if ($isValid) { + $campaigns['campaigns'] = self::getCampaigns($includeId, + $excludeId, + $onlyActive, + $onlyCurrent, + $appendDatesToTitle, + $forceAll + ); + } + + //store in cache. + $validCampaigns[$cacheKey] = $campaigns; + } + + return $validCampaigns[$cacheKey]; + } + + /* + * Is CiviCampaign enabled. + * + */ + public static function isCampaignEnable() { + static $isEnable = NULL; + + if (!isset($isEnable)) { + $isEnable = FALSE; + $config = CRM_Core_Config::singleton(); + if (in_array('CiviCampaign', $config->enableComponents)) { + $isEnable = TRUE; + } + } + + return $isEnable; + } + + /** + * Function to retrieve campaigns for dashboard. + * + * @static + */ + static function getCampaignSummary($params = array( + ), $onlyCount = FALSE) { + $campaigns = array(); + + //build the limit and order clause. + $limitClause = $orderByClause = $lookupTableJoins = NULL; + if (!$onlyCount) { + $sortParams = array( + 'sort' => 'start_date', + 'offset' => 0, + 'rowCount' => 10, + 'sortOrder' => 'desc', + ); + foreach ($sortParams as $name => $default) { + if (CRM_Utils_Array::value($name, $params)) { + $sortParams[$name] = $params[$name]; + } + } + + + //need to lookup tables. + $orderOnCampaignTable = TRUE; + if ($sortParams['sort'] == 'status') { + $orderOnCampaignTable = FALSE; + $lookupTableJoins = " + LEFT JOIN civicrm_option_value status ON ( status.value = campaign.status_id OR campaign.status_id IS NULL ) +INNER JOIN civicrm_option_group grp ON ( status.option_group_id = grp.id AND grp.name = 'campaign_status' )"; + $orderByClause = "ORDER BY status.label {$sortParams['sortOrder']}"; + } + elseif ($sortParams['sort'] == 'campaign_type') { + $orderOnCampaignTable = FALSE; + $lookupTableJoins = " + LEFT JOIN civicrm_option_value campaign_type ON ( campaign_type.value = campaign.campaign_type_id + OR campaign.campaign_type_id IS NULL ) +INNER JOIN civicrm_option_group grp ON ( campaign_type.option_group_id = grp.id AND grp.name = 'campaign_type' )"; + $orderByClause = "ORDER BY campaign_type.label {$sortParams['sortOrder']}"; + } + elseif ($sortParams['sort'] == 'isActive') { + $sortParams['sort'] = 'is_active'; + } + if ($orderOnCampaignTable) { + $orderByClause = "ORDER BY campaign.{$sortParams['sort']} {$sortParams['sortOrder']}"; + } + $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}"; + } + + //build the where clause. + $queryParams = $where = array(); + if (CRM_Utils_Array::value('id', $params)) { + $where[] = "( campaign.id = %1 )"; + $queryParams[1] = array($params['id'], 'Positive'); + } + if (CRM_Utils_Array::value('name', $params)) { + $where[] = "( campaign.name LIKE %2 )"; + $queryParams[2] = array('%' . trim($params['name']) . '%', 'String'); + } + if (CRM_Utils_Array::value('title', $params)) { + $where[] = "( campaign.title LIKE %3 )"; + $queryParams[3] = array('%' . trim($params['title']) . '%', 'String'); + } + if (CRM_Utils_Array::value('start_date', $params)) { + $startDate = CRM_Utils_Date::processDate($params['start_date']); + $where[] = "( campaign.start_date >= %4 OR campaign.start_date IS NULL )"; + $queryParams[4] = array($startDate, 'String'); + } + if (CRM_Utils_Array::value('end_date', $params)) { + $endDate = CRM_Utils_Date::processDate($params['end_date'], '235959'); + $where[] = "( campaign.end_date <= %5 OR campaign.end_date IS NULL )"; + $queryParams[5] = array($endDate, 'String'); + } + if (CRM_Utils_Array::value('description', $params)) { + $where[] = "( campaign.description LIKE %6 )"; + $queryParams[6] = array('%' . trim($params['description']) . '%', 'String'); + } + if (CRM_Utils_Array::value('campaign_type_id', $params)) { + $typeId = $params['campaign_type_id']; + if (is_array($params['campaign_type_id'])) { + $typeId = implode(' , ', $params['campaign_type_id']); + } + $where[] = "( campaign.campaign_type_id IN ( {$typeId} ) )"; + } + if (CRM_Utils_Array::value('status_id', $params)) { + $statusId = $params['status_id']; + if (is_array($params['status_id'])) { + $statusId = implode(' , ', $params['status_id']); + } + $where[] = "( campaign.status_id IN ( {$statusId} ) )"; + } + if (array_key_exists('is_active', $params)) { + $active = "( campaign.is_active = 1 )"; + if (CRM_Utils_Array::value('is_active', $params)) { + $active = "( campaign.is_active = 0 OR campaign.is_active IS NULL )"; + } + $where[] = $active; + } + $whereClause = NULL; + if (!empty($where)) { + $whereClause = ' WHERE ' . implode(" \nAND ", $where); + } + + $properties = array( + 'id', + 'name', + 'title', + 'start_date', + 'end_date', + 'status_id', + 'is_active', + 'description', + 'campaign_type_id', + ); + + $selectClause = ' +SELECT campaign.id as id, + campaign.name as name, + campaign.title as title, + campaign.is_active as is_active, + campaign.status_id as status_id, + campaign.end_date as end_date, + campaign.start_date as start_date, + campaign.description as description, + campaign.campaign_type_id as campaign_type_id'; + if ($onlyCount) { + $selectClause = 'SELECT COUNT(*)'; + } + $fromClause = 'FROM civicrm_campaign campaign'; + + $query = "{$selectClause} {$fromClause} {$lookupTableJoins} {$whereClause} {$orderByClause} {$limitClause}"; + + //in case of only count. + if ($onlyCount) { + return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams); + } + + $campaign = CRM_Core_DAO::executeQuery($query, $queryParams); + while ($campaign->fetch()) { + foreach ($properties as $property) { + $campaigns[$campaign->id][$property] = $campaign->$property; + } + } + + return $campaigns; + } + + /** + * Get the campaign count. + * + * @static + */ + static function getCampaignCount() { + return (int)CRM_Core_DAO::singleValueQuery('SELECT COUNT(*) FROM civicrm_campaign'); + } + + /** + * Function to get Campaigns groups + * + * @param int $campaignId campaign id + * + * @static + */ + static function getCampaignGroups($campaignId) { + static $campaignGroups; + if (!$campaignId) { + return array(); + } + + if (!isset($campaignGroups[$campaignId])) { + $campaignGroups[$campaignId] = array(); + + $query = " + SELECT grp.title, grp.id + FROM civicrm_campaign_group campgrp +INNER JOIN civicrm_group grp ON ( grp.id = campgrp.entity_id ) + WHERE campgrp.group_type = 'Include' + AND campgrp.entity_table = 'civicrm_group' + AND campgrp.campaign_id = %1"; + + $groups = CRM_Core_DAO::executeQuery($query, array(1 => array($campaignId, 'Positive'))); + while ($groups->fetch()) { + $campaignGroups[$campaignId][$groups->id] = $groups->title; + } + } + + return $campaignGroups[$campaignId]; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Campaign_DAO_Campaign', $id, 'is_active', $is_active); + } + + static function accessCampaign() { + static $allow = NULL; + + if (!isset($allow)) { + $allow = FALSE; + if (CRM_Core_Permission::check('manage campaign') || + CRM_Core_Permission::check('administer CiviCampaign') + ) { + $allow = TRUE; + } + } + + return $allow; + } + + /* + * Add select element for campaign + * and assign needful info to templates. + * + */ + public static function addCampaign(&$form, $connectedCampaignId = NULL) { + //some forms do set default and freeze. + $appendDates = TRUE; + if ($form->get('action') & CRM_Core_Action::VIEW) { + $appendDates = FALSE; + } + + $campaignDetails = self::getPermissionedCampaigns($connectedCampaignId, NULL, TRUE, TRUE, $appendDates); + $fields = array('campaigns', 'hasAccessCampaign', 'isCampaignEnabled'); + foreach ($fields as $fld)$$fld = CRM_Utils_Array::value($fld, $campaignDetails); + + //lets see do we have past campaigns. + $hasPastCampaigns = FALSE; + $allActiveCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, TRUE, FALSE); + if (count($allActiveCampaigns) > count($campaigns)) { + $hasPastCampaigns = TRUE; + } + $hasCampaigns = FALSE; + if (!empty($campaigns)) { + $hasCampaigns = TRUE; + } + if ($hasPastCampaigns) { + $hasCampaigns = TRUE; + $form->add('hidden', 'included_past_campaigns'); + } + + $showAddCampaign = FALSE; + $alreadyIncludedPastCampaigns = FALSE; + if ($connectedCampaignId || ($isCampaignEnabled && $hasAccessCampaign)) { + $showAddCampaign = TRUE; + //lets add past campaigns as options to quick-form element. + if ($hasPastCampaigns && $form->getElementValue('included_past_campaigns')) { + $campaigns = $allActiveCampaigns; + $alreadyIncludedPastCampaigns = TRUE; + } + $campaign = &$form->add('select', + 'campaign_id', + ts('Campaign'), + array( + '' => ts('- select -')) + $campaigns + ); + //lets freeze when user does not has access or campaign is disabled. + if (!$isCampaignEnabled || !$hasAccessCampaign) { + $campaign->freeze(); + } + } + + $addCampaignURL = NULL; + if (empty($campaigns) && $hasAccessCampaign && $isCampaignEnabled) { + $addCampaignURL = CRM_Utils_System::url('civicrm/campaign/add', 'reset=1'); + } + + $includePastCampaignURL = NULL; + if ($hasPastCampaigns && $isCampaignEnabled && $hasAccessCampaign) { + $includePastCampaignURL = CRM_Utils_System::url('civicrm/ajax/rest', + 'className=CRM_Campaign_Page_AJAX&fnName=allActiveCampaigns', + FALSE, NULL, FALSE + ); + } + + //carry this info to templates. + $infoFields = array( + 'hasCampaigns', + 'addCampaignURL', + 'showAddCampaign', + 'hasPastCampaigns', + 'hasAccessCampaign', + 'isCampaignEnabled', + 'includePastCampaignURL', + 'alreadyIncludedPastCampaigns', + ); + foreach ($infoFields as $fld) $campaignInfo[$fld] = $$fld; + $form->assign('campaignInfo', $campaignInfo); + } + + /* + * Add campaign in compoent search. + * and assign needful info to templates. + * + */ + public static function addCampaignInComponentSearch(&$form, $elementName = 'campaign_id') { + $campaignInfo = array(); + $campaignDetails = self::getPermissionedCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + $fields = array('campaigns', 'hasAccessCampaign', 'isCampaignEnabled'); + foreach ($fields as $fld)$$fld = CRM_Utils_Array::value($fld, $campaignDetails); + $showCampaignInSearch = FALSE; + if ($isCampaignEnabled && $hasAccessCampaign && !empty($campaigns)) { + //get the current campaign only. + $currentCampaigns = self::getCampaigns(NULL, NULL, FALSE); + $pastCampaigns = array_diff($campaigns, $currentCampaigns); + $allCampaigns = array(); + if (!empty($currentCampaigns)) { + $allCampaigns = array('current_campaign' => ts('Current Campaigns')); + foreach ($currentCampaigns as & $camp) $camp = "   {$camp}"; + $allCampaigns += $currentCampaigns; + } + if (!empty($pastCampaigns)) { + $allCampaigns += array('past_campaign' => ts('Past Campaigns')); + foreach ($pastCampaigns as & $camp) $camp = "   {$camp}"; + $allCampaigns += $pastCampaigns; + } + + $showCampaignInSearch = TRUE; + $form->add('select', $elementName, ts('Campaigns'), $allCampaigns, FALSE, + array('id' => 'campaigns', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + $infoFields = array( + 'elementName', + 'hasAccessCampaign', + 'isCampaignEnabled', + 'showCampaignInSearch', + ); + foreach ($infoFields as $fld) $campaignInfo[$fld] = $$fld; + $form->assign('campaignInfo', $campaignInfo); + } +} + diff --git a/CRM/Campaign/BAO/Petition.php b/CRM/Campaign/BAO/Petition.php new file mode 100644 index 0000000000..abfa47c484 --- /dev/null +++ b/CRM/Campaign/BAO/Petition.php @@ -0,0 +1,631 @@ +cookieExpire = (1 * 60 * 60 * 24); + } + + /** + * Function to get Petition Details for dashboard. + * + * @static + */ + static function getPetitionSummary($params = array( + ), $onlyCount = FALSE) { + //build the limit and order clause. + $limitClause = $orderByClause = $lookupTableJoins = NULL; + if (!$onlyCount) { + $sortParams = array( + 'sort' => 'created_date', + 'offset' => 0, + 'rowCount' => 10, + 'sortOrder' => 'desc', + ); + foreach ($sortParams as $name => $default) { + if (CRM_Utils_Array::value($name, $params)) { + $sortParams[$name] = $params[$name]; + } + } + + //need to lookup tables. + $orderOnPetitionTable = TRUE; + if ($sortParams['sort'] == 'campaign') { + $orderOnPetitionTable = FALSE; + $lookupTableJoins = ' + LEFT JOIN civicrm_campaign campaign ON ( campaign.id = petition.campaign_id )'; + $orderByClause = "ORDER BY campaign.title {$sortParams['sortOrder']}"; + } + elseif ($sortParams['sort'] == 'activity_type') { + $orderOnPetitionTable = FALSE; + $lookupTableJoins = " + LEFT JOIN civicrm_option_value activity_type ON ( activity_type.value = petition.activity_type_id + OR petition.activity_type_id IS NULL ) +INNER JOIN civicrm_option_group grp ON ( activity_type.option_group_id = grp.id AND grp.name = 'activity_type' )"; + $orderByClause = "ORDER BY activity_type.label {$sortParams['sortOrder']}"; + } + elseif ($sortParams['sort'] == 'isActive') { + $sortParams['sort'] = 'is_active'; + } + if ($orderOnPetitionTable) { + $orderByClause = "ORDER BY petition.{$sortParams['sort']} {$sortParams['sortOrder']}"; + } + $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}"; + } + + //build the where clause. + $queryParams = $where = array(); + + //we only have activity type as a + //difference between survey and petition. + $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name'); + if ($petitionTypeID) { + $where[] = "( petition.activity_type_id = %1 )"; + $queryParams[1] = array($petitionTypeID, 'Positive'); + } + if (CRM_Utils_Array::value('title', $params)) { + $where[] = "( petition.title LIKE %2 )"; + $queryParams[2] = array('%' . trim($params['title']) . '%', 'String'); + } + if (CRM_Utils_Array::value('campaign_id', $params)) { + $where[] = '( petition.campaign_id = %3 )'; + $queryParams[3] = array($params['campaign_id'], 'Positive'); + } + $whereClause = NULL; + if (!empty($where)) { + $whereClause = ' WHERE ' . implode(" \nAND ", $where); + } + + $selectClause = ' +SELECT petition.id as id, + petition.title as title, + petition.is_active as is_active, + petition.result_id as result_id, + petition.is_default as is_default, + petition.campaign_id as campaign_id, + petition.activity_type_id as activity_type_id'; + + if ($onlyCount) { + $selectClause = 'SELECT COUNT(*)'; + } + $fromClause = 'FROM civicrm_survey petition'; + + $query = "{$selectClause} {$fromClause} {$whereClause} {$orderByClause} {$limitClause}"; + + if ($onlyCount) { + return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams); + } + + $petitions = array(); + $properties = array( + 'id', + 'title', + 'campaign_id', + 'is_active', + 'is_default', + 'result_id', + 'activity_type_id', + ); + + $petition = CRM_Core_DAO::executeQuery($query, $queryParams); + while ($petition->fetch()) { + foreach ($properties as $property) { + $petitions[$petition->id][$property] = $petition->$property; + } + } + + return $petitions; + } + + /** + * Get the petition count. + * + * @static + */ + static function getPetitionCount() { + $whereClause = 'WHERE ( 1 )'; + $queryParams = array(); + $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name'); + if ($petitionTypeID) { + $whereClause = "WHERE ( petition.activity_type_id = %1 )"; + $queryParams[1] = array($petitionTypeID, 'Positive'); + } + $query = "SELECT COUNT(*) FROM civicrm_survey petition {$whereClause}"; + + return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams); + } + + /** + * takes an associative array and creates a petition signature activity + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return object CRM_Campaign_BAO_Petition + * @access public + * @static + */ + function createSignature(&$params) { + if (empty($params)) { + return; + } + + if (!isset($params['sid'])) { + $statusMsg = ts('No survey sid parameter. Cannot process signature.'); + CRM_Core_Session::setStatus($statusMsg, ts('Sorry'), 'error'); + return; + } + + if (isset($params['contactId'])) { + + // add signature as activity with survey id as source id + // get the activity type id associated with this survey + $surveyInfo = CRM_Campaign_BAO_Petition::getSurveyInfo($params['sid']); + + // create activity + // activity status id (from /civicrm/admin/optionValue?reset=1&action=browse&gid=25) + // 1-Schedule, 2-Completed + + $activityParams = array( + 'source_contact_id' => $params['contactId'], + 'target_contact_id' => $params['contactId'], + 'source_record_id' => $params['sid'], + 'subject' => $surveyInfo['title'], + 'activity_type_id' => $surveyInfo['activity_type_id'], + 'activity_date_time' => date("YmdHis"), + 'status_id' => $params['statusId'], + ); + + //activity creation + // *** check for activity using source id - if already signed + $activity = CRM_Activity_BAO_Activity::create($activityParams); + + // save activity custom data + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_activity', $activity->id); + } + + // set permanent cookie to indicate this petition already signed on the computer + setcookie('signed_' . $params['sid'], $activity->id, time() + $this->cookieExpire, '/'); + } + + return $activity; + } + + function confirmSignature($activity_id, $contact_id, $petition_id) { + // change activity status to completed (status_id = 2) + // I wonder why do we need contact_id when we have activity_id anyway? [chastell] + $sql = 'UPDATE civicrm_activity SET status_id = 2 WHERE id = %1 AND source_contact_id = %2'; + $params = array(1 => array($activity_id, 'Integer'), 2 => array($contact_id, 'Integer')); + CRM_Core_DAO::executeQuery($sql, $params); + + // remove 'Unconfirmed' tag for this contact + $tag_name = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'tag_unconfirmed', + NULL, + 'Unconfirmed' + ); + + $sql = " +DELETE FROM civicrm_entity_tag +WHERE entity_table = 'civicrm_contact' +AND entity_id = %1 +AND tag_id = ( SELECT id FROM civicrm_tag WHERE name = %2 )"; + $params = array(1 => array($contact_id, 'Integer'), + 2 => array($tag_name, 'String'), + ); + CRM_Core_DAO::executeQuery($sql, $params); + + // set permanent cookie to indicate this users email address now confirmed + setcookie("confirmed_{$petition_id}", + $activity_id, + time() + $this->cookieExpire, + '/' + ); + + return TRUE; + } + + /** + * Function to get Petition Signature Total + * + * @param boolean $all + * @param int $id + * @static + */ + static function getPetitionSignatureTotalbyCountry($surveyId) { + $countries = array(); + $sql = " + SELECT count(civicrm_address.country_id) as total, + IFNULL(country_id,'') as country_id,IFNULL(iso_code,'') as country_iso, IFNULL(civicrm_country.name,'') as country + FROM civicrm_activity a, civicrm_survey, civicrm_contact + LEFT JOIN civicrm_address ON civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1 + LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id + WHERE + a.source_contact_id = civicrm_contact.id AND + a.activity_type_id = civicrm_survey.activity_type_id AND + civicrm_survey.id = %1 AND + a.source_record_id = %1 "; + + $params = array(1 => array($surveyId, 'Integer')); + $sql .= " GROUP BY civicrm_address.country_id"; + $fields = array('total', 'country_id', 'country_iso', 'country'); + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + while ($dao->fetch()) { + $row = array(); + foreach ($fields as $field) { + $row[$field] = $dao->$field; + } + $countries[] = $row; + } + return $countries; + } + + /** + * Function to get Petition Signature Total + * + * @param boolean $all + * @param int $id + * @static + */ + static function getPetitionSignatureTotal($surveyId) { + $surveyInfo = CRM_Campaign_BAO_Petition::getSurveyInfo((int) $surveyId); + //$activityTypeID = $surveyInfo['activity_type_id']; + $signature = array(); + + $sql = " + SELECT + status_id,count(id) as total + FROM civicrm_activity + WHERE + source_record_id = " . (int) $surveyId . " AND activity_type_id = " . (int) $surveyInfo['activity_type_id'] . " GROUP BY status_id"; + + $statusTotal = array(); + $total = 0; + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $total += $dao->total; + $statusTotal['status'][$dao->status_id] = $dao->total; + } + $statusTotal['count'] = $total; + return $statusTotal; + } + + + public function getSurveyInfo($surveyId = NULL) { + $surveyInfo = array(); + + $sql = " + SELECT activity_type_id, + campaign_id, + s.title, + ov.label AS activity_type + FROM civicrm_survey s, civicrm_option_value ov, civicrm_option_group og + WHERE s.id = " . (int) $surveyId ." + AND s.activity_type_id = ov.value + AND ov.option_group_id = og.id + AND og.name = 'activity_type'"; + + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + //$survey['campaign_id'] = $dao->campaign_id; + //$survey['campaign_name'] = $dao->campaign_name; + $surveyInfo['activity_type'] = $dao->activity_type; + $surveyInfo['activity_type_id'] = $dao->activity_type_id; + $surveyInfo['title'] = $dao->title; + } + + return $surveyInfo; + } + + /** + * Function to get Petition Signature Details + * + * @param boolean $all + * @param int $id + * @static + */ + static function getPetitionSignature($surveyId, $status_id = NULL) { + + // sql injection protection + $surveyId = (int)$surveyId; + $signature = array(); + + $sql = " + SELECT a.id, + a.source_record_id as survey_id, + a.activity_date_time, + a.status_id, + civicrm_contact.id as contact_id, + civicrm_contact.contact_type,civicrm_contact.contact_sub_type,image_URL, + first_name,last_name,sort_name, + employer_id,organization_name, + household_name, + IFNULL(gender_id,'') AS gender_id, + IFNULL(state_province_id,'') AS state_province_id, + IFNULL(country_id,'') as country_id,IFNULL(iso_code,'') as country_iso, IFNULL(civicrm_country.name,'') as country + FROM civicrm_activity a, civicrm_survey, civicrm_contact + LEFT JOIN civicrm_address ON civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1 + LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id + WHERE + a.source_contact_id = civicrm_contact.id AND + a.activity_type_id = civicrm_survey.activity_type_id AND + civicrm_survey.id = %1 AND + a.source_record_id = %1 "; + + $params = array(1 => array($surveyId, 'Integer')); + + if ($status_id) { + $sql .= " AND status_id = %2"; + $params[2] = array($status_id, 'Integer'); + } + $sql .= " ORDER BY a.activity_date_time"; + + $fields = array( + 'id', 'survey_id', 'contact_id', + 'activity_date_time', 'activity_type_id', + 'status_id', 'first_name', 'last_name', + 'sort_name', 'gender_id', 'country_id', + 'state_province_id', 'country_iso', 'country', + ); + + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + while ($dao->fetch()) { + $row = array(); + foreach ($fields as $field) { + $row[$field] = $dao->$field; + } + $signature[] = $row; + } + return $signature; + } + + /** + * This function returns all entities assigned to a specific tag + * + * @param object $tag an object of a tag. + * + * @return array $contactIds array of contact ids + * @access public + */ + function getEntitiesByTag($tag) { + $contactIds = array(); + $entityTagDAO = new CRM_Core_DAO_EntityTag(); + $entityTagDAO->tag_id = $tag['id']; + $entityTagDAO->find(); + + while ($entityTagDAO->fetch()) { + $contactIds[] = $entityTagDAO->entity_id; + } + return $contactIds; + } + + /** + * Function to check if contact has signed this petition + * + * @param int $surveyId + * @param int $contactId + * @static + */ + static function checkSignature($surveyId, $contactId) { + + $surveyInfo = CRM_Campaign_BAO_Petition::getSurveyInfo($surveyId); + $signature = array(); + + $sql = " + SELECT a.id AS id, + a.source_record_id AS source_record_id, + a.source_contact_id AS source_contact_id, + a.activity_date_time AS activity_date_time, + a.activity_type_id AS activity_type_id, + a.status_id AS status_id, + %1 AS survey_title + FROM civicrm_activity a + WHERE a.source_record_id = %2 + AND a.activity_type_id = %3 + AND a.source_contact_id = %4 +"; + $params = array(1 => array($surveyInfo['title'], 'String'), + 2 => array($surveyId, 'Integer'), + 3 => array($surveyInfo['activity_type_id'], 'Integer'), + 4 => array($contactId, 'Integer'), + ); + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + while ($dao->fetch()) { + $signature[$dao->id]['id'] = $dao->id; + $signature[$dao->id]['source_record_id'] = $dao->source_record_id; + $signature[$dao->id]['source_contact_id'] = CRM_Contact_BAO_Contact::displayName($dao->source_contact_id); + $signature[$dao->id]['activity_date_time'] = $dao->activity_date_time; + $signature[$dao->id]['activity_type_id'] = $dao->activity_type_id; + $signature[$dao->id]['status_id'] = $dao->status_id; + $signature[$dao->id]['survey_title'] = $dao->survey_title; + $signature[$dao->id]['contactId'] = $dao->source_contact_id; + } + + return $signature; + } + + /** + * takes an associative array and sends a thank you or email verification email + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return + * @access public + * @static + */ + function sendEmail($params, $sendEmailMode) { + + /* sendEmailMode + * CRM_Campaign_Form_Petition_Signature::EMAIL_THANK + * connected user via login/pwd - thank you + * or dedupe contact matched who doesn't have a tag CIVICRM_TAG_UNCONFIRMED - thank you + * or login using fb connect - thank you + click to add msg to fb wall + * + * CRM_Campaign_Form_Petition_Signature::EMAIL_CONFIRM + * send a confirmation request email + */ + + // check if the group defined by CIVICRM_PETITION_CONTACTS exists, else create it + $petitionGroupName = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'petition_contacts', + NULL, + 'Petition Contacts' + ); + + $dao = new CRM_Contact_DAO_Group(); + $dao->title = $petitionGroupName; + if (!$dao->find(TRUE)) { + $dao->is_active = 1; + $dao->visibility = 'Public Pages'; + $dao->save(); + } + $group_id = $dao->id; + + // get petition info + $petitionParams['id'] = $params['sid']; + $petitionInfo = array(); + CRM_Campaign_BAO_Survey::retrieve($petitionParams, $petitionInfo); + if (empty($petitionInfo)) { + CRM_Core_Error::fatal('Petition doesn\'t exist.'); + } + + //get the default domain email address. + list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(); + + $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain(); + + $toName = CRM_Contact_BAO_Contact::displayName($params['contactId']); + + $replyTo = "do-not-reply@$emailDomain"; + + // set additional general message template params (custom tokens to use in email msg templates) + // tokens then available in msg template as {$petition.title}, etc + $petitionTokens['title'] = $petitionInfo['title']; + $petitionTokens['petitionId'] = $params['sid']; + $tplParams['petition'] = $petitionTokens; + + switch ($sendEmailMode) { + case CRM_Campaign_Form_Petition_Signature::EMAIL_THANK: + + // add this contact to the CIVICRM_PETITION_CONTACTS group + // Cannot pass parameter 1 by reference + $p = array($params['contactId']); + CRM_Contact_BAO_GroupContact::addContactsToGroup($p, $group_id, 'API'); + + if ($params['email-Primary']) { + CRM_Core_BAO_MessageTemplates::sendTemplate( + array( + 'groupName' => 'msg_tpl_workflow_petition', + 'valueName' => 'petition_sign', + 'contactId' => $params['contactId'], + 'tplParams' => $tplParams, + 'from' => "\"{$domainEmailName}\" <{$domainEmailAddress}>", + 'toName' => $toName, + 'toEmail' => $params['email-Primary'], + 'replyTo' => $replyTo, + 'petitionId' => $params['sid'], + 'petitionTitle' => $petitionInfo['title'], + ) + ); + } + break; + + case CRM_Campaign_Form_Petition_Signature::EMAIL_CONFIRM: + // create mailing event subscription record for this contact + // this will allow using a hash key to confirm email address by sending a url link + $se = CRM_Mailing_Event_BAO_Subscribe::subscribe($group_id, + $params['email-Primary'], + $params['contactId'] + ); + + // require_once 'CRM/Core/BAO/Domain.php'; + // $domain = CRM_Core_BAO_Domain::getDomain(); + $config = CRM_Core_Config::singleton(); + $localpart = CRM_Core_BAO_MailSettings::defaultLocalpart(); + + $replyTo = implode($config->verpSeparator, + array( + $localpart . 'c', + $se->contact_id, + $se->id, + $se->hash, + ) + ) . "@$emailDomain"; + + + $confirmUrl = CRM_Utils_System::url('civicrm/petition/confirm', + "reset=1&cid={$se->contact_id}&sid={$se->id}&h={$se->hash}&a={$params['activityId']}&p={$params['sid']}", + TRUE + ); + $confirmUrlPlainText = CRM_Utils_System::url('civicrm/petition/confirm', + "reset=1&cid={$se->contact_id}&sid={$se->id}&h={$se->hash}&a={$params['activityId']}&p={$params['sid']}", + TRUE, + NULL, + FALSE + ); + + // set email specific message template params and assign to tplParams + $petitionTokens['confirmUrl'] = $confirmUrl; + $petitionTokens['confirmUrlPlainText'] = $confirmUrlPlainText; + $tplParams['petition'] = $petitionTokens; + + if ($params['email-Primary']) { + CRM_Core_BAO_MessageTemplates::sendTemplate( + array( + 'groupName' => 'msg_tpl_workflow_petition', + 'valueName' => 'petition_confirmation_needed', + 'contactId' => $params['contactId'], + 'tplParams' => $tplParams, + 'from' => "\"{$domainEmailName}\" <{$domainEmailAddress}>", + 'toName' => $toName, + 'toEmail' => $params['email-Primary'], + 'replyTo' => $replyTo, + 'petitionId' => $params['sid'], + 'petitionTitle' => $petitionInfo['title'], + 'confirmUrl' => $confirmUrl, + ) + ); + } + break; + } + } +} + diff --git a/CRM/Campaign/BAO/Query.php b/CRM/Campaign/BAO/Query.php new file mode 100755 index 0000000000..b9d771fa2a --- /dev/null +++ b/CRM/Campaign/BAO/Query.php @@ -0,0 +1,584 @@ +_params)) { + foreach ($query->_params as $values) { + if (!is_array($values) || count($values) != 5) { + continue; + } + + list($name, $op, $value, $grouping, $wildcard) = $values; + if ($name == 'campaign_survey_id') { + self::$_applySurveyClause = TRUE; + break; + } + } + } + + //get survey clause in force, + //only when we have survey id. + if (!self::$_applySurveyClause) { + return; + } + + //all below tables are require to fetch result. + + //1. get survey activity target table in. + $query->_select['survey_activity_target_contact_id'] = 'civicrm_activity_target.target_contact_id as survey_activity_target_contact_id'; + $query->_select['survey_activity_target_id'] = 'civicrm_activity_target.id as survey_activity_target_id'; + $query->_element['survey_activity_target_id'] = 1; + $query->_element['survey_activity_target_contact_id'] = 1; + $query->_tables[self::CIVICRM_ACTIVITY_TARGET] = 1; + $query->_whereTables[self::CIVICRM_ACTIVITY_TARGET] = 1; + + //2. get survey activity table in. + $query->_select['survey_activity_id'] = 'civicrm_activity.id as survey_activity_id'; + $query->_element['survey_activity_id'] = 1; + $query->_tables[self::CIVICRM_ACTIVITY] = 1; + $query->_whereTables[self::CIVICRM_ACTIVITY] = 1; + + //3. get the assignee table in. + $query->_select['survey_interviewer_id'] = 'civicrm_activity_assignment.id as survey_interviewer_id'; + $query->_element['survey_interviewer_id'] = 1; + $query->_tables[self::CIVICRM_ACTIVITY_ASSIGNMENT] = 1; + $query->_whereTables[self::CIVICRM_ACTIVITY_ASSIGNMENT] = 1; + + //4. get survey table. + $query->_select['campaign_survey_id'] = 'civicrm_survey.id as campaign_survey_id'; + $query->_element['campaign_survey_id'] = 1; + $query->_tables['civicrm_survey'] = 1; + $query->_whereTables['civicrm_survey'] = 1; + + //5. get campaign table. + $query->_select['campaign_id'] = 'civicrm_campaign.id as campaign_id'; + $query->_element['campaign_id'] = 1; + $query->_tables['civicrm_campaign'] = 1; + $query->_whereTables['civicrm_campaign'] = 1; + } + + static function where(&$query) { + //get survey clause in force, + //only when we have survey id. + if (!self::$_applySurveyClause) { + return; + } + + $grouping = NULL; + foreach (array_keys($query->_params) as $id) { + if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) { + $query->_useDistinct = TRUE; + } + + self::whereClauseSingle($query->_params[$id], $query); + } + } + + static function whereClauseSingle(&$values, &$query) { + //get survey clause in force, + //only when we have survey id. + if (!self::$_applySurveyClause) { + return; + } + + list($name, $op, $value, $grouping, $wildcard) = $values; + + switch ($name) { + case 'campaign_survey_id': + $query->_qill[$grouping][] = ts('Survey - %1', array(1 => CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $value, 'title'))); + + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause('civicrm_activity.source_record_id', + $op, $value, "Integer" + ); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause('civicrm_survey.id', + $op, $value, "Integer" + ); + return; + + case 'survey_status_id': + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + + $query->_qill[$grouping][] = ts('Survey Status - %1', array(1 => $activityStatus[$value])); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause('civicrm_activity.status_id', + $op, $value, "Integer" + ); + return; + + case 'campaign_search_voter_for': + if (in_array($value, array( + 'release', 'interview'))) { + $query->_where[$grouping][] = '(civicrm_activity.is_deleted = 0 OR civicrm_activity.is_deleted IS NULL)'; + } + return; + + case 'survey_interviewer_id': + $surveyInterviewerName = NULL; + foreach ($query->_params as $paramValues) { + if (CRM_Utils_Array::value(0, $paramValues) == 'survey_interviewer_name') { + $surveyInterviewerName = CRM_Utils_Array::value(2, $paramValues); + break; + } + } + $query->_qill[$grouping][] = ts('Survey Interviewer - %1', array(1 => $surveyInterviewerName)); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause('civicrm_activity_assignment.assignee_contact_id', + $op, $value, "Integer" + ); + return; + } + } + + static function from($name, $mode, $side) { + $from = NULL; + //get survey clause in force, + //only when we have survey id. + if (!self::$_applySurveyClause) { + return $from; + } + + switch ($name) { + case self::CIVICRM_ACTIVITY_TARGET: + $from = " INNER JOIN civicrm_activity_target ON ( civicrm_activity_target.target_contact_id = contact_a.id ) "; + break; + + case self::CIVICRM_ACTIVITY: + $surveyActivityTypes = CRM_Campaign_PseudoConstant::activityType(); + $surveyKeys = "(" . implode(',', array_keys($surveyActivityTypes)) . ")"; + $from = " INNER JOIN civicrm_activity ON ( civicrm_activity.id = civicrm_activity_target.activity_id + AND civicrm_activity.activity_type_id IN $surveyKeys ) "; + break; + + case self::CIVICRM_ACTIVITY_ASSIGNMENT: + $from = " +INNER JOIN civicrm_activity_assignment ON ( civicrm_activity.id = civicrm_activity_assignment.activity_id ) "; + break; + + case 'civicrm_survey': + $from = " INNER JOIN civicrm_survey ON ( civicrm_survey.id = civicrm_activity.source_record_id ) "; + break; + + case 'civicrm_campaign': + $from = " $side JOIN civicrm_campaign ON ( civicrm_campaign.id = civicrm_survey.campaign_id ) "; + break; + } + + return $from; + } + + static function defaultReturnProperties($mode, + $includeCustomFields = TRUE + ) { + $properties = NULL; + if ($mode & CRM_Contact_BAO_Query::MODE_CAMPAIGN) { + $properties = array( + 'contact_id' => 1, + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'sort_name' => 1, + 'display_name' => 1, + 'street_unit' => 1, + 'street_name' => 1, + 'street_number' => 1, + 'street_address' => 1, + 'city' => 1, + 'postal_code' => 1, + 'state_province' => 1, + 'country' => 1, + 'email' => 1, + 'phone' => 1, + 'survey_activity_target_id' => 1, + 'survey_activity_id' => 1, + 'survey_status_id' => 1, + 'campaign_survey_id' => 1, + 'campaign_id' => 1, + 'survey_interviewer_id' => 1, + 'survey_activity_target_contact_id' => 1, + ); + } + + return $properties; + } + + static function tableNames(&$tables) {} + static function searchAction(&$row, $id) {} + + static function info(&$tables) { + //get survey clause in force, + //only when we have survey id. + if (!self::$_applySurveyClause) { + return; + } + + $weight = end($tables); + $tables[self::CIVICRM_ACTIVITY_TARGET] = ++$weight; + $tables[self::CIVICRM_ACTIVITY] = ++$weight; + $tables[self::CIVICRM_ACTIVITY_ASSIGNMENT] = ++$weight; + $tables['civicrm_survey'] = ++$weight; + $tables['civicrm_campaign'] = ++$weight; + } + + /** + * add all the elements shared between, + * normal voter search and voter listing (GOTV form) + * + * @access public + * + * @return void + * @static + */ + static function buildSearchForm(&$form) { + + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_Address'); + $className = CRM_Utils_System::getClassName($form); + + $form->add('text', 'sort_name', ts('Contact Name'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name') + ); + $form->add('text', 'street_name', ts('Street Name'), $attributes['street_name']); + $form->add('text', 'street_number', ts('Street Number'), $attributes['street_number']); + $form->add('text', 'street_unit', ts('Street Unit'), $attributes['street_unit']); + $form->add('text', 'street_address', ts('Street Address'), $attributes['street_address']); + $form->add('text', 'city', ts('City'), $attributes['city']); + $form->add('text', 'postal_code', ts('Zip / Postal Code'), $attributes['postal_code']); + + $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(); + $form->add('select', 'contact_type', ts('Contact Type(s)'), $contactTypes, FALSE, + array('id' => 'contact_type', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + $groups = CRM_Core_PseudoConstant::group(); + $form->add('select', 'group', ts('Groups'), $groups, FALSE, + array('id' => 'group', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + + $showInterviewer = FALSE; + if (CRM_Core_Permission::check('administer CiviCampaign')) { + $showInterviewer = TRUE; + } + $form->assign('showInterviewer', $showInterviewer); + + if ($showInterviewer || + $className == 'CRM_Campaign_Form_Gotv' + ) { + //autocomplete url + $dataUrl = CRM_Utils_System::url('civicrm/ajax/rest', + 'className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&reset=1', + FALSE, NULL, FALSE + ); + + $form->assign('dataUrl', $dataUrl); + $form->add('text', 'survey_interviewer_name', ts('Interviewer')); + $form->add('hidden', 'survey_interviewer_id', '', array('id' => 'survey_interviewer_id')); + + $userId = NULL; + if (isset($form->_interviewerId) && $form->_interviewerId) { + $userId = $form->_interviewerId; + } + if (!$userId) { + $session = CRM_core_Session::singleton(); + $userId = $session->get('userID'); + } + if ($userId) { + $defaults = array(); + $defaults['survey_interviewer_id'] = $userId; + $defaults['survey_interviewer_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $userId, + 'sort_name', + 'id' + ); + $form->setDefaults($defaults); + } + } + + //build ward and precinct custom fields. + $query = ' + SELECT fld.id, fld.label + FROM civicrm_custom_field fld +INNER JOIN civicrm_custom_group grp on fld.custom_group_id = grp.id + WHERE grp.name = %1'; + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array('Voter_Info', 'String'))); + $customSearchFields = array(); + while ($dao->fetch()) { + foreach (array( + 'ward', 'precinct') as $name) { + if (stripos($name, $dao->label) !== FALSE) { + $fieldId = $dao->id; + $fieldName = 'custom_' . $dao->id; + $customSearchFields[$name] = $fieldName; + CRM_Core_BAO_CustomField::addQuickFormElement($form, $fieldName, $fieldId, FALSE, FALSE); + break; + } + } + } + $form->assign('customSearchFields', $customSearchFields); + + $surveys = CRM_Campaign_BAO_Survey::getSurveys(); + + if (empty($surveys) && + ($className == 'CRM_Campaign_Form_Search') + ) { + CRM_Core_Error::statusBounce(ts('Could not find survey for %1 respondents.', + array(1 => $form->get('op')) + ), + CRM_Utils_System::url('civicrm/survey/add', + 'reset=1&action=add' + ) + ); + } + + //CRM-7406 -- + //If survey had associated campaign and + //campaign has some contact groups, don't + //allow to search the contacts those are not + //in given campaign groups ( ie not in constituents ) + $groupJs = NULL; + if ($form->get('searchVoterFor') == 'reserve') { + $groupJs = array('onChange' => "buildCampaignGroups( );return false;"); + } + $form->add('select', 'campaign_survey_id', ts('Survey'), $surveys, TRUE, $groupJs); + } + + /* + * Retrieve all valid voter ids, + * and build respective clause to restrict search. + * + * @param array $criteria an array + * @return $voterClause as a string + * @static + */ + function voterClause($params) { + $voterClause = array(); + $fromClause = $whereClause = NULL; + if (!is_array($params) || empty($params)) { + return $voterClause; + } + $surveyId = CRM_Utils_Array::value('campaign_survey_id', $params); + $interviewerId = CRM_Utils_Array::value('survey_interviewer_id', $params); + $searchVoterFor = CRM_Utils_Array::value('campaign_search_voter_for', $params); + + //get the survey activities. + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $status = array('Scheduled'); + if ($searchVoterFor == 'reserve') { + $status[] = 'Completed'; + } + + $completedStatusId = NULL; + foreach ($status as $name) { + if ($statusId = array_search($name, $activityStatus)) { + $statusIds[] = $statusId; + if ($name == 'Completed') { + $completedStatusId = $statusId; + } + } + } + + $voterActValues = CRM_Campaign_BAO_Survey::getSurveyVoterInfo($surveyId, NULL, $statusIds); + + if (!empty($voterActValues)) { + $operator = 'IN'; + $voterIds = array_keys($voterActValues); + if ($searchVoterFor == 'reserve') { + $operator = 'NOT IN'; + //filter out recontact survey contacts. + $recontactInterval = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', + $surveyId, 'recontact_interval' + ); + $recontactInterval = unserialize($recontactInterval); + if ($surveyId && + is_array($recontactInterval) && + !empty($recontactInterval) + ) { + $voterIds = array(); + foreach ($voterActValues as $values) { + $numOfDays = CRM_Utils_Array::value($values['result'], $recontactInterval); + if ($numOfDays && + $values['status_id'] == $completedStatusId + ) { + $recontactIntSeconds = $numOfDays * 24 * 3600; + $actDateTimeSeconds = CRM_Utils_Date::unixTime($values['activity_date_time']); + $totalSeconds = $recontactIntSeconds + $actDateTimeSeconds; + //don't consider completed survey activity + //unless it fulfill recontact interval criteria. + if ($totalSeconds <= time()) { + continue; + } + } + $voterIds[$values['voter_id']] = $values['voter_id']; + } + } + } + + //lets dump these ids in tmp table and + //use appropriate join depend on operator. + if (!empty($voterIds)) { + $voterIdCount = count($voterIds); + + //create temporary table to store voter ids. + $tempTableName = CRM_Core_DAO::createTempTableName('civicrm_survey_respondent'); + CRM_Core_DAO::executeQuery("DROP TABLE IF EXISTS {$tempTableName}"); + + $query = " + CREATE TEMPORARY TABLE {$tempTableName} ( + id int unsigned NOT NULL AUTO_INCREMENT, + survey_contact_id int unsigned NOT NULL, + PRIMARY KEY ( id ) +); +"; + CRM_Core_DAO::executeQuery($query); + + $batch = 100; + $insertedCount = 0; + do { + $processIds = $voterIds; + $insertIds = array_splice($processIds, $insertedCount, $batch); + if (!empty($insertIds)) { + $insertSQL = "INSERT IGNORE INTO {$tempTableName}( survey_contact_id ) + VALUES (" . implode('),(', $insertIds) . ');'; + CRM_Core_DAO::executeQuery($insertSQL); + } + $insertedCount += $batch; + } while ($insertedCount < $voterIdCount); + + if ($operator == 'IN') { + $fromClause = " INNER JOIN {$tempTableName} ON ( {$tempTableName}.survey_contact_id = contact_a.id )"; + } + else { + $fromClause = " LEFT JOIN {$tempTableName} ON ( {$tempTableName}.survey_contact_id = contact_a.id )"; + $whereClause = "( {$tempTableName}.survey_contact_id IS NULL )"; + } + } + } + $voterClause = array( + 'fromClause' => $fromClause, + 'whereClause' => $whereClause, + ); + + return $voterClause; + } + + /** + * Build the campaign clause for component serach. + * + **/ + public static function componentSearchClause(&$params, &$query) { + $op = CRM_Utils_Array::value('op', $params, '='); + $campaign = CRM_Utils_Array::value('campaign', $params); + $tableName = CRM_Utils_Array::value('tableName', $params); + $grouping = CRM_Utils_Array::value('grouping', $params); + if (CRM_Utils_System::isNull($campaign) || empty($tableName)) { + return; + } + + // fixme - what is the purpose of this code? $campaign should be + // an integer, not an array + if (is_array($campaign)) { + foreach (array( + 'current_campaign', 'past_campaign') as $ignore) { + $index = array_search($ignore, $campaign); + if ($index !== FALSE)unset($campaign[$index]); + } + } + + $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + + $campaignIds = $campaignTitles = array(); + if (is_array($campaign)) { + foreach ($campaign as $campId) { + $campaignIds[$campId] = $campId; + $campaignTitles[$campId] = $allCampaigns[$campId]; + } + if (count($campaignIds) > 1) { + $op = 'IN'; + $campaignIds = '(' . implode(',', $campaignIds) . ')'; + } + else { + $campaignIds = reset($campaignIds); + } + } + else { + $campaignIds = $campaign; + if (array_key_exists($campaignIds, $allCampaigns)) { + $campaignTitles[$campaignIds] = $allCampaigns[$campaignIds]; + } + } + $query->_qill[$grouping][] = ts('Campaigns %1', + array(1 => $op) + ) . ' ' . implode(' ' . ts('or') . ' ', $campaignTitles); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("{$tableName}.campaign_id", + $op, + $campaignIds, + 'Integer' + ); + $query->_tables[$tableName] = $query->_whereTables[$tableName] = 1; + } +} + diff --git a/CRM/Campaign/BAO/Survey.php b/CRM/Campaign/BAO/Survey.php new file mode 100644 index 0000000000..3af9a1cdb6 --- /dev/null +++ b/CRM/Campaign/BAO/Survey.php @@ -0,0 +1,1081 @@ +copyValues($params); + + if ($dao->find(TRUE)) { + CRM_Core_DAO::storeValues($dao, $defaults); + return $dao; + } + return NULL; + } + + /** + * takes an associative array and creates a Survey object + * + * the function extract all the params it needs to initialize the create a + * survey object. + * + * + * @return object CRM_Survey_DAO_Survey object + * @access public + * @static + */ + static function create(&$params) { + if (empty($params)) { + return false; + } + + if (CRM_Utils_Array::value('is_default', $params)) { + $query = "UPDATE civicrm_survey SET is_default = 0"; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + + if (!(CRM_Utils_Array::value('id', $params))) { + + if (!(CRM_Utils_Array::value('created_id', $params))) { + $session = CRM_Core_Session::singleton(); + $params['created_id'] = $session->get('userID'); + } + if (!(CRM_Utils_Array::value('created_date', $params))) { + $params['created_date'] = date('YmdHis'); + } + } + + $dao = new CRM_Campaign_DAO_Survey(); + $dao->copyValues($params); + $dao->save(); + + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_survey', $dao->id); + } + return $dao; + } + + /** + * Function to retrieve surveys for dashboard. + * + * @static + */ + static function getSurveySummary($params = array( + ), $onlyCount = FALSE) { + //build the limit and order clause. + $limitClause = $orderByClause = $lookupTableJoins = NULL; + if (!$onlyCount) { + $sortParams = array( + 'sort' => 'created_date', + 'offset' => 0, + 'rowCount' => 10, + 'sortOrder' => 'desc', + ); + foreach ($sortParams as $name => $default) { + if (CRM_Utils_Array::value($name, $params)) { + $sortParams[$name] = $params[$name]; + } + } + + //need to lookup tables. + $orderOnSurveyTable = TRUE; + if ($sortParams['sort'] == 'campaign') { + $orderOnSurveyTable = FALSE; + $lookupTableJoins = ' + LEFT JOIN civicrm_campaign campaign ON ( campaign.id = survey.campaign_id )'; + $orderByClause = "ORDER BY campaign.title {$sortParams['sortOrder']}"; + } + elseif ($sortParams['sort'] == 'activity_type') { + $orderOnSurveyTable = FALSE; + $lookupTableJoins = " + LEFT JOIN civicrm_option_value activity_type ON ( activity_type.value = survey.activity_type_id + OR survey.activity_type_id IS NULL ) +INNER JOIN civicrm_option_group grp ON ( activity_type.option_group_id = grp.id AND grp.name = 'activity_type' )"; + $orderByClause = "ORDER BY activity_type.label {$sortParams['sortOrder']}"; + } + elseif ($sortParams['sort'] == 'isActive') { + $sortParams['sort'] = 'is_active'; + } + if ($orderOnSurveyTable) { + $orderByClause = "ORDER BY survey.{$sortParams['sort']} {$sortParams['sortOrder']}"; + } + $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}"; + } + + //build the where clause. + $queryParams = $where = array(); + + //we only have activity type as a + //difference between survey and petition. + $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name'); + if ($petitionTypeID) { + $where[] = "( survey.activity_type_id != %1 )"; + $queryParams[1] = array($petitionTypeID, 'Positive'); + } + + if (CRM_Utils_Array::value('title', $params)) { + $where[] = "( survey.title LIKE %2 )"; + $queryParams[2] = array('%' . trim($params['title']) . '%', 'String'); + } + if (CRM_Utils_Array::value('campaign_id', $params)) { + $where[] = '( survey.campaign_id = %3 )'; + $queryParams[3] = array($params['campaign_id'], 'Positive'); + } + if (CRM_Utils_Array::value('activity_type_id', $params)) { + $typeId = $params['activity_type_id']; + if (is_array($params['activity_type_id'])) { + $typeId = implode(' , ', $params['activity_type_id']); + } + $where[] = "( survey.activity_type_id IN ( {$typeId} ) )"; + } + $whereClause = NULL; + if (!empty($where)) { + $whereClause = ' WHERE ' . implode(" \nAND ", $where); + } + + $selectClause = ' +SELECT survey.id as id, + survey.title as title, + survey.is_active as is_active, + survey.result_id as result_id, + survey.is_default as is_default, + survey.campaign_id as campaign_id, + survey.activity_type_id as activity_type_id, + survey.release_frequency as release_frequency, + survey.max_number_of_contacts as max_number_of_contacts, + survey.default_number_of_contacts as default_number_of_contacts'; + if ($onlyCount) { + $selectClause = 'SELECT COUNT(*)'; + } + $fromClause = 'FROM civicrm_survey survey'; + + $query = "{$selectClause} {$fromClause} {$lookupTableJoins} {$whereClause} {$orderByClause} {$limitClause}"; + + //return only count. + if ($onlyCount) { + return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams); + } + + $surveys = array(); + $properties = array( + 'id', 'title', 'campaign_id', 'is_active', 'is_default', 'result_id', 'activity_type_id', + 'release_frequency', 'max_number_of_contacts', 'default_number_of_contacts', + ); + + $survey = CRM_Core_DAO::executeQuery($query, $queryParams); + while ($survey->fetch()) { + foreach ($properties as $property) { + $surveys[$survey->id][$property] = $survey->$property; + } + } + + return $surveys; + } + + /** + * Get the survey count. + * + * @static + */ + static function getSurveyCount() { + return (int)CRM_Core_DAO::singleValueQuery('SELECT COUNT(*) FROM civicrm_survey'); + } + + /** + * Function to get Surveys + * + * @param boolean $onlyActive retrieve only active surveys. + * @param boolean $onlyDefault retrieve only default survey. + * @param boolean $forceAll retrieve all surveys. + * + * @static + */ + static function getSurveys($onlyActive = TRUE, + $onlyDefault = FALSE, + $forceAll = FALSE + ) { + $cacheKey = 0; + $cacheKeyParams = array('onlyActive', 'onlyDefault', 'forceAll'); + foreach ($cacheKeyParams as $param) { + $cacheParam = $$param; + if (!$cacheParam) { + $cacheParam = 0; + } + $cacheKey .= '_' . $cacheParam; + } + + static $surveys; + + if (!isset($surveys[$cacheKey])) { + + //we only have activity type as a + //difference between survey and petition. + $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name'); + + $where = array(); + if ($petitionTypeID) { + $where[] = "( survey.activity_type_id != {$petitionTypeID} )"; + } + if (!$forceAll && $onlyActive) { + $where[] = '( survey.is_active = 1 )'; + } + if (!$forceAll && $onlyDefault) { + $where[] = '( survey.is_default = 1 )'; + } + $whereClause = implode(' AND ', $where); + + $query = " +SELECT survey.id as id, + survey.title as title + FROM civicrm_survey as survey + WHERE {$whereClause}"; + $surveys[$cacheKey] = array(); + $survey = CRM_Core_DAO::executeQuery($query); + while ($survey->fetch()) { + $surveys[$cacheKey][$survey->id] = $survey->title; + } + } + + return $surveys[$cacheKey]; + } + + /** + * Function to get Surveys activity types + * + * + * @static + */ + static function getSurveyActivityType($returnColumn = 'label', + $includePetitionActivityType = FALSE + ) { + static $activityTypes; + $cacheKey = "{$returnColumn}_{$includePetitionActivityType}"; + + if (!isset($activityTypes[$cacheKey])) { + $activityTypes = array(); + $campaignCompId = CRM_Core_Component::getComponentID('CiviCampaign'); + if ($campaignCompId) { + $condition = " AND v.component_id={$campaignCompId}"; + if (!$includePetitionActivityType) { + $condition .= " AND v.name != 'Petition'"; + } + $activityTypes[$cacheKey] = CRM_Core_OptionGroup::values('activity_type', + FALSE, FALSE, FALSE, + $condition, + $returnColumn + ); + } + } + + return $activityTypes[$cacheKey]; + } + + /** + * Function to get Surveys custom groups + * + * @param $surveyTypes array an array of survey type id. + * + * @static + */ + static function getSurveyCustomGroups($surveyTypes = array( + )) { + $customGroups = array(); + if (!is_array($surveyTypes)) { + $surveyTypes = array($surveyTypes); + } + + if (!empty($surveyTypes)) { + $activityTypes = array_flip($surveyTypes); + } + else { + $activityTypes = self::getSurveyActivityType(); + } + + if (!empty($activityTypes)) { + $extendSubType = implode('[[:>:]]|[[:<:]]', array_keys($activityTypes)); + + $query = "SELECT cg.id, cg.name, cg.title, cg.extends_entity_column_value + FROM civicrm_custom_group cg + WHERE cg.is_active = 1 AND cg.extends_entity_column_value REGEXP '[[:<:]]{$extendSubType}[[:>:]]'"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $customGroups[$dao->id]['id'] = $dao->id; + $customGroups[$dao->id]['name'] = $dao->name; + $customGroups[$dao->id]['title'] = $dao->title; + $customGroups[$dao->id]['extends'] = $dao->extends_entity_column_value; + } + } + + return $customGroups; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Campaign_DAO_Survey', $id, 'is_active', $is_active); + } + + /** + * Function to delete the survey + * + * @param int $id survey id + * + * @access public + * @static + * + */ + static function del($id) { + if (!$id) { + return NULL; + } + $reportId = CRM_Campaign_BAO_Survey::getReportID($id); + if($reportId){ + CRM_Report_BAO_Instance::delete($reportId); + } + $dao = new CRM_Campaign_DAO_Survey(); + $dao->id = $id; + return $dao->delete(); + } + + /** + * This function retrieve contact information. + * + * @param array $voter an array of contact Ids. + * @param array $returnProperties an array of return elements. + * + * @return $voterDetails array of contact info. + * @static + */ + static function voterDetails($voterIds, $returnProperties = array( + )) { + $voterDetails = array(); + if (!is_array($voterIds) || empty($voterIds)) { + return $voterDetails; + } + + if (empty($returnProperties)) { + $autocompleteContactSearch = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_autocomplete_options' + ); + $returnProperties = array_fill_keys(array_merge(array( + 'contact_type', + 'contact_sub_type', + 'sort_name', + ), + array_keys($autocompleteContactSearch) + ), 1); + } + + $select = $from = array(); + foreach ($returnProperties as $property => $ignore) { + $value = (in_array($property, array( + 'city', 'street_address'))) ? 'address' : $property; + switch ($property) { + case 'sort_name': + case 'contact_type': + case 'contact_sub_type': + $select[] = "$property as $property"; + $from['contact'] = 'civicrm_contact contact'; + break; + + case 'email': + case 'phone': + case 'city': + case 'street_address': + $select[] = "$property as $property"; + $from[$value] = "LEFT JOIN civicrm_{$value} {$value} ON ( contact.id = {$value}.contact_id AND {$value}.is_primary = 1 ) "; + break; + + case 'country': + case 'state_province': + $select[] = "{$property}.name as $property"; + if (!in_array('address', $from)) { + $from['address'] = 'LEFT JOIN civicrm_address address ON ( contact.id = address.contact_id AND address.is_primary = 1) '; + } + $from[$value] = " LEFT JOIN civicrm_{$value} {$value} ON ( address.{$value}_id = {$value}.id ) "; + break; + } + } + + //finally retrieve contact details. + if (!empty($select) && !empty($from)) { + $fromClause = implode(' ', $from); + $selectClause = implode(', ', $select); + $whereClause = "contact.id IN (" . implode(',', $voterIds) . ')'; + + $query = " + SELECT contact.id as contactId, $selectClause + FROM $fromClause + WHERE $whereClause +Group By contact.id"; + + $contact = CRM_Core_DAO::executeQuery($query); + while ($contact->fetch()) { + $voterDetails[$contact->contactId]['contact_id'] = $contact->contactId; + foreach ($returnProperties as $property => $ignore) { + $voterDetails[$contact->contactId][$property] = $contact->$property; + } + $image = CRM_Contact_BAO_Contact_Utils::getImage($contact->contact_sub_type ? + $contact->contact_sub_type : $contact->contact_type, + FALSE, + $contact->contactId + ); + $voterDetails[$contact->contactId]['contact_type'] = $image; + } + $contact->free(); + } + + return $voterDetails; + } + + /** + * This function retrieve survey related activities w/ for give voter ids. + * + * @param int $surveyId survey id. + * @param array $voterIds voterIds. + * + * @return $activityDetails array of survey activity. + * @static + */ + static function voterActivityDetails($surveyId, $voterIds, $interviewerId = NULL, + $statusIds = array()) { + $activityDetails = array(); + if (!$surveyId || + !is_array($voterIds) || empty($voterIds) + ) { + return $activityDetails; + } + + $whereClause = NULL; + if (is_array($statusIds) && !empty($statusIds)) { + $whereClause = ' AND ( activity.status_id IN ( ' . implode(',', array_values($statusIds)) . ' ) )'; + } + + if (!$interviewerId) { + $session = CRM_Core_Session::singleton(); + $interviewerId = $session->get('userID'); + } + + $targetContactIds = ' ( ' . implode(',', $voterIds) . ' ) '; + + $query = " + SELECT activity.id, activity.status_id, + activityTarget.target_contact_id as voter_id, + activityAssignment.assignee_contact_id as interviewer_id + FROM civicrm_activity activity +INNER JOIN civicrm_activity_target activityTarget ON ( activityTarget.activity_id = activity.id ) +INNER JOIN civicrm_activity_assignment activityAssignment ON ( activityAssignment.activity_id = activity.id ) + WHERE activity.source_record_id = %1 + AND ( activity.is_deleted IS NULL OR activity.is_deleted = 0 ) + AND activityAssignment.assignee_contact_id = %2 + AND activityTarget.target_contact_id IN {$targetContactIds} + $whereClause"; + + $activity = CRM_Core_DAO::executeQuery($query, array(1 => array($surveyId, 'Integer'), + 2 => array($interviewerId, 'Integer'), + )); + while ($activity->fetch()) { + $activityDetails[$activity->voter_id] = array( + 'voter_id' => $activity->voter_id, + 'status_id' => $activity->status_id, + 'activity_id' => $activity->id, + 'interviewer_id' => $activity->interviewer_id, + ); + } + + return $activityDetails; + } + + /** + * This function retrieve survey related activities. + * + * @param int $surveyId survey id. + * + * @return $activities an array of survey activity. + * @static + */ + static function getSurveyActivities($surveyId, + $interviewerId = NULL, + $statusIds = NULL, + $voterIds = NULL, + $onlyCount = FALSE + ) { + $activities = array(); + $surveyActivityCount = 0; + if (!$surveyId) { + return ($onlyCount) ? 0 : $activities; + } + + $where = array(); + if (!empty($statusIds)) { + $where[] = '( activity.status_id IN ( ' . implode(',', array_values($statusIds)) . ' ) )'; + } + + if ($interviewerId) { + $where[] = "( activityAssignment.assignee_contact_id = $interviewerId )"; + } + + if (!empty($voterIds)) { + $where[] = "( activityTarget.target_contact_id IN ( " . implode(',', $voterIds) . " ) )"; + } + + $whereClause = NULL; + if (!empty($where)) { + $whereClause = ' AND ( ' . implode(' AND ', $where) . ' )'; + } + + $actTypeId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $surveyId, 'activity_type_id'); + if (!$actTypeId) { + return $activities; + } + + if ($onlyCount) { + $select = "SELECT count(activity.id)"; + } + else { + $select = " + SELECT activity.id, activity.status_id, + activityTarget.target_contact_id as voter_id, + activityAssignment.assignee_contact_id as interviewer_id, + activity.result as result, + activity.activity_date_time as activity_date_time, + contact_a.display_name as voter_name"; + } + + $query = " + $select + FROM civicrm_activity activity +INNER JOIN civicrm_activity_target activityTarget ON ( activityTarget.activity_id = activity.id ) +INNER JOIN civicrm_activity_assignment activityAssignment ON ( activityAssignment.activity_id = activity.id ) +INNER JOIN civicrm_contact contact_a ON ( activityTarget.target_contact_id = contact_a.id ) + WHERE activity.source_record_id = %1 + AND activity.activity_type_id = %2 + AND ( activity.is_deleted IS NULL OR activity.is_deleted = 0 ) + $whereClause"; + + $params = array(1 => array($surveyId, 'Integer'), + 2 => array($actTypeId, 'Integer'), + ); + + if ($onlyCount) { + $dbCount = CRM_Core_DAO::singleValueQuery($query, $params); + return ($dbCount) ? $dbCount : 0; + } + + $activity = CRM_Core_DAO::executeQuery($query, $params); + + while ($activity->fetch()) { + $activities[$activity->id] = array( + 'id' => $activity->id, + 'voter_id' => $activity->voter_id, + 'voter_name' => $activity->voter_name, + 'status_id' => $activity->status_id, + 'interviewer_id' => $activity->interviewer_id, + 'result' => $activity->result, + 'activity_date_time' => $activity->activity_date_time + ); + } + + return $activities; + } + + /** + * This function retrieve survey voter information. + * + * @param int $surveyId survey id. + * @param int $interviewerId interviewer id. + * @param array $statusIds survey status ids. + * + * @return array $$contactIds survey related contact ids. + * @static + */ + static function getSurveyVoterInfo($surveyId, $interviewerId = NULL, $statusIds = array( )) { + $voterIds = array(); + if (!$surveyId) { + return $voterIds; + } + + $cacheKey = $surveyId; + if ($interviewerId) { + $cacheKey .= "_{$interviewerId}"; + } + if (is_array($statusIds) && !empty($statusIds)) { + $cacheKey = "{$cacheKey}_" . implode('_', $statusIds); + } + + static $contactIds = array(); + if (!isset($contactIds[$cacheKey])) { + $activities = self::getSurveyActivities($surveyId, $interviewerId, $statusIds); + foreach ($activities as $values) { + $voterIds[$values['voter_id']] = $values; + } + $contactIds[$cacheKey] = $voterIds; + } + + return $contactIds[$cacheKey]; + } + + /** + * This function retrieve all option groups which are created as a result set + * + * @return $resultSets an array of option groups. + * @static + */ + static function getResultSets( $valueColumnName = 'title' ) { + $resultSets = array(); + $valueColumnName = CRM_Utils_Type::escape($valueColumnName, 'String'); + + $query = "SELECT id, {$valueColumnName} FROM civicrm_option_group WHERE name LIKE 'civicrm_survey_%' AND is_active=1"; + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $resultSets[$dao->id] = $dao->$valueColumnName; + } + + return $resultSets; + } + + /** + * This function is to check survey activity. + * + * @param int $activityId activity id. + * @param int $activityTypeId activity type id. + * @return boolean $isSurveyActivity true/false boolean. + * @static + */ + static function isSurveyActivity($activityId) { + $isSurveyActivity = FALSE; + if (!$activityId) { + return $isSurveyActivity; + } + + $activity = new CRM_Activity_DAO_Activity(); + $activity->id = $activityId; + $activity->selectAdd('source_record_id, activity_type_id'); + if ($activity->find(TRUE) && + $activity->source_record_id + ) { + $surveyActTypes = self::getSurveyActivityType(); + if (array_key_exists($activity->activity_type_id, $surveyActTypes)) { + $isSurveyActivity = TRUE; + } + } + + return $isSurveyActivity; + } + + /** + * This function retrive all response options of survey + * + * @param int $surveyId survey id. + * @return $responseOptions an array of option values + * @static + */ + static function getResponsesOptions($surveyId) { + $responseOptions = array(); + if (!$surveyId) { + return $responseOptions; + } + + $resultId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $surveyId, 'result_id'); + if ($resultId) { + $responseOptions = CRM_Core_OptionGroup::valuesByID($resultId); + } + + return $responseOptions; + } + + /** + * This function return all voter links with respecting permissions + * + * @return $url array of permissioned links + * @static + */ + static function buildPermissionLinks($surveyId, $enclosedInUL = FALSE, $extraULName = 'more') { + $menuLinks = array(); + if (!$surveyId) { + return $menuLinks; + } + + static $voterLinks = array(); + if (empty($voterLinks)) { + $permissioned = FALSE; + if (CRM_Core_Permission::check('manage campaign') || + CRM_Core_Permission::check('administer CiviCampaign') + ) { + $permissioned = TRUE; + } + + if ($permissioned || CRM_Core_Permission::check("reserve campaign contacts")) { + $voterLinks['reserve'] = array( + 'name' => 'reserve', + 'url' => 'civicrm/survey/search', + 'qs' => 'sid=%%id%%&reset=1&op=reserve&force=1', + 'title' => ts('Reserve Respondents'), + ); + } + if ($permissioned || CRM_Core_Permission::check("interview campaign contacts")) { + $voterLinks['release'] = array( + 'name' => 'interview', + 'url' => 'civicrm/survey/search', + 'qs' => 'sid=%%id%%&reset=1&op=interview&force=1', + 'title' => ts('Interview Respondents'), + ); + } + if ($permissioned || CRM_Core_Permission::check("release campaign contacts")) { + $voterLinks['interview'] = array( + 'name' => 'release', + 'url' => 'civicrm/survey/search', + 'qs' => 'sid=%%id%%&reset=1&op=release&force=1', + 'title' => ts('Release Respondents'), + ); + } + } + + if (CRM_Core_Permission::check('access CiviReport')) { + $reportID = self::getReportID($surveyId); + if ($reportID) { + $voterLinks['report'] = + array( + 'name' => 'report', + 'url' => "civicrm/report/instance/{$reportID}", + 'qs' => 'reset=1', + 'title' => ts('View Survey Report'), + ); + } + } + + $ids = array('id' => $surveyId); + foreach ($voterLinks as $link) { + if (CRM_Utils_Array::value('qs', $link) && + !CRM_Utils_System::isNull($link['qs']) + ) { + $urlPath = CRM_Utils_System::url(CRM_Core_Action::replace($link['url'], $ids), + CRM_Core_Action::replace($link['qs'], $ids) + ); + $menuLinks[] = sprintf('%s', + $urlPath, + CRM_Utils_Array::value('title', $link), + $link['title'] + ); + } + } + if ($enclosedInUL) { + $extraLinksName = strtolower($extraULName); + $allLinks = ''; + CRM_Utils_String::append($allLinks, '
  • ', $menuLinks); + $allLinks = "$extraULName "; + $menuLinks = "{$allLinks}"; + } + + return $menuLinks; + } + + /** + * Function to retrieve survey associated profile id. + * + */ + public static function getSurveyProfileId($surveyId) { + if (!$surveyId) { + return NULL; + } + + static $ufIds = array(); + if (!array_key_exists($surveyId, $ufIds)) { + //get the profile id. + $ufJoinParams = array( + 'entity_id' => $surveyId, + 'entity_table' => 'civicrm_survey', + 'module' => 'CiviCampaign', + ); + + list($first, $second) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + + if ($first) { + $ufIds[$surveyId] = array($first); + } + if ($second) { + $ufIds[$surveyId][] = array_shift($second); + } + } + + return $ufIds[$surveyId]; + } + + public Static function getReportID($surveyId) { + static $reportIds = array(); + + if (!array_key_exists($surveyId, $reportIds)) { + $query = "SELECT MAX(id) as id FROM civicrm_report_instance WHERE name = %1"; + $reportID = CRM_Core_DAO::singleValueQuery($query, array(1 => array("survey_{$surveyId}",'String'))); + $reportIds[$surveyId] = $reportID; + } + return $reportIds[$surveyId]; + } + + /** + * Function to decides the contact type for given survey. + * + */ + public static function getSurveyContactType($surveyId) { + $contactType = NULL; + + //apply filter of profile type on search. + $profileId = self::getSurveyProfileId($surveyId); + if ($profileId) { + $profileType = CRM_Core_BAO_UFField::getProfileType($profileId); + if (in_array($profileType, CRM_Contact_BAO_ContactType::basicTypes())) { + $contactType = $profileType; + } + } + + return $contactType; + } + + /** + * Function to get survey supportable profile types + * + */ + public static function surveyProfileTypes() { + static $profileTypes; + + if (!isset($profileTypes)) { + $profileTypes = array_merge(array('Activity', 'Contact'), CRM_Contact_BAO_ContactType::basicTypes()); + $profileTypes = array_diff($profileTypes, array('Organization','Household')); + } + + return $profileTypes; + } + + /** + * Get the valid survey response fields those + * are configured with profile and custom fields. + * + * @param int $surveyId survey id. + * @param int $surveyTypeId survey activity type id. + * + * @return array an array of valid survey response fields. + */ + public static function getSurveyResponseFields($surveyId, $surveyTypeId = NULL) { + if (empty($surveyId)) { + return array(); + } + + static $responseFields; + $cacheKey = "{$surveyId}_{$surveyTypeId}"; + + if (isset($responseFields[$cacheKey])) { + return $responseFields[$cacheKey]; + } + + $responseFields[$cacheKey] = array(); + + $profileId = self::getSurveyProfileId($surveyId); + + if (!$profileId) { + return $responseFields; + } + + if (!$surveyTypeId) { + $surveyTypeId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $surveyId, 'activity_type_id'); + } + + $profileFields = CRM_Core_BAO_UFGroup::getFields($profileId, + FALSE, CRM_Core_Action::VIEW + ); + + //don't load these fields in grid. + $removeFields = array('File', 'RichTextEditor'); + + $supportableFieldTypes = self::surveyProfileTypes(); + + // get custom fields of type survey + $customFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, $surveyTypeId); + + foreach ($profileFields as $name => $field) { + //get only contact and activity fields. + //later stage we might going to consider contact type also. + if (!in_array($field['field_type'], $supportableFieldTypes)) { + continue; + } + if ($field['name'] == 'activity_engagement_level') { + $responseFields[$cacheKey][$name] = $field; + } + // we should allow all supported custom data for survey + // In case of activity, allow normal activity and with subtype survey, + // suppress custom data of other activity types + if (CRM_Core_BAO_CustomField::getKeyID($name) && + !in_array($field['html_type'], $removeFields) + ) { + if ($field['field_type'] != 'Activity') { + $responseFields[$cacheKey][$name] = $field; + } + elseif (array_key_exists(CRM_Core_BAO_CustomField::getKeyID($name), $customFields)) { + $responseFields[$cacheKey][$name] = $field; + } + } + elseif (in_array('Primary', explode('-', $name)) || + CRM_Utils_Array::value('location_type_id', $field) + ) { + //get location related contact fields. + $responseFields[$cacheKey][$name] = $field; + } + } + + return $responseFields[$cacheKey]; + } + + /** + * Get all interviewers of surveys. + * + * @return array an array of valid survey response fields. + */ + public static function getInterviewers() { + static $interviewers; + + if (isset($interviewers)) { + return $interviewers; + } + + $whereClause = NULL; + $activityTypes = self::getSurveyActivityType(); + if (!empty($activityTypes)) { + $whereClause = ' WHERE survey.activity_type_id IN ( ' . implode(' , ', array_keys($activityTypes)) . ' )'; + } + + $interviewers = array(); + + $query = " + SELECT contact.id as id, + contact.sort_name as sort_name + FROM civicrm_contact contact +INNER JOIN civicrm_activity_assignment assignment ON ( assignment.assignee_contact_id = contact.id ) +INNER JOIN civicrm_activity activity ON ( activity.id = assignment.activity_id ) +INNER JOIN civicrm_survey survey ON ( activity.source_record_id = survey.id ) + {$whereClause}"; + + $interviewer = CRM_Core_DAO::executeQuery($query); + while ($interviewer->fetch()) { + $interviewers[$interviewer->id] = $interviewer->sort_name; + } + + return $interviewers; + } + + /** + * Check and update the survey respondents. + * + * @return array success message + */ + public function releaseRespondent($params) { + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $reserveStatusId = array_search('Scheduled', $activityStatus); + $surveyActivityTypes = CRM_Campaign_BAO_Survey::getSurveyActivityType(); + $surveyActivityTypesIds = array_keys($surveyActivityTypes); + + //retrieve all survey activities related to reserve action. + $releasedCount = 0; + if ($reserveStatusId && !empty($surveyActivityTypesIds)) { + $query = ' + SELECT activity.id as id, + activity.activity_date_time as activity_date_time, + survey.id as surveyId, + survey.release_frequency as release_frequency + FROM civicrm_activity activity +INNER JOIN civicrm_survey survey ON ( survey.id = activity.source_record_id ) + WHERE activity.is_deleted = 0 + AND activity.status_id = %1 + AND activity.activity_type_id IN ( ' . implode(', ', $surveyActivityTypesIds) . ' )'; + $activity = CRM_Core_DAO::executeQuery($query, array(1 => array($reserveStatusId, 'Positive'))); + $releasedIds = array(); + while ($activity->fetch()) { + if (!$activity->release_frequency) { + continue; + } + $reservedSeconds = CRM_Utils_Date::unixTime($activity->activity_date_time); + $releasedSeconds = $activity->release_frequency * 24 * 3600; + $totalReservedSeconds = $reservedSeconds + $releasedSeconds; + if ($totalReservedSeconds < time()) { + $releasedIds[$activity->id] = $activity->id; + } + } + + //released respondent. + if (!empty($releasedIds)) { + $query = ' +UPDATE civicrm_activity + SET is_deleted = 1 + WHERE id IN ( ' . implode(', ', $releasedIds) . ' )'; + CRM_Core_DAO::executeQuery($query); + $releasedCount = count($releasedIds); + } + } + + $rtnMsg = array( + 'is_error' => 0, + 'messages' => "Number of respondents released = {$releasedCount}", + ); + + return $rtnMsg; + } +} + diff --git a/CRM/Campaign/Config.php b/CRM/Campaign/Config.php new file mode 100644 index 0000000000..b8afc01f6e --- /dev/null +++ b/CRM/Campaign/Config.php @@ -0,0 +1,39 @@ +_stateMachine = new CRM_Campaign_StateMachine_Search($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $config = CRM_Core_Config::singleton(); + $this->addActions(); + } +} + diff --git a/CRM/Campaign/Form/Campaign.php b/CRM/Campaign/Form/Campaign.php new file mode 100644 index 0000000000..8987f43ac4 --- /dev/null +++ b/CRM/Campaign/Form/Campaign.php @@ -0,0 +1,408 @@ +_cdType = CRM_Utils_Array::value('type', $_GET); + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + return CRM_Custom_Form_CustomData::preProcess($this); + } + + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + + $this->assign('context', $this->_context); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this); + $this->_campaignId = CRM_Utils_Request::retrieve('id', 'Positive', $this); + + $title = NULL; + if ($this->_action & CRM_Core_Action::UPDATE) { + $title = ts('Edit Campaign'); + } + if ($this->_action & CRM_Core_Action::DELETE) { + $title = ts('Delete Campaign'); + } + if ($title) { + CRM_Utils_System::setTitle($title); + } + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign')); + $this->assign('action', $this->_action); + + //load the values; + $this->_values = $this->get('values'); + if (!is_array($this->_values)) { + $this->_values = array(); + + // if we are editing + if (isset($this->_campaignId) && $this->_campaignId) { + $params = array('id' => $this->_campaignId); + CRM_Campaign_BAO_Campaign::retrieve($params, $this->_values); + } + + //lets use current object session. + $this->set('values', $this->_values); + } + + // when custom data is included in form. + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + $this->set('type', 'Campaign'); + $this->set('subType', CRM_Utils_Array::value('campaign_type_id', $_POST)); + $this->set('entityId', $this->_campaignId); + + CRM_Custom_Form_CustomData::preProcess($this); + CRM_Custom_Form_CustomData::buildQuickForm($this); + CRM_Custom_Form_CustomData::setDefaultValues($this); + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = $this->_values; + + //load only custom data defaults. + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + if (isset($defaults['start_date'])) { + list($defaults['start_date'], + $defaults['start_date_time'] + ) = CRM_Utils_Date::setDateDefaults($defaults['start_date'], + 'activityDateTime' + ); + } + else { + list($defaults['start_date'], + $defaults['start_date_time'] + ) = CRM_Utils_Date::setDateDefaults(); + } + + if (isset($defaults['end_date'])) { + list($defaults['end_date'], + $defaults['end_date_time'] + ) = CRM_Utils_Date::setDateDefaults($defaults['end_date'], + 'activityDateTime' + ); + } + + if (!isset($defaults['is_active'])) { + $defaults['is_active'] = 1; + } + + if (!$this->_campaignId) { + return $defaults; + } + + $dao = new CRM_Campaign_DAO_CampaignGroup(); + + $campaignGroups = array(); + $dao->campaign_id = $this->_campaignId; + $dao->find(); + + while ($dao->fetch()) { + $campaignGroups[$dao->entity_table][$dao->group_type][] = $dao->entity_id; + } + + if (!empty($campaignGroups)) { + $defaults['includeGroups'] = $campaignGroups['civicrm_group']['Include']; + } + return $defaults; + } + + public function buildQuickForm() { + if ($this->_action & CRM_Core_Action::DELETE) { + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + return; + } + + $this->applyFilter('__ALL__', 'trim'); + + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + //campaign types. + $campaignTypes = CRM_Campaign_PseudoConstant::campaignType(); + + //lets assign custom data type and subtype. + $this->assign('customDataType', 'Campaign'); + $this->assign('entityID', $this->_campaignId); + $this->assign('customDataSubType', CRM_Utils_Array::value('campaign_type_id', $this->_values)); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Campaign'); + + // add comaign title. + $this->add('text', 'title', ts('Title'), $attributes['title'], TRUE); + + // add description + $this->add('textarea', 'description', ts('Description'), $attributes['description']); + + // add campaign start date + $this->addDateTime('start_date', ts('Start Date'), TRUE, array('formatType' => 'activityDateTime')); + + // add campaign end date + $this->addDateTime('end_date', ts('End Date'), FALSE, array('formatType' => 'activityDateTime')); + + // add campaign type + $this->add('select', 'campaign_type_id', ts('Campaign Type'), + array( + '' => ts('- select -')) + $campaignTypes, TRUE, + array('onChange' => "CRM.buildCustomData( 'Campaign', this.value );") + ); + + // add campaign status + $campaignStatus = CRM_Campaign_PseudoConstant::campaignStatus(); + $this->addElement('select', 'status_id', ts('Campaign Status'), + array( + '' => ts('- select -')) + $campaignStatus + ); + + // add External Identifire Element + $this->add('text', 'external_identifier', ts('External Id'), + CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Campaign', 'external_identifier'), FALSE + ); + + // add Campaign Parent Id + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(CRM_Utils_Array::value('parent_id', $this->_values), + $this->_campaignId + ); + if (!empty($campaigns)) { + $this->addElement('select', 'parent_id', ts('Parent Id'), + array( + '' => ts('- select Parent -')) + $campaigns + ); + } + + //get the campaign groups. + $groups = CRM_Core_PseudoConstant::group(); + + $inG = &$this->addElement('advmultiselect', 'includeGroups', + ts('Include Group(s)') . ' ', + $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + $inG->setButtonAttributes('add', array('value' => ts('Add >>'))); + $inG->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $this->addWysiwyg('goal_general', ts('Campaign Goals'), array('rows' => 2, 'cols' => 40)); + $this->add('text', 'goal_revenue', ts('Revenue Goal'), array('size' => 8, 'maxlength' => 12)); + $this->addRule('goal_revenue', ts('Please enter a valid money value (e.g. %1).', + array(1 => CRM_Utils_Money::format('99.99', ' ')) + ), 'money'); + + // is this Campaign active + $this->addElement('checkbox', 'is_active', ts('Is Active?')); + + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'upload', + 'name' => ts('Save and New'), + 'subName' => 'new', + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * This function is used to add the rules (mainly global rules) for form. + * All local rules are added near the element + * + * @return None + * @access public + * @see valid_date + */ + static function formRule($fields, $files, $errors) { + $errors = array(); + + return empty($errors) ? TRUE : $errors; + } + + /** + * Form submission of new/edit campaign is processed. + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + $session = CRM_Core_Session::singleton(); + + $groups = array(); + if (isset($this->_campaignId)) { + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Campaign_BAO_Campaign::del($this->_campaignId); + CRM_Core_Session::setStatus(ts('Campaign has been deleted.'), ts('Record Deleted'), 'success'); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign')); + return; + } + $params['id'] = $this->_campaignId; + } + else { + $params['created_id'] = $session->get('userID'); + $params['created_date'] = date('YmdHis'); + } + // format params + $params['start_date'] = CRM_Utils_Date::processDate($params['start_date'], $params['start_date_time']); + $params['end_date'] = CRM_Utils_Date::processDate($params['end_date'], $params['end_date_time'], TRUE); + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['last_modified_id'] = $session->get('userID'); + $params['last_modified_date'] = date('YmdHis'); + + if (is_array($params['includeGroups'])) { + foreach ($params['includeGroups'] as $key => $id) { + if ($id) { + $groups['include'][] = $id; + } + } + } + $params['groups'] = $groups; + + // delete previous includes/excludes, if campaign already existed + $groupTableName = CRM_Contact_BAO_Group::getTableName(); + $dao = new CRM_Campaign_DAO_CampaignGroup(); + $dao->campaign_id = $this->_campaignId; + $dao->entity_table = $groupTableName; + $dao->find(); + while ($dao->fetch()) { + $dao->delete(); + } + + //process custom data. + $customFields = CRM_Core_BAO_CustomField::getFields('Campaign', FALSE, FALSE, + CRM_Utils_Array::value('campaign_type_id', $params) + ); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_campaignId, + 'Campaign' + ); + + $result = CRM_Campaign_BAO_Campaign::create($params); + + if ($result) { + CRM_Core_Session::setStatus(ts('Campaign %1 has been saved.', array(1 => $result->title)), ts('Saved'), 'success'); + $session->pushUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign')); + } + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->getButtonName('upload', 'new')) { + CRM_Core_Session::setStatus(ts(' You can add another Campaign.'), '', 'info'); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign/add', 'reset=1&action=add')); + } + else { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign')); + } + } +} + + + diff --git a/CRM/Campaign/Form/Gotv.php b/CRM/Campaign/Form/Gotv.php new file mode 100755 index 0000000000..a56d634b69 --- /dev/null +++ b/CRM/Campaign/Form/Gotv.php @@ -0,0 +1,182 @@ +_search = CRM_Utils_Array::value('search', $_GET); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE); + $this->_surveyId = CRM_Utils_Request::retrieve('sid', 'Positive', $this); + $this->_interviewerId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + //does control come from voting tab interface. + $this->_votingTab = $this->get('votingTab'); + $this->_subVotingTab = $this->get('subVotingTab'); + $this->_searchVoterFor = 'gotv'; + if ($this->_votingTab) { + if ($this->_subVotingTab == 'searchANDReserve') { + $this->_searchVoterFor = 'reserve'; + } + elseif ($this->_subVotingTab == 'searchANDInterview') { + $this->_searchVoterFor = 'interview'; + } + } + $this->assign('force', $this->_force); + $this->assign('votingTab', $this->_votingTab); + $this->assign('searchParams', json_encode($this->get('searchParams'))); + $this->assign('buildSelector', $this->_search); + $this->assign('searchVoterFor', $this->_searchVoterFor); + $this->set('searchVoterFor', $this->_searchVoterFor); + + $surveyTitle = NULL; + if ($this->_surveyId) { + $surveyTitle = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $this->_surveyId, 'title'); + } + $this->assign('surveyTitle', $surveyTitle); + + //append breadcrumb to survey dashboard. + if (CRM_Campaign_BAO_Campaign::accessCampaign()) { + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Survey(s)'), 'url' => $url))); + } + + //set the form title. + CRM_Utils_System::setTitle(ts('GOTV (Voter Tracking)')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + if ($this->_search) { + return; + } + + //build common search form. + CRM_Campaign_BAO_Query::buildSearchForm($this); + + //build the array of all search params. + $this->_searchParams = array(); + foreach ($this->_elements as $element) { + $name = $element->_attributes['name']; + if ($name == 'qfKey') { + continue; + } + $this->_searchParams[$name] = $name; + } + $this->set('searchParams', $this->_searchParams); + $this->assign('searchParams', json_encode($this->_searchParams)); + + $defaults = array(); + + if (!$this->_surveyId) { + $this->_surveyId = key(CRM_Campaign_BAO_Survey::getSurveys(TRUE, TRUE)); + } + + if ($this->_force || $this->_votingTab) { + $session = CRM_Core_Session::singleton(); + $userId = $session->get('userID'); + // get interviewer id + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', + CRM_Core_DAO::$_nullObject, FALSE, $userId + ); + + $defaults['survey_interviewer_id'] = $cid; + $defaults['survey_interviewer_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $cid, + 'sort_name', + 'id' + ); + } + if ($this->_surveyId) { + $defaults['campaign_survey_id'] = $this->_surveyId; + } + if (!empty($defaults)) { + $this->setDefaults($defaults); + } + + //validate the required ids. + $this->validateIds(); + } + + function validateIds() { + $errorMessages = array(); + //check for required permissions. + if (!CRM_Core_Permission::check('manage campaign') && + !CRM_Core_Permission::check('administer CiviCampaign') && + !CRM_Core_Permission::check("{$this->_searchVoterFor} campaign contacts") + ) { + $errorMessages[] = ts('You are not authorized to access this page.'); + } + + $surveys = CRM_Campaign_BAO_Survey::getSurveys(); + if (empty($surveys)) { + $errorMessages[] = ts("Oops. It looks like no surveys have been created. Click here to create a new survey.", array(1 => CRM_Utils_System::url('civicrm/survey/add', 'reset=1&action=add'))); + } + + if ($this->_force && !$this->_surveyId) { + + $errorMessages[] = ts('Could not find Survey.'); + + } + + $this->assign('errorMessages', empty($errorMessages) ? FALSE : $errorMessages); + } +} + diff --git a/CRM/Campaign/Form/Petition.php b/CRM/Campaign/Form/Petition.php new file mode 100644 index 0000000000..0c5cd6ef70 --- /dev/null +++ b/CRM/Campaign/Form/Petition.php @@ -0,0 +1,255 @@ +_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::DELETE)) { + $this->_surveyId = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE); + + if ($this->_action & CRM_Core_Action::UPDATE) { + CRM_Utils_System::setTitle(ts('Edit Petition')); + } + else { + CRM_Utils_System::setTitle(ts('Delete Petition')); + } + } + + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=petition'); + $session->pushUserContext($url); + + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Petition Dashboard'), 'url' => $url))); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @param null + * + * @return array array of default values + * @access public + */ + function setDefaultValues() { + $defaults = array(); + + $ufJoinParams = array( + 'entity_table' => 'civicrm_survey', + 'entity_id' => $this->_surveyId, + 'weight' => 2, + ); + + if ($ufGroupId = CRM_Core_BAO_UFJoin::findUFGroupId($ufJoinParams)) { + $defaults['contact_profile_id'] = $ufGroupId; + } + + if (!isset($defaults['is_active'])) { + $defaults['is_active'] = 1; + } + + $defaultSurveys = CRM_Campaign_BAO_Survey::getSurveys(TRUE, TRUE); + if (!isset($defaults['is_default']) && empty($defaultSurveys)) { + $defaults['is_default'] = 1; + } + + return $defaults; + } + + + public function buildQuickForm() { + + if ($this->_action & CRM_Core_Action::DELETE) { + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + return; + } + + + $this->add('text', 'title', ts('Petition Title'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'title'), TRUE); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey'); + + $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name'); + $this->addElement('hidden', 'activity_type_id', $petitionTypeID); + + // script / instructions / description of petition purpose + $this->addWysiwyg('instructions', ts('Introduction'), $attributes['instructions']); + + // Campaign id + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(CRM_Utils_Array::value('campaign_id', $this->_values)); + $this->add('select', 'campaign_id', ts('Campaign'), array('' => ts('- select -')) + $campaigns); + + $customContactProfiles = CRM_Core_BAO_UFGroup::getProfiles(array('Individual')); + // custom group id + $this->add('select', 'contact_profile_id', ts('Contact Profile'), + array( + '' => ts('- select -')) + $customContactProfiles, TRUE + ); + + $customProfiles = CRM_Core_BAO_UFGroup::getProfiles(array('Activity')); + // custom group id + $this->add('select', 'profile_id', ts('Activity Profile'), + array( + '' => ts('- select -')) + $customProfiles + ); + + // thank you title and text (html allowed in text) + $this->add('text', 'thankyou_title', ts('Thank-you Page Title'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'thankyou_title')); + $this->addWysiwyg('thankyou_text', ts('Thank-you Message'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'thankyou_text')); + + // bypass email confirmation? + $this->add('checkbox', 'bypass_confirm', ts('Bypass email confirmation')); + + // is active ? + $this->add('checkbox', 'is_active', ts('Is Active?')); + + // is default ? + $this->add('checkbox', 'is_default', ts('Is Default?')); + + // add buttons + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'next', + 'name' => ts('Save and New'), + 'subName' => 'new', + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + // add a form rule to check default value + $this->addFormRule(array('CRM_Campaign_Form_Survey_Results', 'formRule'), $this); + } + + + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $session = CRM_Core_Session::singleton(); + + $params['last_modified_id'] = $session->get('userID'); + $params['last_modified_date'] = date('YmdHis'); + + if ($this->_surveyId) { + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Campaign_BAO_Survey::del($this->_surveyId); + CRM_Core_Session::setStatus(ts(' Petition has been deleted.'), ts('Record Deleted'), 'success'); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=petition')); + return; + } + + $params['id'] = $this->_surveyId; + } + else { + $params['created_id'] = $session->get('userID'); + $params['created_date'] = date('YmdHis'); + } + + $params['bypass_confirm'] = CRM_Utils_Array::value('bypass_confirm', $params, 0); + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, 0); + $params['is_default'] = CRM_Utils_Array::value('is_default', $params, 0); + + $surveyId = CRM_Campaign_BAO_Survey::create($params); + + + // also update the ProfileModule tables + $ufJoinParams = array( + 'is_active' => 1, + 'module' => 'CiviCampaign', + 'entity_table' => 'civicrm_survey', + 'entity_id' => $surveyId->id, + ); + + // first delete all past entries + if ($this->_surveyId) { + CRM_Core_BAO_UFJoin::deleteAll($ufJoinParams); + } + if (CRM_Utils_Array::value('profile_id', $params)) { + $ufJoinParams['weight'] = 1; + $ufJoinParams['uf_group_id'] = $params['profile_id']; + CRM_Core_BAO_UFJoin::create($ufJoinParams); + } + + if (CRM_Utils_Array::value('contact_profile_id', $params)) { + $ufJoinParams['weight'] = 2; + $ufJoinParams['uf_group_id'] = $params['contact_profile_id']; + CRM_Core_BAO_UFJoin::create($ufJoinParams); + } + + if (!is_a($surveyId, 'CRM_Core_Error')) { + CRM_Core_Session::setStatus(ts('Petition has been saved.'), ts('Saved'), 'success'); + } + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->getButtonName('next', 'new')) { + CRM_Core_Session::setStatus(ts(' You can add another Petition.'), '', 'info'); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/petition/add', 'reset=1&action=add')); + } + else { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=petition')); + } + } +} + + + + diff --git a/CRM/Campaign/Form/Petition/Signature.php b/CRM/Campaign/Form/Petition/Signature.php new file mode 100644 index 0000000000..5bccc6361d --- /dev/null +++ b/CRM/Campaign/Form/Petition/Signature.php @@ -0,0 +1,675 @@ +forceEmailConfirmed['flag'] = FALSE; + $this->forceEmailConfirmed['email'] = ''; + } + + function getContactID() { + $tempID = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + // force to ignore the authenticated user + if ($tempID === '0') { + return $tempID; + } + + //check if this is a checksum authentication + $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this); + if ($userChecksum) { + //check for anonymous user. + $validUser = CRM_Contact_BAO_Contact_Utils::validChecksum($tempID, $userChecksum); + if ($validUser) { + return $tempID; + } + } + + // check if the user is registered and we have a contact ID + $session = CRM_Core_Session::singleton(); + return $session->get('userID'); + } + + public function preProcess() { + $this->bao = new CRM_Campaign_BAO_Petition(); + $this->_mode = self::MODE_CREATE; + + //get the survey id + $this->_surveyId = CRM_Utils_Request::retrieve('sid', 'Positive', $this); + + //some sanity checks + if (!$this->_surveyId) { + CRM_Core_Error::fatal('Petition id is not valid. (it needs a "sid" in the url).'); + return; + } + //check petition is valid and active + $params['id'] = $this->_surveyId; + $this->petition = array(); + CRM_Campaign_BAO_Survey::retrieve($params, $this->petition); + if (empty($this->petition)) { + CRM_Core_Error::fatal('Petition doesn\'t exist.'); + } + if ($this->petition['is_active'] == 0) { + CRM_Core_Error::fatal('Petition is no longer active.'); + } + + //get userID from session + $session = CRM_Core_Session::singleton(); + + //get the contact id for this user if logged in + $this->_contactId = $this->getContactId(); + if (isset($this->_contactId)) { + $this->_loggedIn = TRUE; + } + + // add the custom contact and activity profile fields to the signature form + + $ufJoinParams = array( + 'entity_id' => $this->_surveyId, + 'entity_table' => 'civicrm_survey', + 'module' => 'CiviCampaign', + 'weight' => 2, + ); + + $this->_contactProfileId = CRM_Core_BAO_UFJoin::findUFGroupId($ufJoinParams); + if ($this->_contactProfileId) { + $this->_contactProfileFields = CRM_Core_BAO_UFGroup::getFields($this->_contactProfileId, FALSE, CRM_Core_Action::ADD); + } + if (!isset($this->_contactProfileFields['email-Primary'])) { + CRM_Core_Error::fatal('The contact profile needs to contain the primary email address field'); + } + + + $ufJoinParams['weight'] = 1; + $this->_activityProfileId = CRM_Core_BAO_UFJoin::findUFGroupId($ufJoinParams); + + if ($this->_activityProfileId) { + $this->_activityProfileFields = CRM_Core_BAO_UFGroup::getFields($this->_activityProfileId, FALSE, CRM_Core_Action::ADD); + } + + $this->setDefaultValues(); + CRM_Utils_System::setTitle($this->petition['title']); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $this->_defaults = array(); + if ($this->_contactId) { + CRM_Core_BAO_UFGroup::setProfileDefaults($this->_contactId, $this->_contactProfileFields, $this->_defaults, TRUE); + if ($this->_activityProfileId) { + CRM_Core_BAO_UFGroup::setProfileDefaults($this->_contactId, $this->_activityProfileFields, $this->_defaults, TRUE); + } + } + + //set custom field defaults + + foreach ($this->_contactProfileFields as $name => $field) { + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) { + $htmlType = $field['html_type']; + + if (!isset($this->_defaults[$name])) { + CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, + $name, + $this->_defaults, + $this->_contactId, + $this->_mode + ); + } + } + } + + if ($this->_activityProfileFields) { + foreach ($this->_activityProfileFields as $name => $field) { + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) { + $htmlType = $field['html_type']; + + if (!isset($this->_defaults[$name])) { + CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, + $name, + $this->_defaults, + $this->_contactId, + $this->_mode + ); + } + } + } + } + + $this->setDefaults($this->_defaults); + } + + public function buildQuickForm() { + $this->assign('survey_id', $this->_surveyId); + $this->assign('petitionTitle', $this->petition['title']); + if (isset($_COOKIE['signed_' . $this->_surveyId])) { + if (isset($_COOKIE['confirmed_' . $this->_surveyId])) { + $this->assign('duplicate', "confirmed"); + } + else { + $this->assign('duplicate', "unconfirmed"); + } + return; + } + + $this->applyFilter('__ALL__', 'trim'); + + $this->buildCustom($this->_contactProfileId, 'petitionContactProfile'); + if ($this->_activityProfileId) { + $this->buildCustom($this->_activityProfileId, 'petitionActivityProfile'); + } + // add buttons + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Sign the Petition'), + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * This function is used to add the rules (mainly global rules) for form. + * All local rules are added near the element + * + * @return None + * @access public + * @see valid_date + */ + + static function formRule($fields, $files, $errors) { + $errors = array(); + + return empty($errors) ? TRUE : $errors; + } + + /** + * Form submission of petition signature + * + * @access public + * + * @return None + */ + public function postProcess() { + $tag_name = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME, + 'tag_unconfirmed' + ); + + + if ($tag_name) { + // Check if contact 'email confirmed' tag exists, else create one + // This should be in the petition module initialise code to create a default tag for this + $tag_params['name'] = $tag_name; + $tag_params['version'] = 3; + $tag = civicrm_api('tag', 'get', $tag_params); + if ($tag['count'] == 0) { + //create tag + $tag_params['description'] = $tag_name; + $tag_params['is_reserved'] = 1; + $tag_params['used_for'] = 'civicrm_contact'; + $tag = civicrm_api('tag', 'create', $tag_params); + } + $this->_tagId = $tag['id']; + } + + // export the field values to be used for saving the profile form + $params = $this->controller->exportValues($this->_name); + + $session = CRM_Core_Session::singleton(); + // format params + $params['last_modified_id'] = $session->get('userID'); + $params['last_modified_date'] = date('YmdHis'); + + if ($this->_action & CRM_Core_Action::ADD) { + $params['created_id'] = $session->get('userID'); + $params['created_date'] = date('YmdHis'); + } + + if (isset($this->_surveyId)) { + $params['sid'] = $this->_surveyId; + } + + if (isset($this->_contactId)) { + $params['contactId'] = $this->_contactId; + } + + // if logged in user, skip dedupe + if ($this->_loggedIn) { + $ids[0] = $this->_contactId; + } + else { + // dupeCheck - check if contact record already exists + // code modified from api/v2/Contact.php-function civicrm_contact_check_params() + $params['contact_type'] = $this->_ctype; + //TODO - current dedupe finds soft deleted contacts - adding param is_deleted not working + // ignore soft deleted contacts + //$params['is_deleted'] = 0; + $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); + $dedupeParams['check_permission'] = ''; + + //dupesByParams($params, $ctype, $level = 'Unsupervised', $except = array()) + $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type']); + } + + $petition_params['id'] = $this->_surveyId; + $petition = array(); + CRM_Campaign_BAO_Survey::retrieve($petition_params, $petition); + + switch (count($ids)) { + case 0: + //no matching contacts - create a new contact + // Add a source for this new contact + $params['source'] = ts('Petition Signature') . ' ' . $this->petition['title']; + + if ($this->petition['bypass_confirm']) { + // send thank you email directly, bypassing confirmation + $this->_sendEmailMode = self::EMAIL_THANK; + // Set status for signature activity to completed + $params['statusId'] = 2; + } + else { + $this->_sendEmailMode = self::EMAIL_CONFIRM; + + // Set status for signature activity to scheduled until email is verified + $params['statusId'] = 1; + } + break; + + case 1: + $this->_contactId = $params['contactId'] = $ids[0]; + + // check if user has already signed this petition - redirects to Thank You if true + $this->redirectIfSigned($params); + + if ($this->petition['bypass_confirm']) { + // send thank you email directly, bypassing confirmation + $this->_sendEmailMode = self::EMAIL_THANK; + // Set status for signature activity to completed + $params['statusId'] = 2; + break; + } + + // dedupe matched single contact, check for 'unconfirmed' tag + if ($tag_name) { + $tag = new CRM_Core_DAO_EntityTag(); + $tag->entity_id = $this->_contactId; + $tag->tag_id = $this->_tagId; + + if (!($tag->find())) { + // send thank you email directly, the user is known and validated + $this->_sendEmailMode = self::EMAIL_THANK; + // Set status for signature activity to completed + $params['statusId'] = 2; + } + else { + // send email verification email + $this->_sendEmailMode = self::EMAIL_CONFIRM; + // Set status for signature activity to scheduled until email is verified + $params['statusId'] = 1; + } + } + break; + + default: + // more than 1 matching contact + // for time being, take the first matching contact (not sure that's the best strategy, but better than creating another duplicate) + $this->_contactId = $params['contactId'] = $ids[0]; + + // check if user has already signed this petition - redirects to Thank You if true + $this->redirectIfSigned($params); + + if ($this->petition['bypass_confirm']) { + // send thank you email directly, bypassing confirmation + $this->_sendEmailMode = self::EMAIL_THANK; + // Set status for signature activity to completed + $params['statusId'] = 2; + break; + } + + if ($tag_name) { + $tag = new CRM_Core_DAO_EntityTag(); + $tag->entity_id = $this->_contactId; + $tag->tag_id = $this->_tagId; + + if (!($tag->find())) { + // send thank you email + $this->_sendEmailMode = self::EMAIL_THANK; + // Set status for signature activity to completed + $params['statusId'] = 2; + } + else { + // send email verification email + $this->_sendEmailMode = self::EMAIL_CONFIRM; + // Set status for signature activity to scheduled until email is verified + $params['statusId'] = 1; + } + } + break; + } + + + + $transaction = new CRM_Core_Transaction(); + + $addToGroupID = isset($this->_addToGroupID) ? $this->_addToGroupID : NULL; + $this->_contactId = CRM_Contact_BAO_Contact::createProfileContact($params, $this->_contactProfileFields, + $this->_contactId, $addToGroupID, + $this->_contactProfileId, $this->_ctype, + TRUE + ); + + // get additional custom activity profile field data + // to save with new signature activity record + $surveyInfo = $this->bao->getSurveyInfo($this->_surveyId); + $customActivityFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, + $surveyInfo['activity_type_id'] + ); + $customActivityFields = CRM_Utils_Array::crmArrayMerge($customActivityFields, + CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, + NULL, NULL, TRUE + ) + ); + + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customActivityFields, + NULL, + 'Activity' + ); + + // create the signature activity record + $params['contactId'] = $this->_contactId; + $result = $this->bao->createSignature($params); + + // send thank you or email verification emails + + // if logged in using Facebook connect and email on form matches Fb email, + // no need for email confirmation, send thank you email + if ($this->forceEmailConfirmed['flag'] && + ($this->forceEmailConfirmed['email'] == $params['email-Primary']) + ) { + $this->_sendEmailMode = self::EMAIL_THANK; + } + + switch ($this->_sendEmailMode) { + case self::EMAIL_THANK: + // mark the signature activity as completed and set confirmed cookie + $this->bao->confirmSignature($result->id, $this->_contactId, $this->_surveyId); + break; + + case self::EMAIL_CONFIRM: + // set 'Unconfirmed' tag for this new contact + if ($tag_name) { + unset($tag_params); + $tag_params['contact_id'] = $this->_contactId; + $tag_params['tag_id'] = $this->_tagId; + $tag_value = civicrm_api('entity_tag', 'create', $tag_params); + } + break; + } + + //send email + $params['activityId'] = $result->id; + $params['tagId'] = $this->_tagId; + $this->bao->sendEmail($params, $this->_sendEmailMode); + + $transaction->commit(); + + if ($result) { + // call the hook before we redirect + $this->postProcessHook(); + + // set the template to thank you + $url = + CRM_Utils_System::url( + 'civicrm/petition/thankyou', + 'pid=' . $this->_surveyId . '&id=' . $this->_sendEmailMode . '&reset=1' + ); + CRM_Utils_System::redirect($url); + } + } + + /** + * Function to build the petition profile form + * + * @return None + * @access public + */ + function buildCustom($id, $name, $viewOnly = FALSE) { + + if ($id) { + $session = CRM_Core_Session::singleton(); + $this->assign("petition", $this->petition); + //$contactID = $this->_contactId; + $contactID = NULL; + $this->assign('contact_id', $this->_contactId); + + $fields = NULL; + // TODO: contactID is never set (commented above) + if ($contactID) { + if (CRM_Core_BAO_UFGroup::filterUFGroups($id, $contactID)) { + $fields = CRM_Core_BAO_UFGroup::getFields($id, FALSE, CRM_Core_Action::ADD); + } + } + else { + $fields = CRM_Core_BAO_UFGroup::getFields($id, FALSE, CRM_Core_Action::ADD); + } + + if ($fields) { + /* + // unset any email-* fields since we already collect it, CRM-2888 + foreach ( array_keys( $fields ) as $fieldName ) { + if ( substr( $fieldName, 0, 6 ) == 'email-' ) { + unset( $fields[$fieldName] ); + } + } + */ + + + $this->assign($name, $fields); + + $addCaptcha = FALSE; + foreach ($fields as $key => $field) { + if ($viewOnly && + isset($field['data_type']) && + $field['data_type'] == 'File' || ($viewOnly && $field['name'] == 'image_URL') + ) { + // ignore file upload fields + continue; + } + + + CRM_Core_BAO_UFGroup::buildProfile($this, $field, CRM_Profile_Form::MODE_CREATE, $contactID, TRUE); + $this->_fields[$key] = $field; + if ($field['add_captcha']) { + $addCaptcha = TRUE; + } + } + + if ($addCaptcha && + !$viewOnly + ) { + $captcha = CRM_Utils_ReCAPTCHA::singleton(); + $captcha->add($this); + $this->assign("isCaptcha", TRUE); + } + } + } + } + + function getTemplateFileName() { + if (isset($this->thankyou)) { + return ('CRM/Campaign/Page/Petition/ThankYou.tpl'); + } + else {} + return parent::getTemplateFileName(); + } + + // check if user has already signed this petition + function redirectIfSigned($params) { + $signature = $this->bao->checkSignature($this->_surveyId, $this->_contactId); + //TODO: error case when more than one signature found for this petition and this contact + if (!empty($signature) && (count($signature) == 1)) { + $signature_id = array_keys($signature); + switch ($signature[$signature_id[0]]['status_id']) { + case 1: + //status is scheduled - email is unconfirmed + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/petition/thankyou', 'pid=' . $this->_surveyId . '&id=4&reset=1')); + break; + + case 2: + //status is completed + $this->bao->sendEmail($params, 1); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/petition/thankyou', 'pid=' . $this->_surveyId . '&id=5&reset=1')); + break; + } + } + } +} + + + diff --git a/CRM/Campaign/Form/Search.php b/CRM/Campaign/Form/Search.php new file mode 100755 index 0000000000..b4f00d61a1 --- /dev/null +++ b/CRM/Campaign/Form/Search.php @@ -0,0 +1,591 @@ +_done = FALSE; + $this->_defaults = array(); + + //set the button name. + $this->_searchButtonName = $this->getButtonName('refresh'); + $this->_printButtonName = $this->getButtonName('next', 'print'); + $this->_actionButtonName = $this->getButtonName('next', 'action'); + + //we allow the controller to set force/reset externally, + //useful when we are being driven by the wizard framework + $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'search'); + $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean', CRM_Core_DAO::$_nullObject); + + //operation for state machine. + $this->_operation = CRM_Utils_Request::retrieve('op', 'String', $this, FALSE, 'reserve'); + //validate operation. + if (!in_array($this->_operation, array( + 'reserve', 'release', 'interview'))) { + $this->_operation = 'reserve'; + $this->set('op', $this->_operation); + } + $this->set('searchVoterFor', $this->_operation); + $this->assign('searchVoterFor', $this->_operation); + $this->assign('isFormSubmitted', $this->isSubmitted()); + + //do check permissions. + if (!CRM_Core_Permission::check('administer CiviCampaign') && + !CRM_Core_Permission::check('manage campaign') && + !CRM_Core_Permission::check("{$this->_operation} campaign contacts") + ) { + CRM_Utils_System::permissionDenied(); + CRM_Utils_System::civiExit(); + } + + $this->assign("context", $this->_context); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + + if (empty($_POST)) { + $this->_formValues = $this->get('formValues'); + } + else { + $this->_formValues = $this->controller->exportValues($this->_name); + } + + if ($this->_force) { + $this->postProcess(); + $this->set('force', 0); + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + //get the voter clause. + $voterClause = $this->voterClause(); + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $selector = new CRM_Campaign_Selector_Search($this->_queryParams, + $this->_action, + $voterClause, + $this->_single, + $this->_limit, + $this->_context + ); + $prefix = NULL; + if ($this->_context == 'user') { + $prefix = $this->_prefix; + } + + $this->assign("{$prefix}limit", $this->_limit); + $this->assign("{$prefix}single", $this->_single); + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::TRANSFER, + $prefix + ); + + $controller->setEmbedded(TRUE); + $controller->moveFromSessionToTemplate(); + + //append breadcrumb to survey dashboard. + if (CRM_Campaign_BAO_Campaign::accessCampaign()) { + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Survey(s)'), 'url' => $url))); + } + + //set the form title. + CRM_Utils_System::setTitle(ts('Find Respondents To %1', array(1 => ucfirst($this->_operation)))); + } + + function setDefaultValues() { + //load the default survey for all actions. + if (empty($this->_defaults)) { + $defaultSurveyId = key(CRM_Campaign_BAO_Survey::getSurveys(TRUE, TRUE)); + if ($defaultSurveyId) { + $this->_defaults['campaign_survey_id'] = $defaultSurveyId; + } + } + + return $this->_defaults; + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + //build the search form. + CRM_Campaign_BAO_Query::buildSearchForm($this); + + /* + * add form checkboxes for each row. This is needed out here to conform to QF protocol + * of all elements being declared in builQuickForm + */ + + + $rows = $this->get('rows'); + if (is_array($rows)) { + if (!$this->_single) { + $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('onclick' => "toggleTaskAction( true ); return toggleCheckboxVals('mark_x_',this);")); + foreach ($rows as $row) { + $this->addElement('checkbox', $row['checkbox'], + NULL, NULL, + array('onclick' => "toggleTaskAction( true ); return checkSelectedBox('" . $row['checkbox'] . "');") + ); + } + } + + $total = $cancel = 0; + + $permission = CRM_Core_Permission::getPermission(); + $allTasks = CRM_Campaign_Task::permissionedTaskTitles($permission); + + //hack to serve right page to state machine. + $taskMapping = array( + 'interview' => 1, + 'reserve' => 2, + 'release' => 3, + ); + + $currentTaskValue = CRM_Utils_Array::value($this->_operation, $taskMapping); + $taskValue = array($currentTaskValue => $allTasks[$currentTaskValue]); + if ($this->_operation == 'interview' && + CRM_Utils_Array::value('campaign_survey_id', $this->_formValues) + ) { + $activityTypes = CRM_Core_PseudoConstant::activityType(FALSE, TRUE, FALSE, 'label', TRUE); + + $surveyTypeId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', + $this->_formValues['campaign_survey_id'], + 'activity_type_id' + ); + $taskValue = array( + $currentTaskValue => ts('Record %1 Responses', + array(1 => $activityTypes[$surveyTypeId]) + )); + } + + $this->add('select', 'task', ts('Actions:') . ' ', $taskValue); + $this->setDefaults(array('task' => $currentTaskValue)); + + $this->add('submit', $this->_actionButtonName, ts('Go'), + array( + 'class' => 'form-submit', + 'id' => 'Go', + ) + ); + + $this->add('submit', $this->_printButtonName, ts('Print'), + array( + 'class' => 'form-submit', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 1);", + ) + ); + + // need to perform tasks on all or selected items ? using radio_ts(task selection) for it + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_sel', array('checked' => 'checked')); + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_all', array('onclick' => $this->getName() . ".toggleSelect.checked = false; toggleCheckboxVals('mark_x_',this); toggleTaskAction( true );")); + } + + // add buttons + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * The post processing of the form gets done here. + * + * Key things done during post processing are + * - check for reset or next request. if present, skip post procesing. + * - now check if user requested running a saved search, if so, then + * the form values associated with the saved search are used for searching. + * - if user has done a submit with new values the regular post submissing is + * done. + * The processing consists of using a Selector / Controller framework for getting the + * search results. + * + * @param + * + * @return void + * @access public + */ + function postProcess() { + if ($this->_done) { + return; + } + + $this->_done = TRUE; + + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + } + + $this->fixFormValues(); + + //format params as per task. + $this->formatParams(); + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $this->set('formValues', $this->_formValues); + $this->set('queryParams', $this->_queryParams); + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->_actionButtonName || $buttonName == $this->_printButtonName) { + // check actionName and if next, then do not repeat a search, since we are going to the next page + + // hack, make sure we reset the task values + $stateMachine = $this->controller->getStateMachine(); + $formName = $stateMachine->getTaskFormName(); + + $this->controller->resetPage($formName); + return; + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + //get the voter clause. + $voterClause = $this->voterClause(); + + $selector = new CRM_Campaign_Selector_Search($this->_queryParams, + $this->_action, + $voterClause, + $this->_single, + $this->_limit, + $this->_context + ); + $selector->setKey($this->controller->_key); + + $prefix = NULL; + if ($this->_context == 'basic' || + $this->_context == 'user' + ) { + $prefix = $this->_prefix; + } + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::SESSION, + $prefix + ); + $controller->setEmbedded(TRUE); + $query = $selector->getQuery(); + if ($this->_context == 'user') { + $query->setSkipPermission(TRUE); + } + $controller->run(); + } + + function formatParams() { + $interviewerId = CRM_Utils_Array::value('survey_interviewer_id', $this->_formValues); + if (!$interviewerId) { + $session = CRM_Core_Session::singleton(); + $this->_formValues['survey_interviewer_id'] = $interviewerId = $session->get('userID'); + } + $this->set('interviewerId', $interviewerId); + if (!CRM_Utils_Array::value('survey_interviewer_name', $this->_formValues)) { + $this->_formValues['survey_interviewer_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $interviewerId, + 'sort_name', + 'id' + ); + } + + //format multi-select group and contact types. + foreach (array( + 'group', 'contact_type') as $param) { + if ($this->_force) { + continue; + } + $paramValue = CRM_Utils_Array::value($param, $this->_formValues); + if ($paramValue && is_array($paramValue)) { + unset($this->_formValues[$param]); + foreach ($paramValue as $key => $value) { + $this->_formValues[$param][$value] = 1; + } + } + } + + //apply filter of survey contact type for search. + $contactType = CRM_Campaign_BAO_Survey::getSurveyContactType(CRM_Utils_Array::value('campaign_survey_id', $this->_formValues)); + if ($contactType && in_array($this->_operation, array( + 'reserve', 'interview'))) { + $this->_formValues['contact_type'][$contactType] = 1; + } + + if ($this->_operation == 'reserve') { + if (CRM_Utils_Array::value('campaign_survey_id', $this->_formValues)) { + $campaignId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', + $this->_formValues['campaign_survey_id'], + 'campaign_id' + ); + + //allow voter search in sub-part of given constituents, + //but make sure in case user does not select any group. + //get all associated campaign groups in where filter, CRM-7406 + $groups = CRM_Utils_Array::value('group', $this->_formValues); + if ($campaignId && CRM_Utils_System::isNull($groups)) { + $campGroups = CRM_Campaign_BAO_Campaign::getCampaignGroups($campaignId); + foreach ($campGroups as $id => $title) $this->_formValues['group'][$id] = 1; + } + + //carry servey id w/ this. + $this->set('surveyId', $this->_formValues['campaign_survey_id']); + unset($this->_formValues['campaign_survey_id']); + } + unset($this->_formValues['survey_interviewer_id']); + } + elseif ($this->_operation == 'interview' || + $this->_operation == 'release' + ) { + //to conduct interview / release activity status should be scheduled. + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + if ($scheduledStatusId = array_search('Scheduled', $activityStatus)) { + $this->_formValues['survey_status_id'] = $scheduledStatusId; + } + } + + //pass voter search operation. + $this->_formValues['campaign_search_voter_for'] = $this->_operation; + } + + function fixFormValues() { + // if this search has been forced + // then see if there are any get values, and if so over-ride the post values + // note that this means that GET over-rides POST :) + + //since we have qfKey, no need to manipulate set defaults. + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', CRM_Core_DAO::$_nullObject); + + if (!$this->_force || CRM_Utils_Rule::qfKey($qfKey)) { + return; + } + + // get survey id + $surveyId = CRM_Utils_Request::retrieve('sid', 'Positive', CRM_Core_DAO::$_nullObject); + + if ($surveyId) { + $surveyId = CRM_Utils_Type::escape($surveyId, 'Integer'); + } + else { + // use default survey id + $surveyId = key(CRM_Campaign_BAO_Survey::getSurveys(TRUE, TRUE)); + } + if (!$surveyId) { + CRM_Core_Error::fatal('Could not find valid Survey Id.'); + } + $this->_formValues['campaign_survey_id'] = $this->_formValues['campaign_survey_id'] = $surveyId; + + $session = CRM_Core_Session::singleton(); + $userId = $session->get('userID'); + + // get interviewer id + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', + CRM_Core_DAO::$_nullObject, FALSE, $userId + ); + //to force other contact as interviewer, user should be admin. + if ($cid != $userId && + !CRM_Core_Permission::check('administer CiviCampaign') + ) { + CRM_Utils_System::permissionDenied(); + CRM_Utils_System::civiExit(); + } + $this->_formValues['survey_interviewer_id'] = $cid; + $this->_formValues['survey_interviewer_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $cid, + 'sort_name', + 'id' + ); + //get all in defaults. + $this->_defaults = $this->_formValues; + $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this); + } + + function voterClause() { + $params = array('campaign_search_voter_for' => $this->_operation); + + $clauseFields = array( + 'surveyId' => 'campaign_survey_id', + 'interviewerId' => 'survey_interviewer_id', + ); + + foreach ($clauseFields as $param => $key) { + $params[$key] = CRM_Utils_Array::value($key, $this->_formValues); + if (!$params[$key]) { + $params[$key] = $this->get($param); + } + } + + //build the clause. + $voterClause = CRM_Campaign_BAO_Query::voterClause($params); + + return $voterClause; + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Find Respondents'); + } +} + diff --git a/CRM/Campaign/Form/Search/Campaign.php b/CRM/Campaign/Form/Search/Campaign.php new file mode 100755 index 0000000000..c063c50ea2 --- /dev/null +++ b/CRM/Campaign/Form/Search/Campaign.php @@ -0,0 +1,129 @@ +_search = CRM_Utils_Array::value('search', $_GET); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE, FALSE); + $this->_searchTab = CRM_Utils_Request::retrieve('type', 'String', $this, FALSE, 'campaign'); + + //when we do load tab, lets load the default objects. + $this->assign('force', ($this->_force || $this->_searchTab) ? TRUE : FALSE); + $this->assign('searchParams', json_encode($this->get('searchParams'))); + $this->assign('buildSelector', $this->_search); + $this->assign('searchFor', $this->_searchTab); + $this->assign('campaignTypes', json_encode($this->get('campaignTypes'))); + $this->assign('campaignStatus', json_encode($this->get('campaignStatus'))); + $this->assign('suppressForm', TRUE); + + //set the form title. + CRM_Utils_System::setTitle(ts('Find Campaigns')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + if ($this->_search) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Campaign'); + $this->add('text', 'campaign_title', ts('Title'), $attributes['title']); + + //campaign description. + $this->add('text', 'description', ts('Description'), $attributes['description']); + + //campaign start date. + $this->addDate('start_date', ts('From'), FALSE, array('formatType' => 'searchDate')); + + //campaign end date. + $this->addDate('end_date', ts('To'), FALSE, array('formatType' => 'searchDate')); + + //campaign type. + $campaignTypes = CRM_Campaign_PseudoConstant::campaignType(); + $this->add('select', 'campaign_type_id', ts('Campaign Type'), + array( + '' => ts('- select -')) + $campaignTypes + ); + + $this->set('campaignTypes', $campaignTypes); + $this->assign('campaignTypes', json_encode($campaignTypes)); + + //campaign status + $campaignStatus = CRM_Campaign_PseudoConstant::campaignStatus(); + $this->addElement('select', 'status_id', ts('Campaign Status'), + array( + '' => ts('- select -')) + $campaignStatus + ); + $this->set('campaignStatus', $campaignStatus); + $this->assign('campaignStatus', json_encode($campaignStatus)); + + //build the array of all search params. + $this->_searchParams = array(); + foreach ($this->_elements as $element) { + $name = $element->_attributes['name']; + $label = $element->_label; + if ($name == 'qfKey') { + continue; + } + $this->_searchParams[$name] = ($label) ? $label : $name; + } + $this->set('searchParams', $this->_searchParams); + $this->assign('searchParams', json_encode($this->_searchParams)); + } +} + diff --git a/CRM/Campaign/Form/Search/Petition.php b/CRM/Campaign/Form/Search/Petition.php new file mode 100755 index 0000000000..267938f5bb --- /dev/null +++ b/CRM/Campaign/Form/Search/Petition.php @@ -0,0 +1,106 @@ +_search = CRM_Utils_Array::value('search', $_GET); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE, FALSE); + $this->_searchTab = CRM_Utils_Request::retrieve('type', 'String', $this, FALSE, 'petition'); + + //when we do load tab, lets load the default objects. + $this->assign('force', ($this->_force || $this->_searchTab) ? TRUE : FALSE); + $this->assign('searchParams', json_encode($this->get('searchParams'))); + $this->assign('buildSelector', $this->_search); + $this->assign('searchFor', $this->_searchTab); + $this->assign('petitionCampaigns', json_encode($this->get('petitionCampaigns'))); + $this->assign('suppressForm', TRUE); + + //set the form title. + CRM_Utils_System::setTitle(ts('Find Petition')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + if ($this->_search) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey'); + $this->add('text', 'petition_title', ts('Title'), $attributes['title']); + + //campaigns + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + $this->add('select', 'petition_campaign_id', ts('Campaign'), array('' => ts('- select -')) + $campaigns); + $this->set('petitionCampaigns', $campaigns); + $this->assign('petitionCampaigns', json_encode($campaigns)); + + //build the array of all search params. + $this->_searchParams = array(); + foreach ($this->_elements as $element) { + $name = $element->_attributes['name']; + $label = $element->_label; + if ($name == 'qfKey') { + continue; + } + $this->_searchParams[$name] = ($label) ? $label : $name; + } + $this->set('searchParams', $this->_searchParams); + $this->assign('searchParams', json_encode($this->_searchParams)); + } +} + diff --git a/CRM/Campaign/Form/Search/Survey.php b/CRM/Campaign/Form/Search/Survey.php new file mode 100755 index 0000000000..e59a783580 --- /dev/null +++ b/CRM/Campaign/Form/Search/Survey.php @@ -0,0 +1,116 @@ +_search = CRM_Utils_Array::value('search', $_GET); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE, FALSE); + $this->_searchTab = CRM_Utils_Request::retrieve('type', 'String', $this, FALSE, 'survey'); + + //when we do load tab, lets load the default objects. + $this->assign('force', ($this->_force || $this->_searchTab) ? TRUE : FALSE); + $this->assign('searchParams', json_encode($this->get('searchParams'))); + $this->assign('buildSelector', $this->_search); + $this->assign('searchFor', $this->_searchTab); + $this->assign('surveyTypes', json_encode($this->get('surveyTypes'))); + $this->assign('surveyCampaigns', json_encode($this->get('surveyCampaigns'))); + $this->assign('suppressForm', TRUE); + + //set the form title. + CRM_Utils_System::setTitle(ts('Find Survey')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + if ($this->_search) { + return; + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey'); + $this->add('text', 'survey_title', ts('Title'), $attributes['title']); + + //activity Type id + $surveyTypes = CRM_Campaign_BAO_Survey::getSurveyActivityType(); + $this->add('select', 'activity_type_id', + ts('Activity Type'), array( + '' => ts('- select -')) + $surveyTypes + ); + $this->set('surveyTypes', $surveyTypes); + $this->assign('surveyTypes', json_encode($surveyTypes)); + + //campaigns + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + $this->add('select', 'survey_campaign_id', ts('Campaign'), array('' => ts('- select -')) + $campaigns); + $this->set('surveyCampaigns', $campaigns); + $this->assign('surveyCampaigns', json_encode($campaigns)); + + //build the array of all search params. + $this->_searchParams = array(); + foreach ($this->_elements as $element) { + $name = $element->_attributes['name']; + $label = $element->_label; + if ($name == 'qfKey') { + continue; + } + $this->_searchParams[$name] = ($label) ? $label : $name; + } + $this->set('searchParams', $this->_searchParams); + $this->assign('searchParams', json_encode($this->_searchParams)); + } +} + diff --git a/CRM/Campaign/Form/Survey.php b/CRM/Campaign/Form/Survey.php new file mode 100644 index 0000000000..500aca6efb --- /dev/null +++ b/CRM/Campaign/Form/Survey.php @@ -0,0 +1,186 @@ +_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add', 'REQUEST'); + $this->_surveyId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE); + + if ($this->_surveyId) { + $this->_single = TRUE; + + $params = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($params, $surveyInfo); + $this->_surveyTitle = $surveyInfo['title']; + $this->assign('surveyTitle', $this->_surveyTitle); + CRM_Utils_System::setTitle(ts('Configure Survey - %1', array(1 => $this->_surveyTitle))); + } + + $this->assign('action', $this->_action); + $this->assign('surveyId', $this->_surveyId); + + // CRM-11480, CRM-11682 + // Preload libraries required by the "Questions" tab + CRM_UF_Page_ProfileEditor::registerProfileScripts(); + CRM_UF_Page_ProfileEditor::registerSchemas(array('IndividualModel', 'ActivityModel')); + + CRM_Campaign_Form_Survey_TabHeader::build($this); + } + + /** + * Function to actually build the form + * + * @param null + * + * @return void + * @access public + */ + public function buildQuickForm() { + $session = CRM_Core_Session::singleton(); + if ($this->_surveyId) { + $buttons = array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'upload', + 'name' => ts('Save and Done'), + 'subName' => 'done', + ), + array( + 'type' => 'upload', + 'name' => ts('Save and Next'), + 'spacing' => '                 ', + 'subName' => 'next', + ), + ); + } + else { + $buttons = array( + array( + 'type' => 'upload', + 'name' => ts('Continue >>'), + 'spacing' => '                 ', + 'isDefault' => TRUE, + ), + ); + } + $buttons[] = + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ); + $this->addButtons($buttons); + + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + $session->replaceUserContext($url); + } + + function endPostProcess() { + // make submit buttons keep the current working tab opened. + if ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD)) { + $tabTitle = $className = CRM_Utils_String::getClassName($this->_name); + if ($tabTitle == 'Main') { + $tabTitle = 'Main settings'; + } + $subPage = strtolower($className); + CRM_Core_Session::setStatus(ts("'%1' have been saved.", array(1 => $tabTitle)), ts('Saved'), 'success'); + + $this->postProcessHook(); + + if ($this->_action & CRM_Core_Action::ADD) + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/survey/configure/questions", + "action=update&reset=1&id={$this->_surveyId}")); + + if ($this->controller->getButtonName('submit') == "_qf_{$className}_upload_done") { + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey')); + } + else if ($this->controller->getButtonName('submit') == "_qf_{$className}_upload_next") { + $subPage = CRM_Campaign_Form_Survey_TabHeader::getNextTab($this); + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/survey/configure/{$subPage}", + "action=update&reset=1&id={$this->_surveyId}")); + } + else { + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/survey/configure/{$subPage}", + "action=update&reset=1&id={$this->_surveyId}")); + } + } + } + + function getTemplateFileName() { + if ($this->controller->getPrint() == CRM_Core_Smarty::PRINT_NOFORM || + $this->getVar('_surveyId') <= 0 ) { + return parent::getTemplateFileName(); + } + else { + // hack lets suppress the form rendering for now + self::$_template->assign('isForm', FALSE); + return 'CRM/Campaign/Form/Survey/Tab.tpl'; + } + } +} + diff --git a/CRM/Campaign/Form/Survey/Delete.php b/CRM/Campaign/Form/Survey/Delete.php new file mode 100644 index 0000000000..df34285e06 --- /dev/null +++ b/CRM/Campaign/Form/Survey/Delete.php @@ -0,0 +1,112 @@ +_surveyId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE); + $params = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($params, $surveyInfo); + $this->_surveyTitle = $surveyInfo['title']; + $this->assign('surveyTitle', $this->_surveyTitle); + CRM_Utils_System::setTitle(ts('Delete Survey') . ' - ' . $this->_surveyTitle); + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Process the form when submitted + * + * @return void + * @access public + */ + public function postProcess() { + if ($this->_surveyId) { + CRM_Campaign_BAO_Survey::del($this->_surveyId); + CRM_Core_Session::setStatus('', ts("'%1' survey has been deleted.", array(1 => $this->_surveyTitle)), 'success'); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey')); + } else { + CRM_Core_Error::fatal(ts('Delete action is missing expected survey ID.')); + } + } +} + diff --git a/CRM/Campaign/Form/Survey/Main.php b/CRM/Campaign/Form/Survey/Main.php new file mode 100644 index 0000000000..b6b4c00ace --- /dev/null +++ b/CRM/Campaign/Form/Survey/Main.php @@ -0,0 +1,246 @@ +_context = CRM_Utils_Request::retrieve('context', 'String', $this); + + $this->assign('context', $this->_context); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this); + + if ($this->_action & CRM_Core_Action::UPDATE) { + CRM_Utils_System::setTitle(ts('Configure Survey') . ' - ' . $this->_surveyTitle); + } + + $this->_cdType = CRM_Utils_Array::value('type', $_GET); + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + return CRM_Custom_Form_CustomData::preProcess($this); + } + + // when custom data is included in this page + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + CRM_Custom_Form_CustomData::preProcess($this); + CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + if ($this->_name != 'Petition') { + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Survey Dashboard'), 'url' => $url))); + } + + $this->_values = $this->get('values'); + if (!is_array($this->_values)) { + $this->_values = array(); + if ($this->_surveyId) { + $params = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($params, $this->_values); + } + $this->set('values', $this->_values); + } + + $this->assign('action', $this->_action); + $this->assign('surveyId', $this->_surveyId); + // for custom data + $this->assign('entityID', $this->_surveyId); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @param null + * + * @return array array of default values + * @access public + */ + function setDefaultValues() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + $defaults = $this->_values; + + if ($this->_surveyId) { + + if (CRM_Utils_Array::value('result_id', $defaults) && + CRM_Utils_Array::value('recontact_interval', $defaults) + ) { + + $resultId = $defaults['result_id']; + $recontactInterval = unserialize($defaults['recontact_interval']); + + unset($defaults['recontact_interval']); + $defaults['option_group_id'] = $resultId; + } + } + + if (!isset($defaults['is_active'])) { + $defaults['is_active'] = 1; + } + + $defaultSurveys = CRM_Campaign_BAO_Survey::getSurveys(TRUE, TRUE); + if (!isset($defaults['is_default']) && empty($defaultSurveys)) { + $defaults['is_default'] = 1; + } + + return $defaults; + } + + /** + * Function to actually build the form + * + * @param null + * + * @return void + * @access public + */ + public function buildQuickForm() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + $this->add('text', 'title', ts('Title'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'title'), TRUE); + + $surveyActivityTypes = CRM_Campaign_BAO_Survey::getSurveyActivityType(); + // Activity Type id + $this->add('select', 'activity_type_id', ts('Activity Type'), array('' => ts('- select -')) + $surveyActivityTypes, TRUE); + + // Campaign id + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(CRM_Utils_Array::value('campaign_id', $this->_values)); + $this->add('select', 'campaign_id', ts('Campaign'), array('' => ts('- select -')) + $campaigns); + + // script / instructions + $this->addWysiwyg('instructions', ts('Instructions for interviewers'), array('rows' => 5, 'cols' => 40)); + + // release frequency + $this->add('text', 'release_frequency', ts('Release frequency'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'release_frequency')); + + $this->addRule('release_frequency', ts('Release Frequency interval should be a positive number.'), 'positiveInteger'); + + // max reserved contacts at a time + $this->add('text', 'default_number_of_contacts', ts('Maximum reserved at one time'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'default_number_of_contacts')); + $this->addRule('default_number_of_contacts', ts('Maximum reserved at one time should be a positive number'), 'positiveInteger'); + + // total reserved per interviewer + $this->add('text', 'max_number_of_contacts', ts('Total reserved per interviewer'), CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'max_number_of_contacts')); + $this->addRule('max_number_of_contacts', ts('Total reserved contacts should be a positive number'), 'positiveInteger'); + + // is active ? + $this->add('checkbox', 'is_active', ts('Active?')); + + // is default ? + $this->add('checkbox', 'is_default', ts('Default?')); + + parent::buildQuickForm(); + } + + /** + * Process the form + * + * @param null + * + * @return void + * @access public + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $session = CRM_Core_Session::singleton(); + + $params['last_modified_id'] = $session->get('userID'); + $params['last_modified_date'] = date('YmdHis'); + + if ($this->_surveyId) { + $params['id'] = $this->_surveyId; + } + else { + $params['created_id'] = $session->get('userID'); + $params['created_date'] = date('YmdHis'); + } + + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, 0); + $params['is_default'] = CRM_Utils_Array::value('is_default', $params, 0); + + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_surveyId, + 'Survey' + ); + $survey = CRM_Campaign_BAO_Survey::create($params); + $this->_surveyId = $survey->id; + + if (CRM_Utils_Array::value('result_id', $this->_values)) { + $query = "SELECT COUNT(*) FROM civicrm_survey WHERE result_id = %1"; + $countSurvey = (int)CRM_Core_DAO::singleValueQuery($query, + array( + 1 => array($this->_values['result_id'], + 'Positive', + )) + ); + // delete option group if no any survey is using it. + if (!$countSurvey) { + CRM_Core_BAO_OptionGroup::del($this->_values['result_id']); + } + } + + parent::endPostProcess(); + } +} + diff --git a/CRM/Campaign/Form/Survey/Questions.php b/CRM/Campaign/Form/Survey/Questions.php new file mode 100644 index 0000000000..6cf45f29fb --- /dev/null +++ b/CRM/Campaign/Form/Survey/Questions.php @@ -0,0 +1,148 @@ + 'civicrm_survey', + 'module' => 'CiviCampaign', + 'entity_id' => $this->_surveyId, + ); + + list($defaults['contact_profile_id'], + $second) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + $defaults['activity_profile_id'] = $second ? array_shift($second) : ''; + + return $defaults; + } + + /** + * Function to actually build the form + * + * @param null + * + * @return void + * @access public + */ + public function buildQuickForm() { + $subTypeId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $this->_surveyId, 'activity_type_id'); + if (!CRM_Core_BAO_CustomGroup::autoCreateByActivityType($subTypeId)) { + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE, FALSE); // everything + // FIXME: Displays weird "/\ Array" message; doesn't work with tabs + CRM_Core_Session::setStatus(ts('There are no custom data sets for activity type "%1". To create one, click here.', array( + 1 => $activityTypes[$subTypeId], + 2 => CRM_Utils_System::url('civicrm/admin/custom/group', 'action=add&reset=1'), + 3 => '_blank', + ))); + } + + $allowCoreTypes = CRM_Campaign_BAO_Survey::surveyProfileTypes(); + $allowSubTypes = array( + 'ActivityType' => array($subTypeId), + ); + $entities = array( + array('entity_name' => 'contact_1', 'entity_type' => 'IndividualModel'), + array('entity_name' => 'activity_1', 'entity_type' => 'ActivityModel', 'entity_sub_type' => $subTypeId), + ); + $this->addProfileSelector('contact_profile_id', ts('Contact Info'), $allowCoreTypes, $allowSubTypes, $entities); + $this->addProfileSelector('activity_profile_id', ts('Questions'), $allowCoreTypes, $allowSubTypes, $entities); + // Note: Because this is in a tab, we also preload the schema via CRM_Campaign_Form_Survey::preProcess + + parent::buildQuickForm(); + } + + + /** + * Process the form + * + * @param null + * + * @return void + * @access public + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + // also update the ProfileModule tables + $ufJoinParams = array( + 'is_active' => 1, + 'module' => 'CiviCampaign', + 'entity_table' => 'civicrm_survey', + 'entity_id' => $this->_surveyId, + ); + + // first delete all past entries + CRM_Core_BAO_UFJoin::deleteAll($ufJoinParams); + + $uf = array(); + $wt = 2; + if (!empty($params['contact_profile_id'])) { + $uf[1] = $params['contact_profile_id']; + $wt = 1; + } + if (!empty($params['activity_profile_id'])) { + $uf[2] = $params['activity_profile_id']; + } + + $uf = array_values($uf); + if (!empty($uf)) { + foreach ($uf as $weight => $ufGroupId) { + $ufJoinParams['weight'] = $weight + $wt; + $ufJoinParams['uf_group_id'] = $ufGroupId; + CRM_Core_BAO_UFJoin::create($ufJoinParams); + unset($ufJoinParams['id']); + } + } + + parent::endPostProcess(); + } +} diff --git a/CRM/Campaign/Form/Survey/Results.php b/CRM/Campaign/Form/Survey/Results.php new file mode 100644 index 0000000000..7c2ceba0f5 --- /dev/null +++ b/CRM/Campaign/Form/Survey/Results.php @@ -0,0 +1,482 @@ +_values = $this->get('values'); + if (!is_array($this->_values)) { + $this->_values = array(); + if ($this->_surveyId) { + $params = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($params, $this->_values); + } + $this->set('values', $this->_values); + } + + $query = "SELECT MAX(id) as id, title FROM civicrm_report_instance WHERE name = %1"; + $params = array( 1 => array("survey_{$this->_surveyId}",'String') ); + $result = CRM_Core_DAO::executeQuery($query, $params); + if ( $result->fetch() ) { + $this->_reportId = $result->id; + $this->_reportTitle = $result->title; + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @param null + * + * @return array array of default values + * @access public + */ + function setDefaultValues() { + $defaults = $this->_values; + + // set defaults for weight. + for ($i = 1; $i <= self::NUM_OPTION; $i++) { + $defaults["option_weight[{$i}]"] = $i; + } + + $defaults['create_report'] = 1; + if ($this->_reportId) { + $defaults['report_title'] = $this->_reportTitle; + } + return $defaults; + } + + /** + * Function to actually build the form + * + * @param null + * + * @return void + * @access public + */ + public function buildQuickForm() { + $optionGroups = CRM_Campaign_BAO_Survey::getResultSets(); + + if (empty($optionGroups)) { + $optionTypes = array('1' => ts('Create new result set')); + } + else { + $optionTypes = array('1' => ts('Create a new result set'), + '2' => ts('Use existing result set'), + ); + $this->add('select', + 'option_group_id', + ts('Select Result Set'), + array( + '' => ts('- select -')) + $optionGroups, FALSE, + array('onChange' => 'loadOptionGroup( )') + ); + } + + $element = &$this->addRadio('option_type', + ts('Survey Responses'), + $optionTypes, + array( + 'onclick' => "showOptionSelect();"), '
    ', TRUE + ); + + if (empty($optionGroups) || !CRM_Utils_Array::value('result_id', $this->_values)) { + $this->setdefaults(array('option_type' => 1)); + } + elseif (CRM_Utils_Array::value('result_id', $this->_values)) { + $this->setdefaults(array( + 'option_type' => 2, + 'option_group_id' => $this->_values['result_id'], + )); + } + + // form fields of Custom Option rows + $defaultOption = array(); + $_showHide = new CRM_Core_ShowHideBlocks('', ''); + + $optionAttributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue'); + $optionAttributes['label']['size'] = $optionAttributes['value']['size'] = 25; + + for ($i = 1; $i <= self::NUM_OPTION; $i++) { + //the show hide blocks + $showBlocks = 'optionField_' . $i; + if ($i > 2) { + $_showHide->addHide($showBlocks); + if ($i == self::NUM_OPTION) { + $_showHide->addHide('additionalOption'); + } + } + else { + $_showHide->addShow($showBlocks); + } + + $this->add('text', 'option_label[' . $i . ']', ts('Label'), + $optionAttributes['label'] + ); + + // value + $this->add('text', 'option_value[' . $i . ']', ts('Value'), + $optionAttributes['value'] + ); + + // weight + $this->add('text', "option_weight[$i]", ts('Order'), + $optionAttributes['weight'] + ); + + $this->add('text', 'option_interval[' . $i . ']', ts('Recontact Interval'), + CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey', 'release_frequency') + ); + + $defaultOption[$i] = $this->createElement('radio', NULL, NULL, NULL, $i); + } + + //default option selection + $this->addGroup($defaultOption, 'default_option'); + + $_showHide->addToTemplate(); + + $this->addElement('checkbox', 'create_report', ts('Create Report')); + $this->addElement('text', 'report_title', ts('Report Title')); + + if( $this->_reportId){ + $this->freeze('create_report'); + $this->freeze('report_title'); + } + + $this->addFormRule(array('CRM_Campaign_Form_Survey_Results', 'formRule'), $this); + + parent::buildQuickForm(); + } + + /** + * global validation rules for the form + * + */ + static function formRule($fields, $files, $form) { + $errors = array(); + + if (CRM_Utils_Array::value('option_label', $fields) && + CRM_Utils_Array::value('option_value', $fields) && + (count(array_filter($fields['option_label'])) == 0) && + (count(array_filter($fields['option_value'])) == 0) + ) { + $errors['option_label[1]'] = ts('Enter at least one result option.'); + return $errors; + } + elseif (!CRM_Utils_Array::value('option_label', $fields) && + !CRM_Utils_Array::value('option_value', $fields) + ) { + return $errors; + } + + if ($fields['option_type'] == 2 && + !CRM_Utils_Array::value('option_group_id', $fields) + ) { + $errors['option_group_id'] = ts("Please select a Survey Result Set."); + return $errors; + } + + $_flagOption = $_rowError = 0; + $_showHide = new CRM_Core_ShowHideBlocks('', ''); + + //capture duplicate Custom option values + if (!empty($fields['option_value'])) { + $countValue = count($fields['option_value']); + $uniqueCount = count(array_unique($fields['option_value'])); + + if ($countValue > $uniqueCount) { + $start = 1; + while ($start < self::NUM_OPTION) { + $nextIndex = $start + 1; + + while ($nextIndex <= self::NUM_OPTION) { + if ($fields['option_value'][$start] == $fields['option_value'][$nextIndex] && + !empty($fields['option_value'][$nextIndex]) + ) { + + $errors['option_value[' . $start . ']'] = ts('Duplicate Option values'); + $errors['option_value[' . $nextIndex . ']'] = ts('Duplicate Option values'); + $_flagOption = 1; + } + $nextIndex++; + } + $start++; + } + } + } + + //capture duplicate Custom Option label + if (!empty($fields['option_label'])) { + $countValue = count($fields['option_label']); + $uniqueCount = count(array_unique($fields['option_label'])); + + if ($countValue > $uniqueCount) { + $start = 1; + while ($start < self::NUM_OPTION) { + $nextIndex = $start + 1; + + while ($nextIndex <= self::NUM_OPTION) { + if ($fields['option_label'][$start] == $fields['option_label'][$nextIndex] && !empty($fields['option_label'][$nextIndex])) { + $errors['option_label[' . $start . ']'] = ts('Duplicate Option label'); + $errors['option_label[' . $nextIndex . ']'] = ts('Duplicate Option label'); + $_flagOption = 1; + } + $nextIndex++; + } + $start++; + } + } + } + + for ($i = 1; $i <= self::NUM_OPTION; $i++) { + if (!$fields['option_label'][$i]) { + if ($fields['option_value'][$i]) { + $errors['option_label[' . $i . ']'] = ts('Option label cannot be empty'); + $_flagOption = 1; + } + else { + $_emptyRow = 1; + } + } + elseif (!strlen(trim($fields['option_value'][$i]))) { + if (!$fields['option_value'][$i]) { + $errors['option_value[' . $i . ']'] = ts('Option value cannot be empty'); + $_flagOption = 1; + } + } + + if (CRM_Utils_Array::value($i, $fields['option_interval']) && !CRM_Utils_Rule::integer($fields['option_interval'][$i])) { + $_flagOption = 1; + $errors['option_interval[' . $i . ']'] = ts('Please enter a valid integer.'); + } + + $showBlocks = 'optionField_' . $i; + if ($_flagOption) { + $_showHide->addShow($showBlocks); + $_rowError = 1; + } + + if (!empty($_emptyRow)) { + $_showHide->addHide($showBlocks); + } + else { + $_showHide->addShow($showBlocks); + } + + if ($i == self::NUM_OPTION) { + $hideBlock = 'additionalOption'; + $_showHide->addHide($hideBlock); + } + + $_flagOption = $_emptyRow = 0; + } + $_showHide->addToTemplate(); + + return empty($errors) ? TRUE : $errors; + } + + /** + * Process the form + * + * @param null + * + * @return void + * @access public + */ + public function postProcess() { + // store the submitted values in an array + $status = ''; + $params = $this->controller->exportValues($this->_name); + $params['id'] = $this->_surveyId; + + $updateResultSet = FALSE; + $resultSetOptGrpId = NULL; + if ((CRM_Utils_Array::value('option_type', $params) == 2) && + CRM_Utils_Array::value('option_group_id', $params) + ) { + $updateResultSet = TRUE; + $resultSetOptGrpId = $params['option_group_id']; + } + + $recontactInterval = array(); + if ($updateResultSet) { + $optionValue = new CRM_Core_DAO_OptionValue(); + $optionValue->option_group_id = $resultSetOptGrpId; + $optionValue->delete(); + + $params['result_id'] = $resultSetOptGrpId; + } + else { + $opGroupName = 'civicrm_survey_' . rand(10, 1000) . '_' . date('YmdHis'); + + $optionGroup = new CRM_Core_DAO_OptionGroup(); + $optionGroup->name = $opGroupName; + $optionGroup->title = $this->_values['title'] . ' Result Set'; + $optionGroup->is_active = 1; + $optionGroup->save(); + + $params['result_id'] = $optionGroup->id; + } + + foreach ($params['option_value'] as $k => $v) { + if (strlen(trim($v))) { + $optionValue = new CRM_Core_DAO_OptionValue(); + $optionValue->option_group_id = $params['result_id']; + $optionValue->label = $params['option_label'][$k]; + $optionValue->name = CRM_Utils_String::titleToVar($params['option_label'][$k]); + $optionValue->value = trim($v); + $optionValue->weight = $params['option_weight'][$k]; + $optionValue->is_active = 1; + + if (CRM_Utils_Array::value('default_option', $params) && + $params['default_option'] == $k + ) { + $optionValue->is_default = 1; + } + + $optionValue->save(); + + // using is_numeric since 0 is a valid value for option_interval + if ( is_numeric($params['option_interval'][$k])) { + $recontactInterval[$optionValue->label] = $params['option_interval'][$k]; + } + } + } + + $params['recontact_interval'] = serialize($recontactInterval); + $survey = CRM_Campaign_BAO_Survey::create($params); + + // create report if required. + if ( !$this->_reportId && $survey->id && $params['create_report'] ) { + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $activityStatus = array_flip($activityStatus); + $this->_params = + array( 'name' => "survey_{$survey->id}", + 'title' => $params['report_title'] ? $params['report_title'] : $this->_values['title'], + 'status_id_op' => 'eq', + 'status_id_value' => $activityStatus['Scheduled'], // reserved status + 'survey_id_value' => array($survey->id), + 'description' => ts('Detailed report for canvassing, phone-banking, walk lists or other surveys.'), + ); + //Default value of order by + $this->_params['order_bys'] = + array( + 1 => + array( + 'column' => 'sort_name', + 'order' => 'ASC' + ), + ); + // for WalkList or default + $displayFields = array('id', 'sort_name', 'result', 'street_number','street_name','street_unit','survey_response'); + if ( CRM_Core_OptionGroup::getValue('activity_type','WalkList') == $this->_values['activity_type_id'] ) { + $this->_params['order_bys'] = + array( + 1 => + array( + 'column' => 'street_name', + 'order' => 'ASC' + ), + 2 => + array( + 'column' => 'street_number_odd_even', + 'order' => 'ASC' + ), + 3 => + array( + 'column' => 'street_number', + 'order' => 'ASC' + ), + 4 => + array( + 'column' => 'sort_name', + 'order' => 'ASC' + ), + ); + } + elseif ( CRM_Core_OptionGroup::getValue('activity_type','PhoneBank') == $this->_values['activity_type_id'] ) { + array_push($displayFields, 'phone'); + } + elseif ((CRM_Core_OptionGroup::getValue('activity_type','Survey') == $this->_values['activity_type_id']) || + (CRM_Core_OptionGroup::getValue('activity_type','Canvass') == $this->_values['activity_type_id']) ) { + array_push($displayFields, 'phone','city','state_province_id','postal_code','email'); + } + foreach($displayFields as $key){ + $this->_params['fields'][$key] = 1; + } + $this->_createNew = TRUE; + $this->_id = CRM_Report_Utils_Report::getInstanceIDForValue('survey/detail'); + CRM_Report_Form_Instance::postProcess($this, FALSE); + + $query = "SELECT MAX(id) FROM civicrm_report_instance WHERE name = %1"; + $reportID = CRM_Core_DAO::singleValueQuery($query, array(1 => array("survey_{$survey->id}",'String'))); + if ($reportID) { + $url = CRM_Utils_System::url("civicrm/report/instance/{$reportID}",'reset=1'); + $status = ts("A Survey Detail Report %2 has been created.", + array(1 => $url, 2 => $this->_params['title'])); + } + } + + if ($status) { + // reset status as we don't want status set by Instance::postProcess + $session = CRM_Core_Session::singleton(); + $session->getStatus(TRUE); + // set new status + CRM_Core_Session::setStatus($status, ts('Saved'), 'success'); + } + + parent::endPostProcess(); + } +} diff --git a/CRM/Campaign/Form/Survey/TabHeader.php b/CRM/Campaign/Form/Survey/TabHeader.php new file mode 100644 index 0000000000..84e17d5dbe --- /dev/null +++ b/CRM/Campaign/Form/Survey/TabHeader.php @@ -0,0 +1,156 @@ +get('tabHeader'); + if (!$tabs || !CRM_Utils_Array::value('reset', $_GET)) { + $tabs = self::process($form); + $form->set('tabHeader', $tabs); + } + $form->assign_by_ref('tabHeader', $tabs); + $selectedTab = self::getCurrentTab($tabs); + $form->assign_by_ref('selectedTab', $selectedTab); + return $tabs; + } + + static function process(&$form) { + if ($form->getVar('_surveyId') <= 0) { + return NULL; + } + + $tabs = array( + 'main' => array('title' => ts('Main Information'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'questions' => array('title' => ts('Questions'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'results' => array('title' => ts('Results'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + ); + + $surveyID = $form->getVar('_surveyId'); + $class = $form->getVar('_name'); + $class = CRM_Utils_String::getClassName($class); + $class = strtolower($class); + + if (array_key_exists($class, $tabs)) { + $tabs[$class]['current'] = TRUE; + $qfKey = $form->get('qfKey'); + if ($qfKey) { + $tabs[$class]['qfKey'] = "&qfKey={$qfKey}"; + } + } + + if ($surveyID) { + $reset = CRM_Utils_Array::value('reset', $_GET) ? 'reset=1&' : ''; + + foreach ($tabs as $key => $value) { + if (!isset($tabs[$key]['qfKey'])) { + $tabs[$key]['qfKey'] = NULL; + } + + $tabs[$key]['link'] = CRM_Utils_System::url("civicrm/survey/configure/{$key}", + "{$reset}action=update&snippet=5&id={$surveyID}{$tabs[$key]['qfKey']}" + ); + $tabs[$key]['active'] = $tabs[$key]['valid'] = TRUE; + } + } + return $tabs; + } + + static function reset(&$form) { + $tabs = self::process($form); + $form->set('tabHeader', $tabs); + } + + static function getCurrentTab($tabs) { + static $current = FALSE; + + if ($current) { + return $current; + } + + if (is_array($tabs)) { + foreach ($tabs as $subPage => $pageVal) { + if ($pageVal['current'] === TRUE) { + $current = $subPage; + break; + } + } + } + + $current = $current ? $current : 'main'; + return $current; + } + + static function getNextTab(&$form) { + static $next = FALSE; + if ($next) + return $next; + + $tabs = $form->get('tabHeader'); + if (is_array($tabs)) { + $current = false; + foreach ($tabs as $subPage => $pageVal) { + if ($current) { + $next = $subPage; + break; + } + if ($pageVal['current'] === TRUE) { + $current = $subPage; + } + } + } + + $next = $next ? $next : 'main'; + return $next; + } +} diff --git a/CRM/Campaign/Form/SurveyType.php b/CRM/Campaign/Form/SurveyType.php new file mode 100644 index 0000000000..88171f0bec --- /dev/null +++ b/CRM/Campaign/Form/SurveyType.php @@ -0,0 +1,185 @@ +_action = CRM_Utils_Request::retrieve('action', 'String', $this); + + if ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::DELETE)) { + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE); + $this->assign('id', $this->_id); + } + $this->assign('action', $this->_action); + $this->assign('id', $this->_id); + + $this->_BAOName = 'CRM_Core_BAO_OptionValue'; + $this->_gName = 'activity_type'; + $this->_gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_gName, 'id', 'name'); + + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/admin/campaign/surveyType', 'reset=1'); + $session->pushUserContext($url); + + if ($this->_id && in_array($this->_gName, CRM_Core_OptionGroup::$_domainIDGroups)) { + $domainID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'domain_id', 'id'); + if (CRM_Core_Config::domainID() != $domainID) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + } + } + + /** + * This function sets the default values for the form. + * the default values are retrieved from the database. + * + * @param null + * + * @return array array of default values + * @access public + */ + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + + if (!isset($defaults['weight']) || !$defaults['weight']) { + $fieldValues = array('option_group_id' => $this->_gid); + $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', $fieldValues); + } + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', 'label', ts('Title'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'label'), TRUE); + + $this->addWysiwyg('description', + ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'description') + ); + + + $this->add('checkbox', 'is_active', ts('Enabled?')); + + if ($this->_action == CRM_Core_Action::UPDATE && + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_id, 'is_reserved') + ) { + $this->freeze(array('label', 'is_active')); + } + $this->add('text', 'weight', ts('Weight'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'weight'), TRUE); + + $this->assign('id', $this->_id); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + + if ($this->_action & CRM_Core_Action::DELETE) { + $fieldValues = array('option_group_id' => $this->_gid); + $wt = CRM_Utils_Weight::delWeight('CRM_Core_DAO_OptionValue', $this->_id, $fieldValues); + + if (CRM_Core_BAO_OptionValue::del($this->_id)) { + CRM_Core_Session::setStatus(ts('Selected Survey type has been deleted.'), ts('Record Deleted'), 'success'); + } + } + else { + $params = $ids = array(); + $params = $this->exportValues(); + + // set db value of filter in params if filter is non editable + if ($this->_id && !array_key_exists('filter', $params)) { + $params['filter'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'filter', 'id'); + } + + $groupParams = array('name' => ($this->_gName)); + $params['component_id'] = CRM_Core_Component::getComponentID('CiviCampaign'); + $optionValue = CRM_Core_OptionValue::addOptionValue($params, $groupParams, $this->_action, $this->_id); + + CRM_Core_Session::setStatus(ts('The Survey type \'%1\' has been saved.', array(1 => $optionValue->label)), ts('Saved'), 'success'); + } + } +} + diff --git a/CRM/Campaign/Form/Task.php b/CRM/Campaign/Form/Task.php new file mode 100755 index 0000000000..9920ae57dd --- /dev/null +++ b/CRM/Campaign/Form/Task.php @@ -0,0 +1,159 @@ +controller->exportValues('Search'); + + $this->_task = $values['task']; + $campaignTasks = CRM_Campaign_Task::tasks(); + $taskName = CRM_Utils_Array::value($this->_task, $campaignTasks); + $this->assign('taskName', $taskName); + + $ids = array(); + if ($values['radio_ts'] == 'ts_sel') { + foreach ($values as $name => $value) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + } + } + } + else { + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); + $cacheKey = "civicrm search {$qfKey}"; + $allCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey, "getall"); + $ids = array_keys($allCids[$cacheKey]); + $this->assign('totalSelectedVoters', count($ids)); + } + + if (!empty($ids)) { + $this->_componentClause = 'contact_a.id IN ( ' . implode(',', $ids) . ' ) '; + $this->assign('totalSelectedVoters', count($ids)); + } + $this->_voterIds = $this->_contactIds = $this->_componentIds = $ids; + + $this->assign('totalSelectedContacts', count($this->_contactIds)); + + //set the context for redirection for any task actions + $session = CRM_Core_Session::singleton(); + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= '&qfKey=' . $qfKey; + } + $session->replaceUserContext(CRM_Utils_System::url('civicrm/survey/search', $urlParams)); + } + + /** + * Given the voter id, compute the contact id + * since its used for things like send email + */ + public function setContactIDs() { + $this->_contactIds = $this->_voterIds; + } + + /** + * simple shell that derived classes can call to add buttons to + * the form with a customized title for the main Submit + * + * @param string $title title of the main button + * @param string $type button type for the form after processing + * + * @return void + * @access public + */ + function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) { + $this->addButtons(array( + array( + 'type' => $nextType, + 'name' => $title, + 'isDefault' => TRUE, + ), + array( + 'type' => $backType, + 'name' => ts('Cancel'), + ), + ) + ); + } +} + diff --git a/CRM/Campaign/Form/Task/Interview.php b/CRM/Campaign/Form/Task/Interview.php new file mode 100755 index 0000000000..a1b214fb3b --- /dev/null +++ b/CRM/Campaign/Form/Task/Interview.php @@ -0,0 +1,651 @@ +_votingTab = $this->get('votingTab'); + $this->_reserveToInterview = $this->get('reserveToInterview'); + if ($this->_reserveToInterview || $this->_votingTab) { + //user came from voting tab / reserve form. + foreach (array( + 'surveyId', 'contactIds', 'interviewerId') as $fld) { + $this->{"_$fld"} = $this->get($fld); + } + //get the target voter ids. + if ($this->_votingTab) { + $this->getVoterIds(); + } + } + else { + parent::preProcess(); + //get the survey id from user submitted values. + $this->_surveyId = CRM_Utils_Array::value('campaign_survey_id', $this->get('formValues')); + $this->_interviewerId = CRM_Utils_Array::value('survey_interviewer_id', $this->get('formValues')); + } + + if ( $this->_surveyId ) { + $params = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($params, $this->_surveyDetails); + } + + $orderClause = false; + $buttonName = $this->controller->getButtonName(); + if ( $buttonName == '_qf_Interview_submit_orderBy' && + CRM_Utils_Array::value('order_bys', $_POST) ) { + $orderByParams = CRM_Utils_Array::value('order_bys', $_POST); + } + elseif ( CRM_Core_OptionGroup::getValue('activity_type','WalkList') == $this->_surveyDetails['activity_type_id'] ) { + $orderByParams = + array( + 1 => + array( + 'column' => 'civicrm_address.street_name', + 'order' => 'ASC', + ), + 2 => + array( + 'column' => 'civicrm_address.street_number%2', + 'order' => 'ASC', + ), + 3 => + array( + 'column' => 'civicrm_address.street_number', + 'order' => 'ASC', + ), + 4 => + array( + 'column' => 'contact_a.sort_name', + 'order' => 'ASC', + ), + ); + } + + $orderBy = array(); + if ( !empty($orderByParams) ) { + foreach ( $orderByParams as $key => $val ) { + if (CRM_Utils_Array::value('column', $val)) { + $orderBy[] = "{$val['column']} {$val['order']}"; + } + } + if ( !empty($orderBy) ) { + $orderClause = "ORDER BY " . implode(', ', $orderBy); + } + } + + $this->_contactIds = array_unique($this->_contactIds); + if (!empty($this->_contactIds) && $orderClause) { + $clause = 'contact_a.id IN ( ' . implode(',', $this->_contactIds) . ' ) '; + $sql = " +SELECT contact_a.id +FROM civicrm_contact contact_a +LEFT JOIN civicrm_address ON contact_a.id = civicrm_address.contact_id +WHERE {$clause} +{$orderClause}"; + + $this->_contactIds = array(); + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $this->_contactIds[] = $dao->id; + } + } + + + //get the contact read only fields to display. + $readOnlyFields = array_merge(array( + 'contact_type' => '', + 'sort_name' => ts('Name'), + )); + + //get the read only field data. + $returnProperties = array_fill_keys(array_keys($readOnlyFields), 1); + $returnProperties['contact_sub_type'] = TRUE; + + //validate all voters for required activity. + //get the survey activities for given voters. + $this->_surveyActivityIds = CRM_Campaign_BAO_Survey::voterActivityDetails($this->_surveyId, + $this->_contactIds, + $this->_interviewerId + ); + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $scheduledStatusId = array_search('Scheduled', $activityStatus); + + $activityIds = array(); + foreach ($this->_contactIds as $key => $voterId) { + $actVals = CRM_Utils_Array::value($voterId, $this->_surveyActivityIds); + $statusId = CRM_Utils_Array::value('status_id', $actVals); + $activityId = CRM_Utils_Array::value('activity_id', $actVals); + if ($activityId && + $statusId && + $scheduledStatusId == $statusId + ) { + $activityIds["activity_id_{$voterId}"] = $activityId; + } + else { + unset($this->_contactIds[$key]); + } + } + + //retrieve the contact details. + $voterDetails = CRM_Campaign_BAO_Survey::voterDetails($this->_contactIds, $returnProperties); + + $this->_allowAjaxReleaseButton = FALSE; + if ($this->_votingTab && + (CRM_Core_Permission::check('manage campaign') || + CRM_Core_Permission::check('administer CiviCampaign') || + CRM_Core_Permission::check('release campaign contacts') + ) + ) { + $this->_allowAjaxReleaseButton = TRUE; + } + + //validate voter ids across profile. + $this->filterVoterIds(); + $this->assign('votingTab', $this->_votingTab); + $this->assign('componentIds', $this->_contactIds); + $this->assign('componentIdsJson', json_encode($this->_contactIds)); + $this->assign('voterDetails', $voterDetails); + $this->assign('readOnlyFields', $readOnlyFields); + $this->assign('interviewerId', $this->_interviewerId); + $this->assign('surveyActivityIds', json_encode($activityIds)); + $this->assign('allowAjaxReleaseButton', $this->_allowAjaxReleaseButton); + + //get the survey values. + $this->_surveyValues = $this->get('surveyValues'); + if (!is_array($this->_surveyValues)) { + $this->_surveyValues = array(); + if ($this->_surveyId) { + $surveyParams = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($surveyParams, $this->_surveyValues); + } + $this->set('surveyValues', $this->_surveyValues); + } + $this->assign('surveyValues', $this->_surveyValues); + + $result = CRM_Campaign_BAO_Survey::getReportID($this->_surveyId); + $this->assign("instanceId",$result); + + //get the survey result options. + $this->_resultOptions = $this->get('resultOptions'); + if (!is_array($this->_resultOptions)) { + $this->_resultOptions = array(); + if ($resultOptionId = CRM_Utils_Array::value('result_id', $this->_surveyValues)) { + $this->_resultOptions = CRM_Core_OptionGroup::valuesByID($resultOptionId); + } + $this->set('resultOptions', $this->_resultOptions); + } + + //validate the required ids. + $this->validateIds(); + + //append breadcrumb to survey dashboard. + if (CRM_Campaign_BAO_Campaign::accessCampaign()) { + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Survey(s)'), 'url' => $url))); + } + + //set the title. + $activityTypes = CRM_Core_PseudoConstant::activityType(FALSE, TRUE, FALSE, 'label', TRUE); + $this->_surveyTypeId = CRM_Utils_Array::value('activity_type_id', $this->_surveyValues); + CRM_Utils_System::setTitle(ts('Record %1 Responses', array(1 => $activityTypes[$this->_surveyTypeId]))); + } + + function validateIds() { + $required = array('surveyId' => ts('Could not find Survey.'), + 'interviewerId' => ts('Could not find Interviewer.'), + 'contactIds' => ts('No respondents are currently reserved for you to interview.'), + 'resultOptions' => ts('Oops. It looks like there is no response option configured.'), + ); + + $errorMessages = array(); + foreach ($required as $fld => $msg) { + if (empty($this->{"_$fld"})) { + if (!$this->_votingTab) { + CRM_Core_Error::statusBounce($msg); + break; + } + $errorMessages[] = $msg; + } + } + + $this->assign('errorMessages', empty($errorMessages) ? FALSE : $errorMessages); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->assign('surveyTypeId', $this->_surveyTypeId); + + $options = + array('' => ' - none - ', + 'civicrm_address.street_name' => 'Street Name', + 'civicrm_address.street_number%2' => 'Odd / Even Street Number', + 'civicrm_address.street_number' => 'Street Number', + 'contact_a.sort_name' => 'Respondent Name', + ); + for ($i = 1; $i < count($options); $i++) { + $this->addElement('select', "order_bys[{$i}][column]", ts('Order by Column'), $options); + $this->addElement('select', "order_bys[{$i}][order]", ts('Order by Order'), array('ASC' => 'Ascending', 'DESC' => 'Descending')); + } + + //pickup the uf fields. + $this->_surveyFields = CRM_Campaign_BAO_Survey::getSurveyResponseFields($this->_surveyId, + $this->_surveyTypeId + ); + + foreach ($this->_contactIds as $contactId) { + //build the profile fields. + foreach ($this->_surveyFields as $name => $field) { + if ($field){ + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contactId); + } + } + + //build the result field. + if (!empty($this->_resultOptions)) { + $this->add('select', "field[$contactId][result]", ts('Result'), + array( + '' => ts('- select -')) + + array_combine($this->_resultOptions, $this->_resultOptions) + ); + } + + $this->add('text', "field[{$contactId}][note]", ts('Note')); + + //need to keep control for release/reserve. + if ($this->_allowAjaxReleaseButton) { + $this->addElement('hidden', + "field[{$contactId}][is_release_or_reserve]", 0, + array('id' => "field_{$contactId}_is_release_or_reserve") + ); + } + } + $this->assign('surveyFields', empty($this->_surveyFields) ? FALSE : $this->_surveyFields); + + //no need to get qf buttons. + if ($this->_votingTab) { + return; + } + + $buttons = array( + array('type' => 'cancel', + 'name' => ts('Done'), + 'subName' => 'interview', + 'isDefault' => TRUE, + )); + + $buttons[] = array( + 'type' => 'submit', + 'name' => ts('Order By >>'), + 'subName' => 'orderBy', + ); + + $manageCampaign = CRM_Core_Permission::check('manage campaign'); + $adminCampaign = CRM_Core_Permission::check('administer CiviCampaign'); + if ($manageCampaign || + $adminCampaign || + CRM_Core_Permission::check('release campaign contacts') + ) { + $buttons[] = array( + 'type' => 'next', + 'name' => ts('Release Respondents >>'), + 'subName' => 'interviewToRelease', + ); + } + if ($manageCampaign || + $adminCampaign || + CRM_Core_Permission::check('reserve campaign contacts') + ) { + $buttons[] = array( + 'type' => 'done', + 'name' => ts('Reserve More Respondents >>'), + 'subName' => 'interviewToReserve', + ); + } + + $this->addButtons($buttons); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + //load default data for only contact fields. + $contactFields = $defaults = array(); + foreach ($this->_surveyFields as $name => $field) { + $acceptable_types = CRM_Contact_BAO_ContactType::basicTypes(); + $acceptable_types[] = 'Contact'; + if (in_array($field['field_type'], $acceptable_types)) { + $contactFields[$name] = $field; + } + } + if (!empty($contactFields)) { + foreach ($this->_contactIds as $contactId) { + CRM_Core_BAO_UFGroup::setProfileDefaults($contactId, $contactFields, $defaults, FALSE); + } + } + + if ( CRM_Core_OptionGroup::getValue('activity_type','WalkList') == $this->_surveyDetails['activity_type_id'] ) { + $defaults['order_bys'] = + array( + 1 => + array( + 'column' => 'civicrm_address.street_name', + 'order' => 'ASC', + ), + 2 => + array( + 'column' => 'civicrm_address.street_number%2', + 'order' => 'ASC', + ), + 3 => + array( + 'column' => 'civicrm_address.street_number', + 'order' => 'ASC', + ), + 4 => + array( + 'column' => 'contact_a.sort_name', + 'order' => 'ASC', + ), + ); + } + else { + $defaults['order_bys'] = + array( + 1 => + array( + 'column' => 'contact_a.sort_name', + 'order' => 'ASC', + ), + ); + } + return $defaults; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $buttonName = $this->controller->getButtonName(); + if ($buttonName == '_qf_Interview_done_interviewToReserve') { + //hey its time to stop cycle. + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/survey/search', 'reset=1&op=reserve')); + } + elseif ($buttonName == '_qf_Interview_next_interviewToRelease') { + //get ready to jump to release form. + foreach (array( + 'surveyId', 'contactIds', 'interviewerId') as $fld) { + $this->controller->set($fld, $this->{"_$fld"}); + } + $this->controller->set('interviewToRelease', TRUE); + } + + // vote is done through ajax + return; + } + + static function registerInterview($params) { + $activityId = CRM_Utils_Array::value('activity_id', $params); + $surveyTypeId = CRM_Utils_Array::value('activity_type_id', $params); + if (!is_array($params) || !$surveyTypeId || !$activityId) { + return FALSE; + } + + static $surveyFields; + if (!is_array($surveyFields)) { + $surveyFields = CRM_Core_BAO_CustomField::getFields('Activity', + FALSE, + FALSE, + $surveyTypeId, + NULL, + FALSE, + TRUE + ); + } + + static $statusId; + if (!$statusId) { + $statusId = array_search('Completed', CRM_Core_PseudoConstant::activityStatus('name')); + } + + //format custom fields. + $customParams = CRM_Core_BAO_CustomField::postProcess($params, + $surveyFields, + $activityId, + 'Activity' + ); + + CRM_Core_BAO_CustomValueTable::store($customParams, 'civicrm_activity', $activityId); + + //process contact data. + $contactParams = $fields = array(); + + $contactFieldTypes = array_merge(array('Contact'), CRM_Contact_BAO_ContactType::basicTypes()); + $responseFields = CRM_Campaign_BAO_Survey::getSurveyResponseFields($params['survey_id']); + if (!empty($responseFields)) { + foreach ($params as $key => $value) { + if (array_key_exists($key, $responseFields)) { + if (in_array($responseFields[$key]['field_type'], $contactFieldTypes)) { + $fields[$key] = $responseFields[$key]; + $contactParams[$key] = $value; + if (isset($params["{$key}_id"])) { + $contactParams["{$key}_id"] = $params["{$key}_id"]; + } + } + } + } + } + + $contactId = CRM_Utils_Array::value('voter_id', $params); + if ($contactId && !empty($contactParams)) { + CRM_Contact_BAO_Contact::createProfileContact($contactParams, $fields, $contactId); + } + + //update activity record. + $activity = new CRM_Activity_DAO_Activity(); + $activity->id = $activityId; + + $activity->selectAdd(); + $activity->selectAdd('activity_date_time, status_id, result, subject'); + $activity->find(TRUE); + $activity->activity_date_time = date('YmdHis'); + $activity->status_id = $statusId; + + if (CRM_Utils_Array::value('details', $params)) { + $activity->details = $params['details']; + } + if ($result = CRM_Utils_Array::value('result', $params)) { + $activity->result = $result; + } + if (CRM_Utils_Array::value('activity_engagement_level', $params)) { + $activity->engagement_level = $params['activity_engagement_level']; + } + + $subject = ''; + $surveyTitle = CRM_Utils_Array::value('surveyTitle', $params); + if ($surveyTitle) { + $subject = ts('%1', array(1 => $surveyTitle)); + $subject .= ' - '; + } + $subject .= ts('Respondent Interview'); + + $activity->subject = $subject; + $activity->save(); + //really this should use Activity BAO& not be here but refactoring will have to be later + //actually the whole ajax call could be done as an api ajax call & post hook would be sorted + CRM_Utils_Hook::post('edit', 'Activity', $activity->id, $activity); + $activity->free(); + + return $activityId; + } + + function getVoterIds() { + if (!$this->_interviewerId) { + $session = CRM_Core_Session::singleton(); + $this->_interviewerId = $session->get('userID'); + } + if (!$this->_surveyId) { + // use default survey id + $dao = new CRM_Campaign_DAO_Survey(); + $dao->is_active = 1; + $dao->is_default = 1; + $dao->find(TRUE); + $this->_surveyId = $dao->id; + } + + $this->_contactIds = $this->get('contactIds'); + if (!is_array($this->_contactIds)) { + //get the survey activities. + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $statusIds = array(); + if ($statusId = array_search('Scheduled', $activityStatus)) { + $statusIds[] = $statusId; + } + $surveyActivities = CRM_Campaign_BAO_Survey::getSurveyVoterInfo($this->_surveyId, + $this->_interviewerId, + $statusIds + ); + $this->_contactIds = array(); + foreach ($surveyActivities as $val) $this->_contactIds[$val['voter_id']] = $val['voter_id']; + $this->set('contactIds', $this->_contactIds); + } + } + + function filterVoterIds() { + //do the cleanup later on. + if (!is_array($this->_contactIds)) { + return; + } + + $profileId = CRM_Campaign_BAO_Survey::getSurveyProfileId($this->_surveyId); + if ($profileId) { + $profileType = CRM_Core_BAO_UFField::getProfileType($profileId); + if (in_array($profileType, CRM_Contact_BAO_ContactType::basicTypes())) { + $voterIdCount = count($this->_contactIds); + + //create temporary table to store voter ids. + $tempTableName = CRM_Core_DAO::createTempTableName('civicrm_survey_respondent'); + CRM_Core_DAO::executeQuery("DROP TABLE IF EXISTS {$tempTableName}"); + $query = " + CREATE TEMPORARY TABLE {$tempTableName} ( + id int unsigned NOT NULL AUTO_INCREMENT, + survey_contact_id int unsigned NOT NULL, + PRIMARY KEY ( id ) +); +"; + CRM_Core_DAO::executeQuery($query); + $batch = 100; + $insertedCount = 0; + do { + $processIds = $this->_contactIds; + $insertIds = array_splice($processIds, $insertedCount, $batch); + if (!empty($insertIds)) { + $insertSQL = "INSERT IGNORE INTO {$tempTableName}( survey_contact_id ) + VALUES (" . implode('),(', $insertIds) . ');'; + CRM_Core_DAO::executeQuery($insertSQL); + } + $insertedCount += $batch; + } while ($insertedCount < $voterIdCount); + + $query = " + SELECT contact.id as id + FROM civicrm_contact contact +INNER JOIN {$tempTableName} ON ( {$tempTableName}.survey_contact_id = contact.id ) + WHERE contact.contact_type != %1"; + $removeContact = CRM_Core_DAO::executeQuery($query, + array(1 => array($profileType, 'String')) + ); + while ($removeContact->fetch()) { + unset($this->_contactIds[$removeContact->id]); + } + } + } + } +} + diff --git a/CRM/Campaign/Form/Task/Print.php b/CRM/Campaign/Form/Task/Print.php new file mode 100755 index 0000000000..36b7c9017f --- /dev/null +++ b/CRM/Campaign/Form/Task/Print.php @@ -0,0 +1,117 @@ +controller->setPrint(1); + + // get the formatted params + $queryParams = $this->get('queryParams'); + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $selector = new CRM_Campaign_Selector_Search($queryParams, + $this->_action, + $this->_componentClause + ); + $controller = new CRM_Core_Selector_Controller($selector, + NULL, + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::SCREEN + ); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + /** + * Build the form - it consists of + * - displaying the QILL (query in local language) + * - displaying elements for saving the search + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // + // just need to add a javacript to popup the window for printing + // + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Print Respondents'), + 'js' => array('onclick' => 'window.print()'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Done'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + // redirect to the main search page after printing is over + } +} + diff --git a/CRM/Campaign/Form/Task/Release.php b/CRM/Campaign/Form/Task/Release.php new file mode 100644 index 0000000000..6b5cce7e2b --- /dev/null +++ b/CRM/Campaign/Form/Task/Release.php @@ -0,0 +1,169 @@ +_interviewToRelease = $this->get('interviewToRelease'); + if ($this->_interviewToRelease) { + //user came from interview form. + foreach (array( + 'surveyId', 'contactIds', 'interviewerId') as $fld) { + $this->{"_$fld"} = $this->get($fld); + } + + if (!empty($this->_contactIds)) { + $this->assign('totalSelectedContacts', count($this->_contactIds)); + } + } + else { + parent::preProcess(); + //get the survey id from user submitted values. + $this->_surveyId = CRM_Utils_Array::value('campaign_survey_id', $this->get('formValues')); + $this->_interviewerId = CRM_Utils_Array::value('survey_interviewer_id', $this->get('formValues')); + } + + if (!$this->_surveyId) { + CRM_Core_Error::statusBounce(ts("Please search with 'Survey', to apply this action.")); + } + if (!$this->_interviewerId) { + CRM_Core_Error::statusBounce(ts('Missing Interviewer contact.')); + } + if (!is_array($this->_contactIds) || empty($this->_contactIds)) { + CRM_Core_Error::statusBounce(ts('Could not find respondents to release.')); + } + + $surveyDetails = array(); + $params = array('id' => $this->_surveyId); + $this->_surveyDetails = CRM_Campaign_BAO_Survey::retrieve($params, $surveyDetails); + + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $statusIds = array(); + foreach (array( + 'Scheduled') as $name) { + if ($statusId = array_search($name, $activityStatus)) { + $statusIds[] = $statusId; + } + } + //fetch the target survey activities. + $this->_surveyActivities = CRM_Campaign_BAO_Survey::voterActivityDetails($this->_surveyId, + $this->_contactIds, + $this->_interviewerId, + $statusIds + ); + if (count($this->_surveyActivities) < 1) { + CRM_Core_Error::statusBounce(ts('We could not found respondent for this survey to release.')); + } + + $this->assign('surveyTitle', $surveyDetails['title']); + + //append breadcrumb to survey dashboard. + if (CRM_Campaign_BAO_Campaign::accessCampaign()) { + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Survey(s)'), 'url' => $url))); + } + + //set the title. + CRM_Utils_System::setTitle(ts('Release Respondents')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + + $this->addDefaultButtons(ts('Release Respondents'), 'done'); + } + + function postProcess() { + $deleteActivityIds = array(); + foreach ($this->_contactIds as $cid) { + if (array_key_exists($cid, $this->_surveyActivities)) { + $deleteActivityIds[] = $this->_surveyActivities[$cid]['activity_id']; + } + } + + //set survey activites as deleted = true. + if (!empty($deleteActivityIds)) { + $query = 'UPDATE civicrm_activity SET is_deleted = 1 WHERE id IN ( ' . implode(', ', $deleteActivityIds) . ' )'; + CRM_Core_DAO::executeQuery($query); + + $status = array(ts("%1 respondent(s) have been released.", array(1 => count($deleteActivityIds)))); + if (count($this->_contactIds) > count($deleteActivityIds)) { + $status[] = ts("%1 respondents did not release.", + array(1 => (count($this->_contactIds) - count($deleteActivityIds))) + ); + } + CRM_Core_Session::setStatus(implode(' ', $status), '', 'info'); + } + } +} + diff --git a/CRM/Campaign/Form/Task/Reserve.php b/CRM/Campaign/Form/Task/Reserve.php new file mode 100644 index 0000000000..1ee60b6ff6 --- /dev/null +++ b/CRM/Campaign/Form/Task/Reserve.php @@ -0,0 +1,352 @@ +_surveyId = $this->get('surveyId'); + $this->_interviewerId = $this->get('interviewerId'); + if (!$this->_surveyId) { + CRM_Core_Error::statusBounce(ts("Could not find Survey Id.")); + } + if (!$this->_interviewerId) { + CRM_Core_Error::statusBounce(ts("Missing Interviewer contact.")); + } + if (!is_array($this->_contactIds) || empty($this->_contactIds)) { + CRM_Core_Error::statusBounce(ts("Could not find contacts for reservation.")); + } + + $params = array('id' => $this->_surveyId); + CRM_Campaign_BAO_Survey::retrieve($params, $this->_surveyDetails); + + //get the survey activities. + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $statusIds = array(); + foreach (array( + 'Scheduled') as $name) { + if ($statusId = array_search($name, $activityStatus)) { + $statusIds[] = $statusId; + } + } + + // these are the activities count that are linked to the current + // interviewer and current survey and not the list of ALL survey activities + $this->_numVoters = CRM_Campaign_BAO_Survey::getSurveyActivities($this->_surveyId, + $this->_interviewerId, + $statusIds, + NULL, + TRUE + ); + //validate the selected survey. + $this->validateSurvey(); + $this->assign('surveyTitle', $this->_surveyDetails['title']); + $this->assign('activityType', $this->_surveyDetails['activity_type_id']); + $this->assign('surveyId', $this->_surveyId); + + //append breadcrumb to survey dashboard. + if (CRM_Campaign_BAO_Campaign::accessCampaign()) { + $url = CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=survey'); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Survey(s)'), 'url' => $url))); + } + + //set the title. + CRM_Utils_System::setTitle(ts('Reserve Respondents')); + } + + function validateSurvey() { + $errorMsg = NULL; + $maxVoters = CRM_Utils_Array::value('max_number_of_contacts', $this->_surveyDetails); + if ($maxVoters) { + if ($maxVoters <= $this->_numVoters) { + $errorMsg = ts('The maximum number of contacts is already reserved for this interviewer.'); + } + elseif (count($this->_contactIds) > ($maxVoters - $this->_numVoters)) { + $errorMsg = ts('You can reserve a maximum of %1 contact(s) at a time for this survey.', + array(1 => $maxVoters - $this->_numVoters) + ); + } + } + + $defaultNum = CRM_Utils_Array::value('default_number_of_contacts', $this->_surveyDetails); + if (!$errorMsg && $defaultNum && (count($this->_contactIds) > $defaultNum)) { + $errorMsg = ts('You can reserve a maximum of %1 contact(s) at a time for this survey.', + array(1 => $defaultNum) + ); + } + + if ($errorMsg) { + CRM_Core_Error::statusBounce($errorMsg); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // allow to add contact to either new or existing group. + $this->addElement('text', 'ActivityType', ts('Activity Type')); + $this->addElement('text', 'newGroupName', ts('Name for new group')); + $this->addElement('text', 'newGroupDesc', ts('Description of new group')); + $groups = CRM_Core_PseudoConstant::group(); + $hasExistingGroups = FALSE; + if (is_array($groups) && !empty($groups)) { + $hasExistingGroups = TRUE; + $this->addElement('select', 'groups', ts('Add respondent(s) to existing group(s)'), + $groups, array('multiple' => "multiple", 'size' => 5) + ); + } + $this->assign('hasExistingGroups', $hasExistingGroups); + + $buttons = array( + array('type' => 'done', + 'name' => ts('Reserve'), + 'subName' => 'reserve', + 'isDefault' => TRUE, + )); + + if (CRM_Core_Permission::check('manage campaign') || + CRM_Core_Permission::check('administer CiviCampaign') || + CRM_Core_Permission::check('interview campaign contacts') + ) { + $buttons[] = array( + 'type' => 'next', + 'name' => ts('Reserve and Interview'), + 'subName' => 'reserveToInterview', + ); + } + $buttons[] = array( + 'type' => 'back', + 'name' => ts('Cancel'), + ); + + $this->addButtons($buttons); + $this->addFormRule(array('CRM_Campaign_Form_Task_Reserve', 'formRule'), $this); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields, $files, $self) { + $errors = array(); + $invalidGroupName = FALSE; + if (CRM_Utils_Array::value('newGroupName', $fields)) { + $title = trim($fields['newGroupName']); + $name = CRM_Utils_String::titleToVar($title); + $query = 'select count(*) from civicrm_group where name like %1 OR title like %2'; + $grpCnt = CRM_Core_DAO::singleValueQuery($query, array(1 => array($name, 'String'), + 2 => array($title, 'String'), + )); + if ($grpCnt) { + $invalidGroupName = TRUE; + $errors['newGroupName'] = ts('Group \'%1\' already exists.', array(1 => $fields['newGroupName'])); + } + } + $self->assign('invalidGroupName', $invalidGroupName); + + return empty($errors) ? TRUE : $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + //add reservation. + $countVoters = 0; + $maxVoters = CRM_Utils_Array::value('max_number_of_contacts', $this->_surveyDetails); + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $statusHeld = array_search('Scheduled', $activityStatus); + + $reservedVoterIds = array(); + foreach ($this->_contactIds as $cid) { + $subject = ts('%1', array(1 => $this->_surveyDetails['title'])) . ' - ' . ts('Respondent Reservation'); + $session = CRM_Core_Session::singleton(); + $activityParams = array('source_contact_id' => $session->get('userID'), + 'assignee_contact_id' => array($this->_interviewerId), + 'target_contact_id' => array($cid), + 'source_record_id' => $this->_surveyId, + 'activity_type_id' => $this->_surveyDetails['activity_type_id'], + 'subject' => $subject, + 'activity_date_time' => date('YmdHis'), + 'status_id' => $statusHeld, + 'skipRecentView' => 1, + 'campaign_id' => CRM_Utils_Array::value('campaign_id', $this->_surveyDetails), + ); + $activity = CRM_Activity_BAO_Activity::create($activityParams); + if ($activity->id) { + $countVoters++; + $reservedVoterIds[$cid] = $cid; + } + if ($maxVoters && ($maxVoters <= ($this->_numVoters + $countVoters))) { + break; + } + } + + //add reserved voters to groups. + $groupAdditions = $this->_addRespondentToGroup($reservedVoterIds); + + // Success message + if ($countVoters > 0) { + $status = '

    ' . ts("%1 Contact(s) have been reserved.", array(1 => $countVoters)) . '

    '; + if ($groupAdditions) { + $status .= '

    ' . ts('Respondent(s) has been added to %1 group(s).', + array(1 => implode(', ', $groupAdditions)) + ) . '

    '; + } + CRM_Core_Session::setStatus($status, ts('Reservation Added'), 'success'); + } + // Error message + if (count($this->_contactIds) > $countVoters) { + CRM_Core_Session::setStatus(ts('Reservation did not add for %1 contact(s).', + array(1 => (count($this->_contactIds) - $countVoters)) + ), ts('Notice')); + } + + //get ready to jump to voter interview form. + $buttonName = $this->controller->getButtonName(); + if (!empty($reservedVoterIds) && + $buttonName == '_qf_Reserve_next_reserveToInterview' + ) { + $this->controller->set('surveyId', $this->_surveyId); + $this->controller->set('contactIds', $reservedVoterIds); + $this->controller->set('interviewerId', $this->_interviewerId); + $this->controller->set('reserveToInterview', TRUE); + } + } + + private function _addRespondentToGroup($contactIds) { + $groupAdditions = array(); + if (empty($contactIds)) { + return $groupAdditions; + } + + $params = $this->controller->exportValues($this->_name); + $groups = CRM_Utils_Array::value('groups', $params, array()); + $newGroupName = CRM_Utils_Array::value('newGroupName', $params); + $newGroupDesc = CRM_Utils_Array::value('newGroupDesc', $params); + + $newGroupId = NULL; + //create new group. + if ($newGroupName) { + $grpParams = array( + 'title' => $newGroupName, + 'description' => $newGroupDesc, + 'is_active' => TRUE, + ); + $group = CRM_Contact_BAO_Group::create($grpParams); + $groups[] = $newGroupId = $group->id; + } + + //add the respondents to groups. + if (is_array($groups)) { + $existingGroups = CRM_Core_PseudoConstant::group(); + foreach ($groups as $groupId) { + $addCount = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId); + $totalCount = CRM_Utils_Array::value(1, $addCount); + if ($groupId == $newGroupId) { + $name = $newGroupName; + $new = TRUE; + } + else { + $name = $existingGroups[$groupId]; + $new = FALSE; + } + if ($totalCount) { + $url = CRM_Utils_System::url('civicrm/group/search', + 'reset=1&force=1&context=smog&gid=' . $groupId + ); + $groupAdditions[] = '' . $name . ''; + } + } + } + + return $groupAdditions; + } +} + diff --git a/CRM/Campaign/Form/Task/Result.php b/CRM/Campaign/Form/Task/Result.php new file mode 100755 index 0000000000..0c5ea416f1 --- /dev/null +++ b/CRM/Campaign/Form/Task/Result.php @@ -0,0 +1,68 @@ +addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Campaign/Info.php b/CRM/Campaign/Info.php new file mode 100644 index 0000000000..b862f32a01 --- /dev/null +++ b/CRM/Campaign/Info.php @@ -0,0 +1,118 @@ + 'CiviCampaign', + 'translatedName' => ts('CiviCampaign'), + 'title' => 'CiviCRM Campaign Engine', + 'search' => 1, + 'showActivitiesInCore' => 1, + ); + } + + + // docs inherited from interface + public function getPermissions() { + return array( + 'administer CiviCampaign', + 'manage campaign', + 'reserve campaign contacts', + 'release campaign contacts', + 'interview campaign contacts', + 'gotv campaign contacts', + 'sign CiviCRM Petition', + ); + } + + + // docs inherited from interface + public function getUserDashboardElement() { + // no dashboard element for this component + return NULL; + } + + public function getUserDashboardObject() { + // no dashboard element for this component + return NULL; + } + + // docs inherited from interface + public function registerTab() { + // this component doesn't use contact record tabs + return NULL; + } + + // docs inherited from interface + public function registerAdvancedSearchPane() { + // this component doesn't use advanced search + return NULL; + } + + // docs inherited from interface + public function getActivityTypes() { + return NULL; + } + + // add shortcut to Create New + public function creatNewShortcut(&$shortCuts) { + if (CRM_Core_Permission::check('manage campaign') || + CRM_Core_Permission::check('administer CiviCampaign') + ) { + $shortCuts = array_merge($shortCuts, array( + array('path' => 'civicrm/campaign/add', + 'query' => "reset=1&action=add", + 'ref' => 'new-campaign', + 'title' => ts('Campaign'), + ), + array( + 'path' => 'civicrm/survey/add', + 'query' => "reset=1&action=add", + 'ref' => 'new-survey', + 'title' => ts('Survey'), + ), + )); + } + } +} + diff --git a/CRM/Campaign/Page/AJAX.php b/CRM/Campaign/Page/AJAX.php new file mode 100644 index 0000000000..eb36cfab6c --- /dev/null +++ b/CRM/Campaign/Page/AJAX.php @@ -0,0 +1,845 @@ + $value) { + if (strpos($key, $customKey) !== FALSE) { + $customFieldKey = str_replace(str_replace(substr($customKey, -6), '', $customKey), '', $key); + $params[$customFieldKey] = $value; + } + } + + if (isset($_POST['field']) && + CRM_Utils_Array::value($voterId, $_POST['field']) && + is_array($_POST['field'][$voterId]) + ) { + foreach ($_POST['field'][$voterId] as $fieldKey => $value) { + $params[$fieldKey] = $value; + } + } + + //lets pickup contat related fields. + foreach ($_POST as $key => $value) { + if (strpos($key, "field_{$voterId}_") !== FALSE && + strpos($key, "field_{$voterId}_custom") === FALSE + ) { + $key = substr($key, strlen("field_{$voterId}_")); + $params[$key] = $value; + } + } + + $result = array( + 'status' => 'fail', + 'voter_id' => $voterId, + 'activity_id' => $params['interviewer_id'], + ); + + //time to validate custom data. + $errors = CRM_Core_BAO_CustomField::validateCustomData($params); + if (is_array($errors) && !empty($errors)) { + $result['errors'] = $errors; + echo json_encode($result); + CRM_Utils_System::civiExit(); + } + + //process the response/interview data. + $activityId = CRM_Campaign_Form_Task_Interview::registerInterview($params); + if ($activityId) { + $result['status'] = 'success'; + } + + echo json_encode($result); + + CRM_Utils_System::civiExit(); + } + + static function loadOptionGroupDetails() { + + $id = CRM_Utils_Array::value('option_group_id', $_POST); + $status = 'fail'; + $opValues = array(); + + if ($id) { + $groupParams['id'] = $id; + CRM_Core_OptionValue::getValues($groupParams, $opValues); + } + + $surveyId = CRM_Utils_Array::value('survey_id', $_POST); + if ($surveyId) { + $survey = new CRM_Campaign_DAO_Survey(); + $survey->id = $surveyId; + $survey->result_id = $id; + if ($survey->find(TRUE)) { + if ($survey->recontact_interval) { + $recontactInterval = unserialize($survey->recontact_interval); + foreach ($opValues as $opValId => $opVal) { + if (is_numeric($recontactInterval[$opVal['label']])) { + $opValues[$opValId]['interval'] = $recontactInterval[$opVal['label']]; + } + } + } + } + } + + if (!empty($opValues)) { + $status = 'success'; + } + + $result = array( + 'status' => $status, + 'result' => $opValues, + ); + + echo json_encode($result); + CRM_Utils_System::civiExit(); + } + + function voterList() { + //get the search criteria params. + $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST)); + + $params = $searchRows = array(); + foreach ($searchParams as $param) { + if (CRM_Utils_Array::value($param, $_POST)) { + $params[$param] = $_POST[$param]; + } + } + + //format multi-select group and contact types. + foreach (array( + 'group', 'contact_type') as $param) { + $paramValue = CRM_Utils_Array::value($param, $params); + if ($paramValue) { + unset($params[$param]); + $paramValue = explode(',', $paramValue); + foreach ($paramValue as $key => $value) { + $params[$param][$value] = 1; + } + } + } + + $voterClauseParams = array(); + foreach (array( + 'campaign_survey_id', 'survey_interviewer_id', 'campaign_search_voter_for') as $fld) { + $voterClauseParams[$fld] = CRM_Utils_Array::value($fld, $params); + } + + $interviewerId = $surveyTypeId = $surveyId = NULL; + $searchVoterFor = $params['campaign_search_voter_for']; + if ($searchVoterFor == 'reserve') { + if (CRM_Utils_Array::value('campaign_survey_id', $params)) { + $survey = new CRM_Campaign_DAO_Survey(); + $survey->id = $surveyId = $params['campaign_survey_id']; + $survey->selectAdd('campaign_id, activity_type_id'); + $survey->find(TRUE); + $campaignId = $survey->campaign_id; + $surveyTypeId = $survey->activity_type_id; + + //allow voter search in sub-part of given constituents, + //but make sure in case user does not select any group. + //get all associated campaign groups in where filter, CRM-7406 + $groups = CRM_Utils_Array::value('group', $params); + if ($campaignId && CRM_Utils_System::isNull($groups)) { + $campaignGroups = CRM_Campaign_BAO_Campaign::getCampaignGroups($campaignId); + foreach ($campaignGroups as $id => $group) $params['group'][$id] = 1; + } + + //apply filter of survey contact type for search. + $contactType = CRM_Campaign_BAO_Survey::getSurveyContactType($surveyId); + if ($contactType) { + $params['contact_type'][$contactType] = 1; + } + + unset($params['campaign_survey_id']); + } + unset($params['survey_interviewer_id']); + } + else { + //get the survey status in where clause. + $scheduledStatusId = array_search('Scheduled', CRM_Core_PseudoConstant::activityStatus('name')); + if ($scheduledStatusId) { + $params['survey_status_id'] = $scheduledStatusId; + } + //BAO/Query knows reserve/release/interview processes. + if ($params['campaign_search_voter_for'] == 'gotv') { + $params['campaign_search_voter_for'] = 'release'; + } + } + + $selectorCols = array( + 'sort_name', + 'street_address', + 'street_name', + 'street_number', + 'street_unit', + ); + + // get the data table params. + $dataTableParams = array( + 'sEcho' => array('name' => 'sEcho', + 'type' => 'Integer', + 'default' => 0, + ), + 'offset' => array( + 'name' => 'iDisplayStart', + 'type' => 'Integer', + 'default' => 0, + ), + 'rowCount' => array( + 'name' => 'iDisplayLength', + 'type' => 'Integer', + 'default' => 25, + ), + 'sort' => array( + 'name' => 'iSortCol_0', + 'type' => 'Integer', + 'default' => 'sort_name', + ), + 'sortOrder' => array( + 'name' => 'sSortDir_0', + 'type' => 'String', + 'default' => 'asc', + ), + ); + foreach ($dataTableParams as $pName => $pValues) { + $$pName = $pValues['default']; + if (CRM_Utils_Array::value($pValues['name'], $_POST)) { + $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']); + if ($pName == 'sort')$$pName = $selectorCols[$$pName]; + } + } + + $queryParams = CRM_Contact_BAO_Query::convertFormValues($params); + $query = new CRM_Contact_BAO_Query($queryParams, + NULL, NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_CAMPAIGN, + TRUE + ); + + //get the voter clause to restrict and validate search. + $voterClause = CRM_Campaign_BAO_Query::voterClause($voterClauseParams); + + $searchCount = $query->searchQuery(0, 0, NULL, + TRUE, FALSE, + FALSE, FALSE, + FALSE, + CRM_Utils_Array::value('whereClause', $voterClause), + NULL, + CRM_Utils_Array::value('fromClause', $voterClause) + ); + + $iTotal = $searchCount; + + $selectorCols = array( + 'contact_type', 'sort_name', 'street_address', + 'street_name', 'street_number', 'street_unit', + ); + + $extraVoterColName = 'is_interview_conducted'; + if ($params['campaign_search_voter_for'] = 'reserve') { + $extraVoterColName = 'reserve_voter'; + } + + if ($searchCount > 0) { + if ($searchCount < $offset) { + $offset = 0; + } + + $config = CRM_Core_Config::singleton(); + + // get the result of the search + $result = $query->searchQuery($offset, $rowCount, $sort, + FALSE, FALSE, + FALSE, FALSE, + FALSE, + CRM_Utils_Array::value('whereClause', $voterClause), + $sortOrder, + CRM_Utils_Array::value('fromClause', $voterClause) + ); + while ($result->fetch()) { + $contactID = $result->contact_id; + $typeImage = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type, + FALSE, + $result->contact_id + ); + + $searchRows[$contactID] = array('id' => $contactID); + foreach ($selectorCols as $col) { + $val = $result->$col; + if ($col == 'contact_type') { + $val = $typeImage; + } + $searchRows[$contactID][$col] = $val; + } + if ($searchVoterFor == 'reserve') { + $voterExtraColHtml = ''; + $msg = ts('Respondent Reserved.'); + $voterExtraColHtml .= " "; + } + elseif ($searchVoterFor == 'gotv') { + $surveyActId = $result->survey_activity_id; + $voterExtraColHtml = ''; + $msg = ts('Vote Recorded'); + $voterExtraColHtml .= "     "; + } + else { + $surveyActId = $result->survey_activity_id; + $voterExtraColHtml = ''; + $msg = ts('Vote Recorded'); + $voterExtraColHtml .= "     "; + } + $searchRows[$contactID][$extraVoterColName] = $voterExtraColHtml; + } + } + + $selectorElements = array_merge($selectorCols, array($extraVoterColName)); + + $iFilteredTotal = $iTotal; + + echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + function processVoterData() { + $status = NULL; + $operation = CRM_Utils_Type::escape($_POST['operation'], 'String'); + if ($operation == 'release') { + $activityId = CRM_Utils_Type::escape($_POST['activity_id'], 'Integer'); + $isDelete = CRM_Utils_String::strtoboolstr(CRM_Utils_Type::escape($_POST['isDelete'], 'String')); + if ($activityId && + CRM_Core_DAO::setFieldValue('CRM_Activity_DAO_Activity', + $activityId, + 'is_deleted', + $isDelete + ) + ) { + $status = 'success'; + } + } + elseif ($operation == 'reserve') { + $activityId = NULL; + $createActivity = TRUE; + if (CRM_Utils_Array::value('activity_id', $_POST)) { + $activityId = CRM_Utils_Type::escape($_POST['activity_id'], 'Integer'); + if ($activityId) { + $createActivity = FALSE; + $activityUpdated = CRM_Core_DAO::setFieldValue('CRM_Activity_DAO_Activity', + $activityId, + 'is_deleted', + 0 + ); + if ($activityUpdated) { + $status = 'success'; + } + } + } + if ($createActivity) { + $ids = array( + 'source_record_id', + 'source_contact_id', + 'target_contact_id', + 'assignee_contact_id', + ); + $activityParams = array(); + foreach ($ids as $id) { + $val = CRM_Utils_Array::value($id, $_POST); + if (!$val) { + $createActivity = FALSE; + break; + } + $activityParams[$id] = CRM_Utils_Type::escape($val, 'Integer'); + } + } + if ($createActivity) { + $isReserved = CRM_Utils_String::strtoboolstr(CRM_Utils_Type::escape($_POST['isReserved'], 'String')); + $activityStatus = CRM_Core_PseudoConstant::activityStatus('name'); + $scheduledStatusId = array_search('Scheduled', $activityStatus); + if ($isReserved) { + $surveyValues = array(); + $surveyParams = array('id' => $activityParams['source_record_id']); + CRM_Core_DAO::commonRetrieve('CRM_Campaign_DAO_Survey', + $surveyParams, + $surveyValues, + array('title', 'activity_type_id', 'campaign_id') + ); + + $activityTypeId = $surveyValues['activity_type_id']; + + $surveytitle = CRM_Utils_Array::value('surveyTitle', $_POST); + if (!$surveytitle) { + $surveytitle = $surveyValues['title']; + } + + $subject = ts('%1', array(1 => $surveytitle)) . ' - ' . ts('Respondent Reservation'); + $activityParams['subject'] = $subject; + $activityParams['status_id'] = $scheduledStatusId; + $activityParams['skipRecentView'] = 1; + $activityParams['activity_date_time'] = date('YmdHis'); + $activityParams['activity_type_id'] = $activityTypeId; + $activityParams['campaign_id'] = $surveyValues['campaign_id']; + + $activity = CRM_Activity_BAO_Activity::create($activityParams); + if ($activity->id) { + $status = 'success'; + } + } + else { + //delete reserved activity for given voter. + $voterIds = array($activityParams['target_contact_id']); + $activities = CRM_Campaign_BAO_Survey::voterActivityDetails($activityParams['source_record_id'], + $voterIds, + $activityParams['source_contact_id'], + array($scheduledStatusId) + ); + foreach ($activities as $voterId => $values) { + $activityId = CRM_Utils_Array::value('activity_id', $values); + if ($activityId && ($values['status_id'] == $scheduledStatusId)) { + CRM_Core_DAO::setFieldValue('CRM_Activity_DAO_Activity', + $activityId, + 'is_deleted', + TRUE + ); + $status = 'success'; + break; + } + } + } + } + } + elseif ($operation == 'gotv') { + $activityId = CRM_Utils_Type::escape($_POST['activity_id'], 'Integer'); + $hasVoted = CRM_Utils_String::strtoboolstr(CRM_Utils_Type::escape($_POST['hasVoted'], 'String')); + if ($activityId) { + if ($hasVoted) { + $statusValue = 2; + } + else { + $statusValue = 1; + } + CRM_Core_DAO::setFieldValue('CRM_Activity_DAO_Activity', + $activityId, + 'status_id', + $statusValue + ); + $status = 'success'; + } + } + + echo json_encode(array('status' => $status)); + CRM_Utils_System::civiExit(); + } + + function allActiveCampaigns() { + $currentCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(); + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, TRUE, FALSE, TRUE); + $options = array( + array('value' => '', + 'title' => ts('- select -'), + )); + foreach ($campaigns as $value => $title) { + $class = NULL; + if (!array_key_exists($value, $currentCampaigns)) { + $class = 'status-past'; + } + $options[] = array( + 'value' => $value, + 'title' => $title, + 'class' => $class, + ); + } + $status = 'fail'; + if (count($options) > 1) { + $status = 'success'; + } + + $results = array( + 'status' => $status, + 'campaigns' => $options, + ); + + echo json_encode($results); + + CRM_Utils_System::civiExit(); + } + + function campaignGroups() { + $surveyId = CRM_Utils_Request::retrieve('survey_id', 'Positive', + CRM_Core_DAO::$_nullObject, FALSE, NULL, 'POST' + ); + $campGroups = array(); + if ($surveyId) { + $campaignId = CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Survey', $surveyId, 'campaign_id'); + if ($campaignId) { + $campGroups = CRM_Campaign_BAO_Campaign::getCampaignGroups($campaignId); + } + } + + //CRM-7406 --If there is no campaign or no group associated with + //campaign of given survey, lets allow to search across all groups. + if (empty($campGroups)) { + $campGroups = CRM_Core_PseudoConstant::group(); + } + $groups = array( + array('value' => '', + 'title' => ts('- select -'), + )); + foreach ($campGroups as $grpId => $title) { + $groups[] = array( + 'value' => $grpId, + 'title' => $title, + ); + } + $results = array( + 'status' => 'success', + 'groups' => $groups, + ); + + echo json_encode($results); + + CRM_Utils_System::civiExit(); + } + + /** + * Retrieve campaigns as for campaign dashboard. + * + **/ + function campaignList() { + //get the search criteria params. + $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST)); + + $params = $searchRows = array(); + foreach ($searchParams as $param) { + if (CRM_Utils_Array::value($param, $_POST)) { + $params[$param] = $_POST[$param]; + } + } + + //this is sequence columns on datatable. + $selectorCols = array( + 'id', + 'name', + 'title', + 'description', + 'start_date', + 'end_date', + 'campaign_type_id', + 'campaign_type', + 'status_id', + 'status', + 'is_active', + 'isActive', + 'action', + ); + + // get the data table params. + $dataTableParams = array( + 'sEcho' => array('name' => 'sEcho', + 'type' => 'Integer', + 'default' => 0, + ), + 'offset' => array( + 'name' => 'iDisplayStart', + 'type' => 'Integer', + 'default' => 0, + ), + 'rowCount' => array( + 'name' => 'iDisplayLength', + 'type' => 'Integer', + 'default' => 25, + ), + 'sort' => array( + 'name' => 'iSortCol_0', + 'type' => 'Integer', + 'default' => 'start_date', + ), + 'sortOrder' => array( + 'name' => 'sSortDir_0', + 'type' => 'String', + 'default' => 'desc', + ), + ); + foreach ($dataTableParams as $pName => $pValues) { + $$pName = $pValues['default']; + if (CRM_Utils_Array::value($pValues['name'], $_POST)) { + $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']); + if ($pName == 'sort') { + $$pName = $selectorCols[$$pName]; + } + } + } + foreach (array( + 'sort', 'offset', 'rowCount', 'sortOrder') as $sortParam) { + $params[$sortParam] = $$sortParam; + } + + $searchCount = CRM_Campaign_BAO_Campaign::getCampaignSummary($params, TRUE); + $campaigns = CRM_Campaign_Page_DashBoard::getCampaignSummary($params); + $iTotal = $searchCount; + + if ($searchCount > 0) { + if ($searchCount < $offset) { + $offset = 0; + } + foreach ($campaigns as $campaignID => $values) { + foreach ($selectorCols as $col) { + $searchRows[$campaignID][$col] = CRM_Utils_Array::value($col, $values); + } + } + } + + $selectorElements = $selectorCols; + + $iFilteredTotal = $iTotal; + + echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + /** + * Retrieve survey for survey dashboard. + * + **/ + function surveyList() { + //get the search criteria params. + $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST)); + + $params = $searchRows = array(); + foreach ($searchParams as $param) { + if (CRM_Utils_Array::value($param, $_POST)) { + $params[$param] = $_POST[$param]; + } + } + + //this is sequence columns on datatable. + $selectorCols = array( + 'id', + 'title', + 'campaign_id', + 'campaign', + 'activity_type_id', + 'activity_type', + 'release_frequency', + 'default_number_of_contacts', + 'max_number_of_contacts', + 'is_default', + 'is_active', + 'isActive', + 'result_id', + 'action', + 'voterLinks', + ); + + // get the data table params. + $dataTableParams = array( + 'sEcho' => array('name' => 'sEcho', + 'type' => 'Integer', + 'default' => 0, + ), + 'offset' => array( + 'name' => 'iDisplayStart', + 'type' => 'Integer', + 'default' => 0, + ), + 'rowCount' => array( + 'name' => 'iDisplayLength', + 'type' => 'Integer', + 'default' => 25, + ), + 'sort' => array( + 'name' => 'iSortCol_0', + 'type' => 'Integer', + 'default' => 'created_date', + ), + 'sortOrder' => array( + 'name' => 'sSortDir_0', + 'type' => 'String', + 'default' => 'desc', + ), + ); + foreach ($dataTableParams as $pName => $pValues) { + $$pName = $pValues['default']; + if (CRM_Utils_Array::value($pValues['name'], $_POST)) { + $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']); + if ($pName == 'sort') { + $$pName = $selectorCols[$$pName]; + } + } + } + foreach (array( + 'sort', 'offset', 'rowCount', 'sortOrder') as $sortParam) { + $params[$sortParam] = $$sortParam; + } + + $surveys = CRM_Campaign_Page_DashBoard::getSurveySummary($params); + $searchCount = CRM_Campaign_BAO_Survey::getSurveySummary($params, TRUE); + $iTotal = $searchCount; + + if ($searchCount > 0) { + if ($searchCount < $offset) { + $offset = 0; + } + foreach ($surveys as $surveyID => $values) { + foreach ($selectorCols as $col) { + $searchRows[$surveyID][$col] = CRM_Utils_Array::value($col, $values); + } + } + } + + $selectorElements = $selectorCols; + + $iFilteredTotal = $iTotal; + + echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + /** + * Retrieve petitions for petition dashboard. + * + **/ + function petitionList() { + //get the search criteria params. + $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST)); + + $params = $searchRows = array(); + foreach ($searchParams as $param) { + if (CRM_Utils_Array::value($param, $_POST)) { + $params[$param] = $_POST[$param]; + } + } + + //this is sequence columns on datatable. + $selectorCols = array( + 'id', + 'title', + 'campaign_id', + 'campaign', + 'activity_type_id', + 'activity_type', + 'is_default', + 'is_active', + 'isActive', + 'action', + ); + + // get the data table params. + $dataTableParams = array( + 'sEcho' => array('name' => 'sEcho', + 'type' => 'Integer', + 'default' => 0, + ), + 'offset' => array( + 'name' => 'iDisplayStart', + 'type' => 'Integer', + 'default' => 0, + ), + 'rowCount' => array( + 'name' => 'iDisplayLength', + 'type' => 'Integer', + 'default' => 25, + ), + 'sort' => array( + 'name' => 'iSortCol_0', + 'type' => 'Integer', + 'default' => 'created_date', + ), + 'sortOrder' => array( + 'name' => 'sSortDir_0', + 'type' => 'String', + 'default' => 'desc', + ), + ); + foreach ($dataTableParams as $pName => $pValues) { + $$pName = $pValues['default']; + if (CRM_Utils_Array::value($pValues['name'], $_POST)) { + $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']); + if ($pName == 'sort') { + $$pName = $selectorCols[$$pName]; + } + } + } + foreach (array( + 'sort', 'offset', 'rowCount', 'sortOrder') as $sortParam) { + $params[$sortParam] = $$sortParam; + } + + $petitions = CRM_Campaign_Page_DashBoard::getPetitionSummary($params); + $searchCount = CRM_Campaign_BAO_Petition::getPetitionSummary($params, TRUE); + $iTotal = $searchCount; + + if ($searchCount > 0) { + if ($searchCount < $offset) { + $offset = 0; + } + foreach ($petitions as $petitionID => $values) { + foreach ($selectorCols as $col) { + $searchRows[$petitionID][$col] = CRM_Utils_Array::value($col, $values); + } + } + } + + $selectorElements = $selectorCols; + + $iFilteredTotal = $iTotal; + + echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Campaign/Page/Campaign.php b/CRM/Campaign/Page/Campaign.php new file mode 100644 index 0000000000..f571d1831e --- /dev/null +++ b/CRM/Campaign/Page/Campaign.php @@ -0,0 +1,136 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/campaign/add', + 'qs' => 'reset=1&action=update&id=%%id%%', + 'title' => ts('Update Campaign'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'title' => ts('Disable Campaign'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Campaign' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'title' => ts('Enable Campaign'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Campaign' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/campaign/add', + 'qs' => 'action=delete&reset=1&id=%%id%%', + 'title' => ts('Delete Campaign'), + ), + ); + } + return self::$_actionLinks; + } + + function browse() { + + $campaigns = CRM_Campaign_BAO_Campaign::getCampaignSummary(); + + if (!empty($campaigns)) { + $campaignType = CRM_Core_PseudoConstant::campaignType(); + $campaignStatus = CRM_Core_PseudoConstant::campaignStatus(); + + foreach ($campaigns as $cmpid => $campaign) { + + $campaigns[$cmpid]['campaign_id'] = $campaign['id']; + $campaigns[$cmpid]['title'] = $campaign['title']; + $campaigns[$cmpid]['name'] = $campaign['name']; + $campaigns[$cmpid]['description'] = $campaign['description']; + $campaigns[$cmpid]['campaign_type_id'] = $campaignType[$campaign['campaign_type_id']]; + $campaigns[$cmpid]['status_id'] = $campaignStatus[$campaign['status_id']]; + + $action = array_sum(array_keys($this->actionLinks())); + if ($campaign['is_active']) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + $campaigns[$cmpid]['action'] = CRM_Core_Action::formLink(self::actionLinks(), $action, + array('id' => $campaign['id']) + ); + } + } + + $this->assign('campaigns', $campaigns); + $this->assign('addCampaignUrl', CRM_Utils_System::url('civicrm/campaign/add', 'reset=1&action=add')); + } + + function run() { + if (!CRM_Core_Permission::check('administer CiviCampaign')) { + CRM_Utils_System::permissionDenied(); + } + + $action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 0 + ); + $this->assign('action', $action); + $this->browse(); + + return parent::run(); + } +} + diff --git a/CRM/Campaign/Page/DashBoard.php b/CRM/Campaign/Page/DashBoard.php new file mode 100644 index 0000000000..824b7d7f64 --- /dev/null +++ b/CRM/Campaign/Page/DashBoard.php @@ -0,0 +1,463 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/campaign/add', + 'qs' => 'reset=1&action=update&id=%%id%%', + 'title' => ts('Update Campaign'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'title' => ts('Disable Campaign'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Campaign' . '\',\'' . 'enable-disable' . '\',\'' . NULL . '\',\'' . 'campaign_row' . '\' );"', + 'ref' => 'disable-action', + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'title' => ts('Enable Campaign'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Campaign' . '\',\'' . 'disable-enable' . '\',\'' . NULL . '\',\'' . 'campaign_row' . '\' );"', + 'ref' => 'enable-action', + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/campaign/add', + 'qs' => 'action=delete&reset=1&id=%%id%%', + 'title' => ts('Delete Campaign'), + ), + ); + } + + return self::$_campaignActionLinks; + } + + function &surveyActionLinks() { + // check if variable _actionsLinks is populated + if (!isset(self::$_surveyActionLinks)) { + self::$_surveyActionLinks = array( + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/survey/configure/main', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Update Survey'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Survey' . '\',\'' . 'enable-disable' . '\',\'' . NULL . '\',\'' . 'survey_row' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Survey'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Survey' . '\',\'' . 'disable-enable' . '\',\'' . NULL . '\',\'' . 'survey_row' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Survey'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/survey/delete', + 'qs' => 'id=%%id%%&reset=1', + 'title' => ts('Delete Survey'), + ), + ); + } + + return self::$_surveyActionLinks; + } + + function &petitionActionLinks() { + if (!isset(self::$_petitionActionLinks)) { + self::$_petitionActionLinks = self::surveyActionLinks(); + self::$_petitionActionLinks[CRM_Core_Action::UPDATE] = array( + 'name' => ts('Edit'), + 'url' => 'civicrm/petition/add', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Update Petition'), + ); + self::$_petitionActionLinks[CRM_Core_Action::DISABLE] = array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Survey' . '\',\'' . 'enable-disable' . '\',\'' . NULL . '\',\'' . 'petition_row' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Petition'), + ); + self::$_petitionActionLinks[CRM_Core_Action::ENABLE] = array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Survey' . '\',\'' . 'disable-enable' . '\',\'' . NULL . '\',\'' . 'petition_row' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Petition'), + ); + self::$_petitionActionLinks[CRM_Core_Action::DELETE] = array( + 'name' => ts('Delete'), + 'url' => 'civicrm/petition/add', + 'qs' => 'action=delete&id=%%id%%&reset=1', + 'title' => ts('Delete Petition'), + ); + self::$_petitionActionLinks[CRM_Core_Action::PROFILE] = array( + 'name' => ts('Sign'), + 'url' => 'civicrm/petition/sign', + 'qs' => 'sid=%%id%%&reset=1', + 'title' => ts('Sign Petition'), + 'fe' => TRUE, + //CRM_Core_Action::PROFILE is used because there isn't a specific action for sign + ); + self::$_petitionActionLinks[CRM_Core_Action::BROWSE] = array( + 'name' => ts('Signatures'), + 'url' => 'civicrm/activity/search', + 'qs' => 'survey=%%id%%&force=1', + 'title' => ts('List the signatures'), + //CRM_Core_Action::PROFILE is used because there isn't a specific action for sign + ); + } + + return self::$_petitionActionLinks; + } + + function browseCampaign() { + // ensure valid javascript (these must have a value set) + $this->assign('searchParams', json_encode(NULL)); + $this->assign('campaignTypes', json_encode(NULL)); + $this->assign('campaignStatus', json_encode(NULL)); + + $this->assign('addCampaignUrl', CRM_Utils_System::url('civicrm/campaign/add', 'reset=1&action=add')); + $campaignCount = CRM_Campaign_BAO_Campaign::getCampaignCount(); + //don't load find interface when no campaigns in db. + if (!$campaignCount) { + $this->assign('hasCampaigns', FALSE); + return; + } + $this->assign('hasCampaigns', TRUE); + + //build the ajaxify campaign search and selector. + $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Search_Campaign', ts('Search Campaigns')); + $controller->set('searchTab', 'campaign'); + $controller->setEmbedded(TRUE); + $controller->process(); + return $controller->run(); + } + + public static function getCampaignSummary($params = array( + )) { + $campaignsData = array(); + + //get the campaigns. + $campaigns = CRM_Campaign_BAO_Campaign::getCampaignSummary($params); + if (!empty($campaigns)) { + $config = CRM_Core_Config::singleton(); + $campaignType = CRM_Campaign_PseudoConstant::campaignType(); + $campaignStatus = CRM_Campaign_PseudoConstant::campaignStatus(); + $properties = array( + 'id', 'name', 'title', 'status_id', 'description', + 'campaign_type_id', 'is_active', 'start_date', 'end_date', + ); + foreach ($campaigns as $cmpid => $campaign) { + foreach ($properties as $prop) { + $campaignsData[$cmpid][$prop] = CRM_Utils_Array::value($prop, $campaign); + } + $statusId = CRM_Utils_Array::value('status_id', $campaign); + $campaignsData[$cmpid]['status'] = CRM_Utils_Array::value($statusId, $campaignStatus); + $campaignsData[$cmpid]['campaign_id'] = $campaign['id']; + $campaignsData[$cmpid]['campaign_type'] = $campaignType[$campaign['campaign_type_id']]; + + $action = array_sum(array_keys(self::campaignActionLinks())); + if ($campaign['is_active']) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $isActive = ts('No'); + if ($campaignsData[$cmpid]['is_active']) { + $isActive = ts('Yes'); + } + $campaignsData[$cmpid]['isActive'] = $isActive; + + if (CRM_Utils_Array::value('start_date', $campaignsData[$cmpid])) { + $campaignsData[$cmpid]['start_date'] = CRM_Utils_Date::customFormat($campaignsData[$cmpid]['start_date'], + $config->dateformatFull + ); + } + if (CRM_Utils_Array::value('end_date', $campaignsData[$cmpid])) { + $campaignsData[$cmpid]['end_date'] = CRM_Utils_Date::customFormat($campaignsData[$cmpid]['end_date'], + $config->dateformatFull + ); + } + $campaignsData[$cmpid]['action'] = CRM_Core_Action::formLink(self::campaignActionLinks(), + $action, + array('id' => $campaign['id']) + ); + } + } + + return $campaignsData; + } + + function browseSurvey() { + // ensure valid javascript - this must have a value set + $this->assign('searchParams', json_encode(NULL)); + $this->assign('surveyTypes', json_encode(NULL)); + $this->assign('surveyCampaigns', json_encode(NULL)); + + $this->assign('addSurveyUrl', CRM_Utils_System::url('civicrm/survey/add', 'reset=1&action=add')); + + $surveyCount = CRM_Campaign_BAO_Survey::getSurveyCount(); + //don't load find interface when no survey in db. + if (!$surveyCount) { + $this->assign('hasSurveys', FALSE); + return; + } + $this->assign('hasSurveys', TRUE); + + //build the ajaxify survey search and selector. + $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Search_Survey', ts('Search Survey')); + $controller->set('searchTab', 'survey'); + $controller->setEmbedded(TRUE); + $controller->process(); + return $controller->run(); + } + + function getSurveySummary($params = array( + )) { + $surveysData = array(); + + //get the survey. + $config = CRM_Core_Config::singleton(); + $surveys = CRM_Campaign_BAO_Survey::getSurveySummary($params); + if (!empty($surveys)) { + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + $surveyType = CRM_Campaign_BAO_Survey::getSurveyActivityType(); + foreach ($surveys as $sid => $survey) { + $surveysData[$sid] = $survey; + $campaignId = CRM_Utils_Array::value('campaign_id', $survey); + $surveysData[$sid]['campaign'] = CRM_Utils_Array::value($campaignId, $campaigns); + $surveysData[$sid]['activity_type'] = $surveyType[$survey['activity_type_id']]; + if (CRM_Utils_Array::value('release_frequency', $survey)) { + $surveysData[$sid]['release_frequency'] = $survey['release_frequency'] . ' Day(s)'; + } + + $action = array_sum(array_keys(self::surveyActionLinks($surveysData[$sid]['activity_type']))); + if ($survey['is_active']) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $isActive = ts('No'); + if ($surveysData[$sid]['is_active']) { + $isActive = ts('Yes'); + } + $surveysData[$sid]['isActive'] = $isActive; + + $isDefault = NULL; + if ($surveysData[$sid]['is_default']) { + $isDefault = '' . ts('Default') . ''; + } + $surveysData[$sid]['is_default'] = $isDefault; + + if ($surveysData[$sid]['result_id']) { + $resultSet = '' . ts('Result Set') . ''; + $surveysData[$sid]['result_id'] = $resultSet; + } else { + $resultUrl = CRM_Utils_System::url("civicrm/survey/configure/results", "action=update&id={$sid}&reset=1"); + $surveysData[$sid]['result_id'] = "(" . ts('Incomplete. Click to configure result set.') . ')'; + } + $surveysData[$sid]['action'] = CRM_Core_Action::formLink(self::surveyActionLinks($surveysData[$sid]['activity_type']), + $action, + array('id' => $sid) + ); + + if (CRM_Utils_Array::value('activity_type', $surveysData[$sid]) != 'Petition') { + $surveysData[$sid]['voterLinks'] = CRM_Campaign_BAO_Survey::buildPermissionLinks($sid, + TRUE, + ts('more') + ); + } + + if ($reportID = CRM_Campaign_BAO_Survey::getReportID($sid)) { + $url = CRM_Utils_System::url("civicrm/report/instance/{$reportID}",'reset=1'); + $surveysData[$sid]['title'] = "{$surveysData[$sid]['title']}"; + } + } + } + + return $surveysData; + } + + function browsePetition() { + // ensure valid javascript - this must have a value set + $this->assign('searchParams', json_encode(NULL)); + $this->assign('petitionCampaigns', json_encode(NULL)); + + $this->assign('addPetitionUrl', CRM_Utils_System::url('civicrm/petition/add', 'reset=1&action=add')); + + $petitionCount = CRM_Campaign_BAO_Petition::getPetitionCount(); + //don't load find interface when no petition in db. + if (!$petitionCount) { + $this->assign('hasPetitions', FALSE); + return; + } + $this->assign('hasPetitions', TRUE); + + //build the ajaxify petition search and selector. + $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Search_Petition', ts('Search Petition')); + $controller->set('searchTab', 'petition'); + $controller->setEmbedded(TRUE); + $controller->process(); + return $controller->run(); + } + + function getPetitionSummary($params = array( + )) { + $config = CRM_Core_Config::singleton(); + $petitionsData = array(); + + //get the petitions. + $petitions = CRM_Campaign_BAO_Petition::getPetitionSummary($params); + if (!empty($petitions)) { + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + $petitionType = CRM_Campaign_BAO_Survey::getSurveyActivityType('label', TRUE); + foreach ($petitions as $pid => $petition) { + $petitionsData[$pid] = $petition; + $camapignId = CRM_Utils_Array::value('campaign_id', $petition); + $petitionsData[$pid]['campaign'] = CRM_Utils_Array::value($camapignId, $campaigns); + $petitionsData[$pid]['activity_type'] = $petitionType[$petition['activity_type_id']]; + + $action = array_sum(array_keys(self::petitionActionLinks())); + + if ($petition['is_active']) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $isActive = ts('No'); + if ($petitionsData[$pid]['is_active']) { + $isActive = ts('Yes'); + } + $petitionsData[$pid]['isActive'] = $isActive; + $isDefault = NULL; + if ($petitionsData[$pid]['is_default']) { + $isDefault = '' . ts('Default') . ''; + } + $petitionsData[$pid]['is_default'] = $isDefault; + + $petitionsData[$pid]['action'] = CRM_Core_Action::formLink(self::petitionActionLinks(), + $action, + array('id' => $pid) + ); + } + } + + return $petitionsData; + } + + function browse() { + $this->_tabs = array('campaign' => ts('Campaigns'), + 'survey' => ts('Surveys'), + 'petition' => ts('Petitions'), + ); + + $subPageType = CRM_Utils_Request::retrieve('type', 'String', $this); + if ($subPageType) { + //load the data in tabs. + $this->{'browse' . ucfirst($subPageType)}(); + } + else { + //build the tabs. + $this->buildTabs(); + } + $this->assign('subPageType', $subPageType); + + //give focus to proper tab. + $selectedTabIndex = array_search(strtolower(CRM_Utils_Array::value('subPage', $_GET, 'campaign')), + array_keys($this->_tabs) + ); + if (!$selectedTabIndex) { + $selectedTabIndex = array_search('campaign', array_keys($this->_tabs)); + } + $this->assign('selectedTabIndex', $selectedTabIndex); + } + + function run() { + if (!CRM_Campaign_BAO_Campaign::accessCampaign()) { + CRM_Utils_System::permissionDenied(); + } + + $this->browse(); + + return parent::run(); + } + + function buildTabs() { + $allTabs = array(); + foreach ($this->_tabs as $name => $title) { + $allTabs[] = array( + 'id' => $name, + 'title' => $title, + 'url' => CRM_Utils_System::url('civicrm/campaign', "reset=1&type=$name&snippet=1"), + ); + } + + $this->assign('allTabs', $allTabs); + } +} + diff --git a/CRM/Campaign/Page/Petition.php b/CRM/Campaign/Page/Petition.php new file mode 100644 index 0000000000..3b7b6baac0 --- /dev/null +++ b/CRM/Campaign/Page/Petition.php @@ -0,0 +1,60 @@ +assign('signatures', $signatures); + } + + function run() { + $action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 0 + ); + $this->assign('action', $action); + $this->browse(); + + return parent::run(); + } +} + diff --git a/CRM/Campaign/Page/Petition/Confirm.php b/CRM/Campaign/Page/Petition/Confirm.php new file mode 100644 index 0000000000..03626e3ec5 --- /dev/null +++ b/CRM/Campaign/Page/Petition/Confirm.php @@ -0,0 +1,117 @@ +confirm($contact_id, $subscribe_id, $hash, $activity_id, $petition_id); + if ($result === FALSE) { + $this->assign('success', $result); + } + else { + $this->assign('success', TRUE); + // $this->assign( 'group' , $result ); + } + + list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contact_id); + $this->assign('display_name', $displayName); + $this->assign('email', $email); + $this->assign('petition_id', $petition_id); + + $this->assign('survey_id', $petition_id); + + $pparams['id'] = $petition_id; + $this->petition = array(); + CRM_Campaign_BAO_Survey::retrieve($pparams, $this->petition); + $this->assign('thankyou_title', CRM_Utils_Array::value('thankyou_title', $this->petition)); + $this->assign('thankyou_text', CRM_Utils_Array::value('thankyou_text', $this->petition)); + CRM_Utils_System::setTitle(CRM_Utils_Array::value('thankyou_title', $this->petition)); + + // send thank you email + $params['contactId'] = $contact_id; + $params['email-Primary'] = $email; + $params['sid'] = $petition_id; + $params['activityId'] = $activity_id; + CRM_Campaign_BAO_Petition::sendEmail($params, CRM_Campaign_Form_Petition_Signature::EMAIL_THANK); + + return parent::run(); + } + + /** + * Confirm email verification + * + * @param int $contact_id The id of the contact + * @param int $subscribe_id The id of the subscription event + * @param string $hash The hash + * + * @return boolean True on success + * @access public + * @static + */ + public static function confirm($contact_id, $subscribe_id, $hash, $activity_id, $petition_id) { + $se = CRM_Mailing_Event_BAO_Subscribe::verify($contact_id, $subscribe_id, $hash); + + if (!$se) { + return FALSE; + } + + $transaction = new CRM_Core_Transaction(); + + $ce = new CRM_Mailing_Event_BAO_Confirm(); + $ce->event_subscribe_id = $se->id; + $ce->time_stamp = date('YmdHis'); + $ce->save(); + + + CRM_Contact_BAO_GroupContact::updateGroupMembershipStatus($contact_id, $se->group_id, + 'Email', $ce->id + ); + + $bao = new CRM_Campaign_BAO_Petition(); + $bao->confirmSignature($activity_id, $contact_id, $petition_id); + } +} + diff --git a/CRM/Campaign/Page/Petition/ThankYou.php b/CRM/Campaign/Page/Petition/ThankYou.php new file mode 100644 index 0000000000..0b6d06d55a --- /dev/null +++ b/CRM/Campaign/Page/Petition/ThankYou.php @@ -0,0 +1,62 @@ +petition = array(); + CRM_Campaign_BAO_Survey::retrieve($params, $this->petition); + $this->assign('petitionTitle', $this->petition['title']); + $this->assign('thankyou_title', CRM_Utils_Array::value('thankyou_title', $this->petition)); + $this->assign('thankyou_text', CRM_Utils_Array::value('thankyou_text', $this->petition)); + $this->assign('survey_id', $petition_id); + $this->assign('status_id', $id); + CRM_Utils_System::setTitle(CRM_Utils_Array::value('thankyou_title', $this->petition)); + + // send thank you or email verification emails + /* + * sendEmailMode + * 1 = connected user via login/pwd - thank you + * or dedupe contact matched who doesn't have a tag CIVICRM_TAG_UNCONFIRMED - thank you + * login using fb connect - thank you + click to add msg to fb wall + * 2 = send a confirmation request email + */ + + + return parent::run(); + } +} + diff --git a/CRM/Campaign/Page/Survey.php b/CRM/Campaign/Page/Survey.php new file mode 100644 index 0000000000..3345c7e602 --- /dev/null +++ b/CRM/Campaign/Page/Survey.php @@ -0,0 +1,121 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/survey/add', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Update Survey'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Survey' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Survey'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Campaign_BAO_Survey' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Survey'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/survey/delete', + 'qs' => 'id=%%id%%&reset=1', + 'title' => ts('Delete Survey'), + ), + ); + } + return self::$_actionLinks; + } + + function browse() { + + $surveys = CRM_Campaign_BAO_Survey::getSurveySummary(); + + if (!empty($surveys)) { + + $surveyType = CRM_Campaign_BAO_Survey::getSurveyActivityType(); + $campaigns = CRM_Campaign_BAO_Campaign::getAllCampaign(); + $activityTypes = CRM_Core_OptionGroup::values('activity_type', FALSE, FALSE, FALSE, FALSE, 'name'); + foreach ($surveys as $sid => $survey) { + $surveys[$sid]['campaign_id'] = $campaigns[$survey['campaign_id']]; + $surveys[$sid]['activity_type_id'] = $surveyType[$survey['activity_type_id']]; + $surveys[$sid]['release_frequency'] = $survey['release_frequency_interval'] . ' ' . $survey['release_frequency_unit']; + + $action = array_sum(array_keys($this->actionLinks())); + if ($survey['is_active']) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $surveys[$sid]['action'] = CRM_Core_Action::formLink($this->actionLinks(), $action, array('id' => $sid)); + } + } + + $this->assign('surveys', $surveys); + $this->assign('addSurveyUrl', CRM_Utils_System::url('civicrm/survey/add', 'reset=1&action=add')); + } + + function run() { + if (!CRM_Campaign_BAO_Campaign::accessCampaign()) { + CRM_Utils_System::permissionDenied(); + } + + $action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 0 + ); + $this->assign('action', $action); + $this->browse(); + + return parent::run(); + } +} + diff --git a/CRM/Campaign/Page/SurveyType.php b/CRM/Campaign/Page/SurveyType.php new file mode 100644 index 0000000000..82a34afdad --- /dev/null +++ b/CRM/Campaign/Page/SurveyType.php @@ -0,0 +1,220 @@ +_gName = 'activity_type'; + + $this->_gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $this->_gName, 'id', 'name'); + + $this->_GName = 'Survey Type'; + + $this->assign('gName', $this->_gName); + $this->assign('GName', $this->_GName); + + CRM_Utils_System::setTitle(ts('%1 Options', array(1 => $this->_GName))); + + $this->assign('addSurveyType', CRM_Utils_System::url("civicrm/admin/campaign/surveyType", 'reset=1&action=add')); + } + + /** + * Get BAO Name + * + * @return string Classname of BAO. + */ + function getBAOName() { + return 'CRM_Core_BAO_OptionValue'; + } + + /** + * Get action Links + * + * @return array (reference) of action links + */ + function &links() { + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/campaign/surveyType', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit %1', array(1 => $this->_gName)), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionValue' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable %1', array(1 => $this->_gName)), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Core_BAO_OptionValue' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable %1', array(1 => $this->_gName)), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/campaign/surveyType', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete %1 Type', array(1 => $this->_gName)), + ), + ); + } + return self::$_links; + } + + /** + * Run the basic page (run essentially starts execution for that page). + * + * @return void + */ + function run() { + $this->preProcess(); + return parent::run(); + } + + /** + * Browse all options + * + * + * @return void + * @access public + * @static + */ + function browse() { + + $campaingCompId = CRM_Core_Component::getComponentID('CiviCampaign'); + $groupParams = array('name' => $this->_gName); + $optionValues = CRM_Core_OptionValue::getRows($groupParams, $this->links(), 'component_id,weight'); + + foreach ($optionValues as $key => $optionValue) { + if (CRM_Utils_Array::value('component_id', $optionValue) != $campaingCompId) { + unset($optionValues[$key]); + } + } + + $returnURL = CRM_Utils_System::url("civicrm/admin/campaign/surveyType", + "reset=1" + ); + $filter = "option_group_id = " . $this->_gid; + CRM_Utils_Weight::addOrder($optionValues, 'CRM_Core_DAO_OptionValue', + 'id', $returnURL, $filter + ); + $this->assign('rows', $optionValues); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Campaign_Form_SurveyType'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return $this->_GName; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/campaign/surveyType'; + } + + /** + * function to get userContext params + * + * @param int $mode mode that we are in + * + * @return string + * @access public + */ + function userContextParams($mode = NULL) { + return 'reset=1'; + } +} + diff --git a/CRM/Campaign/Page/Vote.php b/CRM/Campaign/Page/Vote.php new file mode 100644 index 0000000000..5763747b5c --- /dev/null +++ b/CRM/Campaign/Page/Vote.php @@ -0,0 +1,137 @@ +set('votingTab', TRUE); + $controller->set('subVotingTab', 'searchANDReserve'); + + $controller->process(); + return $controller->run(); + } + + function interview() { + //build interview and release voter interface. + $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Task_Interview', ts('Interview Respondents')); + $controller->set('votingTab', TRUE); + $controller->set('subVotingTab', 'searchANDInterview'); + if ($this->_surveyId) { + $controller->set('surveyId', $this->_surveyId); + } + if ($this->_interviewerId) { + $controller->set('interviewerId', $this->_interviewerId); + } + $controller->process(); + return $controller->run(); + } + + function browse() { + $this->_tabs = array('reserve' => ts('Reserve Respondents'), + 'interview' => ts('Interview Respondents'), + ); + + $this->_surveyId = CRM_Utils_Request::retrieve('sid', 'Positive', $this); + $this->_interviewerId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + $subPageType = CRM_Utils_Request::retrieve('type', 'String', $this); + if ($subPageType) { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/campaign/vote', "reset=1&subPage={$subPageType}")); + //load the data in tabs. + $this->{$subPageType}(); + } + else { + //build the tabs. + $this->buildTabs(); + } + $this->assign('subPageType', $subPageType); + + //give focus to proper tab. + $this->assign('selectedTabIndex', array_search(CRM_Utils_Array::value('subPage', $_GET, 'reserve'), + array_keys($this->_tabs) + )); + } + + function run() { + $this->browse(); + + return parent::run(); + } + + function buildTabs() { + //check for required permissions. + $superUser = FALSE; + if (CRM_Core_Permission::check('manage campaign') || + CRM_Core_Permission::check('administer CiviCampaign') + ) { + $superUser = TRUE; + } + + $allTabs = array(); + foreach ($this->_tabs as $name => $title) { + if (!$superUser && + !CRM_Core_Permission::check("{$name} campaign contacts") + ) { + continue; + } + + $urlParams = "type={$name}&snippet=1"; + if ($this->_surveyId) { + $urlParams .= "&sid={$this->_surveyId}"; + } + if ($this->_interviewerId) { + $urlParams .= "&cid={$this->_interviewerId}"; + } + $allTabs[] = array( + 'id' => $name, + 'title' => $title, + 'url' => CRM_Utils_System::url('civicrm/campaign/vote', + $urlParams + ), + ); + } + + $this->assign('allTabs', empty($allTabs) ? FALSE : $allTabs); + } +} + diff --git a/CRM/Campaign/PseudoConstant.php b/CRM/Campaign/PseudoConstant.php new file mode 100755 index 0000000000..cdd67ca119 --- /dev/null +++ b/CRM/Campaign/PseudoConstant.php @@ -0,0 +1,163 @@ +_queryParams = &$queryParams; + + $this->_single = $single; + $this->_limit = $limit; + $this->_context = $context; + + $this->_campaignClause = $surveyClause; + $this->_campaignFromClause = CRM_Utils_Array::value('fromClause', $surveyClause); + $this->_campaignWhereClause = CRM_Utils_Array::value('whereClause', $surveyClause); + + // type of selector + $this->_action = $action; + + $this->_query = new CRM_Contact_BAO_Query($this->_queryParams, + NULL, NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_CAMPAIGN, + TRUE + ); + } + //end of constructor + + /** + * This method returns the links that are given for each search row. + * currently the links added for each row are + * + * - View + * - Edit + * + * @return array + * @access public + * + */ + static + function &links() { + return self::$_links = array(); + } + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['csvString'] = NULL; + $params['status'] = ts('Respondents') . ' %%StatusMessage%%'; + $params['rowCount'] = ($this->_limit) ? $this->_limit : CRM_Utils_Pager::ROWCOUNT; + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + + /** + * Returns total number of rows for the query. + * + * @param + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action) { + return $this->_query->searchQuery(0, 0, NULL, + TRUE, FALSE, + FALSE, FALSE, FALSE, + $this->_campaignWhereClause, + NULL, + $this->_campaignFromClause + ); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return int the total number of rows for this action + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { + $result = $this->_query->searchQuery($offset, $rowCount, $sort, + FALSE, FALSE, + FALSE, FALSE, + FALSE, $this->_campaignWhereClause, + NULL, + $this->_campaignFromClause + ); + + + // process the result of the query + $rows = array(); + + While ($result->fetch()) { + $row = array(); + // the columns we are interested in + foreach (self::$_properties as $property) { + if (property_exists($result, $property)) { + $row[$property] = $result->$property; + } + } + $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->contact_id; + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_type, FALSE, $result->contact_id); + + $rows[] = $row; + } + $this->buildPrevNextCache($sort); + + return $rows; + } + + function buildPrevNextCache($sort) { + //for prev/next pagination + $crmPID = CRM_Utils_Request::retrieve('crmPID', 'Integer', CRM_Core_DAO::$_nullObject); + + if (!$crmPID) { + $cacheKey = "civicrm search {$this->_key}"; + CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey, 'civicrm_contact'); + + $sql = $this->_query->searchQuery(0, 0, $sort, + FALSE, FALSE, + FALSE, FALSE, + TRUE, $this->_campaignWhereClause, + NULL, + $this->_campaignFromClause + ); + list($select, $from) = explode(' FROM ', $sql); + $insertSQL = " +INSERT INTO civicrm_prevnext_cache ( entity_table, entity_id1, entity_id2, cacheKey, data ) +SELECT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.display_name +FROM {$from} +"; + CRM_Core_Error::ignoreException(); + $result = CRM_Core_DAO::executeQuery($insertSQL); + CRM_Core_Error::setCallback(); + + if (is_a($result, 'DB_Error')) { + return; + } + // also record an entry in the cache key table, so we can delete it periodically + CRM_Core_BAO_Cache::setItem($cacheKey, 'CiviCRM Search PrevNextCache', $cacheKey); + } + } + + /** + * + * @return array $qill which contains an array of strings + * @access public + **/ + public function getQILL() { + return $this->_query->qill(); + } + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + public function &getColumnHeaders($action = NULL, $output = NULL) { + self::$_columnHeaders = array(); + + if (!$this->_single) { + $contactDetails = array( + array('name' => ts('Contact Name'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::ASCENDING, + ), + array('name' => ts('Street Number'), + 'sort' => 'street_number', + ), + array('name' => ts('Street Name'), + 'sort' => 'street_name', + ), + array('name' => ts('Street Address')), + array('name' => ts('City'), + 'sort' => 'city', + ), + array('name' => ts('Postal Code'), + 'sort' => 'postal_code', + ), + array('name' => ts('State'), + 'sort' => 'state_province_name', + ), + array('name' => ts('Country')), + array('name' => ts('Email')), + array('name' => ts('Phone')), + ); + self::$_columnHeaders = array_merge($contactDetails, self::$_columnHeaders); + } + + return self::$_columnHeaders; + } + + function &getQuery() { + return $this->_query; + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('CiviCRM Respondent Search'); + } +} +//end of class + diff --git a/CRM/Campaign/StateMachine/Search.php b/CRM/Campaign/StateMachine/Search.php new file mode 100755 index 0000000000..af9d483240 --- /dev/null +++ b/CRM/Campaign/StateMachine/Search.php @@ -0,0 +1,107 @@ +_pages = array(); + + $this->_pages['CRM_Campaign_Form_Search'] = NULL; + list($task, $result) = $this->taskName($controller, 'Search'); + $this->_task = $task; + if (is_array($task)) { + foreach ($task as $t) { + $this->_pages[$t] = NULL; + } + } + else { + $this->_pages[$task] = NULL; + } + if ($result) { + $this->_pages['CRM_Campaign_Form_Task_Result'] = NULL; + } + + $this->addSequentialPages($this->_pages, $action); + } + + /** + * Determine the form name based on the action. This allows us + * to avoid using conditional state machine, much more efficient + * and simpler + * + * @param CRM_Core_Controller $controller the controller object + * + * @return string the name of the form that will handle the task + * @access protected + */ + function taskName($controller, $formName = 'Search') { + // total hack, check POST vars and then session to determine stuff + // fix value if print button is pressed + if (CRM_Utils_Array::value('_qf_' . $formName . '_next_print', $_POST)) { + $value = CRM_Campaign_Task::PRINT_VOTERS; + } + else { + $value = CRM_Utils_Array::value('task', $_POST); + } + if (!isset($value)) { + $value = $this->_controller->get('task'); + } + $this->_controller->set('task', $value); + + return CRM_Campaign_Task::getTask($value); + } + + /** + * return the form name of the task + * + * @return string + * @access public + */ + function getTaskFormName() { + return CRM_Utils_String::getClassName($this->_task); + } +} + diff --git a/CRM/Campaign/Task.php b/CRM/Campaign/Task.php new file mode 100755 index 0000000000..ddb246e2ca --- /dev/null +++ b/CRM/Campaign/Task.php @@ -0,0 +1,160 @@ + array('title' => ts('Record Respondents Interview'), + 'class' => array( + 'CRM_Campaign_Form_Task_Interview', + 'CRM_Campaign_Form_Task_Release', + ), + 'result' => FALSE, + ), + 2 => array('title' => ts('Reserve Respondents'), + 'class' => array( + 'CRM_Campaign_Form_Task_Reserve', + 'CRM_Campaign_Form_Task_Interview', + 'CRM_Campaign_Form_Task_Release', + ), + 'result' => FALSE, + ), + 3 => array('title' => ts('Release Respondents'), + 'class' => 'CRM_Campaign_Form_Task_Release', + 'result' => FALSE, + ), + 4 => array('title' => ts('Print Respondents'), + 'class' => 'CRM_Campaign_Form_Task_Print', + 'result' => FALSE, + ), + ); + } + + CRM_Utils_Hook::searchTasks('campaign', self::$_tasks); + + asort(self::$_tasks); + + return self::$_tasks; + } + + /** + * These tasks are the core set of task titles + * on voters. + * + * @return array the set of task titles + * @static + * @access public + */ + static function &taskTitles() { + self::tasks(); + $titles = array(); + foreach (self::$_tasks as $id => $value) { + $titles[$id] = $value['title']; + } + + return $titles; + } + + /** + * show tasks selectively based on the permission level + * of the user + * + * @param int $permission + * + * @return array set of tasks that are valid for the user + * @access public + */ + static function &permissionedTaskTitles($permission) { + $tasks = self::taskTitles(); + + return $tasks; + } + + /** + * These tasks are the core set of tasks that the user can perform + * on voters. + * + * @param int $value + * + * @return array the set of tasks for a group of voters. + * @static + * @access public + */ + static function getTask($value) { + self::tasks(); + if (!$value || !CRM_Utils_Array::value($value, self::$_tasks)) { + // make the interview task by default + $value = 1; + } + + return array( + self::$_tasks[$value]['class'], + self::$_tasks[$value]['result'], + ); + } +} + diff --git a/CRM/Campaign/xml/Menu/Campaign.xml b/CRM/Campaign/xml/Menu/Campaign.xml new file mode 100644 index 0000000000..d29a5f84ba --- /dev/null +++ b/CRM/Campaign/xml/Menu/Campaign.xml @@ -0,0 +1,176 @@ + + + + + civicrm/campaign + Campaign Dashboard + CRM_Campaign_Page_DashBoard + administer CiviCampaign;manage campaign + CiviCampaign + + + civicrm/campaign/add + New Campaign + CRM_Campaign_Form_Campaign + administer CiviCampaign;manage campaign + CiviCampaign + + + civicrm/survey/add + New Survey + CRM_Campaign_Form_Survey_Main + administer CiviCampaign;manage campaign + CiviCampaign + + + civicrm/campaign/vote + Conduct Survey + CRM_Campaign_Page_Vote + administer CiviCampaign;manage campaign;reserve campaign contacts;interview campaign contacts + CiviCampaign + + + civicrm/admin/campaign/surveyType + Survey Types + CRM_Campaign_Page_SurveyType + administer CiviCampaign + admin/small/05.png + CiviCampaign + CiviCampaign + 1 + + + civicrm/admin/options/campaign_type + Campaign Types + categorize your campaigns using campaign types. + group=campaign_type + CRM_Admin_Page_Options + CiviCampaign + admin/small/05.png + 2 + CiviCampaign + + + civicrm/admin/options/campaign_status + Campaign Status + Define statuses for campaign here. + group=campaign_status + CRM_Admin_Page_Options + CiviCampaign + admin/small/05.png + 3 + CiviCampaign + + + civicrm/admin/options/engagement_index + Engagement Index + Engagement levels. + group=engagement_index + CRM_Admin_Page_Options + CiviCampaign + admin/small/05.png + 4 + CiviCampaign + + + civicrm/admin/setting/preferences/campaign + CiviCampaign Component Settings + CRM_Admin_Form_Preferences_Campaign + Configure global CiviCampaign behaviors. + CiviCampaign + 10 + CiviCampaign + + + civicrm/survey/search + Reserve Respondents + op=reserve + CRM_Campaign_Controller_Search + administer CiviCampaign;manage campaign;reserve campaign contacts + CiviCampaign + + + civicrm/survey/search + Release Respondents + op=release + CRM_Campaign_Controller_Search + administer CiviCampaign;manage campaign;release campaign contacts + CiviCampaign + + + civicrm/survey/search + Record Respondents Interview + op=interview + CRM_Campaign_Controller_Search + administer CiviCampaign;manage campaign;interview campaign contacts + CiviCampaign + + + civicrm/campaign/gotv + GOTV (Track Voters) + CRM_Campaign_Form_Gotv + administer CiviCampaign;manage campaign;release campaign contacts;gotv campaign contacts + CiviCampaign + + + civicrm/petition/add + New Petition + CRM_Campaign_Form_Petition + administer CiviCampaign;manage campaign + + + civicrm/petition/sign + Sign Petition + CRM_Campaign_Form_Petition_Signature + sign CiviCRM Petition + true + + + civicrm/petition/browse + View Petition Signatures + CRM_Campaign_Page_Petition + + + civicrm/petition/confirm + Email address verified + CRM_Campaign_Page_Petition_Confirm + sign CiviCRM Petition + true + + + civicrm/petition/thankyou + Thank You + CRM_Campaign_Page_Petition_ThankYou + sign CiviCRM Petition + true + + + civicrm/campaign/registerInterview + CRM_Campaign_Page_AJAX::registerInterview + administer CiviCampaign;manage campaign;interview campaign contacts + + + civicrm/survey/configure/main + Configure Survey + CRM_Campaign_Form_Survey_Main + administer CiviCampaign;manage campaign + + + civicrm/survey/configure/questions + Configure Survey + CRM_Campaign_Form_Survey_Questions + administer CiviCampaign;manage campaign + + + civicrm/survey/configure/results + Configure Survey + CRM_Campaign_Form_Survey_Results + administer CiviCampaign;manage campaign + + + civicrm/survey/delete + Delete Survey + CRM_Campaign_Form_Survey_Delete + administer CiviCampaign;manage campaign + + diff --git a/CRM/Case/Audit/Audit.php b/CRM/Case/Audit/Audit.php new file mode 100644 index 0000000000..0401161aef --- /dev/null +++ b/CRM/Case/Audit/Audit.php @@ -0,0 +1,218 @@ +xmlString = $xmlString; + $this->auditConfig = new CRM_Case_Audit_AuditConfig($confFilename); + } + + public function getActivities($printReport = FALSE) { + $retval = array(); + + /* + * Loop through the activities in the file and add them to the appropriate region array. + */ + + $doc = new DOMDocument(); + + if ($doc->loadXML($this->xmlString)) { + $regionList = $this->auditConfig->getRegions(); + + $ifBlanks = $this->auditConfig->getIfBlanks(); + + $includeAll = $doc->getElementsByTagName("IncludeActivities")->item(0)->nodeValue; + $includeAll = ($includeAll == 'All'); + + $activityindex = 0; + $activityList = $doc->getElementsByTagName("Activity"); + + $caseActivities = array(); + $activityStatusType = array(); + + foreach ($activityList as $activity) { + $retval[$activityindex] = array(); + + $ifBlankReplacements = array(); + + $completed = FALSE; + $sortValues = array('1970-01-01'); + $category = ''; + $fieldindex = 1; + $fields = $activity->getElementsByTagName("Field"); + foreach ($fields as $field) { + $datatype_elements = $field->getElementsByTagName("Type"); + $datatype = $datatype_elements->item(0)->nodeValue; + + $label_elements = $field->getElementsByTagName("Label"); + $label = $label_elements->item(0)->nodeValue; + + $value_elements = $field->getElementsByTagName("Value"); + $value = $value_elements->item(0)->nodeValue; + + $category_elements = $field->getElementsByTagName("Category"); + if (!empty($category_elements)) { + $category = $category_elements->item(0)->nodeValue; + } + + // Based on the config file, does this field's label and value indicate a completed activity? + if ($label == $this->auditConfig->getCompletionLabel() && $value == $this->auditConfig->getCompletionValue()) { + $completed = TRUE; + } + + // Based on the config file, does this field's label match the one to use for sorting activities? + if (in_array($label, $this->auditConfig->getSortByLabels())) { + $sortValues[$label] = $value; + } + + foreach ($regionList as $region) { + // Based on the config file, is this field a potential replacement for another? + if (!empty($ifBlanks[$region])) { + if (in_array($label, $ifBlanks[$region])) { + $ifBlankReplacements[$label] = $value; + } + } + + if ($this->auditConfig->includeInRegion($label, $region)) { + $retval[$activityindex][$region][$fieldindex] = array(); + $retval[$activityindex][$region][$fieldindex]['label'] = $label; + $retval[$activityindex][$region][$fieldindex]['datatype'] = $datatype; + $retval[$activityindex][$region][$fieldindex]['value'] = $value; + if ($datatype == 'Date') { + $retval[$activityindex][$region][$fieldindex]['includeTime'] = $this->auditConfig->includeTime($label, $region); + } + + //CRM-4570 + if ($printReport) { + if (!in_array($label, array( + 'Activity Type', 'Status'))) { + $caseActivities[$activityindex][$fieldindex] = array(); + $caseActivities[$activityindex][$fieldindex]['label'] = $label; + $caseActivities[$activityindex][$fieldindex]['datatype'] = $datatype; + $caseActivities[$activityindex][$fieldindex]['value'] = $value; + } + else { + $activityStatusType[$activityindex][$fieldindex] = array(); + $activityStatusType[$activityindex][$fieldindex]['label'] = $label; + $activityStatusType[$activityindex][$fieldindex]['datatype'] = $datatype; + $activityStatusType[$activityindex][$fieldindex]['value'] = $value; + } + } + } + } + + $fieldindex++; + } + + if ($printReport) { + $caseActivities[$activityindex] = CRM_Utils_Array::crmArrayMerge($activityStatusType[$activityindex], $caseActivities[$activityindex]); + $caseActivities[$activityindex]['sortValues'] = $sortValues; + } + + if ($includeAll || !$completed) { + $retval[$activityindex]['completed'] = $completed; + $retval[$activityindex]['category'] = $category; + $retval[$activityindex]['sortValues'] = $sortValues; + + // Now sort the fields based on the order in the config file. + foreach ($regionList as $region) { + $this->auditConfig->sort($retval[$activityindex][$region], $region); + } + + $retval[$activityindex]['editurl'] = $activity->getElementsByTagName("EditURL")->item(0)->nodeValue; + + // If there are any fields with ifBlank specified, replace their values. + // We need to do this as a second pass because if we do it while looping through fields we might not have come across the field we need yet. + foreach ($regionList as $region) { + foreach ($retval[$activityindex][$region] as & $v) { + $vlabel = $v['label']; + if (trim($v['value']) == '' && !empty($ifBlanks[$region][$vlabel])) { + if (!empty($ifBlankReplacements[$ifBlanks[$region][$vlabel]])) { + $v['value'] = $ifBlankReplacements[$ifBlanks[$region][$vlabel]]; + } + } + } + unset($v); + } + + $activityindex++; + } + else { + /* This is a little bit inefficient, but the alternative is to do two passes + because we don't know until we've examined all the field values whether the activity + is completed, since the field that determines it and its value is configurable, + so either way isn't ideal. */ + + unset($retval[$activityindex]); + unset($caseActivities[$activityindex]); + } + } + + if ($printReport) { + @uasort($caseActivities, array($this, "compareActivities")); + } + else { + @uasort($retval, array($this, "compareActivities")); + } + } + + if ($printReport) { + return $caseActivities; + } + else { + return $retval; + } + } + + /* compareActivities + * + * This is intended to be called as a sort callback function, returning whether an activity's date is earlier or later than another's. + * The type of date to use is specified in the config. + * + */ + + public function compareActivities($a, $b) { + // This should work + foreach ($this->auditConfig->getSortByLabels() as $label) { + $aval .= empty($a['sortValues']) ? "" : (empty($a['sortValues'][$label]) ? "" : $a['sortValues'][$label]); + $bval .= empty($b['sortValues']) ? "" : (empty($b['sortValues'][$label]) ? "" : $b['sortValues'][$label]); + } + + if ($aval < $bval) { + return - 1; + } + elseif ($aval > $bval) { + return 1; + } + else { + return 0; + } + } + + static + function run($xmlString, $clientID, $caseID, $printReport = FALSE) { + /* +$fh = fopen('C:/temp/audit2.xml', 'w'); +fwrite($fh, $xmlString); +fclose($fh); +*/ + + $audit = new CRM_Case_Audit_Audit($xmlString, 'audit.conf.xml'); + $activities = $audit->getActivities($printReport); + + $template = CRM_Core_Smarty::singleton(); + $template->assign_by_ref('activities', $activities); + + if ($printReport) { + $reportDate = CRM_Utils_Date::customFormat(date('Y-m-d H:i')); + $template->assign('reportDate', $reportDate); + $contents = $template->fetch('CRM/Case/Audit/Report.tpl'); + } + else { + $contents = $template->fetch('CRM/Case/Audit/Audit.tpl'); + } + return $contents; + } +} diff --git a/CRM/Case/Audit/AuditConfig.php b/CRM/Case/Audit/AuditConfig.php new file mode 100644 index 0000000000..02bfafe76f --- /dev/null +++ b/CRM/Case/Audit/AuditConfig.php @@ -0,0 +1,226 @@ +filename = $filename; + + // set some defaults + $this->completionLabel = "Status"; + $this->completionValue = "Completed"; + $this->sortByLabels = array("Actual Date", "Due Date"); + $this->ifBlanks = array(); + + $this->loadConfig(); + } + + public function getCompletionValue() { + return $this->completionValue; + } + + public function getCompletionLabel() { + return $this->completionLabel; + } + + public function getSortByLabels() { + return $this->sortByLabels; + } + + public function getIfBlanks() { + return $this->ifBlanks; + } + + public function loadConfig() { + $this->regionFieldList = array(); + $this->includeRules = array(); + + $doc = new DOMDocument(); + if ($doc->load(dirname(__FILE__) . '/' . $this->filename)) { + $regions = $doc->getElementsByTagName("region"); + foreach ($regions as $region) { + $regionName = $region->getAttribute("name"); + $this->regionFieldList[$regionName] = array(); + + // Inclusion/exclusion settings + $includeRule = $region->getAttribute("includeRule"); + if (empty($includeRule)) { + $includeRule = 'include'; + } + $this->includeRules[$regionName] = array('rule' => $includeRule); + if ($includeRule == 'exclude') { + $altRegion = $region->getAttribute("exclusionCorrespondingRegion"); + $this->includeRules[$regionName]['altRegion'] = $altRegion; + } + + // Time component display settings + $includeTime = $region->getAttribute("includeTime"); + if (empty($includeTime)) { + $includeTime = 'false'; + } + $this->includeRules[$regionName]['includeTime'] = $includeTime; + + $fieldCount = 0; + $fields = $region->getElementsByTagName("field"); + foreach ($fields as $field) { + /* Storing them this way, which is backwards to how you might normally + have arrays with a numeric key and a text value, ends up making things better + in the other functions, in particular the sorting and also inRegion should end + up being more efficient (searching for a key instead of a value). */ + + $this->regionFieldList[$regionName][$field->nodeValue] = $fieldCount; + + // Field-level overrides of time component display settings + $includeTime = $field->getAttribute("includeTime"); + if (!empty($includeTime)) { + $this->regionFieldList[$regionName][$field->nodeValue]['includeTime'] = $includeTime; + } + + // ifBlank attribute + $ifBlank = $field->getAttribute("ifBlank"); + if (!empty($ifBlank)) { + $this->ifBlanks[$regionName][$field->nodeValue] = $ifBlank; + } + + $fieldCount++; + } + } + + $completionStatus = $doc->getElementsByTagName("completionStatus"); + if (!empty($completionStatus)) { + $label_elements = $completionStatus->item(0)->getElementsByTagName("label"); + $this->completionLabel = $label_elements->item(0)->nodeValue; + + $value_elements = $completionStatus->item(0)->getElementsByTagName("value"); + $this->completionValue = $value_elements->item(0)->nodeValue; + } + + $sortElement = $doc->getElementsByTagName("sortByLabels"); + if (!empty($sortElement)) { + $this->sortByLabels = array(); + $label_elements = $sortElement->item(0)->getElementsByTagName("label"); + foreach ($label_elements as $ele) { + $this->sortByLabels[] = $ele->nodeValue; + } + } + } + } + + /* inRegion + * + * Check if label $n is explicitly listed in region $r in the config. + */ + + public function inRegion($n, $r) { + if (empty($this->regionFieldList[$r])) { + return FALSE; + } + else { + return array_key_exists($n, $this->regionFieldList[$r]); + } + } + + /* includeInRegion + * + * Should field $n be included in region $r, taking into account exclusion rules. + */ + + public function includeInRegion($n, $r) { + $add_it = FALSE; + $rules = $this->includeRules[$r]; + if ($rules['rule'] == 'exclude') { + if (!$this->inRegion($n, $r) && !$this->inRegion($n, $rules['altRegion'])) { + $add_it = TRUE; + } + } + elseif ($this->inRegion($n, $r)) { + $add_it = TRUE; + } + return $add_it; + } + + /* includeTime + * + * Should the time component of field $n in region $r be displayed? + */ + + public function includeTime($n, $r) { + $retval = FALSE; + if (empty($this->regionFieldList[$r][$n]['includeTime'])) { + // No field-level override, so look at the region's settings + if (!empty($this->includeRules[$r]['includeTime'])) { + $retval = $this->includeRules[$r]['includeTime']; + } + } + else { + $retval = $this->regionFieldList[$r][$n]['includeTime']; + } + + // There's a mix of strings and boolean, so convert any strings. + if ($retval == 'false') { + $retval = FALSE; + } + elseif ($retval == 'true') { + $retval = TRUE; + } + + return $retval; + } + + /* getRegions + * + * Return a list of all the regions in the config file. + */ + + public function getRegions() { + return array_keys($this->regionFieldList); + } + + /* sort + * + * Sort a group of fields for a given region according to the order in the config. + * The array to be sorted should have elements that have a member with a key of 'label', and the value should be the field label. + */ + + public function sort(&$f, $r) { + // For exclusion-type regions, there's nothing to do, because we won't have been given any ordering. + if ($this->includeRules[$r]['rule'] == 'exclude') { + return; + } + + $this->sortRegion = $r; + uasort($f, array(&$this, "compareFields")); + } + + /* compareFields + * + * This is intended to be called as a sort callback function, returning whether a field in a region comes before or after another one. + * See also PHP's usort(). + */ + + public function compareFields($a, $b) { + if (empty($this->regionFieldList[$this->sortRegion][$a['label']])) { + $x = 0; + } + else { + $x = $this->regionFieldList[$this->sortRegion][$a['label']]; + } + + if (empty($this->regionFieldList[$this->sortRegion][$b['label']])) { + $y = 0; + } + else { + $y = $this->regionFieldList[$this->sortRegion][$b['label']]; + } + + return $x - $y; + } +} + diff --git a/CRM/Case/Audit/audit.conf.xml b/CRM/Case/Audit/audit.conf.xml new file mode 100644 index 0000000000..9a45b26673 --- /dev/null +++ b/CRM/Case/Audit/audit.conf.xml @@ -0,0 +1,60 @@ + + + + + + + Actual Date + Subject + + + + + + Activity Type + Subject + Actual Date + Created By + Revision + + + + + + + Some field nobody likes + + + + + + + Completed + + + + + + + + + diff --git a/CRM/Case/BAO/Case.php b/CRM/Case/BAO/Case.php new file mode 100644 index 0000000000..c804a7c9c3 --- /dev/null +++ b/CRM/Case/BAO/Case.php @@ -0,0 +1,3069 @@ +copyValues($params); + return $caseDAO->save(); + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $params input parameters to find object + * @param array $values output values of the object + * @param array $ids the array that holds all the db ids + * + * @return CRM_Case_BAO_Case|null the found object or null + * @access public + * @static + */ + static function &getValues(&$params, &$values, &$ids) { + $case = new CRM_Case_BAO_Case(); + + $case->copyValues($params); + + if ($case->find(TRUE)) { + $ids['case'] = $case->id; + CRM_Core_DAO::storeValues($case, $values); + return $case; + } + return NULL; + } + + /** + * takes an associative array and creates a case object + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $ids the array that holds all the db ids + * + * @return object CRM_Case_BAO_Case object + * @access public + * @static + */ + static function &create(&$params) { + $transaction = new CRM_Core_Transaction(); + + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::pre('edit', 'Case', $params['id'], $params); + } + else { + CRM_Utils_Hook::pre('create', 'Case', NULL, $params); + } + + $case = self::add($params); + + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_case', $case->id); + } + + if (is_a($case, 'CRM_Core_Error')) { + $transaction->rollback(); + return $case; + } + + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::post('edit', 'Case', $case->id, $case); + } + else { + CRM_Utils_Hook::post('create', 'Case', $case->id, $case); + } + $transaction->commit(); + + //we are not creating log for case + //since case log can be tracked using log for activity. + return $case; + } + + /** + * Create case contact record + * + * @param array case_id, contact_id + * + * @return object + * @access public + */ + static function addCaseToContact($params) { + $caseContact = new CRM_Case_DAO_CaseContact(); + $caseContact->case_id = $params['case_id']; + $caseContact->contact_id = $params['contact_id']; + $caseContact->find(TRUE); + $caseContact->save(); + + // add to recently viewed + $caseType = CRM_Case_PseudoConstant::caseTypeName($caseContact->case_id, 'label'); + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "action=view&reset=1&id={$caseContact->case_id}&cid={$caseContact->contact_id}&context=home" + ); + + $title = CRM_Contact_BAO_Contact::displayName($caseContact->contact_id) . ' - ' . $caseType['name']; + + $recentOther = array(); + if (CRM_Core_Permission::checkActionPermission('CiviCase', CRM_Core_Action::DELETE)) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/case', + "action=delete&reset=1&id={$caseContact->case_id}&cid={$caseContact->contact_id}&context=home" + ); + } + + // add the recently created case + CRM_Utils_Recent::add($title, + $url, + $caseContact->case_id, + 'Case', + $params['contact_id'], + NULL, + $recentOther + ); + + return $caseContact; + } + + /** + * Delet case contact record + * + * @param int case_id + * + * @return Void + * @access public + */ + static function deleteCaseContact($caseID) { + $caseContact = new CRM_Case_DAO_CaseContact(); + $caseContact->case_id = $caseID; + $caseContact->delete(); + + // delete the recently created Case + $caseRecent = array( + 'id' => $caseID, + 'type' => 'Case', + ); + CRM_Utils_Recent::del($caseRecent); + } + + /** + * This function is used to convert associative array names to values + * and vice-versa. + * + * This function is used by both the web form layer and the api. Note that + * the api needs the name => value conversion, also the view layer typically + * requires value => name conversion + */ + static function lookupValue(&$defaults, $property, &$lookup, $reverse) { + $id = $property . '_id'; + + $src = $reverse ? $property : $id; + $dst = $reverse ? $id : $property; + + if (!array_key_exists($src, $defaults)) { + return FALSE; + } + + $look = $reverse ? array_flip($lookup) : $lookup; + + if (is_array($look)) { + if (!array_key_exists($defaults[$src], $look)) { + return FALSE; + } + } + $defaults[$dst] = $look[$defaults[$src]]; + return TRUE; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. We'll tweak this function to be more + * full featured over a period of time. This is the inverse function of + * create. It also stores all the retrieved values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the name / value pairs + * in a hierarchical manner + * @param array $ids (reference) the array that holds all the db ids + * + * @return object CRM_Case_BAO_Case object + * @access public + * @static + */ + static function retrieve(&$params, &$defaults, &$ids) { + $case = CRM_Case_BAO_Case::getValues($params, $defaults, $ids); + return $case; + } + + /** + * Function to process case activity add/delete + * takes an associative array and + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @access public + * @static + */ + static function processCaseActivity(&$params) { + $caseActivityDAO = new CRM_Case_DAO_CaseActivity(); + $caseActivityDAO->activity_id = $params['activity_id']; + $caseActivityDAO->case_id = $params['case_id']; + + $caseActivityDAO->find(TRUE); + $caseActivityDAO->save(); + } + + /** + * Function to get the case subject for Activity + * + * @param int $activityId activity id + * + * @return case subject or null + * @access public + * @static + */ + static function getCaseSubject($activityId) { + $caseActivity = new CRM_Case_DAO_CaseActivity(); + $caseActivity->activity_id = $activityId; + if ($caseActivity->find(TRUE)) { + return CRM_Core_DAO::getFieldValue('CRM_Case_BAO_Case', $caseActivity->case_id, 'subject'); + } + return NULL; + } + + /** + * Function to get the case type. + * + * @param int $caseId + * + * @return case type + * @access public + * @static + */ + static function getCaseType($caseId, $colName = 'label') { + $caseType = NULL; + if (!$caseId) { + return $caseType; + } + + $sql = " + SELECT ov.{$colName} + FROM civicrm_case ca + INNER JOIN civicrm_option_group og ON og.name='case_type' + INNER JOIN civicrm_option_value ov ON ( ca.case_type_id=ov.value AND ov.option_group_id=og.id ) + WHERE ca.id = %1"; + + $params = array(1 => array($caseId, 'Integer')); + + return CRM_Core_DAO::singleValueQuery($sql, $params); + } + + /** + * Delete the record that are associated with this case + * record are deleted from case + * + * @param int $caseId id of the case to delete + * + * @return void + * @access public + * @static + */ + static function deleteCase($caseId, $moveToTrash = FALSE) { + CRM_Utils_Hook::pre('delete', 'Case', $caseId, CRM_Core_DAO::$_nullArray); + + //delete activities + $activities = self::getCaseActivityDates($caseId); + if ($activities) { + foreach ($activities as $value) { + CRM_Activity_BAO_Activity::deleteActivity($value, $moveToTrash); + } + } + + if (!$moveToTrash) { + $transaction = new CRM_Core_Transaction(); + } + $case = new CRM_Case_DAO_Case(); + $case->id = $caseId; + if (!$moveToTrash) { + $result = $case->delete(); + $transaction->commit(); + } + else { + $result = $case->is_deleted = 1; + $case->save(); + } + + if ($result) { + // CRM-7364, disable relationships + self::enableDisableCaseRelationships($caseId, FALSE); + + CRM_Utils_Hook::post('delete', 'Case', $caseId, $case); + + // remove case from recent items. + $caseRecent = array( + 'id' => $caseId, + 'type' => 'Case', + ); + CRM_Utils_Recent::del($caseRecent); + return TRUE; + } + + return FALSE; + } + + /** + * Function to enable disable case related relationships + * + * @param int $caseId case id + * @param boolean $enable action + * + * @return void + * @access public + * @static + */ + static function enableDisableCaseRelationships($caseId, $enable) { + $contactIds = self::retrieveContactIdsByCaseId($caseId); + if (!empty($contactIds)) { + foreach ($contactIds as $cid) { + $roles = self::getCaseRoles($cid, $caseId); + if (!empty($roles)) { + $relationshipIds = implode(',', array_keys($roles)); + $enable = (int)$enable; + $query = "UPDATE civicrm_relationship SET is_active = {$enable} + WHERE id IN ( {$relationshipIds} )"; + CRM_Core_DAO::executeQuery($query); + } + } + } + } + + /** + * Delete the activities related to case + * + * @param int $activityId id of the activity + * + * @return void + * @access public + * @static + */ + static function deleteCaseActivity($activityId) { + $case = new CRM_Case_DAO_CaseActivity(); + $case->activity_id = $activityId; + $case->delete(); + } + + /** + * Retrieve contact_id by case_id + * + * @param int $caseId ID of the case + * + * @return array + * @access public + * + */ + static function retrieveContactIdsByCaseId($caseId, $contactID = NULL) { + $caseContact = new CRM_Case_DAO_CaseContact(); + $caseContact->case_id = $caseId; + $caseContact->find(); + $contactArray = array(); + $count = 1; + while ($caseContact->fetch()) { + if ($contactID != $caseContact->contact_id) { + $contactArray[$count] = $caseContact->contact_id; + $count++; + } + } + + return $contactArray; + } + + /** + * Look up a case using an activity ID + * + * @param $activity_id + * + * @return int, case ID + */ + static function getCaseIdByActivityId($activityId) { + $originalId = CRM_Core_DAO::singleValueQuery( + 'SELECT original_id FROM civicrm_activity WHERE id = %1', + array('1' => array($activityId, 'Integer')) + ); + $caseId = CRM_Core_DAO::singleValueQuery( + 'SELECT case_id FROM civicrm_case_activity WHERE activity_id in (%1,%2)', + array( + '1' => array($activityId, 'Integer'), + '2' => array($originalId ? $originalId : $activityId, 'Integer'), + ) + ); + return $caseId; + } + + /** + * Retrieve contact names by caseId + * + * @param int $caseId ID of the case + * + * @return array + * + * @access public + * + */ + static function getContactNames($caseId) { + $contactNames = array(); + if (!$caseId) { + return $contactNames; + } + + $query = " + SELECT contact_a.sort_name name, + contact_a.display_name as display_name, + contact_a.id cid, + contact_a.birth_date as birth_date, + ce.email as email, + cp.phone as phone + FROM civicrm_contact contact_a + LEFT JOIN civicrm_case_contact ON civicrm_case_contact.contact_id = contact_a.id + LEFT JOIN civicrm_email ce ON ( ce.contact_id = contact_a.id AND ce.is_primary = 1) + LEFT JOIN civicrm_phone cp ON ( cp.contact_id = contact_a.id AND cp.is_primary = 1) + WHERE civicrm_case_contact.case_id = %1"; + + $dao = CRM_Core_DAO::executeQuery($query, + array(1 => array($caseId, 'Integer')) + ); + while ($dao->fetch()) { + $contactNames[$dao->cid]['contact_id'] = $dao->cid; + $contactNames[$dao->cid]['sort_name'] = $dao->name; + $contactNames[$dao->cid]['display_name'] = $dao->display_name; + $contactNames[$dao->cid]['email'] = $dao->email; + $contactNames[$dao->cid]['phone'] = $dao->phone; + $contactNames[$dao->cid]['birth_date'] = $dao->birth_date; + $contactNames[$dao->cid]['role'] = ts('Client'); + } + + return $contactNames; + } + + /** + * Retrieve case_id by contact_id + * + * @param int $contactId ID of the contact + * @param boolean $includeDeleted include the deleted cases in result + * + * @return array + * + * @access public + * + */ + static function retrieveCaseIdsByContactId($contactID, $includeDeleted = FALSE) { + $query = " +SELECT ca.id as id +FROM civicrm_case_contact cc +INNER JOIN civicrm_case ca ON cc.case_id = ca.id +WHERE cc.contact_id = %1 +"; + if (!$includeDeleted) { + $query .= " AND ca.is_deleted = 0"; + } + + $params = array(1 => array($contactID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $caseArray = array(); + while ($dao->fetch()) { + $caseArray[] = $dao->id; + } + + $dao->free(); + return $caseArray; + } + + static function getCaseActivityQuery($type = 'upcoming', $userID = NULL, $condition = NULL, $isDeleted = 0) { + if (!$userID) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + } + + $actStatus = array_flip(CRM_Core_PseudoConstant::activityStatus('name')); + $scheduledStatusId = $actStatus['Scheduled']; + + $query = "SELECT +civicrm_case.id as case_id, +civicrm_case.subject as case_subject, +civicrm_contact.id as contact_id, +civicrm_contact.sort_name as sort_name, +civicrm_phone.phone as phone, +civicrm_contact.contact_type as contact_type, +civicrm_contact.contact_sub_type as contact_sub_type, +t_act.activity_type_id, +cov_type.label as case_type, +cov_type.name as case_type_name, +cov_status.label as case_status, +cov_status.label as case_status_name, +t_act.status_id, +civicrm_case.start_date as case_start_date, +case_relation_type.label_b_a as case_role, "; + + if ($type == 'upcoming') { + $query .= " +t_act.desired_date as case_scheduled_activity_date, +t_act.id as case_scheduled_activity_id, +t_act.act_type_name as case_scheduled_activity_type_name, +t_act.act_type AS case_scheduled_activity_type "; + } + elseif ($type == 'recent') { + $query .= " +t_act.desired_date as case_recent_activity_date, +t_act.id as case_recent_activity_id, +t_act.act_type_name as case_recent_activity_type_name, +t_act.act_type AS case_recent_activity_type "; + } + + $query .= " FROM civicrm_case + INNER JOIN civicrm_case_contact ON civicrm_case.id = civicrm_case_contact.case_id + INNER JOIN civicrm_contact ON civicrm_case_contact.contact_id = civicrm_contact.id "; + + if ($type == 'upcoming') { + // This gets the earliest activity per case that's scheduled within 14 days from now. + // Note we have an inner select to get the min activity id in order to remove duplicates in case there are two with the same datetime. + // In this case we don't really care which one, so min(id) works. + // optimized in CRM-11837 + $query .= " INNER JOIN +( + SELECT case_id, act.id, activity_date_time AS desired_date, activity_type_id, status_id, aov.name AS act_type_name, aov.label AS act_type + FROM ( + SELECT * + FROM ( + SELECT * + FROM civicrm_view_case_activity_upcoming + ORDER BY activity_date_time ASC, id ASC + ) AS upcomingOrdered + GROUP BY case_id + ) AS act + LEFT JOIN civicrm_option_group aog ON aog.name='activity_type' + LEFT JOIN civicrm_option_value aov ON ( aov.option_group_id = aog.id AND aov.value = act.activity_type_id ) +) AS t_act +"; + } + elseif ($type == 'recent') { + // Similarly, the most recent activity in the past 14 days, and exclude scheduled. + //improve query performance - CRM-10598 + $query .= " INNER JOIN +( + SELECT case_id, act.id, activity_date_time AS desired_date, activity_type_id, status_id, aov.name AS act_type_name, aov.label AS act_type + FROM ( + SELECT * + FROM ( + SELECT * + FROM civicrm_view_case_activity_recent + ORDER BY activity_date_time DESC, id ASC + ) AS recentOrdered + GROUP BY case_id + ) AS act +LEFT JOIN civicrm_option_group aog ON aog.name='activity_type' + LEFT JOIN civicrm_option_value aov ON ( aov.option_group_id = aog.id AND aov.value = act.activity_type_id ) +) AS t_act "; + } + + $query .= " + ON t_act.case_id = civicrm_case.id + LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary=1) + LEFT JOIN civicrm_relationship case_relationship + ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} + AND case_relationship.case_id = civicrm_case.id ) + + LEFT JOIN civicrm_relationship_type case_relation_type + ON ( case_relation_type.id = case_relationship.relationship_type_id + AND case_relation_type.id = case_relationship.relationship_type_id ) + + LEFT JOIN civicrm_option_group cog_type + ON cog_type.name = 'case_type' + + LEFT JOIN civicrm_option_value cov_type + ON ( civicrm_case.case_type_id = cov_type.value + AND cog_type.id = cov_type.option_group_id ) + + LEFT JOIN civicrm_option_group cog_status + ON cog_status.name = 'case_status' + + LEFT JOIN civicrm_option_value cov_status + ON ( civicrm_case.status_id = cov_status.value + AND cog_status.id = cov_status.option_group_id ) +"; + + if ($condition) { + // CRM-8749 backwards compatibility - callers of this function expect to start $condition with "AND" + $query .= " WHERE (1) $condition "; + } + + if ($type == 'upcoming') { + $query .= " ORDER BY case_scheduled_activity_date ASC "; + } + elseif ($type == 'recent') { + $query .= " ORDER BY case_recent_activity_date ASC "; + } + + return $query; + } + + /** + * Retrieve cases related to particular contact or whole contact + * used in Dashboad and Tab + * + * @param boolean $allCases + * + * @param int $userID + * + * @param String $type /upcoming,recent,all/ + * + * @return array Array of Cases + * + * @access public + * + */ + static function getCases($allCases = TRUE, $userID = NULL, $type = 'upcoming', $context = 'dashboard') { + $condition = NULL; + $casesList = array(); + + //validate access for own cases. + if (!self::accessCiviCase()) { + return $casesList; + } + + if (!$userID) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + } + + //validate access for all cases. + if ($allCases && !CRM_Core_Permission::check('access all cases and activities')) { + $allCases = FALSE; + } + + + $condition = " AND civicrm_case.is_deleted = 0 "; + + if (!$allCases) { + $condition .= " AND case_relationship.contact_id_b = {$userID} "; + } + + if ($type == 'upcoming') { + $closedId = CRM_Core_OptionGroup::getValue('case_status', 'Closed', 'name'); + $condition .= " +AND civicrm_case.status_id != $closedId"; + } + + $query = self::getCaseActivityQuery($type, $userID, $condition); + + $queryParams = array(); + $result = CRM_Core_DAO::executeQuery($query, + $queryParams + ); + + $caseStatus = CRM_Core_OptionGroup::values('case_status', FALSE, FALSE, FALSE, " AND v.name = 'Urgent' "); + + $resultFields = array( + 'contact_id', + 'contact_type', + 'sort_name', + 'phone', + 'case_id', + 'case_subject', + 'case_type', + 'case_type_name', + 'status_id', + 'case_status', + 'case_status_name', + 'activity_type_id', + 'case_start_date', + 'case_role', + ); + + if ($type == 'upcoming') { + $resultFields[] = 'case_scheduled_activity_date'; + $resultFields[] = 'case_scheduled_activity_type_name'; + $resultFields[] = 'case_scheduled_activity_type'; + $resultFields[] = 'case_scheduled_activity_id'; + } + elseif ($type == 'recent') { + $resultFields[] = 'case_recent_activity_date'; + $resultFields[] = 'case_recent_activity_type_name'; + $resultFields[] = 'case_recent_activity_type'; + $resultFields[] = 'case_recent_activity_id'; + } + + // we're going to use the usual actions, so doesn't make sense to duplicate definitions + $actions = CRM_Case_Selector_Search::links(); + + + // check is the user has view/edit signer permission + $permissions = array(CRM_Core_Permission::VIEW); + if (CRM_Core_Permission::check('access all cases and activities') || + (!$allCases && CRM_Core_Permission::check('access my cases and activities')) + ) { + $permissions[] = CRM_Core_Permission::EDIT; + } + if (CRM_Core_Permission::check('delete in CiviCase')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + while ($result->fetch()) { + foreach ($resultFields as $donCare => $field) { + $casesList[$result->case_id][$field] = $result->$field; + if ($field == 'contact_type') { + $casesList[$result->case_id]['contact_type_icon'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type + ); + $casesList[$result->case_id]['action'] = CRM_Core_Action::formLink($actions['primaryActions'], $mask, + array( + 'id' => $result->case_id, + 'cid' => $result->contact_id, + 'cxt' => $context, + ) + ); + $casesList[$result->case_id]['moreActions'] = CRM_Core_Action::formLink($actions['moreActions'], + $mask, + array( + 'id' => $result->case_id, + 'cid' => $result->contact_id, + 'cxt' => $context, + ), + ts('more'), + TRUE + ); + } + elseif ($field == 'case_status') { + if (in_array($result->$field, $caseStatus)) { + $casesList[$result->case_id]['class'] = "status-urgent"; + } + else { + $casesList[$result->case_id]['class'] = "status-normal"; + } + } + } + //CRM-4510. + $caseManagerContact = self::getCaseManagerContact($result->case_type_name, $result->case_id); + if (!empty($caseManagerContact)) { + $casesList[$result->case_id]['casemanager_id'] = CRM_Utils_Array::value('casemanager_id', $caseManagerContact); + $casesList[$result->case_id]['casemanager'] = CRM_Utils_Array::value('casemanager', $caseManagerContact); + } + + //do check user permissions for edit/view activity. + if (($actId = CRM_Utils_Array::value('case_scheduled_activity_id', $casesList[$result->case_id])) || + ($actId = CRM_Utils_Array::value('case_recent_activity_id', $casesList[$result->case_id])) + ) { + $casesList[$result->case_id]["case_{$type}_activity_editable"] = self::checkPermission($actId, + 'edit', + $casesList[$result->case_id]['activity_type_id'], $userID + ); + $casesList[$result->case_id]["case_{$type}_activity_viewable"] = self::checkPermission($actId, + 'view', + $casesList[$result->case_id]['activity_type_id'], $userID + ); + } + } + + return $casesList; + } + + /** + * Function to get the summary of cases counts by type and status. + */ + static function getCasesSummary($allCases = TRUE, $userID) { + $caseSummary = array(); + + //validate access for civicase. + if (!self::accessCiviCase()) { + return $caseSummary; + } + + //validate access for all cases. + if ($allCases && !CRM_Core_Permission::check('access all cases and activities')) { + $allCases = FALSE; + } + + $caseTypes = CRM_Case_PseudoConstant::caseType(); + $caseStatuses = CRM_Case_PseudoConstant::caseStatus(); + $caseTypes = array_flip($caseTypes); + + // get statuses as headers for the table + $url = CRM_Utils_System::url('civicrm/case/search', "reset=1&force=1&all=1&status="); + foreach ($caseStatuses as $key => $name) { + $caseSummary['headers'][$key]['status'] = $name; + $caseSummary['headers'][$key]['url'] = $url . $key; + } + + // build rows with actual data + $rows = array(); + $myGroupByClause = $mySelectClause = $myCaseFromClause = $myCaseWhereClause = ''; + + if ($allCases) { + $userID = 'null'; + $all = 1; + $case_owner = 1; + } + else { + $all = 0; + $case_owner = 2; + $myCaseWhereClause = " AND case_relationship.contact_id_b = {$userID}"; + $myGroupByClause = " GROUP BY CONCAT(case_relationship.case_id,'-',case_relationship.contact_id_b)"; + } + + $seperator = CRM_Core_DAO::VALUE_SEPARATOR; + + $query = " +SELECT case_status.label AS case_status, status_id, case_type.label AS case_type, + REPLACE(case_type_id,'{$seperator}','') AS case_type_id, case_relationship.contact_id_b + FROM civicrm_case + LEFT JOIN civicrm_option_group option_group_case_type ON ( option_group_case_type.name = 'case_type' ) + LEFT JOIN civicrm_option_value case_type ON ( civicrm_case.case_type_id = case_type.value + AND option_group_case_type.id = case_type.option_group_id ) + LEFT JOIN civicrm_option_group option_group_case_status ON ( option_group_case_status.name = 'case_status' ) + LEFT JOIN civicrm_option_value case_status ON ( civicrm_case.status_id = case_status.value + AND option_group_case_status.id = case_status.option_group_id ) + LEFT JOIN civicrm_relationship case_relationship ON ( case_relationship.case_id = civicrm_case.id + AND case_relationship.contact_id_b = {$userID}) + WHERE is_deleted =0 +{$myCaseWhereClause} {$myGroupByClause}"; + + $res = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + while ($res->fetch()) { + if (CRM_Utils_Array::value($res->case_type, $rows) && CRM_Utils_Array::value($res->case_status, $rows[$res->case_type])) { + $rows[$res->case_type][$res->case_status]['count'] = $rows[$res->case_type][$res->case_status]['count'] + 1; + } + else { + $rows[$res->case_type][$res->case_status] = array( + 'count' => 1, + 'url' => CRM_Utils_System::url('civicrm/case/search', + "reset=1&force=1&status={$res->status_id}&type={$res->case_type_id}&case_owner={$case_owner}" + ), + ); + } + } + $caseSummary['rows'] = array_merge($caseTypes, $rows); + + return $caseSummary; + } + + /** + * Function to get Case roles + * + * @param int $contactID contact id + * @param int $caseID case id + * @return returns case role / relationships + * + * @static + */ + static function getCaseRoles($contactID, $caseID, $relationshipID = NULL) { + $query = ' + SELECT civicrm_relationship.id as civicrm_relationship_id, + civicrm_contact.sort_name as sort_name, + civicrm_email.email as email, + civicrm_phone.phone as phone, + civicrm_relationship.contact_id_b as civicrm_contact_id, + civicrm_relationship.contact_id_a as client_id, + civicrm_relationship_type.label_a_b as relation, + civicrm_relationship_type.id as relation_type + FROM civicrm_relationship + INNER JOIN civicrm_relationship_type ON civicrm_relationship.relationship_type_id = civicrm_relationship_type.id + INNER JOIN civicrm_contact ON civicrm_relationship.contact_id_b = civicrm_contact.id + LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary = 1) + LEFT JOIN civicrm_email ON (civicrm_email.contact_id = civicrm_contact.id ) + WHERE civicrm_relationship.contact_id_a = %1 AND civicrm_relationship.case_id = %2'; + + + $params = array( + 1 => array($contactID, 'Positive'), + 2 => array($caseID, 'Positive'), + ); + + if ($relationshipID) { + $query .= ' AND civicrm_relationship.id = %3 '; + $params[3] = array($relationshipID, 'Integer'); + } + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $values = array(); + while ($dao->fetch()) { + $rid = $dao->civicrm_relationship_id; + $values[$rid]['cid'] = $dao->civicrm_contact_id; + $values[$rid]['relation'] = $dao->relation; + $values[$rid]['name'] = $dao->sort_name; + $values[$rid]['email'] = $dao->email; + $values[$rid]['phone'] = $dao->phone; + $values[$rid]['relation_type'] = $dao->relation_type; + $values[$rid]['rel_id'] = $dao->civicrm_relationship_id; + $values[$rid]['client_id'] = $dao->client_id; + } + + $dao->free(); + return $values; + } + + /** + * Function to get Case Activities + * + * @param int $caseID case id + * @param array $params posted params + * @param int $contactID contact id + * + * @return returns case activities + * + * @static + */ + static function getCaseActivity($caseID, &$params, $contactID, $context = NULL, $userID = NULL, $type = NULL) { + $values = array(); + + // CRM-5081 - formatting the dates to omit seconds. + // Note the 00 in the date format string is needed otherwise later on it thinks scheduled ones are overdue. + $select = "SELECT count(ca.id) as ismultiple, ca.id as id, + ca.activity_type_id as type, + ca.activity_type_id as activity_type_id, + cc.sort_name as reporter, + cc.id as reporter_id, + acc.sort_name AS assignee, + acc.id AS assignee_id, + DATE_FORMAT(IF(ca.activity_date_time < NOW() AND ca.status_id=ov.value, + ca.activity_date_time, + DATE_ADD(NOW(), INTERVAL 1 YEAR) + ), '%Y%m%d%H%i00') as overdue_date, + DATE_FORMAT(ca.activity_date_time, '%Y%m%d%H%i00') as display_date, + ca.status_id as status, + ca.subject as subject, + ca.is_deleted as deleted, + ca.priority_id as priority, + ca.weight as weight, + GROUP_CONCAT(ef.file_id) as attachment_ids "; + + $from = 'FROM civicrm_case_activity cca + INNER JOIN civicrm_activity ca ON ca.id = cca.activity_id + INNER JOIN civicrm_contact cc ON cc.id = ca.source_contact_id + INNER JOIN civicrm_option_group cog ON cog.name = "activity_type" + INNER JOIN civicrm_option_value cov ON cov.option_group_id = cog.id + AND cov.value = ca.activity_type_id AND cov.is_active = 1 + LEFT JOIN civicrm_entity_file ef on ef.entity_table = "civicrm_activity" AND ef.entity_id = ca.id + LEFT OUTER JOIN civicrm_option_group og ON og.name="activity_status" + LEFT OUTER JOIN civicrm_option_value ov ON ov.option_group_id=og.id AND ov.name="Scheduled" + LEFT JOIN civicrm_activity_assignment caa + ON caa.activity_id = ca.id + LEFT JOIN civicrm_contact acc ON acc.id = caa.assignee_contact_id '; + + $where = 'WHERE cca.case_id= %1 + AND ca.is_current_revision = 1'; + + if (CRM_Utils_Array::value('reporter_id', $params)) { + $where .= " AND ca.source_contact_id = " . CRM_Utils_Type::escape($params['reporter_id'], 'Integer'); + } + + if (CRM_Utils_Array::value('status_id', $params)) { + $where .= " AND ca.status_id = " . CRM_Utils_Type::escape($params['status_id'], 'Integer'); + } + + if (CRM_Utils_Array::value('activity_deleted', $params)) { + $where .= " AND ca.is_deleted = 1"; + } + else { + $where .= " AND ca.is_deleted = 0"; + } + + + if (CRM_Utils_Array::value('activity_type_id', $params)) { + $where .= " AND ca.activity_type_id = " . CRM_Utils_Type::escape($params['activity_type_id'], 'Integer'); + } + + if (CRM_Utils_Array::value('activity_date_low', $params)) { + $fromActivityDate = CRM_Utils_Type::escape(CRM_Utils_Date::processDate($params['activity_date_low']), 'Date'); + } + if (CRM_Utils_Array::value('activity_date_high', $params)) { + $toActivityDate = CRM_Utils_Type::escape(CRM_Utils_Date::processDate($params['activity_date_high']), 'Date'); + $toActivityDate = $toActivityDate ? $toActivityDate + 235959 : NULL; + } + + if (!empty($fromActivityDate)) { + $where .= " AND ca.activity_date_time >= '{$fromActivityDate}'"; + } + + if (!empty($toActivityDate)) { + $where .= " AND ca.activity_date_time <= '{$toActivityDate}'"; + } + + // hack to handle to allow initial sorting to be done by query + if (CRM_Utils_Array::value('sortname', $params) == 'undefined') { + $params['sortname'] = NULL; + } + + if (CRM_Utils_Array::value('sortorder', $params) == 'undefined') { + $params['sortorder'] = NULL; + } + + $sortname = CRM_Utils_Array::value('sortname', $params); + $sortorder = CRM_Utils_Array::value('sortorder', $params); + + $groupBy = " GROUP BY ca.id "; + + if (!$sortname AND !$sortorder) { + // CRM-5081 - added id to act like creation date + $orderBy = " ORDER BY overdue_date ASC, display_date DESC, weight DESC"; + } + else { + $orderBy = " ORDER BY {$sortname} {$sortorder}"; + if ($sortname != 'display_date') { + $orderBy .= ', display_date DESC'; + } + } + + $page = CRM_Utils_Array::value('page', $params); + $rp = CRM_Utils_Array::value('rp', $params); + + if (!$page) { + + $page = 1; + + } + if (!$rp) { + $rp = 10; + } + + $start = (($page - 1) * $rp); + + $query = $select . $from . $where . $groupBy . $orderBy; + + $params = array(1 => array($caseID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $params['total'] = $dao->N; + + //FIXME: need to optimize/cache these queries + $limit = " LIMIT $start, $rp"; + $query .= $limit; + $dao = CRM_Core_DAO::executeQuery($query, $params); + + + $activityTypes = CRM_Case_PseudoConstant::caseActivityType(FALSE, TRUE); + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + $activityPriority = CRM_Core_PseudoConstant::priority(); + + $url = CRM_Utils_System::url("civicrm/case/activity", + "reset=1&cid={$contactID}&caseid={$caseID}", FALSE, NULL, FALSE + ); + + $contextUrl = ''; + if ($context == 'fulltext') { + $contextUrl = "&context={$context}"; + } + $editUrl = "{$url}&action=update{$contextUrl}"; + $deleteUrl = "{$url}&action=delete{$contextUrl}"; + $restoreUrl = "{$url}&action=renew{$contextUrl}"; + $viewTitle = ts('View this activity.'); + $statusTitle = ts('Edit status'); + + $emailActivityTypeIDs = array( + 'Email' => CRM_Core_OptionGroup::getValue('activity_type', + 'Email', + 'name' + ), + 'Inbound Email' => CRM_Core_OptionGroup::getValue('activity_type', + 'Inbound Email', + 'name' + ), + ); + + $emailActivityTypeIDs = array( + 'Email' => CRM_Core_OptionGroup::getValue('activity_type', + 'Email', + 'name' + ), + 'Inbound Email' => CRM_Core_OptionGroup::getValue('activity_type', + 'Inbound Email', + 'name' + ), + ); + + $caseDeleted = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'is_deleted'); + + // define statuses which are handled like Completed status (others are assumed to be handled like Scheduled status) + $compStatusValues = array(); + $compStatusNames = array('Completed', 'Left Message', 'Cancelled', 'Unreachable', 'Not Required'); + foreach ($compStatusNames as $name) { + $compStatusValues[] = CRM_Core_OptionGroup::getValue('activity_status', $name, 'name'); + } + $contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", + "reset=1&cid=", FALSE, NULL, FALSE + ); + $hasViewContact = CRM_Core_Permission::giveMeAllACLs(); + $clientIds = self::retrieveContactIdsByCaseId($caseID); + + if (!$userID) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + } + + while ($dao->fetch()) { + + $allowView = self::checkPermission($dao->id, 'view', $dao->activity_type_id, $userID); + $allowEdit = self::checkPermission($dao->id, 'edit', $dao->activity_type_id, $userID); + $allowDelete = self::checkPermission($dao->id, 'delete', $dao->activity_type_id, $userID); + + //do not have sufficient permission + //to access given case activity record. + if (!$allowView && !$allowEdit && !$allowDelete) { + continue; + } + + $values[$dao->id]['id'] = $dao->id; + $values[$dao->id]['type'] = $activityTypes[$dao->type]['label']; + + $reporterName = $dao->reporter; + if ($hasViewContact) { + $reporterName = '' . $dao->reporter . ''; + } + $values[$dao->id]['reporter'] = $reporterName; + + $targetNames = CRM_Activity_BAO_ActivityTarget::getTargetNames($dao->id); + $targetContactUrls = $withContacts = array(); + foreach ($targetNames as $targetId => $targetName) { + if (!in_array($targetId, $clientIds)) { + $withContacts[$targetId] = $targetName; + } + } + foreach ($withContacts as $cid => $name) { + if ($hasViewContact) { + $name = '' . $name . ''; + } + $targetContactUrls[] = $name; + } + $values[$dao->id]['with_contacts'] = implode('; ', $targetContactUrls); + + $values[$dao->id]['display_date'] = CRM_Utils_Date::customFormat($dao->display_date); + $values[$dao->id]['status'] = $activityStatus[$dao->status]; + + //check for view activity. + $subject = (empty($dao->subject)) ? '(' . ts('no subject') . ')' : $dao->subject; + if ($allowView) { + $subject = '' . $subject . ''; + } + $values[$dao->id]['subject'] = $subject; + + // add activity assignee to activity selector. CRM-4485. + if (isset($dao->assignee)) { + if ($dao->ismultiple == 1) { + if ($dao->reporter_id != $dao->assignee_id) { + $values[$dao->id]['reporter'] .= ($hasViewContact) ? ' / ' . "$dao->assignee" : ' / ' . $dao->assignee; + } + $values[$dao->id]['assignee'] = $dao->assignee; + } + else { + $values[$dao->id]['reporter'] .= ' / ' . ts('(multiple)'); + } + } + $url = ""; + $additionalUrl = "&id={$dao->id}"; + if (!$dao->deleted) { + //hide edit link of activity type email.CRM-4530. + if (!in_array($dao->type, $emailActivityTypeIDs)) { + //hide Edit link if activity type is NOT editable (special case activities).CRM-5871 + if ($allowEdit) { + $url = '' . ts('Edit') . ' '; + } + } + if ($allowDelete) { + if (!empty($url)) { + $url .= " | "; + } + $url .= '' . ts('Delete') . ''; + } + } + elseif (!$caseDeleted) { + $url = '' . ts('Restore') . ''; + $values[$dao->id]['status'] = $values[$dao->id]['status'] . '
    (deleted)'; + } + + //check for operations. + if (self::checkPermission($dao->id, 'Move To Case', $dao->activity_type_id)) { + $url .= " | " . '' . ts('Move To Case') . ' '; + } + if (self::checkPermission($dao->id, 'Copy To Case', $dao->activity_type_id)) { + $url .= " | " . '' . ts('Copy To Case') . ' '; + } + // if there are file attachments we will return how many and, if only one, add a link to it + if(!empty($dao->attachment_ids)){ + $attachmentIDs = explode(',',$dao->attachment_ids); + $values[$dao->id]['no_attachments'] = count($attachmentIDs); + if($values[$dao->id]['no_attachments'] == 1){ + // if there is only one it's easy to do a link - otherwise just flag it + $attachmentViewUrl = CRM_Utils_System::url( + "civicrm/file", + "reset=1&eid=" . $dao->id . "&id=" . $dao->attachment_ids, + FALSE, + NULL, + FALSE + ); + $url .= " | " . "" . ts('View Attachment') . ' '; + } + } + + + $values[$dao->id]['links'] = $url; + $values[$dao->id]['class'] = ""; + + if (!empty($dao->priority)) { + if ($dao->priority == CRM_Core_OptionGroup::getValue('priority', 'Urgent', 'name')) { + $values[$dao->id]['class'] = $values[$dao->id]['class'] . "priority-urgent "; + } + elseif ($dao->priority == CRM_Core_OptionGroup::getValue('priority', 'Low', 'name')) { + $values[$dao->id]['class'] = $values[$dao->id]['class'] . "priority-low "; + } + } + + if (CRM_Utils_Array::crmInArray($dao->status, $compStatusValues)) { + $values[$dao->id]['class'] = $values[$dao->id]['class'] . " status-completed"; + } + else { + if (CRM_Utils_Date::overdue($dao->display_date)) { + $values[$dao->id]['class'] = $values[$dao->id]['class'] . " status-overdue"; + } + else { + $values[$dao->id]['class'] = $values[$dao->id]['class'] . " status-scheduled"; + } + } + + if ($allowEdit) { + $values[$dao->id]['status'] = '' . $values[$dao->id]['status'] . ''; + } + } + $dao->free(); + + return $values; + } + + /** + * Function to get Case Related Contacts + * + * @param int $caseID case id + * @param boolean $skipDetails if true include details of contacts + * + * @return returns $searchRows array of returnproperties + * + * @static + */ + static function getRelatedContacts($caseID, $skipDetails = FALSE) { + $values = array(); + $query = 'SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, crt.label_b_a as role, ce.email + FROM civicrm_relationship cr + LEFT JOIN civicrm_relationship_type crt ON crt.id = cr.relationship_type_id + LEFT JOIN civicrm_contact cc ON cc.id = cr.contact_id_b + LEFT JOIN civicrm_email ce ON ce.contact_id = cc.id + WHERE cr.case_id = %1 AND ce.is_primary= 1 + GROUP BY cc.id'; + + $params = array(1 => array($caseID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + while ($dao->fetch()) { + if ($skipDetails) { + $values[$dao->id] = 1; + } + else { + $values[] = array( + 'contact_id' => $dao->id, + 'display_name' => $dao->name, + 'sort_name' => $dao->sort_name, + 'role' => $dao->role, + 'email' => $dao->email, + ); + } + } + $dao->free(); + + return $values; + } + + /** + * Function that sends e-mail copy of activity + * + * @param int $activityId activity Id + * @param array $contacts array of related contact + * + * @return void + * @access public + */ + static function sendActivityCopy($clientId, $activityId, $contacts, $attachments = NULL, $caseId) { + if (!$activityId) { + return; + } + + $tplParams = $activityInfo = array(); + //if its a case activity + if ($caseId) { + $activityTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityId, 'activity_type_id'); + $nonCaseActivityTypes = CRM_Core_PseudoConstant::activityType(); + if (CRM_Utils_Array::value($activityTypeId, $nonCaseActivityTypes)) { + $anyActivity = TRUE; + } + else { + $anyActivity = FALSE; + } + $tplParams['isCaseActivity'] = 1; + $tplParams['client_id'] = $clientId; + } + else { + $anyActivity = TRUE; + } + + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); + $isRedact = $xmlProcessorProcess->getRedactActivityEmail(); + + $xmlProcessorReport = new CRM_Case_XMLProcessor_Report(); + + $activityInfo = $xmlProcessorReport->getActivityInfo($clientId, $activityId, $anyActivity, $isRedact); + if ($caseId) { + $activityInfo['fields'][] = array('label' => 'Case ID', 'type' => 'String', 'value' => $caseId); + } + $tplParams['activity'] = $activityInfo; + foreach ($tplParams['activity']['fields'] as $k => $val) { + if (CRM_Utils_Array::value('label', $val) == ts('Subject')) { + $activitySubject = $val['value']; + break; + } + } + $session = CRM_Core_Session::singleton(); + // CRM-8926 If user is not logged in, use the activity creator as userID + if (!($userID = $session->get('userID'))) { + $userID = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityId, 'source_contact_id'); + } + + //also create activities simultaneously of this copy. + $activityParams = array(); + + $activityParams['source_record_id'] = $activityId; + $activityParams['source_contact_id'] = $userID; + $activityParams['activity_type_id'] = CRM_Core_OptionGroup::getValue('activity_type', 'Email', 'name'); + $activityParams['activity_date_time'] = date('YmdHis'); + $activityParams['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + $activityParams['medium_id'] = CRM_Core_OptionGroup::getValue('encounter_medium', 'email', 'name'); + $activityParams['case_id'] = $caseId; + $activityParams['is_auto'] = 0; + $activityParams['target_id'] = $clientId; + + $tplParams['activitySubject'] = $activitySubject; + + // if it’s a case activity, add hashed id to the template (CRM-5916) + if ($caseId) { + $tplParams['idHash'] = substr(sha1(CIVICRM_SITE_KEY . $caseId), 0, 7); + } + + $result = array(); + list($name, $address) = CRM_Contact_BAO_Contact_Location::getEmailDetails($userID); + + $receiptFrom = "$name <$address>"; + + $recordedActivityParams = array(); + + foreach ($contacts as $mail => $info) { + $tplParams['contact'] = $info; + self::buildPermissionLinks($tplParams, $activityParams); + + $displayName = $info['display_name']; + + list($result[$info['contact_id']], $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate( + array( + 'groupName' => 'msg_tpl_workflow_case', + 'valueName' => 'case_activity', + 'contactId' => $info['contact_id'], + 'tplParams' => $tplParams, + 'from' => $receiptFrom, + 'toName' => $displayName, + 'toEmail' => $mail, + 'attachments' => $attachments, + ) + ); + + $activityParams['subject'] = $activitySubject . ' - copy sent to ' . $displayName; + $activityParams['details'] = $message; + + if ($result[$info['contact_id']]) { + /* + * Really only need to record one activity with all the targets combined. + * Originally the template was going to possibly have different content, e.g. depending on permissions, + * but it's always the same content at the moment. + */ + if (empty($recordedActivityParams)) { + $recordedActivityParams = $activityParams; + } + else { + $recordedActivityParams['subject'] .= "; $displayName"; + } + $recordedActivityParams['target_contact_id'][] = $info['contact_id']; + } + else { + unset($result[$info['contact_id']]); + } + } + + if (!empty($recordedActivityParams)) { + $activity = CRM_Activity_BAO_Activity::create($recordedActivityParams); + + //create case_activity record if its case activity. + if ($caseId) { + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $caseId, + ); + self::processCaseActivity($caseParams); + } + } + + return $result; + } + + /** + * Retrieve count of activities having a particular type, and + * associated with a particular case. + * + * @param int $caseId ID of the case + * @param int $activityTypeId ID of the activity type + * + * @return array + * + * @access public + * + */ + static function getCaseActivityCount($caseId, $activityTypeId) { + $queryParam = array(1 => array($caseId, 'Integer'), + 2 => array($activityTypeId, 'Integer'), + ); + $query = "SELECT count(ca.id) as countact + FROM civicrm_activity ca + INNER JOIN civicrm_case_activity cca ON ca.id = cca.activity_id + WHERE ca.activity_type_id = %2 + AND cca.case_id = %1 + AND ca.is_deleted = 0"; + + $dao = CRM_Core_DAO::executeQuery($query, $queryParam); + if ($dao->fetch()) { + return $dao->countact; + } + + return FALSE; + } + + /** + * Create an activity for a case via email + * + * @param int $file email sent + * + * @return $activity object of newly creted activity via email + * + * @access public + * + */ + static function recordActivityViaEmail($file) { + if (!file_exists($file) || + !is_readable($file) + ) { + return CRM_Core_Error::fatal(ts('File %1 does not exist or is not readable', + array(1 => $file) + )); + } + + $result = CRM_Utils_Mail_Incoming::parse($file); + if ($result['is_error']) { + return $result; + } + + foreach ($result['to'] as $to) { + $caseId = NULL; + + $emailPattern = '/^([A-Z0-9._%+-]+)\+([\d]+)@[A-Z0-9.-]+\.[A-Z]{2,4}$/i'; + $replacement = preg_replace($emailPattern, '$2', $to['email']); + + if ($replacement !== $to['email']) { + $caseId = $replacement; + //if caseId is invalid, return as error file + if (!CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseId, 'id')) { + return CRM_Core_Error::createAPIError(ts('Invalid case ID ( %1 ) in TO: field.', + array(1 => $caseId) + )); + } + } + else { + continue; + } + + // TODO: May want to replace this with a call to getRelatedAndGlobalContacts() when this feature is revisited. + // (Or for efficiency call the global one outside the loop and then union with this each time.) + $contactDetails = self::getRelatedContacts($caseId, TRUE); + + if (CRM_Utils_Array::value($result['from']['id'], $contactDetails)) { + $params = array(); + $params['subject'] = $result['subject']; + $params['activity_date_time'] = $result['date']; + $params['details'] = $result['body']; + $params['source_contact_id'] = $result['from']['id']; + $params['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', + 'Completed', + 'name' + ); + + $details = CRM_Case_PseudoConstant::caseActivityType(); + $matches = array(); + preg_match('/^\W+([a-zA-Z0-9_ ]+)(\W+)?\n/i', + $result['body'], $matches + ); + + if (!empty($matches) && isset($matches[1])) { + $activityType = trim($matches[1]); + if (isset($details[$activityType])) { + $params['activity_type_id'] = $details[$activityType]['id']; + } + } + if (!isset($params['activity_type_id'])) { + $params['activity_type_id'] = CRM_Core_OptionGroup::getValue('activity_type', 'Inbound Email', 'name'); + } + + // create activity + $activity = CRM_Activity_BAO_Activity::create($params); + + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $caseId, + ); + self::processCaseActivity($caseParams); + } + else { + return CRM_Core_Error::createAPIError(ts('FROM email contact %1 doesn\'t have a relationship to the referenced case.', + array(1 => $result['from']['email']) + )); + } + } + } + + /** + * Function to retrive the scheduled activity type and date + * + * @param array $cases Array of contact and case id + * + * @return array $activityInfo Array of scheduled activity type and date + * + * @access public + * + * @static + */ + static function getNextScheduledActivity($cases, $type = 'upcoming') { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + + $caseID = implode(',', $cases['case_id']); + $contactID = implode(',', $cases['contact_id']); + + $condition = " + AND civicrm_case_contact.contact_id IN( {$contactID} ) + AND civicrm_case.id IN( {$caseID}) + AND civicrm_case.is_deleted = {$cases['case_deleted']}"; + + $query = self::getCaseActivityQuery($type, $userID, $condition, $cases['case_deleted']); + + $res = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + + $activityInfo = array(); + while ($res->fetch()) { + if ($type == 'upcoming') { + $activityInfo[$res->case_id]['date'] = $res->case_scheduled_activity_date; + $activityInfo[$res->case_id]['type'] = $res->case_scheduled_activity_type; + } + else { + $activityInfo[$res->case_id]['date'] = $res->case_recent_activity_date; + $activityInfo[$res->case_id]['type'] = $res->case_recent_activity_type; + } + } + + return $activityInfo; + } + + /** + * combine all the exportable fields from the lower levels object + * + * @return array array of exportable Fields + * @access public + * @static + */ + static function &exportableFields() { + if (!self::$_exportableFields) { + if (!self::$_exportableFields) { + self::$_exportableFields = array(); + } + + $fields = CRM_Case_DAO_Case::export(); + $fields['case_role'] = array('title' => ts('Role in Case')); + $fields['case_type'] = array('title' => ts('Case Type'), + 'name' => 'case_type', + ); + $fields['case_status'] = array('title' => ts('Case Status'), + 'name' => 'case_status', + ); + + self::$_exportableFields = $fields; + } + return self::$_exportableFields; + } + + /** + * Restore the record that are associated with this case + * + * @param int $caseId id of the case to restore + * + * @return true if success. + * @access public + * @static + */ + static function restoreCase($caseId) { + //restore activities + $activities = self::getCaseActivityDates($caseId); + if ($activities) { + foreach ($activities as $value) { + CRM_Activity_BAO_Activity::restoreActivity($value); + } + } + //restore case + $case = new CRM_Case_DAO_Case(); + $case->id = $caseId; + $case->is_deleted = 0; + $case->save(); + + //CRM-7364, enable relationships + self::enableDisableCaseRelationships($caseId, TRUE); + return TRUE; + } + + static function getGlobalContacts(&$groupInfo, $sort = NULL, $showLinks = NULL, $returnOnlyCount = FALSE, $offset = 0, $rowCount = 25) { + $globalContacts = array(); + + $settingsProcessor = new CRM_Case_XMLProcessor_Settings(); + $settings = $settingsProcessor->run(); + if (!empty($settings)) { + $groupInfo['name'] = $settings['groupname']; + if ($groupInfo['name']) { + $searchParams = array('name' => $groupInfo['name']); + $results = array(); + CRM_Contact_BAO_Group::retrieve($searchParams, $results); + if ($results) { + $groupInfo['id'] = $results['id']; + $groupInfo['title'] = $results['title']; + $params = array(array('group', 'IN', array($groupInfo['id'] => 1), 0, 0)); + $return = array('sort_name' => 1, 'display_name' => 1, 'email' => 1, 'phone' => 1); + $return = array('contact_id' => 1, 'sort_name' => 1, 'display_name' => 1, 'email' => 1, 'phone' => 1); + list($globalContacts, $_) = CRM_Contact_BAO_Query::apiQuery($params, $return, NULL, $sort, $offset, $rowCount, TRUE, $returnOnlyCount); + + if ($returnOnlyCount) { + return $globalContacts; + } + + if ($showLinks) { + foreach($globalContacts as $idx => $contact) { + $globalContacts[$idx]['sort_name'] = '' . $contact['sort_name'] . ''; + } + } + } + } + } + return $globalContacts; + } + + /* + * Convenience function to get both case contacts and global in one array + */ + static function getRelatedAndGlobalContacts($caseId) { + $relatedContacts = self::getRelatedContacts($caseId); + + $groupInfo = array(); + $globalContacts = self::getGlobalContacts($groupInfo); + + //unset values which are not required. + foreach ($globalContacts as $k => & $v) { + unset($v['email_id']); + unset($v['group_contact_id']); + unset($v['status']); + unset($v['phone']); + $v['role'] = $groupInfo['title']; + } + //include multiple listings for the same contact/different roles. + $relatedGlobalContacts = array_merge($relatedContacts, $globalContacts); + return $relatedGlobalContacts; + } + + /** + * Function to get Case ActivitiesDueDates with given criteria. + * + * @param int $caseID case id + * @param array $criteriaParams given criteria + * @param boolean $latestDate if set newest or oldest date is selceted. + * + * @return returns case activities due dates + * + * @static + */ + static function getCaseActivityDates($caseID, $criteriaParams = array( + ), $latestDate = FALSE) { + $values = array(); + $selectDate = " ca.activity_date_time"; + $where = $groupBy = ' '; + + if (!$caseID) { + return; + } + + if ($latestDate) { + if (CRM_Utils_Array::value('activity_type_id', $criteriaParams)) { + $where .= " AND ca.activity_type_id = " . CRM_Utils_Type::escape($criteriaParams['activity_type_id'], 'Integer'); + $where .= " AND ca.is_current_revision = 1"; + $groupBy .= " GROUP BY ca.activity_type_id"; + } + + if (CRM_Utils_Array::value('newest', $criteriaParams)) { + $selectDate = " max(ca.activity_date_time) "; + } + else { + $selectDate = " min(ca.activity_date_time) "; + } + } + + $query = "SELECT ca.id, {$selectDate} as activity_date + FROM civicrm_activity ca + LEFT JOIN civicrm_case_activity cca ON cca.activity_id = ca.id LEFT JOIN civicrm_case cc ON cc.id = cca.case_id + WHERE cc.id = %1 {$where} {$groupBy}"; + + $params = array(1 => array($caseID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + while ($dao->fetch()) { + $values[$dao->id]['id'] = $dao->id; + $values[$dao->id]['activity_date'] = $dao->activity_date; + } + $dao->free(); + return $values; + } + + /** + * Function to create activities when Case or Other roles assigned/modified/deleted. + * + * @param int $caseID case id + * @param int $relationshipId relationship id + * @param int $relContactId case role assigne contactId. + * + * @return void on success creates activity and case activity + * + * @static + */ + static function createCaseRoleActivity($caseId, $relationshipId, $relContactId = NULL, $contactId = NULL) { + if (!$caseId || !$relationshipId || empty($relationshipId)) { + return; + } + + $queryParam = array(); + if (is_array($relationshipId)) { + $relationshipId = implode(',', $relationshipId); + $relationshipClause = " civicrm_relationship.id IN ($relationshipId)"; + } + else { + $relationshipClause = " civicrm_relationship.id = %1"; + $queryParam[1] = array($relationshipId, 'Positive'); + } + + $query = " + SELECT cc.display_name as clientName, + cca.display_name as assigneeContactName, + civicrm_relationship.case_id as caseId, + civicrm_relationship_type.label_a_b as relation_a_b, + civicrm_relationship_type.label_b_a as relation_b_a, + civicrm_relationship.contact_id_b as rel_contact_id, + civicrm_relationship.contact_id_a as assign_contact_id + FROM civicrm_relationship_type, civicrm_relationship + LEFT JOIN civicrm_contact cc ON cc.id = civicrm_relationship.contact_id_b + LEFT JOIN civicrm_contact cca ON cca.id = civicrm_relationship.contact_id_a + WHERE civicrm_relationship.relationship_type_id = civicrm_relationship_type.id AND {$relationshipClause}"; + + $dao = CRM_Core_DAO::executeQuery($query, $queryParam); + + while ($dao->fetch()) { + //to get valid assignee contact(s). + if (isset($dao->caseId) || $dao->rel_contact_id != $contactId) { + $caseRelationship = $dao->relation_a_b; + $assigneContactName = $dao->clientName; + $assigneContactIds[$dao->rel_contact_id] = $dao->rel_contact_id; + } + else { + $caseRelationship = $dao->relation_b_a; + $assigneContactName = $dao->assigneeContactName; + $assigneContactIds[$dao->assign_contact_id] = $dao->assign_contact_id; + } + } + + $session = CRM_Core_Session::singleton(); + $activityParams = array( + 'source_contact_id' => $session->get('userID'), + 'subject' => $caseRelationship . ' : ' . $assigneContactName, + 'activity_date_time' => date('YmdHis'), + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'), + ); + + //if $relContactId is passed, role is added or modified. + if (!empty($relContactId)) { + $activityParams['assignee_contact_id'] = $assigneContactIds; + + $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', + 'Assign Case Role', + 'name' + ); + } + else { + $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', + 'Remove Case Role', + 'name' + ); + } + + $activityParams['activity_type_id'] = $activityTypeID; + + $activity = CRM_Activity_BAO_Activity::create($activityParams); + + //create case_activity record. + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $caseId, + ); + + CRM_Case_BAO_Case::processCaseActivity($caseParams); + } + + /** + * Function to get case manger + * contact which is assigned a case role of case manager. + * + * @param int $caseType case type + * @param int $caseId case id + * + * @return array $caseManagerContact array of contact on success otherwise empty + * + * @static + */ + static function getCaseManagerContact($caseType, $caseId) { + if (!$caseType || !$caseId) { + return; + } + + $caseManagerContact = array(); + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + + $managerRoleId = $xmlProcessor->getCaseManagerRoleId($caseType); + + if (!empty($managerRoleId)) { + $managerRoleQuery = " +SELECT civicrm_contact.id as casemanager_id, + civicrm_contact.sort_name as casemanager + FROM civicrm_contact + LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) + LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id + WHERE civicrm_case.id = %2"; + + $managerRoleParams = array( + 1 => array($managerRoleId, 'Integer'), + 2 => array($caseId, 'Integer'), + ); + + $dao = CRM_Core_DAO::executeQuery($managerRoleQuery, $managerRoleParams); + if ($dao->fetch()) { + $caseManagerContact['casemanager_id'] = $dao->casemanager_id; + $caseManagerContact['casemanager'] = $dao->casemanager; + } + } + + return $caseManagerContact; + } + + /** + * Get all cases with no end dates + * + * @return array of case and related data keyed on case id + */ + static function getUnclosedCases($params = array( + ), $excludeCaseIds = array(), $excludeDeleted = TRUE) { + //params from ajax call. + $where = array('( ca.end_date is null )'); + if ($caseType = CRM_Utils_Array::value('case_type', $params)) { + $where[] = "( ov.label LIKE '%$caseType%' )"; + } + if ($sortName = CRM_Utils_Array::value('sort_name', $params)) { + $config = CRM_Core_Config::singleton(); + $search = ($config->includeWildCardInName) ? "%$sortName%" : "$sortName%"; + $where[] = "( sort_name LIKE '$search' )"; + } + if (is_array($excludeCaseIds) && + !CRM_Utils_System::isNull($excludeCaseIds) + ) { + $where[] = ' ( ca.id NOT IN ( ' . implode(',', $excludeCaseIds) . ' ) ) '; + } + if ($excludeDeleted) { + $where[] = ' ( ca.is_deleted = 0 OR ca.is_deleted IS NULL ) '; + } + + //filter for permissioned cases. + $filterCases = array(); + $doFilterCases = FALSE; + if (!CRM_Core_Permission::check('access all cases and activities')) { + $doFilterCases = TRUE; + $session = CRM_Core_Session::singleton(); + $filterCases = CRM_Case_BAO_Case::getCases(FALSE, $session->get('userID')); + } + $whereClause = implode(' AND ', $where); + + $limitClause = ''; + if ($limit = CRM_Utils_Array::value('limit', $params)) { + $limitClause = "LIMIT 0, $limit"; + } + + $query = " + SELECT c.id as contact_id, + c.sort_name, + ca.id, + ca.subject as case_subject, + ov.label as case_type, + ca.start_date as start_date + FROM civicrm_case ca INNER JOIN civicrm_case_contact cc ON ca.id=cc.case_id + INNER JOIN civicrm_contact c ON cc.contact_id=c.id + INNER JOIN civicrm_option_group og ON og.name='case_type' + INNER JOIN civicrm_option_value ov ON (ca.case_type_id=ov.value AND ov.option_group_id=og.id) + WHERE {$whereClause} + ORDER BY c.sort_name + {$limitClause} +"; + $dao = CRM_Core_DAO::executeQuery($query); + $unclosedCases = array(); + while ($dao->fetch()) { + if ($doFilterCases && !array_key_exists($dao->id, $filterCases)) { + continue; + } + $unclosedCases[$dao->id] = array( + 'sort_name' => $dao->sort_name, + 'case_type' => $dao->case_type, + 'contact_id' => $dao->contact_id, + 'start_date' => $dao->start_date, + 'case_subject' => $dao->case_subject, + ); + } + $dao->free(); + + return $unclosedCases; + } + + static function caseCount($contactId = NULL, $excludeDeleted = TRUE) { + $whereConditions = array(); + if ($excludeDeleted) { + $whereConditions[] = "( civicrm_case.is_deleted = 0 OR civicrm_case.is_deleted IS NULL )"; + } + if ($contactId) { + $whereConditions[] = "civicrm_case_contact.contact_id = {$contactId}"; + } + if (!CRM_Core_Permission::check('access all cases and activities')) { + static $accessibleCaseIds; + if (!is_array($accessibleCaseIds)) { + $session = CRM_Core_Session::singleton(); + $accessibleCaseIds = array_keys(self::getCases(FALSE, $session->get('userID'))); + } + //no need of further processing. + if (empty($accessibleCaseIds)) { + return 0; + } + $whereConditions[] = "( civicrm_case.id in (" . implode(',', $accessibleCaseIds) . ") )"; + } + + $whereClause = ''; + if (!empty($whereConditions)) { + $whereClause = "WHERE " . implode(' AND ', $whereConditions); + } + + $query = " + SELECT count( civicrm_case.id ) + FROM civicrm_case +LEFT JOIN civicrm_case_contact ON ( civicrm_case.id = civicrm_case_contact.case_id ) + {$whereClause}"; + + return CRM_Core_DAO::singleValueQuery($query); + } + + /** + * Retrieve cases related to particular contact. + * + * @param int $contactId contact id + * @param boolean $excludeDeleted do not include deleted cases. + * + * @return an array of cases. + * + * @access public + */ + static function getContactCases($contactId, $excludeDeleted = TRUE) { + $cases = array(); + if (!$contactId) { + return $cases; + } + + $whereClause = "civicrm_case_contact.contact_id = %1"; + if ($excludeDeleted) { + $whereClause .= " AND ( civicrm_case.is_deleted = 0 OR civicrm_case.is_deleted IS NULL )"; + } + + $query = " + SELECT civicrm_case.id, case_type_ov.label as case_type, civicrm_case.start_date + FROM civicrm_case +INNER JOIN civicrm_case_contact ON ( civicrm_case.id = civicrm_case_contact.case_id ) + LEFT JOIN civicrm_option_group case_type_og ON ( case_type_og.name = 'case_type' ) + LEFT JOIN civicrm_option_value case_type_ov ON ( civicrm_case.case_type_id = case_type_ov.value + AND case_type_og.id = case_type_ov.option_group_id ) + WHERE {$whereClause}"; + + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactId, 'Integer'))); + while ($dao->fetch()) { + $cases[$dao->id] = array( + 'case_id' => $dao->id, + 'case_type' => $dao->case_type, + 'case_start_date' => $dao->start_date, + ); + } + $dao->free(); + + return $cases; + } + + /** + * Retrieve related cases for give case. + * + * @param int $mainCaseId id of main case + * @param int $contactId id of contact + * @param boolean $excludeDeleted do not include deleted cases. + * + * @return an array of related cases. + * + * @access public + */ + static function getRelatedCases($mainCaseId, $contactId, $excludeDeleted = TRUE) { + //FIXME : do check for permissions. + + $relatedCases = array(); + if (!$mainCaseId || !$contactId) { + return $relatedCases; + } + + $linkActType = array_search('Link Cases', + CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name') + ); + if (!$linkActType) { + return $relatedCases; + } + + $whereClause = "mainCase.id = %2"; + if ($excludeDeleted) { + $whereClause .= " AND ( relAct.is_deleted = 0 OR relAct.is_deleted IS NULL )"; + } + + //1. first fetch related case ids. + $query = " + SELECT relCaseAct.case_id + FROM civicrm_case mainCase + INNER JOIN civicrm_case_activity mainCaseAct ON (mainCaseAct.case_id = mainCase.id) + INNER JOIN civicrm_activity mainAct ON (mainCaseAct.activity_id = mainAct.id AND mainAct.activity_type_id = %1) + INNER JOIN civicrm_case_activity relCaseAct ON (relCaseAct.activity_id = mainAct.id AND mainCaseAct.id != relCaseAct.id) + INNER JOIN civicrm_activity relAct ON (relCaseAct.activity_id = relAct.id AND relAct.activity_type_id = %1) + WHERE $whereClause"; + + $dao = CRM_Core_DAO::executeQuery($query, array( + 1 => array($linkActType, 'Integer'), + 2 => array($mainCaseId, 'Integer'), + )); + $relatedCaseIds = array(); + while ($dao->fetch()) { + $relatedCaseIds[$dao->case_id] = $dao->case_id; + } + $dao->free(); + + // there are no related cases. + if (empty($relatedCaseIds)) { + return $relatedCases; + } + + $whereClause = 'relCase.id IN ( ' . implode(',', $relatedCaseIds) . ' )'; + if ($excludeDeleted) { + $whereClause .= " AND ( relCase.is_deleted = 0 OR relCase.is_deleted IS NULL )"; + } + + //filter for permissioned cases. + $filterCases = array(); + $doFilterCases = FALSE; + if (!CRM_Core_Permission::check('access all cases and activities')) { + $doFilterCases = TRUE; + $session = CRM_Core_Session::singleton(); + $filterCases = CRM_Case_BAO_Case::getCases(FALSE, $session->get('userID')); + } + + //2. fetch the details of related cases. + $query = " + SELECT relCase.id as id, + case_type_ov.label as case_type, + client.display_name as client_name, + client.id as client_id + FROM civicrm_case relCase + INNER JOIN civicrm_case_contact relCaseContact ON ( relCase.id = relCaseContact.case_id ) + INNER JOIN civicrm_contact client ON ( client.id = relCaseContact.contact_id ) + LEFT JOIN civicrm_option_group case_type_og ON ( case_type_og.name = 'case_type' ) + LEFT JOIN civicrm_option_value case_type_ov ON ( relCase.case_type_id = case_type_ov.value + AND case_type_og.id = case_type_ov.option_group_id ) + WHERE {$whereClause}"; + + $dao = CRM_Core_DAO::executeQuery($query); + $contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", "reset=1&cid="); + $hasViewContact = CRM_Core_Permission::giveMeAllACLs(); + + while ($dao->fetch()) { + $caseView = NULL; + if (!$doFilterCases || array_key_exists($dao->id, $filterCases)) { + $caseViewStr = "reset=1&id={$dao->id}&cid={$dao->client_id}&action=view&context=case&selectedChild=case"; + $caseViewUrl = CRM_Utils_System::url("civicrm/contact/view/case", $caseViewStr); + $caseView = "" . ts('View Case') . ""; + } + $clientView = $dao->client_name; + if ($hasViewContact) { + $clientView = "$dao->client_name"; + } + + $relatedCases[$dao->id] = array( + 'case_id' => $dao->id, + 'case_type' => $dao->case_type, + 'client_name' => $clientView, + 'links' => $caseView, + ); + } + $dao->free(); + + return $relatedCases; + } + + /** + * Merge two duplicate contacts' cases - follow CRM-5758 rules. + * + * @see CRM_Dedupe_Merger::cpTables() + * + * TODO: use the 3rd $sqls param to append sql statements rather than executing them here + */ + static function mergeContacts($mainContactId, $otherContactId) { + self::mergeCases($mainContactId, NULL, $otherContactId); + } + + /** + * Function perform two task. + * 1. Merge two duplicate contacts cases - follow CRM-5758 rules. + * 2. Merge two cases of same contact - follow CRM-5598 rules. + * + * @param int $mainContactId contact id of main contact record. + * @param int $mainCaseId case id of main case record. + * @param int $otherContactId contact id of record which is going to merge. + * @param int $otherCaseId case id of record which is going to merge. + * + * @return void. + * @static + */ + static function mergeCases($mainContactId, $mainCaseId = NULL, $otherContactId = NULL, + $otherCaseId = NULL, $changeClient = FALSE ) { + $moveToTrash = TRUE; + + $duplicateContacts = FALSE; + if ($mainContactId && $otherContactId && + $mainContactId != $otherContactId + ) { + $duplicateContacts = TRUE; + } + + $duplicateCases = FALSE; + if ($mainCaseId && $otherCaseId && + $mainCaseId != $otherCaseId + ) { + $duplicateCases = TRUE; + } + + $mainCaseIds = array(); + if (!$duplicateContacts && !$duplicateCases) { + return $mainCaseIds; + } + + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name'); + $activityStatuses = CRM_Core_PseudoConstant::activityStatus('name'); + + $processCaseIds = array($otherCaseId); + if ($duplicateContacts && !$duplicateCases) { + if ($changeClient) { + $processCaseIds = array($mainCaseId); + } + else { + //get all case ids for other contact. + $processCaseIds = self::retrieveCaseIdsByContactId($otherContactId, TRUE); + } + if (!is_array($processCaseIds)) { + return; + } + } + + $session = CRM_Core_Session::singleton(); + $currentUserId = $session->get('userID'); + + // copy all cases and connect to main contact id. + foreach ($processCaseIds as $otherCaseId) { + if ($duplicateContacts) { + $mainCase = CRM_Core_DAO::copyGeneric('CRM_Case_DAO_Case', array('id' => $otherCaseId)); + $mainCaseId = $mainCase->id; + if (!$mainCaseId) { + continue; + } + $mainCase->free(); + $mainCaseIds[] = $mainCaseId; + //insert record for case contact. + $otherCaseContact = new CRM_Case_DAO_CaseContact(); + $otherCaseContact->case_id = $otherCaseId; + $otherCaseContact->find(); + while ($otherCaseContact->fetch()) { + $mainCaseContact = new CRM_Case_DAO_CaseContact(); + $mainCaseContact->case_id = $mainCaseId; + $mainCaseContact->contact_id = $otherCaseContact->contact_id; + if ($mainCaseContact->contact_id == $otherContactId) { + $mainCaseContact->contact_id = $mainContactId; + } + //avoid duplicate object. + if (!$mainCaseContact->find(TRUE)) { + $mainCaseContact->save(); + } + $mainCaseContact->free(); + } + $otherCaseContact->free(); + } + elseif (!$otherContactId) { + $otherContactId = $mainContactId; + } + + if (!$mainCaseId || !$otherCaseId || + !$mainContactId || !$otherContactId + ) { + continue; + } + + // get all activities for other case. + $otherCaseActivities = array(); + CRM_Core_DAO::commonRetrieveAll('CRM_Case_DAO_CaseActivity', 'case_id', $otherCaseId, $otherCaseActivities); + + //for duplicate cases do not process singleton activities. + $otherActivityIds = $singletonActivityIds = array(); + foreach ($otherCaseActivities as $caseActivityId => $otherIds) { + $otherActId = CRM_Utils_Array::value('activity_id', $otherIds); + if (!$otherActId || in_array($otherActId, $otherActivityIds)) { + continue; + } + $otherActivityIds[] = $otherActId; + } + if ($duplicateCases) { + if ($openCaseType = array_search('Open Case', $activityTypes)) { + $sql = " +SELECT id + FROM civicrm_activity + WHERE activity_type_id = $openCaseType + AND id IN ( " . implode(',', array_values($otherActivityIds)) . ');'; + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $singletonActivityIds[] = $dao->id; + } + $dao->free(); + } + } + + // migrate all activities and connect to main contact. + $copiedActivityIds = $activityMappingIds = array(); + sort($otherActivityIds); + foreach ($otherActivityIds as $otherActivityId) { + + //for duplicate cases - + //do not migrate singleton activities. + if (!$otherActivityId || in_array($otherActivityId, $singletonActivityIds)) { + continue; + } + + //migrate activity record. + $otherActivity = new CRM_Activity_DAO_Activity(); + $otherActivity->id = $otherActivityId; + if (!$otherActivity->find(TRUE)) { + continue; + } + + $mainActVals = array(); + $mainActivity = new CRM_Activity_DAO_Activity(); + CRM_Core_DAO::storeValues($otherActivity, $mainActVals); + $mainActivity->copyValues($mainActVals); + $mainActivity->id = NULL; + $mainActivity->activity_date_time = CRM_Utils_Date::isoToMysql($otherActivity->activity_date_time); + //do check for merging contact, + if ($mainActivity->source_contact_id == $otherContactId) { + $mainActivity->source_contact_id = $mainContactId; + } + $mainActivity->source_record_id = CRM_Utils_Array::value($mainActivity->source_record_id, + $activityMappingIds + ); + + $mainActivity->original_id = CRM_Utils_Array::value($mainActivity->original_id, + $activityMappingIds + ); + + $mainActivity->parent_id = CRM_Utils_Array::value($mainActivity->parent_id, + $activityMappingIds + ); + $mainActivity->save(); + $mainActivityId = $mainActivity->id; + if (!$mainActivityId) { + continue; + } + + $activityMappingIds[$otherActivityId] = $mainActivityId; + // insert log of all activites + CRM_Activity_BAO_Activity::logActivityAction($mainActivity); + + $otherActivity->free(); + $mainActivity->free(); + $copiedActivityIds[] = $otherActivityId; + + //create case activity record. + $mainCaseActivity = new CRM_Case_DAO_CaseActivity(); + $mainCaseActivity->case_id = $mainCaseId; + $mainCaseActivity->activity_id = $mainActivityId; + $mainCaseActivity->save(); + $mainCaseActivity->free(); + + //migrate target activities. + $otherTargetActivity = new CRM_Activity_DAO_ActivityTarget(); + $otherTargetActivity->activity_id = $otherActivityId; + $otherTargetActivity->find(); + while ($otherTargetActivity->fetch()) { + $mainActivityTarget = new CRM_Activity_DAO_ActivityTarget(); + $mainActivityTarget->activity_id = $mainActivityId; + $mainActivityTarget->target_contact_id = $otherTargetActivity->target_contact_id; + if ($mainActivityTarget->target_contact_id == $otherContactId) { + $mainActivityTarget->target_contact_id = $mainContactId; + } + //avoid duplicate object. + if (!$mainActivityTarget->find(TRUE)) { + $mainActivityTarget->save(); + } + $mainActivityTarget->free(); + } + $otherTargetActivity->free(); + + //migrate assignee activities. + $otherAssigneeActivity = new CRM_Activity_DAO_ActivityAssignment(); + $otherAssigneeActivity->activity_id = $otherActivityId; + $otherAssigneeActivity->find(); + while ($otherAssigneeActivity->fetch()) { + $mainAssigneeActivity = new CRM_Activity_DAO_ActivityAssignment(); + $mainAssigneeActivity->activity_id = $mainActivityId; + $mainAssigneeActivity->assignee_contact_id = $otherAssigneeActivity->assignee_contact_id; + if ($mainAssigneeActivity->assignee_contact_id == $otherContactId) { + $mainAssigneeActivity->assignee_contact_id = $mainContactId; + } + //avoid duplicate object. + if (!$mainAssigneeActivity->find(TRUE)) { + $mainAssigneeActivity->save(); + } + $mainAssigneeActivity->free(); + } + $otherAssigneeActivity->free(); + } + + //copy case relationship. + if ($duplicateContacts) { + //migrate relationship records. + $otherRelationship = new CRM_Contact_DAO_Relationship(); + $otherRelationship->case_id = $otherCaseId; + $otherRelationship->find(); + $otherRelationshipIds = array(); + while ($otherRelationship->fetch()) { + $otherRelVals = array(); + $updateOtherRel = FALSE; + CRM_Core_DAO::storeValues($otherRelationship, $otherRelVals); + + $mainRelationship = new CRM_Contact_DAO_Relationship(); + $mainRelationship->copyValues($otherRelVals); + $mainRelationship->id = NULL; + $mainRelationship->case_id = $mainCaseId; + if ($mainRelationship->contact_id_a == $otherContactId) { + $updateOtherRel = TRUE; + $mainRelationship->contact_id_a = $mainContactId; + } + + //case creator change only when we merge user contact. + if ($mainRelationship->contact_id_b == $otherContactId) { + //do not change creator for change client. + if (!$changeClient) { + $updateOtherRel = TRUE; + $mainRelationship->contact_id_b = ($currentUserId) ? $currentUserId : $mainContactId; + } + } + $mainRelationship->end_date = CRM_Utils_Date::isoToMysql($otherRelationship->end_date); + $mainRelationship->start_date = CRM_Utils_Date::isoToMysql($otherRelationship->start_date); + + //avoid duplicate object. + if (!$mainRelationship->find(TRUE)) { + $mainRelationship->save(); + } + $mainRelationship->free(); + + //get the other relationship ids to update end date. + if ($updateOtherRel) { + $otherRelationshipIds[$otherRelationship->id] = $otherRelationship->id; + } + } + $otherRelationship->free(); + + //update other relationships end dates + if (!empty($otherRelationshipIds)) { + $sql = 'UPDATE civicrm_relationship + SET end_date = CURDATE() + WHERE id IN ( ' . implode(',', $otherRelationshipIds) . ')'; + CRM_Core_DAO::executeQuery($sql); + } + } + + //move other case to trash. + $mergeCase = self::deleteCase($otherCaseId, $moveToTrash); + if (!$mergeCase) { + continue; + } + + $mergeActSubject = $mergeActSubjectDetails = $mergeActType = ''; + if ($changeClient) { + $mainContactDisplayName = CRM_Contact_BAO_Contact::displayName($mainContactId); + $otherContactDisplayName = CRM_Contact_BAO_Contact::displayName($otherContactId); + + $mergeActType = array_search('Reassigned Case', $activityTypes); + $mergeActSubject = ts("Case %1 reassigned client from %2 to %3. New Case ID is %4.", + array( + 1 => $otherCaseId, 2 => $otherContactDisplayName, + 3 => $mainContactDisplayName, 4 => $mainCaseId, + ) + ); + } + elseif ($duplicateContacts) { + $mergeActType = array_search('Merge Case', $activityTypes); + $mergeActSubject = ts("Case %1 copied from contact id %2 to contact id %3 via merge. New Case ID is %4.", + array( + 1 => $otherCaseId, 2 => $otherContactId, + 3 => $mainContactId, 4 => $mainCaseId, + ) + ); + } + else { + $mergeActType = array_search('Merge Case', $activityTypes); + $mergeActSubject = ts("Case %1 merged into case %2", array(1 => $otherCaseId, 2 => $mainCaseId)); + if (!empty($copiedActivityIds)) { + $sql = ' +SELECT id, subject, activity_date_time, activity_type_id +FROM civicrm_activity +WHERE id IN (' . implode(',', $copiedActivityIds) . ')'; + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $mergeActSubjectDetails .= "{$dao->activity_date_time} :: {$activityTypes[$dao->activity_type_id]}"; + if ($dao->subject) { + $mergeActSubjectDetails .= " :: {$dao->subject}"; + } + $mergeActSubjectDetails .= "
    "; + } + } + } + + //create merge activity record. + $activityParams = array( + 'subject' => $mergeActSubject, + 'details' => $mergeActSubjectDetails, + 'status_id' => array_search('Completed', $activityStatuses), + 'activity_type_id' => $mergeActType, + 'source_contact_id' => $mainContactId, + 'activity_date_time' => date('YmdHis'), + ); + + $mergeActivity = CRM_Activity_BAO_Activity::create($activityParams); + $mergeActivityId = $mergeActivity->id; + if (!$mergeActivityId) { + continue; + } + $mergeActivity->free(); + + //connect merge activity to case. + $mergeCaseAct = array( + 'case_id' => $mainCaseId, + 'activity_id' => $mergeActivityId, + ); + + self::processCaseActivity($mergeCaseAct); + } + return $mainCaseIds; + } + + /** + * Validate contact permission for + * edit/view on activity record and build links. + * + * @param array $tplParams params to be sent to template for sending email. + * @param array $activityParams info of the activity. + * + * @return void + * @static + */ + static function buildPermissionLinks(&$tplParams, $activityParams) { + $activityTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityParams['source_record_id'], + 'activity_type_id', 'id' + ); + + if (CRM_Utils_Array::value('isCaseActivity', $tplParams)) { + $tplParams['editActURL'] = CRM_Utils_System::url('civicrm/case/activity', + "reset=1&cid={$activityParams['target_id']}&caseid={$activityParams['case_id']}&action=update&id={$activityParams['source_record_id']}", TRUE + ); + + $tplParams['viewActURL'] = CRM_Utils_System::url('civicrm/case/activity/view', + "reset=1&aid={$activityParams['source_record_id']}&cid={$activityParams['target_id']}&caseID={$activityParams['case_id']}", TRUE + ); + + $tplParams['manageCaseURL'] = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&id={$activityParams['case_id']}&cid={$activityParams['target_id']}&action=view&context=home", TRUE + ); + } + else { + $tplParams['editActURL'] = CRM_Utils_System::url('civicrm/contact/view/activity', + "atype=$activityTypeId&action=update&reset=1&id={$activityParams['source_record_id']}&cid={$tplParams['contact']['contact_id']}&context=activity", TRUE + ); + + $tplParams['viewActURL'] = CRM_Utils_System::url('civicrm/contact/view/activity', + "atype=$activityTypeId&action=view&reset=1&id={$activityParams['source_record_id']}&cid={$tplParams['contact']['contact_id']}&context=activity", TRUE + ); + } + } + + /** + * Validate contact permission for + * given operation on activity record. + * + * @param int $activityId activity record id. + * @param string $operation user operation. + * @param int $actTypeId activity type id. + * @param int $contactId contact id/if not pass consider logged in + * @param boolean $checkComponent do we need to check component enabled. + * + * @return boolean $allow true/false + * @static + */ + static function checkPermission($activityId, $operation, $actTypeId = NULL, $contactId = NULL, $checkComponent = TRUE) { + $allow = FALSE; + if (!$actTypeId && $activityId) { + $actTypeId = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityId, 'activity_type_id'); + } + + if (!$activityId || !$operation || !$actTypeId) { + return $allow; + } + + //do check for civicase component enabled. + if ($checkComponent) { + static $componentEnabled; + if (!isset($componentEnabled)) { + $config = CRM_Core_Config::singleton(); + $componentEnabled = FALSE; + if (in_array('CiviCase', $config->enableComponents)) { + $componentEnabled = TRUE; + } + } + if (!$componentEnabled) { + return $allow; + } + } + + //do check for cases. + $caseActOperations = array( + 'File On Case', + 'Link Cases', + 'Move To Case', + 'Copy To Case', + ); + + if (in_array($operation, $caseActOperations)) { + static $unclosedCases; + if (!is_array($unclosedCases)) { + $unclosedCases = self::getUnclosedCases(); + } + if ($operation == 'File On Case') { + $allow = (empty($unclosedCases)) ? FALSE : TRUE; + } + else { + $allow = (count($unclosedCases) > 1) ? TRUE : FALSE; + } + } + + $actionOperations = array('view', 'edit', 'delete'); + if (in_array($operation, $actionOperations)) { + + //do cache when user has non/supper permission. + static $allowOperations; + + if (!is_array($allowOperations) || + !array_key_exists($operation, $allowOperations) + ) { + + if (!$contactId) { + $session = CRM_Core_Session::singleton(); + $contactId = $session->get('userID'); + } + + //check for permissions. + $permissions = array( + 'view' => array( + 'access my cases and activities', + 'access all cases and activities', + ), + 'edit' => array( + 'access my cases and activities', + 'access all cases and activities', + ), + 'delete' => array('delete activities'), + ); + + //check for core permission. + $hasPermissions = array(); + $checkPermissions = CRM_Utils_Array::value($operation, $permissions); + if (is_array($checkPermissions)) { + foreach ($checkPermissions as $per) { + if (CRM_Core_Permission::check($per)) { + $hasPermissions[$operation][] = $per; + } + } + } + + //has permissions. + if (!empty($hasPermissions)) { + //need to check activity object specific. + if (in_array($operation, array( + 'view', 'edit'))) { + //do we have supper permission. + if (in_array('access all cases and activities', $hasPermissions[$operation])) { + $allowOperations[$operation] = $allow = TRUE; + } + else { + //user has only access to my cases and activity. + //here object specific permmions come in picture. + + //edit - contact must be source or assignee + //view - contact must be source/assignee/target + $isTarget = $isAssignee = $isSource = FALSE; + + $target = new CRM_Activity_DAO_ActivityTarget(); + $target->activity_id = $activityId; + $target->target_contact_id = $contactId; + if ($target->find(TRUE)) { + $isTarget = TRUE; + } + + $assignee = new CRM_Activity_DAO_ActivityAssignment(); + $assignee->activity_id = $activityId; + $assignee->assignee_contact_id = $contactId; + if ($assignee->find(TRUE)) { + $isAssignee = TRUE; + } + + $activity = new CRM_Activity_DAO_Activity(); + $activity->id = $activityId; + $activity->source_contact_id = $contactId; + if ($activity->find(TRUE)) { + $isSource = TRUE; + } + + if ($operation == 'edit') { + if ($isAssignee || $isSource) { + $allow = TRUE; + } + } + if ($operation == 'view') { + if ($isTarget || $isAssignee || $isSource) { + $allow = TRUE; + } + } + } + } + elseif (is_array($hasPermissions[$operation])) { + $allowOperations[$operation] = $allow = TRUE; + } + } + else { + //contact do not have permission. + $allowOperations[$operation] = FALSE; + } + } + else { + //use cache. + //here contact might have supper/non permission. + $allow = $allowOperations[$operation]; + } + } + + //do further only when operation is granted. + if ($allow) { + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name'); + + //get the activity type name. + $actTypeName = CRM_Utils_Array::value($actTypeId, $activityTypes); + + //do not allow multiple copy / edit action. + $singletonNames = array('Open Case', 'Reassigned Case', 'Merge Case', 'Link Cases', 'Assign Case Role', 'Email', 'Inbound Email'); + + //do not allow to delete these activities, CRM-4543 + $doNotDeleteNames = array('Open Case', 'Change Case Type', 'Change Case Status', 'Change Case Start Date'); + + //allow edit operation. + $allowEditNames = array('Open Case'); + + // do not allow File on Case + $doNotFileNames = array('Open Case', 'Change Case Type', 'Change Case Status', 'Change Case Start Date','Reassigned Case', 'Merge Case', 'Link Cases', 'Assign Case Role'); + + if (in_array($actTypeName, $singletonNames)) { + $allow = FALSE; + if ($operation == 'File On Case') { + $allow = (in_array($actTypeName, $doNotFileNames)) ? FALSE : TRUE; + } + if (in_array($operation, $actionOperations)) { + $allow = TRUE; + if ($operation == 'edit') { + $allow = (in_array($actTypeName, $allowEditNames)) ? TRUE : FALSE; + } + elseif ($operation == 'delete') { + $allow = (in_array($actTypeName, $doNotDeleteNames)) ? FALSE : TRUE; + } + } + } + if ($allow && ($operation == 'delete') && + in_array($actTypeName, $doNotDeleteNames) + ) { + $allow = FALSE; + } + + if ($allow && ($operation == 'File On Case') && + in_array($actTypeName, $doNotFileNames) + ) { + $allow = FALSE; + } + + //check settings file for masking actions + //on the basis the activity types + //hide Edit link if activity type is NOT editable + //(special case activities).CRM-5871 + if ($allow && in_array($operation, $actionOperations)) { + static $actionFilter = array(); + if (!array_key_exists($operation, $actionFilter)) { + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $actionFilter[$operation] = $xmlProcessor->get('Settings', 'ActivityTypes', FALSE, $operation); + } + if (array_key_exists($operation, $actionFilter[$operation]) && + in_array($actTypeId, $actionFilter[$operation][$operation]) + ) { + $allow = FALSE; + } + } + } + + return $allow; + } + + /** + * since we drop 'access CiviCase', allow access + * if user has 'access my cases and activities' + * or 'access all cases and activities' + */ + static function accessCiviCase() { + static $componentEnabled; + if (!isset($componentEnabled)) { + $componentEnabled = FALSE; + $config = CRM_Core_Config::singleton(); + if (in_array('CiviCase', $config->enableComponents)) { + $componentEnabled = TRUE; + } + } + if (!$componentEnabled) { + return FALSE; + } + + if (CRM_Core_Permission::check('access my cases and activities') || + CRM_Core_Permission::check('access all cases and activities') + ) { + return TRUE; + } + + return FALSE; + } + + /** + * Function to check whether activity is a case Activity + * + * @param int $activityID activity id + * + * @return boolean $isCaseActivity true/false + */ + static function isCaseActivity($activityID) { + $isCaseActivity = FALSE; + if ($activityID) { + $params = array(1 => array($activityID, 'Integer')); + $query = "SELECT id FROM civicrm_case_activity WHERE activity_id = %1"; + if (CRM_Core_DAO::singleValueQuery($query, $params)) { + $isCaseActivity = TRUE; + } + } + + return $isCaseActivity; + } + + /** + * Function to get all the case type ids currently in use + * + * + * @return array $caseTypeIds + */ + static function getUsedCaseType() { + static $caseTypeIds; + + if (!is_array($caseTypeIds)) { + $query = "SELECT DISTINCT( civicrm_case.case_type_id ) FROM civicrm_case"; + + $dao = CRM_Core_DAO::executeQuery($query); + $caseTypeIds = array(); + while ($dao->fetch()) { + $typeId = explode(CRM_Core_DAO::VALUE_SEPARATOR, + $dao->case_type_id + ); + $caseTypeIds[] = $typeId[1]; + } + } + + return $caseTypeIds; + } + + /** + * Function to get all the case status ids currently in use + * + * + * @return array $caseStatusIds + */ + static function getUsedCaseStatuses() { + static $caseStatusIds; + + if (!is_array($caseStatusIds)) { + $query = "SELECT DISTINCT( civicrm_case.status_id ) FROM civicrm_case"; + + $dao = CRM_Core_DAO::executeQuery($query); + $caseStatusIds = array(); + while ($dao->fetch()) { + $caseStatusIds[] = $dao->status_id; + } + } + + return $caseStatusIds; + } + + /** + * Function to get all the encounter medium ids currently in use + * + * + * @return array + */ + static function getUsedEncounterMediums() { + static $mediumIds; + + if (!is_array($mediumIds)) { + $query = "SELECT DISTINCT( civicrm_activity.medium_id ) FROM civicrm_activity"; + + $dao = CRM_Core_DAO::executeQuery($query); + $mediumIds = array(); + while ($dao->fetch()) { + $mediumIds[] = $dao->medium_id; + } + } + + return $mediumIds; + } + + /** + * Function to check case configuration. + * + * @return an array $configured + */ + static function isCaseConfigured($contactId = NULL) { + $configured = array_fill_keys(array('configured', 'allowToAddNewCase', 'redirectToCaseAdmin'), FALSE); + + //lets check for case configured. + $allCasesCount = CRM_Case_BAO_Case::caseCount(NULL, FALSE); + $configured['configured'] = ($allCasesCount) ? TRUE : FALSE; + if (!$configured['configured']) { + //do check for case type and case status. + $caseTypes = CRM_Case_PseudoConstant::caseType('label', FALSE); + if (!empty($caseTypes)) { + $configured['configured'] = TRUE; + if (!$configured['configured']) { + $caseStatuses = CRM_Case_PseudoConstant::caseStatus('label', FALSE); + if (!empty($caseStatuses)) { + $configured['configured'] = TRUE; + } + } + } + } + if ($configured['configured']) { + //do check for active case type and case status. + $caseTypes = CRM_Case_PseudoConstant::caseType(); + if (!empty($caseTypes)) { + $caseStatuses = CRM_Case_PseudoConstant::caseStatus(); + if (!empty($caseStatuses)) { + $configured['allowToAddNewCase'] = TRUE; + } + } + + //do we need to redirect user to case admin. + if (!$configured['allowToAddNewCase'] && $contactId) { + //check for current contact case count. + $currentContatCasesCount = CRM_Case_BAO_Case::caseCount($contactId); + //redirect user to case admin page. + if (!$currentContatCasesCount) { + $configured['redirectToCaseAdmin'] = TRUE; + } + } + } + + return $configured; + } + + /* + * Used during case component enablement and during ugprade + */ + static function createCaseViews() { + $sql = self::createCaseViewsQuery('upcoming'); + CRM_Core_Error::ignoreException(); + $dao = new CRM_Core_DAO(); + $dao->query($sql); + if (PEAR::getStaticProperty('DB_DataObject', 'lastError')) { + CRM_Core_Error::setCallback(); + return FALSE; + } + + // Above error doesn't get caught? + $doublecheck = $dao->singleValueQuery("SELECT count(id) FROM civicrm_view_case_activity_upcoming"); + if (is_null($doublecheck)) { + return FALSE; + } + + $sql = self::createCaseViewsQuery('recent'); + CRM_Core_Error::ignoreException(); + $dao->query($sql); + if (PEAR::getStaticProperty('DB_DataObject', 'lastError')) { + CRM_Core_Error::setCallback(); + return FALSE; + } + + // Above error doesn't get caught? + $doublecheck = $dao->singleValueQuery("SELECT count(id) FROM civicrm_view_case_activity_recent"); + if (is_null($doublecheck)) { + return FALSE; + } + + return TRUE; + } + + /* + * helper function, also used by the upgrade in case of error + */ + static function createCaseViewsQuery($section = 'upcoming') { + $sql = ""; + $scheduled_id = CRM_Core_OptionGroup::getValue('activity_status', 'Scheduled', 'name'); + switch ($section) { + case 'upcoming': + $sql = "CREATE OR REPLACE VIEW `civicrm_view_case_activity_upcoming` + AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id + FROM civicrm_case_activity ca + INNER JOIN civicrm_activity a ON ca.activity_id=a.id + WHERE a.activity_date_time <= DATE_ADD( NOW(), INTERVAL 14 DAY ) + AND a.is_current_revision = 1 AND a.is_deleted=0 AND a.status_id = $scheduled_id"; + break; + + case 'recent': + $sql = "CREATE OR REPLACE VIEW `civicrm_view_case_activity_recent` + AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id + FROM civicrm_case_activity ca + INNER JOIN civicrm_activity a ON ca.activity_id=a.id + WHERE a.activity_date_time <= NOW() + AND a.activity_date_time >= DATE_SUB( NOW(), INTERVAL 14 DAY ) + AND a.is_current_revision = 1 AND a.is_deleted=0 AND a.status_id <> $scheduled_id"; + break; + } + + return $sql; + } +} + diff --git a/CRM/Case/BAO/Query.php b/CRM/Case/BAO/Query.php new file mode 100644 index 0000000000..bea869f95a --- /dev/null +++ b/CRM/Case/BAO/Query.php @@ -0,0 +1,744 @@ +_mode & CRM_Contact_BAO_Query::MODE_CASE) || + CRM_Utils_Array::value('case_id', $query->_returnProperties) + ) { + $query->_select['case_id'] = "civicrm_case.id as case_id"; + $query->_element['case_id'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + } + + if (CRM_Utils_Array::value('case_type_id', $query->_returnProperties)) { + $query->_select['case_type_id'] = "case_type.id as case_type_id"; + $query->_element['case_type_id'] = 1; + $query->_tables['case_type'] = $query->_whereTables['case_type'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_type', $query->_returnProperties)) { + $query->_select['case_type'] = "case_type.label as case_type"; + $query->_element['case_type'] = 1; + $query->_tables['case_type'] = $query->_whereTables['case_type'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_start_date', $query->_returnProperties)) { + $query->_select['case_start_date'] = "civicrm_case.start_date as case_start_date"; + $query->_element['case_start_date'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_end_date', $query->_returnProperties)) { + $query->_select['case_end_date'] = "civicrm_case.end_date as case_end_date"; + $query->_element['case_end_date'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_status_id', $query->_returnProperties)) { + $query->_select['case_status_id'] = "case_status.id as case_status_id"; + $query->_element['case_status_id'] = 1; + $query->_tables['case_status_id'] = $query->_whereTables['case_status_id'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_status', $query->_returnProperties)) { + $query->_select['case_status'] = "case_status.label as case_status"; + $query->_element['case_status'] = 1; + $query->_tables['case_status_id'] = $query->_whereTables['case_status_id'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_deleted', $query->_returnProperties)) { + $query->_select['case_deleted'] = "civicrm_case.is_deleted as case_deleted"; + $query->_element['case_deleted'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_role', $query->_returnProperties)) { + $query->_select['case_role'] = "case_relation_type.label_b_a as case_role"; + $query->_element['case_role'] = 1; + $query->_tables['case_relationship'] = $query->_whereTables['case_relationship'] = 1; + $query->_tables['case_relation_type'] = $query->_whereTables['case_relation_type'] = 1; + } + + if (CRM_Utils_Array::value('case_recent_activity_date', $query->_returnProperties)) { + $query->_select['case_recent_activity_date'] = "case_activity.activity_date_time as case_recent_activity_date"; + $query->_element['case_recent_activity_date'] = 1; + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_subject', $query->_returnProperties)) { + $query->_select['case_activity_subject'] = "case_activity.subject as case_activity_subject"; + $query->_element['case_activity_subject'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_subject', $query->_returnProperties)) { + $query->_select['case_subject'] = "civicrm_case.subject as case_subject"; + $query->_element['case_subject'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_source_contact_id', $query->_returnProperties)) { + $query->_select['case_source_contact_id'] = "civicrm_case_reporter.sort_name as case_source_contact_id"; + $query->_element['case_source_contact_id'] = 1; + $query->_tables['civicrm_case_reporter'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_status_id', $query->_returnProperties)) { + $query->_select['case_activity_status_id'] = "rec_activity_status.id as case_activity_status_id"; + $query->_element['case_activity_status_id'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['recent_activity_status'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_status', $query->_returnProperties)) { + $query->_select['case_activity_status'] = "rec_activity_status.label as case_activity_status"; + $query->_element['case_activity_status'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['recent_activity_status'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_duration', $query->_returnProperties)) { + $query->_select['case_activity_duration'] = "case_activity.duration as case_activity_duration"; + $query->_element['case_activity_duration'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_medium_id', $query->_returnProperties)) { + $query->_select['case_activity_medium_id'] = "recent_activity_medium.label as case_activity_medium_id"; + $query->_element['case_activity_medium_id'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['case_activity_medium'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_details', $query->_returnProperties)) { + $query->_select['case_activity_details'] = "case_activity.details as case_activity_details"; + $query->_element['case_activity_details'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_activity_is_auto', $query->_returnProperties)) { + $query->_select['case_activity_is_auto'] = "case_activity.is_auto as case_activity_is_auto"; + $query->_element['case_activity_is_auto'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + + if (CRM_Utils_Array::value('case_scheduled_activity_date', $query->_returnProperties)) { + $query->_select['case_scheduled_activity_date'] = "case_activity.activity_date_time as case_scheduled_activity_date"; + $query->_element['case_scheduled_activity_date'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + if (CRM_Utils_Array::value('case_recent_activity_type', $query->_returnProperties)) { + $query->_select['case_recent_activity_type'] = "rec_activity_type.label as case_recent_activity_type"; + $query->_element['case_recent_activity_type'] = 1; + $query->_tables['case_activity'] = 1; + $query->_tables['case_activity_type'] = 1; + $query->_tables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case'] = 1; + } + } + + /** + * Given a list of conditions in query generate the required + * where clause + * + * @return void + * @access public + */ + static function where(&$query) { + foreach ($query->_params as $id => $values) { + if (!is_array($values) || count($values) != 5) { + continue; + } + + if (substr($query->_params[$id][0], 0, 5) == 'case_') { + if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) { + $query->_useDistinct = TRUE; + } + $grouping = $query->_params[$id][3]; + self::whereClauseSingle($query->_params[$id], $query); + } + } + } + + /** + * where clause for a single field + * + * @return void + * @access public + */ + static function whereClauseSingle(&$values, &$query) { + list($name, $op, $value, $grouping, $wildcard) = $values; + $val = $names = array(); + switch ($name) { + case 'case_status': + case 'case_status_id': + $statuses = CRM_Case_PseudoConstant::caseStatus(); + // Standardize input from checkboxes or single value + if (is_array($value)) { + $value = array_keys($value, 1); + } + foreach ((array) $value as $k) { + if ($k && isset($statuses[$k])) { + $val[$k] = $k; + $names[] = $statuses[$k]; + } + elseif ($k && ($v = CRM_Utils_Array::key($k, $statuses))) { + $val[$v] = $v; + $names[] = $k; + } + } + if ($val) { + $query->_where[$grouping][] = "civicrm_case.status_id IN (" . implode(',', $val) . ")"; + $query->_qill[$grouping][] = ts('Case Status is %1', array(1 => implode(' ' . ts('or') . ' ', $names))); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + } + return; + + case 'case_type_id': + $caseTypes = CRM_Case_PseudoConstant::caseType('label', FALSE); + + if (is_array($value)) { + foreach ($value as $k => $v) { + if ($v) { + $val[$k] = $k; + $names[] = $caseTypes[$k]; + } + } + } + elseif (is_numeric($value)) { + $val[$value] = $value; + $names[] = $value; + } + elseif ($caseTypeId = CRM_Utils_Array::key($value, $caseTypes)) { + $val[$caseTypeId] = $caseTypeId; + $names[] = $caseTypes[$caseTypeId]; + } + + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR . "%' OR civicrm_case.case_type_id LIKE '%" . + CRM_Core_DAO::VALUE_SEPARATOR, $val + ) . CRM_Core_DAO::VALUE_SEPARATOR; + + $query->_where[$grouping][] = "(civicrm_case.case_type_id LIKE '%{$value}%')"; + + $query->_qill[$grouping][] = ts('Case Type is %1', array(1 => implode(' ' . ts('or') . ' ', $names))); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + return; + + case 'case_id': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case.id", $op, $value, 'Int'); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + return; + + case 'case_owner': + case 'case_mycases': + if (!empty($value)) { + if ($value == 2) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_b", $op, $userID, 'Int'); + $query->_qill[$grouping][] = ts('Case %1 My Cases', array(1 => $op)); + $query->_tables['case_relationship'] = $query->_whereTables['case_relationship'] = 1; + } + elseif ($value == 1) { + $query->_qill[$grouping][] = ts('Case %1 All Cases', array(1 => $op)); + $query->_where[$grouping][] = "civicrm_case_contact.contact_id = contact_a.id"; + } + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + } + return; + + case 'case_deleted': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case.is_deleted", $op, $value, 'Boolean'); + if ($value) { + $query->_qill[$grouping][] = ts("Find Deleted Cases"); + } + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + return; + + case 'case_activity_subject': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.subject", $op, $value, 'String'); + $query->_qill[$grouping][] = ts("Activity Subject %1 '%2'", array(1 => $op, 2 => $value)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_subject': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case.subject", $op, $value, 'String'); + $query->_qill[$grouping][] = ts("Case Subject %1 '%2'", array(1 => $op, 2 => $value)); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_source_contact_id': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case_reporter.sort_name", $op, $value, 'String'); + $query->_qill[$grouping][] = ts("Activity Reporter %1 '%2'", array(1 => $op, 2 => $value)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case_reporter'] = $query->_whereTables['civicrm_case_reporter'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_recent_activity_date': + $date = CRM_Utils_Date::format($value); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_date_time", $op, $date, 'Date'); + if ($date) { + $date = CRM_Utils_Date::customFormat($date); + $query->_qill[$grouping][] = ts("Activity Actual Date %1 %2", array(1 => $op, 2 => $date)); + } + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_scheduled_activity_date': + $date = CRM_Utils_Date::format($value); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_date_time", $op, $date, 'Date'); + if ($date) { + $date = CRM_Utils_Date::customFormat($date); + $query->_qill[$grouping][] = ts("Activity Schedule Date %1 %2", array(1 => $op, 2 => $date)); + } + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_recent_activity_type': + $names = $value; + if ($activityType = CRM_Core_OptionGroup::getLabel('activity_type', $value, 'value')) { + $names = $activityType; + } + + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_type_id", $op, $value, 'Int'); + $query->_qill[$grouping][] = ts("Activity Type %1 %2", array(1 => $op, 2 => $names)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['case_activity_type'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_activity_status_id': + $names = $value; + if ($activityStatus = CRM_Core_OptionGroup::getLabel('activity_status', $value, 'value')) { + $names = $activityStatus; + } + + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.status_id", $op, $value, 'Int'); + $query->_qill[$grouping][] = ts("Activity Type %1 %2", array(1 => $op, 2 => $names)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['case_activity_status'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_activity_duration': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.duration", $op, $value, 'Int'); + $query->_qill[$grouping][] = ts("Activity Duration %1 %2", array(1 => $op, 2 => $value)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_activity_medium_id': + $names = $value; + if ($activityMedium = CRM_Core_OptionGroup::getLabel('encounter_medium', $value, 'value')) { + $names = $activityMedium; + } + + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.medium_id", $op, $value, 'Int'); + $query->_qill[$grouping][] = ts("Activity Medium %1 %2", array(1 => $op, 2 => $names)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['case_activity_medium'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_activity_details': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.details", $op, $value, 'String'); + $query->_qill[$grouping][] = ts("Activity Details %1 '%2'", array(1 => $op, 2 => $value)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_activity_is_auto': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.is_auto", $op, $value, 'Boolean'); + $query->_qill[$grouping][] = ts("Activity Auto Genrated %1 '%2'", array(1 => $op, 2 => $value)); + $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + // adding where clause for case_role + + case 'case_role': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_relation_type.name_b_a", $op, $value, 'String'); + $query->_qill[$grouping][] = ts("Role in Case %1 '%2'", array(1 => $op, 2 => $value)); + $query->_tables['case_relation_type'] = $query->_whereTables['case_relationship_type'] = 1; + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + return; + + case 'case_from_start_date_low': + case 'case_from_start_date_high': + $query->dateQueryBuilder($values, + 'civicrm_case', 'case_from_start_date', 'start_date', 'Start Date' + ); + return; + + case 'case_to_end_date_low': + case 'case_to_end_date_high': + $query->dateQueryBuilder($values, + 'civicrm_case', 'case_to_end_date', 'end_date', 'End Date' + ); + return; + + case 'case_start_date': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case.start_date", $op, $value, 'Int'); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + return; + + case 'case_end_date': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case.end_date", $op, $value, 'Int'); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + return; + + case 'case_taglist': + $taglist = $value; + $value = array(); + foreach ($taglist as $val) { + if ($val) { + $val = explode(',', $val); + foreach ($val as $tId) { + if (is_numeric($tId)) { + $value[$tId] = 1; + } + } + } + } + case 'case_tags': + $tags = CRM_Core_PseudoConstant::tag(); + + if (is_array($value)) { + foreach ($value as $k => $v) { + if ($v) { + $val[$k] = $k; + $names[] = $tags[$k]; + } + } + } + + $query->_where[$grouping][] = " civicrm_case_tag.tag_id IN (" . implode(',', $val) . " )"; + $query->_qill[$grouping][] = ts('Case Tags %1', array(1 => $op)) . ' ' . implode(' ' . ts('or') . ' ', $names); + $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1; + $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1; + $query->_tables['civicrm_case_tag'] = $query->_whereTables['civicrm_case_tag'] = 1; + return; + } + } + + static function from($name, $mode, $side) { + $from = ""; + + switch ($name) { + case 'civicrm_case_contact': + $from .= " $side JOIN civicrm_case_contact ON civicrm_case_contact.contact_id = contact_a.id "; + break; + + case 'civicrm_case_reporter': + $from .= " $side JOIN civicrm_contact as civicrm_case_reporter ON case_activity.source_contact_id = civicrm_case_reporter.id "; + break; + + case 'civicrm_case': + $from .= " INNER JOIN civicrm_case ON civicrm_case_contact.case_id = civicrm_case.id"; + break; + + case 'case_status_id': + $from .= " $side JOIN civicrm_option_group option_group_case_status ON (option_group_case_status.name = 'case_status')"; + $from .= " $side JOIN civicrm_option_value case_status ON (civicrm_case.status_id = case_status.value AND option_group_case_status.id = case_status.option_group_id ) "; + break; + + case 'case_type': + $from .= " $side JOIN civicrm_option_group option_group_case_type ON (option_group_case_type.name = 'case_type')"; + $from .= " $side JOIN civicrm_option_value case_type ON (civicrm_case.case_type_id = case_type.value AND option_group_case_type.id = case_type.option_group_id ) "; + break; + + case 'case_activity_type': + $from .= " $side JOIN civicrm_option_group option_group_activity_type ON (option_group_activity_type.name = 'activity_type')"; + $from .= " $side JOIN civicrm_option_value rec_activity_type ON (case_activity.activity_type_id = rec_activity_type.value AND option_group_activity_type.id = rec_activity_type.option_group_id ) "; + break; + + case 'recent_activity_status': + $from .= " $side JOIN civicrm_option_group option_group_activity_status ON (option_group_activity_status.name = 'activity_status')"; + $from .= " $side JOIN civicrm_option_value rec_activity_status ON (case_activity.status_id = rec_activity_status.value AND option_group_activity_status.id = rec_activity_status.option_group_id ) "; + break; + + case 'case_relationship': + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + $from .= " $side JOIN civicrm_relationship case_relationship ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.case_id = civicrm_case.id )"; + break; + + case 'case_relation_type': + $from .= " $side JOIN civicrm_relationship_type case_relation_type ON ( case_relation_type.id = case_relationship.relationship_type_id AND +case_relation_type.id = case_relationship.relationship_type_id )"; + break; + + case 'case_activity_medium': + $from .= " $side JOIN civicrm_option_group option_group_activity_medium ON (option_group_activity_medium.name = 'encounter_medium')"; + $from .= " $side JOIN civicrm_option_value recent_activity_medium ON (case_activity.medium_id = recent_activity_medium.value AND option_group_activity_medium.id = recent_activity_medium.option_group_id ) "; + break; + + case 'case_activity': + $from .= " INNER JOIN civicrm_case_activity ON civicrm_case_activity.case_id = civicrm_case.id "; + $from .= " INNER JOIN civicrm_activity case_activity ON ( civicrm_case_activity.activity_id = case_activity.id + AND case_activity.is_current_revision = 1 )"; + break; + + case 'civicrm_case_tag': + $from .= " $side JOIN civicrm_entity_tag as civicrm_case_tag ON ( civicrm_case_tag.entity_table = 'civicrm_case' AND civicrm_case_tag.entity_id = civicrm_case.id ) "; + break; + } + return $from; + } + + /** + * getter for the qill object + * + * @return string + * @access public + */ + function qill() { + return (isset($this->_qill)) ? $this->_qill : ""; + } + + static function defaultReturnProperties($mode, + $includeCustomFields = TRUE + ) { + + $properties = NULL; + + if ($mode & CRM_Contact_BAO_Query::MODE_CASE) { + $properties = array( + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'contact_id' => 1, + 'sort_name' => 1, + 'display_name' => 1, + 'case_id' => 1, + 'case_activity_subject' => 1, + 'case_subject' => 1, + 'case_status' => 1, + 'case_type' => 1, + 'case_role' => 1, + 'case_deleted' => 1, + 'case_recent_activity_date' => 1, + 'case_recent_activity_type' => 1, + 'case_scheduled_activity_date' => 1, + 'phone' => 1, + // 'case_scheduled_activity_type'=> 1 + ); + + if ($includeCustomFields) { + // also get all the custom case properties + $fields = CRM_Core_BAO_CustomField::getFieldsForImport('Case'); + if (!empty($fields)) { + foreach ($fields as $name => $dontCare) { + $properties[$name] = 1; + } + } + } + } + + return $properties; + } + + /** + * This includes any extra fields that might need for export etc + */ + static function extraReturnProperties($mode) { + $properties = NULL; + + if ($mode & CRM_Contact_BAO_Query::MODE_CASE) { + $properties = array( + 'case_start_date' => 1, + 'case_end_date' => 1, + 'case_subject' => 1, + 'case_source_contact_id' => 1, + 'case_activity_status' => 1, + 'case_activity_duration' => 1, + 'case_activity_medium_id' => 1, + 'case_activity_details' => 1, + 'case_activity_is_auto' => 1, + ); + } + return $properties; + } + + static function tableNames(&$tables) { + if (CRM_Utils_Array::value('civicrm_case', $tables)) { + $tables = array_merge(array('civicrm_case_contact' => 1), $tables); + } + + if (CRM_Utils_Array::value('case_relation_type', $tables)) { + $tables = array_merge(array('case_relationship' => 1), $tables); + } + } + + /** + * add all the elements shared between case search and advanaced search + * + * @access public + * + * @return void + * @static + */ + static function buildSearchForm(&$form) { + $config = CRM_Core_Config::singleton(); + + //validate case configuration. + $configured = CRM_Case_BAO_Case::isCaseConfigured(); + $form->assign('notConfigured', !$configured['configured']); + + $caseTypes = CRM_Case_PseudoConstant::caseType('label', FALSE); + foreach ($caseTypes as $id => $name) { + $form->addElement('checkbox', "case_type_id[$id]", NULL, $name); + } + + $statuses = CRM_Case_PseudoConstant::caseStatus('label', FALSE); + foreach ($statuses as $id => $name) { + $form->addElement('checkbox', "case_status_id[$id]", NULL, $name); + } + + CRM_Core_Form_Date::buildDateRange($form, 'case_from', 1, '_start_date_low', '_start_date_high', ts('From'), FALSE, FALSE); + CRM_Core_Form_Date::buildDateRange($form, 'case_to', 1, '_end_date_low', '_end_date_high', ts('From'), FALSE, FALSE); + + $form->assign('validCiviCase', TRUE); + + //give options when all cases are accessible. + $accessAllCases = FALSE; + if (CRM_Core_Permission::check('access all cases and activities')) { + $accessAllCases = TRUE; + $caseOwner = array(1 => ts('Search All Cases'), 2 => ts('Only My Cases')); + $form->addRadio('case_owner', ts('Cases'), $caseOwner); + } + $form->assign('accessAllCases', $accessAllCases); + + $caseTags = CRM_Core_BAO_Tag::getTags('civicrm_case'); + + if ($caseTags) { + foreach ($caseTags as $tagID => $tagName) { + $form->_tagElement = &$form->addElement('checkbox', "case_tags[$tagID]", NULL, $tagName); + } + } + + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_case'); + CRM_Core_Form_Tag::buildQuickForm($form, $parentNames, 'civicrm_case', NULL, TRUE, FALSE, TRUE); + + if (CRM_Core_Permission::check('administer CiviCRM')) { + $form->addElement('checkbox', 'case_deleted', ts('Deleted Cases')); + } + + // add all the custom searchable fields + $extends = array('Case'); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, $extends); + if ($groupDetails) { + $form->assign('caseGroupTree', $groupDetails); + foreach ($groupDetails as $group) { + foreach ($group['fields'] as $field) { + $fieldId = $field['id']; + $elementName = 'custom_' . $fieldId; + CRM_Core_BAO_CustomField::addQuickFormElement($form, + $elementName, + $fieldId, + FALSE, FALSE, TRUE + ); + } + } + } + $form->setDefaults(array('case_owner' => 1)); + } + + static function searchAction(&$row, $id) {} + + static function addShowHide(&$showHide) { + $showHide->addHide('caseForm'); + $showHide->addShow('caseForm_show'); + } +} + diff --git a/CRM/Case/Config.php b/CRM/Case/Config.php new file mode 100644 index 0000000000..664e9070fd --- /dev/null +++ b/CRM/Case/Config.php @@ -0,0 +1,40 @@ +_stateMachine = new CRM_Case_StateMachine_Search($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $config = CRM_Core_Config::singleton(); + $this->addActions(); + } +} + diff --git a/CRM/Case/Form/Activity.php b/CRM/Case/Form/Activity.php new file mode 100644 index 0000000000..b8f2a57bcc --- /dev/null +++ b/CRM/Case/Form/Activity.php @@ -0,0 +1,707 @@ +_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + if (!$this->_context) { + $this->_context = 'caseActivity'; + } + $this->_crmDir = 'Case'; + $this->assign('context', $this->_context); + + $result = parent::preProcess(); + + $scheduleStatusId = CRM_Core_OptionGroup::getValue('activity_status', 'Scheduled', 'name'); + $this->assign('scheduleStatusId', $scheduleStatusId); + + if ($this->_cdType) { + return $result; + } + + if (!$this->_caseId && $this->_activityId) { + $this->_caseId = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $this->_activityId, + 'case_id', 'activity_id' + ); + } + if ($this->_caseId) { + $this->assign('caseId', $this->_caseId); + } + + if (!$this->_caseId || + (!$this->_activityId && !$this->_activityTypeId) + ) { + CRM_Core_Error::fatal('required params missing.'); + } + + //check for case activity access. + if (!CRM_Case_BAO_Case::accessCiviCase()) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + //validate case id. + if ($this->_caseId && + !CRM_Core_Permission::check('access all cases and activities') + ) { + $session = CRM_Core_Session::singleton(); + $allCases = CRM_Case_BAO_Case::getCases(TRUE, $session->get('userID')); + if (!array_key_exists($this->_caseId, $allCases)) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + } + + //validate case activity id. + if ($this->_activityId && + ($this->_action & CRM_Core_Action::UPDATE) + ) { + $valid = CRM_Case_BAO_Case::checkPermission($this->_activityId, 'edit', + $this->_activityTypeId + ); + if (!$valid) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + } + + $this->_caseType = CRM_Case_BAO_Case::getCaseType($this->_caseId, 'name'); + $this->assign('caseType', $this->_caseType); + + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); + $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); + $this->assign('multiClient', $isMultiClient); + + $clients = CRM_Case_BAO_Case::getContactNames($this->_caseId); + $this->assign('client_names', $clients); + + // set context for pushUserContext and for statusBounce + if ($this->_context == 'fulltext') { + if ($this->_action == CRM_Core_Action::UPDATE || $this->_action == CRM_Core_Action::DELETE) { + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$this->_caseId}&show=1&context={$this->_context}" + ); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/search/custom', 'force=1'); + } + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$this->_caseId}&show=1" + ); + } + if (!$this->_activityId) { + $caseTypes = CRM_Case_PseudoConstant::caseType(); + + if (empty($caseTypes) && ($this->_activityTypeName == 'Change Case Type') && !$this->_caseId) { + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$this->_caseId}&show=1" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + CRM_Core_Error::statusBounce(ts("You do not have any active Case Types")); + } + + // check if activity count is within the limit + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $activityInst = $xmlProcessor->getMaxInstance($this->_caseType); + + // If not bounce back and also provide activity edit link + if (isset($activityInst[$this->_activityTypeName])) { + $activityCount = CRM_Case_BAO_Case::getCaseActivityCount($this->_caseId, $this->_activityTypeId); + if ($activityCount >= $activityInst[$this->_activityTypeName]) { + if ($activityInst[$this->_activityTypeName] == 1) { + $atArray = array('activity_type_id' => $this->_activityTypeId); + $activities = CRM_Case_BAO_Case::getCaseActivity($this->_caseId, + $atArray, + $this->_currentUserId + ); + $activities = array_keys($activities); + $activities = $activities[0]; + $editUrl = CRM_Utils_System::url('civicrm/case/activity', + "reset=1&cid={$this->_currentlyViewedContactId}&caseid={$this->_caseId}&action=update&id={$activities}" + ); + } + CRM_Core_Error::statusBounce(ts("You can not add another '%1' activity to this case. %2", + array( + 1 => $this->_activityTypeName, + 2 => "Do you want to edit the existing activity ?" + ) + ), + $url + ); + } + } + } + + if ($this->_currentlyViewedContactId) { + CRM_Contact_Page_View::setTitle($this->_currentlyViewedContactId); + } + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $this->_defaults = parent::setDefaultValues(); + $targetContactValues = array(); + + //get all clients. + $clients = CRM_Case_BAO_Case::getContactNames($this->_caseId); + if (isset($this->_activityId) && empty($_POST)) { + if (!CRM_Utils_Array::crmIsEmptyArray($this->_defaults['target_contact'])) { + $targetContactValues = array_combine(array_unique($this->_defaults['target_contact']), + explode(';', trim($this->_defaults['target_contact_value'])) + ); + + //exclude all clients. + foreach ($clients as $clientId => $vals) { + if (array_key_exists($clientId, $targetContactValues)) { + unset($targetContactValues[$clientId]); + } + } + } + } + $this->assign('targetContactValues', empty($targetContactValues) ? FALSE : $targetContactValues); + + //return form for ajax + if ($this->_cdType) { + return $this->_defaults; + } + + if (isset($this->_encounterMedium)) { + $this->_defaults['medium_id'] = $this->_encounterMedium; + } + elseif (empty($this->_defaults['medium_id'])) { + // set default encounter medium CRM-4816 + $medium = CRM_Core_OptionGroup::values('encounter_medium', FALSE, FALSE, FALSE, 'AND is_default = 1'); + if (count($medium) == 1) { + $this->_defaults['medium_id'] = key($medium); + } + } + + return $this->_defaults; + } + + public function buildQuickForm() { + $this->_fields['source_contact_id']['label'] = ts('Reported By'); + $this->_fields['status_id']['attributes'] = array('' => ts('- select -')) + CRM_Core_PseudoConstant::activityStatus(); + + if ($this->_caseType) { + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $aTypes = $xmlProcessor->get($this->_caseType, 'ActivityTypes', TRUE); + + // remove Open Case activity type since we're inside an existing case + $openCaseID = CRM_Core_OptionGroup::getValue('activity_type', 'Open Case', 'name'); + unset($aTypes[$openCaseID]); + asort($aTypes); + $this->_fields['followup_activity_type_id']['attributes'] = array( + '' => '- select activity type -') + $aTypes; + } + + $result = parent::buildQuickForm(); + + if ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::DETACH | CRM_Core_Action::RENEW)) { + return; + } + + if ($this->_cdType) { + return $result; + } + + $this->assign('urlPath', 'civicrm/case/activity'); + + $encounterMediums = CRM_Case_PseudoConstant::encounterMedium(); + if ($this->_activityTypeFile == 'OpenCase') { + $this->_encounterMedium = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $this->_activityId, + 'medium_id' + ); + if (!array_key_exists($this->_encounterMedium, $encounterMediums)) { + $encounterMediums[$this->_encounterMedium] = CRM_Core_OptionGroup::getLabel('encounter_medium', + $this->_encounterMedium, + FALSE + ); + } + } + + $this->add('select', 'medium_id', ts('Medium'), $encounterMediums, TRUE); + + $this->_relatedContacts = CRM_Case_BAO_Case::getRelatedAndGlobalContacts($this->_caseId); + //add case client in send a copy selector.CRM-4438. + $relatedContacts = CRM_Case_BAO_Case::getContactNames($this->_caseId); + if (!empty($relatedContacts)) { + foreach ($relatedContacts as $relatedContact) { + $this->_relatedContacts[] = $relatedContact; + } + } + + if (!empty($this->_relatedContacts)) { + $checkBoxes = array(); + foreach ($this->_relatedContacts as $id => $row) { + $checkBoxes[$id] = $this->addElement('checkbox', $id, NULL, ''); + } + + $this->addGroup($checkBoxes, 'contact_check'); + $this->addElement('checkbox', 'toggleSelect', NULL, NULL, + array('onclick' => "return toggleCheckboxVals('contact_check',this);") + ); + $this->assign('searchRows', $this->_relatedContacts); + } + + $this->addFormRule(array('CRM_Case_Form_Activity', 'formRule'), $this); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + // skip form rule if deleting + if (CRM_Utils_Array::value('_qf_Activity_next_', $fields) == 'Delete' || CRM_Utils_Array::value('_qf_Activity_next_', $fields) == 'Restore') { + return TRUE; + } + + return parent::formrule($fields, $files, $self); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $transaction = new CRM_Core_Transaction(); + + if ($this->_action & CRM_Core_Action::DELETE) { + $statusMsg = NULL; + + //block deleting activities which affects + //case attributes.CRM-4543 + $activityCondition = " AND v.name IN ('Open Case', 'Change Case Type', 'Change Case Status', 'Change Case Start Date')"; + $caseAttributeActivities = CRM_Core_OptionGroup::values('activity_type', FALSE, FALSE, FALSE, $activityCondition); + + if (!array_key_exists($this->_activityTypeId, $caseAttributeActivities)) { + $params = array('id' => $this->_activityId); + $activityDelete = CRM_Activity_BAO_Activity::deleteActivity($params, TRUE); + if ($activityDelete) { + $statusMsg = ts('The selected activity has been moved to the Trash. You can view and / or restore deleted activities by checking "Deleted Activities" from the Case Activities search filter (under Manage Case).
    '); + } + } + else { + $statusMsg = ts("Selected Activity cannot be deleted."); + } + + $tagParams = array( + 'entity_table' => 'civicrm_activity', + 'entity_id' => $this->_activityId + ); + CRM_Core_BAO_EntityTag::del($tagParams); + + CRM_Core_Session::setStatus('', $statusMsg, 'info'); + return; + } + + if ($this->_action & CRM_Core_Action::RENEW) { + $statusMsg = NULL; + $params = array('id' => $this->_activityId); + $activityRestore = CRM_Activity_BAO_Activity::restoreActivity($params); + if ($activityRestore) { + $statusMsg = ts('The selected activity has been restored.
    '); + } + CRM_Core_Session::setStatus('', $statusMsg, 'info'); + return; + } + + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + if ($params['source_contact_id']) { + $params['source_contact_id'] = $params['source_contact_qid']; + } + + //set parent id if its edit mode + if ($parentId = CRM_Utils_Array::value('parent_id', $this->_defaults)) { + $params['parent_id'] = $parentId; + } + + // required for status msg + $recordStatus = 'created'; + + // store the dates with proper format + $params['activity_date_time'] = CRM_Utils_Date::processDate($params['activity_date_time'], $params['activity_date_time_time']); + $params['activity_type_id'] = $this->_activityTypeId; + + // format with contact (target contact) values + if (isset($params['contact'][1])) { + $params['target_contact_id'] = explode(',', $params['contact'][1]); + } + else { + $params['target_contact_id'] = array(); + } + + // format activity custom data + if (CRM_Utils_Array::value('hidden_custom', $params)) { + if ($this->_activityId) { + // unset custom fields-id from params since we want custom + // fields to be saved for new activity. + foreach ($params as $key => $value) { + $match = array(); + if (preg_match('/^(custom_\d+_)(\d+)$/', $key, $match)) { + $params[$match[1] . '-1'] = $params[$key]; + + // for autocomplete transfer hidden value instead of label + if ($params[$key] && isset($params[$key . '_id'])) { + $params[$match[1] . '-1_id'] = $params[$key . '_id']; + unset($params[$key . '_id']); + } + unset($params[$key]); + } + } + } + + // build custom data getFields array + $customFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, $this->_activityTypeId); + $customFields = CRM_Utils_Array::crmArrayMerge($customFields, + CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, + NULL, NULL, TRUE + ) + ); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_activityId, + 'Activity' + ); + } + + // assigning formated value + if (CRM_Utils_Array::value('assignee_contact_id', $params)) { + $params['assignee_contact_id'] = explode(',', $params['assignee_contact_id']); + } + else { + $params['assignee_contact_id'] = array(); + } + + + if (isset($this->_activityId)) { + // activity which hasn't been modified by a user yet + if ($this->_defaults['is_auto'] == 1) { + $params['is_auto'] = 0; + } + + // always create a revision of an case activity. CRM-4533 + $newActParams = $params; + + // add target contact values in update mode + if (empty($params['target_contact_id']) && !empty($this->_defaults['target_contact'])) { + $newActParams['target_contact_id'] = $this->_defaults['target_contact']; + } + + // record status for status msg + $recordStatus = 'updated'; + } + + if (!isset($newActParams)) { + // add more attachments if needed for old activity + CRM_Core_BAO_File::formatAttachment($params, + $params, + 'civicrm_activity' + ); + + // call begin post process, before the activity is created/updated. + $this->beginPostProcess($params); + $params['case_id'] = $this->_caseId; + // activity create/update + $activity = CRM_Activity_BAO_Activity::create($params); + + // call end post process, after the activity has been created/updated. + $this->endPostProcess($params, $activity); + } + else { + // since the params we need to set are very few, and we don't want rest of the + // work done by bao create method , lets use dao object to make the changes + $params = array('id' => $this->_activityId); + $params['is_current_revision'] = 0; + $activity = new CRM_Activity_DAO_Activity(); + $activity->copyValues($params); + $activity->save(); + } + + // create a new version of activity if activity was found to + // have been modified/created by user + if (isset($newActParams)) { + // set proper original_id + if (CRM_Utils_Array::value('original_id', $this->_defaults)) { + $newActParams['original_id'] = $this->_defaults['original_id']; + } + else { + $newActParams['original_id'] = $activity->id; + } + //is_current_revision will be set to 1 by default. + + // add attachments if any + CRM_Core_BAO_File::formatAttachment($newActParams, + $newActParams, + 'civicrm_activity' + ); + + // call begin post process, before the activity is created/updated. + $this->beginPostProcess($newActParams); + $newActParams['case_id'] = $this->_caseId; + + $activity = CRM_Activity_BAO_Activity::create($newActParams); + + // call end post process, after the activity has been created/updated. + $this->endPostProcess($newActParams, $activity); + + // copy files attached to old activity if any, to new one, + // as long as users have not selected the 'delete attachment' option. + if (!CRM_Utils_Array::value('is_delete_attachment', $newActParams)) { + CRM_Core_BAO_File::copyEntityFile('civicrm_activity', $this->_activityId, + 'civicrm_activity', $activity->id + ); + } + + // copy back params to original var + $params = $newActParams; + } + + if ($activity->id) { + // add tags if exists + $tagParams = array(); + if (!empty($params['tag'])) { + foreach ($params['tag'] as $tag) { + $tagParams[$tag] = 1; + } + } + + //save static tags + CRM_Core_BAO_EntityTag::create($tagParams, 'civicrm_activity', $activity->id); + + //save free tags + if (isset($params['taglist']) && !empty($params['taglist'])) { + CRM_Core_Form_Tag::postProcess($params['taglist'], $activity->id, 'civicrm_activity', $this); + } + } + + // update existing case record if needed + $caseParams = $params; + $caseParams['id'] = $this->_caseId; + + if (CRM_Utils_Array::value('case_type_id', $caseParams)) { + $caseParams['case_type_id'] = CRM_Core_DAO::VALUE_SEPARATOR . $caseParams['case_type_id'] . CRM_Core_DAO::VALUE_SEPARATOR; + } + if (CRM_Utils_Array::value('case_status_id', $caseParams)) { + $caseParams['status_id'] = $caseParams['case_status_id']; + } + + // unset params intended for activities only + unset($caseParams['subject'], $caseParams['details'], + $caseParams['status_id'], $caseParams['custom'] + ); + $case = CRM_Case_BAO_Case::create($caseParams); + + // create case activity record + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $this->_caseId, + ); + CRM_Case_BAO_Case::processCaseActivity($caseParams); + + + // create activity assignee records + $assigneeParams = array('activity_id' => $activity->id); + + if (!CRM_Utils_Array::crmIsEmptyArray($params['assignee_contact_id'])) { + //skip those assignee contacts which are already assigned + //while sending a copy.CRM-4509. + $activityAssigned = array_flip($params['assignee_contact_id']); + $activityId = isset($this->_activityId) ? $this->_activityId : $activity->id; + $assigneeContacts = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($activityId); + $activityAssigned = array_diff_key($activityAssigned, $assigneeContacts); + + foreach ($params['assignee_contact_id'] as $key => $id) { + $assigneeParams['assignee_contact_id'] = $id; + CRM_Activity_BAO_Activity::createActivityAssignment($assigneeParams); + } + //modify assigne_contact as per newly assigned contact before sending copy. CRM-4509. + $params['assignee_contact_id'] = $activityAssigned; + } + + // Insert civicrm_log record for the activity (e.g. store the + // created / edited by contact id and date for the activity) + // Note - civicrm_log is already created by CRM_Activity_BAO_Activity::create() + + + // send copy to selected contacts. + $mailStatus = ''; + $mailToContacts = array(); + + //CRM-5695 + //check for notification settings for assignee contacts + $selectedContacts = array('contact_check'); + + if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'activity_assignee_notification' + )) { + $selectedContacts[] = 'assignee_contact_id'; + } + + foreach ($selectedContacts as $dnt => $val) { + if (array_key_exists($val, $params) && !CRM_Utils_array::crmIsEmptyArray($params[$val])) { + if ($val == 'contact_check') { + $mailStatus = ts("A copy of the activity has also been sent to selected contacts(s)."); + } + else { + $this->_relatedContacts = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($activity->id, TRUE, FALSE); + $mailStatus .= ' ' . ts("A copy of the activity has also been sent to assignee contacts(s)."); + } + //build an associative array with unique email addresses. + foreach ($params[$val] as $id => $dnc) { + if (isset($id) && array_key_exists($id, $this->_relatedContacts)) { + //if email already exists in array then append with ', ' another role only otherwise add it to array. + if ($contactDetails = CRM_Utils_Array::value($this->_relatedContacts[$id]['email'], $mailToContacts)) { + $caseRole = CRM_Utils_Array::value('role', $this->_relatedContacts[$id]); + $mailToContacts[$this->_relatedContacts[$id]['email']]['role'] = $contactDetails['role'] . ', ' . $caseRole; + } + else { + $mailToContacts[$this->_relatedContacts[$id]['email']] = $this->_relatedContacts[$id]; + } + } + } + } + } + + if (!CRM_Utils_array::crmIsEmptyArray($mailToContacts)) { + //include attachments while sendig a copy of activity. + $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_activity', + $activity->id + ); + + $ics = new CRM_Activity_BAO_ICalendar( $activity ); + $ics->addAttachment( $attachments, $mailToContacts ); + + $result = CRM_Case_BAO_Case::sendActivityCopy($this->_currentlyViewedContactId, + $activity->id, $mailToContacts, $attachments, $this->_caseId + ); + + $ics->cleanup(); + + if (empty($result)) { + $mailStatus = ''; + } + } + else { + $mailStatus = ''; + } + + // create follow up activity if needed + $followupStatus = ''; + if (CRM_Utils_Array::value('followup_activity_type_id', $params)) { + $followupActivity = CRM_Activity_BAO_Activity::createFollowupActivity($activity->id, $params); + + if ($followupActivity) { + $caseParams = array( + 'activity_id' => $followupActivity->id, + 'case_id' => $this->_caseId, + ); + CRM_Case_BAO_Case::processCaseActivity($caseParams); + $followupStatus = ts("A followup activity has been scheduled."); + } + } + + CRM_Core_Session::setStatus('', ts("'%1' activity has been %2. %3 %4", + array( + 1 => $this->_activityTypeName, + 2 => $recordStatus, + 3 => $followupStatus, + 4 => $mailStatus + ) + ), 'info'); + } +} + diff --git a/CRM/Case/Form/Activity/ChangeCaseStartDate.php b/CRM/Case/Form/Activity/ChangeCaseStartDate.php new file mode 100644 index 0000000000..57012650ba --- /dev/null +++ b/CRM/Case/Form/Activity/ChangeCaseStartDate.php @@ -0,0 +1,241 @@ +_caseId)) { + CRM_Core_Error::fatal(ts('Case Id not found.')); + } + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form) { + $defaults = array(); + + $openCaseActivityType = CRM_Core_OptionGroup::getValue('activity_type', + 'Open Case', + 'name' + ); + $openCaseParams = array('activity_type_id' => $openCaseActivityType); + $openCaseInfo = CRM_Case_BAO_Case::getCaseActivityDates($form->_caseId, $openCaseParams, TRUE); + if (empty($openCaseInfo)) { + list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults(); + } + else { + // We know there can only be one result + $openCaseInfo = current($openCaseInfo); + + // store activity id for updating it later + $form->openCaseActivityId = $openCaseInfo['id']; + + list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults($openCaseInfo['activity_date']); + } + return $defaults; + } + + static function buildQuickForm(&$form) { + $form->removeElement('status_id'); + $form->removeElement('priority_id'); + + $currentStartDate = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $form->_caseId, 'start_date'); + $form->assign('current_start_date', $currentStartDate); + $form->addDate('start_date', ts('New Start Date'), FALSE, array('formatType' => 'activityDateTime')); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $form) { + return TRUE; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function beginPostProcess(&$form, &$params) { + if ($form->_context == 'case') { + $params['id'] = $form->_id; + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function endPostProcess(&$form, &$params, $activity) { + if (CRM_Utils_Array::value('start_date', $params)) { + $params['start_date'] = CRM_Utils_Date::processDate($params['start_date'], $params['start_date_time']); + } + + $caseType = $form->_caseType; + + if (!$caseType && $form->_caseId) { + + $query = " +SELECT cov_type.label as case_type FROM civicrm_case +LEFT JOIN civicrm_option_group cog_type ON cog_type.name = 'case_type' +LEFT JOIN civicrm_option_value cov_type ON +( civicrm_case.case_type_id = cov_type.value AND cog_type.id = cov_type.option_group_id ) +WHERE civicrm_case.id= %1"; + + $queryParams = array(1 => array($form->_caseId, 'Integer')); + $caseType = CRM_Core_DAO::singleValueQuery($query, $queryParams); + } + + if (!$form->_currentlyViewedContactId || + !$form->_currentUserId || + !$form->_caseId || + !$caseType + ) { + CRM_Core_Error::fatal('Required parameter missing for ChangeCaseType - end post processing'); + } + + $config = CRM_Core_Config::singleton(); + + $params['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + $activity->status_id = $params['status_id']; + $params['priority_id'] = CRM_Core_OptionGroup::getValue('priority', 'Normal', 'name'); + $activity->priority_id = $params['priority_id']; + + // 1. save activity subject with new start date + $currentStartDate = CRM_Utils_Date::customFormat(CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', + $form->_caseId, 'start_date' + ), $config->dateformatFull); + $newStartDate = CRM_Utils_Date::customFormat(CRM_Utils_Date::mysqlToIso($params['start_date']), $config->dateformatFull); + $subject = 'Change Case Start Date from ' . $currentStartDate . ' to ' . $newStartDate; + $activity->subject = $subject; + $activity->save(); + // 2. initiate xml processor + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $xmlProcessorParams = array( + 'clientID' => $form->_currentlyViewedContactId, + 'creatorID' => $form->_currentUserId, + 'standardTimeline' => 0, + 'activity_date_time' => $params['start_date'], + 'caseID' => $form->_caseId, + 'caseType' => $caseType, + 'activityTypeName' => 'Change Case Start Date', + 'activitySetName' => 'standard_timeline', + 'resetTimeline' => 1, + ); + + $xmlProcessor->run($caseType, $xmlProcessorParams); + + // 2.5 Update open case activity date + // Multiple steps since revisioned + if ($form->openCaseActivityId) { + + $abao = new CRM_Activity_BAO_Activity(); + $oldParams = array('id' => $form->openCaseActivityId); + $oldActivityDefaults = array(); + $oldActivity = $abao->retrieve($oldParams, $oldActivityDefaults); + + // save the old values + require_once 'api/v3/utils.php'; + $openCaseParams = array(); + //@todo calling api functions directly is not supported + _civicrm_api3_object_to_array($oldActivity, $openCaseParams); + + // update existing revision + $oldParams = array( + 'id' => $form->openCaseActivityId, + 'is_current_revision' => 0, + ); + $oldActivity = new CRM_Activity_DAO_Activity(); + $oldActivity->copyValues($oldParams); + $oldActivity->save(); + + // change some params for the new one + unset($openCaseParams['id']); + $openCaseParams['activity_date_time'] = $params['start_date']; + $openCaseParams['target_contact_id'] = $oldActivityDefaults['target_contact']; + $openCaseParams['assignee_contact_id'] = $oldActivityDefaults['assignee_contact']; + $session = CRM_Core_Session::singleton(); + $openCaseParams['source_contact_id'] = $session->get('userID'); + + // original_id always refers to the first activity, so only update if null (i.e. this is the second revision) + $openCaseParams['original_id'] = $openCaseParams['original_id'] ? $openCaseParams['original_id'] : $form->openCaseActivityId; + + $newActivity = CRM_Activity_BAO_Activity::create($openCaseParams); + if (is_a($newActivity, 'CRM_Core_Error')) { + CRM_Core_Error::fatal('Unable to update Open Case activity'); + } + else { + // Create linkage to case + $caseActivityParams = array( + 'activity_id' => $newActivity->id, + 'case_id' => $form->_caseId, + ); + + CRM_Case_BAO_Case::processCaseActivity($caseActivityParams); + + $caseActivityParams = array( + 'activityID' => $form->openCaseActivityId, + 'mainActivityId' => $newActivity->id, + ); + CRM_Activity_BAO_Activity::copyExtendedActivityData($caseActivityParams); + } + } + + // 3.status msg + $params['statusMsg'] = ts('Case Start Date changed successfully.'); + } +} + diff --git a/CRM/Case/Form/Activity/ChangeCaseStatus.php b/CRM/Case/Form/Activity/ChangeCaseStatus.php new file mode 100644 index 0000000000..948013d2d8 --- /dev/null +++ b/CRM/Case/Form/Activity/ChangeCaseStatus.php @@ -0,0 +1,167 @@ +_caseId)) { + CRM_Core_Error::fatal(ts('Case Id not found.')); + } + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form) { + $defaults = array(); + // Retrieve current case status + $defaults['case_status_id'] = $form->_defaultCaseStatus; + + return $defaults; + } + + static function buildQuickForm(&$form) { + $form->removeElement('status_id'); + $form->removeElement('priority_id'); + + $form->_caseStatus = CRM_Case_PseudoConstant::caseStatus(); + $form->_defaultCaseStatus = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $form->_caseId, 'status_id'); + + if (!array_key_exists($form->_defaultCaseStatus, $form->_caseStatus)) { + $form->_caseStatus[$form->_defaultCaseStatus] = CRM_Core_OptionGroup::getLabel('case_status', + $form->_defaultCaseStatus, + FALSE + ); + } + $form->add('select', 'case_status_id', ts('Case Status'), + $form->_caseStatus, TRUE + ); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $form) { + return TRUE; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function beginPostProcess(&$form, &$params) { + $params['id'] = CRM_Utils_Array::value('case_id', $params); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function endPostProcess(&$form, &$params, $activity) { + $groupingValues = CRM_Core_OptionGroup::values('case_status', FALSE, TRUE, FALSE, NULL, 'value'); + + // Set case end_date if we're closing the case. Clear end_date if we're (re)opening it. + if (CRM_Utils_Array::value($params['case_status_id'], $groupingValues) == 'Closed' + && CRM_Utils_Array::value('activity_date_time', $params) + ) { + $params['end_date'] = $params['activity_date_time']; + + // End case-specific relationships (roles) + foreach ($params['target_contact_id'] as $cid) { + $rels = CRM_Case_BAO_Case::getCaseRoles($cid, $params['case_id']); + // FIXME: Is there an existing function to close a relationship? + $query = 'UPDATE civicrm_relationship SET end_date=%2 WHERE id=%1'; + foreach ($rels as $relId => $relData) { + $relParams = array(1 => array($relId, 'Integer'), + 2 => array($params['end_date'], 'Timestamp'), + ); + CRM_Core_DAO::executeQuery($query, $relParams); + } + } + } + elseif (CRM_Utils_Array::value($params['case_status_id'], $groupingValues) == 'Opened') { + $params['end_date'] = "null"; + + // Reopen case-specific relationships (roles) + foreach ($params['target_contact_id'] as $cid) { + $rels = CRM_Case_BAO_Case::getCaseRoles($cid, $params['case_id']); + // FIXME: Is there an existing function? + $query = 'UPDATE civicrm_relationship SET end_date=NULL WHERE id=%1'; + foreach ($rels as $relId => $relData) { + $relParams = array(1 => array($relId, 'Integer'), + ); + CRM_Core_DAO::executeQuery($query, $relParams); + } + } + } + $params['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + $activity->status_id = $params['status_id']; + $params['priority_id'] = CRM_Core_OptionGroup::getValue('priority', 'Normal', 'name'); + $activity->priority_id = $params['priority_id']; + + if ($activity->subject == 'null') { + $activity->subject = ts('Case status changed from %1 to %2', array(1 => CRM_Utils_Array::value($form->_defaults['case_status_id'], $form->_caseStatus), + 2 => CRM_Utils_Array::value($params['case_status_id'], $form->_caseStatus), + ) + ); + $activity->save(); + } + + // FIXME: does this do anything ? + $params['statusMsg'] = ts('Case Status changed successfully.'); + } +} + diff --git a/CRM/Case/Form/Activity/ChangeCaseType.php b/CRM/Case/Form/Activity/ChangeCaseType.php new file mode 100644 index 0000000000..adcc3a9e07 --- /dev/null +++ b/CRM/Case/Form/Activity/ChangeCaseType.php @@ -0,0 +1,184 @@ +_caseId)) { + CRM_Core_Error::fatal(ts('Case Id not found.')); + } + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form) { + $defaults = array(); + + $defaults['is_reset_timeline'] = 1; + + $defaults['reset_date_time'] = array(); + list($defaults['reset_date_time'], $defaults['reset_date_time_time']) = CRM_Utils_Date::setDateDefaults(NULL, 'activityDateTime'); + $defaults['case_type_id'] = $form->_caseTypeId; + + return $defaults; + } + + static function buildQuickForm(&$form) { + $form->removeElement('status_id'); + $form->removeElement('priority_id'); + + $form->_caseType = CRM_Case_PseudoConstant::caseType(); + $caseTypeId = explode(CRM_Case_BAO_Case::VALUE_SEPARATOR, CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', + $form->_caseId, + 'case_type_id' + )); + $form->_caseTypeId = $caseTypeId[1]; + if (!in_array($form->_caseTypeId, $form->_caseType)) { + $form->_caseType[$form->_caseTypeId] = CRM_Core_OptionGroup::getLabel('case_type', $form->_caseTypeId, FALSE); + } + + $form->add('select', 'case_type_id', ts('New Case Type'), + $form->_caseType, TRUE + ); + + // timeline + $form->addYesNo('is_reset_timeline', ts('Reset Case Timeline?'), NULL, TRUE, array('onclick' => "return showHideByValue('is_reset_timeline','','resetTimeline','table-row','radio',false);")); + $form->addDateTime('reset_date_time', ts('Reset Start Date'), FALSE, array('formatType' => 'activityDateTime')); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $form) { + return TRUE; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function beginPostProcess(&$form, &$params) { + if ($form->_context == 'case') { + $params['id'] = $form->_id; + } + + if (CRM_Utils_Array::value('is_reset_timeline', $params) == 0) { + unset($params['reset_date_time']); + } + else { + // store the date with proper format + $params['reset_date_time'] = CRM_Utils_Date::processDate($params['reset_date_time'], $params['reset_date_time_time']); + } + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function endPostProcess(&$form, &$params, $activity) { + if (!$form->_caseId) { + // always expecting a change, so case-id is a must. + return; + } + + $caseTypes = CRM_Case_PseudoConstant::caseType('name'); + $allCaseTypes = CRM_Case_PseudoConstant::caseType('label', FALSE); + + if (CRM_Utils_Array::value($params['case_type_id'], $caseTypes)) { + $caseType = $caseTypes[$params['case_type_id']]; + } + + if (!$form->_currentlyViewedContactId || + !$form->_currentUserId || + !$params['case_type_id'] || + !$caseType + ) { + CRM_Core_Error::fatal('Required parameter missing for ChangeCaseType - end post processing'); + } + + $params['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + $activity->status_id = $params['status_id']; + $params['priority_id'] = CRM_Core_OptionGroup::getValue('priority', 'Normal', 'name'); + $activity->priority_id = $params['priority_id']; + + if ($activity->subject == 'null') { + $activity->subject = ts('Case type changed from %1 to %2', + array(1 => CRM_Utils_Array::value($form->_defaults['case_type_id'], $allCaseTypes), + 2 => CRM_Utils_Array::value($params['case_type_id'], $allCaseTypes), + ) + ); + $activity->save(); + } + + // 1. initiate xml processor + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $xmlProcessorParams = array( + 'clientID' => $form->_currentlyViewedContactId, + 'creatorID' => $form->_currentUserId, + 'standardTimeline' => 1, + 'activityTypeName' => 'Change Case Type', + 'activity_date_time' => CRM_Utils_Array::value('reset_date_time', $params), + 'caseID' => $form->_caseId, + 'resetTimeline' => CRM_Utils_Array::value('is_reset_timeline', $params), + ); + + $xmlProcessor->run($caseType, $xmlProcessorParams); + // status msg + $params['statusMsg'] = ts('Case Type changed successfully.'); + } +} + diff --git a/CRM/Case/Form/Activity/LinkCases.php b/CRM/Case/Form/Activity/LinkCases.php new file mode 100644 index 0000000000..3d3c132b99 --- /dev/null +++ b/CRM/Case/Form/Activity/LinkCases.php @@ -0,0 +1,140 @@ +_caseId)) { + CRM_Core_Error::fatal(ts('Case Id not found.')); + } + + $form->assign('clientID', $form->_currentlyViewedContactId); + $form->assign('caseTypeLabel', CRM_Case_BAO_Case::getCaseType($form->_caseId)); + + // get the related cases for given case. + $relatedCases = $form->get('relatedCases'); + if (!isset($relatedCases)) { + $relatedCases = CRM_Case_BAO_Case::getRelatedCases($form->_caseId, $form->_currentlyViewedContactId); + $form->set('relatedCases', empty($relatedCases) ? FALSE : $relatedCases); + } + $excludeCaseIds = array($form->_caseId); + if (is_array($relatedCases) && !empty($relatedCases)) { + $excludeCaseIds = array_merge($excludeCaseIds, array_keys($relatedCases)); + } + $form->assign('excludeCaseIds', implode(',', $excludeCaseIds)); + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form) { + return $defaults = array(); + } + + static function buildQuickForm(&$form) { + $form->add('text', 'link_to_case', ts('Link To Case')); + $form->add('hidden', 'link_to_case_id', '', array('id' => 'link_to_case_id')); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $form) { + $errors = array(); + + $linkCaseId = CRM_Utils_Array::value('link_to_case_id', $values); + if (!$linkCaseId) { + $errors['link_to_case'] = ts('Please select a case to link.'); + } + elseif ($linkCaseId == $form->_caseId) { + $errors['link_to_case'] = ts('Please select some other case to link.'); + } + + // do check for existing related cases. + $relatedCases = $form->get('relatedCases'); + if (is_array($relatedCases) && array_key_exists($linkCaseId, $relatedCases)) { + $errors['link_to_case'] = ts('It looks like selected case is already linked.'); + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function beginPostProcess(&$form, &$params) { + $params['id'] = $params['case_id']; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function endPostProcess(&$form, &$params, &$activity) { + $activityId = $activity->id; + $linkCaseID = CRM_Utils_Array::value('link_to_case_id', $params); + + //create a link between two cases. + if ($activityId && $linkCaseID) { + $caseParams = array( + 'case_id' => $linkCaseID, + 'activity_id' => $activityId, + ); + CRM_Case_BAO_Case::processCaseActivity($caseParams); + } + } +} + diff --git a/CRM/Case/Form/Activity/OpenCase.php b/CRM/Case/Form/Activity/OpenCase.php new file mode 100644 index 0000000000..47581849b5 --- /dev/null +++ b/CRM/Case/Form/Activity/OpenCase.php @@ -0,0 +1,352 @@ +_allowMultiClient = (bool)$xmlProcessorProcess->getAllowMultipleCaseClients(); + + if ($form->_context == 'caseActivity') { + $contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $form); + $atype = CRM_Core_OptionGroup::getValue('activity_type', + 'Change Case Start Date', + 'name' + ); + $form->assign('changeStartURL', CRM_Utils_System::url('civicrm/case/activity', + "action=add&reset=1&cid=$contactID&caseid={$form->_caseId}&atype=$atype" + ) + ); + return; + } + + $form->_context = CRM_Utils_Request::retrieve('context', 'String', $form); + $form->_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $form); + $form->assign('context', $form->_context); + + // Add attachments + CRM_Core_BAO_File::buildAttachment( $form, 'civicrm_activity', $form->_activityId ); + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form) { + $defaults = array(); + if ($form->_context == 'caseActivity') { + return $defaults; + } + + list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults(); + + // set default case status, case type, encounter medium, location type and phone type defaults are set in DB + $caseStatus = CRM_Core_OptionGroup::values('case_status', FALSE, FALSE, FALSE, 'AND is_default = 1'); + if (count($caseStatus) == 1) { + $defaults['status_id'] = key($caseStatus); + } + $caseType = CRM_Core_OptionGroup::values('case_type', FALSE, FALSE, FALSE, 'AND is_default = 1'); + if (count($caseType) == 1) { + $defaults['case_type_id'] = key($caseType); + } + $medium = CRM_Core_OptionGroup::values('encounter_medium', FALSE, FALSE, FALSE, 'AND is_default = 1'); + if (count($medium) == 1) { + $defaults['medium_id'] = key($medium); + } + + $defaultLocationType = CRM_Core_BAO_LocationType::getDefault(); + if ($defaultLocationType->id) { + $defaults['location[1][location_type_id]'] = $defaultLocationType->id; + } + + $phoneType = CRM_Core_OptionGroup::values('phone_type', FALSE, FALSE, FALSE, 'AND is_default = 1'); + if (count($phoneType) == 1) { + $defaults['location[1][phone][1][phone_type_id]'] = key($phoneType); + } + + return $defaults; + } + + static function buildQuickForm(&$form) { + if ($form->_context == 'caseActivity') { + return; + } + if ($form->_context == 'standalone') { + CRM_Contact_Form_NewContact::buildQuickForm($form); + } + + $caseType = array('' => '-select-') + CRM_Case_PseudoConstant::caseType(); + $form->add('select', 'case_type_id', ts('Case Type'), + $caseType, TRUE, array( + 'onchange' => + "CRM.buildCustomData( 'Case', this.value );", + ) + ); + + $caseStatus = CRM_Case_PseudoConstant::caseStatus(); + $form->add('select', 'status_id', ts('Case Status'), + $caseStatus, TRUE + ); + + $form->add('text', 'duration', ts('Duration'), array('size' => 4, 'maxlength' => 8)); + $form->addRule('duration', ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger'); + + if ($form->_currentlyViewedContactId) { + list($displayName) = CRM_Contact_BAO_Contact::getDisplayAndImage($form->_currentlyViewedContactId); + $form->assign('clientName', $displayName); + } + + $form->addDate('start_date', ts('Case Start Date'), TRUE, array('formatType' => 'activityDateTime')); + + $form->add('select', 'medium_id', ts('Medium'), + CRM_Case_PseudoConstant::encounterMedium(), TRUE + ); + + // calling this field activity_location to prevent conflict with contact location fields + $form->add('text', 'activity_location', ts('Location'), CRM_Core_DAO::getAttribute('CRM_Activity_DAO_Activity', 'location')); + + $form->addWysiwyg('activity_details', ts('Details'), array('rows' => 4, 'cols' => 60), FALSE); + + $form->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'upload', + 'name' => ts('Save and New'), + 'subName' => 'new', + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function beginPostProcess(&$form, &$params) { + if ($form->_context == 'caseActivity') { + return; + } + + // set the contact, when contact is selected + if (isset($params['contact_select_id']) && CRM_utils_Array::value(1, $params['contact_select_id'])) { + $params['contact_id'] = $params['contact_select_id'][1]; + $form->_currentlyViewedContactId = $params['contact_id']; + } + elseif ($form->_allowMultiClient && $form->_context != 'case') { + $clients = explode(',', $params['contact'][1]); + $form->_currentlyViewedContactId = $clients[0]; + } + + // for open case start date should be set to current date + $params['start_date'] = CRM_Utils_Date::processDate($params['start_date'], $params['start_date_time']); + $caseStatus = CRM_Case_PseudoConstant::caseStatus('name'); + // for resolved case the end date should set to now + if ($params['status_id'] == array_search('Closed', $caseStatus)) { + $params['end_date'] = $params['now']; + } + + // rename activity_location param to the correct column name for activity DAO + $params['location'] = CRM_Utils_Array::value('activity_location', $params); + + // Add attachments + CRM_Core_BAO_File::formatAttachment( + $params, + $params, + 'civicrm_activity', + $form->_activityId + ); + + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields, $files, $form) { + if ($form->_context == 'caseActivity') { + return TRUE; + } + + $errors = array(); + + if (!$form->_allowMultiClient) { + //check if contact is selected in standalone mode + if (isset($fields['contact_select_id'][1]) && !$fields['contact_select_id'][1]) { + $errors['contact[1]'] = ts('Please select a contact or create new contact'); + } + } + else { + //check selected contact for multi client option + if (isset($fields['contact'][1]) && !$fields['contact'][1]) { + $errors['contact[1]'] = ts('Please select a valid contact or create new contact'); + } + } + return $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + static function endPostProcess(&$form, &$params) { + if ($form->_context == 'caseActivity') { + return; + } + + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); + $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); + + if (!$isMultiClient && !$form->_currentlyViewedContactId) { + CRM_Core_Error::fatal('Required parameter missing for OpenCase - end post processing'); + } + + if (!$form->_currentUserId || + !$params['case_id'] || + !$params['case_type'] + ) { + CRM_Core_Error::fatal('Required parameter missing for OpenCase - end post processing'); + } + + // 1. create case-contact + if ($isMultiClient && $form->_context != 'case') { + $client = explode(',', $params['contact'][1]); + foreach ($client as $key => $cliId) { + if (empty($cliId)) { + CRM_Core_Error::fatal('contact_id cannot be empty'); + } + $contactParams = array( + 'case_id' => $params['case_id'], + 'contact_id' => $cliId, + ); + CRM_Case_BAO_Case::addCaseToContact($contactParams); + } + } + else { + $contactParams = array( + 'case_id' => $params['case_id'], + 'contact_id' => $form->_currentlyViewedContactId, + ); + CRM_Case_BAO_Case::addCaseToContact($contactParams); + $client = $form->_currentlyViewedContactId; + } + + // 2. initiate xml processor + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + + $xmlProcessorParams = array( + 'clientID' => $client, + 'creatorID' => $form->_currentUserId, + 'standardTimeline' => 1, + 'activityTypeName' => 'Open Case', + 'caseID' => $params['case_id'], + 'subject' => $params['activity_subject'], + 'location' => $params['location'], + 'activity_date_time' => $params['start_date'], + 'duration' => CRM_Utils_Array::value('duration', $params), + 'medium_id' => $params['medium_id'], + 'details' => $params['activity_details'], + ); + + if (array_key_exists('custom', $params) && is_array($params['custom'])) { + $xmlProcessorParams['custom'] = $params['custom']; + } + + // Add parameters for attachments + $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + for ( $i = 1; $i <= $numAttachments; $i++ ) { + $attachName = "attachFile_$i"; + if ( isset( $params[$attachName] ) && !empty( $params[$attachName] ) ) { + $xmlProcessorParams[$attachName] = $params[$attachName]; + } + } + + $xmlProcessor->run($params['case_type'], $xmlProcessorParams); + + // status msg + $params['statusMsg'] = ts('Case opened successfully.'); + + $buttonName = $form->controller->getButtonName(); + $session = CRM_Core_Session::singleton(); + if ($buttonName == $form->getButtonName('upload', 'new')) { + if ($form->_context == 'standalone') { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/case/add', + 'reset=1&action=add&context=standalone' + )); + } + else { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=add&context=case&cid={$form->_contactID}" + )); + } + } + } +} + diff --git a/CRM/Case/Form/ActivityToCase.php b/CRM/Case/Form/ActivityToCase.php new file mode 100644 index 0000000000..228e75ac5f --- /dev/null +++ b/CRM/Case/Form/ActivityToCase.php @@ -0,0 +1,100 @@ +_activityId = CRM_Utils_Request::retrieve('activityId', 'Positive', CRM_Core_DAO::$_nullObject); + if (!$this->_activityId) { + CRM_Core_Error::fatal('required activity id is missing.'); + } + + $this->_currentCaseId = CRM_Utils_Request::retrieve('caseId', 'Positive', CRM_Core_DAO::$_nullObject); + $this->assign('currentCaseId', $this->_currentCaseId); + $this->assign('buildCaseActivityForm', TRUE); + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $targetContactValues = $defaults = array(); + $params = array('id' => $this->_activityId); + + CRM_Activity_BAO_Activity::retrieve($params, $defaults); + $defaults['case_activity_subject'] = $defaults['subject']; + if (!CRM_Utils_Array::crmIsEmptyArray($defaults['target_contact'])) { + $targetContactValues = array_combine(array_unique($defaults['target_contact']), + explode(';', trim($defaults['target_contact_value'])) + ); + } + $this->assign('targetContactValues', empty($targetContactValues) ? FALSE : $targetContactValues); + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + // tokeninput url + $tokenUrl = CRM_Utils_System::url("civicrm/ajax/checkemail", "noemail=1", FALSE, NULL, FALSE); + $this->assign('tokenUrl', $tokenUrl); + + $this->add('text', 'unclosed_cases', ts('Select Case')); + $this->add('hidden', 'unclosed_case_id', '', array('id' => 'open_case_id')); + $this->add('text', 'target_contact_id', ts('With Contact(s)')); + $this->add('text', 'case_activity_subject', ts('Subject'), array('size' => 50)); + } +} + diff --git a/CRM/Case/Form/ActivityView.php b/CRM/Case/Form/ActivityView.php new file mode 100644 index 0000000000..0861cbc4fe --- /dev/null +++ b/CRM/Case/Form/ActivityView.php @@ -0,0 +1,184 @@ +assign('contactID', $contactID); + $this->assign('caseID', $caseID); + $this->assign('type', $type); + // CRM-9145 + $this->assign('activityID', $activityID); + + $xmlProcessor = new CRM_Case_XMLProcessor_Report(); + $report = $xmlProcessor->getActivityInfo($contactID, $activityID, TRUE); + + $attachmentUrl = CRM_Core_BAO_File::attachmentInfo('civicrm_activity', $activityID); + if ($attachmentUrl) { + $report['fields'][] = array( + 'label' => 'Attachment(s)', + 'value' => $attachmentUrl, + 'type' => 'Link', + ); + } + + $tags = CRM_Core_BAO_EntityTag::getTag($activityID, 'civicrm_activity'); + if (!empty($tags)) { + $allTag = CRM_Core_PseudoConstant::tag(); + foreach ($tags as $tid) { + $tags[$tid] = $allTag[$tid]; + } + $report['fields'][] = array( + 'label' => 'Tags', + 'value' => implode('
    ', $tags), + 'type' => 'String', + ); + } + + $this->assign('report', $report); + + $latestRevisionID = CRM_Activity_BAO_Activity::getLatestActivityId($activityID); + + $viewPriorActivities = array(); + $priorActivities = CRM_Activity_BAO_Activity::getPriorAcitivities($activityID); + foreach ($priorActivities as $activityId => $activityValues) { + if (CRM_Case_BAO_Case::checkPermission($activityId, 'view', NULL, $contactID)) { + $viewPriorActivities[$activityId] = $activityValues; + } + } + + if ($revs) { + $this->assign('revs', $revs); + + $this->assign('result', $viewPriorActivities); + $this->assign('subject', $activitySubject); + $this->assign('latestRevisionID', $latestRevisionID); + } + else { + if (count($viewPriorActivities) > 1) { + $this->assign('activityID', $activityID); + } + + if ($latestRevisionID != $activityID) { + $this->assign('latestRevisionID', $latestRevisionID); + } + } + + $parentID = CRM_Activity_BAO_Activity::getParentActivity($activityID); + if ($parentID) { + $this->assign('parentID', $parentID); + } + + //viewing activity should get diplayed in recent list.CRM-4670 + $activityTypeID = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $activityID, 'activity_type_id'); + + $activityTargetContacts = CRM_Activity_BAO_ActivityTarget::retrieveTargetIdsByActivityId($activityID); + if (!empty($activityTargetContacts)) { + $recentContactId = $activityTargetContacts[0]; + } + else { + $recentContactId = $contactID; + } + + if (!isset($caseID)) { + $caseID = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $activityID, 'case_id', 'activity_id'); + } + + $url = CRM_Utils_System::url('civicrm/case/activity/view', + "reset=1&aid={$activityID}&cid={$recentContactId}&caseID={$caseID}&context=home" + ); + + $recentContactDisplay = CRM_Contact_BAO_Contact::displayName($recentContactId); + // add the recently created Activity + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE); + + $title = ""; + if (isset($activitySubject)) { + $title = $activitySubject . ' - '; + } + + $title = $title . $recentContactDisplay . ' (' . $activityTypes[$activityTypeID] . ')'; + + $recentOther = array(); + if (CRM_Case_BAO_Case::checkPermission($activityID, 'edit')) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/case/activity', + "reset=1&action=update&id={$activityID}&cid={$recentContactId}&caseid={$caseID}&context=home" + ); + } + if (CRM_Case_BAO_Case::checkPermission($activityID, 'delete')) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/case/activity', + "reset=1&action=delete&id={$activityID}&cid={$recentContactId}&caseid={$caseID}&context=home" + ); + } + + CRM_Utils_Recent::add($title, + $url, + $activityID, + 'Activity', + $recentContactId, + $recentContactDisplay, + $recentOther + ); + } +} + diff --git a/CRM/Case/Form/Case.php b/CRM/Case/Form/Case.php new file mode 100644 index 0000000000..4925bf74ac --- /dev/null +++ b/CRM/Case/Form/Case.php @@ -0,0 +1,434 @@ +_cdType = CRM_Utils_Array::value('type', $_GET); + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + return CRM_Custom_Form_CustomData::preProcess($this); + } + + $this->_caseId = CRM_Utils_Request::retrieve('id', 'Positive', $this); + + $this->_currentlyViewedContactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + if ($this->_action & CRM_Core_Action::ADD && !$this->_currentlyViewedContactId) { + // check for add contacts permissions + if (!CRM_Core_Permission::check('add contacts')) { + CRM_Utils_System::permissionDenied(); + return; + } + } + + //CRM-4418 + if (!CRM_Core_Permission::checkActionPermission('CiviCase', $this->_action)) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + + if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW) { + return TRUE; + } + + if (!$this->_caseId) { + $caseAttributes = array('case_type' => CRM_Case_PseudoConstant::caseType(), + 'case_status' => CRM_Case_PseudoConstant::caseStatus(), + 'encounter_medium' => CRM_Case_PseudoConstant::encounterMedium(), + ); + + foreach ($caseAttributes as $key => $values) { + if (empty($values)) { + CRM_Core_Error::fatal(ts('You do not have any active %1', + array(1 => str_replace('_', ' ', $key)) + )); + break; + } + } + } + + if ($this->_action & CRM_Core_Action::ADD) { + $this->_activityTypeId = CRM_Core_OptionGroup::getValue('activity_type', + 'Open Case', + 'name' + ); + if (!$this->_activityTypeId) { + CRM_Core_Error::fatal(ts('The Open Case activity type is missing or disabled. Please have your site administrator check Administer > Option Lists > Activity Types for the CiviCase component.')); + } + } + + //check for case permissions. + if (!CRM_Case_BAO_Case::accessCiviCase()) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + if (($this->_action & CRM_Core_Action::ADD) && + (!CRM_Core_Permission::check('access all cases and activities') && + !CRM_Core_Permission::check('add cases') + ) + ) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + + if ($this->_activityTypeFile = + CRM_Activity_BAO_Activity::getFileForActivityTypeId($this->_activityTypeId, + 'Case' + ) + ) { + $this->assign('activityTypeFile', $this->_activityTypeFile); + } + + $details = CRM_Case_PseudoConstant::caseActivityType(FALSE); + + CRM_Utils_System::setTitle($details[$this->_activityTypeId]['label']); + $this->assign('activityType', $details[$this->_activityTypeId]['label']); + $this->assign('activityTypeDescription', $details[$this->_activityTypeId]['description']); + + if (isset($this->_currentlyViewedContactId)) { + $contact = new CRM_Contact_DAO_Contact(); + $contact->id = $this->_currentlyViewedContactId; + if (!$contact->find(TRUE)) { + CRM_Core_Error::statusBounce(ts('Client contact does not exist: %1', array(1 => $this->_currentlyViewedContactId))); + } + $this->assign('clientName', $contact->display_name); + } + + + $session = CRM_Core_Session::singleton(); + $this->_currentUserId = $session->get('userID'); + + //when custom data is included in this page + CRM_Custom_Form_CustomData::preProcess($this, NULL, $this->_activityTypeId, 1, 'Activity'); + eval("CRM_Case_Form_Activity_{$this->_activityTypeFile}::preProcess( \$this );"); + $activityGroupTree = $this->_groupTree; + + // for case custom fields to populate with defaults + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + CRM_Custom_Form_CustomData::preProcess($this); + CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + // so that grouptree is not populated with case fields, since the grouptree is used + // for populating activity custom fields. + $this->_groupTree = $activityGroupTree; + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW || $this->_cdType) { + return TRUE; + } + eval('$defaults = CRM_Case_Form_Activity_' . $this->_activityTypeFile . '::setDefaultValues($this);'); + $defaults = array_merge($defaults, CRM_Custom_Form_CustomData::setDefaultValues($this)); + return $defaults; + } + + public function buildQuickForm() { + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); + $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); + $this->assign('multiClient', $isMultiClient); + + if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW) { + $title = 'Delete'; + if ($this->_action & CRM_Core_Action::RENEW) { + $title = 'Restore'; + } + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => $title, + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + return; + } + + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::buildQuickForm($this); + } + //need to assign custom data type and subtype to the template + $this->assign('customDataType', 'Case'); + + CRM_Custom_Form_CustomData::buildQuickForm($this); + // we don't want to show button on top of custom form + $this->assign('noPreCustomButton', TRUE); + + $s = CRM_Core_DAO::getAttribute('CRM_Activity_DAO_Activity', 'subject'); + if (!is_array($s)) { + $s = array(); + } + $this->add('text', 'activity_subject', ts('Subject'), + array_merge($s, array( + 'maxlength' => '128')), TRUE + ); + + $tags = CRM_Core_BAO_Tag::getTags('civicrm_case'); + if (!empty($tags)) { + $this->add('select', 'tag', ts('Select Tags'), $tags, FALSE, + array('id' => 'tags', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + + // build tag widget + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_case'); + CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_case', NULL, FALSE, TRUE); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + eval("CRM_Case_Form_Activity_{$this->_activityTypeFile}::buildQuickForm( \$this );"); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + if ($this->_action & CRM_Core_Action::DELETE || $this->_action & CRM_Core_Action::RENEW || $this->_cdType) { + return TRUE; + } + eval('$this->addFormRule' . "(array('CRM_Case_Form_Activity_{$this->_activityTypeFile}', 'formrule'), \$this);"); + $this->addFormRule(array('CRM_Case_Form_Case', 'formRule'), $this); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $form) { + return TRUE; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $transaction = new CRM_Core_Transaction(); + + // check if dedupe button, if so return. + $buttonName = $this->controller->getButtonName(); + if (isset($this->_dedupeButtonName) && $buttonName == $this->_dedupeButtonName) { + return; + } + + if ($this->_action & CRM_Core_Action::DELETE) { + $statusMsg = NULL; + $caseDelete = CRM_Case_BAO_Case::deleteCase($this->_caseId, TRUE); + if ($caseDelete) { + $statusMsg = ts('The selected case has been moved to the Trash. You can view and / or restore deleted cases by checking the "Deleted Cases" option under Find Cases.
    '); + } + CRM_Core_Session::setStatus($statusMsg, ts('Case Deleted'), 'success'); + return; + } + + if ($this->_action & CRM_Core_Action::RENEW) { + $statusMsg = NULL; + $caseRestore = CRM_Case_BAO_Case::restoreCase($this->_caseId); + if ($caseRestore) { + $statusMsg = ts('The selected case has been restored.
    '); + } + CRM_Core_Session::setStatus($statusMsg, ts('Restored'), 'success'); + return; + } + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + $params['now'] = date("Ymd"); + + + // 1. call begin post process + if ($this->_activityTypeFile) { + eval("CRM_Case_Form_Activity_{$this->_activityTypeFile}" . "::beginPostProcess( \$this, \$params );"); + } + + if (CRM_Utils_Array::value('hidden_custom', $params) && + !isset($params['custom']) + ) { + $customFields = array(); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + NULL, + 'Case' + ); + } + + // 2. create/edit case + if (CRM_Utils_Array::value('case_type_id', $params)) { + $caseType = CRM_Case_PseudoConstant::caseType('name'); + $params['case_type'] = $caseType[$params['case_type_id']]; + $params['subject'] = $params['activity_subject']; + $params['case_type_id'] = CRM_Core_DAO::VALUE_SEPARATOR . $params['case_type_id'] . CRM_Core_DAO::VALUE_SEPARATOR; + } + $caseObj = CRM_Case_BAO_Case::create($params); + $params['case_id'] = $caseObj->id; + // unset any ids, custom data + unset($params['id'], $params['custom']); + + // add tags if exists + $tagParams = array(); + if (!empty($params['tag'])) { + $tagParams = array(); + foreach ($params['tag'] as $tag) { + $tagParams[$tag] = 1; + } + } + CRM_Core_BAO_EntityTag::create($tagParams, 'civicrm_case', $caseObj->id); + + //save free tags + if (isset($params['case_taglist']) && !empty($params['case_taglist'])) { + CRM_Core_Form_Tag::postProcess($params['case_taglist'], $caseObj->id, 'civicrm_case', $this); + } + + // user context + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_currentlyViewedContactId}&id={$caseObj->id}" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + + // 3. format activity custom data + if (CRM_Utils_Array::value('hidden_custom', $params)) { + $customFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, $this->_activityTypeId); + $customFields = CRM_Utils_Array::crmArrayMerge($customFields, + CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE, + NULL, NULL, TRUE + ) + ); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_activityId, + 'Activity' + ); + } + + // 4. call end post process + if ($this->_activityTypeFile) { + eval("CRM_Case_Form_Activity_{$this->_activityTypeFile}" . "::endPostProcess( \$this, \$params );"); + } + + // 5. auto populate activites + + // 6. set status + CRM_Core_Session::setStatus($params['statusMsg'], '', 'info'); + } +} + diff --git a/CRM/Case/Form/CaseView.php b/CRM/Case/Form/CaseView.php new file mode 100644 index 0000000000..7ddad8384c --- /dev/null +++ b/CRM/Case/Form/CaseView.php @@ -0,0 +1,537 @@ +_showRelatedCases = CRM_Utils_Array::value('relatedCases', $_GET); + + + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); + $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); + $this->assign('multiClient', $isMultiClient); + + //pull the related cases. + $this->assign('showRelatedCases', FALSE); + if ($this->_showRelatedCases) { + $relatedCases = $this->get('relatedCases'); + if (!isset($relatedCases)) { + $cId = CRM_Utils_Request::retrieve('cid', 'Integer', CRM_Core_DAO::$_nullObject); + $caseId = CRM_Utils_Request::retrieve('id', 'Integer', CRM_Core_DAO::$_nullObject); + $relatedCases = CRM_Case_BAO_Case::getRelatedCases($caseId, $cId); + } + $this->assign('relatedCases', $relatedCases); + $this->assign('showRelatedCases', TRUE); + return; + } + + //check for civicase access. + if (!CRM_Case_BAO_Case::accessCiviCase()) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + $this->_hasAccessToAllCases = CRM_Core_Permission::check('access all cases and activities'); + $this->assign('hasAccessToAllCases', $this->_hasAccessToAllCases); + + $this->_contactID = $this->get('cid'); + $this->_caseID = $this->get('id'); + + $fulltext = CRM_Utils_Request::retrieve('context', 'String', CRM_Core_DAO::$_nullObject); + if ($fulltext == 'fulltext') { + $this->assign('fulltext', $fulltext); + } + + $this->assign('caseID', $this->_caseID); + $this->assign('contactID', $this->_contactID); + + //validate case id. + $this->_userCases = array(); + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + if (!$this->_hasAccessToAllCases) { + $this->_userCases = CRM_Case_BAO_Case::getCases(FALSE, $userID); + if (!array_key_exists($this->_caseID, $this->_userCases)) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + } + $this->assign('userID', $userID); + + if (CRM_Case_BAO_Case::caseCount($this->_contactID) >= 2) { + $this->_mergeCases = TRUE; + } + $this->assign('mergeCases', $this->_mergeCases); + + //retrieve details about case + $params = array('id' => $this->_caseID); + + $returnProperties = array('case_type_id', 'subject', 'status_id', 'start_date'); + CRM_Core_DAO::commonRetrieve('CRM_Case_BAO_Case', $params, $values, $returnProperties); + + $values['case_type_id'] = trim(CRM_Utils_Array::value('case_type_id', $values), + CRM_Core_DAO::VALUE_SEPARATOR + ); + $values['case_type_id'] = explode(CRM_Core_DAO::VALUE_SEPARATOR, + CRM_Utils_Array::value('case_type_id', $values) + ); + + $statuses = CRM_Case_PseudoConstant::caseStatus('label', FALSE); + $caseTypeName = CRM_Case_BAO_Case::getCaseType($this->_caseID, 'name'); + $caseType = CRM_Case_BAO_Case::getCaseType($this->_caseID); + + $this->_caseDetails = array( + 'case_type' => $caseType, + 'case_status' => $statuses[$values['case_status_id']], + 'case_subject' => CRM_Utils_Array::value('subject', $values), + 'case_start_date' => $values['case_start_date'], + ); + $this->_caseType = $caseTypeName; + $this->assign('caseDetails', $this->_caseDetails); + + $newActivityUrl = CRM_Utils_System::url('civicrm/case/activity', + "action=add&reset=1&cid={$this->_contactID}&caseid={$this->_caseID}&atype=", + FALSE, NULL, FALSE + ); + $this->assign('newActivityUrl', $newActivityUrl); + + // Send Email activity requires a different URL format from all other activities + $newActivityEmailUrl = CRM_Utils_System::url('civicrm/activity/email/add', + "action=add&context=standalone&reset=1&caseid={$this->_caseID}&atype=", + FALSE, NULL, FALSE + ); + $this->assign('newActivityEmailUrl', $newActivityEmailUrl); + + $reportUrl = CRM_Utils_System::url('civicrm/case/report', + "reset=1&cid={$this->_contactID}&caseid={$this->_caseID}&asn=", + FALSE, NULL, FALSE + ); + $this->assign('reportUrl', $reportUrl); + + // add to recently viewed + + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "action=view&reset=1&id={$this->_caseID}&cid={$this->_contactID}&context=home" + ); + + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactID); + $this->assign('displayName', $displayName); + + $title = $displayName . ' - ' . $caseType; + CRM_Utils_System::setTitle(ts('Case Summary for') . ' ' . $title); + + $recentOther = array(); + if (CRM_Core_Permission::checkActionPermission('CiviCase', CRM_Core_Action::DELETE)) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/case', + "action=delete&reset=1&id={$this->_caseID}&cid={$this->_contactID}&context=home" + ); + } + + // add the recently created case + CRM_Utils_Recent::add($displayName . ' - ' . $caseType, + $url, + $this->_caseID, + 'Case', + $this->_contactID, + NULL, + $recentOther + ); + + + //get the related cases for given case. + $relatedCases = $this->get('relatedCases'); + if (!isset($relatedCases)) { + $relatedCases = CRM_Case_BAO_Case::getRelatedCases($this->_caseID, $this->_contactID); + $relatedCases = empty($relatedCases) ? FALSE : $relatedCases; + $this->set('relatedCases', $relatedCases); + } + $this->assign('hasRelatedCases', $relatedCases); + + $entitySubType = !empty($values['case_type_id']) ? $values['case_type_id'][0] : NULL; + $this->assign('caseTypeID', $entitySubType); + $groupTree = &CRM_Core_BAO_CustomGroup::getTree('Case', + $this, + $this->_caseID, + NULL, + $entitySubType + ); + CRM_Core_BAO_CustomGroup::buildCustomDataView($this, + $groupTree + ); + } + + /** + * This function sets the default values for the form. For edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + //this call is for show related cases. + if ($this->_showRelatedCases) { + return; + } + + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $caseRoles = $xmlProcessor->get($this->_caseType, 'CaseRoles'); + $reports = $xmlProcessor->get($this->_caseType, 'ActivitySets'); + + //adding case manager.CRM-4510. + $managerRoleId = $xmlProcessor->getCaseManagerRoleId($this->_caseType); + if (!empty($managerRoleId)) { + $caseRoles[$managerRoleId] = $caseRoles[$managerRoleId] . '
    ' . '(' . ts('Case Manager') . ')'; + } + + $aTypes = $xmlProcessor->get($this->_caseType, 'ActivityTypes', TRUE); + + $allActTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name'); + + // remove Open Case activity type since we're inside an existing case + if (($openActTypeId = array_search('Open Case', $allActTypes)) && + array_key_exists($openActTypeId, $aTypes) + ) { + unset($aTypes[$openActTypeId]); + } + + //check for link cases. + $unclosedCases = CRM_Case_BAO_Case::getUnclosedCases(NULL, array($this->_caseID)); + if (empty($unclosedCases) && + ($linkActTypeId = array_search('Link Cases', $allActTypes)) && + array_key_exists($linkActTypeId, $aTypes) + ) { + unset($aTypes[$linkActTypeId]); + } + + if (!$xmlProcessor->getNaturalActivityTypeSort()) { + asort($aTypes); + } + + $this->add('select', 'activity_type_id', ts('New Activity'), array('' => ts('- select activity type -')) + $aTypes); + if ($this->_hasAccessToAllCases) { + $this->add('select', 'report_id', ts('Run QA Audit / Redact'), + array( + '' => ts('- select activity set -')) + $reports + ); + $this->add('select', 'timeline_id', ts('Add Timeline'), + array( + '' => ts('- select activity set -')) + $reports + ); + } + $this->addElement('submit', $this->getButtonName('next'), ts('Go'), + array( + 'class' => 'form-submit-inline', + 'onclick' => "return checkSelection( this );", + ) + ); + + if ($this->_mergeCases) { + $allCases = CRM_Case_BAO_Case::getContactCases($this->_contactID); + $otherCases = array(); + foreach ($allCases as $caseId => $details) { + //filter current and own cases. + if (($caseId == $this->_caseID) || + (!$this->_hasAccessToAllCases && + !array_key_exists($caseId, $this->_userCases) + ) + ) { + continue; + } + + $otherCases[$caseId] = 'Case ID: ' . $caseId . ' Type: ' . $details['case_type'] . ' Start: ' . $details['case_start_date']; + } + if (empty($otherCases)) { + $this->_mergeCases = FALSE; + $this->assign('mergeCases', $this->_mergeCases); + } + else { + $this->add('select', 'merge_case_id', + ts('Select Case for Merge'), + array( + '' => ts('- select case -')) + $otherCases + ); + $this->addElement('submit', + $this->getButtonName('next', 'merge_case'), + ts('Merge'), + array( + 'class' => 'form-submit-inline', + 'onclick' => "return checkSelection( this );", + ) + ); + } + } + + $this->add('text', 'change_client_id', ts('Assign to another Client')); + $this->add('hidden', 'contact_id', '', array('id' => 'contact_id')); + $this->addElement('submit', + $this->getButtonName('next', 'edit_client'), + ts('Reassign Case'), + array( + 'class' => 'form-submit-inline', + 'onclick' => "return checkSelection( this );", + ) + ); + + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + $this->add('select', 'status_id', ts('Status'), array("" => ts(' - any status - ')) + $activityStatus); + $this->add('select', 'activity_change_status', ts('New Status'), $activityStatus); + + // activity dates + $this->addDate('activity_date_low', ts('Activity Dates - From'), FALSE, array('formatType' => 'searchDate')); + $this->addDate('activity_date_high', ts('To'), FALSE, array('formatType' => 'searchDate')); + + if (CRM_Core_Permission::check('administer CiviCRM')) { + $this->add('checkbox', 'activity_deleted', ts('Deleted Activities')); + } + + //get case related relationships (Case Role) + $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($this->_contactID, $this->_caseID); + + //save special label because we unset it in the loop + $managerLabel = empty($managerRoleId) ? '' : $caseRoles[$managerRoleId]; + + //build reporter select + $reporters = array("" => ts(' - any reporter - ')); + foreach ($caseRelationships as $key => & $value) { + $reporters[$value['cid']] = $value['name'] . " ( {$value['relation']} )"; + + if (!empty($managerRoleId)) { + if ($managerRoleId == $value['relation_type']) { + $value['relation'] = $managerLabel; + } + } + + //calculate roles that don't have relationships + if (CRM_Utils_Array::value($value['relation_type'], $caseRoles)) { + unset($caseRoles[$value['relation_type']]); + } + } + + // take all case activity types for search filter, CRM-7187 + $aTypesFilter = array(); + $allCaseActTypes = CRM_Case_PseudoConstant::caseActivityType(); + foreach ($allCaseActTypes as $typeDetails) { + if (!in_array($typeDetails['name'], array( + 'Open Case'))) { + $aTypesFilter[$typeDetails['id']] = CRM_Utils_Array::value('label', $typeDetails); + } + } + asort($aTypesFilter); + $this->add('select', 'activity_type_filter_id', ts('Activity Type'), array('' => ts('- select activity type -')) + $aTypesFilter); + + $this->assign('caseRelationships', $caseRelationships); + + //also add client as role. CRM-4438 + $caseRoles['client'] = CRM_Case_BAO_Case::getContactNames($this->_caseID); + + $this->assign('caseRoles', $caseRoles); + + $this->add('select', 'reporter_id', ts('Reporter/Role'), $reporters); + + // Retrieve ALL client relationships + $relClient = CRM_Contact_BAO_Relationship::getRelationship($this->_contactID, + CRM_Contact_BAO_Relationship::CURRENT, + 0, 0, 0, NULL, NULL, FALSE + ); + + // Now build 'Other Relationships' array by removing relationships that are already listed under Case Roles + // so they don't show up twice. + $clientRelationships = array(); + foreach ($relClient as $r) { + if (!array_key_exists($r['id'], $caseRelationships)) { + $clientRelationships[] = $r; + } + } + $this->assign('clientRelationships', $clientRelationships); + + // Now global contact list that appears on all cases. + $globalGroupInfo = array(); + $relGlobal = CRM_Case_BAO_Case::getGlobalContacts($globalGroupInfo); + $this->assign('globalRelationships', $relGlobal); + $this->assign('globalGroupInfo', $globalGroupInfo); + + // List of relationship types + $baoRel = new CRM_Contact_BAO_Relationship(); + $relType = $baoRel->getRelationType('Individual'); + $roleTypes = array(); + foreach ($relType as $k => $v) { + $roleTypes[substr($k, 0, strpos($k, '_'))] = $v; + } + $this->add('select', 'role_type', ts('Relationship Type'), array('' => ts('- select type -')) + $roleTypes); + + $hookCaseSummary = CRM_Utils_Hook::caseSummary($this->_caseID); + if (is_array($hookCaseSummary)) { + $this->assign('hookCaseSummary', $hookCaseSummary); + } + + + $allTags = CRM_Core_BAO_Tag::getTags('civicrm_case'); + + if (!empty($allTags)) { + $this->add('select', 'case_tag', ts('Tags'), $allTags, FALSE, + array('id' => 'tags', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + + $tags = CRM_Core_BAO_EntityTag::getTag($this->_caseID, 'civicrm_case'); + + $this->setDefaults(array('case_tag' => $tags)); + + foreach ($tags as $tid) { + $tags[$tid] = $allTags[$tid]; + } + + $this->assign('tags', implode(', ', array_filter($tags))); + $this->assign('showTags', TRUE); + } + else { + $this->assign('showTags', FALSE); + } + + // build tagset widget + + // see if we have any tagsets which can be assigned to cases + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_case'); + if ($parentNames) { + $this->assign('showTagsets', TRUE); + } + else { + $this->assign('showTagsets', FALSE); + } + CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_case', $this->_caseID, FALSE, TRUE); + + $this->addButtons(array( + array( + 'type' => 'cancel', + 'name' => ts('Done'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + $buttonName = $this->controller->getButtonName(); + + // user context + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_contactID}&id={$this->_caseID}&show=1" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + + if (CRM_Utils_Array::value('timeline_id', $params) && + CRM_Utils_Array::value('_qf_CaseView_next', $_POST) + ) { + $session = CRM_Core_Session::singleton(); + $this->_uid = $session->get('userID'); + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $xmlProcessorParams = array( + 'clientID' => $this->_contactID, + 'creatorID' => $this->_uid, + 'standardTimeline' => 0, + 'activity_date_time' => date('YmdHis'), + 'caseID' => $this->_caseID, + 'caseType' => $this->_caseType, + 'activitySetName' => $params['timeline_id'], + ); + $xmlProcessor->run($this->_caseType, $xmlProcessorParams); + $reports = $xmlProcessor->get($this->_caseType, 'ActivitySets'); + + CRM_Core_Session::setStatus(ts('Activities from the %1 activity set have been added to this case.', + array(1 => $reports[$params['timeline_id']]) + ), ts('Done'), 'success'); + } + elseif ($this->_mergeCases && + $buttonName == '_qf_CaseView_next_merge_case' + ) { + + $mainCaseId = $params['merge_case_id']; + $otherCaseId = $this->_caseID; + + //merge two cases. + CRM_Case_BAO_Case::mergeCases($this->_contactID, $mainCaseId, NULL, $otherCaseId); + + //redirect user to main case view. + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_contactID}&id={$mainCaseId}&show=1" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + elseif ($buttonName == '_qf_CaseView_next_edit_client') { + $mainCaseId = CRM_Case_BAO_Case::mergeCases($params['contact_id'], $this->_caseID, $this->_contactID, NULL, TRUE); + + // user context + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$params['contact_id']}&id={$mainCaseId[0]}&show=1" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + } +} + diff --git a/CRM/Case/Form/CustomData.php b/CRM/Case/Form/CustomData.php new file mode 100644 index 0000000000..319e8413b0 --- /dev/null +++ b/CRM/Case/Form/CustomData.php @@ -0,0 +1,183 @@ +_groupID = CRM_Utils_Request::retrieve('groupID', 'Positive', $this, TRUE); + $this->_entityID = CRM_Utils_Request::retrieve('entityID', 'Positive', $this, TRUE); + $this->_subTypeID = CRM_Utils_Request::retrieve('subType', 'Positive', $this, TRUE); + $this->_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + + $groupTree = &CRM_Core_BAO_CustomGroup::getTree('Case', + $this, + $this->_entityID, + $this->_groupID, + $this->_subTypeID + ); + // simplified formatted groupTree + $groupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree, 1, $this); + foreach ($groupTree as $groupValues) { + $this->_customTitle = $groupValues['title']; + } + + $this->_defaults = array(); + CRM_Core_BAO_CustomGroup::setDefaults($groupTree, $this->_defaults); + $this->setDefaults($this->_defaults); + + CRM_Core_BAO_CustomGroup::buildQuickForm($this, $groupTree, FALSE, 1); + + //need to assign custom data type and subtype to the template + $this->assign('entityID', $this->_entityID); + $this->assign('groupID', $this->_groupID); + $this->assign('subType', $this->_subTypeID); + $this->assign('contactID', $this->_contactID); + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + 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(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Process the user submitted custom data values. + * + * @access public + * + * @return void + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + $fields = array(); + + $transaction = new CRM_Core_Transaction(); + + CRM_Core_BAO_CustomValueTable::postProcess($params, + $fields, + 'civicrm_case', + $this->_entityID, + 'Case' + ); + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/view/case', "reset=1&id={$this->_entityID}&cid={$this->_contactID}&action=view")); + + $session = CRM_Core_Session::singleton(); + $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'Change Custom Data', 'name'); + $activityParams = array( + 'activity_type_id' => $activityTypeID, + 'source_contact_id' => $session->get('userID'), + 'is_auto' => TRUE, + 'subject' => $this->_customTitle . " : change data", + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + 'Completed', + 'name' + ), + 'target_contact_id' => $this->_contactID, + 'details' => json_encode($this->_defaults), + 'activity_date_time' => date('YmdHis'), + ); + $activity = CRM_Activity_BAO_Activity::create($activityParams); + + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $this->_entityID, + ); + CRM_Case_BAO_Case::processCaseActivity($caseParams); + + $transaction->commit(); + } +} + diff --git a/CRM/Case/Form/EditClient.php b/CRM/Case/Form/EditClient.php new file mode 100644 index 0000000000..e06701be36 --- /dev/null +++ b/CRM/Case/Form/EditClient.php @@ -0,0 +1,125 @@ +_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + $this->_caseId = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + + //get current client name. + $this->assign('currentClientName', CRM_Contact_BAO_Contact::displayName($this->_contactId)); + + //set the context. + $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&force=1&cid={$this->_contactId}&selectedChild=case"); + if ($context == 'search') { + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + //validate the qfKey + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + $url = CRM_Utils_System::url('civicrm/case/search', $urlParams); + } + elseif ($context == 'dashboard') { + $url = CRM_Utils_System::url('civicrm/case', 'reset=1'); + } + elseif (in_array($context, array( + 'dashlet', 'dashletFullscreen'))) { + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + } + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->add('text', 'change_client_id', ts('Select Contact')); + $this->add('hidden', 'contact_id', '', array('id' => 'contact_id')); + $this->addElement('submit', + $this->getButtonName('next', 'edit_client'), + ts('Reassign Case'), + array( + 'class' => 'form-submit-inline', + 'onclick' => "return checkSelection( this );", + ) + ); + + $this->addElement('submit', + $this->getButtonName('cancel', 'edit_client'), + ts('Cancel'), + array('class' => 'form-submit-inline') + ); + + $this->assign('contactId', $this->_contactId); + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + + //assign case to another client. + $mainCaseId = CRM_Case_BAO_Case::mergeCases($params['contact_id'], $this->_caseId, $this->_contactId, NULL, TRUE); + + // user context + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$params['contact_id']}&id={$mainCaseId[0]}&show=1" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } +} + diff --git a/CRM/Case/Form/Report.php b/CRM/Case/Form/Report.php new file mode 100644 index 0000000000..61a5e02588 --- /dev/null +++ b/CRM/Case/Form/Report.php @@ -0,0 +1,139 @@ +_caseID = CRM_Utils_Request::retrieve('caseid', 'Integer', $this, TRUE); + $this->_clientID = CRM_Utils_Request::retrieve('cid', 'Integer', $this, TRUE); + $this->_activitySetName = CRM_Utils_Request::retrieve('asn', 'String', $this, TRUE); + + $this->_report = $this->get('report'); + if ($this->_report) { + $this->assign_by_ref('report', $this->_report); + } + + // user context + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "reset=1&action=view&cid={$this->_clientID}&id={$this->_caseID}&show=1" + ); + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + + public function buildQuickForm() { + if ($this->_report) { + return; + } + + $includeActivites = array(1 => ts('Include All Activities'), + 2 => ts('Include Missing Activities Only'), + ); + $includeActivitesGroup = $this->addRadio('include_activities', + NULL, + $includeActivites, + NULL, + ' ', + TRUE + ); + $includeActivitesGroup->setValue(1); + + $this->add('checkbox', + 'is_redact', + ts('Redact (hide) Client and Service Provider Data') + ); + + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Generate Report'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $xmlProcessor = new CRM_Case_XMLProcessor_Report(); + $contents = $xmlProcessor->run($this->_clientID, + $this->_caseID, + $this->_activitySetName, + $params + ); + $this->set('report', $contents); + } +} + diff --git a/CRM/Case/Form/Search.php b/CRM/Case/Form/Search.php new file mode 100644 index 0000000000..949554bd32 --- /dev/null +++ b/CRM/Case/Form/Search.php @@ -0,0 +1,554 @@ +set('searchFormName', 'Search'); + + //check for civicase access. + if (!CRM_Case_BAO_Case::accessCiviCase()) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + + //validate case configuration. + $configured = CRM_Case_BAO_Case::isCaseConfigured(); + $this->assign('notConfigured', !$configured['configured']); + if (!$configured['configured']) { + return; + } + + /** + * set the button names + */ + $this->_searchButtonName = $this->getButtonName('refresh'); + $this->_printButtonName = $this->getButtonName('next', 'print'); + $this->_actionButtonName = $this->getButtonName('next', 'action'); + + $this->_done = FALSE; + $this->defaults = array(); + + /* + * we allow the controller to set force/reset externally, useful when we are being + * driven by the wizard framework + */ + + $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean', CRM_Core_DAO::$_nullObject); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE); + $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'search'); + + $this->assign('context', $this->_context); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST) && !$this->controller->isModal()) { + $this->_formValues = $this->controller->exportValues($this->_name); + } + else { + $this->_formValues = $this->get('formValues'); + } + + if (empty($this->_formValues)) { + if (isset($this->_ssID)) { + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + } + } + + if ($this->_force) { + $this->postProcess(); + $this->set('force', 0); + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $selector = new CRM_Case_Selector_Search($this->_queryParams, + $this->_action, + NULL, + $this->_single, + $this->_limit, + $this->_context + ); + + $prefix = NULL; + if ($this->_context == 'user') { + $prefix = $this->_prefix; + } + + $this->assign("{$prefix}limit", $this->_limit); + $this->assign("{$prefix}single", $this->_single); + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::TRANSFER, + $prefix + ); + $controller->setEmbedded(TRUE); + $controller->moveFromSessionToTemplate(); + + $this->assign('summary', $this->get('summary')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->addElement('text', + 'sort_name', + ts('Client Name or Email'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name') + ); + + CRM_Case_BAO_Query::buildSearchForm($this); + + /* + * add form checkboxes for each row. This is needed out here to conform to QF protocol + * of all elements being declared in builQuickForm + */ + $rows = $this->get('rows'); + if (is_array($rows)) { + + if (!$this->_single) { + $this->addElement('checkbox', + 'toggleSelect', + NULL, + NULL, + array('onclick' => "toggleTaskAction( true ); return toggleCheckboxVals('mark_x_',this);") + ); + + foreach ($rows as $row) { + $this->addElement('checkbox', $row['checkbox'], + NULL, NULL, + array('onclick' => "toggleTaskAction( true ); return checkSelectedBox('" . $row['checkbox'] . "');") + ); + } + } + + $total = $cancel = 0; + + $permission = CRM_Core_Permission::getPermission(); + + $tasks = array('' => ts('- actions -')) + CRM_Case_Task::permissionedTaskTitles($permission); + + if (CRM_Utils_Array::value('case_deleted', $this->_formValues)) { + unset($tasks[1]); + } + else { + unset($tasks[4]); + } + + $this->add('select', 'task', ts('Actions:') . ' ', $tasks); + $this->add('submit', $this->_actionButtonName, ts('Go'), + array( + 'class' => 'form-submit', + 'id' => 'Go', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 0);", + ) + ); + + $this->add('submit', $this->_printButtonName, ts('Print'), + array( + 'class' => 'form-submit', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 1);", + ) + ); + + // need to perform tasks on all or selected items ? using radio_ts(task selection) for it + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_sel', array('checked' => 'checked')); + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_all', array('onclick' => $this->getName() . ".toggleSelect.checked = false; toggleCheckboxVals('mark_x_',this); toggleTaskAction( true );")); + } + + // add buttons + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + )); + } + + /** + * The post processing of the form gets done here. + * + * Key things done during post processing are + * - check for reset or next request. if present, skip post procesing. + * - now check if user requested running a saved search, if so, then + * the form values associated with the saved search are used for searching. + * - if user has done a submit with new values the regular post submissing is + * done. + * The processing consists of using a Selector / Controller framework for getting the + * search results. + * + * @param + * + * @return void + * @access public + */ + function postProcess() { + if ($this->_done) { + return; + } + + $this->_done = TRUE; + $this->_formValues = $this->controller->exportValues($this->_name); + $this->fixFormValues(); + + if (isset($this->_ssID) && empty($_POST)) { + // if we are editing / running a saved search and the form has not been posted + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + } + + //search for civicase + if (!$this->_force) { + if (array_key_exists('case_owner', $this->_formValues) && !$this->_formValues['case_owner']) { + $this->_formValues['case_owner'] = 0; + } + } + + //only fetch own cases. + if (!CRM_Core_Permission::check('access all cases and activities')) { + $this->_formValues['case_owner'] = 2; + } + + if (!CRM_Utils_Array::value('case_deleted', $this->_formValues)) { + $this->_formValues['case_deleted'] = 0; + } + CRM_Core_BAO_CustomValue::fixFieldValueOfTypeMemo($this->_formValues); + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $this->set('formValues', $this->_formValues); + $this->set('queryParams', $this->_queryParams); + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->_actionButtonName || $buttonName == $this->_printButtonName) { + // check actionName and if next, then do not repeat a search, since we are going to the next page + + // hack, make sure we reset the task values + $stateMachine = &$this->controller->getStateMachine(); + $formName = $stateMachine->getTaskFormName(); + $this->controller->resetPage($formName); + return; + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $selector = new CRM_Case_Selector_Search($this->_queryParams, + $this->_action, + NULL, + $this->_single, + $this->_limit, + $this->_context + ); + $selector->setKey($this->controller->_key); + + $prefix = NULL; + if ($this->_context == 'user') { + $prefix = $this->_prefix; + } + + $this->assign("{$prefix}limit", $this->_limit); + $this->assign("{$prefix}single", $this->_single); + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::SESSION, + $prefix + ); + $controller->setEmbedded(TRUE); + + $query = &$selector->getQuery(); + if ($this->_context == 'user') { + $query->setSkipPermission(TRUE); + } + $controller->run(); + } + + /** + * This function is used to add the rules (mainly global rules) for form. + * All local rules are added near the element + * + * @return None + * @access public + * @see valid_date + */ + function addRules() { + $this->addFormRule(array('CRM_Case_Form_Search', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * + * @return void + * @static + * @access public + */ + static function formRule($fields) { + $errors = array(); + + if (!empty($errors)) { + return $errors; + } + + return TRUE; + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + $defaults = array(); + $defaults = $this->_formValues; + return $defaults; + } + + function fixFormValues() { + if (!$this->_force) { + return; + } + + $caseStatus = CRM_Utils_Request::retrieve('status', 'Positive', + CRM_Core_DAO::$_nullObject + ); + if ($caseStatus) { + $this->_formValues['case_status_id'] = $caseStatus; + $this->_defaults['case_status_id'] = $caseStatus; + } + $caseType = CRM_Utils_Request::retrieve('type', 'Positive', + CRM_Core_DAO::$_nullObject + ); + if ($caseType) { + $this->_formValues['case_type_id'][$caseType] = 1; + $this->_defaults['case_type_id'][$caseType] = 1; + } + + $caseFromDate = CRM_Utils_Request::retrieve('pstart', 'Date', + CRM_Core_DAO::$_nullObject + ); + if ($caseFromDate) { + list($date) = CRM_Utils_Date::setDateDefaults($caseFromDate); + $this->_formValues['case_start_date_low'] = $date; + $this->_defaults['case_start_date_low'] = $date; + } + + $caseToDate = CRM_Utils_Request::retrieve('pend', 'Date', + CRM_Core_DAO::$_nullObject + ); + if ($caseToDate) { + list($date) = CRM_Utils_Date::setDateDefaults($caseToDate); + $this->_formValues['case_start_date_high'] = $date; + $this->_defaults['case_start_date_high'] = $date; + } + + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + if ($cid) { + $cid = CRM_Utils_Type::escape($cid, 'Integer'); + if ($cid > 0) { + $this->_formValues['contact_id'] = $cid; + list($display, $image) = CRM_Contact_BAO_Contact::getDisplayAndImage($cid); + $this->_defaults['sort_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, + 'sort_name' + ); + // also assign individual mode to the template + $this->_single = TRUE; + } + } + else { + // First, if "all" is stored in the session, default to all cases, otherwise default to no selection. + $session = CRM_Core_Session::singleton(); + if (CRM_Utils_Request::retrieve('all', 'Positive', $session)) { + $this->_formValues['case_owner'] = 1; + $this->_defaults['case_owner'] = 1; + } + else { + $this->_formValues['case_owner'] = 0; + $this->_defaults['case_owner'] = 0; + } + + // Now if case_owner is set in the url/post, use that instead. + $caseOwner = CRM_Utils_Request::retrieve('case_owner', 'Positive', + CRM_Core_DAO::$_nullObject + ); + if ($caseOwner) { + $this->_formValues['case_owner'] = $caseOwner; + $this->_defaults['case_owner'] = $caseOwner; + } + } + } + + function getFormValues() { + return NULL; + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Find Cases'); + } +} + diff --git a/CRM/Case/Form/Task.php b/CRM/Case/Form/Task.php new file mode 100644 index 0000000000..2ec851d779 --- /dev/null +++ b/CRM/Case/Form/Task.php @@ -0,0 +1,173 @@ +_caseIds = array(); + + $values = $form->controller->exportValues($form->get('searchFormName')); + + $form->_task = $values['task']; + $caseTasks = CRM_Case_Task::tasks(); + $form->assign('taskName', $caseTasks[$form->_task]); + + $ids = array(); + if ($values['radio_ts'] == 'ts_sel') { + foreach ($values as $name => $value) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + } + } + } + else { + $queryParams = $form->get('queryParams'); + $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_CASE + ); + $query->_distinctComponentClause = " ( civicrm_case.id )"; + $query->_groupByComponentClause = " GROUP BY civicrm_case.id "; + $result = $query->searchQuery(0, 0, NULL); + while ($result->fetch()) { + $ids[] = $result->case_id; + } + } + + if (!empty($ids)) { + $form->_componentClause = ' civicrm_case.id IN ( ' . implode(',', $ids) . ' ) '; + $form->assign('totalSelectedCases', count($ids)); + } + + $form->_caseIds = $form->_componentIds = $ids; + + //set the context for redirection for any task actions + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + + $session = CRM_Core_Session::singleton(); + $searchFormName = strtolower($form->get('searchFormName')); + if ($searchFormName == 'search') { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/case/search', $urlParams)); + } + else { + $session->replaceUserContext(CRM_Utils_System::url("civicrm/contact/search/$searchFormName", + $urlParams + )); + } + } + + /** + * Given the signer id, compute the contact id + * since its used for things like send email + */ + public function setContactIDs() { + $this->_contactIds = &CRM_Core_DAO::getContactIDsFromComponent($this->_caseIds, + 'civicrm_case' + ); + } + + /** + * simple shell that derived classes can call to add buttons to + * the form with a customized title for the main Submit + * + * @param string $title title of the main button + * @param string $type button type for the form after processing + * + * @return void + * @access public + */ + function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) { + $this->addButtons(array( + array( + 'type' => $nextType, + 'name' => $title, + 'isDefault' => TRUE, + ), + array( + 'type' => $backType, + 'name' => ts('Cancel'), + ), + ) + ); + } +} + diff --git a/CRM/Case/Form/Task/Delete.php b/CRM/Case/Form/Task/Delete.php new file mode 100644 index 0000000000..23e36ea2d7 --- /dev/null +++ b/CRM/Case/Form/Task/Delete.php @@ -0,0 +1,101 @@ +addDefaultButtons(ts('Delete Cases'), 'done'); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $deletedCases = 0; + foreach ($this->_caseIds as $caseId) { + if (CRM_Case_BAO_Case::deleteCase($caseId, $this->_moveToTrash)) { + $deletedCases++; + } + } + + CRM_Core_Session::setStatus($deletedCases, ts('Deleted Cases'), 'success'); + CRM_Core_Session::setStatus('', ts('Total Selected Case(s): %1', array(1 => count($this->_caseIds))), 'info'); + } +} + diff --git a/CRM/Case/Form/Task/Print.php b/CRM/Case/Form/Task/Print.php new file mode 100644 index 0000000000..ce94bf5034 --- /dev/null +++ b/CRM/Case/Form/Task/Print.php @@ -0,0 +1,109 @@ +controller->setPrint(1); + + // get the formatted params + $queryParams = $this->get('queryParams'); + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $selector = new CRM_Case_Selector_Search($queryParams, $this->_action, $this->_componentClause); + $controller = new CRM_Core_Selector_Controller($selector, NULL, $sortID, CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::SCREEN); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + /** + * Build the form - it consists of + * - displaying the QILL (query in local language) + * - displaying elements for saving the search + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // + // just need to add a javacript to popup the window for printing + // + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Print Case List'), + 'js' => array('onclick' => 'window.print()'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Done'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + // redirect to the main search page after printing is over + } +} + diff --git a/CRM/Case/Form/Task/Restore.php b/CRM/Case/Form/Task/Restore.php new file mode 100644 index 0000000000..7cc449f7e5 --- /dev/null +++ b/CRM/Case/Form/Task/Restore.php @@ -0,0 +1,90 @@ +addDefaultButtons(ts('Restore Cases'), 'done'); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $restoredCases = 0; + foreach ($this->_caseIds as $caseId) { + if (CRM_Case_BAO_Case::restoreCase($caseId)) { + $restoredCases++; + } + } + + CRM_Core_Session::setStatus($restoredCases, ts('Restored Cases'), 'success'); + CRM_Core_Session::setStatus('', ts('Total Selected Case(s): %1', array(1 => count($this->_caseIds))), 'info'); + } +} + diff --git a/CRM/Case/Form/Task/Result.php b/CRM/Case/Form/Task/Result.php new file mode 100644 index 0000000000..458b9c79d9 --- /dev/null +++ b/CRM/Case/Form/Task/Result.php @@ -0,0 +1,68 @@ +addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Case/Form/Task/SearchTaskHookSample.php b/CRM/Case/Form/Task/SearchTaskHookSample.php new file mode 100644 index 0000000000..c02f9da85f --- /dev/null +++ b/CRM/Case/Form/Task/SearchTaskHookSample.php @@ -0,0 +1,92 @@ +_caseIds); + $statusId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'case_status', 'id', 'name'); + $query = " +SELECT ct.display_name as display_name, + cs.start_date as start_date, + ov.label as status + +FROM civicrm_case cs +INNER JOIN civicrm_case_contact cc ON ( cs.id = cc.case_id) +INNER JOIN civicrm_contact ct ON ( cc.contact_id = ct.id) +LEFT JOIN civicrm_option_value ov ON (cs.status_id = ov.value AND ov.option_group_id = {$statusId} ) +WHERE cs.id IN ( {$caseIDs} )"; + + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + while ($dao->fetch()) { + $rows[] = array( + 'display_name' => $dao->display_name, + 'start_date' => CRM_Utils_Date::customFormat($dao->start_date), + 'status' => $dao->status, + ); + } + $this->assign('rows', $rows); + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Case/Info.php b/CRM/Case/Info.php new file mode 100644 index 0000000000..3e73073268 --- /dev/null +++ b/CRM/Case/Info.php @@ -0,0 +1,111 @@ + 'CiviCase', + 'translatedName' => ts('CiviCase'), + 'title' => ts('CiviCase Engine'), + 'search' => 1, + 'showActivitiesInCore' => 0, + ); + } + + // docs inherited from interface + public function getPermissions() { + return array( + 'delete in CiviCase', + 'administer CiviCase', + 'access my cases and activities', + 'access all cases and activities', + 'add cases', + ); + } + + // docs inherited from interface + public function getUserDashboardElement() { + return array(); + } + + // docs inherited from interface + public function registerTab() { + return array('title' => ts('Cases'), + 'url' => 'case', + 'weight' => 50, + ); + } + + // docs inherited from interface + public function registerAdvancedSearchPane() { + return array('title' => ts('Cases'), + 'weight' => 50, + ); + } + + // docs inherited from interface + public function getActivityTypes() { + return NULL; + } + + // add shortcut to Create New + public function creatNewShortcut(&$shortCuts) { + if (CRM_Core_Permission::check('access all cases and activities') || + CRM_Core_Permission::check('add cases') + ) { + $atype = CRM_Core_OptionGroup::getValue('activity_type', + 'Open Case', + 'name' + ); + if ($atype) { + $shortCuts = array_merge($shortCuts, array( + array('path' => 'civicrm/case/add', + 'query' => "reset=1&action=add&atype=$atype&context=standalone", + 'ref' => 'new-case', + 'title' => ts('Case'), + ))); + } + } + } +} + diff --git a/CRM/Case/Page/AJAX.php b/CRM/Case/Page/AJAX.php new file mode 100644 index 0000000000..9739f1f461 --- /dev/null +++ b/CRM/Case/Page/AJAX.php @@ -0,0 +1,183 @@ + $limit, + 'case_type' => trim(CRM_Utils_Array::value(1, $criteria)), + 'sort_name' => trim(CRM_Utils_Array::value(0, $criteria)), + ); + + $excludeCaseIds = array(); + if ($caseIdStr = CRM_Utils_Array::value('excludeCaseIds', $_GET)) { + $excludeIdStr = CRM_Utils_Type::escape($caseIdStr, 'String'); + $excludeCaseIds = explode(',', $excludeIdStr); + } + $unclosedCases = CRM_Case_BAO_Case::getUnclosedCases($params, $excludeCaseIds); + + foreach ($unclosedCases as $caseId => $details) { + echo $details['sort_name'] . ' (' . $details['case_type'] . ': ' . $details['case_subject'] . ') ' . "|$caseId|" . $details['contact_id'] . '|' . $details['case_type'] . '|' . $details['sort_name'] . "\n"; + } + + CRM_Utils_System::civiExit(); + } + + function processCaseTags() { + + $caseId = CRM_Utils_Type::escape($_POST['case_id'], 'Integer'); + $tags = CRM_Utils_Type::escape($_POST['tag'], 'String'); + + if (empty($caseId)) { + echo 'false'; + CRM_Utils_System::civiExit(); + } + + $tagIds = array(); + if ($tags) { + $tagIds = explode(',', $tags); + } + + $params = array( + 'entity_id' => $caseId, + 'entity_table' => 'civicrm_case', + ); + + CRM_Core_BAO_EntityTag::del($params); + + foreach ($tagIds as $tagid) { + if (is_numeric($tagid)) { + $params['tag_id'] = $tagid; + CRM_Core_BAO_EntityTag::add($params); + } + } + + $session = CRM_Core_Session::singleton(); + + $activityParams = array(); + $activityParams['source_contact_id'] = $session->get('userID'); + $activityParams['activity_type_id'] = CRM_Core_OptionGroup::getValue('activity_type', 'Change Case Tags', 'name'); + $activityParams['activity_date_time'] = date('YmdHis'); + $activityParams['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + $activityParams['case_id'] = $caseId; + $activityParams['is_auto'] = 0; + $activityParams['subject'] = 'Change Case Tags'; + + $activity = CRM_Activity_BAO_Activity::create($activityParams); + + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $caseId, + ); + + CRM_Case_BAO_Case::processCaseActivity($caseParams); + + echo 'true'; + CRM_Utils_System::civiExit(); + } + + function caseDetails() { + $caseId = CRM_Utils_Type::escape($_GET['caseId'], 'Integer'); + $sql = "SELECT * FROM civicrm_case where id = %1"; + $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($caseId, 'Integer'))); + + if ($dao->fetch()) { + $caseType = CRM_Case_BAO_Case::getCaseType((str_replace(CRM_Core_DAO::VALUE_SEPARATOR, + "", + $dao->case_type_id + ))); + $caseStatuses = CRM_Case_PseudoConstant::caseStatus(); + $cs = $caseStatuses[$dao->status_id]; + $caseDetails = " + + + + " . CRM_Utils_Date::customFormat($dao->end_date) . "
    " . ts('Case Subject') . "{$dao->subject}
    " . ts('Case Type') . "{$caseType}
    " . ts('Case Status') . "{$cs}
    " . ts('Case Start Date') . "" . CRM_Utils_Date::customFormat($dao->start_date) . "
    " . ts('Case End Date') . "
    "; + echo $caseDetails; + } + else { + echo ts('Could not find valid Case!'); + } + CRM_Utils_System::civiExit(); + } + + function addClient() { + $caseId = CRM_Utils_Type::escape($_POST['caseID'], 'Integer'); + $contactId = CRM_Utils_Type::escape($_POST['contactID'], 'Integer'); + + $params = array( + 'case_id' => $caseId, + 'contact_id' => $contactId, + ); + + CRM_Case_BAO_Case::addCaseToContact($params); + + $session = CRM_Core_Session::singleton(); + + $activityParams = array(); + $activityParams['source_contact_id'] = $session->get('userID'); + $activityParams['activity_type_id'] = CRM_Core_OptionGroup::getValue('activity_type', 'Add Client To Case', 'name'); + $activityParams['activity_date_time'] = date('YmdHis'); + $activityParams['status_id'] = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + $activityParams['case_id'] = $caseId; + $activityParams['is_auto'] = 0; + $activityParams['subject'] = 'Client Added To Case'; + + $activity = CRM_Activity_BAO_Activity::create($activityParams); + + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $caseId, + ); + + CRM_Case_BAO_Case::processCaseActivity($caseParams); + echo json_encode(TRUE); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Case/Page/CaseDetails.php b/CRM/Case/Page/CaseDetails.php new file mode 100644 index 0000000000..03d101cb45 --- /dev/null +++ b/CRM/Case/Page/CaseDetails.php @@ -0,0 +1,72 @@ +_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + $type = CRM_Utils_Request::retrieve('type', 'String', CRM_Core_DAO::$_nullObject); + + $this->assign('action', $this->_action); + $this->assign('context', $this->_context); + + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + $caseId = CRM_Utils_Request::retrieve('caseId', 'Positive', $this); + + CRM_Case_Page_Tab::setContext(); + + $params = array('date_range' => 0); + + $caseDetails = array(); + if (CRM_Case_BAO_Case::accessCiviCase()) { + $caseDetails = CRM_Case_BAO_Case::getCaseActivity($caseId, $params, $this->_contactId, NULL, NULL, $type); + } + + $this->assign('rows', $caseDetails); + $this->assign('caseId', $caseId); + $this->assign('contactId', $this->_contactId); + + return parent::run(); + } +} + diff --git a/CRM/Case/Page/DashBoard.php b/CRM/Case/Page/DashBoard.php new file mode 100644 index 0000000000..9f3a4a33e6 --- /dev/null +++ b/CRM/Case/Page/DashBoard.php @@ -0,0 +1,114 @@ +assign('notConfigured', !$configured['configured']); + $this->assign('allowToAddNewCase', $configured['allowToAddNewCase']); + if (!$configured['configured']) { + return; + } + + $session = CRM_Core_Session::singleton(); + $allCases = CRM_Utils_Request::retrieve('all', 'Positive', $session); + + CRM_Utils_System::setTitle(ts('CiviCase Dashboard')); + + $userID = $session->get('userID'); + + //validate access for all cases. + if ($allCases && !CRM_Core_Permission::check('access all cases and activities')) { + $allCases = FALSE; + CRM_Core_Session::setStatus(ts('You are not authorized to access all cases and activities.'), ts('Sorry'), 'error'); + } + if (!$allCases) { + $this->assign('myCases', TRUE); + } + else { + $this->assign('myCases', FALSE); + } + + $this->assign('newClient', FALSE); + if (CRM_Core_Permission::check('add contacts') && + CRM_Core_Permission::check('access all cases and activities') + ) { + $this->assign('newClient', TRUE); + } + $summary = CRM_Case_BAO_Case::getCasesSummary($allCases, $userID); + $upcoming = CRM_Case_BAO_Case::getCases($allCases, $userID, 'upcoming'); + $recent = CRM_Case_BAO_Case::getCases($allCases, $userID, 'recent'); + + $this->assign('casesSummary', $summary); + if (!empty($upcoming)) { + $this->assign('upcomingCases', $upcoming); + } + if (!empty($recent)) { + $this->assign('recentCases', $recent); + } + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + return parent::run(); + } +} + diff --git a/CRM/Case/Page/Tab.php b/CRM/Case/Page/Tab.php new file mode 100644 index 0000000000..0b39236a46 --- /dev/null +++ b/CRM/Case/Page/Tab.php @@ -0,0 +1,330 @@ +_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + //validate case configuration. + $configured = CRM_Case_BAO_Case::isCaseConfigured($this->_contactId); + $this->assign('notConfigured', !$configured['configured']); + $this->assign('allowToAddNewCase', $configured['allowToAddNewCase']); + $this->assign('redirectToCaseAdmin', $configured['redirectToCaseAdmin']); + if (!$configured['configured'] || $configured['redirectToCaseAdmin']) { + return; + } + + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + + if ($this->_contactId) { + $this->assign('contactId', $this->_contactId); + // check logged in user permission + if ($this->_id && ($this->_action & CRM_Core_Action::VIEW)) { + //user might have special permissions to view this case, CRM-5666 + if (!CRM_Core_Permission::check('access all cases and activities')) { + $session = CRM_Core_Session::singleton(); + $userCases = CRM_Case_BAO_Case::getCases(FALSE, $session->get('userID')); + if (!array_key_exists($this->_id, $userCases)) { + CRM_Core_Error::fatal(ts('You are not authorized to access this page.')); + } + } + } + else { + CRM_Contact_Page_View::checkUserPermission($this); + } + + // set page title + CRM_Contact_Page_View::setTitle($this->_contactId); + } + else { + if ($this->_action & CRM_Core_Action::VIEW) { + CRM_Core_Error::fatal('Contact Id is required for view action.'); + } + } + + $activityTypes = CRM_Case_PseudoConstant::caseActivityType(); + + $this->assign('openCaseId', $activityTypes['Open Case']['id']); + $this->assign('changeCaseTypeId', $activityTypes['Change Case Type']['id']); + $this->assign('changeCaseStatusId', $activityTypes['Change Case Status']['id']); + $this->assign('changeCaseStartDateId', $activityTypes['Change Case Start Date']['id']); + } + + /** + * View details of a case + * + * @return void + * @access public + */ + function view() { + $controller = new CRM_Core_Controller_Simple( + 'CRM_Case_Form_CaseView', + 'View Case', + $this->_action, + FALSE, + FALSE, + TRUE + ); + $controller->setEmbedded(TRUE); + $controller->set('id', $this->_id); + $controller->set('cid', $this->_contactId); + $controller->run(); + + $this->assign('caseId', $this->_id); + $output = CRM_Core_Selector_Controller::SESSION; + $selector = new CRM_Activity_Selector_Activity($this->_contactId, $this->_permission, FALSE, 'case'); + $controller = + new CRM_Core_Selector_Controller( + $selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + NULL, + CRM_Core_Action::VIEW, + $this, + $output, + NULL, + $this->_id + ); + + + $controller->setEmbedded(TRUE); + + $controller->run(); + $controller->moveFromSessionToTemplate(); + + $this->assign('context', 'case'); + } + + /** + * This function is called when action is browse + * + * return null + * @access public + */ + function browse() { + + $controller = new CRM_Core_Controller_Simple('CRM_Case_Form_Search', ts('Case'), NULL); + $controller->setEmbedded(TRUE); + $controller->reset(); + $controller->set('limit', 20); + $controller->set('force', 1); + $controller->set('context', 'case'); + $controller->process(); + $controller->run(); + + if ($this->_contactId) { + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + $this->assign('displayName', $displayName); + } + } + + /** + * This function is called when action is update or new + * + * return null + * @access public + */ + function edit() { + $config = CRM_Core_Config::singleton(); + + $controller = new CRM_Core_Controller_Simple( + 'CRM_Case_Form_Case', + 'Open Case', + $this->_action + ); + + $controller->setEmbedded(TRUE); + + return $controller->run(); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $contactID = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullArray); + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + + if ($context == 'standalone' && !$contactID) { + $this->_action = CRM_Core_Action::ADD; + } + else { + // we need to call parent preprocess only when we are viewing / editing / adding participant record + $this->preProcess(); + } + + $this->assign('action', $this->_action); + + $this->setContext(); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->view(); + } + elseif (($this->_action & + (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | + CRM_Core_Action::DELETE | CRM_Core_Action::RENEW + ) + ) || + !empty($_POST) + ) { + $this->edit(); + } + elseif ($this->_contactId) { + $this->browse(); + } + + return parent::run(); + } + + /** + * Get action links + * + * @return array (reference) of action links + * @static + */ + static + function &links() { + $config = CRM_Core_Config::singleton(); + + if (!(self::$_links)) { + $deleteExtra = ts('Are you sure you want to delete this case?'); + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('Manage'), + 'url' => 'civicrm/contact/view/case', + 'qs' => 'action=view&reset=1&cid=%%cid%%&id=%%id%%', + 'title' => ts('Manage Case'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/case', + 'qs' => 'action=delete&reset=1&cid=%%cid%%&id=%%id%%', + 'title' => ts('Delete Case'), + ), + ); + } + return self::$_links; + } + + function setContext() { + $context = $this->get('context'); + $url = NULL; + + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + //validate the qfKey + if (!CRM_Utils_Rule::qfKey($qfKey)) { + $qfKey = NULL; + } + + switch ($context) { + case 'activity': + if ($this->_contactId) { + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&force=1&cid={$this->_contactId}&selectedChild=activity" + ); + } + break; + + case 'dashboard': + $url = CRM_Utils_System::url('civicrm/case', "reset=1"); + break; + + case 'search': + $urlParams = 'force=1'; + if ($qfKey) { + $urlParams .= "&qfKey=$qfKey"; + } + + $url = CRM_Utils_System::url('civicrm/case/search', $urlParams); + break; + + case 'dashlet': + case 'dashletFullscreen': + case 'home': + case 'standalone': + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + break; + + case 'fulltext': + $action = CRM_Utils_Request::retrieve('action', 'String', $this); + $urlParams = 'force=1'; + $urlString = 'civicrm/contact/search/custom'; + if ($action == CRM_Core_Action::RENEW) { + if ($this->_contactId) { + $urlParams .= '&cid=' . $this->_contactId; + } + $urlParams .= '&context=fulltext&action=view'; + $urlString = 'civicrm/contact/view/case'; + } + if ($qfKey) { + $urlParams .= "&qfKey=$qfKey"; + } + $url = CRM_Utils_System::url($urlString, $urlParams); + break; + + default: + if ($this->_contactId) { + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&force=1&cid={$this->_contactId}&selectedChild=case" + ); + } + break; + } + + if ($url) { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + } +} + diff --git a/CRM/Case/PseudoConstant.php b/CRM/Case/PseudoConstant.php new file mode 100644 index 0000000000..5540c9d5c3 --- /dev/null +++ b/CRM/Case/PseudoConstant.php @@ -0,0 +1,280 @@ +fetch()) { + if ($indexName) { + $index = $dao->name; + } + else { + $index = $dao->value; + } + $activityTypes[$index] = array(); + $activityTypes[$index]['id'] = $dao->value; + $activityTypes[$index]['label'] = $dao->label; + $activityTypes[$index]['name'] = $dao->name; + $activityTypes[$index]['description'] = $dao->description; + } + self::$activityTypeList[$cache] = $activityTypes; + } + return self::$activityTypeList[$cache]; + } + + /** + * Get the associated case type name/id, given a case Id + * + * @access public + * + * @return array - array reference of all case type name/id + * @static + */ + public static function caseTypeName($caseId, $column = 'name') { + if (!$caseId) { + return FALSE; + } + + if (!array_key_exists($caseId, self::$caseTypePair) || empty(self::$caseTypePair[$caseId][$column])) { + $caseTypes = self::caseType($column); + $caseTypeIds = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', + $caseId, + 'case_type_id' + ); + $caseTypeId = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($caseTypeIds, + CRM_Core_DAO::VALUE_SEPARATOR + ) + ); + $caseTypeId = $caseTypeId[0]; + + self::$caseTypePair[$caseId][$column] = array( + 'id' => $caseTypeId, + 'name' => $caseTypes[$caseTypeId], + ); + } + + return self::$caseTypePair[$caseId][$column]; + } + + /** + * Flush given pseudoconstant so it can be reread from db + * nex time it's requested. + * + * @access public + * @static + * + * @param boolean $name pseudoconstant to be flushed + * + */ + public static function flush($name) { + self::$$name = NULL; + } +} + diff --git a/CRM/Case/Selector/Search.php b/CRM/Case/Selector/Search.php new file mode 100644 index 0000000000..d03b06e5a2 --- /dev/null +++ b/CRM/Case/Selector/Search.php @@ -0,0 +1,494 @@ +_queryParams = &$queryParams; + + $this->_single = $single; + $this->_limit = $limit; + $this->_context = $context; + + $this->_additionalClause = $additionalClause; + + // type of selector + $this->_action = $action; + + $this->_query = new CRM_Contact_BAO_Query($this->_queryParams, + CRM_Case_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CASE, + FALSE + ), + NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_CASE + ); + + $this->_query->_distinctComponentClause = " civicrm_case.id "; + $this->_query->_groupByComponentClause = " GROUP BY civicrm_case.id "; + } + //end of constructor + + /** + * This method returns the links that are given for each search row. + * currently the links added for each row are + * + * - View + * - Edit + * + * @return array + * @access public + * + */ + static + function &links($isDeleted = FALSE, $key = NULL) { + $extraParams = ($key) ? "&key={$key}" : NULL; + + if ($isDeleted) { + self::$_links = array( + CRM_Core_Action::RENEW => array( + 'name' => ts('Restore'), + 'url' => 'civicrm/contact/view/case', + 'qs' => 'reset=1&action=renew&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams, + 'ref' => 'restore-case', + 'title' => ts('Restore Case'), + ), + ); + } + else { + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('Manage'), + 'url' => 'civicrm/contact/view/case', + 'qs' => 'reset=1&id=%%id%%&cid=%%cid%%&action=view&context=%%cxt%%&selectedChild=case' . $extraParams, + 'ref' => 'manage-case', + 'title' => ts('Manage Case'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/case', + 'qs' => 'reset=1&action=delete&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams, + 'ref' => 'delete-case', + 'title' => ts('Delete Case'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Assign to Another Client'), + 'url' => 'civicrm/contact/view/case/editClient', + 'qs' => 'reset=1&action=update&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams, + 'ref' => 'reassign', + 'title' => ts('Assign to Another Client'), + ), + ); + } + + $actionLinks = array(); + foreach (self::$_links as $key => $value) { + if ($value['ref'] == 'reassign') { + $actionLinks['moreActions'][$key] = $value; + } + else { + $actionLinks['primaryActions'][$key] = $value; + } + } + + return $actionLinks; + } + //end of function + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['status'] = ts('Case') . ' %%StatusMessage%%'; + $params['csvString'] = NULL; + if ($this->_limit) { + $params['rowCount'] = $this->_limit; + } + else { + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + } + + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + //end of function + + /** + * Returns total number of rows for the query. + * + * @param + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action) { + return $this->_query->searchQuery(0, 0, NULL, + TRUE, FALSE, + FALSE, FALSE, + FALSE, + $this->_additionalClause + ); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return int the total number of rows for this action + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { + $result = $this->_query->searchQuery($offset, $rowCount, $sort, + FALSE, FALSE, + FALSE, FALSE, + FALSE, + $this->_additionalClause + ); + // process the result of the query + $rows = array(); + + //CRM-4418 check for view, edit, delete + $permissions = array(CRM_Core_Permission::VIEW); + if (CRM_Core_Permission::check('access all cases and activities') + || CRM_Core_Permission::check('access my cases and activities') + ) { + $permissions[] = CRM_Core_Permission::EDIT; + } + if (CRM_Core_Permission::check('delete in CiviCase')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + $caseStatus = CRM_Core_OptionGroup::values('case_status', FALSE, FALSE, FALSE, " AND v.name = 'Urgent' "); + + $scheduledInfo = array(); + + while ($result->fetch()) { + $row = array(); + // the columns we are interested in + foreach (self::$_properties as $property) { + if (isset($result->$property)) { + $row[$property] = $result->$property; + } + } + + $isDeleted = FALSE; + if ($result->case_deleted) { + $isDeleted = TRUE; + $row['case_status_id'] = empty($row['case_status_id']) ? "" : $row['case_status_id'] . '
    (deleted)'; + } + + $scheduledInfo['case_id'][] = $result->case_id; + $scheduledInfo['contact_id'][] = $result->contact_id; + $scheduledInfo['case_deleted'] = $result->case_deleted; + $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->case_id; + + $links = self::links($isDeleted, $this->_key); + $row['action'] = CRM_Core_Action::formLink($links['primaryActions'], + $mask, array( + 'id' => $result->case_id, + 'cid' => $result->contact_id, + 'cxt' => $this->_context, + ) + ); + $row['moreActions'] = CRM_Core_Action::formLink(CRM_Utils_Array::value('moreActions', $links), + $mask, array( + 'id' => $result->case_id, + 'cid' => $result->contact_id, + 'cxt' => $this->_context, + ), + ts('more'), + TRUE + ); + + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type + ); + + //adding case manager to case selector.CRM-4510. + $caseType = CRM_Case_BAO_Case::getCaseType($result->case_id, 'name'); + $caseManagerContact = CRM_Case_BAO_Case::getCaseManagerContact($caseType, $result->case_id); + + if (!empty($caseManagerContact)) { + $row['casemanager_id'] = CRM_Utils_Array::value('casemanager_id', $caseManagerContact); + $row['casemanager'] = CRM_Utils_Array::value('casemanager', $caseManagerContact); + } + + if (isset($result->case_status_id) && + array_key_exists($result->case_status_id, $caseStatus) + ) { + $row['class'] = "status-urgent"; + } + else { + $row['class'] = "status-normal"; + } + + $rows[$result->case_id] = $row; + } + + //retrive the scheduled & recent Activity type and date for selector + if (!empty($scheduledInfo)) { + $schdeduledActivity = CRM_Case_BAO_Case::getNextScheduledActivity($scheduledInfo, 'upcoming'); + foreach ($schdeduledActivity as $key => $value) { + $rows[$key]['case_scheduled_activity_date'] = $value['date']; + $rows[$key]['case_scheduled_activity_type'] = $value['type']; + } + $recentActivity = CRM_Case_BAO_Case::getNextScheduledActivity($scheduledInfo, 'recent'); + foreach ($recentActivity as $key => $value) { + $rows[$key]['case_recent_activity_date'] = $value['date']; + $rows[$key]['case_recent_activity_type'] = $value['type']; + } + } + return $rows; + } + + /** + * + * @return array $qill which contains an array of strings + * @access public + */ + + // the current internationalisation is bad, but should more or less work + // for most of "European" languages + public function getQILL() { + return $this->_query->qill(); + } + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + public function &getColumnHeaders($action = NULL, $output = NULL) { + if (!isset(self::$_columnHeaders)) { + self::$_columnHeaders = array( + array( + 'name' => ts('Subject'), + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Status'), + 'sort' => 'case_status', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Case Type'), + 'sort' => 'case_type_id', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('My Role'), + 'sort' => 'case_role', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Case Manager'), + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Most Recent'), + 'sort' => 'case_recent_activity_date', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Next Sched.'), + 'sort' => 'case_scheduled_activity_date', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('name' => ts('Actions')), + ); + + if (!$this->_single) { + $pre = array( + array( + 'name' => ts('Client'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::ASCENDING, + ), + ); + + self::$_columnHeaders = array_merge($pre, self::$_columnHeaders); + } + } + return self::$_columnHeaders; + } + + function alphabetQuery() { + return $this->_query->searchQuery(NULL, NULL, NULL, FALSE, FALSE, TRUE); + } + + function &getQuery() { + return $this->_query; + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('Case Search'); + } +} +//end of class + diff --git a/CRM/Case/StateMachine/Search.php b/CRM/Case/StateMachine/Search.php new file mode 100644 index 0000000000..87ca4cc4e3 --- /dev/null +++ b/CRM/Case/StateMachine/Search.php @@ -0,0 +1,118 @@ +_pages = array(); + + $this->_pages['CRM_Case_Form_Search'] = NULL; + list($task, $result) = $this->taskName($controller, 'Search'); + $this->_task = $task; + + if (is_array($task)) { + foreach ($task as $t) { + $this->_pages[$t] = NULL; + } + } + else { + $this->_pages[$task] = NULL; + } + + if ($result) { + $this->_pages['CRM_Case_Form_Task_Result'] = NULL; + } + + $this->addSequentialPages($this->_pages, $action); + } + + /** + * Determine the form name based on the action. This allows us + * to avoid using conditional state machine, much more efficient + * and simpler + * + * @param CRM_Core_Controller $controller the controller object + * + * @return string the name of the form that will handle the task + * @access protected + */ + function taskName($controller, $formName = 'Search') { + // total hack, check POST vars and then session to determine stuff + // fix value if print button is pressed + if (CRM_Utils_Array::value('_qf_' . $formName . '_next_print', $_POST)) { + $value = CRM_Case_Task::PRINT_CASES; + } + else { + $value = CRM_Utils_Array::value('task', $_POST); + } + if (!isset($value)) { + $value = $this->_controller->get('task'); + } + $this->_controller->set('task', $value); + + return CRM_Case_Task::getTask($value); + } + + /** + * return the form name of the task + * + * @return string + * @access public + */ + function getTaskFormName() { + return CRM_Utils_String::getClassName($this->_task); + } + + /** + * Since this is a state machine for search and we want to come back to the same state + * we dont want to issue a reset of the state session when we are done processing a task + * + */ + function shouldReset() { + return FALSE; + } +} + diff --git a/CRM/Case/Task.php b/CRM/Case/Task.php new file mode 100644 index 0000000000..7948e8719f --- /dev/null +++ b/CRM/Case/Task.php @@ -0,0 +1,184 @@ + array('title' => ts('Delete Cases'), + 'class' => 'CRM_Case_Form_Task_Delete', + 'result' => FALSE, + ), + 2 => array('title' => ts('Print Cases'), + 'class' => 'CRM_Case_Form_Task_Print', + 'result' => FALSE, + ), + 3 => array('title' => ts('Export Cases'), + 'class' => array( + 'CRM_Export_Form_Select', + 'CRM_Export_Form_Map', + ), + 'result' => FALSE, + ), + 4 => array('title' => ts('Restore Cases'), + 'class' => 'CRM_Case_Form_Task_Restore', + 'result' => FALSE, + ), + ); + //CRM-4418, check for delete + if (!CRM_Core_Permission::check('delete in CiviCase')) { + unset(self::$_tasks[1]); + } + } + + CRM_Utils_Hook::searchTasks('case', self::$_tasks); + asort(self::$_tasks); + return self::$_tasks; + } + + /** + * These tasks are the core set of task titles + * + * @return array the set of task titles + * @static + * @access public + */ + static function &taskTitles() { + self::tasks(); + $titles = array(); + foreach (self::$_tasks as $id => $value) { + // skip Print Cases task + if ($id != 2) { + $titles[$id] = $value['title']; + } + } + return $titles; + } + + /** + * These tasks get added based on the context the user is in + * + * @return array the set of optional tasks for a group of contacts + * @static + * @access public + */ + static function &optionalTaskTitle() { + $tasks = array(); + return $tasks; + } + + /** + * show tasks selectively based on the permission level + * of the user + * + * @param int $permission + * + * @return array set of tasks that are valid for the user + * @access public + */ + static function &permissionedTaskTitles($permission) { + $tasks = array(); + if (($permission == CRM_Core_Permission::EDIT) + || CRM_Core_Permission::check('access all cases and activities') + || CRM_Core_Permission::check('access my cases and activities') + ) { + $tasks = self::taskTitles(); + } + else { + $tasks = array( + 3 => self::$_tasks[3]['title'], + ); + //CRM-4418, + if (CRM_Core_Permission::check('delete in CiviCase')) { + $tasks[1] = self::$_tasks[1]['title']; + } + } + return $tasks; + } + + /** + * These tasks are the core set of tasks + * + * @param int $value + * + * @return array the set of tasks for a group of contacts + * @static + * @access public + */ + static function getTask($value) { + self::tasks(); + if (!$value || !CRM_Utils_Array::value($value, self::$_tasks)) { + // make the print task by default + $value = 2; + } + + return array( + self::$_tasks[$value]['class'], + self::$_tasks[$value]['result'], + ); + } +} + diff --git a/CRM/Case/XMLProcessor.php b/CRM/Case/XMLProcessor.php new file mode 100644 index 0000000000..eefa3fd962 --- /dev/null +++ b/CRM/Case/XMLProcessor.php @@ -0,0 +1,127 @@ +customTemplateDir) && + $config->customTemplateDir + ) { + // check if the file exists in the custom templates directory + $fileName = implode(DIRECTORY_SEPARATOR, + array( + $config->customTemplateDir, + 'CRM', + 'Case', + 'xml', + 'configuration', + "$caseType.xml", + ) + ); + } + + if (!$fileName || + !file_exists($fileName) + ) { + // check if file exists locally + $fileName = implode(DIRECTORY_SEPARATOR, + array(dirname(__FILE__), + 'xml', + 'configuration', + "$caseType.xml", + ) + ); + + if (!file_exists($fileName)) { + // check if file exists locally + $fileName = implode(DIRECTORY_SEPARATOR, + array(dirname(__FILE__), + 'xml', + 'configuration.sample', + "$caseType.xml", + ) + ); + } + if (!file_exists($fileName)) { + return FALSE; + } + } + + // read xml file + $dom = new DomDocument(); + $dom->load($fileName); + $dom->xinclude(); + self::$_xml[$caseType] = simplexml_import_dom($dom); + } + return self::$_xml[$caseType]; + } + + function &allActivityTypes($indexName = TRUE, $all = FALSE) { + static $activityTypes = NULL; + if (!$activityTypes) { + $activityTypes = CRM_Case_PseudoConstant::caseActivityType($indexName, $all); + } + return $activityTypes; + } + + function &allRelationshipTypes() { + static $relationshipTypes = array(); + + if (!$relationshipTypes) { + $relationshipInfo = CRM_Core_PseudoConstant::relationshipType(); + + $relationshipTypes = array(); + foreach ($relationshipInfo as $id => $info) { + $relationshipTypes[$id] = $info['label_b_a']; + } + } + + return $relationshipTypes; + } +} + diff --git a/CRM/Case/XMLProcessor/Process.php b/CRM/Case/XMLProcessor/Process.php new file mode 100644 index 0000000000..1418b8156e --- /dev/null +++ b/CRM/Case/XMLProcessor/Process.php @@ -0,0 +1,510 @@ +retrieve($caseType); + + if ($xml === FALSE) { + $docLink = CRM_Utils_System::docURL2("user/case-management/setup"); + CRM_Core_Error::fatal(ts("Configuration file could not be retrieved for case type = '%1' %2.", + array(1 => $caseType, 2 => $docLink) + )); + return FALSE; + } + + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); + $this->_isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); + + $this->process($xml, $params); + } + + function get($caseType, $fieldSet, $isLabel = FALSE, $maskAction = FALSE) { + $xml = $this->retrieve($caseType); + if ($xml === FALSE) { + $docLink = CRM_Utils_System::docURL2("user/case-management/setup"); + CRM_Core_Error::fatal(ts("Unable to load configuration file for the referenced case type: '%1' %2.", + array(1 => $caseType, 2 => $docLink) + )); + return FALSE; + } + + switch ($fieldSet) { + case 'CaseRoles': + return $this->caseRoles($xml->CaseRoles); + + case 'ActivitySets': + return $this->activitySets($xml->ActivitySets); + + case 'ActivityTypes': + return $this->activityTypes($xml->ActivityTypes, FALSE, $isLabel, $maskAction); + } + } + + function process($xml, &$params) { + $standardTimeline = CRM_Utils_Array::value('standardTimeline', $params); + $activitySetName = CRM_Utils_Array::value('activitySetName', $params); + $activityTypeName = CRM_Utils_Array::value('activityTypeName', $params); + + if ('Open Case' == CRM_Utils_Array::value('activityTypeName', $params)) { + // create relationships for the ones that are required + foreach ($xml->CaseRoles as $caseRoleXML) { + foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) { + if ((int ) $relationshipTypeXML->creator == 1) { + if (!$this->createRelationships((string ) $relationshipTypeXML->name, + $params + )) { + CRM_Core_Error::fatal(); + return FALSE; + } + } + } + } + } + + if ('Change Case Start Date' == CRM_Utils_Array::value('activityTypeName', $params)) { + // delete all existing activities which are non-empty + $this->deleteEmptyActivity($params); + } + + foreach ($xml->ActivitySets as $activitySetsXML) { + foreach ($activitySetsXML->ActivitySet as $activitySetXML) { + if ($standardTimeline) { + if ((boolean ) $activitySetXML->timeline) { + return $this->processStandardTimeline($activitySetXML, + $params + ); + } + } + elseif ($activitySetName) { + $name = (string ) $activitySetXML->name; + if ($name == $activitySetName) { + return $this->processActivitySet($activitySetXML, + $params + ); + } + } + } + } + } + + function processStandardTimeline($activitySetXML, &$params) { + if ('Change Case Type' == CRM_Utils_Array::value('activityTypeName', $params)) { + // delete all existing activities which are non-empty + $this->deleteEmptyActivity($params); + } + + foreach ($activitySetXML->ActivityTypes as $activityTypesXML) { + foreach ($activityTypesXML as $activityTypeXML) { + $this->createActivity($activityTypeXML, $params); + } + } + } + + function processActivitySet($activitySetXML, &$params) { + foreach ($activitySetXML->ActivityTypes as $activityTypesXML) { + foreach ($activityTypesXML as $activityTypeXML) { + $this->createActivity($activityTypeXML, $params); + } + } + } + + function &caseRoles($caseRolesXML, $isCaseManager = FALSE) { + $relationshipTypes = &$this->allRelationshipTypes(); + + $result = array(); + foreach ($caseRolesXML as $caseRoleXML) { + foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) { + $relationshipTypeName = (string ) $relationshipTypeXML->name; + $relationshipTypeID = array_search($relationshipTypeName, + $relationshipTypes + ); + if ($relationshipTypeID === FALSE) { + continue; + } + + if (!$isCaseManager) { + $result[$relationshipTypeID] = $relationshipTypeName; + } + elseif ($relationshipTypeXML->manager) { + return $relationshipTypeID; + } + } + } + return $result; + } + + function createRelationships($relationshipTypeName, &$params) { + $relationshipTypes = &$this->allRelationshipTypes(); + // get the relationship id + $relationshipTypeID = array_search($relationshipTypeName, $relationshipTypes); + + if ($relationshipTypeID === FALSE) { + $docLink = CRM_Utils_System::docURL2("user/case-management/setup"); + CRM_Core_Error::fatal(ts('Relationship type %1, found in case configuration file, is not present in the database %2', + array(1 => $relationshipTypeName, 2 => $docLink) + )); + return FALSE; + } + + $client = $params['clientID']; + if (!is_array($client)) { + $client = array($client); + } + + foreach ($client as $key => $clientId) { + $relationshipParams = array( + 'relationship_type_id' => $relationshipTypeID, + 'contact_id_a' => $clientId, + 'contact_id_b' => $params['creatorID'], + 'is_active' => 1, + 'case_id' => $params['caseID'], + 'start_date' => date("Ymd"), + ); + + if (!$this->createRelationship($relationshipParams)) { + CRM_Core_Error::fatal(); + return FALSE; + } + } + return TRUE; + } + + function createRelationship(&$params) { + $dao = new CRM_Contact_DAO_Relationship(); + $dao->copyValues($params); + // only create a relationship if it does not exist + if (!$dao->find(TRUE)) { + $dao->save(); + } + return TRUE; + } + + function activityTypes($activityTypesXML, $maxInst = FALSE, $isLabel = FALSE, $maskAction = FALSE) { + $activityTypes = &$this->allActivityTypes(TRUE, TRUE); + $result = array(); + foreach ($activityTypesXML as $activityTypeXML) { + foreach ($activityTypeXML as $recordXML) { + $activityTypeName = (string ) $recordXML->name; + $maxInstances = (string ) $recordXML->max_instances; + $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $activityTypes); + + if ($activityTypeInfo['id']) { + if ($maskAction) { + if ($maskAction == 'edit' && '0' === (string ) $recordXML->editable) { + $result[$maskAction][] = $activityTypeInfo['id']; + } + } + else { + if (!$maxInst) { + //if we want,labels of activities should be returned. + if ($isLabel) { + $result[$activityTypeInfo['id']] = $activityTypeInfo['label']; + } + else { + $result[$activityTypeInfo['id']] = $activityTypeName; + } + } + else { + if ($maxInstances) { + $result[$activityTypeName] = $maxInstances; + } + } + } + } + } + } + + // call option value hook + CRM_Utils_Hook::optionValues($result, 'case_activity_type'); + + return $result; + } + + function deleteEmptyActivity(&$params) { + $query = " +DELETE a +FROM civicrm_activity a +INNER JOIN civicrm_activity_target t ON t.activity_id = a.id +WHERE t.target_contact_id = %1 +AND a.is_auto = 1 +AND a.is_current_revision = 1 +"; + $sqlParams = array(1 => array($params['clientID'], 'Integer')); + CRM_Core_DAO::executeQuery($query, $sqlParams); + } + + function isActivityPresent(&$params) { + $query = " +SELECT count(a.id) +FROM civicrm_activity a +INNER JOIN civicrm_case_activity ca on ca.activity_id = a.id +WHERE a.activity_type_id = %1 +AND ca.case_id = %2 +AND a.is_deleted = 0 +"; + + $sqlParams = array(1 => array($params['activityTypeID'], 'Integer'), + 2 => array($params['caseID'], 'Integer'), + ); + $count = CRM_Core_DAO::singleValueQuery($query, $sqlParams); + + // check for max instance + $caseType = CRM_Case_BAO_Case::getCaseType($params['caseID'], 'name'); + $maxInstance = self::getMaxInstance($caseType, $params['activityTypeName']); + + return $maxInstance ? ($count < $maxInstance ? FALSE : TRUE) : FALSE; + } + + function createActivity($activityTypeXML, &$params) { + $activityTypeName = (string) $activityTypeXML->name; + $activityTypes = &$this->allActivityTypes(TRUE, TRUE); + $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $activityTypes); + + if (!$activityTypeInfo) { + $docLink = CRM_Utils_System::docURL2("user/case-management/setup"); + CRM_Core_Error::fatal(ts('Activity type %1, found in case configuration file, is not present in the database %2', + array(1 => $activityTypeName, 2 => $docLink) + )); + return FALSE; + } + + $activityTypeID = $activityTypeInfo['id']; + + if (isset($activityTypeXML->status)) { + $statusName = (string) $activityTypeXML->status; + } + else { + $statusName = 'Scheduled'; + } + + if ($this->_isMultiClient) { + $client = $params['clientID']; + } + else { + $client = array(1 => $params['clientID']); + } + + //set order + $orderVal = ''; + if (isset($activityTypeXML->order)) { + $orderVal = (string) $activityTypeXML->order; + } + + if ($activityTypeName == 'Open Case') { + $activityParams = array( + 'activity_type_id' => $activityTypeID, + 'source_contact_id' => $params['creatorID'], + 'is_auto' => FALSE, + 'is_current_revision' => 1, + 'subject' => CRM_Utils_Array::value('subject', $params) ? $params['subject'] : $activityTypeName, + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + $statusName, + 'name' + ), + 'target_contact_id' => $client, + 'medium_id' => CRM_Utils_Array::value('medium_id', $params), + 'location' => CRM_Utils_Array::value('location', $params), + 'details' => CRM_Utils_Array::value('details', $params), + 'duration' => CRM_Utils_Array::value('duration', $params), + 'weight' => $orderVal, + ); + } + else { + $activityParams = array( + 'activity_type_id' => $activityTypeID, + 'source_contact_id' => $params['creatorID'], + 'is_auto' => TRUE, + 'is_current_revision' => 1, + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + $statusName, + 'name' + ), + 'target_contact_id' => $client, + 'weight' => $orderVal, + ); + } + + //parsing date to default preference format + $params['activity_date_time'] = CRM_Utils_Date::processDate($params['activity_date_time']); + + if ($activityTypeName == 'Open Case') { + // we don't set activity_date_time for auto generated + // activities, but we want it to be set for open case. + $activityParams['activity_date_time'] = $params['activity_date_time']; + if (array_key_exists('custom', $params) && is_array($params['custom'])) { + $activityParams['custom'] = $params['custom']; + } + + // Add parameters for attachments + + $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + for ( $i = 1; $i <= $numAttachments; $i++ ) { + $attachName = "attachFile_$i"; + if ( isset( $params[$attachName] ) && !empty( $params[$attachName] ) ) { + $activityParams[$attachName] = $params[$attachName]; + } + } + } + else { + $activityDate = NULL; + //get date of reference activity if set. + if ($referenceActivityName = (string) $activityTypeXML->reference_activity) { + + //we skip open case as reference activity.CRM-4374. + if (CRM_Utils_Array::value('resetTimeline', $params) && $referenceActivityName == 'Open Case') { + $activityDate = $params['activity_date_time']; + } + else { + $referenceActivityInfo = CRM_Utils_Array::value($referenceActivityName, $activityTypes); + if ($referenceActivityInfo['id']) { + $caseActivityParams = array('activity_type_id' => $referenceActivityInfo['id']); + + //if reference_select is set take according activity. + if ($referenceSelect = (string) $activityTypeXML->reference_select) { + $caseActivityParams[$referenceSelect] = 1; + } + + $referenceActivity = CRM_Case_BAO_Case::getCaseActivityDates($params['caseID'], $caseActivityParams, TRUE); + + if (is_array($referenceActivity)) { + foreach ($referenceActivity as $aId => $details) { + $activityDate = CRM_Utils_Array::value('activity_date', $details); + break; + } + } + } + } + } + if (!$activityDate) { + $activityDate = $params['activity_date_time']; + } + list($activity_date, $activity_time) = CRM_Utils_Date::setDateDefaults($activityDate); + $activityDateTime = CRM_Utils_Date::processDate($activity_date, $activity_time); + //add reference offset to date. + if ((int) $activityTypeXML->reference_offset) { + $activityDateTime = CRM_Utils_Date::intervalAdd('day', (int) $activityTypeXML->reference_offset, + $activityDateTime + ); + } + + $activityParams['activity_date_time'] = CRM_Utils_Date::format($activityDateTime); + } + + // if same activity is already there, skip and dont touch + $params['activityTypeID'] = $activityTypeID; + $params['activityTypeName'] = $activityTypeName; + if ($this->isActivityPresent($params)) { + return TRUE; + } + $activityParams['case_id'] = $params['caseID']; + if (CRM_Utils_Array::value('is_auto', $activityParams)) { + $activityParams['skipRecentView'] = TRUE; + } + + $activity = CRM_Activity_BAO_Activity::create($activityParams); + + if (!$activity) { + CRM_Core_Error::fatal(); + return FALSE; + } + + // create case activity record + $caseParams = array( + 'activity_id' => $activity->id, + 'case_id' => $params['caseID'], + ); + CRM_Case_BAO_Case::processCaseActivity($caseParams); + return TRUE; + } + + function activitySets($activitySetsXML) { + $result = array(); + foreach ($activitySetsXML as $activitySetXML) { + foreach ($activitySetXML as $recordXML) { + $activitySetName = (string ) $recordXML->name; + $activitySetLabel = (string ) $recordXML->label; + $result[$activitySetName] = $activitySetLabel; + } + } + + return $result; + } + + function getMaxInstance($caseType, $activityTypeName = NULL) { + $xml = $this->retrieve($caseType); + + if ($xml === FALSE) { + CRM_Core_Error::fatal(); + return FALSE; + } + + $activityInstances = $this->activityTypes($xml->ActivityTypes, TRUE); + return $activityTypeName ? CRM_Utils_Array::value($activityTypeName, $activityInstances) : $activityInstances; + } + + function getCaseManagerRoleId($caseType) { + $xml = $this->retrieve($caseType); + return $this->caseRoles($xml->CaseRoles, TRUE); + } + + function getRedactActivityEmail() { + $xml = $this->retrieve("Settings"); + return ( string ) $xml->RedactActivityEmail ? 1 : 0; + } + + /** + * Retrieves AllowMultipleCaseClients setting + * + * @return string 1 if allowed, 0 if not + */ + function getAllowMultipleCaseClients() { + $xml = $this->retrieve("Settings"); + if ($xml) { + return ( string ) $xml->AllowMultipleCaseClients ? 1 : 0; + } + return 0; + } + + /** + * Retrieves NaturalActivityTypeSort setting + * + * @return string 1 if natural, 0 if alphabetic + */ + function getNaturalActivityTypeSort() { + $xml = $this->retrieve("Settings"); + return ( string ) $xml->NaturalActivityTypeSort ? 1 : 0; + } +} + diff --git a/CRM/Case/XMLProcessor/Report.php b/CRM/Case/XMLProcessor/Report.php new file mode 100644 index 0000000000..cb6a7f8109 --- /dev/null +++ b/CRM/Case/XMLProcessor/Report.php @@ -0,0 +1,908 @@ + $rule) { + $$rule = CRM_Case_PseudoConstant::redactionRule($key); + + if (!empty($$rule)) { + foreach ($$rule as & $val) { + //suffixed with a randomly generated 4-digit number + if ($key == 'redactionStringRules') { + $val .= rand(10000, 100000); + } + } + + if (!empty($this->{'_' . $rule})) { + $this->{'_' . $rule} = CRM_Utils_Array::crmArrayMerge($this->{'_' . $rule}, $$rule); + } + else { + $this->{'_' . $rule} = $$rule; + } + } + } + } + + function &caseInfo($clientID, + $caseID + ) { + $case = $this->_redactionRegexRules = array(); + + if (empty($this->_redactionStringRules)) { + $this->_redactionStringRules = array(); + } + + if ($this->_isRedact == 1) { + $this->getRedactionRules(); + } + + $client = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $clientID, 'display_name'); + + // add Client to the strings to be redacted across the case session + if (!array_key_exists($client, $this->_redactionStringRules)) { + $this->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($this->_redactionStringRules, + array($client => 'name_' . rand(10000, 100000)) + ); + $clientSortName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $clientID, 'sort_name'); + if (!array_key_exists($clientSortName, $this->_redactionStringRules)) { + $this->_redactionStringRules[$clientSortName] = $this->_redactionStringRules[$client]; + } + } + + $case['clientName'] = $this->redact($client); + + $dao = new CRM_Case_DAO_Case(); + $dao->id = $caseID; + if ($dao->find(TRUE)) { + $case['subject'] = $dao->subject; + $case['start_date'] = $dao->start_date; + $case['end_date'] = $dao->end_date; + // FIXME: when we resolve if case_type_is single or multi-select + if (strpos($dao->case_type_id, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) { + $caseTypeID = substr($dao->case_type_id, 1, -1); + } + else { + $caseTypeID = $dao->case_type_id; + } + $caseTypeIDs = explode(CRM_Core_DAO::VALUE_SEPARATOR, + $dao->case_type_id + ); + + $case['caseType'] = CRM_Case_BAO_Case::getCaseType($caseID); + $case['caseTypeName'] = CRM_Case_BAO_Case::getCaseType($caseID, 'name'); + $case['status'] = CRM_Core_OptionGroup::getLabel('case_status', $dao->status_id, FALSE); + } + return $case; + } + + function getActivityTypes($xml, $activitySetName) { + foreach ($xml->ActivitySets as $activitySetsXML) { + foreach ($activitySetsXML->ActivitySet as $activitySetXML) { + if ((string ) $activitySetXML->name == $activitySetName) { + $activityTypes = array(); + $allActivityTypes = &$this->allActivityTypes(); + foreach ($activitySetXML->ActivityTypes as $activityTypesXML) { + foreach ($activityTypesXML as $activityTypeXML) { + $activityTypeName = (string ) $activityTypeXML->name; + $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $allActivityTypes); + if ($activityTypeInfo) { + $activityTypes[$activityTypeInfo['id']] = $activityTypeInfo; + } + } + } + return empty($activityTypes) ? FALSE : $activityTypes; + } + } + } + return FALSE; + } + + function getActivitySetLabel($xml, $activitySetName) { + foreach ($xml->ActivitySets as $activitySetsXML) { + foreach ($activitySetsXML->ActivitySet as $activitySetXML) { + if ((string ) $activitySetXML->name == $activitySetName) { + return (string ) $activitySetXML->label; + } + } + } + return NULL; + } + + function getActivities($clientID, + $caseID, + $activityTypes, + &$activities + ) { + // get all activities for this case that in this activityTypes set + foreach ($activityTypes as $aType) { + $map[$aType['id']] = $aType; + } + + // get all core activities + $coreActivityTypes = CRM_Case_PseudoConstant::caseActivityType(FALSE, TRUE); + + foreach ($coreActivityTypes as $aType) { + $map[$aType['id']] = $aType; + } + + $activityTypeIDs = implode(',', array_keys($map)); + $query = " +SELECT a.*, c.id as caseID +FROM civicrm_activity a, + civicrm_case c, + civicrm_case_activity ac +WHERE a.is_current_revision = 1 +AND a.is_deleted =0 +AND a.activity_type_id IN ( $activityTypeIDs ) +AND c.id = ac.case_id +AND a.id = ac.activity_id +AND ac.case_id = %1 +"; + + $params = array(1 => array($caseID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + while ($dao->fetch()) { + $activityTypeInfo = $map[$dao->activity_type_id]; + $activities[] = $this->getActivity($clientID, + $dao, + $activityTypeInfo + ); + } + } + + function &getActivityInfo($clientID, $activityID, $anyActivity = FALSE, $redact = 0) { + static $activityInfos = array(); + if ($redact) { + $this->_isRedact = 1; + $this->getRedactionRules(); + } + + + $index = $activityID . '_' . (int) $anyActivity; + + if ($clientID) { + $index = $index . '_' . $clientID; + } + + + if (!array_key_exists($index, $activityInfos)) { + $activityInfos[$index] = array(); + $selectCaseActivity = ""; + $joinCaseActivity = ""; + + if ($clientID) { + $selectCaseActivity = ", ca.case_id as caseID "; + $joinCaseActivity = " INNER JOIN civicrm_case_activity ca ON a.id = ca.activity_id "; + } + + $query = " +SELECT a.*, aa.assignee_contact_id as assigneeID, at.target_contact_id as targetID +{$selectCaseActivity} +FROM civicrm_activity a +{$joinCaseActivity} +LEFT JOIN civicrm_activity_target at ON a.id = at.activity_id +LEFT JOIN civicrm_activity_assignment aa ON a.id = aa.activity_id +WHERE a.id = %1 + "; + $params = array(1 => array($activityID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + if ($dao->fetch()) { + //if activity type is email get info of all activities. + if ($dao->activity_type_id == CRM_Core_OptionGroup::getValue('activity_type', 'Email', 'name')) { + $anyActivity = TRUE; + } + $activityTypes = $this->allActivityTypes(FALSE, $anyActivity); + $activityTypeInfo = NULL; + + if (isset($activityTypes[$dao->activity_type_id])) { + $activityTypeInfo = $activityTypes[$dao->activity_type_id]; + } + if ($activityTypeInfo) { + $activityInfos[$index] = $this->getActivity($clientID, $dao, $activityTypeInfo); + } + } + } + + return $activityInfos[$index]; + } + + function &getActivity($clientID, + $activityDAO, + &$activityTypeInfo + ) { + + if (empty($this->_redactionStringRules)) { + $this->_redactionStringRules = array(); + } + + $activity = array(); + $activity['fields'] = array(); + if ($clientID) { + $clientID = CRM_Utils_Type::escape($clientID, 'Integer'); + if (!in_array($activityTypeInfo['name'], array( + 'Email', 'Inbound Email'))) { + $activity['editURL'] = CRM_Utils_System::url('civicrm/case/activity', + "reset=1&cid={$clientID}&caseid={$activityDAO->caseID}&action=update&atype={$activityDAO->activity_type_id}&id={$activityDAO->id}" + ); + } + else { + $activity['editURL'] = ''; + } + + $client = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $clientID, 'display_name'); + // add Client SortName as well as Display to the strings to be redacted across the case session + // suffixed with a randomly generated 4-digit number + if (!array_key_exists($client, $this->_redactionStringRules)) { + $this->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($this->_redactionStringRules, + array($client => 'name_' . rand(10000, 100000)) + ); + + $clientSortName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $clientID, 'sort_name'); + if (!array_key_exists($clientSortName, $this->_redactionStringRules)) { + $this->_redactionStringRules[$clientSortName] = $this->_redactionStringRules[$client]; + } + } + + $activity['fields'][] = array( + 'label' => 'Client', + 'value' => $this->redact($client), + 'type' => 'String', + ); + } + + if (!empty($activityDAO->targetID)) { + // Re-lookup the target ID since the DAO only has the first recipient if there are multiple. + // Maybe not the best solution. + $targetNames = CRM_Activity_BAO_ActivityTarget::getTargetNames($activityDAO->id); + $processTarget = FALSE; + $label = ts('With Contact(s)'); + if (in_array($activityTypeInfo['name'], array( + 'Email', 'Inbound Email'))) { + $processTarget = TRUE; + $label = ts('Recipient'); + } + if (!$processTarget) { + foreach ($targetNames as $targetID => $targetName) { + if ($targetID != $clientID) { + $processTarget = TRUE; + break; + } + } + } + + if ($processTarget) { + $targetRedacted = array(); + foreach ($targetNames as $targetID => $target) { + // add Recipient SortName as well as Display to the strings to be redacted across the case session + // suffixed with a randomly generated 4-digit number + if (!array_key_exists($target, $this->_redactionStringRules)) { + $this->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($this->_redactionStringRules, + array($target => 'name_' . rand(10000, 100000)) + ); + $targetSortName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $targetID, 'sort_name'); + if (!array_key_exists($targetSortName, $this->_redactionStringRules)) { + $this->_redactionStringRules[$targetSortName] = $this->_redactionStringRules[$target]; + } + } + $targetRedacted[] = $this->redact($target); + } + + $activity['fields'][] = array( + 'label' => $label, + 'value' => implode('; ', $targetRedacted), + 'type' => 'String', + ); + } + } + + // Activity Type info is a special field + $activity['fields'][] = array( + 'label' => 'Activity Type', + 'value' => $activityTypeInfo['label'], + 'type' => 'String', + ); + + $activity['fields'][] = array( + 'label' => 'Subject', + 'value' => htmlspecialchars($this->redact($activityDAO->subject)), + 'type' => 'Memo', + ); + + $creator = $this->getCreatedBy($activityDAO->id); + // add Creator to the strings to be redacted across the case session + if (!array_key_exists($creator, $this->_redactionStringRules)) { + $this->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($this->_redactionStringRules, + array($creator => 'name_' . rand(10000, 100000)) + ); + } + $activity['fields'][] = array( + 'label' => 'Created By', + 'value' => $this->redact($creator), + 'type' => 'String', + ); + + $reporter = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $activityDAO->source_contact_id, + 'display_name' + ); + + // add Reporter SortName as well as Display to the strings to be redacted across the case session + // suffixed with a randomly generated 4-digit number + if (!array_key_exists($reporter, $this->_redactionStringRules)) { + $this->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($this->_redactionStringRules, + array($reporter => 'name_' . rand(10000, 100000)) + ); + + $reporterSortName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $activityDAO->source_contact_id, + 'sort_name' + ); + if (!array_key_exists($reporterSortName, $this->_redactionStringRules)) { + $this->_redactionStringRules[$reporterSortName] = $this->_redactionStringRules[$reporter]; + } + } + + $activity['fields'][] = array( + 'label' => 'Reported By', + 'value' => $this->redact($reporter), + 'type' => 'String', + ); + + if (!empty($activityDAO->assigneeID)) { + //allow multiple assignee contacts.CRM-4503. + $assignee_contact_names = CRM_Activity_BAO_ActivityAssignment::getAssigneeNames($activityDAO->id, TRUE); + + foreach ($assignee_contact_names as & $assignee) { + // add Assignee to the strings to be redacted across the case session + $this->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($this->_redactionStringRules, + array($assignee => 'name_' . rand(10000, 100000)) + ); + $assignee = $this->redact($assignee); + } + $assigneeContacts = implode(', ', $assignee_contact_names); + $activity['fields'][] = array( + 'label' => 'Assigned To', + 'value' => $assigneeContacts, + 'type' => 'String', + ); + } + + if ($activityDAO->medium_id) { + $activity['fields'][] = array( + 'label' => 'Medium', + 'value' => CRM_Core_OptionGroup::getLabel('encounter_medium', + $activityDAO->medium_id, FALSE + ), + 'type' => 'String', + ); + } + + $activity['fields'][] = array( + 'label' => 'Location', + 'value' => $activityDAO->location, + 'type' => 'String', + ); + + $activity['fields'][] = array( + 'label' => 'Date and Time', + 'value' => $activityDAO->activity_date_time, + 'type' => 'Date', + ); + + $activity['fields'][] = array( + 'label' => 'Details', + 'value' => $this->redact(CRM_Utils_String::stripAlternatives($activityDAO->details)), + 'type' => 'Memo', + ); + + // Skip Duration field if empty (to avoid " minutes" output). Might want to do this for all fields at some point. dgg + if ($activityDAO->duration) { + $activity['fields'][] = array( + 'label' => 'Duration', + 'value' => $activityDAO->duration . ' ' . ts('minutes'), + 'type' => 'Int', + ); + } + $activity['fields'][] = array( + 'label' => 'Status', + 'value' => CRM_Core_OptionGroup::getLabel('activity_status', + $activityDAO->status_id + ), + 'type' => 'String', + ); + + $activity['fields'][] = array( + 'label' => 'Priority', + 'value' => CRM_Core_OptionGroup::getLabel('priority', + $activityDAO->priority_id + ), + 'type' => 'String', + ); + + //for now empty custom groups + $activity['customGroups'] = $this->getCustomData($clientID, + $activityDAO, + $activityTypeInfo + ); + + return $activity; + } + + function getCustomData($clientID, + $activityDAO, + &$activityTypeInfo + ) { + list($typeValues, $options, $sql) = $this->getActivityTypeCustomSQL($activityTypeInfo['id'], '%Y-%m-%d'); + + $params = array(1 => array($activityDAO->id, 'Integer')); + + $customGroups = array(); + foreach ($sql as $tableName => $sqlClause) { + $dao = CRM_Core_DAO::executeQuery($sqlClause, $params); + if ($dao->fetch()) { + $customGroup = array(); + foreach ($typeValues[$tableName] as $columnName => $typeValue) { + $value = CRM_Core_BAO_CustomField::getDisplayValue($dao->$columnName, + $typeValue['fieldID'], + $options + ); + + if (CRM_Utils_Array::value('type', $typeValue) == 'Date') { + $value = $dao->$columnName; + } + + if ($value) { + // Note: this is already taken care in getDisplayValue above, but sometimes + // strings like '^A^A' creates problem. So to fix this special case - + if (strstr($value, CRM_Core_DAO::VALUE_SEPARATOR)) { + $value = trim($value, CRM_Core_DAO::VALUE_SEPARATOR); + } + if (CRM_Utils_Array::value('type', $typeValue) == 'String' || + CRM_Utils_Array::value('type', $typeValue) == 'Memo' + ) { + $value = $this->redact($value); + } + elseif (CRM_Utils_Array::value('type', $typeValue) == 'File') { + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', $typeValue, 'entity_table'); + $value = CRM_Core_BAO_File::attachmentInfo($tableName, $activityDAO->id); + } + elseif (CRM_Utils_Array::value('type', $typeValue) == 'Link') { + $value = CRM_Utils_System::formatWikiURL($value); + } + } + //$typeValue + $customGroup[] = array( + 'label' => $typeValue['label'], + 'value' => $value, + 'type' => $typeValue['type'], + ); + } + $customGroups[$dao->groupTitle] = $customGroup; + } + } + + return empty($customGroups) ? NULL : $customGroups; + } + + function getActivityTypeCustomSQL($activityTypeID, $dateFormat = NULL) { + static $cache = array(); + + if (is_null($activityTypeID)) { + $activityTypeID = 0; + } + + if (!isset($cache[$activityTypeID])) { + $query = " +SELECT cg.title as groupTitle, + cg.table_name as tableName , + cf.column_name as columnName, + cf.label as label , + cg.id as groupID , + cf.id as fieldID , + cf.data_type as dataType , + cf.html_type as htmlType , + cf.option_group_id as optionGroupID +FROM civicrm_custom_group cg, + civicrm_custom_field cf +WHERE cf.custom_group_id = cg.id +AND cg.extends = 'Activity'"; + + if ($activityTypeID) { + $query .= "AND ( cg.extends_entity_column_value IS NULL OR cg.extends_entity_column_value LIKE '%" . CRM_Core_DAO::VALUE_SEPARATOR . "%1" . CRM_Core_DAO::VALUE_SEPARATOR . "%' )"; + } + else { + $query .= "AND cg.extends_entity_column_value IS NULL"; + } + $query .= "ORDER BY cf.weight"; + $params = array( + 1 => array($activityTypeID, + 'Integer', + )); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $result = $options = $sql = $groupTitle = array(); + while ($dao->fetch()) { + if (!array_key_exists($dao->tableName, $result)) { + $result[$dao->tableName] = array(); + $sql[$dao->tableName] = array(); + } + $result[$dao->tableName][$dao->columnName] = array( + 'label' => $dao->label, + 'type' => $dao->dataType, + 'fieldID' => $dao->fieldID, + ); + + $options[$dao->fieldID] = array(); + $options[$dao->fieldID]['attributes'] = array( + 'label' => $dao->label, + 'data_type' => $dao->dataType, + 'html_type' => $dao->htmlType, + ); + // since we want to add ISO date format. + if ($dateFormat && $dao->htmlType == 'Select Date') { + $options[$dao->fieldID]['attributes']['format'] = $dateFormat; + } + if ($dao->optionGroupID) { + $query = " +SELECT label, value + FROM civicrm_option_value + WHERE option_group_id = {$dao->optionGroupID} +"; + + $option = CRM_Core_DAO::executeQuery($query); + while ($option->fetch()) { + $dataType = $dao->dataType; + if ($dataType == 'Int' || $dataType == 'Float') { + $num = round($option->value, 2); + $options[$dao->fieldID]["$num"] = $option->label; + } + else { + $options[$dao->fieldID][$option->value] = $option->label; + } + } + } + + $sql[$dao->tableName][] = $dao->columnName; + $groupTitle[$dao->tableName] = $dao->groupTitle; + } + + foreach ($sql as $tableName => $values) { + $columnNames = implode(',', $values); + $sql[$tableName] = " +SELECT '{$groupTitle[$tableName]}' as groupTitle, $columnNames +FROM $tableName +WHERE entity_id = %1 +"; + } + + $cache[$activityTypeID] = array($result, $options, $sql); + } + return $cache[$activityTypeID]; + } + + function getCreatedBy($activityID) { + $query = " +SELECT c.display_name +FROM civicrm_contact c, + civicrm_log l +WHERE l.entity_table = 'civicrm_activity' +AND l.entity_id = %1 +AND l.modified_id = c.id +LIMIT 1 +"; + + $params = array(1 => array($activityID, 'Integer')); + return CRM_Core_DAO::singleValueQuery($query, $params); + } + + private function redact($string, $printReport = FALSE, $replaceString = array( + )) { + if ($printReport) { + return CRM_Utils_String::redaction($string, $replaceString); + } + elseif ($this->_isRedact) { + $regexToReplaceString = CRM_Utils_String::regex($string, $this->_redactionRegexRules); + return CRM_Utils_String::redaction($string, array_merge($this->_redactionStringRules, $regexToReplaceString)); + } + return $string; + } + + function getCaseReport($clientID, $caseID, $activitySetName, $params, $form) { + + $template = CRM_Core_Smarty::singleton(); + + $template->assign('caseId', $caseID); + $template->assign('clientID', $clientID); + $template->assign('activitySetName', $activitySetName); + + if (CRM_Utils_Array::value('is_redact', $params)) { + $form->_isRedact = TRUE; + $template->assign('_isRedact', 'true'); + } + else { + $form->_isRedact = FALSE; + $template->assign('_isRedact', 'false'); + } + + // first get all case information + $case = $form->caseInfo($clientID, $caseID); + $template->assign_by_ref('case', $case); + + if ($params['include_activities'] == 1) { + $template->assign('includeActivities', 'All'); + } + else { + $template->assign('includeActivities', 'Missing activities only'); + } + + $xml = $form->retrieve($case['caseTypeName']); + + $activitySetNames = CRM_Case_XMLProcessor_Process::activitySets($xml->ActivitySets); + $pageTitle = CRM_Utils_Array::value($activitySetName, $activitySetNames); + $template->assign('pageTitle', $pageTitle); + + if ($activitySetName) { + $activityTypes = $form->getActivityTypes($xml, $activitySetName); + } + else { + $activityTypes = CRM_Case_XMLProcessor::allActivityTypes(); + } + + if (!$activityTypes) { + return FALSE; + } + + // next get activity set Informtion + $activitySet = array('label' => $form->getActivitySetLabel($xml, $activitySetName), + 'includeActivities' => 'All', + 'redact' => 'false', + ); + $template->assign_by_ref('activitySet', $activitySet); + + //now collect all the information about activities + $activities = array(); + $form->getActivities($clientID, $caseID, $activityTypes, $activities); + $template->assign_by_ref('activities', $activities); + + // now run the template + $contents = $template->fetch('CRM/Case/XMLProcessor/Report.tpl'); + return $contents; + } + + function printCaseReport() { + $caseID = CRM_Utils_Request::retrieve('caseID', 'Positive', CRM_Core_DAO::$_nullObject); + $clientID = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject); + $activitySetName = CRM_Utils_Request::retrieve('asn', 'String', CRM_Core_DAO::$_nullObject); + $isRedact = CRM_Utils_Request::retrieve('redact', 'Boolean', CRM_Core_DAO::$_nullObject); + $includeActivities = CRM_Utils_Request::retrieve('all', 'Positive', CRM_Core_DAO::$_nullObject); + $params = $otherRelationships = $globalGroupInfo = array(); + $report = new CRM_Case_XMLProcessor_Report($isRedact); + if ($includeActivities) { + $params['include_activities'] = 1; + } + + if ($isRedact) { + $params['is_redact'] = 1; + $report->_redactionStringRules = array(); + } + $template = CRM_Core_Smarty::singleton(); + + //get case related relationships (Case Role) + $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($clientID, $caseID); + $caseType = CRM_Case_BAO_Case::getCaseType($caseID, 'name'); + + $xmlProcessor = new CRM_Case_XMLProcessor_Process(); + $caseRoles = $xmlProcessor->get($caseType, 'CaseRoles'); + foreach ($caseRelationships as $key => & $value) { + if (CRM_Utils_Array::value($value['relation_type'], $caseRoles)) { + unset($caseRoles[$value['relation_type']]); + } + if ($isRedact) { + if (!array_key_exists($value['name'], $report->_redactionStringRules)) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($value['name'] => 'name_' . rand(10000, 100000)) + ); + } + $value['name'] = self::redact($value['name'], TRUE, $report->_redactionStringRules); + if (CRM_Utils_Array::value('email', $value) && + !array_key_exists($value['email'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($value['email'] => 'email_' . rand(10000, 100000)) + ); + } + + $value['email'] = self::redact($value['email'], TRUE, $report->_redactionStringRules); + + if (CRM_Utils_Array::value('phone', $value) && + !array_key_exists($value['phone'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($value['phone'] => 'phone_' . rand(10000, 100000)) + ); + } + $value['phone'] = self::redact($value['phone'], TRUE, $report->_redactionStringRules); + } + } + + $caseRoles['client'] = CRM_Case_BAO_Case::getContactNames($caseID); + if ($isRedact) { + if (!array_key_exists($caseRoles['client']['sort_name'], $report->_redactionStringRules)) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($caseRoles['client']['sort_name'] => 'name_' . rand(10000, 100000)) + ); + } + if (!array_key_exists($caseRoles['client']['display_name'], $report->_redactionStringRules)) { + $report->_redactionStringRules[$caseRoles['client']['display_name']] = $report->_redactionStringRules[$caseRoles['client']['sort_name']]; + } + $caseRoles['client']['sort_name'] = self::redact($caseRoles['client']['sort_name'], TRUE, $report->_redactionStringRules); + if (CRM_Utils_Array::value('email', $caseRoles['client']) && + !array_key_exists($caseRoles['client']['email'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($caseRoles['client']['email'] => 'email_' . rand(10000, 100000)) + ); + } + $caseRoles['client']['email'] = self::redact($caseRoles['client']['email'], TRUE, $report->_redactionStringRules); + + if (CRM_Utils_Array::value('phone', $caseRoles['client']) && + !array_key_exists($caseRoles['client']['phone'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($caseRoles['client']['phone'] => 'phone_' . rand(10000, 100000)) + ); + } + $caseRoles['client']['phone'] = self::redact($caseRoles['client']['phone'], TRUE, $report->_redactionStringRules); + } + + // Retrieve ALL client relationships + $relClient = CRM_Contact_BAO_Relationship::getRelationship($clientID, + CRM_Contact_BAO_Relationship::CURRENT, + 0, 0, 0, NULL, NULL, FALSE + ); + foreach ($relClient as $r) { + if ($isRedact) { + if (!array_key_exists($r['name'], $report->_redactionStringRules)) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($r['name'] => 'name_' . rand(10000, 100000)) + ); + } + if (!array_key_exists($r['display_name'], $report->_redactionStringRules)) { + $report->_redactionStringRules[$r['display_name']] = $report->_redactionStringRules[$r['name']]; + } + $r['name'] = self::redact($r['name'], TRUE, $report->_redactionStringRules); + + if (CRM_Utils_Array::value('phone', $r) && + !array_key_exists($r['phone'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($r['phone'] => 'phone_' . rand(10000, 100000)) + ); + } + $r['phone'] = self::redact($r['phone'], TRUE, $report->_redactionStringRules); + + if (CRM_Utils_Array::value('email', $r) && + !array_key_exists($r['email'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($r['email'] => 'email_' . rand(10000, 100000)) + ); + } + $r['email'] = self::redact($r['email'], TRUE, $report->_redactionStringRules); + } + if (!array_key_exists($r['id'], $caseRelationships)) { + $otherRelationships[] = $r; + } + } + + // Now global contact list that appears on all cases. + $relGlobal = CRM_Case_BAO_Case::getGlobalContacts($globalGroupInfo); + foreach ($relGlobal as & $r) { + if ($isRedact) { + if (!array_key_exists($r['sort_name'], $report->_redactionStringRules)) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($r['sort_name'] => 'name_' . rand(10000, 100000)) + ); + } + if (!array_key_exists($r['display_name'], $report->_redactionStringRules)) { + $report->_redactionStringRules[$r['display_name']] = $report->_redactionStringRules[$r['sort_name']]; + } + + $r['sort_name'] = self::redact($r['sort_name'], TRUE, $report->_redactionStringRules); + + if (CRM_Utils_Array::value('phone', $r) && + !array_key_exists($r['phone'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($r['phone'] => 'phone_' . rand(10000, 100000)) + ); + } + $r['phone'] = self::redact($r['phone'], TRUE, $report->_redactionStringRules); + + if (CRM_Utils_Array::value('email', $r) && + !array_key_exists($r['email'], $report->_redactionStringRules) + ) { + $report->_redactionStringRules = CRM_Utils_Array::crmArrayMerge($report->_redactionStringRules, + array($r['email'] => 'email_' . rand(10000, 100000)) + ); + } + $r['email'] = self::redact($r['email'], TRUE, $report->_redactionStringRules); + } + } + + $template->assign('caseRelationships', $caseRelationships); + $template->assign('caseRoles', $caseRoles); + $template->assign('otherRelationships', $otherRelationships); + $template->assign('globalRelationships', $relGlobal); + $template->assign('globalGroupInfo', $globalGroupInfo); + $contents = self::getCaseReport($clientID, + $caseID, + $activitySetName, + $params, + $report + ); + $printReport = CRM_Case_Audit_Audit::run($contents, $clientID, $caseID, TRUE); + echo $printReport; + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Case/XMLProcessor/Settings.php b/CRM/Case/XMLProcessor/Settings.php new file mode 100644 index 0000000000..373f9cd553 --- /dev/null +++ b/CRM/Case/XMLProcessor/Settings.php @@ -0,0 +1,59 @@ +retrieve($filename); + + // For now it's not an error. In the future it might be a required file. + if ($xml !== FALSE) { + // There's only one setting right now, and only one value. + if ($xml->group[0]) { + if ($xml->group[0]->attributes()) { + $groupName = (string) $xml->group[0]->attributes()->name; + if ($groupName) { + $this->_settings['groupname'] = $groupName; + } + } + } + } + return $this->_settings; + } +} + diff --git a/CRM/Case/xml/HRD/CivilAndPolitical.xml b/CRM/Case/xml/HRD/CivilAndPolitical.xml new file mode 100644 index 0000000000..618432980d --- /dev/null +++ b/CRM/Case/xml/HRD/CivilAndPolitical.xml @@ -0,0 +1,84 @@ + + + + Civil and Political + + + Open Case + 1 + + + Change Case Type + + + Change Case Status + + + Follow up + + + Source(incoming) + + + Incoming correspondence + + + Incoming Press Release + + + Complaint + + + Urgent Action(incoming) + + + Outgoing correspondence + + + Outgoing Press Release + + + FL Action(outgoing) + + + FL Urgent Action(outgoing) + + + Lobbying(outgoing) + + + + + standard_timeline + + true + + + Open Case + Closed + + + Source(incoming) + Open Case + 2 + newest + + + Follow up + Open Case + 14 + newest + + + + + + + Case Coordinator + 1 + + + Supervisor + + + diff --git a/CRM/Case/xml/HRD/EconomicSocialCultural.xml b/CRM/Case/xml/HRD/EconomicSocialCultural.xml new file mode 100644 index 0000000000..64815121bf --- /dev/null +++ b/CRM/Case/xml/HRD/EconomicSocialCultural.xml @@ -0,0 +1,84 @@ + + + + Economic, Social and Cultural + + + Open Case + 1 + + + Change Case Type + + + Change Case Status + + + Follow up + + + Source(incoming) + + + Incoming correspondence + + + Incoming Press Release + + + Complaint + + + Urgent Action(incoming) + + + Outgoing correspondence + + + Outgoing Press Release + + + FL Action(outgoing) + + + FL Urgent Action(outgoing) + + + Lobbying(outgoing) + + + + + standard_timeline + + true + + + Open Case + Closed + + + Source(incoming) + Open Case + 2 + newest + + + Follow up + Open Case + 14 + newest + + + + + + + Case Coordinator + 1 + + + Supervisor + + + diff --git a/CRM/Case/xml/HRD/GenderIssues.xml b/CRM/Case/xml/HRD/GenderIssues.xml new file mode 100644 index 0000000000..705c00cc73 --- /dev/null +++ b/CRM/Case/xml/HRD/GenderIssues.xml @@ -0,0 +1,84 @@ + + + + Gender Issues + + + Open Case + 1 + + + Change Case Type + + + Change Case Status + + + Follow up + + + Source(incoming) + + + Incoming correspondence + + + Incoming Press Release + + + Complaint + + + Urgent Action(incoming) + + + Outgoing correspondence + + + Outgoing Press Release + + + FL Action(outgoing) + + + FL Urgent Action(outgoing) + + + Lobbying(outgoing) + + + + + standard_timeline + + true + + + Open Case + Closed + + + Source(incoming) + Open Case + 2 + newest + + + Follow up + Open Case + 14 + newest + + + + + + + Case Coordinator + 1 + + + Supervisor + + + diff --git a/CRM/Case/xml/HRD/HRD.mysql b/CRM/Case/xml/HRD/HRD.mysql new file mode 100644 index 0000000000..ea55d332fc --- /dev/null +++ b/CRM/Case/xml/HRD/HRD.mysql @@ -0,0 +1,45 @@ +-- /******************************************************* +-- * +-- * Configuration Data for CiviCase Component +-- * For: HRD +-- * +-- *******************************************************/ + +-- /******************************************************* +-- * +-- * Case Types +-- * +-- *******************************************************/ +SELECT @option_group_id_case_type := max(id) from civicrm_option_group where name = 'case_type'; +SELECT @caseCompId := id FROM `civicrm_component` where `name` like 'CiviCase'; + +INSERT INTO + `civicrm_option_value` (`option_group_id`, `label`, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `description`, `is_optgroup`, `is_reserved`, `is_active`) +VALUES +(@option_group_id_case_type, 'Civil and Political' , 1, 'Civil and Political' , NULL, 0, 1, 1, NULL, 0, 1, 1), +(@option_group_id_case_type, 'Economic, Social and Cultural', 2, 'Economic, Social and Cultural', NULL, 0, 0, 2, NULL, 0, 1, 1), +(@option_group_id_case_type, 'Gender Issues' , 3, 'Gender Issues' , NULL, 0, 0, 3, NULL, 0, 1, 1); + + +-- /******************************************************* +-- * +-- * Additional Case Activity Types +-- * +-- *******************************************************/ +SELECT @option_group_id_activity_type := max(id) from civicrm_option_group where name = 'activity_type'; + +SELECT @max_val := MAX(ROUND(op.value)) FROM civicrm_option_value op WHERE op.option_group_id = @option_group_id_activity_type; + +INSERT INTO + `civicrm_option_value` (`option_group_id`, `label`, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `description`, `is_optgroup`, `is_reserved`, `is_active`, `component_id` ) +VALUES + (@option_group_id_activity_type, 'Source(incoming)', (SELECT @max_val := @max_val+1), 'Source(incoming)', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Incoming correspondence', (SELECT @max_val := @max_val+1), 'Incoming correspondence', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Incoming Press Release', (SELECT @max_val := @max_val+1), 'Incoming Press Release', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Complaint', (SELECT @max_val := @max_val+1), 'Complaint', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Urgent Action(incoming)', (SELECT @max_val := @max_val+1), 'Urgent Action(incoming)', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Outgoing correspondence', (SELECT @max_val := @max_val+1), 'Outgoing correspondence', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Outgoing Press Release', (SELECT @max_val := @max_val+1), 'Outgoing Press Release', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'FL Action(outgoing)', (SELECT @max_val := @max_val+1), 'FL Action(outgoing)', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'FL Urgent Action(outgoing)', (SELECT @max_val := @max_val+1), 'FL Urgent Action(outgoing)', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), + (@option_group_id_activity_type, 'Lobbying(outgoing)', (SELECT @max_val := @max_val+1), '', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ); diff --git a/CRM/Case/xml/Menu/Case.xml b/CRM/Case/xml/Menu/Case.xml new file mode 100644 index 0000000000..be30bf1dba --- /dev/null +++ b/CRM/Case/xml/Menu/Case.xml @@ -0,0 +1,138 @@ + + + + + civicrm/case + CiviCase Dashboard + CRM_Case_Page_DashBoard + 1 + 900 + CiviCase + + + civicrm/case/add + Open Case + CRM_Case_Form_Case + 1 + CiviCase + + + civicrm/case/search + Find Cases + CRM_Case_Controller_Search + 1 + 910 + + + civicrm/case/activity + Case Activity + CRM_Case_Form_Activity + + + civicrm/case/report + Case Report + CRM_Case_Form_Report + access all cases and activities + + + civicrm/case/cd/edit + Case Custom Set + CRM_Case_Form_CustomData + + + civicrm/contact/view/case + Case + CRM_Case_Page_Tab + + + civicrm/case/activity/view + Activity View + CRM_Case_Form_ActivityView + + + civicrm/contact/view/case/editClient + Assign to Another Client + CRM_Case_Form_EditClient + + + civicrm/case/addToCase + Build Activity To Case + CRM_Case_Form_ActivityToCase + + + civicrm/case/details + Case Details + CRM_Case_Page_CaseDetails + + + civicrm/admin/options/case_type + Case Types + List of types which can be assigned to Cases. (Enable the Cases tab from Global Settings - Site Preferences if you want to track cases.) + group=case_type + administer CiviCase + CRM_Admin_Page_Options + CiviCase + admin/small/case_type.png + 390 + + + civicrm/admin/options/redaction_rule + Redaction Rules + List of rules which can be applied to user input strings so that the redacted output can be recognized as repeated instances of the same string or can be identified as a "semantic type of the data element" within case data. + group=redaction_rule + CRM_Admin_Page_Options + administer CiviCase + CiviCase + admin/small/redaction_type.png + 400 + + + civicrm/admin/options/case_status + Case Statuses + List of statuses that can be assigned to a case. + group=case_status + CRM_Admin_Page_Options + administer CiviCase + CiviCase + admin/small/case_type.png + 400 + + + civicrm/admin/options/encounter_medium + Encounter Mediums + List of encounter mediums. + group=encounter_medium + CRM_Admin_Page_Options + administer CiviCase + CiviCase + admin/small/case_type.png + 400 + + + civicrm/case/report/print + CRM_Case_XMLProcessor_Report::printCaseReport + access all cases and activities + + + civicrm/case/ajax/unclosed + CRM_Case_Page_AJAX::unclosedCases + + + civicrm/case/ajax/relcases + CRM_Case_Page_AJAX::getRelatedCases + + + civicrm/case/ajax/addclient + CRM_Case_Page_AJAX::addClient + + + civicrm/case/ajax/processtags + CRM_Case_Page_AJAX::processCaseTags + access CiviCRM + 3 + + + civicrm/case/ajax/details + CRM_Case_Page_AJAX::CaseDetails + + diff --git a/CRM/Case/xml/configuration.sample/AdultDayCareReferral.xml b/CRM/Case/xml/configuration.sample/AdultDayCareReferral.xml new file mode 100644 index 0000000000..cde1a97f28 --- /dev/null +++ b/CRM/Case/xml/configuration.sample/AdultDayCareReferral.xml @@ -0,0 +1,84 @@ + + + + Adult Day Care Referral + + + Open Case + 1 + + + Medical evaluation + + + Mental health evaluation + + + ADC referral + + + Follow up + + + Change Case Type + + + Change Case Status + + + Change Case Start Date + + + Link Cases + + + + + standard_timeline + + true + + + Open Case + Completed + + + Medical evaluation + Open Case + 3 + newest + + + Mental health evaluation + Open Case + 7 + newest + + + ADC referral + Open Case + 10 + newest + + + Follow up + Open Case + 14 + newest + + + + + + + Senior Services Coordinator + 1 + + + Health Services Coordinator + + + Benefits Specialist + + + diff --git a/CRM/Case/xml/configuration.sample/HousingSupport.xml b/CRM/Case/xml/configuration.sample/HousingSupport.xml new file mode 100644 index 0000000000..33412b6d6d --- /dev/null +++ b/CRM/Case/xml/configuration.sample/HousingSupport.xml @@ -0,0 +1,109 @@ + + + + Housing Support + + + Open Case + 1 + + + Medical evaluation + + + Mental health evaluation + + + Secure temporary housing + + + Income and benefits stabilization + + + Long-term housing plan + + + Follow up + + + Change Case Type + + + Change Case Status + + + Change Case Start Date + + + Link Cases + + + + + standard_timeline + + true + + + Open Case + Completed + + + Medical evaluation + Open Case + 1 + newest + + + Mental health evaluation + Open Case + 1 + newest + + + Secure temporary housing + Open Case + 2 + newest + + + Follow up + Open Case + 3 + newest + + + Income and benefits stabilization + Open Case + 7 + newest + + + Long-term housing plan + Open Case + 14 + newest + + + Follow up + Open Case + 21 + newest + + + + + + + Homeless Services Coordinator + 1 + 1 + + + Health Services Coordinator + + + Benefits Specialist + + + diff --git a/CRM/Case/xml/configuration.sample/SampleConfig.mysql b/CRM/Case/xml/configuration.sample/SampleConfig.mysql new file mode 100644 index 0000000000..92ca672c34 --- /dev/null +++ b/CRM/Case/xml/configuration.sample/SampleConfig.mysql @@ -0,0 +1,58 @@ +-- /********************************************************************** +-- * +-- * Configuration Data for CiviCase Component +-- * For: Sample Case Types - Housing Support and Adult Day Care Referral +-- * +-- **********************************************************************/ + +SELECT @caseCompId := id FROM `civicrm_component` where `name` like 'CiviCase'; + +-- /******************************************************* +-- * +-- * Case Types +-- * +-- *******************************************************/ +SELECT @option_group_id_case_type := max(id) from civicrm_option_group where name = 'case_type'; +SELECT @max_val := IF ( value <> 'NULL',max(value) , 0 ) from civicrm_option_value where option_group_id=@option_group_id_case_type; +SELECT @max_wt := IF ( value <> 'NULL',max(weight), 0 ) from civicrm_option_value where option_group_id=@option_group_id_case_type; + +INSERT INTO `civicrm_option_value` (`option_group_id`, `label`, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `description`, `is_optgroup`, `is_reserved`, `is_active`) VALUES (@option_group_id_case_type, 'Housing Support', @max_val + 1, 'housing_support', NULL, 0, 0, @max_wt + 1, 'Help homeless individuals obtain temporary and long-term housing', 0, 0, 1), (@option_group_id_case_type, 'Adult Day Care Referral', @max_val + 2, 'adult_day_care_referral', NULL, 0, 0, @max_wt + 2, 'Arranging adult day care for senior individuals', 0, 0, 1); + +-- /******************************************************* +-- * +-- * Case Status - Set names for Open and Closed +-- * +-- *******************************************************/ +SELECT @csgId := max(id) from civicrm_option_group where name = 'case_status'; +UPDATE civicrm_option_value SET name = 'Open' where option_group_id = @csgId AND label = 'Ongoing'; +UPDATE civicrm_option_value SET name = 'Closed' where option_group_id = @csgId AND label = 'Resolved'; + +-- /******************************************************* +-- * +-- * Activity Types +-- * +-- *******************************************************/ +SELECT @option_group_id_activity_type := max(id) from civicrm_option_group where name = 'activity_type'; + +SELECT @max_val := MAX(ROUND(op.value)) FROM civicrm_option_value op WHERE op.option_group_id = @option_group_id_activity_type; + +INSERT INTO `civicrm_option_value` (`option_group_id`, `label`, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `description`, `is_optgroup`, `is_reserved`, `is_active`, `component_id` ) VALUES (@option_group_id_activity_type, 'Medical evaluation', (SELECT @max_val := @max_val+1), 'Medical evaluation', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), (@option_group_id_activity_type, 'Mental health evaluation', (SELECT @max_val := @max_val+1), 'Mental health evaluation', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), (@option_group_id_activity_type, 'Secure temporary housing', (SELECT @max_val := @max_val+1), 'Secure temporary housing', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), (@option_group_id_activity_type, 'Income and benefits stabilization', (SELECT @max_val := @max_val+1), 'Income and benefits stabilization', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), (@option_group_id_activity_type, 'Long-term housing plan', (SELECT @max_val := @max_val+1), 'Long-term housing plan', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ), (@option_group_id_activity_type, 'ADC referral', (SELECT @max_val := @max_val+1), 'ADC referral', NULL, 0, 0, (SELECT @max_val := @max_val+1), '', 0, 0, 1, @caseCompId ); + +-- Get Open Case id so we can add custom fields for this activity type if we need to +SELECT @at1 := max(value) from civicrm_option_value where name = 'Open Case'; + +-- /******************************************************* +-- * +-- * Relationship Types (Case Roles) +-- * +-- *******************************************************/ + +INSERT INTO `civicrm_relationship_type` ( name_a_b, label_a_b, name_b_a, label_b_a, description, contact_type_a, contact_type_b, is_reserved, is_active ) VALUES ('Homeless Services Coordinator is', 'Homeless Services Coordinator is', 'Homeless Services Coordinator', 'Homeless Services Coordinator', 'Homeless Services Coordinator', 'Individual', 'Individual', 0, 1), ('Health Services Coordinator is', 'Health Services Coordinator is', 'Health Services Coordinator', 'Health Services Coordinator', 'Health Services Coordinator', 'Individual', 'Individual', 0, 1), ('Senior Services Coordinator is', 'Senior Services Coordinator is', 'Senior Services Coordinator', 'Senior Services Coordinator', 'Senior Services Coordinator', 'Individual', 'Individual', 0, 1), ('Benefits Specialist is', 'Benefits Specialist is', 'Benefits Specialist', 'Benefits Specialist', 'Benefits Specialist', 'Individual', 'Individual', 0, 1); + +-- /******************************************************* +-- * +-- * Case Resources Group +-- * +-- *******************************************************/ + +INSERT INTO `civicrm_group` (`name`, `title`, `description`, `source`, `saved_search_id`, `is_active`, `visibility`, `where_clause`, `select_tables`, `where_tables`, `group_type`, `cache_date`, `parents`, `children`, `is_hidden`) VALUES ('Case_Resources', 'Case Resources', 'Contacts in this group are listed with their phone number and email when viewing case. You also can send copies of case activities to these contacts.', NULL, NULL, 1, 'User and User Admin Only', ' ( `civicrm_group_contact-5`.group_id IN ( 5 ) AND `civicrm_group_contact-5`.status IN ("Added") ) ', 'a:10:{s:15:"civicrm_contact";i:1;s:15:"civicrm_address";i:1;s:22:"civicrm_state_province";i:1;s:15:"civicrm_country";i:1;s:13:"civicrm_email";i:1;s:13:"civicrm_phone";i:1;s:10:"civicrm_im";i:1;s:19:"civicrm_worldregion";i:1;s:25:"`civicrm_group_contact-5`";s:114:" LEFT JOIN civicrm_group_contact `civicrm_group_contact-5` ON contact_a.id = `civicrm_group_contact-5`.contact_id ";s:6:"gender";i:1;}', 'a:2:{s:15:"civicrm_contact";i:1;s:25:"`civicrm_group_contact-5`";s:114:" LEFT JOIN civicrm_group_contact `civicrm_group_contact-5` ON contact_a.id = `civicrm_group_contact-5`.contact_id ";}', '2', NULL, NULL, NULL, 0); diff --git a/CRM/Case/xml/configuration.sample/Settings.xml b/CRM/Case/xml/configuration.sample/Settings.xml new file mode 100644 index 0000000000..6fca653644 --- /dev/null +++ b/CRM/Case/xml/configuration.sample/Settings.xml @@ -0,0 +1,25 @@ + + + + + + 0 + + 0 + + 0 + + + + Change Case Status + 0 + + + Change Case Start Date + 0 + + + diff --git a/CRM/Case/xml/samples/report.xml b/CRM/Case/xml/samples/report.xml new file mode 100644 index 0000000000..0c70c1210b --- /dev/null +++ b/CRM/Case/xml/samples/report.xml @@ -0,0 +1,210 @@ + + + Jack Smith, M.D. + Substance Abuse + Acute morphine addiction + Ongoing + 2008-09-12 + + + + All + false + + http://drupal.demo.civicrm.org/civicrm/activity?action=update&id=13&cid=201&reset=1 + + + + Case History + Open Case + String + + + + Ann Jones + String + + + + Ann Jones + String + + + + 2008-09-12T11:00 + Date + + + + 2008-09-12T11:00 + Date + + + + Opened the case during inbound phone call. + String + + + + Phone + String + + + + 15 + Int + + + + Client called very distressed and with suicidal thoughts. + Memo + + + + Completed + String + + + + + http://drupal.demo.civicrm.org/civicrm/activity?action=update&id=14&cid=201&reset=1 + + + + Case History + Presenting Problem + String + + + + Ann Jones + String + + + + Jack Smith, M.D. + String + + + + 2008-09-12 + Date + + + + 2008-09-12T11:00 + Date + + + + Defined the problem as seen by the client. + String + + + + Phone + String + + + + 30 + Int + + + + Client admitted to heavy drug use and said he really needed help kicking the habit. Problem started after cycling accident in 2006. + Memo + + + + 2006-09-01 + Date + + + + Completed + String + + + + + http://drupal.demo.civicrm.org/civicrm/activity?action=update&id=15&cid=201&reset=1 + + + + Medications and Substance Use + Medication and Drug Use + String + + + + Ann Jones + String + + + + Jack Smith, M.D. + String + + + + 2008-09-17 + Date + + + + 2008-09-17T10:00 + Date + + + + 50 + Int + + + + Went through a list of all the client's prescribed and non-prescribed medication and drug usage, focusing on the last 2 years. Usage trends are significantly upward for the primary problem drug. + Memo + + + + In-Person + String + + + + http://drupal.demo.civicrm.org/civicrm/file?reset=1&id=1&eid=102 + File + + + Drug Usage + + + Morphine + String + + + + Yes + Boolean + + + + 2006-09-01 + Date + + + + 2008-09-15 + Date + + + + + Completed + String + + + + + diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php new file mode 100644 index 0000000000..194e12da96 --- /dev/null +++ b/CRM/Contact/BAO/Contact.php @@ -0,0 +1,2971 @@ + $v) { + if ($v) { + $newPref[$k] = $v; + } + } + + $prefComm = $newPref; + if (is_array($prefComm) && !empty($prefComm)) { + $prefComm = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($prefComm)) . CRM_Core_DAO::VALUE_SEPARATOR; + $contact->preferred_communication_method = $prefComm; + } + else { + $contact->preferred_communication_method = ''; + } + } + + $allNull = $contact->copyValues($params); + + $contact->id = CRM_Utils_Array::value('contact_id', $params); + + if ($contact->contact_type == 'Individual') { + $allNull = FALSE; + + //format individual fields + CRM_Contact_BAO_Individual::format($params, $contact); + } + elseif ($contact->contact_type == 'Household') { + if (isset($params['household_name'])) { + $allNull = FALSE; + $contact->display_name = $contact->sort_name = CRM_Utils_Array::value('household_name', $params, ''); + } + } + elseif ($contact->contact_type == 'Organization') { + if (isset($params['organization_name'])) { + $allNull = FALSE; + $contact->display_name = $contact->sort_name = CRM_Utils_Array::value('organization_name', $params, ''); + } + } + + // privacy block + $privacy = CRM_Utils_Array::value('privacy', $params); + if ($privacy && + is_array($privacy) && + !empty($privacy) + ) { + $allNull = FALSE; + foreach (self::$_commPrefs as $name) { + $contact->$name = CRM_Utils_Array::value($name, $privacy, FALSE); + } + } + + // since hash was required, make sure we have a 0 value for it, CRM-1063 + // fixed in 1.5 by making hash optional + // only do this in create mode, not update + if ((!array_key_exists('hash', $contact) || !$contact->hash) && !$contact->id) { + $allNull = FALSE; + $contact->hash = md5(uniqid(rand(), TRUE)); + } + + // Even if we don't need $employerId, it's important to call getFieldValue() before + // the contact is saved because we want the existing value to be cached. + // createCurrentEmployerRelationship() needs the old value not the updated one. CRM-10788 + $employerId = empty($contact->id) ? NULL : CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contact->id, 'employer_id'); + + if (!$allNull) { + $contact->save(); + + CRM_Core_BAO_Log::register($contact->id, + 'civicrm_contact', + $contact->id + ); + } + + if ($contact->contact_type == 'Individual' && + (isset($params['current_employer']) || + isset($params['employer_id']) + ) + ) { + // create current employer + if (isset($params['employer_id'])) { + CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($contact->id, + $params['employer_id'] + ); + } + elseif ($params['current_employer']) { + CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($contact->id, + $params['current_employer'] + ); + } + else { + //unset if employer id exits + if ($employerId) { + CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($contact->id, $employerId); + } + } + } + + //update cached employee name + if ($contact->contact_type == 'Organization') { + CRM_Contact_BAO_Contact_Utils::updateCurrentEmployer($contact->id); + } + + return $contact; + } + + /** + * Function to create contact + * takes an associative array and creates a contact object and all the associated + * derived objects (i.e. individual, location, email, phone etc) + * + * This function is invoked from within the web form layer and also from the api layer + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param boolean $fixAddress if we need to fix address + * @param boolean $invokeHooks if we need to invoke hooks + * + * @return object CRM_Contact_BAO_Contact object + * @access public + * @static + */ + static function &create(&$params, $fixAddress = TRUE, $invokeHooks = TRUE, $skipDelete = FALSE) { + $contact = NULL; + if (!CRM_Utils_Array::value('contact_type', $params) && + !CRM_Utils_Array::value('contact_id', $params) + ) { + return $contact; + } + + $isEdit = TRUE; + if ($invokeHooks) { + if (!empty($params['contact_id'])) { + CRM_Utils_Hook::pre('edit', $params['contact_type'], $params['contact_id'], $params); + } + else { + CRM_Utils_Hook::pre('create', $params['contact_type'], NULL, $params); + $isEdit = FALSE; + } + } + + $config = CRM_Core_Config::singleton(); + + // CRM-6942: set preferred language to the current language if it’s unset (and we’re creating a contact) + if (empty($params['contact_id']) && empty($params['preferred_language'])) { + $params['preferred_language'] = $config->lcMessages; + } + + // CRM-9739: set greeting & addressee if unset and we’re creating a contact + if (empty($params['contact_id'])) { + foreach (self::$_greetingTypes as $greeting) { + if (empty($params[$greeting . '_id'])) { + if ($defaultGreetingTypeId = + CRM_Contact_BAO_Contact_Utils::defaultGreeting($params['contact_type'], $greeting) + ) { + $params[$greeting . '_id'] = $defaultGreetingTypeId; + } + } + } + } + + $transaction = new CRM_Core_Transaction(); + + $contact = self::add($params); + if (!$contact) { + // not dying here is stupid, since we get into wierd situation and into a bug that + // is impossible to figure out for the user or for us + // CRM-7925 + CRM_Core_Error::fatal(); + } + + $params['contact_id'] = $contact->id; + + if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'is_enabled' + )) { + // in order to make sure that every contact must be added to a group (CRM-4613) - + $domainGroupID = CRM_Core_BAO_Domain::getGroupId(); + if (CRM_Utils_Array::value('group', $params) && is_array($params['group'])) { + $grpFlp = array_flip($params['group']); + if (!array_key_exists(1, $grpFlp)) { + $params['group'][$domainGroupID] = 1; + } + } + else { + $params['group'] = array($domainGroupID => 1); + } + } + + if (array_key_exists('group', $params)) { + $contactIds = array($params['contact_id']); + foreach ($params['group'] as $groupId => $flag) { + if ($flag == 1) { + CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId); + } + elseif ($flag == -1) { + CRM_Contact_BAO_GroupContact::removeContactsFromGroup($contactIds, $groupId); + } + } + } + + //add location Block data + $blocks = CRM_Core_BAO_Location::create($params, $fixAddress); + foreach ($blocks as $name => $value) { + $contact->$name = $value; + } + + //add website + CRM_Core_BAO_Website::create($params['website'], $contact->id, $skipDelete); + + //get userID from session + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + // add notes + if (CRM_Utils_Array::value('note', $params)) { + if (is_array($params['note'])) { + foreach ($params['note'] as $note) { + $contactId = $contact->id; + if (isset($note['contact_id'])) { + $contactId = $note['contact_id']; + } + //if logged in user, overwrite contactId + if ($userID) { + $contactId = $userID; + } + + $noteParams = array( + 'entity_id' => $contact->id, + 'entity_table' => 'civicrm_contact', + 'note' => $note['note'], + 'subject' => CRM_Utils_Array::value('subject', $note), + 'contact_id' => $contactId, + ); + CRM_Core_BAO_Note::add($noteParams, CRM_Core_DAO::$_nullArray); + } + } + else { + $contactId = $contact->id; + if (isset($note['contact_id'])) { + $contactId = $note['contact_id']; + } + //if logged in user, overwrite contactId + if ($userID) { + $contactId = $userID; + } + + $noteParams = array( + 'entity_id' => $contact->id, + 'entity_table' => 'civicrm_contact', + 'note' => $params['note'], + 'subject' => CRM_Utils_Array::value('subject', $params), + 'contact_id' => $contactId, + ); + CRM_Core_BAO_Note::add($noteParams, CRM_Core_DAO::$_nullArray); + } + } + + + // update the UF user_unique_id if that has changed + CRM_Core_BAO_UFMatch::updateUFName($contact->id); + + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_contact', $contact->id); + } + + // make a civicrm_subscription_history entry only on contact create (CRM-777) + if (!CRM_Utils_Array::value('contact_id', $params)) { + $subscriptionParams = array( + 'contact_id' => $contact->id, + 'status' => 'Added', + 'method' => 'Admin', + ); + CRM_Contact_BAO_SubscriptionHistory::create($subscriptionParams); + } + + $transaction->commit(); + + // CRM-6367: fetch the right label for contact type’s display + $contact->contact_type_display = CRM_Core_DAO::getFieldValue( + 'CRM_Contact_DAO_ContactType', + $contact->contact_type, + 'label', + 'name' + ); + + if (!$config->doNotResetCache) { + // Note: doNotResetCache flag is currently set by import contact process and merging, + // since resetting and + // rebuilding cache could be expensive (for many contacts). We might come out with better + // approach in future. + CRM_Contact_BAO_Contact_Utils::clearContactCaches($contact->id); + } + + if ($invokeHooks) { + if ($isEdit) { + CRM_Utils_Hook::post('edit', $params['contact_type'], $contact->id, $contact); + } + else { + CRM_Utils_Hook::post('create', $params['contact_type'], $contact->id, $contact); + } + } + + // process greetings CRM-4575, cache greetings + self::processGreetings($contact); + + return $contact; + } + + /** + * Get the display name and image of a contact + * + * @param int $id the contactId + * + * @return array the displayName and contactImage for this contact + * @access public + * @static + */ + static function getDisplayAndImage($id, $type = FALSE) { + $sql = " +SELECT civicrm_contact.display_name as display_name, + civicrm_contact.contact_type as contact_type, + civicrm_contact.contact_sub_type as contact_sub_type, + civicrm_email.email as email +FROM civicrm_contact +LEFT JOIN civicrm_email ON civicrm_email.contact_id = civicrm_contact.id + AND civicrm_email.is_primary = 1 +WHERE civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer'); + $dao = new CRM_Core_DAO(); + $dao->query($sql); + if ($dao->fetch()) { + $image = CRM_Contact_BAO_Contact_Utils::getImage($dao->contact_sub_type ? + $dao->contact_sub_type : $dao->contact_type, FALSE, $id + ); + $imageUrl = CRM_Contact_BAO_Contact_Utils::getImage($dao->contact_sub_type ? + $dao->contact_sub_type : $dao->contact_type, TRUE, $id + ); + + // use email if display_name is empty + if (empty($dao->display_name)) { + $dao->display_name = $dao->email; + } + return $type ? array( + $dao->display_name, $image, + $dao->contact_type, $dao->contact_sub_type, $imageUrl, + ) : array($dao->display_name, $image, $imageUrl); + } + return NULL; + } + + /** + * + * Get the values for pseudoconstants for name->value and reverse. + * + * @param array $defaults (reference) the default values, some of which need to be resolved. + * @param boolean $reverse true if we want to resolve the values in the reverse direction (value -> name) + * + * @return none + * @access public + * @static + */ + static function resolveDefaults(&$defaults, $reverse = FALSE) { + // hack for birth_date + if (CRM_Utils_Array::value('birth_date', $defaults)) { + if (is_array($defaults['birth_date'])) { + $defaults['birth_date'] = CRM_Utils_Date::format($defaults['birth_date'], '-'); + } + } + + CRM_Utils_Array::lookupValue($defaults, 'prefix', CRM_Core_PseudoConstant::individualPrefix(), $reverse); + CRM_Utils_Array::lookupValue($defaults, 'suffix', CRM_Core_PseudoConstant::individualSuffix(), $reverse); + CRM_Utils_Array::lookupValue($defaults, 'gender', CRM_Core_PseudoConstant::gender(), $reverse); + + //lookup value of email/postal greeting, addressee, CRM-4575 + foreach (self::$_greetingTypes as $greeting) { + $filterCondition = array('contact_type' => CRM_Utils_Array::value('contact_type', $defaults), + 'greeting_type' => $greeting, + ); + CRM_Utils_Array::lookupValue($defaults, $greeting, + CRM_Core_PseudoConstant::greeting($filterCondition), $reverse + ); + } + + $blocks = array('address', 'im', 'phone'); + foreach ($blocks as $name) { + if (!array_key_exists($name, $defaults) || !is_array($defaults[$name])) { + continue; + } + foreach ($defaults[$name] as $count => & $values) { + + //get location type id. + CRM_Utils_Array::lookupValue($values, 'location_type', CRM_Core_PseudoConstant::locationType(), $reverse); + + if ($name == 'address') { + // FIXME: lookupValue doesn't work for vcard_name + if (CRM_Utils_Array::value('location_type_id', $values)) { + $vcardNames = CRM_Core_PseudoConstant::locationVcardName(); + $values['vcard_name'] = $vcardNames[$values['location_type_id']]; + } + + if (!CRM_Utils_Array::lookupValue($values, + 'country', + CRM_Core_PseudoConstant::country(), + $reverse + ) && + $reverse + ) { + CRM_Utils_Array::lookupValue($values, + 'country', + CRM_Core_PseudoConstant::countryIsoCode(), + $reverse + ); + } + + // CRM-7597 + // if we find a country id above, we need to restrict it to that country + // rather than the list of all countries + + if (!empty($values['country_id'])) { + $stateProvinceList = CRM_Core_PseudoConstant::stateProvinceForCountry($values['country_id']); + } + else { + $stateProvinceList = CRM_Core_PseudoConstant::stateProvince(); + } + if (!CRM_Utils_Array::lookupValue($values, + 'state_province', + $stateProvinceList, + $reverse + ) && + $reverse + ) { + + if (!empty($values['country_id'])) { + $stateProvinceList = CRM_Core_PseudoConstant::stateProvinceForCountry($values['country_id'], 'abbreviation'); + } + else { + $stateProvinceList = CRM_Core_PseudoConstant::stateProvinceAbbreviation(); + } + CRM_Utils_Array::lookupValue($values, + 'state_province', + $stateProvinceList, + $reverse + ); + } + + if (!empty($values['state_province_id'])) { + $countyList = CRM_Core_PseudoConstant::countyForState($values['state_province_id']); + } + else { + $countyList = CRM_Core_PseudoConstant::county(); + } + CRM_Utils_Array::lookupValue($values, + 'county', + $countyList, + $reverse + ); + } + + if ($name == 'im') { + CRM_Utils_Array::lookupValue($values, + 'provider', + CRM_Core_PseudoConstant::IMProvider(), + $reverse + ); + } + + if ($name == 'phone') { + CRM_Utils_Array::lookupValue($values, + 'phone_type', + CRM_Core_PseudoConstant::phoneType(), + $reverse + ); + } + + //kill the reference. + unset($values); + } + } + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * contact_id. We'll tweak this function to be more full featured over a period + * of time. This is the inverse function of create. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the name / value pairs + * in a hierarchical manner + * @param boolean $microformat for location in microformat + * + * @return object CRM_Contact_BAO_Contact object + * @access public + * @static + */ + static function &retrieve(&$params, &$defaults, $microformat = FALSE) { + if (array_key_exists('contact_id', $params)) { + $params['id'] = $params['contact_id']; + } + elseif (array_key_exists('id', $params)) { + $params['contact_id'] = $params['id']; + } + + $contact = self::getValues($params, $defaults); + + unset($params['id']); + + //get the block information for this contact + $entityBlock = array('contact_id' => $params['contact_id']); + $blocks = CRM_Core_BAO_Location::getValues($entityBlock, $microformat); + $defaults = array_merge($defaults, $blocks); + foreach ($blocks as $block => $value) $contact->$block = $value; + + if (!isset($params['noNotes'])) { + $contact->notes = CRM_Core_BAO_Note::getValues($params, $defaults); + } + + if (!isset($params['noRelationships'])) { + $contact->relationship = CRM_Contact_BAO_Relationship::getValues($params, $defaults); + } + + if (!isset($params['noGroups'])) { + $contact->groupContact = CRM_Contact_BAO_GroupContact::getValues($params, $defaults); + } + + if (!isset($params['noWebsite'])) { + $contact->website = CRM_Core_BAO_Website::getValues($params, $defaults); + } + + return $contact; + } + + /** + * function to get the display name of a contact + * + * @param int $id id of the contact + * + * @return null|string display name of the contact if found + * @static + * @access public + */ + static function displayName($id) { + $displayName = NULL; + if ($id) { + $displayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $id, 'display_name'); + } + + return $displayName; + } + + /** + * Delete a contact and all its associated records + * + * @param int $id id of the contact to delete + * @param bool $restore whether to actually restore, not delete + * @param bool $skipUndelete whether to force contact delete or not + * + * @return boolean true if contact deleted, false otherwise + * @access public + * @static + */ + static function deleteContact($id, $restore = FALSE, $skipUndelete = FALSE) { + + if (!$id) { + return FALSE; + } + + // make sure we have edit permission for this contact + // before we delete + if (($skipUndelete && !CRM_Core_Permission::check('delete contacts')) || + ($restore && !CRM_Core_Permission::check('access deleted contacts')) + ) { + return FALSE; + } + + // make sure this contact_id does not have any membership types + $membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', + $id, + 'id', + 'member_of_contact_id' + ); + if ($membershipTypeID) { + return FALSE; + } + + $contact = new CRM_Contact_DAO_Contact(); + $contact->id = $id; + if (!$contact->find(TRUE)) { + return FALSE; + } + + $contactType = $contact->contact_type; + $action = ($restore) ? 'restore' : 'delete'; + + CRM_Utils_Hook::pre($action, $contactType, $id, CRM_Core_DAO::$_nullArray); + + if ($restore) { + self::contactTrashRestore($contact, TRUE); + CRM_Utils_Hook::post($action, $contactType, $contact->id, $contact); + return TRUE; + } + + + // currently we only clear employer cache. + // we are not deleting inherited membership if any. + if ($contact->contact_type == 'Organization') { + CRM_Contact_BAO_Contact_Utils::clearAllEmployee($id); + } + + // start a new transaction + $transaction = new CRM_Core_Transaction(); + + if ($skipUndelete or !CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_undelete', NULL)) { + + //delete billing address if exists. + CRM_Contribute_BAO_Contribution::deleteAddress(NULL, $id); + + // delete the log entries since we dont have triggers enabled as yet + $logDAO = new CRM_Core_DAO_Log(); + $logDAO->entity_table = 'civicrm_contact'; + $logDAO->entity_id = $id; + $logDAO->delete(); + + // do activity cleanup, CRM-5604 + CRM_Activity_BAO_Activity::cleanupActivity($id); + + // delete all notes related to contact + CRM_Core_BAO_Note::cleanContactNotes($id); + + $contact->delete(); + } + else { + self::contactTrashRestore($contact); + } + + //delete the contact id from recently view + CRM_Utils_Recent::delContact($id); + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + + // delete any dupe cache entry + CRM_Core_BAO_PrevNextCache::deleteItem($id); + + $transaction->commit(); + + CRM_Utils_Hook::post('delete', $contactType, $contact->id, $contact); + + // also reset the DB_DO global array so we can reuse the memory + // http://issues.civicrm.org/jira/browse/CRM-4387 + CRM_Core_DAO::freeResult(); + + return TRUE; + } + + /** + * function to delete the image of a contact + * + * @param int $id id of the contact + * + * @return boolean true if contact image is deleted + */ + public static function deleteContactImage($id) { + if (!$id) { + return FALSE; + } + $query = " +UPDATE civicrm_contact +SET image_URL=NULL +WHERE id={$id}; "; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + return TRUE; + } + + /** + * function to return relative path + * @todo make this a method of $config->userSystem (i.e. UF classes) rather than a static function + * + * @param String $absPath absolute path + * + * @return String $relativePath Relative url of uploaded image + */ + public static function getRelativePath($absolutePath) { + $relativePath = NULL; + $config = CRM_Core_Config::singleton(); + if ($config->userFramework == 'Joomla') { + $userFrameworkBaseURL = trim(str_replace('/administrator/', '', $config->userFrameworkBaseURL)); + $customFileUploadDirectory = strstr(str_replace('\\', '/', $absolutePath), '/media'); + $relativePath = $userFrameworkBaseURL . $customFileUploadDirectory; + } + elseif ($config->userSystem->is_drupal == '1') { + //ideally we would do a bigger re-factoring & move the getRelativePath onto the UF class + $rootPath = $config->userSystem->cmsRootPath(); + $baseUrl = $config->userFrameworkBaseURL; + + //format url for language negotiation, CRM-7135 + $baseUrl = CRM_Utils_System::languageNegotiationURL($baseUrl, FALSE, TRUE); + + $relativePath = str_replace("{$rootPath}/", + $baseUrl, + str_replace('\\', '/', $absolutePath) + ); + } else if ( $config->userFramework == 'WordPress' ) { + $userFrameworkBaseURL = trim( str_replace( '/wp-admin/', '', $config->userFrameworkBaseURL ) ); + $customFileUploadDirectory = strstr( str_replace('\\', '/', $absolutePath), '/wp-content/' ); + $relativePath = $userFrameworkBaseURL . $customFileUploadDirectory; + } + + return $relativePath; + } + + /** + * function to return proportional height and width of the image + * + * @param Integer $imageWidth width of image + * + * @param Integer $imageHeight height of image + * + * @return Array thumb dimension of image + */ + public static function getThumbSize($imageWidth, $imageHeight) { + $thumbWidth = 100; + if ($imageWidth && $imageHeight) { + $imageRatio = $imageWidth / $imageHeight; + } + else { + $imageRatio = 1; + } + if ($imageRatio > 1) { + $imageThumbWidth = $thumbWidth; + $imageThumbHeight = round($thumbWidth / $imageRatio); + } + else { + $imageThumbHeight = $thumbWidth; + $imageThumbWidth = round($thumbWidth * $imageRatio); + } + + return array($imageThumbWidth, $imageThumbHeight); + } + + /** + * function to validate type of contact image + * + * @param Array $param array of contact/profile field to be edited/added + * + * @param String $imageIndex index of image field + * + * @param String $statusMsg status message to be set after operation + * + * @opType String $opType type of operation like fatal, bounce etc + * + * @return boolean true if valid image extension + */ + public static function processImageParams(&$params, + $imageIndex = 'image_URL', + $statusMsg = NULL, + $opType = 'status' + ) { + $mimeType = array( + 'image/jpeg', + 'image/jpg', + 'image/png', + 'image/bmp', + 'image/p-jpeg', + 'image/gif', + 'image/x-png', + ); + + if (in_array($params[$imageIndex]['type'], $mimeType)) { + $params[$imageIndex] = CRM_Contact_BAO_Contact::getRelativePath($params[$imageIndex]['name']); + return TRUE; + } + else { + unset($params[$imageIndex]); + if (!$statusMsg) { + $statusMsg = ts('Image could not be uploaded due to invalid type extension.'); + } + if ($opType == 'status') { + CRM_Core_Session::setStatus($statusMsg, 'Sorry', 'error'); + } + // FIXME: additional support for fatal, bounce etc could be added. + return FALSE; + } + } + + /** + * function to extract contact id from url for deleting contact image + */ + public static function processImage() { + + $action = CRM_Utils_Request::retrieve('action', 'String', $this); + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + // retrieve contact id in case of Profile context + $id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $cid = $cid ? $cid : $id; + if ($action & CRM_Core_Action::DELETE) { + if (CRM_Utils_Request::retrieve('confirmed', 'Boolean', $this)) { + CRM_Contact_BAO_Contact::deleteContactImage($cid); + CRM_Core_Session::setStatus(ts('Contact image deleted successfully'), ts('Image Deleted'), 'success'); + $session = CRM_Core_Session::singleton(); + $toUrl = $session->popUserContext(); + CRM_Utils_System::redirect($toUrl); + } + } + } + + /** + * Function to set is_delete true or restore deleted contact + * + * @param int $contact Contact DAO object + * @param boolean $restore true to set the is_delete = 1 else false to restore deleted contact, + * i.e. is_delete = 0 + * + * @return void + * @static + */ + static function contactTrashRestore($contact, $restore = FALSE) { + $op = ($restore ? 'restore' : 'trash'); + + CRM_Utils_Hook::pre($op, $contact->contact_type, $contact->id, CRM_Core_DAO::$_nullArray); + + $params = array(1 => array($contact->id, 'Integer')); + $isDelete = ' is_deleted = 1 '; + if ($restore) { + $isDelete = ' is_deleted = 0 '; + } + else { + $query = "DELETE FROM civicrm_uf_match WHERE contact_id = %1"; + CRM_Core_DAO::executeQuery($query, $params); + } + + $query = "UPDATE civicrm_contact SET {$isDelete} WHERE id = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + CRM_Utils_Hook::post($op, $contact->contact_type, $contact->id, $contact); + } + + /** + * Get contact type for a contact. + * + * @param int $id - id of the contact whose contact type is needed + * + * @return string contact_type if $id found else null "" + * + * @access public + * + * @static + * + */ + public static function getContactType($id) { + return CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $id, 'contact_type'); + } + + /** + * Get contact sub type for a contact. + * + * @param int $id - id of the contact whose contact sub type is needed + * + * @return string contact_sub_type if $id found else null "" + * + * @access public + * + * @static + * + */ + public static function getContactSubType($id, $implodeDelimiter = NULL) { + $subtype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $id, 'contact_sub_type'); + if (!$subtype) { + return $implodeDelimiter ? NULL : array(); + } + + $subtype = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($subtype, CRM_Core_DAO::VALUE_SEPARATOR)); + + if ($implodeDelimiter) { + $subtype = implode($implodeDelimiter, $subtype); + } + return $subtype; + } + + /** + * Get pair of contact-type and sub-type for a contact. + * + * @param int $id - id of the contact whose contact sub/contact type is needed + * + * @return array + * + * @access public + * + * @static + * + */ + public static function getContactTypes($id) { + $params = array('id' => $id); + $details = array(); + $contact = CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_Contact', + $params, + $details, + array('contact_type', 'contact_sub_type') + ); + + if ($contact) { + $contactTypes = array(); + if ($contact->contact_sub_type) + $contactTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($contact->contact_sub_type, CRM_Core_DAO::VALUE_SEPARATOR)); + array_unshift($contactTypes, $contact->contact_type); + + return $contactTypes; + } + else { + CRM_Core_Error::fatal(); + } + } + + /** + * combine all the importable fields from the lower levels object + * + * The ordering is important, since currently we do not have a weight + * scheme. Adding weight is super important and should be done in the + * next week or so, before this can be called complete. + * + * @param int $contactType contact Type + * @param boolean $status status is used to manipulate first title + * @param boolean $showAll if true returns all fields (includes disabled fields) + * @param boolean $isProfile if its profile mode + * @param boolean $checkPermission if false, do not include permissioning clause (for custom data) + * + * @return array array of importable Fields + * @access public + * @static + */ + static function importableFields($contactType = 'Individual', + $status = FALSE, + $showAll = FALSE, + $isProfile = FALSE, + $checkPermission = TRUE, + $withMultiCustomFields = FALSE + ) { + if (empty($contactType)) { + $contactType = 'All'; + } + + $cacheKeyString = "importableFields $contactType"; + $cacheKeyString .= $status ? '_1' : '_0'; + $cacheKeyString .= $showAll ? '_1' : '_0'; + $cacheKeyString .= $isProfile ? '_1' : '_0'; + $cacheKeyString .= $checkPermission ? '_1' : '_0'; + + $fields = CRM_Utils_Array::value($cacheKeyString, self::$_importableFields); + + if (!$fields) { + // check if we can retrieve from database cache + $fields = CRM_Core_BAO_Cache::getItem('contact fields', $cacheKeyString); + } + + if (!$fields) { + $fields = CRM_Contact_DAO_Contact::import(); + + // get the fields thar are meant for contact types + if (in_array($contactType, array( + 'Individual', 'Household', 'Organization', 'All'))) { + $fields = array_merge($fields, CRM_Core_OptionValue::getFields('', $contactType)); + } + + $locationFields = array_merge(CRM_Core_DAO_Address::import(), + CRM_Core_DAO_Phone::import(), + CRM_Core_DAO_Email::import(), + CRM_Core_DAO_IM::import(TRUE), + CRM_Core_DAO_OpenID::import() + ); + + $locationFields = array_merge($locationFields, + CRM_Core_BAO_CustomField::getFieldsForImport('Address', + FALSE, + FALSE, + FALSE, + FALSE + ) + ); + + foreach ($locationFields as $key => $field) { + $locationFields[$key]['hasLocationType'] = TRUE; + } + + $fields = array_merge($fields, $locationFields); + + $fields = array_merge($fields, + CRM_Contact_DAO_Contact::import() + ); + $fields = array_merge($fields, + CRM_Core_DAO_Note::import() + ); + + //website fields + $fields = array_merge($fields, CRM_Core_DAO_Website::import()); + + if ($contactType != 'All') { + $fields = array_merge($fields, + CRM_Core_BAO_CustomField::getFieldsForImport($contactType, + $showAll, + TRUE, + FALSE, + FALSE, + $withMultiCustomFields + ) + ); + //unset the fields, which are not related to their + //contact type. + $commonValues = array( + 'Individual' => array('household_name', 'legal_name', 'sic_code', 'organization_name'), + 'Household' => array( + 'first_name', 'middle_name', 'last_name', 'job_title', + 'gender_id', 'birth_date', 'organization_name', 'legal_name', + 'legal_identifier', 'sic_code', 'home_URL', 'is_deceased', + 'deceased_date', + ), + 'Organization' => array( + 'first_name', 'middle_name', 'last_name', 'job_title', + 'gender_id', 'birth_date', 'household_name', 'is_deceased', 'deceased_date', + ), + ); + foreach ($commonValues[$contactType] as $value) { + unset($fields[$value]); + } + } + else { + foreach (array( + 'Individual', 'Household', 'Organization') as $type) { + $fields = array_merge($fields, + CRM_Core_BAO_CustomField::getFieldsForImport($type, + $showAll, + FALSE, + FALSE, + FALSE, + $withMultiCustomFields + ) + ); + } + } + + if ($isProfile) { + $fields = array_merge($fields, array('group' => array('title' => ts('Group(s)'), + 'name' => 'group', + ), + 'tag' => array('title' => ts('Tag(s)'), + 'name' => 'tag', + ), + 'note' => array('title' => ts('Note(s)'), + 'name' => 'note', + ), + )); + } + + //Sorting fields in alphabetical order(CRM-1507) + $fields = CRM_Utils_Array::crmArraySortByField($fields, 'title'); + + CRM_Core_BAO_Cache::setItem($fields, 'contact fields', $cacheKeyString); + } + + self::$_importableFields[$cacheKeyString] = $fields; + + if (!$isProfile) { + if (!$status) { + $fields = array_merge(array('do_not_import' => array('title' => ts('- do not import -'))), + self::$_importableFields[$cacheKeyString] + ); + } + else { + $fields = array_merge(array('' => array('title' => ts('- Contact Fields -'))), + self::$_importableFields[$cacheKeyString] + ); + } + } + return $fields; + } + + /** + * combine all the exportable fields from the lower levels object + * + * currentlty we are using importable fields as exportable fields + * + * @param int $contactType contact Type + * @param boolean $status true while exporting primary contacts + * @param boolean $export true when used during export + * @param boolean $search true when used during search, might conflict with export param? + * + * @return array array of exportable Fields + * @access public + * @static + */ + static function &exportableFields($contactType = 'Individual', $status = FALSE, $export = FALSE, $search = FALSE, $withMultiRecord = FALSE) { + if (empty($contactType)) { + $contactType = 'All'; + } + + $cacheKeyString = "exportableFields $contactType"; + $cacheKeyString .= $export ? '_1' : '_0'; + $cacheKeyString .= $status ? '_1' : '_0'; + $cacheKeyString .= $search ? '_1' : '_0'; + + if (!self::$_exportableFields || !CRM_Utils_Array::value($cacheKeyString, self::$_exportableFields)) { + if (!self::$_exportableFields) { + self::$_exportableFields = array(); + } + + // check if we can retrieve from database cache + $fields = CRM_Core_BAO_Cache::getItem('contact fields', $cacheKeyString); + + if (!$fields) { + $fields = array(); + $fields = CRM_Contact_DAO_Contact::export(); + + // the fields are meant for contact types + if (in_array($contactType, array( + 'Individual', 'Household', 'Organization', 'All'))) { + $fields = array_merge($fields, CRM_Core_OptionValue::getFields('', $contactType)); + } + // add current employer for individuals + $fields = array_merge($fields, array( + 'current_employer' => + array( + 'name' => 'organization_name', + 'title' => ts('Current Employer'), + ), + )); + + $locationType = array( + 'location_type' => array('name' => 'location_type', + 'where' => 'civicrm_location_type.name', + 'title' => ts('Location Type'), + )); + + $IMProvider = array( + 'im_provider' => array('name' => 'im_provider', + 'where' => 'civicrm_im.provider_id', + 'title' => ts('IM Provider'), + )); + + $locationFields = array_merge($locationType, + CRM_Core_DAO_Address::export(), + CRM_Core_DAO_Phone::export(), + CRM_Core_DAO_Email::export(), + $IMProvider, + CRM_Core_DAO_IM::export(TRUE), + CRM_Core_DAO_OpenID::export() + ); + + $locationFields = array_merge($locationFields, + CRM_Core_BAO_CustomField::getFieldsForImport('Address') + ); + + foreach ($locationFields as $key => $field) { + $locationFields[$key]['hasLocationType'] = TRUE; + } + + $fields = array_merge($fields, $locationFields); + + //add world region + $fields = array_merge($fields, + CRM_Core_DAO_Worldregion::export() + ); + + + $fields = array_merge($fields, + CRM_Contact_DAO_Contact::export() + ); + + //website fields + $fields = array_merge($fields, CRM_Core_DAO_Website::export()); + + if ($contactType != 'All') { + $fields = array_merge($fields, + CRM_Core_BAO_CustomField::getFieldsForImport($contactType, $status, TRUE, $search, TRUE, $withMultiRecord) + ); + } + else { + foreach (array( + 'Individual', 'Household', 'Organization') as $type) { + $fields = array_merge($fields, + CRM_Core_BAO_CustomField::getFieldsForImport($type, FALSE, FALSE, $search, TRUE, $withMultiRecord) + ); + } + } + + //fix for CRM-791 + if ($export) { + $fields = array_merge($fields, array('groups' => array('title' => ts('Group(s)'), + 'name' => 'groups', + ), + 'tags' => array('title' => ts('Tag(s)'), + 'name' => 'tags', + ), + 'notes' => array('title' => ts('Note(s)'), + 'name' => 'notes', + ), + )); + } + else { + $fields = array_merge($fields, array('group' => array('title' => ts('Group(s)'), + 'name' => 'group', + ), + 'tag' => array('title' => ts('Tag(s)'), + 'name' => 'tag', + ), + 'note' => array('title' => ts('Note(s)'), + 'name' => 'note', + ), + )); + } + + //Sorting fields in alphabetical order(CRM-1507) + foreach ($fields as $k => $v) { + $sortArray[$k] = CRM_Utils_Array::value('title', $v); + } + + $fields = array_merge($sortArray, $fields); + //unset the field which are not related to their contact type. + if ($contactType != 'All') { + $commonValues = array( + 'Individual' => array('household_name', 'legal_name', 'sic_code', 'organization_name', + 'email_greeting_custom', 'postal_greeting_custom', + 'addressee_custom', + ), + 'Household' => array( + 'first_name', 'middle_name', 'last_name', 'job_title', + 'gender_id', 'birth_date', 'organization_name', 'legal_name', + 'legal_identifier', 'sic_code', 'home_URL', 'is_deceased', + 'deceased_date', 'current_employer', 'email_greeting_custom', + 'postal_greeting_custom', 'addressee_custom', + 'individual_prefix', 'individual_suffix', 'gender', + ), + 'Organization' => array( + 'first_name', 'middle_name', 'last_name', 'job_title', + 'gender_id', 'birth_date', 'household_name', + 'email_greeting_custom', + 'postal_greeting_custom', 'individual_prefix', + 'individual_suffix', 'gender', 'addressee_custom', + 'is_deceased', 'deceased_date', 'current_employer', + ), + ); + foreach ($commonValues[$contactType] as $value) { + unset($fields[$value]); + } + } + + CRM_Core_BAO_Cache::setItem($fields, 'contact fields', $cacheKeyString); + } + self::$_exportableFields[$cacheKeyString] = $fields; + } + + if (!$status) { + $fields = self::$_exportableFields[$cacheKeyString]; + } + else { + $fields = array_merge(array('' => array('title' => ts('- Contact Fields -'))), + self::$_exportableFields[$cacheKeyString] + ); + } + + return $fields; + } + + /** + * Function to get the all contact details(Hierarchical) + * + * @param int $contactId contact id + * @param array $fields fields array + * + * @return $values array contains the contact details + * @static + * @access public + */ + static function getHierContactDetails($contactId, &$fields) { + $params = array(array('contact_id', '=', $contactId, 0, 0)); + $options = array(); + + $returnProperties = self::makeHierReturnProperties($fields, $contactId); + + // we dont know the contents of return properties, but we need the lower level ids of the contact + // so add a few fields + $returnProperties['first_name'] = + $returnProperties['organization_name'] = + $returnProperties['household_name'] = + $returnProperties['contact_type'] = + $returnProperties['contact_sub_type'] = 1; + return list($query, $options) = CRM_Contact_BAO_Query::apiQuery($params, $returnProperties, $options); + } + + /** + * given a set of flat profile style field names, create a hierarchy + * for query to use and crete the right sql + * + * @param array $properties a flat return properties name value array + * @param int $contactId contact id + * + * @return array a hierarchical property tree if appropriate + * @access public + * @static + */ + static function &makeHierReturnProperties($fields, $contactId = NULL) { + $locationTypes = CRM_Core_PseudoConstant::locationType(); + + $returnProperties = array(); + + $multipleFields = array('website' => 'url'); + foreach ($fields as $name => $dontCare) { + if (strpos($name, '-') !== FALSE) { + list($fieldName, $id, $type) = CRM_Utils_System::explode('-', $name, 3); + + if (!in_array($fieldName, $multipleFields)) { + if ($id == 'Primary') { + $locationTypeName = 1; + } + else { + $locationTypeName = CRM_Utils_Array::value($id, $locationTypes); + if (!$locationTypeName) { + continue; + } + } + + if (!CRM_Utils_Array::value('location', $returnProperties)) { + $returnProperties['location'] = array(); + } + if (!CRM_Utils_Array::value($locationTypeName, $returnProperties['location'])) { + $returnProperties['location'][$locationTypeName] = array(); + $returnProperties['location'][$locationTypeName]['location_type'] = $id; + } + if (in_array($fieldName, array( + 'phone', 'im', 'email', 'openid', 'phone_ext'))) { + if ($type) { + $returnProperties['location'][$locationTypeName][$fieldName . '-' . $type] = 1; + } + else { + $returnProperties['location'][$locationTypeName][$fieldName] = 1; + } + } + elseif (substr($fieldName, 0, 14) === 'address_custom') { + $returnProperties['location'][$locationTypeName][substr($fieldName, 8)] = 1; + } + else { + $returnProperties['location'][$locationTypeName][$fieldName] = 1; + } + } + else { + $returnProperties['website'][$id][$fieldName] = 1; + } + } + else { + $returnProperties[$name] = 1; + } + } + + return $returnProperties; + } + + /** + * Function to return the primary location type of a contact + * + * $params int $contactId contact_id + * $params boolean $isPrimaryExist if true, return primary contact location type otherwise null + * $params boolean $skipDefaultPriamry if true, return primary contact location type otherwise null + * + * @return int $locationType location_type_id + * @access public + * @static + */ + static function getPrimaryLocationType($contactId, $skipDefaultPriamry = FALSE, $block = NULL) { + if($block){ + $entityBlock = array('contact_id' => $contactId); + $blocks = CRM_Core_BAO_Location::getValues($entityBlock); + foreach($blocks[$block] as $key => $value){ + if (CRM_Utils_Array::value('is_primary', $value)){ + $locationType = CRM_Utils_Array::value('location_type_id',$value); + } + } + } + else { + $query = " +SELECT + IF ( civicrm_email.location_type_id IS NULL, + IF ( civicrm_address.location_type_id IS NULL, + IF ( civicrm_phone.location_type_id IS NULL, + IF ( civicrm_im.location_type_id IS NULL, + IF ( civicrm_openid.location_type_id IS NULL, null, civicrm_openid.location_type_id) + ,civicrm_im.location_type_id) + ,civicrm_phone.location_type_id) + ,civicrm_address.location_type_id) + ,civicrm_email.location_type_id) as locationType +FROM civicrm_contact + LEFT JOIN civicrm_email ON ( civicrm_email.is_primary = 1 AND civicrm_email.contact_id = civicrm_contact.id ) + LEFT JOIN civicrm_address ON ( civicrm_address.is_primary = 1 AND civicrm_address.contact_id = civicrm_contact.id) + LEFT JOIN civicrm_phone ON ( civicrm_phone.is_primary = 1 AND civicrm_phone.contact_id = civicrm_contact.id) + LEFT JOIN civicrm_im ON ( civicrm_im.is_primary = 1 AND civicrm_im.contact_id = civicrm_contact.id) + LEFT JOIN civicrm_openid ON ( civicrm_openid.is_primary = 1 AND civicrm_openid.contact_id = civicrm_contact.id) +WHERE civicrm_contact.id = %1 "; + + $params = array(1 => array($contactId, 'Integer')); + + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $locationType = NULL; + if ($dao->fetch()) { + $locationType = $dao->locationType; + } + } + if (isset($locationType)) { + return $locationType; + } + elseif ($skipDefaultPriamry) { + // if there is no primary contact location then return null + return NULL; + } + else { + // if there is no primart contact location, then return default + // location type of the system + $defaultLocationType = CRM_Core_BAO_LocationType::getDefault(); + return $defaultLocationType->id; + } + } + + /** + * function to get the display name, primary email and location type of a contact + * + * @param int $id id of the contact + * + * @return array of display_name, email if found, do_not_email or (null,null,null) + * @static + * @access public + */ + static function getContactDetails($id) { + // check if the contact type + $contactType = self::getContactType($id); + + $nameFields = ($contactType == 'Individual') ? "civicrm_contact.first_name, civicrm_contact.last_name, civicrm_contact.display_name" : "civicrm_contact.display_name"; + + $sql = " +SELECT $nameFields, civicrm_email.email, civicrm_contact.do_not_email, civicrm_email.on_hold, civicrm_contact.is_deceased +FROM civicrm_contact LEFT JOIN civicrm_email ON (civicrm_contact.id = civicrm_email.contact_id) +WHERE civicrm_contact.id = %1 +ORDER BY civicrm_email.is_primary DESC"; + $params = array(1 => array($id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + + if ($dao->fetch()) { + if ($contactType == 'Individual') { + if ($dao->first_name || $dao->last_name) { + $name = "{$dao->first_name} {$dao->last_name}"; + } + else { + $name = $dao->display_name; + } + } + else { + $name = $dao->display_name; + } + $email = $dao->email; + $doNotEmail = $dao->do_not_email ? TRUE : FALSE; + $onHold = $dao->on_hold ? TRUE : FALSE; + $isDeceased = $dao->is_deceased ? TRUE : FALSE; + return array($name, $email, $doNotEmail, $onHold, $isDeceased); + } + return array(NULL, NULL, NULL, NULL, NULL); + } + + /** + * function to add/edit/register contacts through profile. + * + * @params array $params Array of profile fields to be edited/added. + * @params int $contactID contact_id of the contact to be edited/added. + * @params array $fields array of fields from UFGroup + * @params int $addToGroupID specifies the default group to which contact is added. + * @params int $ufGroupId uf group id (profile id) + * @param string $ctype contact type + * @param boolean $visibility basically lets us know where this request is coming from + * if via a profile from web, we restrict what groups are changed + * + * @return int contact id created/edited + * @static + * @access public + */ + static function createProfileContact( + &$params, + &$fields, + $contactID = NULL, + $addToGroupID = NULL, + $ufGroupId = NULL, + $ctype = NULL, + $visibility = FALSE + ) { + // add ufGroupID to params array ( CRM-2012 ) + if ($ufGroupId) { + $params['uf_group_id'] = $ufGroupId; + } + + if ($contactID) { + $editHook = TRUE; + CRM_Utils_Hook::pre('edit', 'Profile', $contactID, $params); + } + else { + $editHook = FALSE; + CRM_Utils_Hook::pre('create', 'Profile', NULL, $params); + } + + list($data, $contactDetails) = self::formatProfileContactParams($params, $fields, $contactID, $ufGroupId, $ctype); + + // manage is_opt_out + if (array_key_exists('is_opt_out', $fields) && array_key_exists('is_opt_out', $params)) { + $wasOptOut = CRM_Utils_Array::value('is_opt_out', $contactDetails, FALSE); + $isOptOut = CRM_Utils_Array::value('is_opt_out', $params, FALSE); + $data['is_opt_out'] = $isOptOut; + // on change, create new civicrm_subscription_history entry + if (($wasOptOut != $isOptOut) && + CRM_Utils_Array::value('contact_id', $contactDetails) + ) { + $shParams = array( + 'contact_id' => $contactDetails['contact_id'], + 'status' => $isOptOut ? 'Removed' : 'Added', + 'method' => 'Web', + ); + CRM_Contact_BAO_SubscriptionHistory::create($shParams); + } + } + + $contact = self::create($data); + + // contact is null if the profile does not have any contact fields + if ($contact) { + $contactID = $contact->id; + } + + if (empty($contactID)) { + CRM_Core_Error::fatal('Cannot proceed without a valid contact id'); + } + + // Process group and tag + if (CRM_Utils_Array::value('group', $fields)) { + $method = 'Admin'; + // this for sure means we are coming in via profile since i added it to fix + // removing contacts from user groups -- lobo + if ($visibility) { + $method = 'Web'; + } + CRM_Contact_BAO_GroupContact::create($params['group'], $contactID, $visibility, $method); + } + + if (CRM_Utils_Array::value('tag', $fields)) { + CRM_Core_BAO_EntityTag::create($params['tag'], 'civicrm_contact', $contactID); + } + + //to add profile in default group + if (is_array($addToGroupID)) { + $contactIds = array($contactID); + foreach ($addToGroupID as $groupId) { + CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId); + } + } + elseif ($addToGroupID) { + $contactIds = array($contactID); + CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $addToGroupID); + } + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + + if ($editHook) { + CRM_Utils_Hook::post('edit', 'Profile', $contactID, $params); + } + else { + CRM_Utils_Hook::post('create', 'Profile', $contactID, $params); + } + return $contactID; + } + + static function formatProfileContactParams( + &$params, + &$fields, + $contactID = NULL, + $ufGroupId = NULL, + $ctype = NULL, + $skipCustom = FALSE + ) { + + $data = $contactDetails = array(); + + // get the contact details (hier) + if ($contactID) { + list($details, $options) = self::getHierContactDetails($contactID, $fields); + + $contactDetails = $details[$contactID]; + $data['contact_type'] = CRM_Utils_Array::value('contact_type', $contactDetails); + $data['contact_sub_type'] = CRM_Utils_Array::value('contact_sub_type', $contactDetails); + } + else { + //we should get contact type only if contact + if ($ufGroupId) { + $data['contact_type'] = CRM_Core_BAO_UFField::getProfileType($ufGroupId); + + //special case to handle profile with only contact fields + if ($data['contact_type'] == 'Contact') { + $data['contact_type'] = 'Individual'; + } + elseif (CRM_Contact_BAO_ContactType::isaSubType($data['contact_type'])) { + $data['contact_type'] = CRM_Contact_BAO_ContactType::getBasicType($data['contact_type']); + } + } + elseif ($ctype) { + $data['contact_type'] = $ctype; + } + else { + $data['contact_type'] = 'Individual'; + } + } + + //fix contact sub type CRM-5125 + if (array_key_exists('contact_sub_type', $params) && + !empty($params['contact_sub_type']) + ) { + $data['contact_sub_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, (array)$params['contact_sub_type']) . CRM_Core_DAO::VALUE_SEPARATOR; + } + elseif (array_key_exists('contact_sub_type_hidden', $params) && + !empty($params['contact_sub_type_hidden']) + ) { + // if profile was used, and had any subtype, we obtain it from there + $data['contact_sub_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, (array)$params['contact_sub_type_hidden']) . CRM_Core_DAO::VALUE_SEPARATOR; + } + + if ($ctype == 'Organization') { + $data['organization_name'] = CRM_Utils_Array::value('organization_name', $contactDetails); + } + elseif ($ctype == 'Household') { + $data['household_name'] = CRM_Utils_Array::value('household_name', $contactDetails); + } + + $locationType = array(); + $count = 1; + + if ($contactID) { + //add contact id + $data['contact_id'] = $contactID; + $primaryLocationType = self::getPrimaryLocationType($contactID); + } + else { + $defaultLocation = CRM_Core_BAO_LocationType::getDefault(); + $defaultLocationId = $defaultLocation->id; + } + + // get the billing location type + $locationTypes = CRM_Core_PseudoConstant::locationType(); + $billingLocationTypeId = array_search('Billing', $locationTypes); + + $blocks = array('email', 'phone', 'im', 'openid'); + + $multiplFields = array('url'); + // prevent overwritten of formatted array, reset all block from + // params if it is not in valid format (since import pass valid format) + foreach ($blocks as $blk) { + if (array_key_exists($blk, $params) && + !is_array($params[$blk]) + ) { + unset($params[$blk]); + } + } + + $primaryPhoneLoc = NULL; + foreach ($params as $key => $value) { + $fieldName = $locTypeId = $typeId = NULL; + list($fieldName, $locTypeId, $typeId) = CRM_Utils_System::explode('-', $key, 3); + + //store original location type id + $actualLocTypeId = $locTypeId; + + if ($locTypeId == 'Primary') { + if ($contactID) { + if(in_array( $fieldName, $blocks)){ + $locTypeId = self::getPrimaryLocationType($contactID, FALSE, $fieldName); + } + else{ + $locTypeId = self::getPrimaryLocationType($contactID, FALSE, 'address'); + } + $primaryLocationType = $locTypeId; + } + else { + $locTypeId = $defaultLocationId; + } + } + + if (is_numeric($locTypeId) && + !in_array($fieldName, $multiplFields) && + substr($fieldName, 0, 7) != 'custom_' + ) { + $index = $locTypeId; + + if (is_numeric($typeId)) { + $index .= '-' . $typeId; + } + if (!in_array($index, $locationType)) { + $locationType[$count] = $index; + $count++; + } + + $loc = CRM_Utils_Array::key($index, $locationType); + + $blockName = in_array( $fieldName, $blocks) ? $fieldName : 'address'; + + $data[$blockName][$loc]['location_type_id'] = $locTypeId; + + //set is_billing true, for location type "Billing" + if ($locTypeId == $billingLocationTypeId) { + $data[$blockName][$loc]['is_billing'] = 1; + } + + if ($contactID) { + //get the primary location type + if ($locTypeId == $primaryLocationType) { + $data[$blockName][$loc]['is_primary'] = 1; + } + } + elseif ($locTypeId == $defaultLocationId) { + $data[$blockName][$loc]['is_primary'] = 1; + } + + if ( in_array($fieldName, array('phone'))) { + if ($typeId) { + $data['phone'][$loc]['phone_type_id'] = $typeId; + } + else { + $data['phone'][$loc]['phone_type_id'] = ''; + } + $data['phone'][$loc]['phone'] = $value; + + //special case to handle primary phone with different phone types + // in this case we make first phone type as primary + if (isset($data['phone'][$loc]['is_primary']) && !$primaryPhoneLoc) { + $primaryPhoneLoc = $loc; + } + + if ($loc != $primaryPhoneLoc) { + unset($data['phone'][$loc]['is_primary']); + } + } + elseif ($fieldName == 'phone_ext') { + $data['phone'][$loc]['phone_ext'] = $value; + } + elseif ($fieldName == 'email') { + $data['email'][$loc]['email'] = $value; + } + elseif ($fieldName == 'im') { + if (isset($params[$key . '-provider_id'])) { + $data['im'][$loc]['provider_id'] = $params[$key . '-provider_id']; + } + if (strpos($key, '-provider_id') !== FALSE) { + $data['im'][$loc]['provider_id'] = $params[$key]; + } + else { + $data['im'][$loc]['name'] = $value; + } + } + elseif ($fieldName == 'openid') { + $data['openid'][$loc]['openid'] = $value; + } + else { + if ($fieldName === 'state_province') { + // CRM-3393 + if (is_numeric($value) && ((int ) $value) >= 1000) { + $data['address'][$loc]['state_province_id'] = $value; + } + elseif (empty($value)) { + $data['address'][$loc]['state_province_id'] = ''; + } + else { + $data['address'][$loc]['state_province'] = $value; + } + } + elseif ($fieldName === 'country') { + // CRM-3393 + if (is_numeric($value) && ((int ) $value) >= 1000 + ) { + $data['address'][$loc]['country_id'] = $value; + } + elseif (empty($value)) { + $data['address'][$loc]['country_id'] = ''; + } + else { + $data['address'][$loc]['country'] = $value; + } + } + elseif ($fieldName === 'county') { + $data['address'][$loc]['county_id'] = $value; + } + elseif ($fieldName == 'address_name') { + $data['address'][$loc]['name'] = $value; + } + elseif (substr($fieldName, 0, 14) === 'address_custom') { + $data['address'][$loc][substr($fieldName, 8)] = $value; + } + else { + $data['address'][$loc][$fieldName] = $value; + } + } + } + else { + if (substr($key, 0, 4) === 'url-') { + $websiteField = explode('-', $key); + if (isset($websiteField[2])) { + $data['website'][$websiteField[1]]['website_type_id'] = $value; + } + else { + $data['website'][$websiteField[1]]['url'] = $value; + } + } + elseif ($key === 'individual_suffix') { + $data['suffix_id'] = $value; + } + elseif ($key === 'individual_prefix') { + $data['prefix_id'] = $value; + } + elseif ($key === 'gender') { + $data['gender_id'] = $value; + } + //save email/postal greeting and addressee values if any, CRM-4575 + elseif (in_array($key, self::$_greetingTypes, TRUE)) { + $data[$key . '_id'] = $value; + } + elseif (!$skipCustom && ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($key))) { + // for autocomplete transfer hidden value instead of label + if ($params[$key] && isset($params[$key . '_id'])) { + $value = $params[$key . '_id']; + } + + // we need to append time with date + if ($params[$key] && isset($params[$key . '_time'])) { + $value .= ' ' . $params[$key . '_time']; + } + + $valueId = NULL; + if (CRM_Utils_Array::value('customRecordValues', $params)) { + if (is_array($params['customRecordValues']) && !empty($params['customRecordValues'])) { + foreach ($params['customRecordValues'] as $recId => $customFields) { + if (is_array($customFields) && !empty($customFields)) { + foreach ($customFields as $customFieldName) { + if ($customFieldName == $key) { + $valueId = $recId; + break; + } + } + } + } + } + } + + $type = $data['contact_type']; + if ( CRM_Utils_Array::value('contact_sub_type', $data) ) { + $type = $data['contact_sub_type']; + $type = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($type, CRM_Core_DAO::VALUE_SEPARATOR)); + // generally a contact even if, has multiple subtypes the parent-type is going to be one only + // and since formatCustomField() would be interested in parent type, lets consider only one subtype + // as the results going to be same. + $type = $type[0]; + } + + CRM_Core_BAO_CustomField::formatCustomField($customFieldId, + $data['custom'], + $value, + $type, + $valueId, + $contactID + ); + } + elseif ($key == 'edit') { + continue; + } + else { + if ($key == 'location') { + foreach ($value as $locationTypeId => $field) { + foreach ($field as $block => $val) { + if ($block == 'address' && array_key_exists('address_name', $val)) { + $value[$locationTypeId][$block]['name'] = $value[$locationTypeId][$block]['address_name']; + } + } + } + } + if($key == 'phone' && isset($params['phone_ext'])){ + $data[$key] = $value; + foreach($value as $cnt => $phoneBlock){ + if($params[$key][$cnt]['location_type_id'] == $params['phone_ext'][$cnt]['location_type_id']){ + $data[$key][$cnt]['phone_ext'] = CRM_Utils_Array::retrieveValueRecursive($params['phone_ext'][$cnt], 'phone_ext'); + } + } + } + else { + $data[$key] = $value; + } + } + } + } + + if (!isset($data['contact_type'])) { + $data['contact_type'] = 'Individual'; + } + + //set the values for checkboxes (do_not_email, do_not_mail, do_not_trade, do_not_phone) + $privacy = CRM_Core_SelectValues::privacy(); + foreach ($privacy as $key => $value) { + if (array_key_exists($key, $fields)) { + if (array_key_exists($key, $params)) { + $data[$key] = $params[$key]; + // dont reset it for existing contacts + } + elseif (!$contactID) { + $data[$key] = 0; + } + } + } + + return array($data, $contactDetails); + } + + /** + * Function to find the get contact details + * does not respect ACLs for now, which might need to be rectified at some + * stage based on how its used + * + * @param string $mail primary email address of the contact + * @param string $ctype contact type + * + * @return object $dao contact details + * @static + */ + static function &matchContactOnEmail($mail, $ctype = NULL) { + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + $mail = $strtolower(trim($mail)); + $query = " +SELECT civicrm_contact.id as contact_id, + civicrm_contact.hash as hash, + civicrm_contact.contact_type as contact_type, + civicrm_contact.contact_sub_type as contact_sub_type +FROM civicrm_contact +INNER JOIN civicrm_email ON ( civicrm_contact.id = civicrm_email.contact_id )"; + + + if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'uniq_email_per_site' + )) { + // try to find a match within a site (multisite). + $groups = CRM_Core_BAO_Domain::getChildGroupIds(); + if (!empty($groups)) { + $query .= " +INNER JOIN civicrm_group_contact gc ON +(civicrm_contact.id = gc.contact_id AND gc.status = 'Added' AND gc.group_id IN (" . implode(',', $groups) . "))"; + } + } + + $query .= " +WHERE civicrm_email.email = %1 AND civicrm_contact.is_deleted=0"; + $p = array(1 => array($mail, 'String')); + + if ($ctype) { + $query .= " AND civicrm_contact.contact_type = %3"; + $p[3] = array($ctype, 'String'); + } + + $query .= " ORDER BY civicrm_email.is_primary DESC"; + + $dao = CRM_Core_DAO::executeQuery($query, $p); + + if ($dao->fetch()) { + return $dao; + } + return CRM_Core_DAO::$_nullObject; + } + + /** + * Function to find the contact details associated with an OpenID + * + * @param string $openId openId of the contact + * @param string $ctype contact type + * + * @return object $dao contact details + * @static + */ + static function &matchContactOnOpenId($openId, $ctype = NULL) { + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + $openId = $strtolower(trim($openId)); + $query = " +SELECT civicrm_contact.id as contact_id, + civicrm_contact.hash as hash, + civicrm_contact.contact_type as contact_type, + civicrm_contact.contact_sub_type as contact_sub_type +FROM civicrm_contact +INNER JOIN civicrm_openid ON ( civicrm_contact.id = civicrm_openid.contact_id ) +WHERE civicrm_openid.openid = %1"; + $p = array(1 => array($openId, 'String')); + + if ($ctype) { + $query .= " AND civicrm_contact.contact_type = %3"; + $p[3] = array($ctype, 'String'); + } + + $query .= " ORDER BY civicrm_openid.is_primary DESC"; + + $dao = CRM_Core_DAO::executeQuery($query, $p); + + if ($dao->fetch()) { + return $dao; + } + return CRM_Core_DAO::$_nullObject; + } + + /** + * Funtion to get primary email of the contact + * + * @param int $contactID contact id + * + * @return string $dao->email email address if present else null + * @static + * @access public + */ + public static function getPrimaryEmail($contactID) { + // fetch the primary email + $query = " + SELECT civicrm_email.email as email + FROM civicrm_contact +LEFT JOIN civicrm_email ON ( civicrm_contact.id = civicrm_email.contact_id ) + WHERE civicrm_email.is_primary = 1 + AND civicrm_contact.id = %1"; + $p = array(1 => array($contactID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $p); + + $email = NULL; + if ($dao->fetch()) { + $email = $dao->email; + } + $dao->free(); + return $email; + } + + /** + * Funtion to get primary OpenID of the contact + * + * @param int $contactID contact id + * + * @return string $dao->openid OpenID if present else null + * @static + * @access public + */ + public static function getPrimaryOpenId($contactID) { + // fetch the primary OpenID + $query = " +SELECT civicrm_openid.openid as openid +FROM civicrm_contact +LEFT JOIN civicrm_openid ON ( civicrm_contact.id = civicrm_openid.contact_id ) +WHERE civicrm_contact.id = %1 +AND civicrm_openid.is_primary = 1"; + $p = array(1 => array($contactID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $p); + + $openId = NULL; + if ($dao->fetch()) { + $openId = $dao->openid; + } + $dao->free(); + return $openId; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $params input parameters to find object + * @param array $values output values of the object + * + * @return CRM_Contact_BAO_Contact|null the found object or null + * @access public + * @static + */ + public static function getValues(&$params, &$values) { + $contact = new CRM_Contact_BAO_Contact(); + + $contact->copyValues($params); + + if ($contact->find(TRUE)) { + + CRM_Core_DAO::storeValues($contact, $values); + + $privacy = array(); + foreach (self::$_commPrefs as $name) { + if (isset($contact->$name)) { + $privacy[$name] = $contact->$name; + } + } + + if (!empty($privacy)) { + $values['privacy'] = $privacy; + } + + // communication Prefferance + $preffComm = $comm = array(); + $comm = explode(CRM_Core_DAO::VALUE_SEPARATOR, + $contact->preferred_communication_method + ); + foreach ($comm as $value) { + $preffComm[$value] = 1; + } + $temp = array('preferred_communication_method' => $contact->preferred_communication_method); + + $names = array( + 'preferred_communication_method' => array('newName' => 'preferred_communication_method_display', + 'groupName' => 'preferred_communication_method', + )); + + CRM_Core_OptionGroup::lookupValues($temp, $names, FALSE); + + $values['preferred_communication_method'] = $preffComm; + $values['preferred_communication_method_display'] = CRM_Utils_Array::value('preferred_communication_method_display', $temp); + + CRM_Contact_DAO_Contact::addDisplayEnums($values); + + // get preferred languages + if (!empty($contact->preferred_language)) { + $languages = CRM_Core_PseudoConstant::languages(); + $values['preferred_language'] = CRM_Utils_Array::value($contact->preferred_language, $languages); + } + + // Calculating Year difference + if ($contact->birth_date) { + $birthDate = CRM_Utils_Date::customFormat($contact->birth_date, '%Y%m%d'); + if ($birthDate < date('Ymd')) { + $age = CRM_Utils_Date::calculateAge($birthDate); + $values['age']['y'] = CRM_Utils_Array::value('years', $age); + $values['age']['m'] = CRM_Utils_Array::value('months', $age); + } + + list($values['birth_date']) = CRM_Utils_Date::setDateDefaults($contact->birth_date, 'birth'); + $values['birth_date_display'] = $contact->birth_date; + } + + if ($contact->deceased_date) { + list($values['deceased_date']) = CRM_Utils_Date::setDateDefaults($contact->deceased_date, 'birth'); + $values['deceased_date_display'] = $contact->deceased_date; + } + + $contact->contact_id = $contact->id; + + return $contact; + } + return NULL; + } + + /** + * Given the component name and returns + * the count of participation of contact + * + * @param string $component input component name + * @param integer $contactId input contact id + * @param string $tableName optional tableName if component is custom group + * + * @return total number of count of occurence in database + * @access public + * @static + */ + static function getCountComponent($component, $contactId, $tableName = NULL) { + $object = NULL; + switch ($component) { + case 'tag': + return CRM_Core_BAO_EntityTag::getContactTags($contactId, TRUE); + + case 'rel': + return CRM_Contact_BAO_Relationship::getRelationship($contactId, + CRM_Contact_BAO_Relationship::CURRENT, + 0, 1 + ); + + case 'group': + return CRM_Contact_BAO_GroupContact::getContactGroup($contactId, "Added", NULL, TRUE); + + case 'log': + if (CRM_Core_BAO_Log::useLoggingReport()) { + return FALSE; + } + return CRM_Core_BAO_Log::getContactLogCount($contactId); + + case 'note': + return CRM_Core_BAO_Note::getContactNoteCount($contactId); + + case 'contribution': + return CRM_Contribute_BAO_Contribution::contributionCount($contactId); + + case 'membership': + return CRM_Member_BAO_Membership::getContactMembershipCount($contactId, TRUE); + + case 'participant': + return CRM_Event_BAO_Participant::getContactParticipantCount($contactId); + + case 'pledge': + return CRM_Pledge_BAO_Pledge::getContactPledgeCount($contactId); + + case 'case': + return CRM_Case_BAO_Case::caseCount($contactId); + + case 'grant': + return CRM_Grant_BAO_Grant::getContactGrantCount($contactId); + + case 'activity': + $input = array( + 'contact_id' => $contactId, + 'admin' => FALSE, + 'caseId' => NULL, + 'context' => 'activity', + ); + return CRM_Activity_BAO_Activity::getActivitiesCount($input); + + default: + $custom = explode('_', $component); + if ($custom['0'] = 'custom') { + if (!$tableName) { + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $custom['1'], 'table_name'); + } + $queryString = "SELECT count(id) FROM {$tableName} WHERE entity_id = {$contactId}"; + return CRM_Core_DAO::singleValueQuery($queryString); + } + } + } + + /** + * Function to process greetings and cache + * + * @param object $contact contact object after save + * @param boolean $useDefaults use default greeting values + * + * @return void + * @access public + * @static + */ + static function processGreetings(&$contact, $useDefaults = FALSE) { + if ($useDefaults) { + //retrieve default greetings + $defaultGreetings = CRM_Core_PseudoConstant::greetingDefaults(); + $contactDefaults = $defaultGreetings[$contact->contact_type]; + } + + // note that contact object not always has required greeting related + // fields that are required to calculate greeting and + // also other fields used in tokens etc, + // hence we need to retrieve it again. + $contact->find(TRUE); + + // store object values to an array + $contactDetails = array(); + CRM_Core_DAO::storeValues($contact, $contactDetails); + $contactDetails = array(array($contact->id => $contactDetails)); + + $emailGreetingString = $postalGreetingString = $addresseeString = NULL; + $updateQueryString = array(); + + //cache email and postal greeting to greeting display + if ($contact->email_greeting_custom != 'null' && $contact->email_greeting_custom) { + $emailGreetingString = $contact->email_greeting_custom; + } + elseif ($contact->email_greeting_id != 'null' && $contact->email_greeting_id) { + // the filter value for Individual contact type is set to 1 + $filter = array( + 'contact_type' => $contact->contact_type, + 'greeting_type' => 'email_greeting', + ); + + $emailGreeting = CRM_Core_PseudoConstant::greeting($filter); + $emailGreetingString = $emailGreeting[$contact->email_greeting_id]; + $updateQueryString[] = " email_greeting_custom = NULL "; + } + else { + if ($useDefaults) { + reset($contactDefaults['email_greeting']); + $emailGreetingID = key($contactDefaults['email_greeting']); + $emailGreetingString = $contactDefaults['email_greeting'][$emailGreetingID]; + $updateQueryString[] = " email_greeting_id = $emailGreetingID "; + $updateQueryString[] = " email_greeting_custom = NULL "; + } + elseif ($contact->email_greeting_custom) { + $updateQueryString[] = " email_greeting_display = NULL "; + } + } + + if ($emailGreetingString) { + CRM_Utils_Token::replaceGreetingTokens($emailGreetingString, + $contactDetails, + $contact->id, + 'CRM_Contact_BAO_Contact' + ); + $emailGreetingString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($emailGreetingString)); + $updateQueryString[] = " email_greeting_display = '{$emailGreetingString}'"; + } + + //postal greetings + if ($contact->postal_greeting_custom != 'null' && $contact->postal_greeting_custom) { + $postalGreetingString = $contact->postal_greeting_custom; + } + elseif ($contact->postal_greeting_id != 'null' && $contact->postal_greeting_id) { + $filter = array( + 'contact_type' => $contact->contact_type, + 'greeting_type' => 'postal_greeting', + ); + $postalGreeting = CRM_Core_PseudoConstant::greeting($filter); + $postalGreetingString = $postalGreeting[$contact->postal_greeting_id]; + $updateQueryString[] = " postal_greeting_custom = NULL "; + } + else { + if ($useDefaults) { + reset($contactDefaults['postal_greeting']); + $postalGreetingID = key($contactDefaults['postal_greeting']); + $postalGreetingString = $contactDefaults['postal_greeting'][$postalGreetingID]; + $updateQueryString[] = " postal_greeting_id = $postalGreetingID "; + $updateQueryString[] = " postal_greeting_custom = NULL "; + } + elseif ($contact->postal_greeting_custom) { + $updateQueryString[] = " postal_greeting_display = NULL "; + } + } + + if ($postalGreetingString) { + CRM_Utils_Token::replaceGreetingTokens($postalGreetingString, + $contactDetails, + $contact->id, + 'CRM_Contact_BAO_Contact' + ); + $postalGreetingString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($postalGreetingString)); + $updateQueryString[] = " postal_greeting_display = '{$postalGreetingString}'"; + } + + // addressee + if ($contact->addressee_custom != 'null' && $contact->addressee_custom) { + $addresseeString = $contact->addressee_custom; + } + elseif ($contact->addressee_id != 'null' && $contact->addressee_id) { + $filter = array( + 'contact_type' => $contact->contact_type, + 'greeting_type' => 'addressee', + ); + + $addressee = CRM_Core_PseudoConstant::greeting($filter); + $addresseeString = $addressee[$contact->addressee_id]; + $updateQueryString[] = " addressee_custom = NULL "; + } + else { + if ($useDefaults) { + reset($contactDefaults['addressee']); + $addresseeID = key($contactDefaults['addressee']); + $addresseeString = $contactDefaults['addressee'][$addresseeID]; + $updateQueryString[] = " addressee_id = $addresseeID "; + $updateQueryString[] = " addressee_custom = NULL "; + } + elseif ($contact->addressee_custom) { + $updateQueryString[] = " addressee_display = NULL "; + } + } + + if ($addresseeString) { + CRM_Utils_Token::replaceGreetingTokens($addresseeString, + $contactDetails, + $contact->id, + 'CRM_Contact_BAO_Contact' + ); + $addresseeString = CRM_Core_DAO::escapeString(CRM_Utils_String::stripSpaces($addresseeString)); + $updateQueryString[] = " addressee_display = '{$addresseeString}'"; + } + + if (!empty($updateQueryString)) { + $updateQueryString = implode(',', $updateQueryString); + $queryString = "UPDATE civicrm_contact SET {$updateQueryString} WHERE id = {$contact->id}"; + CRM_Core_DAO::executeQuery($queryString); + } + } + + /** + * Function to retrieve loc block ids w/ given condition. + * + * @param int $contactId contact id. + * @param array $criteria key => value pair which should be + * fulfill by return record ids. + * @param string $condOperator operator use for grouping multiple conditions. + * + * @return array $locBlockIds loc block ids which fulfill condition. + * @static + */ + static function getLocBlockIds($contactId, $criteria = array( + ), $condOperator = 'AND') { + $locBlockIds = array(); + if (!$contactId) { + return $locBlockIds; + } + + foreach (array( + 'Email', 'OpenID', 'Phone', 'Address', 'IM') as $block) { + $name = strtolower($block); + eval("\$blockDAO = new CRM_Core_DAO_$block();"); + + // build the condition. + if (is_array($criteria)) { + eval('$object = new CRM_Core_DAO_' . $block . '( );'); + $fields = $object->fields(); + $conditions = array(); + foreach ($criteria as $field => $value) { + if (array_key_exists($field, $fields)) { + $cond = "( $field = $value )"; + // value might be zero or null. + if (!$value || strtolower($value) == 'null') { + $cond = "( $field = 0 OR $field IS NULL )"; + } + $conditions[] = $cond; + } + } + if (!empty($conditions)) { + $blockDAO->whereAdd(implode(" $condOperator ", $conditions)); + } + } + + $blockDAO->contact_id = $contactId; + $blockDAO->find(); + while ($blockDAO->fetch()) { + $locBlockIds[$name][] = $blockDAO->id; + } + $blockDAO->free(); + } + + return $locBlockIds; + } + + /** + * Function to build context menu items. + * + * @return array of context menu for logged in user. + * @static + */ + static function contextMenu($contactId = NULL) { + $menu = array( + 'view' => array('title' => ts('View Contact'), + 'weight' => 0, + 'ref' => 'view-contact', + 'key' => 'view', + 'permissions' => array('view all contacts'), + ), + 'add' => array('title' => ts('Edit Contact'), + 'weight' => 0, + 'ref' => 'edit-contact', + 'key' => 'add', + 'permissions' => array('edit all contacts'), + ), + 'delete' => array('title' => ts('Delete Contact'), + 'weight' => 0, + 'ref' => 'delete-contact', + 'key' => 'delete', + 'permissions' => array('access deleted contacts', 'delete contacts'), + ), + 'contribution' => array('title' => ts('Add Contribution'), + 'weight' => 5, + 'ref' => 'new-contribution', + 'key' => 'contribution', + 'component' => 'CiviContribute', + 'href' => CRM_Utils_System::url('civicrm/contact/view/contribution', + 'reset=1&action=add&context=contribution' + ), + 'permissions' => array( + 'access CiviContribute', + 'edit contributions', + ), + ), + 'participant' => array('title' => ts('Register for Event'), + 'weight' => 10, + 'ref' => 'new-participant', + 'key' => 'participant', + 'component' => 'CiviEvent', + 'href' => CRM_Utils_System::url('civicrm/contact/view/participant', 'reset=1&action=add&context=participant'), + 'permissions' => array( + 'access CiviEvent', + 'edit event participants', + ), + ), + 'activity' => array('title' => ts('Record Activity'), + 'weight' => 35, + 'ref' => 'new-activity', + 'key' => 'activity', + 'permissions' => array('edit all contacts'), + ), + 'pledge' => array('title' => ts('Add Pledge'), + 'weight' => 15, + 'ref' => 'new-pledge', + 'key' => 'pledge', + 'href' => CRM_Utils_System::url('civicrm/contact/view/pledge', + 'reset=1&action=add&context=pledge' + ), + 'component' => 'CiviPledge', + 'permissions' => array( + 'access CiviPledge', + 'edit pledges', + ), + ), + 'membership' => array('title' => ts('Add Membership'), + 'weight' => 20, + 'ref' => 'new-membership', + 'key' => 'membership', + 'component' => 'CiviMember', + 'href' => CRM_Utils_System::url('civicrm/contact/view/membership', + 'reset=1&action=add&context=membership' + ), + 'permissions' => array( + 'access CiviMember', + 'edit memberships', + ), + ), + 'case' => array('title' => ts('Add Case'), + 'weight' => 25, + 'ref' => 'new-case', + 'key' => 'case', + 'component' => 'CiviCase', + 'href' => CRM_Utils_System::url('civicrm/case/add', 'reset=1&action=add&context=case'), + 'permissions' => array('add cases'), + ), + 'grant' => array('title' => ts('Add Grant'), + 'weight' => 26, + 'ref' => 'new-grant', + 'key' => 'grant', + 'component' => 'CiviGrant', + 'href' => CRM_Utils_System::url('civicrm/contact/view/grant', + 'reset=1&action=add&context=grant' + ), + 'permissions' => array('edit grants'), + ), + 'rel' => array('title' => ts('Add Relationship'), + 'weight' => 30, + 'ref' => 'new-relationship', + 'key' => 'rel', + 'href' => CRM_Utils_System::url('civicrm/contact/view/rel', + 'reset=1&action=add' + ), + 'permissions' => array('edit all contacts'), + ), + 'note' => array('title' => ts('Add Note'), + 'weight' => 40, + 'ref' => 'new-note', + 'key' => 'note', + 'href' => CRM_Utils_System::url('civicrm/contact/view/note', + 'reset=1&action=add' + ), + 'permissions' => array('edit all contacts'), + ), + 'email' => array('title' => ts('Send an Email'), + 'weight' => 45, + 'ref' => 'new-email', + 'key' => 'email', + 'permissions' => array('view all contacts'), + ), + 'group' => array('title' => ts('Add to Group'), + 'weight' => 50, + 'ref' => 'group-add-contact', + 'key' => 'group', + 'permissions' => array('edit groups'), + ), + 'tag' => array('title' => ts('Tag'), + 'weight' => 55, + 'ref' => 'tag-contact', + 'key' => 'tag', + 'permissions' => array('edit all contacts'), + ), + ); + + CRM_Utils_Hook::summaryActions($menu, $contactId); + //1. check for component is active. + //2. check for user permissions. + //3. check for acls. + //3. edit and view contact are directly accessible to user. + + $aclPermissionedTasks = array( + 'view-contact', 'edit-contact', 'new-activity', + 'new-email', 'group-add-contact', 'tag-contact', 'delete-contact', + ); + $corePermission = CRM_Core_Permission::getPermission(); + + $config = CRM_Core_Config::singleton(); + + $contextMenu = array(); + foreach ($menu as $key => $values) { + $componentName = CRM_Utils_Array::value('component', $values); + + // if component action - make sure component is enable. + if ($componentName && !in_array($componentName, $config->enableComponents)) { + continue; + } + + // make sure user has all required permissions. + $hasAllPermissions = FALSE; + + $permissions = CRM_Utils_Array::value('permissions', $values); + if (!is_array($permissions) || empty($permissions)) { + $hasAllPermissions = TRUE; + } + + // iterate for required permissions in given permissions array. + if (!$hasAllPermissions) { + $hasPermissions = 0; + foreach ($permissions as $permission) { + if (CRM_Core_Permission::check($permission)) { + $hasPermissions++; + } + } + + if (count($permissions) == $hasPermissions) { + $hasAllPermissions = TRUE; + } + + // if still user does not have required permissions, check acl. + if (!$hasAllPermissions && $values['ref'] != 'delete-contact') { + if (in_array($values['ref'], $aclPermissionedTasks) && + $corePermission == CRM_Core_Permission::EDIT + ) { + $hasAllPermissions = TRUE; + } + elseif (in_array($values['ref'], array( + 'new-email'))) { + // grant permissions for these tasks. + $hasAllPermissions = TRUE; + } + } + } + + // user does not have necessary permissions. + if (!$hasAllPermissions) { + continue; + } + + // build directly accessible action menu. + if (in_array($values['ref'], array( + 'view-contact', 'edit-contact'))) { + $contextMenu['primaryActions'][$key] = array( + 'title' => $values['title'], + 'ref' => $values['ref'], + 'key' => $values['key'], + ); + continue; + } + + // finally get menu item for -more- action widget. + $contextMenu['moreActions'][$values['weight']] = array( + 'title' => $values['title'], + 'ref' => $values['ref'], + 'href' => CRM_Utils_Array::value('href', $values), + 'key' => $values['key'], + ); + } + + ksort($contextMenu['moreActions']); + + return $contextMenu; + } + + /** + * Function to retrieve display name of contact that address is shared + * based on $masterAddressId or $contactId . + * + * @param int $masterAddressId master id. + * @param int $contactId contact id. + * + * @return display name |null the found display name or null. + * @access public + * @static + */ + static function getMasterDisplayName($masterAddressId = NULL, $contactId = NULL) { + $masterDisplayName = NULL; + $sql = NULL; + if (!$masterAddressId && !$contactId) { + return $masterDisplayName; + } + + if ($masterAddressId) { + $sql = " + SELECT display_name from civicrm_contact +LEFT JOIN civicrm_address ON ( civicrm_address.contact_id = civicrm_contact.id ) + WHERE civicrm_address.id = " . $masterAddressId; + } + elseif ($contactId) { + $sql = " + SELECT display_name from civicrm_contact cc, civicrm_address add1 +LEFT JOIN civicrm_address add2 ON ( add1.master_id = add2.id ) + WHERE cc.id = add2.contact_id AND add1.contact_id = " . $contactId; + } + + $masterDisplayName = CRM_Core_DAO::singleValueQuery($sql); + return $masterDisplayName; + } + + /** + * Get the creation/modification times for a contact + * + * @return array('created_date' => $, 'modified_date' => $) + */ + static function getTimestamps($contactId) { + $timestamps = CRM_Core_DAO::executeQuery( + 'SELECT created_date, modified_date + FROM civicrm_contact + WHERE id = %1', + array( + 1 => array($contactId, 'Integer'), + ) + ); + if ($timestamps->fetch()) { + return array( + 'created_date' => $timestamps->created_date, + 'modified_date' => $timestamps->modified_date, + ); + } + else { + return NULL; + } + } + + /** + * Get a list of triggers for the contact table + * + * @see hook_civicrm_triggerInfo + * @see CRM_Core_DAO::triggerRebuild + * @see http://issues.civicrm.org/jira/browse/CRM-10554 + */ + static function triggerInfo(&$info, $tableName = NULL) { + //during upgrade, first check for valid version and then create triggers + //i.e the columns created_date and modified_date are introduced in 4.3.alpha1 so dont create triggers for older version + if (CRM_Core_Config::isUpgradeMode()) { + $currentVer = CRM_Core_BAO_Domain::version(TRUE); + //if current version is less than 4.3.alpha1 dont create below triggers + if (version_compare($currentVer, '4.3.alpha1') < 0) { + return; + } + } + + if ($tableName == NULL || $tableName == self::getTableName()) { + $info[] = array( + 'table' => array(self::getTableName()), + 'when' => 'BEFORE', + 'event' => array('INSERT'), + 'sql' => "\nSET NEW.created_date = CURRENT_TIMESTAMP;\n", + ); + } + + // Update timestamp when modifying closely related core tables + $relatedTables = array( + 'civicrm_address', + 'civicrm_email', + 'civicrm_im', + 'civicrm_phone', + 'civicrm_website', + ); + $info[] = array( + 'table' => $relatedTables, + 'when' => 'AFTER', + 'event' => array('INSERT', 'UPDATE'), + 'sql' => "\nUPDATE civicrm_contact SET modified_date = CURRENT_TIMESTAMP WHERE id = NEW.contact_id;\n", + ); + $info[] = array( + 'table' => $relatedTables, + 'when' => 'AFTER', + 'event' => array('DELETE'), + 'sql' => "\nUPDATE civicrm_contact SET modified_date = CURRENT_TIMESTAMP WHERE id = OLD.contact_id;\n", + ); + + // Update timestamp when modifying related custom-data tables + $customGroupTables = array(); + $customGroupDAO = CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity('Contact'); + $customGroupDAO->is_multiple = 0; + $customGroupDAO->find(); + while ($customGroupDAO->fetch()) { + $customGroupTables[] = $customGroupDAO->table_name; + } + if (!empty($customGroupTables)) { + $info[] = array( + 'table' => $customGroupTables, + 'when' => 'AFTER', + 'event' => array('INSERT', 'UPDATE'), + 'sql' => "\nUPDATE civicrm_contact SET modified_date = CURRENT_TIMESTAMP WHERE id = NEW.entity_id;\n", + ); + $info[] = array( + 'table' => $customGroupTables, + 'when' => 'AFTER', + 'event' => array('DELETE'), + 'sql' => "\nUPDATE civicrm_contact SET modified_date = CURRENT_TIMESTAMP WHERE id = OLD.entity_id;\n", + ); + } + + // Update phone table to populate phone_numeric field + if (!$tableName || $tableName == 'civicrm_phone') { + // Define stored sql function needed for phones + CRM_Core_DAO::executeQuery(self::DROP_STRIP_FUNCTION_43); + CRM_Core_DAO::executeQuery(self::CREATE_STRIP_FUNCTION_43); + $info[] = array( + 'table' => array('civicrm_phone'), + 'when' => 'BEFORE', + 'event' => array('INSERT', 'UPDATE'), + 'sql' => "\nSET NEW.phone_numeric = civicrm_strip_non_numeric(NEW.phone);\n", + ); + } + } + + /** + * Function to check if contact is being used in civicrm_domain + * based on $contactId + * + * @param int $contactId contact id. + * + * @return true if present else false. + * @access public + * @static + */ + static function checkDomainContact($contactId) { + if (!$contactId) + return FALSE; + $domainId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', $contactId, 'id', 'contact_id'); + + if ($domainId) { + return TRUE; + } else { + return FALSE; + } + } +} diff --git a/CRM/Contact/BAO/Contact/Location.php b/CRM/Contact/BAO/Contact/Location.php new file mode 100644 index 0000000000..35b295f9e3 --- /dev/null +++ b/CRM/Contact/BAO/Contact/Location.php @@ -0,0 +1,200 @@ + array($id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + return array($dao->display_name, $dao->email, $dao->location_type_id, $dao->id); + } + return array(NULL, NULL, NULL, NULL); + } + + /** + * function to get the sms number and display name of a contact + * + * @param int $id id of the contact + * + * @return array tuple of display_name and sms if found, or (null,null) + * @static + * @access public + */ + static function getPhoneDetails($id, $type = NULL) { + if (!$id) { + return array(NULL, NULL); + } + + $cond = NULL; + if ($type) { + $cond = " AND civicrm_phone.phone_type_id = '$type'"; + } + + + $sql = " + SELECT civicrm_contact.display_name, civicrm_phone.phone, civicrm_contact.do_not_sms + FROM civicrm_contact +LEFT JOIN civicrm_phone ON ( civicrm_phone.contact_id = civicrm_contact.id ) + WHERE civicrm_phone.is_primary = 1 + $cond + AND civicrm_contact.id = %1"; + + $params = array(1 => array($id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + return array($dao->display_name, $dao->phone, $dao->do_not_sms); + } + return array(NULL, NULL, NULL); + } + + /** + * function to get the information to map a contact + * + * @param array $ids the list of ids for which we want map info + * $param int $locationTypeID + * + * @return null|string display name of the contact if found + * @static + * @access public + */ + static function &getMapInfo($ids, $locationTypeID = NULL, $imageUrlOnly = FALSE) { + $idString = ' ( ' . implode(',', $ids) . ' ) '; + $sql = " + SELECT civicrm_contact.id as contact_id, + civicrm_contact.contact_type as contact_type, + civicrm_contact.contact_sub_type as contact_sub_type, + civicrm_contact.display_name as display_name, + civicrm_address.street_address as street_address, + civicrm_address.supplemental_address_1 as supplemental_address_1, + civicrm_address.supplemental_address_2 as supplemental_address_2, + civicrm_address.city as city, + civicrm_address.postal_code as postal_code, + civicrm_address.postal_code_suffix as postal_code_suffix, + civicrm_address.geo_code_1 as latitude, + civicrm_address.geo_code_2 as longitude, + civicrm_state_province.abbreviation as state, + civicrm_country.name as country, + civicrm_location_type.name as location_type + FROM civicrm_contact +LEFT JOIN civicrm_address ON civicrm_address.contact_id = civicrm_contact.id +LEFT JOIN civicrm_state_province ON civicrm_address.state_province_id = civicrm_state_province.id +LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id +LEFT JOIN civicrm_location_type ON civicrm_location_type.id = civicrm_address.location_type_id +WHERE civicrm_address.geo_code_1 IS NOT NULL +AND civicrm_address.geo_code_2 IS NOT NULL +AND civicrm_contact.id IN $idString "; + + $params = array(); + if (!$locationTypeID) { + $sql .= " AND civicrm_address.is_primary = 1"; + } + else { + $sql .= " AND civicrm_address.location_type_id = %1"; + $params[1] = array($locationTypeID, 'Integer'); + } + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + + $locations = array(); + $config = CRM_Core_Config::singleton(); + + while ($dao->fetch()) { + $location = array(); + $location['contactID'] = $dao->contact_id; + $location['displayName'] = addslashes($dao->display_name); + $location['city'] = $dao->city; + $location['state'] = $dao->state; + $location['postal_code'] = $dao->postal_code; + $location['lat'] = $dao->latitude; + $location['lng'] = $dao->longitude; + $location['marker_class'] = $dao->contact_type; + $address = ''; + + CRM_Utils_String::append($address, '
    ', + array( + $dao->street_address, + $dao->supplemental_address_1, + $dao->supplemental_address_2, + $dao->city, + ) + ); + CRM_Utils_String::append($address, ', ', + array($dao->state, $dao->postal_code) + ); + CRM_Utils_String::append($address, '
    ', + array($dao->country) + ); + $location['address'] = addslashes($address); + $location['displayAddress'] = str_replace('
    ', ', ', $address); + $location['url'] = CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $dao->contact_id); + $location['location_type'] = $dao->location_type; + $location['image'] = CRM_Contact_BAO_Contact_Utils::getImage(isset($dao->contact_sub_type) ? + $dao->contact_sub_type : $dao->contact_type, $imageUrlOnly, $dao->contact_id + ); + $locations[] = $location; + } + return $locations; + } +} + diff --git a/CRM/Contact/BAO/Contact/Optimizer.php b/CRM/Contact/BAO/Contact/Optimizer.php new file mode 100644 index 0000000000..cc42f03529 --- /dev/null +++ b/CRM/Contact/BAO/Contact/Optimizer.php @@ -0,0 +1,178 @@ + $value ) { + if ( ! empty( $value['url'] ) ) { + $oldEmpty = false; + $old[] = array( 'website_type_id' => $value['website_type_id'], 'url' => $value['url'] ); + } + } + + foreach ( $newWebsiteValues as $idx => $value ) { + if ( ! empty( $value['url'] ) ) { + $newEmpty = false; + $new[] = array( 'website_type_id' => $value['website_type_id'], 'url' => $value['url'] ); + } + } + + // if both old and new are empty, we can delete new and avoid a write + if ( $oldEmpty && $newEmpty ) { + unset( $newValues['website'] ); + } + + // if different number of non-empty entries, return + if ( count( $new ) != count( $old ) ) { + return; + } + + // same number of entries, check if they are exactly the same + foreach ( $old as $oldID => $oldValues ) { + $found = false; + foreach ( $new as $newID => $newValues ) { + if ( + $old['website_type_id'] == $new['website_type_id'] && + $old['url'] == $new['url'] + ) { + $found = true; + unset( $new[$newID] ); + break; + } + if ( ! $found ) { + return; + } + } + } + + // if we've come here, this means old and new are the same + // we can skip saving new and return + unset( $newValues['website'] ); + } + + static function email( &$newValues, &$oldValues ) { + $oldEmailValues = CRM_Utils_Array::value( 'email', $oldValues ); + $newEmailValues = CRM_Utils_Array::value( 'email', $newValues ); + + if ( $oldEmailValues == null || $newEmailValues == null ) { + return; + } + + // check if we had a value in the old + $oldEmpty = $newEmpty = true; + $old = $new = array( ); + + foreach ( $oldEmailValues as $idx => $value ) { + if ( ! empty( $value['email'] ) ) { + $oldEmpty = false; + $old[] = array( + 'email' => $value['email'], + 'location_type_id' => $value['location_type_id'], + 'on_hold' => $value['on_hold'] ? 1 : 0, + 'is_primary' => $value['is_primary'] ? 1 : 0, + 'is_bulkmail' => $value['is_bulkmail'] ? 1 : 0, + 'signature_text' => $value['signature_text'] ? $value['signature_text'] : '', + 'signature_html' => $value['signature_html'] ? $value['signature_html'] : '', + ); + } + } + + foreach ( $newEmailValues as $idx => $value ) { + if ( ! empty( $value['email'] ) ) { + $newEmpty = false; + $new[] = array( + 'email' => $value['email'], + 'location_type_id' => $value['location_type_id'], + 'on_hold' => $value['on_hold'] ? 1 : 0, + 'is_primary' => $value['is_primary'] ? 1 : 0, + 'is_bulkmail' => $value['is_bulkmail'] ? 1 : 0, + 'signature_text' => $value['signature_text'] ? $value['signature_text'] : '', + 'signature_html' => $value['signature_html'] ? $value['signature_html'] : '', + ); + } + } + + // if both old and new are empty, we can delete new and avoid a write + if ( $oldEmpty && $newEmpty ) { + unset( $newValues['email'] ); + } + + // if different number of non-empty entries, return + if ( count( $new ) != count( $old ) ) { + return; + } + + // same number of entries, check if they are exactly the same + foreach ( $old as $oldID => $oldValues ) { + $found = false; + foreach ( $new as $newID => $newValues ) { + if ( + $old['email_type_id'] == $new['email_type_id'] && + $old['url'] == $new['url'] + ) { + $found = true; + unset( $new[$newID] ); + break; + } + if ( ! $found ) { + return; + } + } + } + + // if we've come here, this means old and new are the same + // we can skip saving new and return + unset( $newValues['email'] ); + } +} + diff --git a/CRM/Contact/BAO/Contact/Permission.php b/CRM/Contact/BAO/Contact/Permission.php new file mode 100644 index 0000000000..d8a6e6cb94 --- /dev/null +++ b/CRM/Contact/BAO/Contact/Permission.php @@ -0,0 +1,310 @@ + array($id, 'Integer')); + + return (CRM_Core_DAO::singleValueQuery($query, $params) > 0) ? TRUE : FALSE; + } + + /** + * fill the acl contact cache for this contact id if empty + * + * @param int $id contact id + * @param string $type the type of operation (view|edit) + * @param boolean $force should we force a recompute + * + * @return void + * @access public + * @static + */ + static function cache($userID, $type = CRM_Core_Permission::VIEW, $force = FALSE) { + static $_processed = array(); + + if ($type = CRM_Core_Permission::VIEW) { + $operationClause = " operation IN ( 'Edit', 'View' ) "; + $operation = 'View'; + } + else { + $operationClause = " operation = 'Edit' "; + $operation = 'Edit'; + } + + if (!$force) { + if (CRM_Utils_Array::value($userID, $_processed)) { + return; + } + + // run a query to see if the cache is filled + $sql = " +SELECT count(id) +FROM civicrm_acl_contact_cache +WHERE user_id = %1 +AND $operationClause +"; + $params = array(1 => array($userID, 'Integer')); + $count = CRM_Core_DAO::singleValueQuery($sql, $params); + if ($count > 0) { + $_processed[$userID] = 1; + return; + } + } + + $tables = array(); + $whereTables = array(); + + $permission = CRM_ACL_API::whereClause($type, $tables, $whereTables, $userID); + + $from = CRM_Contact_BAO_Query::fromClause($whereTables); + + CRM_Core_DAO::executeQuery(" +INSERT INTO civicrm_acl_contact_cache ( user_id, contact_id, operation ) +SELECT $userID as user_id, contact_a.id as contact_id, '$operation' as operation + $from +WHERE $permission +GROUP BY contact_a.id +ON DUPLICATE KEY UPDATE + user_id=VALUES(user_id), + contact_id=VALUES(contact_id), + operation=VALUES(operation)" + ); + + CRM_Core_DAO::executeQuery('DELETE FROM civicrm_acl_contact_cache WHERE contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)'); + $_processed[$userID] = 1; + + return; + } + + /** + * Function to check if there are any contacts in cache table + * + * @param string $type the type of operation (view|edit) + * @param int $contactID contact id + * + * @return boolean + * @access public + * @static + */ + static function hasContactsInCache($type = CRM_Core_Permission::VIEW, + $contactID = NULL + ) { + if (!$contactID) { + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + } + + if ($type = CRM_Core_Permission::VIEW) { + $operationClause = " operation IN ( 'Edit', 'View' ) "; + $operation = 'View'; + } + else { + $operationClause = " operation = 'Edit' "; + $operation = 'Edit'; + } + + // fill cache + self::cache($contactID); + + $sql = " +SELECT id +FROM civicrm_acl_contact_cache +WHERE user_id = %1 +AND $operationClause LIMIT 1"; + + $params = array(1 => array($contactID, 'Integer')); + return (bool) CRM_Core_DAO::singleValueQuery($sql, $params); + } + + static function cacheClause($contactAlias = 'contact_a', $contactID = NULL) { + if (CRM_Core_Permission::check('view all contacts') || + CRM_Core_Permission::check('edit all contacts') + ) { + if (is_array($contactAlias)) { + $wheres = array(); + foreach ($contactAlias as $alias) { + // CRM-6181 + $wheres[] = "$alias.is_deleted = 0"; + } + return array(NULL, '(' . implode(' AND ', $wheres) . ')'); + } + else { + // CRM-6181 + return array(NULL, "$contactAlias.is_deleted = 0"); + } + } + + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + if (!$contactID) { + $contactID = 0; + } + $contactID = CRM_Utils_Type::escape($contactID, 'Integer'); + + self::cache($contactID); + + if (is_array($contactAlias) && !empty($contactAlias)) { + //More than one contact alias + $clauses = array(); + foreach ($contactAlias as $k => $alias) { + $clauses[] = " INNER JOIN civicrm_acl_contact_cache aclContactCache_{$k} ON {$alias}.id = aclContactCache_{$k}.contact_id AND aclContactCache_{$k}.user_id = $contactID "; + } + + $fromClause = implode(" ", $clauses); + $whereClase = NULL; + } + else { + $fromClause = " INNER JOIN civicrm_acl_contact_cache aclContactCache ON {$contactAlias}.id = aclContactCache.contact_id "; + $whereClase = " aclContactCache.user_id = $contactID "; + } + + return array($fromClause, $whereClase); + } + + /** + * Function to get the permission base on its relationship + * + * @param int $selectedContactId contact id of selected contact + * @param int $contactId contact id of the current contact + * + * @return booleab true if logged in user has permission to view + * selected contact record else false + * @static + */ + static function relationship($selectedContactID, $contactID = NULL) { + $session = CRM_Core_Session::singleton(); + if (!$contactID) { + $contactID = $session->get('userID'); + if (!$contactID) { + return FALSE; + } + } + if ($contactID == $selectedContactID) { + return TRUE; + } + else { + $query = " +SELECT id +FROM civicrm_relationship +WHERE (( contact_id_a = %1 AND contact_id_b = %2 AND is_permission_a_b = 1 ) OR + ( contact_id_a = %2 AND contact_id_b = %1 AND is_permission_b_a = 1 )) AND + (contact_id_a NOT IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)) AND + (contact_id_b NOT IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)) + AND ( civicrm_relationship.is_active = 1 ) +"; + $params = array(1 => array($contactID, 'Integer'), + 2 => array($selectedContactID, 'Integer'), + ); + return CRM_Core_DAO::singleValueQuery($query, $params); + } + } + + + static function validateOnlyChecksum($contactID, &$form, $redirect = TRUE) { + // check if this is of the format cs=XXX + if (!CRM_Contact_BAO_Contact_Utils::validChecksum($contactID, + CRM_Utils_Request::retrieve('cs', 'String', $form, FALSE) + )) { + if ($redirect) { + // also set a message in the UF framework + $message = ts('You do not have permission to edit this contact record. Contact the site administrator if you need assistance.'); + CRM_Utils_System::setUFMessage($message); + + $config = CRM_Core_Config::singleton(); + CRM_Core_Error::statusBounce($message, + $config->userFrameworkBaseURL + ); + // does not come here, we redirect in the above statement + } + return FALSE; + } + + // so here the contact is posing as $contactID, lets set the logging contact ID variable + // CRM-8965 + CRM_Core_DAO::executeQuery('SET @civicrm_user_id = %1', + array(1 => array($contactID, 'Integer')) + ); + return TRUE; + } + + static function validateChecksumContact($contactID, &$form, $redirect = TRUE) { + if (!self::allow($contactID, CRM_Core_Permission::EDIT)) { + // check if this is of the format cs=XXX + return self::validateOnlyChecksum($contactID, $form, $redirect); + } + return TRUE; + } +} + diff --git a/CRM/Contact/BAO/Contact/Utils.php b/CRM/Contact/BAO/Contact/Utils.php new file mode 100644 index 0000000000..2f8c6a2a07 --- /dev/null +++ b/CRM/Contact/BAO/Contact/Utils.php @@ -0,0 +1,1091 @@ + $contactType); + CRM_Contact_BAO_ContactType::retrieve($params, $typeInfo); + + if (CRM_Utils_Array::value('image_URL', $typeInfo)) { + $imageUrl = $typeInfo['image_URL']; + $config = CRM_Core_Config::singleton(); + + if (!preg_match("/^(\/|(http(s)?:)).+$/i", $imageUrl)) { + $imageUrl = $config->resourceBase . $imageUrl; + } + $imageInfo[$contactType]['image'] = "
    "; + $imageInfo[$contactType]['url'] = $imageUrl; + } + else { + $isSubtype = (array_key_exists('parent_id', $typeInfo) && + $typeInfo['parent_id'] + ) ? TRUE : FALSE; + + if ($isSubtype) { + $type = CRM_Contact_BAO_ContactType::getBasicType($typeInfo['name']) . '-subtype'; + } + else { + $type = CRM_Utils_Array::value('name', $typeInfo); + } + + // do not add title since it hides contact name + if ($addProfileOverlay) { + $imageInfo[$contactType]['image'] = "
    "; + } + else{ + $imageInfo[$contactType]['image'] = "
    "; + } + $imageInfo[$contactType]['url'] = NULL; + } + } + + if ($addProfileOverlay) { + static $summaryOverlayProfileId = NULL; + if (!$summaryOverlayProfileId) { + $summaryOverlayProfileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name'); + } + + $profileURL = CRM_Utils_System::url('civicrm/profile/view', + "reset=1&gid={$summaryOverlayProfileId}&id={$contactId}&snippet=4" + ); + + $imageInfo[$contactType]['summary-link'] = '' . $imageInfo[$contactType]['image'] . ''; + } + else { + $imageInfo[$contactType]['summary-link'] = $imageInfo[$contactType]['image']; + } + + return $urlOnly ? $imageInfo[$contactType]['url'] : $imageInfo[$contactType]['summary-link']; + } + + /** + * function check for mix contact ids(individual+household etc...) + * + * @param array $contactIds array of contact ids + * + * @return boolen true or false true if mix contact array else fale + * + * @access public + * @static + */ + public static function checkContactType(&$contactIds) { + if (empty($contactIds)) { + return FALSE; + } + + $idString = implode(',', $contactIds); + $query = " +SELECT count( DISTINCT contact_type ) +FROM civicrm_contact +WHERE id IN ( $idString ) +"; + $count = CRM_Core_DAO::singleValueQuery($query, + CRM_Core_DAO::$_nullArray + ); + return $count > 1 ? TRUE : FALSE; + } + + /** + * Generate a checksum for a contactID + * + * @param int $contactID + * @param int $ts timestamp that checksum was generated + * @param int $live life of this checksum in hours/ 'inf' for infinite + * @param string $hash contact hash, if sent, prevents a query in inner loop + * + * @return array ( $cs, $ts, $live ) + * @static + * @access public + */ + static function generateChecksum($contactID, $ts = NULL, $live = NULL, $hash = NULL) { + // return a warning message if we dont get a contactID + // this typically happens when we do a message preview + // or an anon mailing view - CRM-8298 + if (!$contactID) { + return 'invalidChecksum'; + } + + if (!$hash) { + $hash = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $contactID, 'hash' + ); + } + + if (!$hash) { + $hash = md5(uniqid(rand(), TRUE)); + CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Contact', + $contactID, + 'hash', $hash + ); + } + + if (!$ts) { + $ts = time(); + } + + if (!$live) { + $days = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'checksum_timeout', + NULL, + 7 + ); + $live = 24 * $days; + } + + $cs = md5("{$hash}_{$contactID}_{$ts}_{$live}"); + return "{$cs}_{$ts}_{$live}"; + } + + /** + * Make sure the checksum is valid for the passed in contactID + * + * @param int $contactID + * @param string $inputCheck checksum to match against + * + * @return boolean true if valid, else false + * @static + * @access public + */ + static function validChecksum($contactID, $inputCheck) { + + $input = CRM_Utils_System::explode('_', $inputCheck, 3); + + $inputCS = CRM_Utils_Array::value(0, $input); + $inputTS = CRM_Utils_Array::value(1, $input); + $inputLF = CRM_Utils_Array::value(2, $input); + + $check = self::generateChecksum($contactID, $inputTS, $inputLF); + + if ($check != $inputCheck) { + return FALSE; + } + + // no life limit for checksum + if ($inputLF == 'inf') { + return TRUE; + } + + // checksum matches so now check timestamp + $now = time(); + return ($inputTS + ($inputLF * 60 * 60) >= $now); + } + + /** + * Function to get the count of contact loctions + * + * @param int $contactId contact id + * + * @return int $locationCount max locations for the contact + * @static + * @access public + */ + static function maxLocations($contactId) { + $contactLocations = array(); + + // find number of location blocks for this contact and adjust value accordinly + // get location type from email + $query = " +( SELECT location_type_id FROM civicrm_email WHERE contact_id = {$contactId} ) +UNION +( SELECT location_type_id FROM civicrm_phone WHERE contact_id = {$contactId} ) +UNION +( SELECT location_type_id FROM civicrm_im WHERE contact_id = {$contactId} ) +UNION +( SELECT location_type_id FROM civicrm_address WHERE contact_id = {$contactId} ) +"; + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + return $dao->N; + } + + /** + * Create Current employer relationship for a individual + * + * @param int $contactID contact id of the individual + * @param string $organization it can be name or id of organization + * + * @access public + * @static + */ + static function createCurrentEmployerRelationship($contactID, $organization) { + $organizationId = NULL; + + // if organization id is passed. + if (is_numeric($organization)) { + $organizationId = $organization; + } + else { + $orgName = explode('::', $organization); + trim($orgName[0]); + + $organizationParams = array(); + $organizationParams['organization_name'] = $orgName[0]; + + $dedupeParams = CRM_Dedupe_Finder::formatParams($organizationParams, 'Organization'); + + $dedupeParams['check_permission'] = FALSE; + $dupeIDs = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Organization', 'Supervised'); + + if (is_array($dupeIDs) && !empty($dupeIDs)) { + // we should create relationship only w/ first org CRM-4193 + foreach ($dupeIDs as $orgId) { + $organizationId = $orgId; + break; + } + } + else { + //create new organization + $newOrg = array( + 'contact_type' => 'Organization', + 'organization_name' => trim($orgName[0]), + ); + $org = CRM_Contact_BAO_Contact::add($newOrg); + $organizationId = $org->id; + } + } + + if ($organizationId) { + $cid = array('contact' => $contactID); + + // get the relationship type id of "Employee of" + $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Employee of', 'id', 'name_a_b'); + if (!$relTypeId) { + CRM_Core_Error::fatal(ts("You seem to have deleted the relationship type 'Employee of'")); + } + + // create employee of relationship + $relationshipParams = array( + 'is_active' => TRUE, + 'relationship_type_id' => $relTypeId . '_a_b', + 'contact_check' => array($organizationId => TRUE), + ); + list($valid, $invalid, $duplicate, + $saved, $relationshipIds + ) = CRM_Contact_BAO_Relationship::create($relationshipParams, $cid); + + + // In case we change employer, clean prveovious employer related records. + $previousEmployerID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'employer_id'); + if ($previousEmployerID && + $previousEmployerID != $organizationId + ) { + self::clearCurrentEmployer($contactID, $previousEmployerID); + } + + // set current employer + self::setCurrentEmployer(array($contactID => $organizationId)); + + $relationshipParams['relationship_ids'] = $relationshipIds; + // handle related meberships. CRM-3792 + self::currentEmployerRelatedMembership($contactID, $organizationId, $relationshipParams, $duplicate); + } + } + + /** + * create related memberships for current employer + * + * @param int $contactID contact id of the individual + * @param int $employerID contact id of the organization. + * @param array $relationshipParams relationship params. + * @param boolean $duplicate are we triggered existing relationship. + * + * @access public + * @static + */ + static function currentEmployerRelatedMembership($contactID, $employerID, $relationshipParams, $duplicate = FALSE) { + $ids = array(); + $action = CRM_Core_Action::ADD; + + //we do not know that triggered relationship record is active. + if ($duplicate) { + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->contact_id_a = $contactID; + $relationship->contact_id_b = $employerID; + $relationship->relationship_type_id = $relationshipParams['relationship_type_id']; + if ($relationship->find(TRUE)) { + $action = CRM_Core_Action::UPDATE; + $ids['contact'] = $contactID; + $ids['contactTarget'] = $employerID; + $ids['relationship'] = $relationship->id; + CRM_Contact_BAO_Relationship::setIsActive($relationship->id, TRUE); + } + $relationship->free(); + } + + //need to handle related meberships. CRM-3792 + CRM_Contact_BAO_Relationship::relatedMemberships($contactID, $relationshipParams, $ids, $action); + } + + /** + * Function to set current employer id and organization name + * + * @param array $currentEmployerParams associated array of contact id and its employer id + * + */ + static function setCurrentEmployer($currentEmployerParams) { + foreach ($currentEmployerParams as $contactId => $orgId) { + $query = "UPDATE civicrm_contact contact_a,civicrm_contact contact_b +SET contact_a.employer_id=contact_b.id, contact_a.organization_name=contact_b.organization_name +WHERE contact_a.id ={$contactId} AND contact_b.id={$orgId}; "; + + //FIXME : currently civicrm mysql_query support only single statement + //execution, though mysql 5.0 support multiple statement execution. + $dao = CRM_Core_DAO::executeQuery($query); + } + } + + /** + * Function to update cached current employer name + * + * @param int $organizationId current employer id + * + */ + static function updateCurrentEmployer($organizationId) { + $query = "UPDATE civicrm_contact contact_a,civicrm_contact contact_b +SET contact_a.organization_name=contact_b.organization_name +WHERE contact_a.employer_id=contact_b.id AND contact_b.id={$organizationId}; "; + + $dao = CRM_Core_DAO::executeQuery($query); + } + + /** + * Function to clear cached current employer name + * + * @param int $contactId contact id ( mostly individual contact id) + * @param int $employerId contact id ( mostly organization contact id) + * + */ + static function clearCurrentEmployer($contactId, $employerId = NULL) { + $query = "UPDATE civicrm_contact +SET organization_name=NULL, employer_id = NULL +WHERE id={$contactId}; "; + + $dao = CRM_Core_DAO::executeQuery($query); + + // need to handle related meberships. CRM-3792 + if ($employerId) { + //1. disable corresponding relationship. + //2. delete related membership. + + //get the relationship type id of "Employee of" + $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Employee of', 'id', 'name_a_b'); + if (!$relTypeId) { + CRM_Core_Error::fatal(ts("You seem to have deleted the relationship type 'Employee of'")); + } + $relMembershipParams['relationship_type_id'] = $relTypeId . '_a_b'; + $relMembershipParams['contact_check'][$employerId] = 1; + + //get relationship id. + if (CRM_Contact_BAO_Relationship::checkDuplicateRelationship($relMembershipParams, $contactId, $employerId)) { + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->contact_id_a = $contactId; + $relationship->contact_id_b = $employerId; + $relationship->relationship_type_id = $relTypeId; + + if ($relationship->find(TRUE)) { + CRM_Contact_BAO_Relationship::setIsActive($relationship->id, FALSE); + CRM_Contact_BAO_Relationship::relatedMemberships($contactId, $relMembershipParams, + $ids = array( + ), CRM_Core_Action::DELETE + ); + } + $relationship->free(); + } + } + } + + /** + * Function to build form for related contacts / on behalf of organization. + * + * @param $form object invoking Object + * @param $contactType string contact type + * @param $title string fieldset title + * @param $maxLocationBlocks int number of location blocks + * + * @static + * + */ + static function buildOnBehalfForm(&$form, + $contactType = 'Individual', + $countryID = NULL, + $stateID = NULL, + $title = 'Contact Information', + $contactEditMode = FALSE, + $maxLocationBlocks = 1 + ) { + if ($title == 'Contact Information') { + $title = ts('Contact Information'); + } + + $config = CRM_Core_Config::singleton(); + + $form->assign('contact_type', $contactType); + $form->assign('fieldSetTitle', $title); + $form->assign('contactEditMode', $contactEditMode); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact'); + if ($form->_contactId) { + $form->assign('orgId', $form->_contactId); + } + + switch ($contactType) { + case 'Organization': + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + + if ($contactID) { + $employers = CRM_Contact_BAO_Relationship::getPermissionedEmployer($contactID); + } + + $locDataURL = CRM_Utils_System::url('civicrm/ajax/permlocation', 'cid=', FALSE, NULL, FALSE); + $form->assign('locDataURL', $locDataURL); + + if (!$contactEditMode && $contactID && (count($employers) >= 1)) { + + $dataURL = CRM_Utils_System::url('civicrm/ajax/employer', + 'cid=' . $contactID, + FALSE, NULL, FALSE + ); + $form->assign('employerDataURL', $dataURL); + + $form->add('text', 'organization_id', ts('Select an existing related Organization OR Enter a new one')); + $form->add('hidden', 'onbehalfof_id', '', array('id' => 'onbehalfof_id')); + $orgOptions = array('0' => ts('Create new organization'), + '1' => ts('Select existing organization'), + ); + $orgOptionExtra = array('onclick' => "showHideByValue('org_option','true','select_org','table-row','radio',true);showHideByValue('org_option','true','create_org','table-row','radio',false);"); + $form->addRadio('org_option', ts('options'), $orgOptions, $orgOptionExtra); + $form->assign('relatedOrganizationFound', TRUE); + } + + $isRequired = FALSE; + if (CRM_Utils_Array::value('is_for_organization', $form->_values) == 2) { + $isRequired = TRUE; + } + $form->add('text', 'organization_name', ts('Organization Name'), $attributes['organization_name'], $isRequired); + break; + + case 'Household': + $form->add('text', 'household_name', ts('Household Name'), + $attributes['household_name'] + ); + break; + + default: + // individual + $form->addElement('select', 'prefix_id', ts('Prefix'), + array('' => ts('- prefix -')) + CRM_Core_PseudoConstant::individualPrefix() + ); + $form->addElement('text', 'first_name', ts('First Name'), + $attributes['first_name'] + ); + $form->addElement('text', 'middle_name', ts('Middle Name'), + $attributes['middle_name'] + ); + $form->addElement('text', 'last_name', ts('Last Name'), + $attributes['last_name'] + ); + $form->addElement('select', 'suffix_id', ts('Suffix'), + array('' => ts('- suffix -')) + CRM_Core_PseudoConstant::individualSuffix() + ); + } + + $addressSequence = $config->addressSequence(); + $form->assign('addressSequence', array_fill_keys($addressSequence, 1)); + + //Primary Phone + $form->addElement('text', + 'phone[1][phone]', + ts('Primary Phone'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Phone', + 'phone' + ) + ); + //Primary Email + $form->addElement('text', + 'email[1][email]', + ts('Primary Email'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', + 'email' + ) + ); + //build the address block + CRM_Contact_Form_Edit_Address::buildQuickForm($form); + + // also fix the state country selector + CRM_Contact_Form_Edit_Address::fixStateSelect($form, + 'address[1][country_id]', + 'address[1][state_province_id]', + "address[1][county_id]", + $countryID, + $stateID + ); + } + + /** + * Function to clear cache employer name and employer id + * of all employee when employer get deleted. + * + * @param int $employerId contact id of employer ( organization id ) + * + */ + static function clearAllEmployee($employerId) { + $query = " +UPDATE civicrm_contact + SET organization_name=NULL, employer_id = NULL + WHERE employer_id={$employerId}; "; + + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + + /** + * Given an array of contact ids this function will return array with links to view contact page + * + * @param array $contactIDs associated contact id's + * @param int $originalId associated with the contact which is edited + * + * + * @return array $contactViewLinks returns array with links to contact view + * @static + * @access public + */ + static function formatContactIDSToLinks($contactIDs, $addViewLink = TRUE, $addEditLink = TRUE, $originalId = NULL) { + $contactLinks = array(); + if (!is_array($contactIDs) || empty($contactIDs)) { + return $contactLinks; + } + + // does contact has sufficient permissions. + $permissions = array( + 'view' => 'view all contacts', + 'edit' => 'edit all contacts', + 'merge' => 'merge duplicate contacts', + ); + + $permissionedContactIds = array(); + foreach ($permissions as $task => $permission) { + // give permission. + if (CRM_Core_Permission::check($permission)) { + foreach ($contactIDs as $contactId) { + $permissionedContactIds[$contactId][$task] = TRUE; + } + continue; + } + + // check permission on acl basis. + if (in_array($task, array( + 'view', 'edit'))) { + $aclPermission = CRM_Core_Permission::VIEW; + if ($task == 'edit') { + $aclPermission = CRM_Core_Permission::EDIT; + } + foreach ($contactIDs as $contactId) { + if (CRM_Contact_BAO_Contact_Permission::allow($contactId, $aclPermission)) { + $permissionedContactIds[$contactId][$task] = TRUE; + } + } + } + } + + // retrieve display names for all contacts + $query = ' + SELECT c.id, c.display_name, c.contact_type, ce.email + FROM civicrm_contact c +LEFT JOIN civicrm_email ce ON ( ce.contact_id=c.id AND ce.is_primary = 1 ) + WHERE c.id IN (' . implode(',', $contactIDs) . ' ) LIMIT 20'; + + $dao = CRM_Core_DAO::executeQuery($query); + + $contactLinks['msg'] = NULL; + $i = 0; + while ($dao->fetch()) { + + $contactLinks['rows'][$i]['display_name'] = $dao->display_name; + $contactLinks['rows'][$i]['primary_email'] = $dao->email; + + // get the permission for current contact id. + $hasPermissions = CRM_Utils_Array::value($dao->id, $permissionedContactIds); + if (!is_array($hasPermissions) || empty($hasPermissions)) { + $i++; + continue; + } + + // do check for view. + if (array_key_exists('view', $hasPermissions)) { + $contactLinks['rows'][$i]['view'] = '' . ts('View') . ''; + if (!$contactLinks['msg']) { + $contactLinks['msg'] = 'view'; + } + } + if (array_key_exists('edit', $hasPermissions)) { + $contactLinks['rows'][$i]['edit'] = '' . ts('Edit') . ''; + if (!$contactLinks['msg'] || $contactLinks['msg'] != 'merge') { + $contactLinks['msg'] = 'edit'; + } + } + if (!empty($originalId) && array_key_exists('merge', $hasPermissions)) { + $rgBao = new CRM_Dedupe_BAO_RuleGroup(); + $rgBao->contact_type = $dao->contact_type; + $rgBao->used = 'Supervised'; + if ($rgBao->find(TRUE)) { + $rgid = $rgBao->id; + } + if ($rgid && isset($dao->id)) { + //get an url to merge the contact + $contactLinks['rows'][$i]['merge'] = '' . ts('Merge') . ''; + $contactLinks['msg'] = 'merge'; + } + } + + $i++; + } + + return $contactLinks; + } + + /** + * This function retrieve component related contact information. + * + * @param array $componentIds array of component Ids. + * @param array $returnProperties array of return elements. + * + * @return $contactDetails array of contact info. + * @static + */ + static function contactDetails($componentIds, $componentName, $returnProperties = array( + )) { + $contactDetails = array(); + if (empty($componentIds) || + !in_array($componentName, array('CiviContribute', 'CiviMember', 'CiviEvent', 'Activity')) + ) { + return $contactDetails; + } + + if (empty($returnProperties)) { + $autocompleteContactSearch = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_autocomplete_options' + ); + $returnProperties = array_fill_keys(array_merge(array('sort_name'), + array_keys($autocompleteContactSearch) + ), 1); + } + + $compTable = NULL; + if ($componentName == 'CiviContribute') { + $compTable = 'civicrm_contribution'; + } + elseif ($componentName == 'CiviMember') { + $compTable = 'civicrm_membership'; + } + elseif ($componentName == 'Activity') { + $compTable = 'civicrm_activity'; + } + else { + $compTable = 'civicrm_participant'; + } + + $select = $from = array(); + foreach ($returnProperties as $property => $ignore) { + $value = (in_array($property, array( + 'city', 'street_address'))) ? 'address' : $property; + switch ($property) { + case 'sort_name': + if ($componentName == 'Activity') { + $select[] = "contact_source.$property as $property"; + $from[$value] = "INNER JOIN civicrm_contact contact ON ( contact.id = $compTable.source_contact_id )"; + } + else { + $select[] = "$property as $property"; + $from[$value] = "INNER JOIN civicrm_contact contact ON ( contact.id = $compTable.contact_id )"; + } + break; + + case 'target_sort_name': + $select[] = "contact_target.sort_name as $property"; + $from[$value] = "INNER JOIN civicrm_contact contact_source ON ( contact_source.id = $compTable.source_contact_id ) + LEFT JOIN civicrm_activity_target ON (civicrm_activity_target.activity_id = $compTable.id) + LEFT JOIN civicrm_contact as contact_target ON ( contact_target.id = civicrm_activity_target.target_contact_id )"; + break; + + case 'email': + case 'phone': + case 'city': + case 'street_address': + $select[] = "$property as $property"; + // Grab target contact properties if this is for activity + if ($componentName == 'Activity') { + $from[$value] = "LEFT JOIN civicrm_{$value} {$value} ON ( contact_target.id = {$value}.contact_id AND {$value}.is_primary = 1 ) "; + } + else { + $from[$value] = "LEFT JOIN civicrm_{$value} {$value} ON ( contact.id = {$value}.contact_id AND {$value}.is_primary = 1 ) "; + } + break; + + case 'country': + case 'state_province': + $select[] = "{$property}.name as $property"; + if (!in_array('address', $from)) { + // Grab target contact properties if this is for activity + if ($componentName == 'Activity') { + $from['address'] = 'LEFT JOIN civicrm_address address ON ( contact_target.id = address.contact_id AND address.is_primary = 1) '; + } + else { + $from['address'] = 'LEFT JOIN civicrm_address address ON ( contact.id = address.contact_id AND address.is_primary = 1) '; + } + } + $from[$value] = " LEFT JOIN civicrm_{$value} {$value} ON ( address.{$value}_id = {$value}.id ) "; + break; + } + } + + //finally retrieve contact details. + if (!empty($select) && !empty($from)) { + $fromClause = implode(' ', $from); + $selectClause = implode(', ', $select); + $whereClause = "{$compTable}.id IN (" . implode(',', $componentIds) . ')'; + + $query = " + SELECT contact.id as contactId, $compTable.id as componentId, $selectClause + FROM $compTable as $compTable $fromClause + WHERE $whereClause +Group By componentId"; + + $contact = CRM_Core_DAO::executeQuery($query); + while ($contact->fetch()) { + $contactDetails[$contact->componentId]['contact_id'] = $contact->contactId; + foreach ($returnProperties as $property => $ignore) { + $contactDetails[$contact->componentId][$property] = $contact->$property; + } + } + $contact->free(); + } + + return $contactDetails; + } + + /** + * Function handles shared contact address processing + * In this function we just modify submitted values so that new address created for the user + * has same address as shared contact address. We copy the address so that search etc will be + * much efficient. + * + * @param array $address this is associated array which contains submitted form values + * + * @return void + * @static + * @access public + */ + static function processSharedAddress(&$address) { + if (!is_array($address)) { + return; + } + + // Sharing contact address during create mode is pretty straight forward. + // In update mode we should check following: + // - We should check if user has uncheck shared contact address + // - If yes then unset the master_id or may be just delete the address that copied master + // Normal update process will automatically create new address with submitted values + + // 1. loop through entire subnitted address array + $masterAddress = array(); + $skipFields = array('is_primary', 'location_type_id', 'is_billing', 'master_id'); + foreach ($address as & $values) { + // 2. check if master id exists, if not continue + if (!CRM_Utils_Array::value('master_id', $values) || + !CRM_Utils_Array::value('use_shared_address', $values) + ) { + // we should unset master id when use uncheck share address for existing address + $values['master_id'] = 'null'; + continue; + } + + // 3. get the address details for master_id + $masterAddress = new CRM_Core_BAO_Address(); + $masterAddress->id = CRM_Utils_Array::value('master_id', $values); + $masterAddress->find(TRUE); + + // 4. modify submitted params and update it with shared contact address + // make sure you preserve specific form values like location type, is_primary_ is_billing, master_id + // CRM-10336: Also empty any fields from the existing address block if they don't exist in master (otherwise they will persist) + foreach ($values as $field => $submittedValue) { + if (!in_array($field, $skipFields)){ + if (isset($masterAddress->$field)) { + $values[$field] = $masterAddress->$field; + } else { + $values[$field] = ''; + } + } + } + } + } + + /** + * Function to get the list of contact name give address associated array + * + * @param array $addresses associated array of + * + * @return $contactNames associated array of contact names + * @static + */ + static function getAddressShareContactNames(&$addresses) { + $contactNames = array(); + // get the list of master id's for address + $masterAddressIds = array(); + foreach ($addresses as $key => $addressValue) { + if (CRM_Utils_Array::value('master_id', $addressValue)) { + $masterAddressIds[] = $addressValue['master_id']; + } + } + + if (!empty($masterAddressIds)) { + $query = 'SELECT ca.id, cc.display_name, cc.id as cid, cc.is_deleted + FROM civicrm_contact cc + INNER JOIN civicrm_address ca ON cc.id = ca.contact_id + WHERE ca.id IN ( ' . implode(',', $masterAddressIds) . ')'; + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$dao->cid}"); + $contactNames[$dao->id] = array( + 'name' => "{$dao->display_name}", + 'is_deleted' => $dao->is_deleted, + ); + } + } + return $contactNames; + } + + /** + * Clear the contact cache so things are kosher. We started off being super aggressive with clearing + * caches, but are backing off from this with every release. Compromise between ease of coding versus + * performance versus being accurate at that very instant + * + * @param $contactID - the contactID that was edited / deleted + * + * @return void + * @static + */ + static function clearContactCaches($contactID = NULL) { + // clear acl cache if any. + CRM_ACL_BAO_Cache::resetCache(); + + if (empty($contactID)) { + // also clear prev/next dedupe cache - if no contactID passed in + CRM_Core_BAO_PrevNextCache::deleteItem(); + } + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + } + + public static function updateGreeting($params) { + $contactType = $params['ct']; + $greeting = $params['gt']; + $valueID = $id = CRM_Utils_Array::value('id', $params); + $force = CRM_Utils_Array::value('force', $params); + + // if valueID is not passed use default value + if (!$valueID) { + $valueID = $id = self::defaultGreeting($contactType, $greeting); + } + + $filter = array( + 'contact_type' => $contactType, + 'greeting_type' => $greeting, + ); + + $allGreetings = CRM_Core_PseudoConstant::greeting($filter); + $originalGreetingString = $greetingString = CRM_Utils_Array::value($valueID, $allGreetings); + if (!$greetingString) { + CRM_Core_Error::fatal(ts('Incorrect greeting value id %1, or no default greeting for this contact type and greeting type.', array(1 => $valueID))); + } + + // build return properties based on tokens + $greetingTokens = CRM_Utils_Token::getTokens($greetingString); + $tokens = CRM_Utils_Array::value('contact', $greetingTokens); + $greetingsReturnProperties = array(); + if (is_array($tokens)) { + $greetingsReturnProperties = array_fill_keys(array_values($tokens), 1); + } + + // Process ALL contacts only when force=1 or force=2 is passed. Else only contacts with NULL greeting or addressee value are updated. + $processAll = $processOnlyIdSet = FALSE; + if ($force == 1) { + $processAll = TRUE; + } + elseif ($force == 2) { + $processOnlyIdSet = TRUE; + } + + //FIXME : apiQuery should handle these clause. + $filterContactFldIds = $filterIds = array(); + $idFldName = $displayFldName = NULL; + if (in_array($greeting, CRM_Contact_BAO_Contact::$_greetingTypes)) { + $idFldName = $greeting . '_id'; + $displayFldName = $greeting . '_display'; + } + + if ($idFldName) { + // if $force == 1 then update all contacts else only + // those with NULL greeting or addressee value CRM-9476 + if ($processAll) { + $sql = "SELECT DISTINCT id, $idFldName FROM civicrm_contact WHERE contact_type = %1 "; + } + else { + $sql = "SELECT DISTINCT id, $idFldName FROM civicrm_contact WHERE contact_type = %1 + AND ( {$idFldName} IS NULL OR ( {$idFldName} IS NOT NULL AND {$displayFldName} IS NULL ) ) "; + } + + $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($contactType, 'String'))); + while ($dao->fetch()) { + $filterContactFldIds[$dao->id] = $dao->$idFldName; + + if (!CRM_Utils_System::isNull($dao->$idFldName)) { + $filterIds[$dao->id] = $dao->$idFldName; + } + } + } + + if (empty($filterContactFldIds)) { + $filterContactFldIds[] = 0; + } + + // retrieve only required contact information + $extraParams[] = array('contact_type', '=', $contactType, 0, 0); + // we do token replacement in the replaceGreetingTokens hook + list($greetingDetails) = CRM_Utils_Token::getTokenDetails(array_keys($filterContactFldIds), + $greetingsReturnProperties, + FALSE, FALSE, $extraParams + ); + // perform token replacement and build update SQL + $contactIds = array(); + $cacheFieldQuery = "UPDATE civicrm_contact SET {$greeting}_display = CASE id "; + foreach ($greetingDetails as $contactID => $contactDetails) { + if (!$processAll && + !array_key_exists($contactID, $filterContactFldIds) + ) { + continue; + } + + if ($processOnlyIdSet && !array_key_exists($contactID, $filterIds)) { + continue; + } + + if ($id) { + $greetingString = $originalGreetingString; + $contactIds[] = $contactID; + } + else { + if ($greetingBuffer = CRM_Utils_Array::value($filterContactFldIds[$contactID], $allGreetings)) { + $greetingString = $greetingBuffer; + } + } + + CRM_Utils_Token::replaceGreetingTokens($greetingString, $contactDetails, $contactID, 'CRM_UpdateGreeting'); + $greetingString = CRM_Core_DAO::escapeString($greetingString); + $cacheFieldQuery .= " WHEN {$contactID} THEN '{$greetingString}' "; + + $allContactIds[] = $contactID; + } + + if (!empty($allContactIds)) { + $cacheFieldQuery .= " ELSE {$greeting}_display + END;"; + if (!empty($contactIds)) { + // need to update greeting _id field. + // reset greeting _custom + $resetCustomGreeting = ''; + if ($valueID != 4) { + $resetCustomGreeting = ", {$greeting}_custom = NULL "; + } + + $queryString = " +UPDATE civicrm_contact +SET {$greeting}_id = {$valueID} + {$resetCustomGreeting} +WHERE id IN (" . implode(',', $contactIds) . ")"; + CRM_Core_DAO::executeQuery($queryString); + } + + // now update cache field + CRM_Core_DAO::executeQuery($cacheFieldQuery); + } + } + + /** + * Fetch the default greeting for a given contact type + * + * @param string $contactType contact type + * @param string $greetingType greeting type + * + * @return int or null + */ + static function defaultGreeting($contactType, $greetingType) { + $contactTypeFilters = array('Individual' => 1, 'Household' => 2, 'Organization' => 3); + if (!isset($contactTypeFilters[$contactType])) { + return; + } + $filter = $contactTypeFilters[$contactType]; + + $id = CRM_Core_OptionGroup::values($greetingType, NULL, NULL, NULL, + " AND is_default = 1 AND (filter = {$filter} OR filter = 0)", + 'value' + ); + if (!empty($id)) { + return current($id); + } + } +} + diff --git a/CRM/Contact/BAO/ContactType.php b/CRM/Contact/BAO/ContactType.php new file mode 100644 index 0000000000..4010b97678 --- /dev/null +++ b/CRM/Contact/BAO/ContactType.php @@ -0,0 +1,852 @@ +copyValues($params); + if ($contactType->find(TRUE)) { + CRM_Core_DAO::storeValues($contactType, $defaults); + return $contactType; + } + return NULL; + } + + static function isActive($contactType) { + $contact = self::contactTypeInfo(FALSE); + $active = array_key_exists($contactType, $contact) ? TRUE : FALSE; + return $active; + } + + /** + * + *function to retrieve basic contact type information. + * + *@return array of basic contact types information. + *@static + * + */ + static function &basicTypeInfo($all = FALSE) { + static $_cache = NULL; + + if ($_cache === NULL) { + $_cache = array(); + } + + $argString = $all ? 'CRM_CT_BTI_1' : 'CRM_CT_BTI_0'; + if (!array_key_exists($argString, $_cache)) { + $cache = CRM_Utils_Cache::singleton(); + $_cache[$argString] = $cache->get($argString); + if (!$_cache[$argString]) { + $sql = " +SELECT * +FROM civicrm_contact_type +WHERE parent_id IS NULL +"; + if ($all === FALSE) { + $sql .= " AND is_active = 1"; + } + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray, + FALSE, + 'CRM_Contact_DAO_ContactType' + ); + while ($dao->fetch()) { + $value = array(); + CRM_Core_DAO::storeValues($dao, $value); + $_cache[$argString][$dao->name] = $value; + } + + $cache->set($argString, $_cache[$argString]); + } + } + return $_cache[$argString]; + } + + /** + * + *function to retrieve all basic contact types. + * + *@return array of basic contact types + *@static + * + */ + static function basicTypes($all = FALSE) { + return array_keys(self::basicTypeInfo($all)); + } + + static function basicTypePairs($all = FALSE, $key = 'name') { + $subtypes = self::basicTypeInfo($all); + + $pairs = array(); + foreach ($subtypes as $name => $info) { + $index = ($key == 'name') ? $name : $info[$key]; + $pairs[$index] = $info['label']; + } + return $pairs; + } + + /** + * + *function to retrieve all subtypes Information. + * + *@param array $contactType. + *@return array of sub type information + *@static + * + */ + static function &subTypeInfo($contactType = NULL, $all = FALSE, $ignoreCache = FALSE, $reset = FALSE) { + static $_cache = NULL; + + if ($reset === TRUE) { + $_cache = NULL; + } + + if ($_cache === NULL) { + $_cache = array(); + } + if ($contactType && !is_array($contactType)) { + $contactType = array($contactType); + } + + $argString = $all ? 'CRM_CT_STI_1_' : 'CRM_CT_STI_0_'; + if (!empty($contactType)) { + $argString .= implode('_', $contactType); + } + + if ((!array_key_exists($argString, $_cache)) || $ignoreCache) { + $cache = CRM_Utils_Cache::singleton(); + $_cache[$argString] = $cache->get($argString); + if (!$_cache[$argString] || $ignoreCache) { + $_cache[$argString] = array(); + + $ctWHERE = ''; + if (!empty($contactType)) { + $ctWHERE = " AND parent.name IN ('" . implode("','", $contactType) . "')"; + } + + $sql = " +SELECT subtype.*, parent.name as parent, parent.label as parent_label +FROM civicrm_contact_type subtype +INNER JOIN civicrm_contact_type parent ON subtype.parent_id = parent.id +WHERE subtype.name IS NOT NULL AND subtype.parent_id IS NOT NULL {$ctWHERE} +"; + if ($all === FALSE) { + $sql .= " AND subtype.is_active = 1 AND parent.is_active = 1 ORDER BY parent.id"; + } + $dao = CRM_Core_DAO::executeQuery($sql, array(), + FALSE, 'CRM_Contact_DAO_ContactType' + ); + while ($dao->fetch()) { + $value = array(); + CRM_Core_DAO::storeValues($dao, $value); + $value['parent'] = $dao->parent; + $value['parent_label'] = $dao->parent_label; + $_cache[$argString][$dao->name] = $value; + } + + $cache->set($argString, $_cache[$argString]); + } + } + return $_cache[$argString]; + } + + /** + * + *function to retrieve all subtypes + * + *@param array $contactType. + *@return list of all subtypes OR list of subtypes associated to + *a given basic contact type + *@static + * + */ + static function subTypes($contactType = NULL, $all = FALSE, $columnName = 'name', $ignoreCache = FALSE) { + if ($columnName == 'name') { + return array_keys(self::subTypeInfo($contactType, $all, $ignoreCache)); + } + else { + return array_values(self::subTypePairs($contactType, FALSE, NULL, $ignoreCache)); + } + } + + /** + * + *function to retrieve subtype pairs with name as 'subtype-name' and 'label' as value + * + *@param array $contactType. + *@return list of subtypes with name as 'subtype-name' and 'label' as value + *@static + * + */ + static function subTypePairs($contactType = NULL, $all = FALSE, $labelPrefix = '- ', $ignoreCache = FALSE) { + $subtypes = self::subTypeInfo($contactType, $all, $ignoreCache); + + $pairs = array(); + foreach ($subtypes as $name => $info) { + $pairs[$name] = $labelPrefix . $info['label']; + } + return $pairs; + } + + /** + * + *function to retrieve list of all types i.e basic + subtypes. + * + *@return array of basic types + all subtypes. + *@static + * + */ + static function contactTypes($all = FALSE) { + return array_keys(self::contactTypeInfo($all)); + } + + /** + * + *function to retrieve info array about all types i.e basic + subtypes. + * + *@return array of basic types + all subtypes. + *@static + * + */ + static function contactTypeInfo($all = FALSE, $reset = FALSE) { + static $_cache = NULL; + + if ($reset === TRUE) { + $_cache = NULL; + } + + if ($_cache === NULL) { + $_cache = array(); + } + + $argString = $all ? 'CRM_CT_CTI_1' : 'CRM_CT_CTI_0'; + if (!array_key_exists($argString, $_cache)) { + $cache = CRM_Utils_Cache::singleton(); + $_cache[$argString] = $cache->get($argString); + if (!$_cache[$argString]) { + $_cache[$argString] = array(); + + $sql = " +SELECT type.*, parent.name as parent, parent.label as parent_label +FROM civicrm_contact_type type +LEFT JOIN civicrm_contact_type parent ON type.parent_id = parent.id +WHERE type.name IS NOT NULL +"; + if ($all === FALSE) { + $sql .= " AND type.is_active = 1"; + } + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray, + FALSE, + 'CRM_Contact_DAO_ContactType' + ); + while ($dao->fetch()) { + $value = array(); + CRM_Core_DAO::storeValues($dao, $value); + if (array_key_exists('parent_id', $value)) { + $value['parent'] = $dao->parent; + $value['parent_label'] = $dao->parent_label; + } + $_cache[$argString][$dao->name] = $value; + } + + $cache->set($argString, $_cache[$argString]); + } + } + + return $_cache[$argString]; + } + + /** + * + *function to retrieve basic type pairs with name as 'built-in name' and 'label' as value + * + *@param array $contactType. + *@return list of basictypes with name as 'built-in name' and 'label' as value + *@static + * + */ + static function contactTypePairs($all = FALSE, $typeName = NULL, $delimiter = NULL) { + $types = self::contactTypeInfo($all); + + if ($typeName && !is_array($typeName)) { + $typeName = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($typeName, CRM_Core_DAO::VALUE_SEPARATOR)); + } + + $pairs = array(); + if ($typeName) { + foreach ($typeName as $type) { + if (array_key_exists($type, $types)) { + $pairs[$type] = $types[$type]['label']; + } + } + } + else { + foreach ($types as $name => $info) { + $pairs[$name] = $info['label']; + } + } + + return !$delimiter ? $pairs : implode($delimiter, $pairs); + } + + static function &getSelectElements($all = FALSE, + $isSeperator = TRUE, + $seperator = CRM_Core_DAO::VALUE_SEPARATOR + ) { + static $_cache = NULL; + + if ($_cache === NULL) { + $_cache = array(); + } + + $argString = $all ? 'CRM_CT_GSE_1' : 'CRM_CT_GSE_0'; + $argString .= $isSeperator ? '_1' : '_0'; + if (!array_key_exists($argString, $_cache)) { + $cache = CRM_Utils_Cache::singleton(); + $_cache[$argString] = $cache->get($argString); + + if (!$_cache[$argString]) { + $_cache[$argString] = array(); + + $sql = " +SELECT c.name as child_name , c.label as child_label , c.id as child_id, + p.name as parent_name, p.label as parent_label, p.id as parent_id +FROM civicrm_contact_type c +LEFT JOIN civicrm_contact_type p ON ( c.parent_id = p.id ) +WHERE ( c.name IS NOT NULL ) +"; + + if ($all === FALSE) { + $sql .= " +AND c.is_active = 1 +AND ( p.is_active = 1 OR p.id IS NULL ) +"; + } + $sql .= " ORDER BY c.id"; + + $values = array(); + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + if (!empty($dao->parent_id)) { + $key = $isSeperator ? $dao->parent_name . $seperator . $dao->child_name : $dao->child_name; + $label = "- {$dao->child_label}"; + $pName = $dao->parent_name; + } + else { + $key = $dao->child_name; + $label = $dao->child_label; + $pName = $dao->child_name; + } + + if (!isset($values[$pName])) { + $values[$pName] = array(); + } + $values[$pName][] = array('key' => $key, 'label' => $label); + } + + $selectElements = array(); + foreach ($values as $pName => $elements) { + foreach ($elements as $element) { + $selectElements[$element['key']] = $element['label']; + } + } + $_cache[$argString] = $selectElements; + + $cache->set($argString, $_cache[$argString]); + } + } + return $_cache[$argString]; + } + + /** + * function to check if a given type is a subtype + * + *@param string $subType contact subType. + *@return boolean true if subType, false otherwise. + *@static + * + */ + static function isaSubType($subType, $ignoreCache = FALSE) { + return in_array($subType, self::subTypes(NULL, TRUE, 'name', $ignoreCache)); + } + + /** + *function to retrieve the basic contact type associated with + *given subType. + * + *@param array/string $subType contact subType. + *@return array/string of basicTypes. + *@static + * + */ + static function getBasicType($subType) { + static $_cache = NULL; + if ($_cache === NULL) { + $_cache = array(); + } + + $isArray = TRUE; + if ($subType && !is_array($subType)) { + $subType = array($subType); + $isArray = FALSE; + } + $argString = implode('_', $subType); + + if (!array_key_exists($argString, $_cache)) { + $_cache[$argString] = array(); + + $sql = " +SELECT subtype.name as contact_subtype, type.name as contact_type +FROM civicrm_contact_type subtype +INNER JOIN civicrm_contact_type type ON ( subtype.parent_id = type.id ) +WHERE subtype.name IN ('" . implode("','", $subType) . "' )"; + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + if (!$isArray) { + $_cache[$argString] = $dao->contact_type; + break; + } + $_cache[$argString][$dao->contact_subtype] = $dao->contact_type; + } + } + return $_cache[$argString]; + } + + /** + * + *function to suppress all subtypes present in given array. + * + *@param array $subType contact subType. + *@return array of suppresssubTypes . + *@static + * + */ + static function suppressSubTypes(&$subTypes, $ignoreCache = FALSE) { + $subTypes = array_diff($subTypes, self::subTypes(NULL, TRUE, 'name', $ignoreCache)); + return $subTypes; + } + + /** + * + *function to verify if a given subtype is associated with a given basic contact type. + * + *@param string $subType contact subType + *@param string $contactType contact Type + *@return boolean true if contact extends, false otherwise. + *@static + * + */ + static function isExtendsContactType($subType, $contactType, $ignoreCache = FALSE, $columnName = 'name') { + if (!is_array($subType)) { + $subType = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($subType, CRM_Core_DAO::VALUE_SEPARATOR)); + } + $subtypeList = self::subTypes($contactType, TRUE, $columnName, $ignoreCache); + $intersection = array_intersect($subType, $subtypeList); + return $subType == $intersection; + } + + /** + * + *function to create shortcuts menu for contactTypes + * + *@return array of contactTypes + *@static + * + */ + static function getCreateNewList() { + $shortCuts = array(); + $contactTypes = self::getSelectElements(); + foreach ($contactTypes as $key => $value) { + if ($key) { + $typeValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $key); + $typeUrl = 'ct=' . CRM_Utils_Array::value('0', $typeValue); + if ($csType = CRM_Utils_Array::value('1', $typeValue)) { + $typeUrl .= "&cst=$csType"; + } + $shortCuts[] = array( + 'path' => 'civicrm/contact/add', + 'query' => "$typeUrl&reset=1", + 'ref' => "new-$value", + 'title' => $value, + ); + } + } + return $shortCuts; + } + + /** + * Function to delete Contact SubTypes + * + * @param int $contactTypeId ID of the Contact Subtype to be deleted. + * + * @access public + * @static + */ + static function del($contactTypeId) { + + if (!$contactTypeId) { + return FALSE; + } + + $params = array('id' => $contactTypeId); + self::retrieve($params, $typeInfo); + $name = $typeInfo['name']; + // check if any custom group + $custom = new CRM_Core_DAO_CustomGroup(); + $custom->whereAdd("extends_entity_column_value LIKE '%" . + CRM_Core_DAO::VALUE_SEPARATOR . + $name . + CRM_Core_DAO::VALUE_SEPARATOR . "%'" + ); + if ($custom->find()) { + return FALSE; + } + + // remove subtype for existing contacts + $sql = " +UPDATE civicrm_contact SET contact_sub_type = NULL +WHERE contact_sub_type = '$name'"; + CRM_Core_DAO::executeQuery($sql); + + // remove subtype from contact type table + $contactType = new CRM_Contact_DAO_ContactType(); + $contactType->id = $contactTypeId; + $contactType->delete(); + + // remove navigation entry if any + if ($name) { + $sql = " +DELETE +FROM civicrm_navigation +WHERE name = %1"; + $params = array(1 => array("New $name", 'String')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + CRM_Core_BAO_Navigation::resetNavigation(); + } + return TRUE; + } + + /** + * Function to add or update Contact SubTypes + * + * @param array $params an assoc array of name/value pairs + * + * @return object + * @access public + * @static + */ + static function add($params) { + + // label or name + if (!CRM_Utils_Array::value('label', $params)) { + return; + } + if (CRM_Utils_Array::value('parent_id', $params) && + !CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_ContactType', $params['parent_id']) + ) { + return; + } + + $contactType = new CRM_Contact_DAO_ContactType(); + $contactType->copyValues($params); + $contactType->id = CRM_Utils_Array::value('id', $params); + $contactType->is_active = CRM_Utils_Array::value('is_active', $params, 0); + + + + $contactType->save(); + if ($contactType->find(TRUE)) { + $contactName = $contactType->name; + $contact = ucfirst($contactType->label); + $active = $contactType->is_active; + } + + if (CRM_Utils_Array::value('id', $params)) { + $params = array('name' => "New $contactName"); + $newParams = array( + 'label' => "New $contact", + 'is_active' => $active, + ); + CRM_Core_BAO_Navigation::processUpdate($params, $newParams); + } + else { + $name = self::getBasicType($contactName); + if (!$name) { + return; + } + $value = array('name' => "New $name"); + CRM_Core_BAO_Navigation::retrieve($value, $navinfo); + $navigation = array( + 'label' => "New $contact", + 'name' => "New $contactName", + 'url' => "civicrm/contact/add&ct=$name&cst=$contactName&reset=1", + 'permission' => 'add contacts', + 'parent_id' => $navinfo['id'], + 'is_active' => $active, + ); + CRM_Core_BAO_Navigation::add($navigation); + } + CRM_Core_BAO_Navigation::resetNavigation(); + + // reset the cache after adding + self::subTypeInfo(NULL, FALSE, FALSE, TRUE); + + return $contactType; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on success, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + $params = array('id' => $id); + self::retrieve($params, $contactinfo); + $params = array('name' => "New $contactinfo[name]"); + $newParams = array('is_active' => $is_active); + CRM_Core_BAO_Navigation::processUpdate($params, $newParams); + CRM_Core_BAO_Navigation::resetNavigation(); + return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_ContactType', $id, + 'is_active', $is_active + ); + } + + static function getLabel($typeName) { + $types = self::contactTypeInfo(TRUE); + + if (array_key_exists($typeName, $types)) { + return $types[$typeName]['label']; + } + return $typeName; + } + + /** + * Function to check whether allow to change any contact's subtype + * on the basis of custom data and relationship of specific subtype + * currently used in contact/edit form amd in import validation + * + * @param int $contactId contact id. + * @param string $subType subtype. + * + * @return boolean true/false. + * @static + */ + static function isAllowEdit($contactId, $subType = NULL) { + + if (!$contactId) { + return TRUE; + } + + if (empty($subType)) { + $subType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $contactId, + 'contact_sub_type' + ); + } + + if (self::hasCustomData($subType, $contactId) || self::hasRelationships($contactId, $subType)) { + return FALSE; + } + + return TRUE; + } + + static function hasCustomData($contactType, $contactId = NULL) { + $subTypeClause = ''; + + if (self::isaSubType($contactType)) { + $subType = $contactType; + $contactType = self::getBasicType($subType); + + // check for empty custom data which extends subtype + $subTypeValue = CRM_Core_DAO::VALUE_SEPARATOR . $subType . CRM_Core_DAO::VALUE_SEPARATOR; + $subTypeClause = " AND extends_entity_column_value LIKE '%{$subTypeValue}%' "; + } + $query = "SELECT table_name FROM civicrm_custom_group WHERE extends = '{$contactType}' {$subTypeClause}"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $sql = "SELECT count(id) FROM {$dao->table_name}"; + if ($contactId) { + $sql .= " WHERE entity_id = {$contactId}"; + } + $sql .= " LIMIT 1"; + + $customDataCount = CRM_Core_DAO::singleValueQuery($sql); + if (!empty($customDataCount)) { + $dao->free(); + return TRUE; + } + } + return FALSE; + } + + static function hasRelationships($contactId, $contactType) { + $subTypeClause = NULL; + if (self::isaSubType($contactType)) { + $subType = $contactType; + $contactType = self::getBasicType($subType); + $subTypeClause = " AND ( ( crt.contact_type_a = '{$contactType}' AND crt.contact_sub_type_a = '{$subType}') OR + ( crt.contact_type_b = '{$contactType}' AND crt.contact_sub_type_b = '{$subType}') ) "; + } + else { + $subTypeClause = " AND ( crt.contact_type_a = '{$contactType}' OR crt.contact_type_b = '{$contactType}' ) "; + } + + // check relationships for + $relationshipQuery = " +SELECT count(cr.id) FROM civicrm_relationship cr +INNER JOIN civicrm_relationship_type crt ON +( cr.relationship_type_id = crt.id {$subTypeClause} ) +WHERE ( cr.contact_id_a = {$contactId} OR cr.contact_id_b = {$contactId} ) +LIMIT 1"; + + $relationshipCount = CRM_Core_DAO::singleValueQuery($relationshipQuery); + + if (!empty($relationshipCount)) { + return TRUE; + } + + return FALSE; + } + + static function getSubtypeCustomPair($contactType, $subtypeSet = array( + )) { + if (empty($subtypeSet)) { + return $subtypeSet; + } + + $customSet = $subTypeClause = array(); + foreach ($subtypeSet as $subtype) { + $subtype = CRM_Utils_Type::escape($subtype, 'String'); + $subType = CRM_Core_DAO::VALUE_SEPARATOR . $subtype . CRM_Core_DAO::VALUE_SEPARATOR; + $subTypeClause[] = "extends_entity_column_value LIKE '%{$subtype}%' "; + } + $query = "SELECT table_name +FROM civicrm_custom_group +WHERE extends = %1 AND " . implode(" OR ", $subTypeClause); + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactType, 'String'))); + while ($dao->fetch()) { + $customSet[] = $dao->table_name; + } + return array_unique($customSet); + } + + static function deleteCustomSetForSubtypeMigration($contactID, + $contactType, + $oldSubtypeSet = array(), + $newSubtypeSet = array() + ) { + $oldCustomSet = self::getSubtypeCustomPair($contactType, $oldSubtypeSet); + $newCustomSet = self::getSubtypeCustomPair($contactType, $newSubtypeSet); + + $customToBeRemoved = array_diff($oldCustomSet, $newCustomSet); + foreach ($customToBeRemoved as $customTable) { + self::deleteCustomRowsForEntityID($customTable, $contactID); + } + return TRUE; + } + + /** + * Delete content / rows of a custom table specific to a subtype for a given custom-group. + * This function currently works for contact subtypes only and could be later improved / genralized + * to work for other subtypes as well. + * + * @param int $gID - custom group id. + * @param array $subtypes - list of subtypes related to which entry is to be removed. + * + * @return void + * @access public + */ + function deleteCustomRowsOfSubtype($gID, $subtypes = array( + )) { + if (!$gID or empty($subtypes)) { + return FALSE; + } + + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $gID, 'table_name'); + + $subtypeClause = array(); + foreach ($subtypes as $subtype) { + $subtype = CRM_Utils_Type::escape($subtype, 'String'); + $subtypeClause[] = "civicrm_contact.contact_sub_type LIKE '%" . CRM_Core_DAO::VALUE_SEPARATOR . $subtype . CRM_Core_DAO::VALUE_SEPARATOR . "%'"; + } + $subtypeClause = implode(' OR ', $subtypeClause); + + $query = "DELETE custom.* +FROM {$tableName} custom +INNER JOIN civicrm_contact ON civicrm_contact.id = custom.entity_id +WHERE ($subtypeClause)"; + return CRM_Core_DAO::singleValueQuery($query); + } + + /** + * Delete content / rows of a custom table specific entity-id for a given custom-group table. + * + * @param int $customTable - custom table name. + * @param int $entityID - entity id. + * + * @return void + * @access public + */ + function deleteCustomRowsForEntityID($customTable, $entityID) { + $customTable = CRM_Utils_Type::escape($customTable, 'String'); + $query = "DELETE FROM {$customTable} WHERE entity_id = %1"; + return CRM_Core_DAO::singleValueQuery($query, array(1 => array($entityID, 'Integer'))); + } +} + diff --git a/CRM/Contact/BAO/Group.php b/CRM/Contact/BAO/Group.php new file mode 100644 index 0000000000..4e82c340af --- /dev/null +++ b/CRM/Contact/BAO/Group.php @@ -0,0 +1,1167 @@ +copyValues($params); + if ($group->find(TRUE)) { + CRM_Core_DAO::storeValues($group, $defaults); + return $group; + } + + return NULL; + } + + /** + * Function to delete the group and all the object that connect to + * this group. Incredibly destructive + * + * @param int $id group id + * + * @return null + * @access public + * @static + * + */ + static function discard($id) { + CRM_Utils_Hook::pre('delete', 'Group', $id, CRM_Core_DAO::$_nullArray); + + $transaction = new CRM_Core_Transaction(); + + // added for CRM-1631 and CRM-1794 + // delete all subscribed mails with the selected group id + $subscribe = new CRM_Mailing_Event_DAO_Subscribe(); + $subscribe->group_id = $id; + $subscribe->delete(); + + // delete all Subscription records with the selected group id + $subHistory = new CRM_Contact_DAO_SubscriptionHistory(); + $subHistory->group_id = $id; + $subHistory->delete(); + + // delete all crm_group_contact records with the selected group id + $groupContact = new CRM_Contact_DAO_GroupContact(); + $groupContact->group_id = $id; + $groupContact->delete(); + + // make all the 'add_to_group_id' field of 'civicrm_uf_group table', pointing to this group, as null + $params = array(1 => array($id, 'Integer')); + $query = "UPDATE civicrm_uf_group SET `add_to_group_id`= NULL WHERE `add_to_group_id` = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + $query = "UPDATE civicrm_uf_group SET `limit_listings_group_id`= NULL WHERE `limit_listings_group_id` = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + // make sure u delete all the entries from civicrm_mailing_group and civicrm_campaign_group + // CRM-6186 + $query = "DELETE FROM civicrm_mailing_group where entity_table = 'civicrm_group' AND entity_id = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + $query = "DELETE FROM civicrm_campaign_group where entity_table = 'civicrm_group' AND entity_id = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + $query = "DELETE FROM civicrm_acl_entity_role where entity_table = 'civicrm_group' AND entity_id = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'is_enabled' + )) { + // clear any descendant groups cache if exists + $finalGroups = CRM_Core_BAO_Cache::deleteGroup('descendant groups for an org'); + } + + // delete from group table + $group = new CRM_Contact_DAO_Group(); + $group->id = $id; + $group->delete(); + + $transaction->commit(); + + CRM_Utils_Hook::post('delete', 'Group', $id, $group); + + // delete the recently created Group + $groupRecent = array( + 'id' => $id, + 'type' => 'Group', + ); + CRM_Utils_Recent::del($groupRecent); + } + + /** + * Returns an array of the contacts in the given group. + * + */ + static function getGroupContacts($id) { + $params = array(array('group', 'IN', array($id => 1), 0, 0)); + list($contacts, $_) = CRM_Contact_BAO_Query::apiQuery($params, array('contact_id')); + return $contacts; + } + + /** + * Get the count of a members in a group with the specific status + * + * @param int $id group id + * @param enum $status status of members in group + * + * @return int count of members in the group with above status + * @access public + */ + static function memberCount($id, $status = 'Added', $countChildGroups = FALSE) { + $groupContact = new CRM_Contact_DAO_GroupContact(); + $groupIds = array($id); + if ($countChildGroups) { + $groupIds = CRM_Contact_BAO_GroupNesting::getDescendentGroupIds($groupIds); + } + $count = 0; + + $contacts = self::getGroupContacts($id); + + foreach ($groupIds as $groupId) { + + $groupContacts = self::getGroupContacts($groupId); + foreach ($groupContacts as $gcontact) { + if ($groupId != $id) { + // Loop through main group's contacts + // and subtract from the count for each contact which + // matches one in the present group, if it is not the + // main group + foreach ($contacts as $contact) { + if ($contact['contact_id'] == $gcontact['contact_id']) { + $count--; + } + } + } + } + $groupContact->group_id = $groupId; + if (isset($status)) { + $groupContact->status = $status; + } + $groupContact->_query['condition'] = 'WHERE contact_id NOT IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)'; + $count += $groupContact->count(); + } + return $count; + } + + /** + * Get the list of member for a group id + * + * @param int $lngGroupId this is group id + * + * @return array $aMembers this arrray contains the list of members for this group id + * @access public + * @static + */ + static function &getMember($groupID, $useCache = TRUE) { + $params = array(array('group', 'IN', array($groupID => 1), 0, 0)); + $returnProperties = array('contact_id'); + list($contacts, $_) = CRM_Contact_BAO_Query::apiQuery($params, $returnProperties, NULL, NULL, 0, 0, $useCache); + + $aMembers = array(); + foreach ($contacts as $contact) { + $aMembers[$contact['contact_id']] = 1; + } + + return $aMembers; + } + + /** + * Returns array of group object(s) matching a set of one or Group properties. + * + * @param array $param Array of one or more valid property_name=>value pairs. + * Limits the set of groups returned. + * @param array $returnProperties Which properties should be included in the returned group objects. + * (member_count should be last element.) + * + * @return An array of group objects. + * + * @access public + * + * @todo other BAO functions that use returnProperties (e.g. Query Objects) receive the array flipped & filled with 1s and + * add in essential fields (e.g. id). This should follow a regular pattern like the others + */ + static function getGroups( + $params = NULL, + $returnProperties = NULL, + $sort = NULL, + $offset = NULL, + $rowCount = NULL + ) { + $dao = new CRM_Contact_DAO_Group(); + $dao->is_active = 1; + if ($params) { + foreach ($params as $k => $v) { + if ($k == 'name' || $k == 'title') { + $dao->whereAdd($k . ' LIKE "' . CRM_Core_DAO::escapeString($v) . '"'); + } + elseif (is_array($v)) { + $dao->whereAdd($k . ' IN (' . implode(',', $v) . ')'); + } + else { + $dao->$k = $v; + } + } + } + + if ($offset || $rowCount) { + $offset = ($offset > 0) ? $offset : 0; + $rowCount = ($rowCount > 0) ? $rowCount : 25; + $dao->limit($offset, $rowCount); + } + + if ($sort) { + $dao->orderBy($sort); + } + + // return only specific fields if returnproperties are sent + if (!empty($returnProperties)) { + $dao->selectAdd(); + $dao->selectAdd(implode(',', $returnProperties)); + } + $dao->find(); + + $flag = $returnProperties && in_array('member_count', $returnProperties) ? 1 : 0; + + $groups = array(); + while ($dao->fetch()) { + $group = new CRM_Contact_DAO_Group(); + if ($flag) { + $dao->member_count = CRM_Contact_BAO_Group::memberCount($dao->id); + } + $groups[] = clone($dao); + } + return $groups; + } + + /** + * make sure that the user has permission to access this group + * + * @param int $id the id of the object + * + * @return string the permission that the user has (or null) + * @access public + * @static + */ + static function checkPermission($id) { + $allGroups = CRM_Core_PseudoConstant::allGroup(); + + $permissions = NULL; + if (CRM_Core_Permission::check('edit all contacts') || + CRM_ACL_API::groupPermission(CRM_ACL_API::EDIT, $id, NULL, + 'civicrm_saved_search', $allGroups + ) + ) { + $permissions[] = CRM_Core_Permission::EDIT; + } + + if (CRM_Core_Permission::check('view all contacts') || + CRM_ACL_API::groupPermission(CRM_ACL_API::VIEW, $id, NULL, + 'civicrm_saved_search', $allGroups + ) + ) { + $permissions[] = CRM_Core_Permission::VIEW; + } + + if (!empty($permissions) && CRM_Core_Permission::check('delete contacts')) { + // Note: using !empty() in if condition, restricts the scope of delete + // permission to groups/contacts that are editable/viewable. + // We can remove this !empty condition once we have ACL support for delete functionality. + $permissions[] = CRM_Core_Permission::DELETE; + } + + return $permissions; + } + + /** + * Create a new group + * + * @param array $params Associative array of parameters + * + * @return object|null The new group BAO (if created) + * @access public + * @static + */ + public static function &create(&$params) { + + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::pre('edit', 'Group', $params['id'], $params); + } + else { + CRM_Utils_Hook::pre('create', 'Group', NULL, $params); + } + + // form the name only if missing: CRM-627 + if (!CRM_Utils_Array::value('name', $params) && + !CRM_Utils_Array::value('id', $params) + ) { + $params['name'] = CRM_Utils_String::titleToVar($params['title']); + } + + // convert params if array type + if (isset($params['group_type'])) { + if (is_array($params['group_type'])) { + $params['group_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($params['group_type']) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + } + } + else { + $params['group_type'] = ''; + } + + $session = CRM_Core_Session::singleton( ); + if ($cid = $session->get('userID')) { + $params['created_id'] = $cid; + } + + $group = new CRM_Contact_BAO_Group(); + $group->copyValues($params); + + if (!CRM_Utils_Array::value('id', $params)) { + $group->name .= "_tmp"; + } + $group->save(); + + if (!$group->id) { + return NULL; + } + + if (!CRM_Utils_Array::value('id', $params)) { + $group->name = substr($group->name, 0, -4) . "_{$group->id}"; + } + + $group->buildClause(); + $group->save(); + + // add custom field values + if (CRM_Utils_Array::value('custom', $params)) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_group', $group->id); + } + + // make the group, child of domain/site group by default. + $domainGroupID = CRM_Core_BAO_Domain::getGroupId(); + if (CRM_Utils_Array::value('no_parent', $params) !== 1) { + if (empty($params['parents']) && + $domainGroupID != $group->id && + CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'is_enabled' + ) && + !CRM_Contact_BAO_GroupNesting::hasParentGroups($group->id) + ) { + // if no parent present and the group doesn't already have any parents, + // make sure site group goes as parent + $params['parents'] = array($domainGroupID => 1); + } + elseif (array_key_exists('parents', $params) && !is_array($params['parents'])) { + $params['parents'] = array($params['parents'] => 1); + } + + if (!empty($params['parents'])) { + foreach ($params['parents'] as $parentId => $dnc) { + if ($parentId && !CRM_Contact_BAO_GroupNesting::isParentChild($parentId, $group->id)) { + CRM_Contact_BAO_GroupNesting::add($parentId, $group->id); + } + } + } + + // clear any descendant groups cache if exists + $finalGroups = CRM_Core_BAO_Cache::deleteGroup('descendant groups for an org'); + + // this is always required, since we don't know when a + // parent group is removed + CRM_Contact_BAO_GroupNestingCache::update(); + + // update group contact cache for all parent groups + $parentIds = CRM_Contact_BAO_GroupNesting::getParentGroupIds($group->id); + foreach ($parentIds as $parentId) { + CRM_Contact_BAO_GroupContactCache::add($parentId); + } + } + + if (CRM_Utils_Array::value('organization_id', $params)) { + $groupOrg = array(); + $groupOrg = $params; + $groupOrg['group_id'] = $group->id; + CRM_Contact_BAO_GroupOrganization::add($groupOrg); + } + + CRM_Contact_BAO_GroupContactCache::add($group->id); + + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::post('edit', 'Group', $group->id, $group); + } + else { + CRM_Utils_Hook::post('create', 'Group', $group->id, $group); + } + + $recentOther = array(); + if (CRM_Core_Permission::check('edit groups')) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/group', 'reset=1&action=update&id=' . $group->id); + // currently same permission we are using for delete a group + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/group', 'reset=1&action=delete&id=' . $group->id); + } + + // add the recently added group (unless hidden: CRM-6432) + if (!$group->is_hidden) { + CRM_Utils_Recent::add($group->title, + CRM_Utils_System::url('civicrm/group/search', 'reset=1&force=1&context=smog&gid=' . $group->id), + $group->id, + 'Group', + NULL, + NULL, + $recentOther + ); + } + return $group; + } + + /** + * given a saved search compute the clause and the tables + * and store it for future use + */ + function buildClause() { + $params = array(array('group', 'IN', array($this->id => 1), 0, 0)); + + if (!empty($params)) { + $tables = $whereTables = array(); + $this->where_clause = CRM_Contact_BAO_Query::getWhereClause($params, NULL, $tables, $whereTables); + if (!empty($tables)) { + $this->select_tables = serialize($tables); + } + if (!empty($whereTables)) { + $this->where_tables = serialize($whereTables); + } + } + + return; + } + + /** + * Defines a new smart group + * + * @param array $params Associative array of parameters + * + * @return object|null The new group BAO (if created) + * @access public + * @static + */ + public static function createSmartGroup(&$params) { + if (CRM_Utils_Array::value('formValues', $params)) { + $ssParams = $params; + unset($ssParams['id']); + if (isset($ssParams['saved_search_id'])) { + $ssParams['id'] = $ssParams['saved_search_id']; + } + + $savedSearch = CRM_Contact_BAO_SavedSearch::create($params); + + $params['saved_search_id'] = $savedSearch->id; + } + else { + return NULL; + } + + return self::create($params); + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $isActive value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $isActive) { + return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Group', $id, 'is_active', $isActive); + } + + /** + * build the condition to retrieve groups. + * + * @param string $groupType type of group(Access/Mailing) OR the key of the group + * @param boolen $excludeHidden exclude hidden groups. + * + * @return string $condition + * @static + */ + static function groupTypeCondition($groupType = NULL, $excludeHidden = TRUE) { + $value = NULL; + if ($groupType == 'Mailing') { + $value = CRM_Core_DAO::VALUE_SEPARATOR . '2' . CRM_Core_DAO::VALUE_SEPARATOR; + } + elseif ($groupType == 'Access') { + $value = CRM_Core_DAO::VALUE_SEPARATOR . '1' . CRM_Core_DAO::VALUE_SEPARATOR; + } + elseif (!empty($groupType)){ + // ie we have been given the group key + $value = CRM_Core_DAO::VALUE_SEPARATOR . $groupType . CRM_Core_DAO::VALUE_SEPARATOR; + } + + $condition = NULL; + if ($excludeHidden) { + $condition = "is_hidden = 0"; + } + + if ($value) { + if ($condition) { + $condition .= " AND group_type LIKE '%$value%'"; + } + else { + $condition = "group_type LIKE '%$value%'"; + } + } + + return $condition; + } + + public function __toString() { + return $this->title; + } + + /** + * This function create the hidden smart group when user perform + * contact seach and want to send mailing to search contacts. + * + * @param array $params ( reference ) an assoc array of name/value pairs + * + * @return array ( smartGroupId, ssId ) smart group id and saved search id + * @access public + * @static + */ + static function createHiddenSmartGroup($params) { + $ssId = CRM_Utils_Array::value('saved_search_id', $params); + + //add mapping record only for search builder saved search + $mappingId = NULL; + if ($params['search_context'] == 'builder') { + //save the mapping for search builder + if (!$ssId) { + //save record in mapping table + $temp = array(); + $mappingParams = array('mapping_type' => 'Search Builder'); + $mapping = CRM_Core_BAO_Mapping::add($mappingParams, $temp); + $mappingId = $mapping->id; + } + else { + //get the mapping id from saved search + $savedSearch = new CRM_Contact_BAO_SavedSearch(); + $savedSearch->id = $ssId; + $savedSearch->find(TRUE); + $mappingId = $savedSearch->mapping_id; + } + + //save mapping fields + CRM_Core_BAO_Mapping::saveMappingFields($params['form_values'], $mappingId); + } + + //create/update saved search record. + $savedSearch = new CRM_Contact_BAO_SavedSearch(); + $savedSearch->id = $ssId; + $savedSearch->form_values = serialize($params['form_values']); + $savedSearch->mapping_id = $mappingId; + $savedSearch->search_custom_id = CRM_Utils_Array::value('search_custom_id', $params); + $savedSearch->save(); + + $ssId = $savedSearch->id; + if (!$ssId) { + return NULL; + } + + $smartGroupId = NULL; + if (CRM_Utils_Array::value('saved_search_id', $params)) { + $smartGroupId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $ssId, 'id', 'saved_search_id'); + } + else { + //create group only when new saved search. + $groupParams = array( + 'title' => "Hidden Smart Group {$ssId}", + 'is_active' => CRM_Utils_Array::value('is_active', $params, 1), + 'is_hidden' => CRM_Utils_Array::value('is_hidden', $params, 1), + 'group_type' => CRM_Utils_Array::value('group_type', $params), + 'visibility' => CRM_Utils_Array::value('visibility', $params), + 'saved_search_id' => $ssId, + ); + + $smartGroup = self::create($groupParams); + $smartGroupId = $smartGroup->id; + } + + return array($smartGroupId, $ssId); + } + + /** + * This function is a wrapper for ajax group selector + * + * @param array $params associated array for params record id. + * + * @return array $groupList associated array of group list + * @access public + */ + public function getGroupListSelector(&$params) { + // format the params + $params['offset'] = ($params['page'] - 1) * $params['rp']; + $params['rowCount'] = $params['rp']; + $params['sort'] = CRM_Utils_Array::value('sortBy', $params); + + // get groups + $groups = CRM_Contact_BAO_Group::getGroupList($params); + + //skip total if we are making call to show only children + if ( !CRM_Utils_Array::value('parent_id', $params) ) { + // add total + $params['total'] = CRM_Contact_BAO_Group::getGroupCount($params); + + // get all the groups + $allGroups = CRM_Core_PseudoConstant::allGroup(); + } + + // format params and add links + $groupList = array(); + if (!empty($groups)) { + foreach ($groups as $id => $value) { + $groupList[$id]['group_id'] = $value['id']; + $groupList[$id]['group_name'] = $value['title']; + $groupList[$id]['class'] = $value['class']; + + // append parent names if in search mode + if ( !CRM_Utils_Array::value('parent_id', $params) && + CRM_Utils_Array::value( 'parents', $value ) ) { + $groupIds = explode(',', $value['parents']); + $title = array(); + foreach($groupIds as $gId) { + $title[] = $allGroups[$gId]; + } + $groupList[$id]['group_name'] .= '
    '.ts('Child of').': ' . implode(', ', $title) . '
    '; + $groupList[$id]['class'] = ''; + } + + $groupList[$id]['group_description'] = CRM_Utils_Array::value('description', $value); + if ( CRM_Utils_Array::value('group_type', $value) ) { + $groupList[$id]['group_type'] = $value['group_type']; + } + else { + $groupList[$id]['group_type'] = ''; + } + $groupList[$id]['visibility'] = $value['visibility']; + $groupList[$id]['links'] = $value['action']; + $groupList[$id]['org_info'] = CRM_Utils_Array::value('org_info', $value); + $groupList[$id]['created_by'] = CRM_Utils_Array::value('created_by', $value); + + $groupList[$id]['is_parent'] = $value['is_parent']; + } + return $groupList; + } + } + + /** + * This function to get list of groups + * + * @param array $params associated array for params + * @access public + */ + static function getGroupList(&$params) { + $config = CRM_Core_Config::singleton(); + + $whereClause = self::whereClause($params, FALSE); + + //$this->pagerAToZ( $whereClause, $params ); + + if (!empty($params['rowCount']) && + $params['rowCount'] > 0 + ) { + $limit = " LIMIT {$params['offset']}, {$params['rowCount']} "; + } + + $orderBy = ' ORDER BY groups.title asc'; + if (CRM_Utils_Array::value('sort', $params)) { + $orderBy = ' ORDER BY ' . CRM_Utils_Array::value('sort', $params); + } + + $select = $from = $where = ""; + $groupOrg = FALSE; + if (CRM_Core_Permission::check('administer Multiple Organizations') && + CRM_Core_Permission::isMultisiteEnabled() + ) { + $select = ", contact.display_name as org_name, contact.id as org_id"; + $from = " LEFT JOIN civicrm_group_organization gOrg + ON gOrg.group_id = groups.id + LEFT JOIN civicrm_contact contact + ON contact.id = gOrg.organization_id "; + + //get the Organization ID + $orgID = CRM_Utils_Request::retrieve('oid', 'Positive', CRM_Core_DAO::$_nullObject); + if ($orgID) { + $where = " AND gOrg.organization_id = {$orgID}"; + } + + $groupOrg = TRUE; + } + + $query = " + SELECT groups.*, createdBy.sort_name as created_by {$select} + FROM civicrm_group groups + LEFT JOIN civicrm_contact createdBy + ON createdBy.id = groups.created_id + {$from} + WHERE $whereClause {$where} + {$orderBy} + {$limit}"; + + $object = CRM_Core_DAO::executeQuery($query, $params, TRUE, 'CRM_Contact_DAO_Group'); + + //FIXME CRM-4418, now we are handling delete separately + //if we introduce 'delete for group' make sure to handle here. + $groupPermissions = array(CRM_Core_Permission::VIEW); + if (CRM_Core_Permission::check('edit groups')) { + $groupPermissions[] = CRM_Core_Permission::EDIT; + $groupPermissions[] = CRM_Core_Permission::DELETE; + } + + // CRM-9936 + $reservedPermission = CRM_Core_Permission::check('administer reserved groups'); + + $links = self::actionLinks(); + + $allTypes = CRM_Core_OptionGroup::values('group_type'); + $values = array(); + + while ($object->fetch()) { + $permission = CRM_Contact_BAO_Group::checkPermission($object->id, $object->title); + if ($permission) { + $newLinks = $links; + $values[$object->id] = array(); + CRM_Core_DAO::storeValues($object, $values[$object->id]); + if ($object->saved_search_id) { + $values[$object->id]['title'] .= ' (' . ts('Smart Group') . ')'; + // check if custom search, if so fix view link + $customSearchID = CRM_Core_DAO::getFieldValue( + 'CRM_Contact_DAO_SavedSearch', + $object->saved_search_id, + 'search_custom_id' + ); + + if ($customSearchID) { + $newLinks[CRM_Core_Action::VIEW]['url'] = 'civicrm/contact/search/custom'; + $newLinks[CRM_Core_Action::VIEW]['qs'] = "reset=1&force=1&ssID={$object->saved_search_id}"; + } + } + + $action = array_sum(array_keys($newLinks)); + + // CRM-9936 + if (array_key_exists('is_reserved', $object)) { + //if group is reserved and I don't have reserved permission, suppress delete/edit + if ($object->is_reserved && !$reservedPermission) { + $action -= CRM_Core_Action::DELETE; + $action -= CRM_Core_Action::UPDATE; + $action -= CRM_Core_Action::DISABLE; + } + } + + $values[$object->id]['class'] = ''; + if (array_key_exists('is_active', $object)) { + if ($object->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $values[$object->id]['class'] = 'disabled'; + $action -= CRM_Core_Action::VIEW; + $action -= CRM_Core_Action::DISABLE; + } + } + + $action = $action & CRM_Core_Action::mask($groupPermissions); + + $values[$object->id]['visibility'] = CRM_Contact_DAO_Group::tsEnum('visibility', + $values[$object->id]['visibility'] + ); + if (isset($values[$object->id]['group_type'])) { + $groupTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($values[$object->id]['group_type'], 1, -1) + ); + $types = array(); + foreach ($groupTypes as $type) { + $types[] = CRM_Utils_Array::value($type, $allTypes); + } + $values[$object->id]['group_type'] = implode(', ', $types); + } + $values[$object->id]['action'] = CRM_Core_Action::formLink($newLinks, + $action, + array( + 'id' => $object->id, + 'ssid' => $object->saved_search_id, + ) + ); + + // If group has children, add class for link to view children + $values[$object->id]['is_parent'] = false; + if (array_key_exists('children', $values[$object->id])) { + $values[$object->id]['class'] = "crm-group-parent"; + $values[$object->id]['is_parent'] = true; + } + + // If group is a child, add child class + if (array_key_exists('parents', $values[$object->id])) { + $values[$object->id]['class'] = "crm-group-child"; + } + + if (array_key_exists('children', $values[$object->id]) + && array_key_exists('parents', $values[$object->id])) { + $values[$object->id]['class'] = "crm-group-child crm-group-parent"; + } + + if ($groupOrg) { + if ($object->org_id) { + $contactUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$object->org_id}"); + $values[$object->id]['org_info'] = "{$object->org_name}"; + } + else { + $values[$object->id]['org_info'] = ''; // Empty cell + } + } + else { + $values[$object->id]['org_info'] = NULL; // Collapsed column if all cells are NULL + } + if ($object->created_id) { + $contactUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$object->created_id}"); + $values[$object->id]['created_by'] = "{$object->created_by}"; + } + } + } + + return $values; + } + + /** + * This function to get hierarchical list of groups (parent followed by children) + * + * @param array $params associated array for params + * @access public + */ + static function getGroupsHierarchy ( + $groupIds, + $parents = NULL, + $spacer = '', + $titleOnly = FALSE + ) { + // + // need to return id, title (w/ spacer), description, visibility + + // We need to build a list of tags ordered by hierarchy and sorted by + // name. The heirarchy will be communicated by an accumulation of + // separators in front of the name to give it a visual offset. + // Instead of recursively making mysql queries, we'll make one big + // query and build the heirarchy with the algorithm below. + $groups = array(); + $args = array(1 => array($groupIds, 'String')); + $query = "SELECT id, title, description, visibility, parents + FROM civicrm_group + WHERE id $groupIds"; + if ($parents) { + // group can have > 1 parent so parents may be comma separated list (eg. '1,2,5'). We just grab and match on 1st parent. + $parentArray = explode(',', $parents); + $parent = $parentArray[0]; + $args[2] = array($parent, 'Integer'); + $query .= " AND SUBSTRING_INDEX(parents, ',', 1) = %2"; + } + $query .= " ORDER BY title"; + $dao = CRM_Core_DAO::executeQuery($query, $args); + + // Sort the groups into the correct storage by the parent + // $roots represent the current leaf nodes that need to be checked for + // children. $rows represent the unplaced nodes + $roots = $rows = $allGroups = array(); + while ($dao->fetch()) { + $allGroups[$dao->id] = array('title' => $dao->title, + 'visibility' => $dao->visibility, + 'description' => $dao->description); + + if ($dao->parents == $parents) { + $roots[] = array('id' => $dao->id, + 'prefix' => '', + 'title' => $dao->title); + } + else { + // group can have > 1 parent so $dao->parents may be comma separated list (eg. '1,2,5'). Grab and match on 1st parent. + $parentArray = explode(',', $dao->parents); + $parent = $parentArray[0]; + $rows[] = array('id' => $dao->id, + 'prefix' => '', + 'title' => $dao->title, + 'parents' => $parent); + } + } + $dao->free(); + // While we have nodes left to build, shift the first (alphabetically) + // node of the list, place it in our groups list and loop through the + // list of unplaced nodes to find its children. We make a copy to + // iterate through because we must modify the unplaced nodes list + // during the loop. + while (count($roots)) { + $new_roots = array(); + $current_rows = $rows; + $root = array_shift($roots); + $groups[$root['id']] = array($root['prefix'], $root['title']); + + // As you find the children, append them to the end of the new set + // of roots (maintain alphabetical ordering). Also remove the node + // from the set of unplaced nodes. + if (is_array($current_rows)) { + foreach ($current_rows as $key => $row) { + if ($row['parents'] == $root['id']) { + $new_roots[] = array('id' => $row['id'], 'prefix' => $groups[$root['id']][0] . $spacer, 'title' => $row['title']); + unset($rows[$key]); + } + } + } + + //As a group, insert the new roots into the beginning of the roots + //list. This maintains the hierarchical ordering of the tags. + $roots = array_merge($new_roots, $roots); + } + + // Prefix titles with the calcuated spacing to give the visual + // appearance of ordering when transformed into HTML in the form layer. Add description and visibility. + $groupsReturn = array(); + foreach ($groups as $key=>$value) { + if ($titleOnly) { + $groupsReturn[$key] = $value[0] . $value[1]; + } else { + $groupsReturn[$key] = array('title' => $value[0] . $value[1], + 'description' => $allGroups[$key]['description'], + 'visibility' => $allGroups[$key]['visibility'],); + } + } + + return $groupsReturn; + } + + static function getGroupCount(&$params) { + $whereClause = self::whereClause($params, FALSE); + $query = "SELECT COUNT(*) FROM civicrm_group groups"; + + if (CRM_Utils_Array::value('created_by', $params)) { + $query .= " +INNER JOIN civicrm_contact createdBy + ON createdBy.id = groups.created_id"; + } + $query .= " +WHERE {$whereClause}"; + return CRM_Core_DAO::singleValueQuery($query, $params); + } + + function whereClause(&$params, $sortBy = TRUE, $excludeHidden = TRUE) { + $values = array(); + $clauses = array(); + + $title = CRM_Utils_Array::value('title', $params); + if ($title) { + $clauses[] = "groups.title LIKE %1"; + if (strpos($title, '%') !== FALSE) { + $params[1] = array($title, 'String', FALSE); + } + else { + $params[1] = array($title, 'String', TRUE); + } + } + + $groupType = CRM_Utils_Array::value('group_type', $params); + if ($groupType) { + $types = explode(',', $groupType); + if (!empty($types)) { + $clauses[] = 'groups.group_type LIKE %2'; + $typeString = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $types) . CRM_Core_DAO::VALUE_SEPARATOR; + $params[2] = array($typeString, 'String', TRUE); + } + } + + $visibility = CRM_Utils_Array::value('visibility', $params); + if ($visibility) { + $clauses[] = 'groups.visibility = %3'; + $params[3] = array($visibility, 'String'); + } + + $groupStatus = CRM_Utils_Array::value('status', $params); + if ($groupStatus) { + switch ($groupStatus) { + case 1: + $clauses[] = 'groups.is_active = 1'; + $params[4] = array($groupStatus, 'Integer'); + break; + + case 2: + $clauses[] = 'groups.is_active = 0'; + $params[4] = array($groupStatus, 'Integer'); + break; + + case 3: + $clauses[] = '(groups.is_active = 0 OR groups.is_active = 1 )'; + break; + } + } + + $parentsOnly = CRM_Utils_Array::value('parentsOnly', $params); + if ($parentsOnly) { + $clauses[] = 'groups.parents IS NULL'; + } + + // only show child groups of a specific parent group + $parent_id = CRM_Utils_Array::value('parent_id', $params); + if ($parent_id) { + $clauses[] = 'groups.id IN (SELECT child_group_id FROM civicrm_group_nesting WHERE parent_group_id = %5)'; + $params[5] = array($parent_id, 'Integer'); + } + + if ($createdBy = CRM_Utils_Array::value('created_by', $params)) { + $clauses[] = "createdBy.sort_name LIKE %6"; + if (strpos($createdBy, '%') !== FALSE) { + $params[6] = array($createdBy, 'String', FALSE); + } + else { + $params[6] = array($createdBy, 'String', TRUE); + } + } + + /* + if ( $sortBy && + $this->_sortByCharacter !== null ) { + $clauses[] = + "groups.title LIKE '" . + strtolower(CRM_Core_DAO::escapeWildCardString($this->_sortByCharacter)) . + "%'"; + } + + // dont do a the below assignement when doing a + // AtoZ pager clause + if ( $sortBy ) { + if ( count( $clauses ) > 1 ) { + $this->assign( 'isSearch', 1 ); + } else { + $this->assign( 'isSearch', 0 ); + } + } + */ + + + if (empty($clauses)) { + $clauses[] = 'groups.is_active = 1'; + } + + if ($excludeHidden) { + $clauses[] = 'groups.is_hidden = 0'; + } + + return implode(' AND ', $clauses); + } + + /** + * Function to define action links + * + * @return array $links array of action links + * @access public + */ + static function actionLinks() { + $links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('Contacts'), + 'url' => 'civicrm/group/search', + 'qs' => 'reset=1&force=1&context=smog&gid=%%id%%', + 'title' => ts('Group Contacts'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Settings'), + 'url' => 'civicrm/group', + 'qs' => 'reset=1&action=update&id=%%id%%', + 'title' => ts('Edit Group'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contact_BAO_Group' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Group'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contact_BAO_Group' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Group'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/group', + 'qs' => 'reset=1&action=delete&id=%%id%%', + 'title' => ts('Delete Group'), + ), + ); + + return $links; + } + + function pagerAtoZ($whereClause, $whereParams) { + $query = " + SELECT DISTINCT UPPER(LEFT(groups.title, 1)) as sort_name + FROM civicrm_group groups + WHERE $whereClause + ORDER BY LEFT(groups.title, 1) + "; + $dao = CRM_Core_DAO::executeQuery($query, $whereParams); + + return CRM_Utils_PagerAToZ::getAToZBar($dao, $this->_sortByCharacter, TRUE); + } +} + diff --git a/CRM/Contact/BAO/GroupContact.php b/CRM/Contact/BAO/GroupContact.php new file mode 100644 index 0000000000..835e37cdb7 --- /dev/null +++ b/CRM/Contact/BAO/GroupContact.php @@ -0,0 +1,792 @@ +copyValues($params); + CRM_Contact_BAO_SubscriptionHistory::create($params); + $groupContact->save(); + return $groupContact; + } + + /** + * Check if there is data to create the object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * @access public + * @static + */ + static function dataExists(&$params) { + // return if no data present + if ($params['group_id'] == 0) { + return FALSE; + } + + return TRUE; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $params input parameters to find object + * @param array $values output values of the object + * @param array $ids the array that holds all the db ids + * + * @return array (reference) the values that could be potentially assigned to smarty + * @access public + * @static + */ + static function getValues(&$params, &$values) { + if (empty($params)) { + return NULL; + } + $values['group']['data'] = &CRM_Contact_BAO_GroupContact::getContactGroup($params['contact_id'], + 'Added', + 3 + ); + + // get the total count of groups + $values['group']['totalCount'] = CRM_Contact_BAO_GroupContact::getContactGroup($params['contact_id'], + 'Added', + NULL, + TRUE + ); + + return NULL; + } + + /** + * Given an array of contact ids, add all the contacts to the group + * + * @param array $contactIds (reference ) the array of contact ids to be added + * @param int $groupId the id of the group + * + * @return array (total, added, notAdded) count of contacts added to group + * @access public + * @static + */ + static function addContactsToGroup( + &$contactIds, + $groupId, + $method = 'Admin', + $status = 'Added', + $tracking = NULL + ) { + + + CRM_Utils_Hook::pre('create', 'GroupContact', $groupId, $contactIds); + + list($numContactsAdded, + $numContactsNotAdded + ) = self::bulkAddContactsToGroup($contactIds, + $groupId, + $method, + $status, + $tracking + ); + + // also reset the acl cache + $config = CRM_Core_Config::singleton(); + if (!$config->doNotResetCache) { + CRM_ACL_BAO_Cache::resetCache(); + } + + // reset the group contact cache for all group(s) + // if this group is being used as a smart group + CRM_Contact_BAO_GroupContactCache::remove(); + + CRM_Utils_Hook::post('create', 'GroupContact', $groupId, $contactIds); + + return array(count($contactIds), $numContactsAdded, $numContactsNotAdded); + } + + /** + * Given an array of contact ids, remove all the contacts from the group + * + * @param array $contactIds (reference ) the array of contact ids to be removed + * @param int $groupId the id of the group + * + * @return array (total, removed, notRemoved) count of contacts removed to group + * @access public + * @static + */ + static function removeContactsFromGroup( + &$contactIds, + $groupId, + $method = 'Admin', + $status = 'Removed', + $tracking = NULL + ) { + if (!is_array($contactIds)) { + return array(0, 0, 0); + } + + if ($status == 'Removed' || $status == 'Deleted') { + $op = 'delete'; + } + else { + $op = 'edit'; + } + + CRM_Utils_Hook::pre($op, 'GroupContact', $groupId, $contactIds); + + $date = date('YmdHis'); + $numContactsRemoved = 0; + $numContactsNotRemoved = 0; + + $group = new CRM_Contact_DAO_Group(); + $group->id = $groupId; + $group->find(TRUE); + + foreach ($contactIds as $contactId) { + if ($status == 'Deleted') { + $query = "DELETE FROM civicrm_group_contact WHERE contact_id=$contactId AND group_id=$groupId"; + $dao = CRM_Core_DAO::executeQuery($query); + $historyParams = array( + 'group_id' => $groupId, + 'contact_id' => $contactId, + 'status' => $status, + 'method' => $method, + 'date' => $date, + 'tracking' => $tracking, + ); + CRM_Contact_BAO_SubscriptionHistory::create($historyParams); + } + else { + $groupContact = new CRM_Contact_DAO_GroupContact(); + $groupContact->group_id = $groupId; + $groupContact->contact_id = $contactId; + // check if the selected contact id already a member, or if this is + // an opt-out of a smart group. + // if not a member remove to groupContact else keep the count of contacts that are not removed + if ($groupContact->find(TRUE) || $group->saved_search_id) { + // remove the contact from the group + $numContactsRemoved++; + } + else { + $numContactsNotRemoved++; + } + + //now we grant the negative membership to contact if not member. CRM-3711 + $historyParams = array( + 'group_id' => $groupId, + 'contact_id' => $contactId, + 'status' => $status, + 'method' => $method, + 'date' => $date, + 'tracking' => $tracking, + ); + CRM_Contact_BAO_SubscriptionHistory::create($historyParams); + $groupContact->status = $status; + $groupContact->save(); + } + } + + // also reset the acl cache + $config = CRM_Core_Config::singleton(); + if (!$config->doNotResetCache) { + CRM_ACL_BAO_Cache::resetCache(); + } + + // reset the group contact cache for all group(s) + // if this group is being used as a smart group + CRM_Contact_BAO_GroupContactCache::remove(); + + CRM_Utils_Hook::post($op, 'GroupContact', $groupId, $contactIds); + + return array(count($contactIds), $numContactsRemoved, $numContactsNotRemoved); + } + + /** + * Function to get list of all the groups and groups for a contact + * + * @param int $contactId contact id + * + * @access public + * + * @return array $values this array has key-> group id and value group title + * @static + */ + static function getGroupList($contactId = 0, $visibility = FALSE) { + $group = new CRM_Contact_DAO_Group(); + + $select = $from = $where = ''; + + $select = 'SELECT DISTINCT civicrm_group.id, civicrm_group.title '; + $from = ' FROM civicrm_group '; + $where = " WHERE civicrm_group.is_active = 1 "; + if ($contactId) { + $from .= ' , civicrm_group_contact '; + $where .= " AND civicrm_group.id = civicrm_group_contact.group_id + AND civicrm_group_contact.contact_id = " . CRM_Utils_Type::escape($contactId, 'Integer'); + } + + if ($visibility) { + $where .= " AND civicrm_group.visibility != 'User and User Admin Only'"; + } + + $orderby = " ORDER BY civicrm_group.name"; + $sql = $select . $from . $where . $orderby; + + $group->query($sql); + + $values = array(); + while ($group->fetch()) { + $values[$group->id] = $group->title; + } + + return $values; + } + + /** + * Function to get the list of groups for contact based on status of group membership + * + * @param int $contactId contact id + * @param string $status state of membership + * @param int $numGroupContact number of groups for a contact that should be shown + * @param boolean $count true if we are interested only in the count + * @param boolean $ignorePermission true if we should ignore permissions for the current user + * useful in profile where permissions are limited for the user. If left + * at false only groups viewable by the current user are returned + * @param boolean $onlyPublicGroups true if we want to hide system groups + * + * @return array (reference )|int $values the relevant data object values for the contact or + * the total count when $count is true + * + * $access public + */ + static function &getContactGroup( + $contactId, + $status = NULL, + $numGroupContact = NULL, + $count = FALSE, + $ignorePermission = FALSE, + $onlyPublicGroups = FALSE, + $excludeHidden = TRUE + ) { + if ($count) { + $select = 'SELECT count(DISTINCT civicrm_group_contact.id)'; + } + else { + $select = 'SELECT + civicrm_group_contact.id as civicrm_group_contact_id, + civicrm_group.title as group_title, + civicrm_group.visibility as visibility, + civicrm_group_contact.status as status, + civicrm_group.id as group_id, + civicrm_group.is_hidden as is_hidden, + civicrm_subscription_history.date as date, + civicrm_subscription_history.method as method'; + } + + $where = " WHERE contact_a.id = %1 AND civicrm_group.is_active = 1 "; + + if ($excludeHidden) { + $where .= " AND civicrm_group.is_hidden = 0 "; + } + + $params = array(1 => array($contactId, 'Integer')); + if (!empty($status)) { + $where .= ' AND civicrm_group_contact.status = %2'; + $params[2] = array($status, 'String'); + } + $tables = array( + 'civicrm_group_contact' => 1, + 'civicrm_group' => 1, + 'civicrm_subscription_history' => 1, + ); + $whereTables = array(); + if ($ignorePermission) { + $permission = ' ( 1 ) '; + } + else { + $permission = CRM_Core_Permission::getPermissionedStaticGroupClause(CRM_Core_Permission::VIEW, $tables, $whereTables); + } + + $from = CRM_Contact_BAO_Query::fromClause($tables); + + $where .= " AND $permission "; + + if ($onlyPublicGroups) { + $where .= " AND civicrm_group.visibility != 'User and User Admin Only' "; + } + + $order = $limit = ''; + if (!$count) { + $order = ' ORDER BY civicrm_group.title, civicrm_subscription_history.date ASC'; + + if ($numGroupContact) { + $limit = " LIMIT 0, $numGroupContact"; + } + } + + $sql = $select . $from . $where . $order . $limit; + + if ($count) { + $result = CRM_Core_DAO::singleValueQuery($sql, $params); + return $result; + } + else { + $dao = CRM_Core_DAO::executeQuery($sql, $params); + $values = array(); + while ($dao->fetch()) { + $id = $dao->civicrm_group_contact_id; + $values[$id]['id'] = $id; + $values[$id]['group_id'] = $dao->group_id; + $values[$id]['title'] = $dao->group_title; + $values[$id]['visibility'] = $dao->visibility; + $values[$id]['is_hidden'] = $dao->is_hidden; + switch ($dao->status) { + case 'Added': + $prefix = 'in_'; + break; + + case 'Removed': + $prefix = 'out_'; + break; + + default: + $prefix = 'pending_'; + } + $values[$id][$prefix . 'date'] = $dao->date; + $values[$id][$prefix . 'method'] = $dao->method; + if ($status == 'Removed') { + $query = "SELECT `date` as `date_added` FROM civicrm_subscription_history WHERE id = (SELECT max(id) FROM civicrm_subscription_history WHERE contact_id = %1 AND status = \"Added\" AND group_id = $dao->group_id )"; + $dateDAO = CRM_Core_DAO::executeQuery($query, $params); + if ($dateDAO->fetch()) { + $values[$id]['date_added'] = $dateDAO->date_added; + } + } + } + return $values; + } + } + + /** + * Returns membership details of a contact for a group + * + * @param int $contactId id of the contact + * @param int $groupID Id of a perticuler group + * @param string $method If we want the subscription history details for a specific method + * + * @return object of group contact + * @access public + * @static + */ + function &getMembershipDetail($contactId, $groupID, $method = 'Email') { + $leftJoin = $where = $orderBy = null; + + if ($method) { + $leftJoin = + "LEFT JOIN civicrm_subscription_history ON (civicrm_group_contact.contact_id = civicrm_subscription_history.contact_id)"; + $where = "AND civicrm_subscription_history.method ='Email'"; + $orderBy = "ORDER BY civicrm_subscription_history.id DESC"; + } + $query = " +SELECT * + FROM civicrm_group_contact + $leftJoin + WHERE civicrm_group_contact.contact_id = %1 + AND civicrm_group_contact.group_id = %2 + $where + $orderBy +"; + + $params = array( + 1 => array($contactId, 'Integer'), + 2 => array($groupID, 'Integer'), + ); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $dao->fetch(); + return $dao; + } + + /** + * Method to update the Status of Group member form 'Pending' to 'Added' + * + * @param int $contactId id of the contact + * + * @param int $groupID Id of a perticuler group + * + * @param mixed $tracking tracking information for history + * + * @return null If success + * @access public + * @static + */ + static function updateGroupMembershipStatus($contactId, $groupID, $method = 'Email', $tracking = NULL) { + if (!isset($contactId) && !isset($groupID)) { + return CRM_Core_Error::fatal("$contactId or $groupID should not empty"); + } + + $query = " +UPDATE civicrm_group_contact + SET civicrm_group_contact.status = 'Added' + WHERE civicrm_group_contact.contact_id = %1 + AND civicrm_group_contact.group_id = %2"; + $params = array( + 1 => array($contactId, 'Integer'), + 2 => array($groupID, 'Integer'), + ); + + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $params = array( + 'contact_id' => $contactId, + 'group_id' => $groupID, + 'status' => 'Added', + 'method' => $method, + 'tracking' => $tracking, + ); + + CRM_Contact_BAO_SubscriptionHistory::create($params); + return NULL; + } + + /** + * Method to get Group Id + * + * @param int $groupContactID Id of a perticuler group + * + * + * @return groupID + * @access public + * @static + */ + static function getGroupId($groupContactID) { + $dao = new CRM_Contact_DAO_GroupContact(); + $dao->id = $groupContactID; + $dao->find(TRUE); + return $dao->group_id; + } + + /** + * takes an associative array and creates / removes + * contacts from the groups + * + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $contactId contact id + * + * @return none + * @access public + * @static + */ + static function create(&$params, $contactId, $visibility = FALSE, $method = 'Admin') { + $contactIds = array(); + $contactIds[] = $contactId; + + //if $visibility is true we are coming in via profile mean $method = 'Web' + $ignorePermission = FALSE; + if ($visibility) { + $ignorePermission = TRUE; + } + + if ($contactId) { + $contactGroupList = &CRM_Contact_BAO_GroupContact::getContactGroup($contactId, 'Added', + NULL, FALSE, $ignorePermission + ); + if (is_array($contactGroupList)) { + foreach ($contactGroupList as $key) { + $groupId = $key['group_id']; + $contactGroup[$groupId] = $groupId; + } + } + } + + // get the list of all the groups + $allGroup = CRM_Contact_BAO_GroupContact::getGroupList(0, $visibility); + + // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input + if (!is_array($params)) { + $params = array(); + } + + // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input + if (!isset($contactGroup) || !is_array($contactGroup)) { + $contactGroup = array(); + } + + // check which values has to be add/remove contact from group + foreach ($allGroup as $key => $varValue) { + if (CRM_Utils_Array::value($key, $params) && !array_key_exists($key, $contactGroup)) { + // add contact to group + CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $key, $method); + } + elseif (!CRM_Utils_Array::value($key, $params) && array_key_exists($key, $contactGroup)) { + // remove contact from group + CRM_Contact_BAO_GroupContact::removeContactsFromGroup($contactIds, $key, $method); + } + } + } + + static function isContactInGroup($contactID, $groupID) { + if (!CRM_Utils_Rule::positiveInteger($contactID) || + !CRM_Utils_Rule::positiveInteger($groupID) + ) { + return FALSE; + } + + $params = array( + array('group', 'IN', array($groupID => 1), 0, 0), + array('contact_id', '=', $contactID, 0, 0), + ); + list($contacts, $_) = CRM_Contact_BAO_Query::apiQuery($params, array('contact_id')); + + if (!empty($contacts)) { + return TRUE; + } + return FALSE; + } + + /** + * Function merges the groups from otherContactID to mainContactID + * along with subscription history + * + * @param int $mainContactId contact id of main contact record. + * @param int $otherContactId contact id of record which is going to merge. + * + * @see CRM_Dedupe_Merger::cpTables() + * + * TODO: use the 3rd $sqls param to append sql statements rather than executing them here + * + * @return void. + * @static + */ + static function mergeGroupContact($mainContactId, $otherContactId) { + $params = array(1 => array($mainContactId, 'Integer'), + 2 => array($otherContactId, 'Integer'), + ); + + // find all groups that are in otherContactID but not in mainContactID, copy them over + $sql = " +SELECT cOther.group_id +FROM civicrm_group_contact cOther +LEFT JOIN civicrm_group_contact cMain ON cOther.group_id = cMain.group_id AND cMain.contact_id = %1 +WHERE cOther.contact_id = %2 +AND cMain.contact_id IS NULL +"; + $dao = CRM_Core_DAO::executeQuery($sql, $params); + + $otherGroupIDs = array(); + while ($dao->fetch()) { + $otherGroupIDs[] = $dao->group_id; + } + + if (!empty($otherGroupIDs)) { + $otherGroupIDString = implode(',', $otherGroupIDs); + + $sql = " +UPDATE civicrm_group_contact +SET contact_id = %1 +WHERE contact_id = %2 +AND group_id IN ( $otherGroupIDString ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + + $sql = " +UPDATE civicrm_subscription_history +SET contact_id = %1 +WHERE contact_id = %2 +AND group_id IN ( $otherGroupIDString ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + } + + $sql = " +SELECT cOther.group_id as group_id, + cOther.status as group_status +FROM civicrm_group_contact cMain +INNER JOIN civicrm_group_contact cOther ON cMain.group_id = cOther.group_id +WHERE cMain.contact_id = %1 +AND cOther.contact_id = %2 +"; + $dao = CRM_Core_DAO::executeQuery($sql, $params); + + $groupIDs = array(); + while ($dao->fetch()) { + // only copy it over if it has added status and migrate the history + if ($dao->group_status == 'Added') { + $groupIDs[] = $dao->group_id; + } + } + + if (!empty($groupIDs)) { + $groupIDString = implode(',', $groupIDs); + + $sql = " +UPDATE civicrm_group_contact +SET status = 'Added' +WHERE contact_id = %1 +AND group_id IN ( $groupIDString ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + + $sql = " +UPDATE civicrm_subscription_history +SET contact_id = %1 +WHERE contact_id = %2 +AND group_id IN ( $groupIDString ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + } + + // delete all the other group contacts + $sql = " + DELETE + FROM civicrm_group_contact + WHERE contact_id = %2 + "; + CRM_Core_DAO::executeQuery($sql, $params); + + $sql = " + DELETE + FROM civicrm_subscription_history + WHERE contact_id = %2 + "; + CRM_Core_DAO::executeQuery($sql, $params); + } + + /** + * Given an array of contact ids, add all the contacts to the group + * + * @param array $contactIds (reference ) the array of contact ids to be added + * @param int $groupId the id of the group + * + * @return array (total, added, notAdded) count of contacts added to group + * @access public + * @static + */ + static function bulkAddContactsToGroup( + $contactIDs, + $groupID, + $method = 'Admin', + $status = 'Added', + $tracking = NULL + ) { + + $numContactsAdded = 0; + $numContactsNotAdded = 0; + + $contactGroupSQL = " +REPLACE INTO civicrm_group_contact ( group_id, contact_id, status ) +VALUES +"; + $subscriptioHistorySQL = " +INSERT INTO civicrm_subscription_history( group_id, contact_id, date, method, status, tracking ) +VALUES +"; + + $date = date('YmdHis'); + + // to avoid long strings, lets do BULK_INSERT_HIGH_COUNT values at a time + while (!empty($contactIDs)) { + $input = array_splice($contactIDs, 0, CRM_Core_DAO::BULK_INSERT_HIGH_COUNT); + $contactStr = implode(',', $input); + + // lets check their current status + $sql = " +SELECT GROUP_CONCAT(contact_id) as contactStr +FROM civicrm_group_contact +WHERE group_id = %1 +AND status = %2 +AND contact_id IN ( $contactStr ) +"; + $params = array(1 => array($groupID, 'Integer'), + 2 => array($status, 'String'), + ); + + $presentIDs = array(); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + $presentIDs = explode(',', $dao->contactStr); + $presentIDs = array_flip($presentIDs); + } + + $gcValues = $shValues = array(); + foreach ($input as $cid) { + if (isset($presentIDs[$cid])) { + $numContactsNotAdded++; + continue; + } + + $gcValues[] = "( $groupID, $cid, '$status' )"; + $shValues[] = "( $groupID, $cid, '$date', '$method', '$status', '$tracking' )"; + $numContactsAdded++; + } + + if (!empty($gcValues)) { + $cgSQL = $contactGroupSQL . implode(",\n", $gcValues); + CRM_Core_DAO::executeQuery($cgSQL); + + $shSQL = $subscriptioHistorySQL . implode(",\n", $shValues); + CRM_Core_DAO::executeQuery($shSQL); + } + } + + return array($numContactsAdded, $numContactsNotAdded); + } +} + diff --git a/CRM/Contact/BAO/GroupContactCache.php b/CRM/Contact/BAO/GroupContactCache.php new file mode 100644 index 0000000000..7fb320b275 --- /dev/null +++ b/CRM/Contact/BAO/GroupContactCache.php @@ -0,0 +1,511 @@ + 0) { + $limitClause = " LIMIT 0, $limit"; + $orderClause = " ORDER BY g.cache_date, g.refresh_date"; + } + $query = " +SELECT g.id +FROM civicrm_group g +WHERE ( g.saved_search_id IS NOT NULL OR + g.children IS NOT NULL ) +AND ( g.cache_date IS NULL OR + ( TIMESTAMPDIFF(MINUTE, g.cache_date, $now) >= $smartGroupCacheTimeout ) OR + ( $now >= g.refresh_date ) + ) + $groupIDClause + $limitClause + $orderClause +"; + + $dao = CRM_Core_DAO::executeQuery($query); + $processGroupIDs = array(); + $refreshGroupIDs = $groupIDs; + while ($dao->fetch()) { + $processGroupIDs[] = $dao->id; + + // remove this id from refreshGroupIDs + foreach ($refreshGroupIDs as $idx => $gid) { + if ($gid == $dao->id) { + unset($refreshGroupIDs[$idx]); + break; + } + } + } + + if (!empty($refreshGroupIDs)) { + $refreshGroupIDString = CRM_Core_DAO::escapeString(implode(', ', $refreshGroupIDString)); + $time = CRM_Utils_Date::getUTCTime('YmdHis', $smartGroupCacheTimeout * 60); + $query = " +UPDATE civicrm_group g +SET g.refresh_date = $time +WHERE g.id IN ( {$refreshGroupIDString} ) +AND g.refresh_date IS NULL +"; + } + + if (empty($processGroupIDs)) { + return TRUE; + } + else { + self::add($processGroupIDs); + return FALSE; + } + } + + static function add($groupID) { + // first delete the current cache + self::remove($groupID); + if (!is_array($groupID)) { + $groupID = array($groupID); + } + + $returnProperties = array('contact_id'); + foreach ($groupID as $gid) { + $params = array(array('group', 'IN', array($gid => 1), 0, 0)); + // the below call update the cache table as a byproduct of the query + CRM_Contact_BAO_Query::apiQuery($params, $returnProperties, NULL, NULL, 0, 0, FALSE); + } + } + + static function store(&$groupID, &$values) { + $processed = FALSE; + + // sort the values so we put group IDs in front and hence optimize + // mysql storage (or so we think) CRM-9493 + sort($values); + + // to avoid long strings, lets do BULK_INSERT_COUNT values at a time + while (!empty($values)) { + $processed = TRUE; + $input = array_splice($values, 0, CRM_Core_DAO::BULK_INSERT_COUNT); + $str = implode(',', $input); + $sql = "INSERT IGNORE INTO civicrm_group_contact_cache (group_id,contact_id) VALUES $str;"; + CRM_Core_DAO::executeQuery($sql); + } + self::updateCacheTime($groupID, $processed); + } + + /** + * Change the cache_date + * + * @param $groupID array(int) + * @param $processed bool, whether the cache data was recently modified + */ + static function updateCacheTime($groupID, $processed) { + // only update cache entry if we had any values + if ($processed) { + // also update the group with cache date information + //make sure to give original timezone settings again. + $now = CRM_Utils_Date::getUTCTime(); + $refresh = 'null'; + } + else { + $now = 'null'; + $refresh = 'null'; + } + + $groupIDs = implode(',', $groupID); + $sql = " +UPDATE civicrm_group +SET cache_date = $now, refresh_date = $refresh +WHERE id IN ( $groupIDs ) +"; + CRM_Core_DAO::executeQuery($sql); + } + + static function remove($groupID = NULL, $onceOnly = TRUE) { + static $invoked = FALSE; + + // typically this needs to happy only once per instance + // this is especially true in import, where we dont need + // to do this all the time + // this optimization is done only when no groupID is passed + // i.e. cache is reset for all groups + if ($onceOnly && + $invoked && + $groupID == NULL + ) { + return; + } + + if ($groupID == NULL) { + $invoked = TRUE; + } else if (is_array($groupID)) { + foreach ($groupID as $gid) + unset(self::$_alreadyLoaded[$gid]); + } else if ($groupID && array_key_exists($groupID, self::$_alreadyLoaded)) { + unset(self::$_alreadyLoaded[$groupID]); + } + + $refresh = null; + $params = array(); + $smartGroupCacheTimeout = self::smartGroupCacheTimeout(); + + $now = CRM_Utils_Date::getUTCTime(); + $refreshTime = CRM_Utils_Date::getUTCTime('YmdHis', $smartGroupCacheTimeout * 60); + + if (!isset($groupID)) { + if ($smartGroupCacheTimeout == 0) { + $query = " +TRUNCATE civicrm_group_contact_cache +"; + $update = " +UPDATE civicrm_group g +SET cache_date = null, + refresh_date = null +"; + } + else { + $query = " +DELETE gc +FROM civicrm_group_contact_cache gc +INNER JOIN civicrm_group g ON g.id = gc.group_id +WHERE TIMESTAMPDIFF(MINUTE, g.cache_date, $now) >= $smartGroupCacheTimeout +"; + $update = " +UPDATE civicrm_group g +SET cache_date = null, + refresh_date = null +WHERE TIMESTAMPDIFF(MINUTE, cache_date, $now) >= $smartGroupCacheTimeout +"; + $refresh = " +UPDATE civicrm_group g +SET refresh_date = $refreshTime +WHERE TIMESTAMPDIFF(MINUTE, cache_date, $now) < $smartGroupCacheTimeout +AND refresh_date IS NULL +"; + } + } + elseif (is_array($groupID)) { + $groupIDs = implode(', ', $groupID); + $query = " +DELETE g +FROM civicrm_group_contact_cache g +WHERE g.group_id IN ( $groupIDs ) +"; + $update = " +UPDATE civicrm_group g +SET cache_date = null, + refresh_date = null +WHERE id IN ( $groupIDs ) +"; + } + else { + $query = " +DELETE g +FROM civicrm_group_contact_cache g +WHERE g.group_id = %1 +"; + $update = " +UPDATE civicrm_group g +SET cache_date = null, + refresh_date = null +WHERE id = %1 +"; + $params = array(1 => array($groupID, 'Integer')); + } + + CRM_Core_DAO::executeQuery($query, $params); + + if ($refresh) { + CRM_Core_DAO::executeQuery($refresh, $params); + } + + // also update the cache_date for these groups + CRM_Core_DAO::executeQuery($update, $params); + } + + /** + * load the smart group cache for a saved search + */ + static function load(&$group, $fresh = FALSE) { + $groupID = $group->id; + $savedSearchID = $group->saved_search_id; + if (array_key_exists($groupID, self::$_alreadyLoaded) && !$fresh) { + return; + } + self::$_alreadyLoaded[$groupID] = 1; + $sql = NULL; + $idName = 'id'; + $customClass = NULL; + if ($savedSearchID) { + $ssParams = CRM_Contact_BAO_SavedSearch::getSearchParams($savedSearchID); + + // rectify params to what proximity search expects if there is a value for prox_distance + // CRM-7021 + if (!empty($ssParams)) { + CRM_Contact_BAO_ProximityQuery::fixInputParams($ssParams); + } + + + $returnProperties = array(); + if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $savedSearchID, 'mapping_id')) { + $fv = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID); + $returnProperties = CRM_Core_BAO_Mapping::returnProperties($fv); + } + + if (isset($ssParams['customSearchID'])) { + // if custom search + + // we split it up and store custom class + // so temp tables are not destroyed if they are used + // hence customClass is defined above at top of function + $customClass = + CRM_Contact_BAO_SearchCustom::customClass($ssParams['customSearchID'], $savedSearchID); + $searchSQL = $customClass->contactIDs(); + $idName = 'contact_id'; + } + else { + $formValues = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID); + + $query = + new CRM_Contact_BAO_Query( + $ssParams, $returnProperties, NULL, + FALSE, FALSE, 1, + TRUE, TRUE, + FALSE, + CRM_Utils_Array::value('display_relationship_type', $formValues), + CRM_Utils_Array::value('operator', $formValues, 'AND') + ); + $query->_useDistinct = FALSE; + $query->_useGroupBy = FALSE; + $searchSQL = + $query->searchQuery( + 0, 0, NULL, + FALSE, FALSE, + FALSE, TRUE, + TRUE, + NULL, NULL, NULL, + TRUE + ); + } + $groupID = CRM_Utils_Type::escape($groupID, 'Integer'); + $sql = $searchSQL . " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.status = 'Removed' + AND civicrm_group_contact.group_id = $groupID ) "; + } + + if ($sql) { + $sql = preg_replace("/^\s*SELECT/", "SELECT $groupID as group_id, ", $sql); + } + + // lets also store the records that are explicitly added to the group + // this allows us to skip the group contact LEFT JOIN + $sqlB = " +SELECT $groupID as group_id, contact_id as $idName +FROM civicrm_group_contact +WHERE civicrm_group_contact.status = 'Added' + AND civicrm_group_contact.group_id = $groupID "; + + $groupIDs = array($groupID); + self::remove($groupIDs); + + foreach (array($sql, $sqlB) as $selectSql) { + if (!$selectSql) { + continue; + } + $insertSql = "INSERT IGNORE INTO civicrm_group_contact_cache (group_id,contact_id) ($selectSql);"; + $processed = TRUE; // FIXME + $result = CRM_Core_DAO::executeQuery($insertSql); + } + self::updateCacheTime($groupIDs, $processed); + + if ($group->children) { + + //Store a list of contacts who are removed from the parent group + $sql = " +SELECT contact_id +FROM civicrm_group_contact +WHERE civicrm_group_contact.status = 'Removed' +AND civicrm_group_contact.group_id = $groupID "; + $dao = CRM_Core_DAO::executeQuery($sql); + $removed_contacts = array(); + while ($dao->fetch()) { + $removed_contacts[] = $dao->contact_id; + } + + $childrenIDs = explode(',', $group->children); + foreach ($childrenIDs as $childID) { + $contactIDs = CRM_Contact_BAO_Group::getMember($childID, FALSE); + //Unset each contact that is removed from the parent group + foreach ($removed_contacts as $removed_contact) { + unset($contactIDs[$removed_contact]); + } + $values = array(); + foreach ($contactIDs as $contactID => $dontCare) { + $values[] = "({$groupID},{$contactID})"; + } + + self::store($groupIDs, $values); + } + } + } + + static function smartGroupCacheTimeout() { + $config = CRM_Core_Config::singleton(); + + if ( + isset($config->smartGroupCacheTimeout) && + is_numeric($config->smartGroupCacheTimeout) && + $config->smartGroupCacheTimeout > 0) { + return $config->smartGroupCacheTimeout; + } + + // lets have a min cache time of 5 mins if not set + return 5; + } + + static function contactGroup($contactID) { + if (empty($contactID)) { + return; + } + + if (is_array($contactID)) { + $contactIDs = $contactID; + } + else { + $contactIDs = array($contactID); + } + + self::loadAll(); + + $contactIDString = CRM_Core_DAO::escapeString(implode(', ', $contactIDs)); + $sql = " +SELECT gc.group_id, gc.contact_id, g.title, g.children, g.description +FROM civicrm_group_contact_cache gc +INNER JOIN civicrm_group g ON g.id = gc.group_id +WHERE gc.contact_id IN ($contactIDString) +ORDER BY gc.contact_id, g.children +"; + + $dao = CRM_Core_DAO::executeQuery($sql); + $contactGroup = array(); + $prevContactID = null; + while ($dao->fetch()) { + if ( + $prevContactID && + $prevContactID != $dao->contact_id + ) { + $contactGroup[$prevContactID]['groupTitle'] = implode(', ', $contactGroup[$prevContactID]['groupTitle']); + } + $prevContactID = $dao->contact_id; + if (!array_key_exists($dao->contact_id, $contactGroup)) { + $contactGroup[$dao->contact_id] = + array( 'group' => array(), 'groupTitle' => array()); + } + + $contactGroup[$dao->contact_id]['group'][] = + array( + 'id' => $dao->group_id, + 'title' => $dao->title, + 'description' => $dao->description, + 'children' => $dao->children + ); + $contactGroup[$dao->contact_id]['groupTitle'][] = $dao->title; + } + + if ($prevContactID) { + $contactGroup[$prevContactID]['groupTitle'] = implode(', ', $contactGroup[$prevContactID]['groupTitle']); + } + + if (is_numeric($contactID)) { + return $contactGroup[$contactID]; + } + else { + return $contactGroup; + } + } + +} + diff --git a/CRM/Contact/BAO/GroupNesting.php b/CRM/Contact/BAO/GroupNesting.php new file mode 100644 index 0000000000..39d8d25f84 --- /dev/null +++ b/CRM/Contact/BAO/GroupNesting.php @@ -0,0 +1,688 @@ +_styleLabels = $styleLabels; + $this->_styleIndent = $styleIndent; + } + + function setSortOrder($sortOrder) { + switch ($sortOrder) { + case 'ASC': + case 'DESC': + if ($sortOrder != self::$_sortOrder) { + self::$_sortOrder = $sortOrder; + $this->rewind(); + } + break; + + default: + // spit out some error, someday + } + } + + function getSortOrder() { + return self::$_sortOrder; + } + + function getCurrentNestingLevel() { + return count($this->_parentStack); + } + + /** + * Go back to the first element in the group nesting graph, + * which is the first group (according to _sortOrder) that + * has no parent groups + */ + function rewind() { + $this->_parentStack = array(); + // calling _getNextParentlessGroup w/ no arguments + // makes it return the first parentless group + $firstGroup = $this->_getNextParentlessGroup(); + $this->_current = $firstGroup; + $this->_lastParentlessGroup = $firstGroup; + $this->_alreadyStyled = FALSE; + } + + function current() { + if ($this->_styleLabels && + $this->valid() && + !$this->_alreadyStyled + ) { + $styledGroup = clone($this->_current); + $nestingLevel = $this->getCurrentNestingLevel(); + $indent = ''; + while ($nestingLevel--) { + $indent .= $this->_styleIndent; + } + $styledGroup->title = $indent . $styledGroup->title; + + $this->_current = &$styledGroup; + $this->_alreadyStyled = TRUE; + } + return $this->_current; + } + + function key() { + $group = &$this->_current; + $ids = array(); + foreach ($this->_parentStack as $parentGroup) { + $ids[] = $parentGroup->id; + } + $key = implode('-', $ids); + if (strlen($key) > 0) { + $key .= '-'; + } + $key .= $group->id; + return $key; + } + + function next() { + $currentGroup = &$this->_current; + $childGroup = $this->_getNextChildGroup($currentGroup); + if ($childGroup) { + $nextGroup = &$childGroup; + $this->_parentStack[] = &$this->_current; + } + else { + $nextGroup = $this->_getNextSiblingGroup($currentGroup); + if (!$nextGroup) { + // no sibling, find an ancestor w/ a sibling + for (;; ) { + // since we pop this array everytime, we should be + // reasonably safe from infinite loops, I think :) + $ancestor = array_pop($this->_parentStack); + $this->_current = &$ancestor; + if ($ancestor == NULL) { + break; + } + $nextGroup = $this->_getNextSiblingGroup($ancestor); + if ($nextGroup) { + break; + } + } + } + } + $this->_current = &$nextGroup; + $this->_alreadyStyled = FALSE; + return $nextGroup; + } + + function valid() { + if ($this->_current) { + return TRUE; + } + else { + return FALSE; + } + } + + function _getNextParentlessGroup(&$group = NULL) { + $lastParentlessGroup = $this->_lastParentlessGroup; + $nextGroup = new CRM_Contact_BAO_Group(); + $nextGroup->order_by = 'title ' . self::$_sortOrder; + $nextGroup->find(); + if ($group == NULL) { + $sawLast = TRUE; + } + else { + $sawLast = FALSE; + } + while ($nextGroup->fetch()) { + if (!self::hasParentGroups($nextGroup->id) && $sawLast) { + return $nextGroup; + } + elseif ($lastParentlessGroup->id == $nextGroup->id) { + $sawLast = TRUE; + } + } + return NULL; + } + + function _getNextChildGroup(&$parentGroup, &$group = NULL) { + $children = self::getChildGroupIds($parentGroup->id); + if (count($children) > 0) { + // we have child groups, so get the first one based on _sortOrder + $childGroup = new CRM_Contact_BAO_Group(); + $cgQuery = "SELECT * FROM civicrm_group WHERE id IN (" . implode(',', $children) . ") ORDER BY title " . self::$_sortOrder; + $childGroup->query($cgQuery); + $currentGroup = &$this->_current; + if ($group == NULL) { + $sawLast = TRUE; + } + else { + $sawLast = FALSE; + } + while ($childGroup->fetch()) { + if ($sawLast) { + return $childGroup; + } + elseif ($currentGroup->id === $childGroup->id) { + $sawLast = TRUE; + } + } + } + return NULL; + } + + function _getNextSiblingGroup(&$group) { + $parentGroup = end($this->_parentStack); + if ($parentGroup) { + $nextGroup = $this->_getNextChildGroup($parentGroup, $group); + return $nextGroup; + } + else { + /* if we get here, it could be because we're out of siblings + * (in which case we return null) or because we're at the + * top level groups which do not have parents but may still + * have siblings, so check for that first. + */ + + $nextGroup = $this->_getNextParentlessGroup($group); + if ($nextGroup) { + $this->_lastParentlessGroup = $nextGroup; + return $nextGroup; + } + return NULL; + } + } + + /** + * Adds a new child group identified by $childGroupId to the group + * identified by $groupId + * + * @param $groupId The id of the group to add the child to + * @param $childGroupId The id of the new child group + * + * @return void + * + * @access public + */ + static function add($parentID, $childID) { + // TODO: Add checks here to make sure invalid nests can't be created + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "REPLACE INTO civicrm_group_nesting (child_group_id, parent_group_id) VALUES ($childID,$parentID);"; + $dao->query($query); + } + + /** + * Removes a child group identified by $childGroupId from the group + * identified by $groupId; does not delete child group, just the + * association between the two + * + * @param $parentID The id of the group to remove the child from + * @param $childID The id of the child group being removed + * + * @return void + * + * @access public + */ + static function remove($parentID, $childID) { + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "DELETE FROM civicrm_group_nesting WHERE child_group_id = $childID AND parent_group_id = $parentID"; + $dao->query($query); + } + + /** + * Removes associations where a child group is identified by $childGroupId from the group + * identified by $groupId; does not delete child group, just the + * association between the two + * + * @param $parentID The id of the group to remove the child from + * @param $childID The id of the child group being removed + * + * @return void + * + * @access public + */ + static function removeAllParentForChild($childID) { + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "DELETE FROM civicrm_group_nesting WHERE child_group_id = $childID"; + $dao->query($query); + } + + /** + * Returns true if the association between parent and child is present, + * false otherwise. + * + * @param $parentID The parent id of the association + * @param $childID The child id of the association + * + * @return boolean True if association is found, false otherwise. + * + * @access public + */ + static function isParentChild($parentID, $childID) { + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT id FROM civicrm_group_nesting WHERE child_group_id = $childID AND parent_group_id = $parentID"; + $dao->query($query); + if ($dao->fetch()) { + return TRUE; + } + return FALSE; + } + + /** + * Returns true if if the given groupId has 1 or more child groups, + * false otherwise. + * + * @param $groupId The id of the group to check for child groups + * + * @return boolean True if 1 or more child groups are found, false otherwise. + * + * @access public + */ + static function hasChildGroups($groupId) { + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT child_group_id FROM civicrm_group_nesting WHERE parent_group_id = $groupId LIMIT 1"; + //print $query . "\n

    "; + $dao->query($query); + if ($dao->fetch()) { + return TRUE; + } + return FALSE; + } + + /** + * Returns true if the given groupId has 1 or more parent groups, + * false otherwise. + * + * @param $groupId The id of the group to check for parent groups + * + * @return boolean True if 1 or more parent groups are found, false otherwise. + * + * @access public + */ + static function hasParentGroups($groupId) { + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT parent_group_id FROM civicrm_group_nesting WHERE child_group_id = $groupId LIMIT 1"; + $dao->query($query); + if ($dao->fetch()) { + return TRUE; + } + return FALSE; + } + + /** + * Returns true if checkGroupId is a parent of one of the groups in + * groupIds, false otherwise. + * + * @param $groupIds Array of group ids (or one group id) to serve as the starting point + * @param $checkGroupId The group id to check if it is a parent of the $groupIds group(s) + * + * @return boolean True if $checkGroupId points to a group that is a parent of one of the $groupIds groups, false otherwise. + * + * @access public + */ + static function isParentGroup($groupIds, $checkGroupId) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT parent_group_id FROM civicrm_group_nesting WHERE child_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + while ($dao->fetch()) { + $parentGroupId = $dao->parent_group_id; + if ($parentGroupId == $checkGroupId) { + /* print "One of these:
    ";
    +                print_r($groupIds);
    +                print "
    has groupId $checkGroupId as an ancestor.
    "; */ + + return TRUE; + } + } + return FALSE; + } + + /** + * Returns true if checkGroupId is a child of one of the groups in + * groupIds, false otherwise. + * + * @param $groupIds Array of group ids (or one group id) to serve as the starting point + * @param $checkGroupId The group id to check if it is a child of the $groupIds group(s) + * + * @return boolean True if $checkGroupId points to a group that is a child of one of the $groupIds groups, false otherwise. + * + * @access public + */ + static function isChildGroup($groupIds, $checkGroupId) { + + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT child_group_id FROM civicrm_group_nesting WHERE parent_group_id IN (" . implode(',', $groupIds) . ")"; + //print $query; + $dao->query($query); + while ($dao->fetch()) { + $childGroupId = $dao->child_group_id; + if ($childGroupId == $checkGroupId) { + /* print "One of these:
    ";
    +                 print_r($groupIds);
    +                 print "
    has groupId $checkGroupId as a descendent.

    "; */ + + return TRUE; + } + } + return FALSE; + } + + /** + * Returns true if checkGroupId is an ancestor of one of the groups in + * groupIds, false otherwise. + * + * @param $groupIds Array of group ids (or one group id) to serve as the starting point + * @param $checkGroupId The group id to check if it is an ancestor of the $groupIds group(s) + * + * @return boolean True if $checkGroupId points to a group that is an ancestor of one of the $groupIds groups, false otherwise. + * + * @access public + */ + static function isAncestorGroup($groupIds, $checkGroupId) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT parent_group_id FROM civicrm_group_nesting WHERE child_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + $nextGroupIds = array(); + $gotAtLeastOneResult = FALSE; + while ($dao->fetch()) { + $gotAtLeastOneResult = TRUE; + $parentGroupId = $dao->parent_group_id; + if ($parentGroupId == $checkGroupId) { + /* print "One of these:
    ";
    +                print_r($groupIds);
    +                print "
    has groupId $checkGroupId as an ancestor.
    "; */ + + return TRUE; + } + $nextGroupIds[] = $parentGroupId; + } + if ($gotAtLeastOneResult) { + return self::isAncestorGroup($nextGroupIds, $checkGroupId); + } + else { + return FALSE; + } + } + + /** + * Returns true if checkGroupId is a descendent of one of the groups in + * groupIds, false otherwise. + * + * @param $groupIds Array of group ids (or one group id) to serve as the starting point + * @param $checkGroupId The group id to check if it is a descendent of the $groupIds group(s) + * + * @return boolean True if $checkGroupId points to a group that is a descendent of one of the $groupIds groups, false otherwise. + * + * @access public + */ + static function isDescendentGroup($groupIds, $checkGroupId) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT child_group_id FROM civicrm_group_nesting WHERE parent_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + $nextGroupIds = array(); + $gotAtLeastOneResult = FALSE; + while ($dao->fetch()) { + $gotAtLeastOneResult = TRUE; + $childGroupId = $dao->child_group_id; + if ($childGroupId == $checkGroupId) { + /* print "One of these:
    ";
    +                print_r($groupIds);
    +                print "
    has groupId $checkGroupId as a descendent.

    "; */ + + return TRUE; + } + $nextGroupIds[] = $childGroupId; + } + if ($gotAtLeastOneResult) { + return self::isDescendentGroup($nextGroupIds, $checkGroupId); + } + else { + return FALSE; + } + } + + /** + * Returns array of group ids of ancestor groups of the specified group. + * + * @param $groupIds An array of valid group ids (passed by reference) + * + * @return $groupIdArray List of groupIds that represent the requested group and its ancestors + * + * @access public + */ + static function getAncestorGroupIds($groupIds, $includeSelf = TRUE) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT parent_group_id, child_group_id + FROM civicrm_group_nesting + WHERE child_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + $tmpGroupIds = array(); + $parentGroupIds = array(); + if ($includeSelf) { + $parentGroupIds = $groupIds; + } + while ($dao->fetch()) { + // make sure we're not following any cyclical references + if (!array_key_exists($dao->child_group_id, $parentGroupIds) && $dao->parent_group_id != $groupIds[0]) { + $tmpGroupIds[] = $dao->parent_group_id; + } + } + if (!empty($tmpGroupIds)) { + $newParentGroupIds = self::getAncestorGroupIds($tmpGroupIds); + $parentGroupIds = array_merge($parentGroupIds, $newParentGroupIds); + } + return $parentGroupIds; + } + + /** + * Returns array of ancestor groups of the specified group. + * + * @param $groupIds An array of valid group ids (passed by reference) + * + * @return $groupArray List of ancestor groups + * + * @access public + */ + static function getAncestorGroups($groupIds, $includeSelf = TRUE) { + $groupIds = self::getAncestorGroupIds($groupIds, $includeSelf); + $params['id'] = $groupIds; + return CRM_Contact_BAO_Group::getGroups($params); + } + + /** + * Returns array of group ids of child groups of the specified group. + * + * @param $groupIds An array of valid group ids (passed by reference) + * + * @return $groupIdArray List of groupIds that represent the requested group and its children + * + * @access public + */ + static function getChildGroupIds($groupIds) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT child_group_id FROM civicrm_group_nesting WHERE parent_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + $childGroupIds = array(); + while ($dao->fetch()) { + $childGroupIds[] = $dao->child_group_id; + } + return $childGroupIds; + } + + /** + * Returns array of group ids of parent groups of the specified group. + * + * @param $groupIds An array of valid group ids (passed by reference) + * + * @return $groupIdArray List of groupIds that represent the requested group and its parents + * + * @access public + */ + static function getParentGroupIds($groupIds) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT parent_group_id FROM civicrm_group_nesting WHERE child_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + $parentGroupIds = array(); + while ($dao->fetch()) { + $parentGroupIds[] = $dao->parent_group_id; + } + return $parentGroupIds; + } + + /** + * Returns array of group ids of descendent groups of the specified group. + * + * @param $groupIds An array of valid group ids (passed by reference) + * + * @return $groupIdArray List of groupIds that represent the requested group and its descendents + * + * @access public + */ + static function getDescendentGroupIds($groupIds, $includeSelf = TRUE) { + if (!is_array($groupIds)) { + $groupIds = array($groupIds); + } + $dao = new CRM_Contact_DAO_GroupNesting(); + $query = "SELECT child_group_id, parent_group_id FROM civicrm_group_nesting WHERE parent_group_id IN (" . implode(',', $groupIds) . ")"; + $dao->query($query); + $tmpGroupIds = array(); + $childGroupIds = array(); + if ($includeSelf) { + $childGroupIds = $groupIds; + } + while ($dao->fetch()) { + // make sure we're not following any cyclical references + if (!array_key_exists($dao->parent_group_id, $childGroupIds) && $dao->child_group_id != $groupIds[0]) { + $tmpGroupIds[] = $dao->child_group_id; + } + } + if (!empty($tmpGroupIds)) { + $newChildGroupIds = self::getDescendentGroupIds($tmpGroupIds); + $childGroupIds = array_merge($childGroupIds, $newChildGroupIds); + } + return $childGroupIds; + } + + /** + * Returns array of descendent groups of the specified group. + * + * @param $groupIds An array of valid group ids (passed by reference) + * + * @return $groupArray List of descendent groups + * + * @access public + */ + static function getDescendentGroups($groupIds, $includeSelf = TRUE) { + $groupIds = self::getDescendentGroupIds($groupIds, $includeSelf); + $params['id'] = $groupIds; + return CRM_Contact_BAO_Group::getGroups($params); + } + + /** + * Returns array of group ids of valid potential child groups of the specified group. + * + * @param $groupId The group id to get valid potential children for + * + * @return $groupIdArray List of groupIds that represent the valid potential children of the group + * + * @access public + */ + static function getPotentialChildGroupIds($groupId) { + $groups = CRM_Contact_BAO_Group::getGroups(); + $potentialChildGroupIds = array(); + foreach ($groups as $group) { + $potentialChildGroupId = $group->id; + // print "Checking if $potentialChildGroupId is a descendent/ancestor of $groupId

    "; + if (!self::isDescendentGroup($groupId, $potentialChildGroupId) && + !self::isAncestorGroup($groupId, $potentialChildGroupId) && + $potentialChildGroupId != $groupId + ) { + $potentialChildGroupIds[] = $potentialChildGroupId; + } + } + return $potentialChildGroupIds; + } + + static function getContainingGroups($contactId, $parentGroupId) { + $groups = CRM_Contact_BAO_Group::getGroups(); + $containingGroups = array(); + foreach ($groups as $group) { + if (self::isDescendentGroup($parentGroupId, $group->id)) { + $members = CRM_Contact_BAO_Group::getMember($group->id); + if ($members[$contactId]) { + $containingGroups[] = $group->title; + } + } + } + + return $containingGroups; + } +} + diff --git a/CRM/Contact/BAO/GroupNestingCache.php b/CRM/Contact/BAO/GroupNestingCache.php new file mode 100644 index 0000000000..04431ec39d --- /dev/null +++ b/CRM/Contact/BAO/GroupNestingCache.php @@ -0,0 +1,230 @@ +fetch()) { + if (!array_key_exists($dao->child, $tree)) { + $tree[$dao->child] = array('children' => array(), + 'parents' => array(), + ); + } + + if (!array_key_exists($dao->parent, $tree)) { + $tree[$dao->parent] = array('children' => array(), + 'parents' => array(), + ); + } + + $tree[$dao->child]['parents'][] = $dao->parent; + $tree[$dao->parent]['children'][] = $dao->child; + } + + if (self::checkCyclicGraph($tree)) { + CRM_Core_Error::fatal(ts('We detected a cycle which we cant handle. aborting')); + } + + // first reset the current cache entries + $sql = " +UPDATE civicrm_group +SET parents = null, + children = null +"; + CRM_Core_DAO::executeQuery($sql); + + $values = array(); + foreach (array_keys($tree) as $id) { + $parents = implode(',', $tree[$id]['parents']); + $children = implode(',', $tree[$id]['children']); + $parents = $parents == NULL ? 'null' : "'$parents'"; + $children = $children == NULL ? 'null' : "'$children'"; + $sql = " +UPDATE civicrm_group +SET parents = $parents , + children = $children +WHERE id = $id +"; + CRM_Core_DAO::executeQuery($sql); + } + + // this tree stuff is quite useful, so lets store it in the cache + CRM_Core_BAO_Cache::setItem($tree, 'contact groups', 'nestable tree hierarchy'); + } + + static function checkCyclicGraph(&$tree) { + // lets keep this simple, we should probably use a graph algoritm here at some stage + + // foreach group that has a parent or a child, ensure that + // the ancestors and descendants dont intersect + foreach ($tree as $id => $dontCare) { + if (self::isCyclic($tree, $id)) { + return TRUE; + } + } + + return FALSE; + } + + static function isCyclic(&$tree, $id) { + $parents = $children = array(); + self::getAll($parent, $tree, $id, 'parents'); + self::getAll($child, $tree, $id, 'children'); + + $one = array_intersect($parents, $children); + $two = array_intersect($children, $parents); + if (!empty($one) || + !empty($two) + ) { + CRM_Core_Error::debug($id, $tree); + CRM_Core_Error::debug($id, $one); + CRM_Core_Error::debug($id, $two); + return TRUE; + } + return FALSE; + } + + static function getPotentialCandidates($id, &$groups) { + $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy'); + + if ($tree === NULL) { + self::update(); + $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy'); + } + + $potential = $groups; + + // remove all descendants + self::invalidate($potential, $tree, $id, 'children'); + + // remove all ancestors + self::invalidate($potential, $tree, $id, 'parents'); + + return array_keys($potential); + } + + static function invalidate(&$potential, &$tree, $id, $token) { + unset($potential[$id]); + + if (!isset($tree[$id]) || + empty($tree[$id][$token]) + ) { + return; + } + + foreach ($tree[$id][$token] as $tokenID) { + self::invalidate($potential, $tree, $tokenID, $token); + } + } + + static function getAll(&$all, &$tree, $id, $token) { + // if seen before, dont do anything + if (isset($all[$id])) { + return; + } + + $all[$id] = 1; + if (!isset($tree[$id]) || + empty($tree[$id][$token]) + ) { + return; + } + + foreach ($tree[$id][$token] as $tokenID) { + self::getAll($all, $tree, $tokenID, $token); + } + } + + static function json() { + $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy'); + + if ($tree === NULL) { + self::update(); + $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy'); + } + + // get all the groups + $groups = CRM_Core_PseudoConstant::group(); + + foreach ($groups as $id => $name) { + $string = "id:'$id', name:'$name'"; + if (isset($tree[$id])) { + $children = array(); + if (!empty($tree[$id]['children'])) { + foreach ($tree[$id]['children'] as $child) { + $children[] = "{_reference:'$child'}"; + } + $children = implode(',', $children); + $string .= ", children:[$children]"; + if (empty($tree[$id]['parents'])) { + $string .= ", type:'rootGroup'"; + } + else { + $string .= ", type:'middleGroup'"; + } + } + else { + $string .= ", type:'leafGroup'"; + } + } + else { + $string .= ", children:[], type:'rootGroup'"; + } + $values[] = "{ $string }"; + } + + $items = implode(",\n", $values); + $json = "{ + identifier:'id', + label:'name', + items:[ $items ] +}"; + return $json; + } +} + diff --git a/CRM/Contact/BAO/GroupOrganization.php b/CRM/Contact/BAO/GroupOrganization.php new file mode 100644 index 0000000000..1fd0816a5f --- /dev/null +++ b/CRM/Contact/BAO/GroupOrganization.php @@ -0,0 +1,155 @@ +copyValues($formatedValues); + $groupOrganization->save(); + return $groupOrganization; + } + + /** + * Format the params + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $formatedValues (reference ) an assoc array of name/value pairs + * + * @return void + * @access public + * @static + */ + static function formatValues(&$params, &$formatedValues) { + if (CRM_Utils_Array::value('group_organization', $params)) { + $formatedValues['id'] = $params['group_organization']; + } + + if (CRM_Utils_Array::value('group_id', $params)) { + $formatedValues['group_id'] = $params['group_id']; + } + + if (CRM_Utils_Array::value('organization_id', $params)) { + $formatedValues['organization_id'] = $params['organization_id']; + } + } + + /** + * Check if there is data to create the object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * @access public + * @static + */ + static function dataExists($params) { + // return if no data present + if (CRM_Utils_Array::value('organization_id', $params) && + CRM_Utils_Array::value('group_id', $params) + ) { + return TRUE; + } + return FALSE; + } + + static function retrieve($groupID, &$defaults) { + $dao = new CRM_Contact_DAO_GroupOrganization(); + $dao->group_id = $groupID; + if ($dao->find(TRUE)) { + $defaults['group_organization'] = $dao->id; + $defaults['organization_id'] = $dao->organization_id; + } + } + + /** + * Method to check group organization relationship exist + * + * @param int $contactId + * + * @return boolean + * @access public + * @static + */ + static function hasGroupAssociated($contactID) { + $orgID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_GroupOrganization', + $contactID, 'group_id', 'organization_id' + ); + if ($orgID) { + return TRUE; + } + return FALSE; + } + + /** + * Function to delete Group Organization + * + * @param int $groupOrganizationID group organization id that needs to be deleted + * + * @return $results no of deleted group organization on success, false otherwise + * @access public + */ + static function deleteGroupOrganization($groupOrganizationID) { + $results = NULL; + $groupOrganization = new CRM_Contact_DAO_GroupOrganization(); + $groupOrganization->id = $groupOrganizationID; + + $results = $groupOrganization->delete(); + + return $results; + } +} + diff --git a/CRM/Contact/BAO/Household.php b/CRM/Contact/BAO/Household.php new file mode 100644 index 0000000000..469649133e --- /dev/null +++ b/CRM/Contact/BAO/Household.php @@ -0,0 +1,73 @@ +id) { + $individual = new CRM_Contact_BAO_Contact(); + $individual->id = $contact->id; + if ($individual->find(TRUE)) { + + //lets allow to update single name field though preserveDBName + //but if db having null value and params contain value, CRM-4330. + $useDBNames = array(); + + foreach (array( + 'last', 'middle', 'first', 'nick') as $name) { + $dbName = "{$name}_name"; + $value = $individual->$dbName; + + // the db has name values + if ($value && CRM_Utils_Array::value('preserveDBName', $params)) { + $useDBNames[] = $name; + } + } + + foreach (array( + 'prefix', 'suffix') as $name) { + $dbName = "{$name}_id"; + $value = $individual->$dbName; + if ($value && CRM_Utils_Array::value('preserveDBName', $params)) { + $useDBNames[] = $name; + } + } + + // CRM-4430 + //1. preserve db name if want + //2. lets get value from param if exists. + //3. if not in params, lets get from db. + + foreach (array( + 'last', 'middle', 'first', 'nick') as $name) { + $phpName = "{$name}Name"; + $dbName = "{$name}_name"; + $value = $individual->$dbName; + if (in_array($name, $useDBNames)) { + $params[$dbName] = $value; + $contact->$dbName = $value; + $$phpName = $value; + } + elseif (array_key_exists($dbName, $params)) { + $$phpName = $params[$dbName]; + } + elseif ($value) { + $$phpName = $value; + } + } + + foreach (array( + 'prefix', 'suffix') as $name) { + $phpName = $name; + $dbName = "{$name}_id"; + $vals = "{$name}es"; + + $value = $individual->$dbName; + if (in_array($name, $useDBNames)) { + $params[$dbName] = $value; + $contact->$dbName = $value; + if ($value) { + $temp = $$vals; + $$phpName = $temp[$value]; + } + else { + $$phpName = NULL; + } + } + elseif (array_key_exists($dbName, $params)) { + $temp = $$vals; + // CRM-5278 + if (!empty($params[$dbName])) { + $$phpName = CRM_Utils_Array::value($params[$dbName], $temp); + } + } + elseif ($value) { + $temp = $$vals; + $$phpName = $temp[$value]; + } + } + } + } + + //first trim before further processing. + foreach (array( + 'lastName', 'firstName', 'middleName') as $fld) { + $$fld = trim($$fld); + } + + if ($lastName || $firstName || $middleName) { + // make sure we have values for all the name fields. + $formatted = $params; + $nameParams = array( + 'first_name' => $firstName, + 'middle_name' => $middleName, + 'last_name' => $lastName, + 'nick_name' => $nickName, + 'individual_suffix' => $suffix, + 'individual_prefix' => $prefix, + 'prefix_id' => $prefix_id, + 'suffix_id' => $suffix_id, + ); + // make sure we have all the name fields. + foreach ($nameParams as $name => $value) { + if (!CRM_Utils_Array::value($name, $formatted) && $value) { + $formatted[$name] = $value; + } + } + + $tokens = array(); + CRM_Utils_Hook::tokens($tokens); + $tokenFields = array(); + foreach ($tokens as $category => $catTokens) { + foreach ($catTokens as $token => $label) { + $tokenFields[] = $token; + } + } + + //build the sort name. + $format = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'sort_name_format' + ); + $sortName = CRM_Utils_Address::format($formatted, $format, + FALSE, FALSE, TRUE, $tokenFields + ); + $sortName = trim($sortName); + + //build the display name. + $format = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'display_name_format' + ); + $displayName = CRM_Utils_Address::format($formatted, $format, + FALSE, FALSE, TRUE, $tokenFields + ); + $displayName = trim($displayName); + } + + //start further check for email. + if (empty($sortName) || empty($displayName)) { + $email = NULL; + if (CRM_Utils_Array::value('email', $params) && + is_array($params['email']) + ) { + foreach ($params['email'] as $emailBlock) { + if (isset($emailBlock['is_primary'])) { + $email = $emailBlock['email']; + break; + } + } + } + $uniqId = CRM_Utils_Array::value('user_unique_id', $params); + if (!$email && $contact->id) { + $email = CRM_Contact_BAO_Contact::getPrimaryEmail($contact->id); + } + } + + //now set the names. + $names = array('sortName' => 'sort_name', 'displayName' => 'display_name'); + foreach ($names as $value => $name) { + if (empty($$value)) { + if ($email) { + $$value = $email; + } + elseif ($uniqId) { + $$value = $uniqId; + } + } + //finally if we could not pass anything lets keep db. + if (!empty($$value)) { + $contact->$name = $$value; + } + } + + $format = CRM_Utils_Date::getDateFormat('birth'); + if ($date = CRM_Utils_Array::value('birth_date', $params)) { + if (in_array($format, array( + 'dd-mm', 'mm/dd'))) { + $separator = '/'; + if ($format == 'dd-mm') { + $separator = '-'; + } + $date = $date . $separator . '1902'; + } + elseif (in_array($format, array( + 'yy-mm'))) { + $date = $date . '-01'; + } + elseif (in_array($format, array( + 'M yy'))) { + $date = $date . '-01'; + } + elseif (in_array($format, array( + 'yy'))) { + $date = $date . '-01-01'; + } + $contact->birth_date = CRM_Utils_Date::processDate($date); + } + elseif ($contact->birth_date) { + $contact->birth_date = CRM_Utils_Date::isoToMysql($contact->birth_date); + } + + if ($date = CRM_Utils_Array::value('deceased_date', $params)) { + if (in_array($format, array( + 'dd-mm', 'mm/dd'))) { + $separator = '/'; + if ($format == 'dd-mm') { + $separator = '-'; + } + $date = $date . $separator . '1902'; + } + elseif (in_array($format, array( + 'yy-mm'))) { + $date = $date . '-01'; + } + elseif (in_array($format, array( + 'M yy'))) { + $date = $date . '-01'; + } + elseif (in_array($format, array( + 'yy'))) { + $date = $date . '-01-01'; + } + + $contact->deceased_date = CRM_Utils_Date::processDate($date); + } + elseif ($contact->deceased_date) { + $contact->deceased_date = CRM_Utils_Date::isoToMysql($contact->deceased_date); + } + + if ($middle_name = CRM_Utils_Array::value('middle_name', $params)) { + $contact->middle_name = $middle_name; + } + + return $contact; + } + + /** + * regenerates display_name for contacts with given prefixes/suffixes + * + * @param array $ids the array with the prefix/suffix id governing which contacts to regenerate + * @param int $action the action describing whether prefix/suffix was UPDATED or DELETED + * + * @return void + */ + static function updateDisplayNames(&$ids, $action) { + // get the proper field name (prefix_id or suffix_id) and its value + $fieldName = ''; + foreach ($ids as $key => $value) { + switch ($key) { + case 'individualPrefix': + $fieldName = 'prefix_id'; + $fieldValue = $value; + break 2; + + case 'individualSuffix': + $fieldName = 'suffix_id'; + $fieldValue = $value; + break 2; + } + } + if ($fieldName == '') { + return; + } + + // query for the affected individuals + $fieldValue = CRM_Utils_Type::escape($fieldValue, 'Integer'); + $contact = new CRM_Contact_BAO_Contact(); + $contact->$fieldName = $fieldValue; + $contact->find(); + + // iterate through the affected individuals and rebuild their display_names + while ($contact->fetch()) { + $contact = new CRM_Contact_BAO_Contact(); + $contact->id = $contact->contact_id; + if ($action == CRM_Core_Action::DELETE) { + $contact->$fieldName = 'NULL'; + $contact->save(); + } + $contact->display_name = $contact->displayName(); + $contact->save(); + } + } + + /** + * creates display name + * + * @return string the constructed display name + */ + function displayName() { + $prefix = CRM_Core_PseudoConstant::individualPrefix(); + $suffix = CRM_Core_PseudoConstant::individualSuffix(); + return str_replace(' ', ' ', trim($prefix[$this->prefix_id] . ' ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name . ' ' . $suffix[$this->suffix_id])); + } + + /** + * Check if there is data to create the object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * @access public + * @static + */ + static function dataExists(&$params) { + if ($params['contact_type'] == 'Individual') { + return TRUE; + } + + return FALSE; + } +} + diff --git a/CRM/Contact/BAO/ProximityQuery.php b/CRM/Contact/BAO/ProximityQuery.php new file mode 100644 index 0000000000..02a57f999d --- /dev/null +++ b/CRM/Contact/BAO/ProximityQuery.php @@ -0,0 +1,364 @@ + pi()) { + $maxLong = $maxLong - pi() * 2; + } + + return array(rad2deg($minLong), + rad2deg($maxLong), + ); + } + + /** + * Estimate the min and max latitudes within $distance of a given location. + */ + static function earthLatitudeRange($longitude, $latitude, $distance) { + $long = deg2rad($longitude); + $lat = deg2rad($latitude); + $radius = self::earthRadius($latitude); + + $angle = $distance / $radius; + $minLat = $lat - $angle; + $maxLat = $lat + $angle; + $rightangle = pi() / 2.0; + + // wrapped around the south pole + if ($minLat < - $rightangle) { + $overshoot = -$minLat - $rightangle; + $minLat = -$rightangle + $overshoot; + if ($minLat > $maxLat) { + $maxLat = $minLat; + } + $minLat = -$rightangle; + } + + // wrapped around the north pole + if ($maxLat > $rightangle) { + $overshoot = $maxLat - $rightangle; + $maxLat = $rightangle - $overshoot; + if ($maxLat < $minLat) { + $minLat = $maxLat; + } + $maxLat = $rightangle; + } + + return array(rad2deg($minLat), + rad2deg($maxLat), + ); + } + + /* + * Returns the SQL fragment needed to add a column called 'distance' + * to a query that includes the location table + * + * @param $longitude + * @param $latitude + */ + + static function earthDistanceSQL($longitude, $latitude) { + $long = deg2rad($longitude); + $lat = deg2rad($latitude); + $radius = self::earthRadius($latitude); + + $cosLong = cos($long); + $cosLat = cos($lat); + $sinLong = sin($long); + $sinLat = sin($lat); + + return " +IFNULL( ACOS( $cosLat * COS( RADIANS( $latitude ) ) * + ( $cosLong * COS( RADIANS( $longitude ) ) + + $sinLong * SIN( RADIANS( $longitude ) ) ) + + $sinLat * SIN( RADIANS( $latitude ) ) ), 0.00000 ) * $radius +"; + } + + static function where($latitude, $longitude, $distance, $tablePrefix = 'civicrm_address') { + self::initialize(); + + $params = array(); + $clause = array(); + + list($minLongitude, $maxLongitude) = self::earthLongitudeRange($longitude, + $latitude, + $distance + ); + list($minLatitude, $maxLatitude) = self::earthLatitudeRange($longitude, + $latitude, + $distance + ); + + $earthDistanceSQL = self::earthDistanceSQL($longitude, $latitude); + + $where = " +{$tablePrefix}.geo_code_1 >= $minLatitude AND +{$tablePrefix}.geo_code_1 <= $maxLatitude AND +{$tablePrefix}.geo_code_2 >= $minLongitude AND +{$tablePrefix}.geo_code_2 <= $maxLongitude AND +$earthDistanceSQL <= $distance +"; + + return $where; + } + + static function process(&$query, &$values) { + list($name, $op, $distance, $grouping, $wildcard) = $values; + + // also get values array for all address related info + $proximityVars = array( + 'street_address' => 1, + 'city' => 1, + 'postal_code' => 1, + 'state_province_id' => 0, + 'country_id' => 0, + 'state_province' => 0, + 'country' => 0, + 'distance_unit' => 0, + ); + + $proximityAddress = array(); + $qill = array(); + foreach ($proximityVars as $var => $recordQill) { + $proximityValues = $query->getWhereValues("prox_{$var}", $grouping); + if (!empty($proximityValues) && + !empty($proximityValues[2]) + ) { + $proximityAddress[$var] = $proximityValues[2]; + if ($recordQill) { + $qill[] = $proximityValues[2]; + } + } + } + + if (empty($proximityAddress)) { + return; + } + + if (isset($proximityAddress['state_province_id'])) { + $proximityAddress['state_province'] = CRM_Core_PseudoConstant::stateProvince($proximityAddress['state_province_id']); + $qill[] = $proximityAddress['state_province']; + } + + if (isset($proximityAddress['country_id'])) { + $proximityAddress['country'] = CRM_Core_PseudoConstant::country($proximityAddress['country_id']); + $qill[] = $proximityAddress['country']; + } + + $config = CRM_Core_Config::singleton(); + if (empty($config->geocodeMethod)) { + CRM_Core_Error::fatal(ts('Proximity searching requires you to set a valid geocoding provider')); + } + + require_once (str_replace('_', DIRECTORY_SEPARATOR, $config->geocodeMethod) . '.php'); + eval($config->geocodeMethod . '::format( $proximityAddress );'); + if (!is_numeric(CRM_Utils_Array::value('geo_code_1', $proximityAddress)) || + !is_numeric(CRM_Utils_Array::value('geo_code_2', $proximityAddress)) + ) { + return; + } + + if (isset($proximityAddress['distance_unit']) && + $proximityAddress['distance_unit'] == 'miles' + ) { + $qillUnits = " {$distance} " . ts('miles'); + $distance = $distance * 1609.344; + } + else { + $qillUnits = " {$distance} " . ts('km'); + $distance = $distance * 1000.00; + } + + $qill = ts('Proximity search to a distance of %1 from %2', + array( + 1 => $qillUnits, + 2 => implode(', ', $qill) + ) + ); + + $query->_tables['civicrm_address'] = $query->_whereTables['civicrm_address'] = 1; + $query->_where[$grouping][] = self::where($proximityAddress['geo_code_1'], + $proximityAddress['geo_code_2'], + $distance + ); + $query->_qill[$grouping][] = $qill; + return; + } + + static function fixInputParams(&$input) { + foreach ($input as $param) { + if (CRM_Utils_Array::value('0', $param) == 'prox_distance') { + // add prox_ prefix to these + $param_alter = array('street_address', 'city', 'postal_code', 'state_province', 'country'); + + foreach ($input as $key => $_param) { + if (in_array($_param[0], $param_alter)) { + $input[$key][0] = 'prox_' . $_param[0]; + + // _id suffix where needed + if ($_param[0] == 'country' || $_param[0] == 'state_province') { + $input[$key][0] .= '_id'; + + // flatten state_province array + if (is_array($input[$key][2])) { + $input[$key][2] = $input[$key][2][0]; + } + } + } + } + return; + } + } + } +} + diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php new file mode 100644 index 0000000000..6e4fef7a41 --- /dev/null +++ b/CRM/Contact/BAO/Query.php @@ -0,0 +1,4964 @@ + 1, + 'civicrm_country' => 1, + 'civicrm_county' => 1, + 'civicrm_address' => 1, + 'civicrm_location_type' => 1, + ); + + /** + * List of location specific fields + */ + static $_locationSpecificFields = array( + 'street_address', + 'street_number', + 'street_name', + 'street_unit', + 'supplemental_address_1', + 'supplemental_address_2', + 'city', + 'postal_code', + 'postal_code_suffix', + 'geo_code_1', + 'geo_code_2', + 'state_province', + 'country', + 'county', + 'phone', + 'email', + 'im', + 'address_name', + ); + + /** + * Rememeber if we handle either end of a number or date range + * so we can skip the other + */ + protected $_rangeCache = array(); + + /** + * class constructor which also does all the work + * + * @param array $params + * @param array $returnProperties + * @param array $fields + * @param boolean $includeContactIds + * @param boolean $strict + * @param boolean $mode - mode the search is operating on + * + * @return Object + * @access public + */ + function __construct( + $params = NULL, $returnProperties = NULL, $fields = NULL, + $includeContactIds = FALSE, $strict = FALSE, $mode = 1, + $skipPermission = FALSE, $searchDescendentGroups = TRUE, + $smartGroupCache = TRUE, $displayRelationshipType = NULL, + $operator = 'AND' + ) { + $this->_params = &$params; + if ($this->_params == NULL) { + $this->_params = array(); + } + + if (empty($returnProperties)) { + $this->_returnProperties = self::defaultReturnProperties($mode); + } + else { + $this->_returnProperties = &$returnProperties; + } + + $this->_includeContactIds = $includeContactIds; + $this->_strict = $strict; + $this->_mode = $mode; + $this->_skipPermission = $skipPermission; + $this->_smartGroupCache = $smartGroupCache; + $this->_displayRelationshipType = $displayRelationshipType; + $this->setOperator($operator); + + if ($fields) { + $this->_fields = &$fields; + $this->_search = FALSE; + $this->_skipPermission = TRUE; + } + else { + $this->_fields = CRM_Contact_BAO_Contact::exportableFields('All', FALSE, TRUE, TRUE); + + $fields = CRM_Core_Component::getQueryFields(); + unset($fields['note']); + $this->_fields = array_merge($this->_fields, $fields); + + // add activity fields + $fields = CRM_Activity_BAO_Activity::exportableFields(); + $this->_fields = array_merge($this->_fields, $fields); + } + + // basically do all the work once, and then reuse it + $this->initialize(); + } + + /** + * function which actually does all the work for the constructor + * + * @return void + * @access private + */ + function initialize() { + $this->_select = array(); + $this->_element = array(); + $this->_tables = array(); + $this->_whereTables = array(); + $this->_where = array(); + $this->_qill = array(); + $this->_options = array(); + $this->_cfIDs = array(); + $this->_paramLookup = array(); + $this->_having = array(); + + $this->_customQuery = NULL; + + // reset cached static variables - CRM-5803 + self::$_activityRole = NULL; + self::$_considerCompActivities = NULL; + self::$_withContactActivitiesOnly = NULL; + + $this->_select['contact_id'] = 'contact_a.id as contact_id'; + $this->_element['contact_id'] = 1; + $this->_tables['civicrm_contact'] = 1; + + if (!empty($this->_params)) { + $this->buildParamsLookup(); + } + + $this->_whereTables = $this->_tables; + + $this->selectClause(); + $this->_whereClause = $this->whereClause(); + + $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode); + $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode); + + $this->openedSearchPanes(TRUE); + } + + function buildParamsLookup() { + // first fix and handle contact deletion nicely + // this code is primarily for search builder use case + // where different clauses can specify if they want deleted + // contacts or not + // CRM-11971 + $trashParamExists = FALSE; + $paramByGroup = array(); + foreach ( $this->_params as $k => $param ) { + if ( $param[0] == 'contact_is_deleted' ) { + $trashParamExists = TRUE; + } + $paramByGroup[$param[3]][$k] = $param; + } + + if ( $trashParamExists ) { + $this->_skipDeleteClause = TRUE; + + //cycle through group sets and explicitly add trash param if not set + foreach ( $paramByGroup as $setID => $set ) { + if ( + !in_array(array('contact_is_deleted', '=', '1', $setID, '0'), $this->_params) && + !in_array(array('contact_is_deleted', '=', '0', $setID, '0'), $this->_params) ) { + $this->_params[] = array( + 'contact_is_deleted', + '=', + '0', + $setID, + '0', + ); + } + } + } + + foreach ($this->_params as $value) { + if (!CRM_Utils_Array::value(0, $value)) { + continue; + } + $cfID = CRM_Core_BAO_CustomField::getKeyID($value[0]); + if ($cfID) { + if (!array_key_exists($cfID, $this->_cfIDs)) { + $this->_cfIDs[$cfID] = array(); + } + $this->_cfIDs[$cfID][] = $value; + } + + if (!array_key_exists($value[0], $this->_paramLookup)) { + $this->_paramLookup[$value[0]] = array(); + } + $this->_paramLookup[$value[0]][] = $value; + } + } + + /** + * Some composite fields do not appear in the fields array + * hack to make them part of the query + * + * @return void + * @access public + */ + function addSpecialFields() { + static $special = array('contact_type', 'contact_sub_type', 'sort_name', 'display_name'); + foreach ($special as $name) { + if (CRM_Utils_Array::value($name, $this->_returnProperties)) { + $this->_select[$name] = "contact_a.{$name} as $name"; + $this->_element[$name] = 1; + } + } + } + + /** + * Given a list of conditions in params and a list of desired + * return Properties generate the required select and from + * clauses. Note that since the where clause introduces new + * tables, the initial attempt also retrieves all variables used + * in the params list + * + * @return void + * @access public + */ + function selectClause() { + $properties = array(); + + $this->addSpecialFields(); + + foreach ($this->_fields as $name => $field) { + + // skip component fields + // there are done by the alter query below + // and need not be done on every field + if ((substr($name, 0, 12) == 'participant_') || + (substr($name, 0, 7) == 'pledge_') || + (substr($name, 0, 5) == 'case_') + ) { + continue; + } + + // redirect to activity select clause + if (substr($name, 0, 9) == 'activity_') { + CRM_Activity_BAO_Query::select($this); + continue; + } + + // if this is a hierarchical name, we ignore it + $names = explode('-', $name); + if (count($names > 1) && isset($names[1]) && is_numeric($names[1])) { + continue; + } + + $cfID = CRM_Core_BAO_CustomField::getKeyID($name); + + if (CRM_Utils_Array::value($name, $this->_paramLookup) || + CRM_Utils_Array::value($name, $this->_returnProperties) + ) { + + if ($cfID) { + // add to cfIDs array if not present + if (!array_key_exists($cfID, $this->_cfIDs)) { + $this->_cfIDs[$cfID] = array(); + } + } + elseif (isset($field['where'])) { + list($tableName, $fieldName) = explode('.', $field['where'], 2); + if (isset($tableName)) { + + if (CRM_Utils_Array::value($tableName, self::$_dependencies)) { + $this->_tables['civicrm_address'] = 1; + $this->_select['address_id'] = 'civicrm_address.id as address_id'; + $this->_element['address_id'] = 1; + } + + if ($tableName == 'gender' || $tableName == 'individual_prefix' + || $tableName == 'individual_suffix' || $tableName == 'im_provider' + || $tableName == 'email_greeting' || $tableName == 'postal_greeting' + || $tableName == 'addressee' + ) { + CRM_Core_OptionValue::select($this); + if (in_array($tableName, array( + 'email_greeting', 'postal_greeting', 'addressee'))) { + //get display + $greetField = "{$name}_display"; + $this->_select[$greetField] = "contact_a.{$greetField} as {$greetField}"; + $this->_element[$greetField] = 1; + //get custom + $greetField = "{$name}_custom"; + $this->_select[$greetField] = "contact_a.{$greetField} as {$greetField}"; + $this->_element[$greetField] = 1; + } + } + else { + $this->_tables[$tableName] = 1; + + // also get the id of the tableName + $tName = substr($tableName, 8); + + if ($tName != 'contact') { + $this->_select["{$tName}_id"] = "{$tableName}.id as {$tName}_id"; + $this->_element["{$tName}_id"] = 1; + } + + //special case for phone + if ($name == 'phone') { + $this->_select['phone_type_id'] = "civicrm_phone.phone_type_id as phone_type_id"; + $this->_element['phone_type_id'] = 1; + } + + // if IM then select provider_id also + // to get "IM Service Provider" in a file to be exported, CRM-3140 + if ($name == 'im') { + $this->_select['provider_id'] = "civicrm_im.provider_id as provider_id"; + $this->_element['provider_id'] = 1; + } + + if ($name == 'state_province') { + $this->_select[$name] = "civicrm_state_province.abbreviation as `$name`, civicrm_state_province.name as state_province_name"; + $this->_element['state_province_name'] = 1; + } + elseif ($tName == 'contact') { + // special case, when current employer is set for Individual contact + if ($fieldName == 'organization_name') { + $this->_select[$name] = "IF ( contact_a.contact_type = 'Individual', NULL, contact_a.organization_name ) as organization_name"; + } + elseif ($fieldName != 'id') { + $this->_select[$name] = "contact_a.{$fieldName} as `$name`"; + } + } + else { + $this->_select[$name] = "{$field['where']} as `$name`"; + } + $this->_element[$name] = 1; + } + } + } + elseif ($name === 'tags') { + $this->_useGroupBy = TRUE; + $this->_select[$name] = "GROUP_CONCAT(DISTINCT(civicrm_tag.name)) as tags"; + $this->_element[$name] = 1; + $this->_tables['civicrm_tag'] = 1; + $this->_tables['civicrm_entity_tag'] = 1; + } + elseif ($name === 'groups') { + $this->_useGroupBy = TRUE; + $this->_select[$name] = "GROUP_CONCAT(DISTINCT(civicrm_group.title)) as groups"; + $this->_element[$name] = 1; + $this->_tables['civicrm_group'] = 1; + } + elseif ($name === 'notes') { + $this->_useGroupBy = TRUE; + $this->_select[$name] = "GROUP_CONCAT(DISTINCT(civicrm_note.note)) as notes"; + $this->_element[$name] = 1; + $this->_tables['civicrm_note'] = 1; + } + elseif ($name === 'current_employer') { + $this->_select[$name] = "IF ( contact_a.contact_type = 'Individual', contact_a.organization_name, NULL ) as current_employer"; + $this->_element[$name] = 1; + } + } + + if ($cfID && + CRM_Utils_Array::value('is_search_range', $field) + ) { + // this is a custom field with range search enabled, so we better check for two/from values + if (CRM_Utils_Array::value($name . '_from', $this->_paramLookup)) { + if (!array_key_exists($cfID, $this->_cfIDs)) { + $this->_cfIDs[$cfID] = array(); + } + foreach ($this->_paramLookup[$name . '_from'] as $pID => $p) { + // search in the cdID array for the same grouping + $fnd = FALSE; + foreach ($this->_cfIDs[$cfID] as $cID => $c) { + if ($c[3] == $p[3]) { + $this->_cfIDs[$cfID][$cID][2]['from'] = $p[2]; + $fnd = TRUE; + } + } + if (!$fnd) { + $p[2] = array('from' => $p[2]); + $this->_cfIDs[$cfID][] = $p; + } + } + } + if (CRM_Utils_Array::value($name . '_to', $this->_paramLookup)) { + if (!array_key_exists($cfID, $this->_cfIDs)) { + $this->_cfIDs[$cfID] = array(); + } + foreach ($this->_paramLookup[$name . '_to'] as $pID => $p) { + // search in the cdID array for the same grouping + $fnd = FALSE; + foreach ($this->_cfIDs[$cfID] as $cID => $c) { + if ($c[4] == $p[4]) { + $this->_cfIDs[$cfID][$cID][2]['to'] = $p[2]; + $fnd = TRUE; + } + } + if (!$fnd) { + $p[2] = array('to' => $p[2]); + $this->_cfIDs[$cfID][] = $p; + } + } + } + } + } + + // add location as hierarchical elements + $this->addHierarchicalElements(); + + // add multiple field like website + $this->addMultipleElements(); + + //fix for CRM-951 + CRM_Core_Component::alterQuery($this, 'select'); + + if (!empty($this->_cfIDs)) { + $this->_customQuery = new CRM_Core_BAO_CustomQuery($this->_cfIDs, TRUE); + $this->_customQuery->query(); + $this->_select = array_merge($this->_select, $this->_customQuery->_select); + $this->_element = array_merge($this->_element, $this->_customQuery->_element); + $this->_tables = array_merge($this->_tables, $this->_customQuery->_tables); + $this->_whereTables = array_merge($this->_whereTables, $this->_customQuery->_whereTables); + $this->_options = $this->_customQuery->_options; + } + } + + /** + * If the return Properties are set in a hierarchy, traverse the hierarchy to get + * the return values + * + * @return void + * @access public + */ + function addHierarchicalElements() { + if (!CRM_Utils_Array::value('location', $this->_returnProperties)) { + return; + } + if (!is_array($this->_returnProperties['location'])) { + return; + } + + $locationTypes = CRM_Core_PseudoConstant::locationType(); + $processed = array(); + $index = 0; + + $addressCustomFields = CRM_Core_BAO_CustomField::getFieldsForImport('Address'); + $addressCustomFieldIds = array(); + + foreach ($this->_returnProperties['location'] as $name => $elements) { + $lCond = self::getPrimaryCondition($name); + + if (!$lCond) { + $locationTypeId = array_search($name, $locationTypes); + if ($locationTypeId === FALSE) { + continue; + } + $lCond = "location_type_id = $locationTypeId"; + $this->_useDistinct = TRUE; + + //commented for CRM-3256 + $this->_useGroupBy = TRUE; + } + + $name = str_replace(' ', '_', $name); + + $tName = "$name-location_type"; + $ltName = "`$name-location_type`"; + $this->_select["{$tName}_id"] = "`$tName`.id as `{$tName}_id`"; + $this->_select["{$tName}"] = "`$tName`.name as `{$tName}`"; + $this->_element["{$tName}_id"] = 1; + $this->_element["{$tName}"] = 1; + + $locationTypeName = $tName; + $locationTypeJoin = array(); + + $addAddress = FALSE; + $addWhereCount = 0; + foreach ($elements as $elementFullName => $dontCare) { + $index++; + $elementName = $elementCmpName = $elementFullName; + + if (substr($elementCmpName, 0, 5) == 'phone') { + $elementCmpName = 'phone'; + } + + if (in_array($elementCmpName, array_keys($addressCustomFields))) { + if ($cfID = CRM_Core_BAO_CustomField::getKeyID($elementCmpName)) { + $addressCustomFieldIds[$cfID][$name] = 1; + } + } + //add address table only once + if ((in_array($elementCmpName, self::$_locationSpecificFields) || !empty($addressCustomFieldIds)) + && !$addAddress + && !in_array($elementCmpName, array('email', 'phone', 'im', 'openid')) + ) { + $tName = "$name-address"; + $aName = "`$name-address`"; + $this->_select["{$tName}_id"] = "`$tName`.id as `{$tName}_id`"; + $this->_element["{$tName}_id"] = 1; + $addressJoin = "\nLEFT JOIN civicrm_address $aName ON ($aName.contact_id = contact_a.id AND $aName.$lCond)"; + $this->_tables[$tName] = $addressJoin; + $locationTypeJoin[$tName] = " ( $aName.location_type_id = $ltName.id ) "; + $processed[$aName] = 1; + $addAddress = TRUE; + } + + $cond = $elementType = ''; + if (strpos($elementName, '-') !== FALSE) { + // this is either phone, email or IM + list($elementName, $elementType) = explode('-', $elementName); + + + if (($elementName != 'phone') && ($elementName != 'im')) { + $cond = self::getPrimaryCondition($elementType); + } + if ((!$cond) && ($elementName == 'phone')) { + $cond = "phone_type_id = '$elementType'"; + } + elseif ((!$cond) && ($elementName == 'im')) { + // IM service provider id, CRM-3140 + $cond = "provider_id = '$elementType'"; + } + $elementType = '-' . $elementType; + } + + $field = CRM_Utils_Array::value($elementName, $this->_fields); + + // hack for profile, add location id + if (!$field) { + if ($elementType && + // fix for CRM-882( to handle phone types ) + !is_numeric($elementType) + ) { + if (is_numeric($name)) { + $field = CRM_Utils_Array::value($elementName . "-Primary$elementType", $this->_fields); + } + else { + $field = CRM_Utils_Array::value($elementName . "-$locationTypeId$elementType", $this->_fields); + } + } + elseif (is_numeric($name)) { + //this for phone type to work + if (in_array($elementName, array('phone', 'phone_ext'))) { + $field = CRM_Utils_Array::value($elementName . "-Primary" . $elementType, $this->_fields); + } + else { + $field = CRM_Utils_Array::value($elementName . "-Primary", $this->_fields); + } + } + else { + //this is for phone type to work for profile edit + if (in_array($elementName, array('phone', 'phone_ext'))) { + $field = CRM_Utils_Array::value($elementName . "-$locationTypeId$elementType", $this->_fields); + } + else { + $field = CRM_Utils_Array::value($elementName . "-$locationTypeId", $this->_fields); + } + } + } + + // check if there is a value, if so also add to where Clause + $addWhere = FALSE; + if ($this->_params) { + $nm = $elementName; + if (isset($locationTypeId)) { + $nm .= "-$locationTypeId"; + } + if (!is_numeric($elementType)) { + $nm .= "$elementType"; + } + + foreach ($this->_params as $id => $values) { + if ($values[0] == $nm || + (in_array($elementName, array('phone', 'im')) + && (strpos($values[0], $nm) !== FALSE) + ) + ) { + $addWhere = TRUE; + $addWhereCount++; + break; + } + } + } + + if ($field && isset($field['where'])) { + list($tableName, $fieldName) = explode('.', $field['where'], 2); + $tName = $name . '-' . substr($tableName, 8) . $elementType; + if (isset($tableName)) { + $this->_select["{$tName}_id"] = "`$tName`.id as `{$tName}_id`"; + $this->_element["{$tName}_id"] = 1; + if (substr($tName, -15) == '-state_province') { + // FIXME: hack to fix CRM-1900 + $a = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_format' + ); + + if (substr_count($a, 'state_province_name') > 0) { + $this->_select["{$name}-{$elementFullName}"] = "`$tName`.name as `{$name}-{$elementFullName}`"; + } + else { + $this->_select["{$name}-{$elementFullName}"] = "`$tName`.abbreviation as `{$name}-{$elementFullName}`"; + } + } + else { + if (substr($elementFullName, 0, 2) == 'im') { + $provider = "{$name}-{$elementFullName}-provider_id"; + $this->_select[$provider] = "`$tName`.provider_id as `{$name}-{$elementFullName}-provider_id`"; + $this->_element[$provider] = 1; + } + + $this->_select["{$name}-{$elementFullName}"] = "`$tName`.$fieldName as `{$name}-{$elementFullName}`"; + } + + $this->_element["{$name}-{$elementFullName}"] = 1; + if (!CRM_Utils_Array::value("`$tName`", $processed)) { + $processed["`$tName`"] = 1; + $newName = $tableName . '_' . $index; + switch ($tableName) { + case 'civicrm_phone': + case 'civicrm_email': + case 'civicrm_im': + case 'civicrm_openid': + + $this->_tables[$tName] = "\nLEFT JOIN $tableName `$tName` ON contact_a.id = `$tName`.contact_id AND `$tName`.$lCond"; + // this special case to add phone type + if ($cond) { + $phoneTypeCondition = " AND `$tName`.$cond "; + //gross hack to pickup corrupted data also, CRM-7603 + if (strpos($cond, 'phone_type_id') !== FALSE) { + $phoneTypeCondition = " AND ( `$tName`.$cond OR `$tName`.phone_type_id IS NULL ) "; + } + $this->_tables[$tName] .= $phoneTypeCondition; + } + + //build locationType join + $locationTypeJoin[$tName] = " ( `$tName`.location_type_id = $ltName.id )"; + + if ($addWhere) { + $this->_whereTables[$tName] = $this->_tables[$tName]; + } + break; + + case 'civicrm_state_province': + $this->_tables[$tName] = "\nLEFT JOIN $tableName `$tName` ON `$tName`.id = $aName.state_province_id"; + if ($addWhere) { + $this->_whereTables["{$name}-address"] = $addressJoin; + $this->_whereTables[$tName] = $this->_tables[$tName]; + } + break; + + case 'civicrm_country': + $this->_tables[$newName] = "\nLEFT JOIN $tableName `$tName` ON `$tName`.id = $aName.country_id"; + if ($addWhere) { + $this->_whereTables["{$name}-address"] = $addressJoin; + $this->_whereTables[$newName] = $this->_tables[$newName]; + } + break; + + case 'civicrm_county': + $this->_tables[$newName] = "\nLEFT JOIN $tableName `$tName` ON `$tName`.id = $aName.county_id"; + if ($addWhere) { + $this->_whereTables["{$name}-address"] = $addressJoin; + $this->_whereTables[$newName] = $this->_tables[$newName]; + } + break; + + default: + if ($addWhere) { + $this->_whereTables["{$name}-address"] = $addressJoin; + } + break; + } + } + } + } + } + + // add location type join + $ltypeJoin = "\nLEFT JOIN civicrm_location_type $ltName ON ( " . implode('OR', $locationTypeJoin) . " )"; + $this->_tables[$locationTypeName] = $ltypeJoin; + + // table should be present in $this->_whereTables, + // to add its condition in location type join, CRM-3939. + if ($addWhereCount) { + $locClause = array(); + foreach ($this->_whereTables as $tableName => $clause) { + if (CRM_Utils_Array::value($tableName, $locationTypeJoin)) { + $locClause[] = $locationTypeJoin[$tableName]; + } + } + + if (!empty($locClause)) { + $this->_whereTables[$locationTypeName] = "\nLEFT JOIN civicrm_location_type $ltName ON ( " . implode('OR', $locClause) . " )"; + } + } + } + + if (!empty($addressCustomFieldIds)) { + $cfIDs = $addressCustomFieldIds; + $customQuery = new CRM_Core_BAO_CustomQuery($cfIDs); + foreach ($addressCustomFieldIds as $cfID => $locTypeName) { + foreach ($locTypeName as $name => $dnc) { + $fieldName = "$name-custom_{$cfID}"; + $tName = "$name-address-custom-{$cfID}"; + $aName = "`$name-address-custom-{$cfID}`"; + $this->_select["{$tName}_id"] = "`$tName`.id as `{$tName}_id`"; + $this->_element["{$tName}_id"] = 1; + $this->_select[$fieldName] = "`$tName`.{$customQuery->_fields[$cfID]['column_name']} as `{$fieldName}`"; + $this->_element[$fieldName] = 1; + $this->_tables[$tName] = "\nLEFT JOIN {$customQuery->_fields[$cfID]['table_name']} $aName ON ($aName.entity_id = `$name-address`.id)"; + } + } + } + } + + /** + * If the return Properties are set in a hierarchy, traverse the hierarchy to get + * the return values + * + * @return void + * @access public + */ + function addMultipleElements() { + if (!CRM_Utils_Array::value('website', $this->_returnProperties)) { + return; + } + if (!is_array($this->_returnProperties['website'])) { + return; + } + + foreach ($this->_returnProperties['website'] as $key => $elements) { + foreach ($elements as $elementFullName => $dontCare) { + $tName = "website-{$key}-{$elementFullName}"; + $this->_select["{$tName}_id"] = "`$tName`.id as `{$tName}_id`"; + $this->_select["{$tName}"] = "`$tName`.url as `{$tName}`"; + $this->_element["{$tName}_id"] = 1; + $this->_element["{$tName}"] = 1; + + $type = "website-{$key}-website_type_id"; + $this->_select[$type] = "`$tName`.website_type_id as `{$type}`"; + $this->_element[$type] = 1; + $this->_tables[$tName] = "\nLEFT JOIN civicrm_website `$tName` ON (`$tName`.contact_id = contact_a.id )"; + } + } + } + + /** + * generate the query based on what type of query we need + * + * @param boolean $count + * @param boolean $sortByChar + * @param boolean $groupContacts + * + * @return the sql string for that query (this will most likely + * change soon) + * @access public + */ + function query($count = FALSE, $sortByChar = FALSE, $groupContacts = FALSE) { + if ($count) { + if (isset($this->_distinctComponentClause)) { + // we add distinct to get the right count for components + // for the more complex result set, we use GROUP BY the same id + // CRM-9630 + $select = "SELECT count( DISTINCT {$this->_distinctComponentClause} )"; + } + else { + $select = 'SELECT count(DISTINCT contact_a.id) as rowCount'; + } + $from = $this->_simpleFromClause; + if ($this->_useDistinct) { + $this->_useGroupBy = TRUE; + } + } + elseif ($sortByChar) { + $select = 'SELECT DISTINCT UPPER(LEFT(contact_a.sort_name, 1)) as sort_name'; + $from = $this->_simpleFromClause; + } + elseif ($groupContacts) { + $select = 'SELECT contact_a.id as id'; + if ($this->_useDistinct) { + $this->_useGroupBy = TRUE; + } + $from = $this->_simpleFromClause; + } + else { + if (CRM_Utils_Array::value('group', $this->_paramLookup)) { + // make sure there is only one element + // this is used when we are running under smog and need to know + // how the contact was added (CRM-1203) + if ((count($this->_paramLookup['group']) == 1) && + (count($this->_paramLookup['group'][0][2]) == 1) + ) { + $groups = array_keys($this->_paramLookup['group'][0][2]); + $groupId = $groups[0]; + + //check if group is saved search + $group = new CRM_Contact_BAO_Group(); + $group->id = $groupId; + $group->find(TRUE); + + if (!isset($group->saved_search_id)) { + $tbName = "`civicrm_group_contact-{$groupId}`"; + $this->_select['group_contact_id'] = "$tbName.id as group_contact_id"; + $this->_element['group_contact_id'] = 1; + $this->_select['status'] = "$tbName.status as status"; + $this->_element['status'] = 1; + $this->_tables[$tbName] = 1; + } + } + $this->_useGroupBy = TRUE; + } + if ($this->_useDistinct && !isset($this->_distinctComponentClause)) { + if (!($this->_mode & CRM_Contact_BAO_Query::MODE_ACTIVITY)) { + // CRM-5954 + $this->_select['contact_id'] = 'contact_a.id as contact_id'; + $this->_useDistinct = FALSE; + $this->_useGroupBy = TRUE; + } + } + + $select = "SELECT "; + if (isset($this->_distinctComponentClause)) { + $select .= "{$this->_distinctComponentClause}, "; + } + $select .= implode(', ', $this->_select); + $from = $this->_fromClause; + } + + $where = ''; + if (!empty($this->_whereClause)) { + $where = "WHERE {$this->_whereClause}"; + } + + $having = ''; + if (!empty($this->_having)) { + foreach ($this->_having as $havingsets) { + foreach ($havingsets as $havingset) { + $havingvalue[] = $havingset; + } + } + $having = ' HAVING ' . implode(' AND ', $havingvalue); + } + + // if we are doing a transform, do it here + // use the $from, $where and $having to get the contact ID + if ($this->_displayRelationshipType) { + $this->filterRelatedContacts($from, $where, $having); + } + + return array($select, $from, $where, $having); + } + + function &getWhereValues($name, $grouping) { + $result = NULL; + foreach ($this->_params as $id => $values) { + if ($values[0] == $name && $values[3] == $grouping) { + return $values; + } + } + + return $result; + } + + static function fixDateValues($relative, &$from, &$to) { + if ($relative) { + list($from, $to) = CRM_Utils_Date::getFromTo($relative, $from, $to); + } + } + + static function convertFormValues(&$formValues, $wildcard = 0, $useEquals = FALSE) { + $params = array(); + if (empty($formValues)) { + return $params; + } + + foreach ($formValues as $id => $values) { + if ($id == 'privacy') { + if (is_array($formValues['privacy'])) { + $op = CRM_Utils_Array::value('do_not_toggle', $formValues['privacy']) ? '=' : '!='; + foreach ($formValues['privacy'] as $key => $value) { + if ($value) { + $params[] = array($key, $op, $value, 0, 0); + } + } + } + } + elseif ($id == 'email_on_hold') { + if ($formValues['email_on_hold']['on_hold']) { + $params[] = array('on_hold', '=', $formValues['email_on_hold']['on_hold'], 0, 0); + } + } + elseif (preg_match('/_date_relative$/', $id) || + $id == 'event_relative' || + $id == 'case_from_relative' || + $id == 'case_to_relative' + ) { + if ($id == 'event_relative') { + $fromRange = 'event_start_date_low'; + $toRange = 'event_end_date_high'; + } + else if ($id == 'case_from_relative') { + $fromRange = 'case_from_start_date_low'; + $toRange = 'case_from_start_date_high'; + } + else if ($id == 'case_to_relative') { + $fromRange = 'case_to_end_date_low'; + $toRange = 'case_to_end_date_high'; + } + else { + $dateComponent = explode('_date_relative', $id); + $fromRange = "{$dateComponent[0]}_date_low"; + $toRange = "{$dateComponent[0]}_date_high"; + } + + if (array_key_exists($fromRange, $formValues) && array_key_exists($toRange, $formValues)) { + CRM_Contact_BAO_Query::fixDateValues($formValues[$id], $formValues[$fromRange], $formValues[$toRange]); + continue; + } + } + else { + $values = CRM_Contact_BAO_Query::fixWhereValues($id, $values, $wildcard, $useEquals); + + if (!$values) { + continue; + } + $params[] = $values; + } + } + return $params; + } + + static function &fixWhereValues($id, &$values, $wildcard = 0, $useEquals = FALSE) { + // skip a few search variables + static $skipWhere = NULL; + static $arrayValues = NULL; + static $likeNames = NULL; + $result = NULL; + + if (CRM_Utils_System::isNull($values)) { + return $result; + } + + if (!$skipWhere) { + $skipWhere = array( + 'task', 'radio_ts', 'uf_group_id', + 'component_mode', 'qfKey', 'operator', + 'display_relationship_type', + ); + } + + if (in_array($id, $skipWhere) || + substr($id, 0, 4) == '_qf_' || + substr($id, 0, 7) == 'hidden_' + ) { + return $result; + } + + if (!$likeNames) { + $likeNames = array('sort_name', 'email', 'note', 'display_name'); + } + + // email comes in via advanced search + // so use wildcard always + if ($id == 'email') { + $wildcard = 1; + } + + if (!$useEquals && in_array($id, $likeNames)) { + $result = array($id, 'LIKE', $values, 0, 1); + } + elseif (is_string($values) && strpos($values, '%') !== FALSE) { + $result = array($id, 'LIKE', $values, 0, 0); + } + elseif ($id == 'group') { + if (is_array($values)) { + foreach ($values as $groupIds => $val) { + $matches = array(); + if (preg_match('/-(\d+)$/', $groupIds, $matches)) { + if (strlen($matches[1]) > 0) { + $values[$matches[1]] = 1; + unset($values[$groupIds]); + } + } + } + } + else { + $groupIds = explode(',', $values); + unset($values); + foreach ($groupIds as $groupId) { + $values[$groupId] = 1; + } + } + + $result = array($id, 'IN', $values, 0, 0); + } + elseif ($id == 'contact_tags' || $id == 'tag') { + if (!is_array($values)) { + $tagIds = explode(',', $values); + unset($values); + foreach ($tagIds as $tagId) { + $values[$tagId] = 1; + } + } + $result = array($id, 'IN', $values, 0, 0); + } + else { + $result = array($id, '=', $values, 0, $wildcard); + } + + return $result; + } + + function whereClauseSingle(&$values) { + // do not process custom fields or prefixed contact ids or component params + if (CRM_Core_BAO_CustomField::getKeyID($values[0]) || + (substr($values[0], 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) || + (substr($values[0], 0, 13) == 'contribution_') || + (substr($values[0], 0, 6) == 'event_') || + (substr($values[0], 0, 12) == 'participant_') || + (substr($values[0], 0, 7) == 'member_') || + (substr($values[0], 0, 6) == 'grant_') || + (substr($values[0], 0, 7) == 'pledge_') || + (substr($values[0], 0, 5) == 'case_') + ) { + return; + } + + switch ($values[0]) { + case 'deleted_contacts': + $this->deletedContacts($values); + return; + + case 'contact_type': + $this->contactType($values); + return; + + case 'contact_sub_type': + $this->contactSubType($values); + return; + + case 'group': + list($name, $op, $value, $grouping, $wildcard) = $values; + $this->group($values); + return; + case 'group_type': + // so we resolve this into a list of groups & proceed as if they had been + // handed in + list($name, $op, $value, $grouping, $wildcard) = $values; + $values[0] = 'group'; + $values[1] = 'IN'; + $this->_paramLookup['group'][0][0] ='group'; + $this->_paramLookup['group'][0][1] = 'IN'; + $this->_paramLookup['group'][0][2] = $values[2] = $this->getGroupsFromTypeCriteria($value); + $this->group($values); + return; + // case tag comes from find contacts + + case 'tag_search': + $this->tagSearch($values); + return; + + case 'tag': + case 'contact_tags': + $this->tag($values); + return; + + case 'note': + case 'note_body': + case 'note_subject': + $this->notes($values); + return; + + case 'uf_user': + $this->ufUser($values); + return; + + case 'sort_name': + case 'display_name': + $this->sortName($values); + //force civicrm_activity_target, CRM-7812 + self::$_withContactActivitiesOnly = TRUE; + return; + + case 'email': + $this->email($values); + return; + + case 'phone_numeric': + $this->phone_numeric($values); + return; + + case 'phone_phone_type_id': + case 'phone_location_type_id': + $this->phone_option_group($values); + return; + + case 'street_address': + $this->street_address($values); + return; + + case 'street_number': + $this->street_number($values); + return; + + case 'sortByCharacter': + $this->sortByCharacter($values); + return; + + case 'location_type': + $this->locationType($values); + return; + + case 'county': + $this->county($values); + return; + + case 'state_province': + $this->stateProvince($values); + return; + + case 'country': + $this->country($values, FALSE); + return; + + case 'postal_code': + case 'postal_code_low': + case 'postal_code_high': + $this->postalCode($values); + return; + + case 'activity_date': + case 'activity_date_low': + case 'activity_date_high': + case 'activity_role': + case 'activity_status': + case 'activity_subject': + case 'test_activities': + case 'activity_type_id': + case 'activity_survey_id': + case 'activity_tags': + case 'activity_taglist': + case 'activity_test': + case 'activity_contact_name': + case 'activity_campaign_id': + case 'activity_engagement_level': + case 'activity_id': + case 'source_contact': + CRM_Activity_BAO_Query::whereClauseSingle($values, $this); + return; + + case 'birth_date_low': + case 'birth_date_high': + case 'deceased_date_low': + case 'deceased_date_high': + $this->demographics($values); + return; + + case 'log_date_low': + case 'log_date_high': + $this->modifiedDates($values); + return; + + case 'changed_by': + $this->changeLog($values); + return; + + case 'do_not_phone': + case 'do_not_email': + case 'do_not_mail': + case 'do_not_sms': + case 'do_not_trade': + case 'is_opt_out': + $this->privacy($values); + return; + + case 'privacy_options': + $this->privacyOptions($values); + return; + + case 'privacy_operator': + case 'privacy_toggle': + // these are handled by privacy options + return; + + case 'preferred_communication_method': + $this->preferredCommunication($values); + return; + + case 'relation_type_id': + $this->relationship($values); + return; + + case 'relation_target_name': + case 'relation_status': + case 'relation_date_low': + case 'relation_date_high': + // since this case is handled with the above + return; + + case 'task_status_id': + $this->task($values); + return; + + case 'task_id': + // since this case is handled with the above + return; + + case 'prox_distance': + CRM_Contact_BAO_ProximityQuery::process($this, $values); + return; + + case 'prox_street_address': + case 'prox_city': + case 'prox_postal_code': + case 'prox_state_province_id': + case 'prox_country_id': + // handled by the proximity_distance clause + return; + + default: + $this->restWhere($values); + return; + } + } + + /** + * Given a list of conditions in params generate the required + * where clause + * + * @return void + * @access public + */ + function whereClause() { + $this->_where[0] = array(); + $this->_qill[0] = array(); + + $config = CRM_Core_Config::singleton(); + + $this->includeContactIds(); + if (!empty($this->_params)) { + + foreach (array_keys($this->_params) as $id) { + if (!CRM_Utils_Array::value(0, $this->_params[$id])) { + continue; + } + // check for both id and contact_id + if ($this->_params[$id][0] == 'id' || $this->_params[$id][0] == 'contact_id') { + if ($this->_params[$id][1] == 'IS NULL' || + $this->_params[$id][1] == 'IS NOT NULL' + ) { + $this->_where[0][] = "contact_a.id {$this->_params[$id][1]}"; + } + else { + $this->_where[0][] = "contact_a.id {$this->_params[$id][1]} {$this->_params[$id][2]}"; + } + } + else { + $this->whereClauseSingle($this->_params[$id]); + } + } + + CRM_Core_Component::alterQuery($this, 'where'); + } + + if ($this->_customQuery) { + // Added following if condition to avoid the wrong value diplay for 'myaccount' / any UF info. + // Hope it wont affect the other part of civicrm.. if it does please remove it. + if (!empty($this->_customQuery->_where)) { + $this->_where = CRM_Utils_Array::crmArrayMerge($this->_where, $this->_customQuery->_where); + } + + $this->_qill = CRM_Utils_Array::crmArrayMerge($this->_qill, $this->_customQuery->_qill); + } + + $clauses = array(); + $andClauses = array(); + + $validClauses = 0; + if (!empty($this->_where)) { + foreach ($this->_where as $grouping => $values) { + if ($grouping > 0 && !empty($values)) { + $clauses[$grouping] = ' ( ' . implode(" {$this->_operator} ", $values) . ' ) '; + $validClauses++; + } + } + + if (!empty($this->_where[0])) { + $andClauses[] = ' ( ' . implode(" {$this->_operator} ", $this->_where[0]) . ' ) '; + } + if (!empty($clauses)) { + $andClauses[] = ' ( ' . implode(' OR ', $clauses) . ' ) '; + } + + if ($validClauses > 1) { + $this->_useDistinct = TRUE; + } + } + + return implode(' AND ', $andClauses); + } + + function restWhere(&$values) { + $name = CRM_Utils_Array::value(0, $values); + $op = CRM_Utils_Array::value(1, $values); + $value = CRM_Utils_Array::value(2, $values); + $grouping = CRM_Utils_Array::value(3, $values); + $wildcard = CRM_Utils_Array::value(4, $values); + + if (isset($grouping) && !CRM_Utils_Array::value($grouping, $this->_where)) { + $this->_where[$grouping] = array(); + } + + $multipleFields = array('url'); + + //check if the location type exits for fields + $lType = ''; + $locType = explode('-', $name); + + if (!in_array($locType[0], $multipleFields)) { + //add phone type if exists + if (isset($locType[2]) && $locType[2]) { + $locType[2] = CRM_Core_DAO::escapeString($locType[2]); + } + } + + $field = CRM_Utils_Array::value($name, $this->_fields); + + if (!$field) { + $field = CRM_Utils_Array::value($locType[0], $this->_fields); + + if (!$field) { + return; + } + } + + $setTables = TRUE; + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + + if (substr($name, 0, 14) === 'state_province') { + if (isset($locType[1]) && is_numeric($locType[1])) { + $setTables = FALSE; + + list($tName, $fldName) = self::getLocationTableName($field['where'], $locType); + $this->_whereTables[$tName] = $this->_tables[$tName]; + $where = "`$tName`.$fldName"; + } + else { + $where = $field['where']; + } + + if (is_numeric($value)) { + $where = str_replace('.name', '.id', $where); + $this->_where[$grouping][] = self::buildClause($where, $op, $value, 'Positive'); + $states = CRM_Core_PseudoConstant::stateProvince(); + $value = $states[(int ) $value]; + } + else { + $wc = self::caseImportant($op) ? "LOWER($where)" : $where; + $this->_where[$grouping][] = self::buildClause($wc, $op, $value, 'String'); + } + if (!$lType) { + $this->_qill[$grouping][] = ts('State') . " $op '$value'"; + } + else { + $this->_qill[$grouping][] = ts('State') . " ($lType) $op '$value'"; + } + } + elseif (substr($name, 0, 7) === 'country') { + if (isset($locType[1]) && is_numeric($locType[1])) { + $setTables = FALSE; + + list($tName, $fldName) = self::getLocationTableName($field['where'], $locType); + $this->_whereTables[$tName] = $this->_tables[$tName]; + $where = "`$tName`.$fldName"; + } + else { + $where = $field['where']; + } + + if (is_numeric($value)) { + $where = str_replace('.name', '.id', $where); + $this->_where[$grouping][] = self::buildClause($where, $op, $value, 'Positive'); + $countries = CRM_Core_PseudoConstant::country(); + $value = $countries[(int ) $value]; + } + else { + $wc = self::caseImportant($op) ? "LOWER($where)" : $where; + $this->_where[$grouping][] = self::buildClause($wc, $op, $value, 'String'); + } + if (!$lType) { + $this->_qill[$grouping][] = ts('Country') . " $op '$value'"; + } + else { + $this->_qill[$grouping][] = ts('Country') . " ($lType) $op '$value'"; + } + } + elseif (substr($name, 0, 6) === 'county') { + if (isset($locType[1]) && is_numeric($locType[1])) { + $setTables = FALSE; + + list($tName, $fldName) = self::getLocationTableName($field['where'], $locType); + $this->_whereTables[$tName] = $this->_tables[$tName]; + $where = "`$tName`.$fldName"; + } + else { + $where = $field['where']; + } + if (is_numeric($value)) { + $where = str_replace('.name', '.id', $where); + $this->_where[$grouping][] = self::buildClause($where, $op, $value, 'Positive'); + $counties = CRM_Core_PseudoConstant::county(); + $value = $counties[(int ) $value]; + } + else { + $wc = self::caseImportant($op) ? "LOWER($where)" : $where; + $this->_where[$grouping][] = self::buildClause($wc, $op, $value, 'String'); + } + + if (!$lType) { + $this->_qill[$grouping][] = ts('County') . " $op '$value'"; + } + else { + $this->_qill[$grouping][] = ts('County') . " ($lType) $op '$value'"; + } + } + elseif ($name === 'world_region') { + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::worldRegion(), + $field, + ts('World Region') + ); + } + elseif ($name === 'individual_prefix') { + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::individualPrefix(), + $field, + ts('Individual Prefix') + ); + } + elseif ($name === 'individual_suffix') { + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::individualSuffix(), + $field, + ts('Individual Suffix') + ); + } + elseif ($name === 'gender') { + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::gender(), + $field, + ts('Gender') + ); + self::$_openedPanes[ts('Demographics')] = TRUE; + } + elseif ($name === 'birth_date') { + $date = CRM_Utils_Date::processDate($value); + $this->_where[$grouping][] = self::buildClause("contact_a.{$name}", $op, $date); + + if ($date) { + $date = CRM_Utils_Date::customFormat($date); + $this->_qill[$grouping][] = "$field[title] $op \"$date\""; + } + else { + $this->_qill[$grouping][] = "$field[title] $op"; + } + self::$_openedPanes[ts('Demographics')] = TRUE; + } + elseif ($name === 'deceased_date') { + $date = CRM_Utils_Date::processDate($value); + $this->_where[$grouping][] = self::buildClause("contact_a.{$name}", $op, $date); + if ($date) { + $date = CRM_Utils_Date::customFormat($date); + $this->_qill[$grouping][] = "$field[title] $op \"$date\""; + } + else { + $this->_qill[$grouping][] = "$field[title] $op"; + } + self::$_openedPanes[ts('Demographics')] = TRUE; + } + elseif ($name === 'is_deceased') { + $this->_where[$grouping][] = self::buildClause("contact_a.{$name}", $op, $value); + $this->_qill[$grouping][] = "$field[title] $op \"$value\""; + self::$_openedPanes[ts('Demographics')] = TRUE; + } + elseif ($name === 'contact_id') { + if (is_int($value)) { + $this->_where[$grouping][] = self::buildClause($field['where'], $op, $value); + $this->_qill[$grouping][] = "$field[title] $op $value"; + } + } + elseif ($name === 'name') { + $value = $strtolower(CRM_Core_DAO::escapeString($value)); + if ($wildcard) { + $value = "%$value%"; + $op = 'LIKE'; + } + $wc = self::caseImportant($op) ? "LOWER({$field['where']})" : "{$field['where']}"; + $this->_where[$grouping][] = self::buildClause($wc, $op, "'$value'"); + $this->_qill[$grouping][] = "$field[title] $op \"$value\""; + } + elseif ($name === 'current_employer') { + $value = $strtolower(CRM_Core_DAO::escapeString($value)); + if ($wildcard) { + $value = "%$value%"; + $op = 'LIKE'; + } + $wc = self::caseImportant($op) ? "LOWER(contact_a.organization_name)" : "contact_a.organization_name"; + $this->_where[$grouping][] = self::buildClause($wc, $op, + "'$value' AND contact_a.contact_type ='Individual'" + ); + $this->_qill[$grouping][] = "$field[title] $op \"$value\""; + } + elseif ($name === 'email_greeting') { + $filterCondition = array('greeting_type' => 'email_greeting'); + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::greeting($filterCondition), + $field, + ts('Email Greeting') + ); + } + elseif ($name === 'postal_greeting') { + $filterCondition = array('greeting_type' => 'postal_greeting'); + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::greeting($filterCondition), + $field, + ts('Postal Greeting') + ); + } + elseif ($name === 'addressee') { + $filterCondition = array('greeting_type' => 'addressee'); + $this->optionValueQuery( + $name, $op, $value, $grouping, + CRM_Core_PseudoConstant::greeting($filterCondition), + $field, + ts('Addressee') + ); + } + elseif (substr($name, 0, 4) === 'url-') { + $tName = 'civicrm_website'; + $this->_whereTables[$tName] = $this->_tables[$tName] = "\nLEFT JOIN civicrm_website ON ( civicrm_website.contact_id = contact_a.id )"; + $value = $strtolower(CRM_Core_DAO::escapeString($value)); + if ($wildcard) { + $value = "%$value%"; + $op = 'LIKE'; + } + + $wc = 'civicrm_website.url'; + $this->_where[$grouping][] = self::buildClause($wc, $op, "'$value'"); + $this->_qill[$grouping][] = "$field[title] $op \"$value\""; + } + elseif ($name === 'contact_is_deleted') { + $this->_where[$grouping][] = self::buildClause("contact_a.is_deleted", $op, $value); + $this->_qill[$grouping][] = "$field[title] $op \"$value\""; + } + else { + // sometime the value is an array, need to investigate and fix + if (is_array($value)) { + CRM_Core_Error::fatal(); + } + + if (!empty($field['where'])) { + if ($op != 'IN') { + $value = $strtolower($value); + } + if ($wildcard) { + $value = "%$value%"; + $op = 'LIKE'; + } + + if (isset($locType[1]) && + is_numeric($locType[1]) + ) { + $setTables = FALSE; + + //get the location name + $locationType = CRM_Core_PseudoConstant::locationType(); + list($tName, $fldName) = self::getLocationTableName($field['where'], $locType); + + $where = "`$tName`.$fldName"; + + $this->_where[$grouping][] = self::buildClause("LOWER($where)", $op, $value); + $this->_whereTables[$tName] = $this->_tables[$tName]; + $this->_qill[$grouping][] = "$field[title] $op '$value'"; + } + else { + list($tableName, $fieldName) = explode('.', $field['where'], 2); + if ($tableName == 'civicrm_contact') { + $fieldName = "LOWER(contact_a.{$fieldName})"; + } + else { + if ($op != 'IN' && !is_numeric($value)) { + $fieldName = "LOWER({$field['where']})"; + } + else { + $fieldName = "{$field['where']}"; + } + } + + $type = NULL; + if (CRM_Utils_Array::value('type', $field)) { + $type = CRM_Utils_Type::typeToString($field['type']); + } + + $this->_where[$grouping][] = self::buildClause($fieldName, $op, $value, $type); + $this->_qill[$grouping][] = "$field[title] $op $value"; + } + } + } + + if ($setTables && isset($field['where'])) { + list($tableName, $fieldName) = explode('.', $field['where'], 2); + if (isset($tableName)) { + $this->_tables[$tableName] = 1; + $this->_whereTables[$tableName] = 1; + } + } + } + + + static function getLocationTableName(&$where, &$locType) { + if (isset($locType[1]) && is_numeric($locType[1])) { + list($tbName, $fldName) = explode(".", $where); + + //get the location name + $locationType = CRM_Core_PseudoConstant::locationType(); + $specialFields = array('email', 'im', 'phone', 'openid', 'phone_ext'); + if (in_array($locType[0], $specialFields)) { + //hack to fix / special handing for phone_ext + if ($locType[0] == 'phone_ext') { + $locType[0] = 'phone'; + } + if (isset($locType[2]) && $locType[2]) { + $tName = "{$locationType[$locType[1]]}-{$locType[0]}-{$locType[2]}"; + } + else { + $tName = "{$locationType[$locType[1]]}-{$locType[0]}"; + } + } + elseif (in_array($locType[0], + array( + 'address_name', 'street_address', 'supplemental_address_1', 'supplemental_address_2', + 'city', 'postal_code', 'postal_code_suffix', 'geo_code_1', 'geo_code_2', + ) + )) { + //fix for search by profile with address fields. + $tName = "{$locationType[$locType[1]]}-address"; + } + elseif ($locType[0] == 'on_hold') { + $tName = "{$locationType[$locType[1]]}-email"; + } + else { + $tName = "{$locationType[$locType[1]]}-{$locType[0]}"; + } + $tName = str_replace(' ', '_', $tName); + return array($tName, $fldName); + } + CRM_Core_Error::fatal(); + } + + /** + * Given a result dao, extract the values and return that array + * + * @param Object $dao + * + * @return array values for this query + */ + function store($dao) { + $value = array(); + + foreach ($this->_element as $key => $dontCare) { + if (property_exists($dao, $key)) { + if (strpos($key, '-') !== FALSE) { + $values = explode('-', $key); + $lastElement = array_pop($values); + $current = &$value; + $cnt = count($values); + $count = 1; + foreach ($values as $v) { + if (!array_key_exists($v, $current)) { + $current[$v] = array(); + } + //bad hack for im_provider + if ($lastElement == 'provider_id') { + if ($count < $cnt) { + $current = &$current[$v]; + } + else { + $lastElement = "{$v}_{$lastElement}"; + } + } + else { + $current = &$current[$v]; + } + $count++; + } + + $current[$lastElement] = $dao->$key; + } + else { + $value[$key] = $dao->$key; + } + } + } + return $value; + } + + /** + * getter for tables array + * + * @return array + * @access public + */ + function tables() { + return $this->_tables; + } + + function whereTables() { + return $this->_whereTables; + } + + /** + * generate the where clause (used in match contacts and permissions) + * + * @param array $params + * @param array $fields + * @param array $tables + * @param boolean $strict + * + * @return string + * @access public + * @static + */ + static function getWhereClause($params, $fields, &$tables, &$whereTables, $strict = FALSE) { + $query = new CRM_Contact_BAO_Query($params, NULL, $fields, + FALSE, $strict + ); + + $tables = array_merge($query->tables(), $tables); + $whereTables = array_merge($query->whereTables(), $whereTables); + + return $query->_whereClause; + } + + /** + * create the from clause + * + * @param array $tables tables that need to be included in this from clause + * if null, return mimimal from clause (i.e. civicrm_contact) + * @param array $inner tables that should be inner-joined + * @param array $right tables that should be right-joined + * + * @return string the from clause + * @access public + * @static + */ + static function fromClause(&$tables, $inner = NULL, $right = NULL, $primaryLocation = TRUE, $mode = 1) { + + $from = ' FROM civicrm_contact contact_a'; + if (empty($tables)) { + return $from; + } + + if (CRM_Utils_Array::value('civicrm_worldregion', $tables)) { + $tables = array_merge(array('civicrm_country' => 1), $tables); + } + + if ((CRM_Utils_Array::value('civicrm_state_province', $tables) || + CRM_Utils_Array::value('civicrm_country', $tables) || + CRM_Utils_Array::value('civicrm_county', $tables) + ) && + !CRM_Utils_Array::value('civicrm_address', $tables) + ) { + $tables = array_merge(array('civicrm_address' => 1), + $tables + ); + } + + // add group_contact table if group table is present + if (CRM_Utils_Array::value('civicrm_group', $tables) && + !CRM_Utils_Array::value('civicrm_group_contact', $tables) + ) { + $tables['civicrm_group_contact'] = " LEFT JOIN civicrm_group_contact ON civicrm_group_contact.contact_id = contact_a.id AND civicrm_group_contact.status = 'Added'"; + } + + // add group_contact and group table is subscription history is present + if (CRM_Utils_Array::value('civicrm_subscription_history', $tables) + && !CRM_Utils_Array::value('civicrm_group', $tables) + ) { + $tables = array_merge(array( + 'civicrm_group' => 1, + 'civicrm_group_contact' => 1, + ), + $tables + ); + } + + // to handle table dependencies of components + CRM_Core_Component::tableNames($tables); + + //format the table list according to the weight + $info = CRM_Core_TableHierarchy::info(); + + foreach ($tables as $key => $value) { + $k = 99; + if (strpos($key, '-') !== FALSE) { + $keyArray = explode('-', $key); + $k = CRM_Utils_Array::value('civicrm_' . $keyArray[1], $info, 99); + } + elseif (strpos($key, '_') !== FALSE) { + $keyArray = explode('_', $key); + if (is_numeric(array_pop($keyArray))) { + $k = CRM_Utils_Array::value(implode('_', $keyArray), $info, 99); + } + else { + $k = CRM_Utils_Array::value($key, $info, 99); + } + } + else { + $k = CRM_Utils_Array::value($key, $info, 99); + } + $tempTable[$k . ".$key"] = $key; + } + ksort($tempTable); + $newTables = array(); + foreach ($tempTable as $key) { + $newTables[$key] = $tables[$key]; + } + + $tables = $newTables; + + foreach ($tables as $name => $value) { + if (!$value) { + continue; + } + + if (CRM_Utils_Array::value($name, $inner)) { + $side = 'INNER'; + } + elseif (CRM_Utils_Array::value($name, $right)) { + $side = 'RIGHT'; + } + else { + $side = 'LEFT'; + } + + if ($value != 1) { + // if there is already a join statement in value, use value itself + if (strpos($value, 'JOIN')) { + $from .= " $value "; + } + else { + $from .= " $side JOIN $name ON ( $value ) "; + } + continue; + } + switch ($name) { + case 'civicrm_address': + if ($primaryLocation) { + $from .= " $side JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id AND civicrm_address.is_primary = 1 )"; + } + else { + $from .= " $side JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id ) "; + } + continue; + + case 'civicrm_phone': + $from .= " $side JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id AND civicrm_phone.is_primary = 1) "; + continue; + + case 'civicrm_email': + $from .= " $side JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1) "; + continue; + + case 'civicrm_im': + $from .= " $side JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id AND civicrm_im.is_primary = 1) "; + continue; + + case 'im_provider': + $from .= " $side JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id) "; + $from .= " $side JOIN civicrm_option_group option_group_imProvider ON option_group_imProvider.name = 'instant_messenger_service'"; + $from .= " $side JOIN civicrm_option_value im_provider ON (civicrm_im.provider_id = im_provider.value AND option_group_imProvider.id = im_provider.option_group_id)"; + continue; + + case 'civicrm_openid': + $from .= " $side JOIN civicrm_openid ON ( civicrm_openid.contact_id = contact_a.id AND civicrm_openid.is_primary = 1 )"; + continue; + + case 'civicrm_state_province': + $from .= " $side JOIN civicrm_state_province ON civicrm_address.state_province_id = civicrm_state_province.id "; + continue; + + case 'civicrm_country': + $from .= " $side JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id "; + continue; + + case 'civicrm_worldregion': + $from .= " $side JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id "; + continue; + + case 'civicrm_county': + $from .= " $side JOIN civicrm_county ON civicrm_address.county_id = civicrm_county.id "; + continue; + + case 'civicrm_location_type': + $from .= " $side JOIN civicrm_location_type ON civicrm_address.location_type_id = civicrm_location_type.id "; + continue; + + case 'civicrm_group': + $from .= " $side JOIN civicrm_group ON civicrm_group.id = civicrm_group_contact.group_id "; + continue; + + case 'civicrm_group_contact': + $from .= " $side JOIN civicrm_group_contact ON contact_a.id = civicrm_group_contact.contact_id "; + continue; + + case 'civicrm_activity': + case 'civicrm_activity_tag': + case 'activity_type': + case 'activity_status': + case 'civicrm_activity_contact': + case 'source_contact': + $from .= CRM_Activity_BAO_Query::from($name, $mode, $side); + continue; + + case 'civicrm_entity_tag': + $from .= " $side JOIN civicrm_entity_tag ON ( civicrm_entity_tag.entity_table = 'civicrm_contact' AND + civicrm_entity_tag.entity_id = contact_a.id ) "; + continue; + + case 'civicrm_note': + $from .= " $side JOIN civicrm_note ON ( civicrm_note.entity_table = 'civicrm_contact' AND + contact_a.id = civicrm_note.entity_id ) "; + continue; + + case 'civicrm_subscription_history': + $from .= " $side JOIN civicrm_subscription_history + ON civicrm_group_contact.contact_id = civicrm_subscription_history.contact_id + AND civicrm_group_contact.group_id = civicrm_subscription_history.group_id"; + continue; + + case 'individual_prefix': + $from .= " $side JOIN civicrm_option_group option_group_prefix ON (option_group_prefix.name = 'individual_prefix')"; + $from .= " $side JOIN civicrm_option_value individual_prefix ON (contact_a.prefix_id = individual_prefix.value AND option_group_prefix.id = individual_prefix.option_group_id ) "; + continue; + + case 'individual_suffix': + $from .= " $side JOIN civicrm_option_group option_group_suffix ON (option_group_suffix.name = 'individual_suffix')"; + $from .= " $side JOIN civicrm_option_value individual_suffix ON (contact_a.suffix_id = individual_suffix.value AND option_group_suffix.id = individual_suffix.option_group_id ) "; + continue; + + case 'gender': + $from .= " $side JOIN civicrm_option_group option_group_gender ON (option_group_gender.name = 'gender')"; + $from .= " $side JOIN civicrm_option_value gender ON (contact_a.gender_id = gender.value AND option_group_gender.id = gender.option_group_id) "; + continue; + + case 'civicrm_relationship': + if (self::$_relType == 'reciprocal') { + $from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id OR civicrm_relationship.contact_id_a = contact_a.id)"; + $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id OR civicrm_relationship.contact_id_b = contact_b.id)"; + } + elseif (self::$_relType == 'b') { + $from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id )"; + $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id )"; + } + else { + $from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_a = contact_a.id )"; + $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_b = contact_b.id )"; + } + continue; + + case 'civicrm_log': + $from .= " $side JOIN civicrm_log ON (civicrm_log.entity_id = contact_a.id AND civicrm_log.entity_table = 'civicrm_contact')"; + $from .= " $side JOIN civicrm_contact contact_b_log ON (civicrm_log.modified_id = contact_b_log.id)"; + continue; + + case 'civicrm_tag': + $from .= " $side JOIN civicrm_tag ON civicrm_entity_tag.tag_id = civicrm_tag.id "; + continue; + + case 'civicrm_task_status': + $from .= " $side JOIN civicrm_task_status ON ( civicrm_task_status.responsible_entity_table = 'civicrm_contact' + AND contact_a.id = civicrm_task_status.responsible_entity_id )"; + continue; + + case 'civicrm_grant': + $from .= CRM_Grant_BAO_Query::from($name, $mode, $side); + continue; + + //build fromClause for email greeting, postal greeting, addressee CRM-4575 + + case 'email_greeting': + $from .= " $side JOIN civicrm_option_group option_group_email_greeting ON (option_group_email_greeting.name = 'email_greeting')"; + $from .= " $side JOIN civicrm_option_value email_greeting ON (contact_a.email_greeting_id = email_greeting.value AND option_group_email_greeting.id = email_greeting.option_group_id ) "; + continue; + + case 'postal_greeting': + $from .= " $side JOIN civicrm_option_group option_group_postal_greeting ON (option_group_postal_greeting.name = 'postal_greeting')"; + $from .= " $side JOIN civicrm_option_value postal_greeting ON (contact_a.postal_greeting_id = postal_greeting.value AND option_group_postal_greeting.id = postal_greeting.option_group_id ) "; + continue; + + case 'addressee': + $from .= " $side JOIN civicrm_option_group option_group_addressee ON (option_group_addressee.name = 'addressee')"; + $from .= " $side JOIN civicrm_option_value addressee ON (contact_a.addressee_id = addressee.value AND option_group_addressee.id = addressee.option_group_id ) "; + continue; + + case 'civicrm_website': + $from .= " $side JOIN civicrm_website ON contact_a.id = civicrm_website.contact_id "; + continue; + + default: + $from .= CRM_Core_Component::from($name, $mode, $side); + continue; + } + } + + return $from; + } + + /** + * WHERE / QILL clause for deleted_contacts + * + * @return void + */ + function deletedContacts($values) { + list($_, $_, $value, $grouping, $_) = $values; + if ($value) { + // *prepend* to the relevant grouping as this is quite an important factor + array_unshift($this->_qill[$grouping], ts('Search in Trash')); + } + } + + /** + * where / qill clause for contact_type + * + * @return void + * @access public + */ + function contactType(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $subTypes = array(); + $clause = array(); + + // account for search builder mapping multiple values + if (!is_array($value)) { + $values = self::parseSearchBuilderString($value, 'String'); + if (is_array($values)) { + $value = array_flip($values); + } + } + + if (is_array($value)) { + foreach ($value as $k => $v) { + // fix for CRM-771 + if ($k) { + $subType = NULL; + $contactType = $k; + if (strpos($k, CRM_Core_DAO::VALUE_SEPARATOR)) { + list($contactType, $subType) = explode(CRM_Core_DAO::VALUE_SEPARATOR, $k, 2); + } + + if (!empty($subType)) { + $subTypes[$subType] = 1; + } + $clause[$contactType] = "'" . CRM_Utils_Type::escape($contactType, 'String') . "'"; + } + } + } + else { + $contactTypeANDSubType = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value, 2); + $contactType = $contactTypeANDSubType[0]; + $subType = CRM_Utils_Array::value(1, $contactTypeANDSubType); + if (!empty($subType)) { + $subTypes[$subType] = 1; + } + $clause[$contactType] = "'" . CRM_Utils_Type::escape($contactType, 'String') . "'"; + } + + // fix for CRM-771 + if (!empty($clause)) { + $this->_where[$grouping][] = 'contact_a.contact_type IN (' . implode(',', $clause) . ')'; + $this->_qill[$grouping][] = ts('Contact Type') . ' - ' . implode(' ' . ts('or') . ' ', $clause); + + if (!empty($subTypes)) { + $this->includeContactSubTypes($subTypes, $grouping); + } + } + } + + /** + * where / qill clause for contact_sub_type + * + * @return void + * @access public + */ + function contactSubType(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + $this->includeContactSubTypes($value, $grouping); + } + + function includeContactSubTypes($value, $grouping) { + + $clause = array(); + $alias = "contact_a.contact_sub_type"; + + if (is_array($value)) { + foreach ($value as $k => $v) { + if (!empty($k)) { + $clause[$k] = "($alias like '%" . CRM_Core_DAO::VALUE_SEPARATOR . CRM_Utils_Type::escape($k, 'String') . CRM_Core_DAO::VALUE_SEPARATOR . "%')"; + } + } + } + else { + $clause[$value] = "($alias like '%" . CRM_Core_DAO::VALUE_SEPARATOR . CRM_Utils_Type::escape($value, 'String') . CRM_Core_DAO::VALUE_SEPARATOR . "%')"; + } + + if (!empty($clause)) { + $this->_where[$grouping][] = "( " . implode(' OR ', $clause) . " )"; + $this->_qill[$grouping][] = ts('Contact Subtype') . ' - ' . implode(' ' . ts('or') . ' ', array_keys($clause)); + } + } + + /** + * where / qill clause for groups + * + * @return void + * @access public + */ + function group(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (count($value) > 1) { + $this->_useDistinct = TRUE; + } + + $groupNames = CRM_Core_PseudoConstant::group(); + $groupIds = implode(',', array_keys($value)); + + $names = array(); + foreach ($value as $id => $dontCare) { + if (array_key_exists($id, $groupNames) && $dontCare) { + $names[] = $groupNames[$id]; + } + } + + $statii = array(); + $in = FALSE; + $gcsValues = &$this->getWhereValues('group_contact_status', $grouping); + if ($gcsValues && + is_array($gcsValues[2]) + ) { + foreach ($gcsValues[2] as $k => $v) { + if ($v) { + if ($k == 'Added') { + $in = TRUE; + } + $statii[] = "'" . CRM_Utils_Type::escape($k, 'String') . "'"; + } + } + } + else { + $statii[] = '"Added"'; + $in = TRUE; + } + + $skipGroup = FALSE; + if (count($value) == 1 && + count($statii) == 1 && + $statii[0] == '"Added"' + ) { + // check if smart group, if so we can get rid of that one additional + // left join + $groupIDs = array_keys($value); + + if (CRM_Utils_Array::value(0, $groupIDs) && + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', + $groupIDs[0], + 'saved_search_id' + ) + ) { + $skipGroup = TRUE; + } + } + + if (!$skipGroup) { + $gcTable = "`civicrm_group_contact-{$groupIds}`"; + $this->_tables[$gcTable] = $this->_whereTables[$gcTable] = " LEFT JOIN civicrm_group_contact {$gcTable} ON contact_a.id = {$gcTable}.contact_id "; + } + + $qill = ts('Contacts %1', array(1 => $op)); + $qill .= ' ' . implode(' ' . ts('or') . ' ', $names); + + $groupClause = NULL; + + if (!$skipGroup) { + $groupClause = "{$gcTable}.group_id $op ( $groupIds )"; + if (!empty($statii)) { + $groupClause .= " AND {$gcTable}.status IN (" . implode(', ', $statii) . ")"; + $qill .= " " . ts('AND') . " " . ts('Group Status') . ' - ' . implode(' ' . ts('or') . ' ', $statii); + } + } + + if ($in) { + $ssClause = $this->savedSearch($values); + if ($ssClause) { + if ($groupClause) { + $groupClause = "( ( $groupClause ) OR ( $ssClause ) )"; + } + else { + $groupClause = $ssClause; + } + } + } + + $this->_where[$grouping][] = $groupClause; + $this->_qill[$grouping][] = $qill; + } + /* + * Function translates selection of group type into a list of groups + */ + function getGroupsFromTypeCriteria($value){ + $groupIds = array(); + foreach ($value as $groupTypeValue) { + $groupList = CRM_Core_PseudoConstant::group($groupTypeValue); + $groupIds = ($groupIds + $groupList); + } + return $groupIds; + } + + /** + * where / qill clause for smart groups + * + * @return void + * @access public + */ + function savedSearch(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + return $this->addGroupContactCache(array_keys($value)); + } + + function addGroupContactCache($groups, $tableAlias = NULL, $joinTable = "contact_a") { + $config = CRM_Core_Config::singleton(); + + // find all the groups that are part of a saved search + $groupIDs = implode(',', $groups); + if (empty($groupIDs)) { + return NULL; + } + + $sql = " +SELECT id, cache_date, saved_search_id, children +FROM civicrm_group +WHERE id IN ( $groupIDs ) + AND ( saved_search_id != 0 + OR saved_search_id IS NOT NULL + OR children IS NOT NULL ) +"; + $group = CRM_Core_DAO::executeQuery($sql); + $ssWhere = array(); + while ($group->fetch()) { + if ($tableAlias == NULL) { + $alias = "`civicrm_group_contact_cache_{$group->id}`"; + } + else { + $alias = $tableAlias; + } + + $this->_useDistinct = TRUE; + + if (!$this->_smartGroupCache || $group->cache_date == NULL) { + CRM_Contact_BAO_GroupContactCache::load($group); + } + + $this->_tables[$alias] = $this->_whereTables[$alias] = " LEFT JOIN civicrm_group_contact_cache {$alias} ON {$joinTable}.id = {$alias}.contact_id "; + $ssWhere[] = "{$alias}.group_id = {$group->id}"; + } + + if (!empty($ssWhere)) { + return implode(' OR ', $ssWhere); + } + return NULL; + } + + /** + * where / qill clause for cms users + * + * @return void + * @access public + */ + function ufUser(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if ($value == 1) { + $this->_tables['civicrm_uf_match'] = $this->_whereTables['civicrm_uf_match'] = ' INNER JOIN civicrm_uf_match ON civicrm_uf_match.contact_id = contact_a.id '; + + $this->_qill[$grouping][] = ts('CMS User'); + } + elseif ($value == 0) { + $this->_tables['civicrm_uf_match'] = $this->_whereTables['civicrm_uf_match'] = ' LEFT JOIN civicrm_uf_match ON civicrm_uf_match.contact_id = contact_a.id '; + + $this->_where[$grouping][] = " civicrm_uf_match.contact_id IS NULL"; + $this->_qill[$grouping][] = ts('Not a CMS User'); + } + } + + /** + * all tag search specific + * + * @return void + * @access public + */ + function tagSearch(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $op = "LIKE"; + $value = "%{$value}%"; + + + $useAllTagTypes = $this->getWhereValues('all_tag_types', $grouping); + $tagTypesText = $this->getWhereValues('tag_types_text', $grouping); + + $etTable = "`civicrm_entity_tag-" . $value . "`"; + $tTable = "`civicrm_tag-" . $value . "`"; + + if ($useAllTagTypes[2]) { + $this->_tables[$etTable] = + $this->_whereTables[$etTable] = + " LEFT JOIN civicrm_entity_tag {$etTable} ON ( {$etTable}.entity_id = contact_a.id) + LEFT JOIN civicrm_tag {$tTable} ON ( {$etTable}.tag_id = {$tTable}.id )"; + + // search tag in cases + $etCaseTable = "`civicrm_entity_case_tag-" . $value . "`"; + $tCaseTable = "`civicrm_case_tag-" . $value . "`"; + $this->_tables[$etCaseTable] = + $this->_whereTables[$etCaseTable] = + " LEFT JOIN civicrm_case_contact ON civicrm_case_contact.contact_id = contact_a.id + LEFT JOIN civicrm_case + ON (civicrm_case_contact.case_id = civicrm_case.id + AND civicrm_case.is_deleted = 0 ) + LEFT JOIN civicrm_entity_tag {$etCaseTable} ON ( {$etCaseTable}.entity_table = 'civicrm_case' AND {$etCaseTable}.entity_id = civicrm_case.id ) + LEFT JOIN civicrm_tag {$tCaseTable} ON ( {$etCaseTable}.tag_id = {$tCaseTable}.id )"; + // search tag in activities + $etActTable = "`civicrm_entity_act_tag-" . $value . "`"; + $tActTable = "`civicrm_act_tag-" . $value . "`"; + $this->_tables[$etActTable] = + $this->_whereTables[$etActTable] = + " LEFT JOIN civicrm_activity_target + ON ( civicrm_activity_target.target_contact_id = contact_a.id ) + LEFT JOIN civicrm_activity + ON ( civicrm_activity.id = civicrm_activity_target.activity_id + AND civicrm_activity.is_deleted = 0 AND civicrm_activity.is_current_revision = 1 ) + LEFT JOIN civicrm_entity_tag as {$etActTable} ON ( {$etActTable}.entity_table = 'civicrm_activity' AND {$etActTable}.entity_id = civicrm_activity.id ) + LEFT JOIN civicrm_tag {$tActTable} ON ( {$etActTable}.tag_id = {$tActTable}.id )"; + + $this->_where[$grouping][] = "({$tTable}.name $op '". $value . "' OR {$tCaseTable}.name $op '". $value . "' OR {$tActTable}.name $op '". $value . "')"; + $this->_qill[$grouping][] = ts('Tag '.$tagTypesText[2].' %1 ', array( 1 => $op)) . ' ' . $value; + } else { + $etTable = "`civicrm_entity_tag-" . $value . "`"; + $tTable = "`civicrm_tag-" . $value . "`"; + $this->_tables[$etTable] = $this->_whereTables[$etTable] = " LEFT JOIN civicrm_entity_tag {$etTable} ON ( {$etTable}.entity_id = contact_a.id AND + {$etTable}.entity_table = 'civicrm_contact' ) + LEFT JOIN civicrm_tag {$tTable} ON ( {$etTable}.tag_id = {$tTable}.id ) "; + + $this->_where[$grouping][] = self::buildClause("{$tTable}.name", $op, $value, 'String'); + $this->_qill[$grouping][] = ts('Tagged %1', array(1 => $op)) . ' ' . $value; + } + } + + /** + * where / qill clause for tag + * + * @return void + * @access public + */ + function tag(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $tagNames = CRM_Core_PseudoConstant::tag(); + if (is_array($value)) { + if (count($value) > 1) { + $this->_useDistinct = TRUE; + } + foreach ($value as $id => $dontCare) { + $names[] = CRM_Utils_Array::value($id, $tagNames); + } + $names = implode(' ' . ts('or') . ' ', $names); + $value = implode(',', array_keys($value)); + } + else { + $names = CRM_Utils_Array::value($value, $tagNames); + } + + + $useAllTagTypes = $this->getWhereValues('all_tag_types', $grouping); + $tagTypesText = $this->getWhereValues('tag_types_text', $grouping); + + $etTable = "`civicrm_entity_tag-" . $value . "`"; + + if ($useAllTagTypes[2]) { + $this->_tables[$etTable] = + $this->_whereTables[$etTable] = + " LEFT JOIN civicrm_entity_tag {$etTable} ON ( {$etTable}.entity_id = contact_a.id AND {$etTable}.entity_table = 'civicrm_contact') "; + + // search tag in cases + $etCaseTable = "`civicrm_entity_case_tag-" . $value . "`"; + $this->_tables[$etCaseTable] = + $this->_whereTables[$etCaseTable] = + " LEFT JOIN civicrm_case_contact ON civicrm_case_contact.contact_id = contact_a.id + LEFT JOIN civicrm_case + ON (civicrm_case_contact.case_id = civicrm_case.id + AND civicrm_case.is_deleted = 0 ) + LEFT JOIN civicrm_entity_tag {$etCaseTable} ON ( {$etCaseTable}.entity_table = 'civicrm_case' AND {$etCaseTable}.entity_id = civicrm_case.id ) "; + // search tag in activities + $etActTable = "`civicrm_entity_act_tag-" . $value . "`"; + $this->_tables[$etActTable] = + $this->_whereTables[$etActTable] = + " LEFT JOIN civicrm_activity_target + ON ( civicrm_activity_target.target_contact_id = contact_a.id ) + LEFT JOIN civicrm_activity + ON ( civicrm_activity.id = civicrm_activity_target.activity_id + AND civicrm_activity.is_deleted = 0 AND civicrm_activity.is_current_revision = 1 ) + LEFT JOIN civicrm_entity_tag as {$etActTable} ON ( {$etActTable}.entity_table = 'civicrm_activity' AND {$etActTable}.entity_id = civicrm_activity.id ) "; + + // CRM-10338 + if ( in_array( $op, array( 'IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY' ) ) ) { + $this->_where[$grouping][] = "({$etTable}.tag_id $op OR {$etCaseTable}.tag_id $op OR {$etActTable}.tag_id $op)"; + } + else { + $this->_where[$grouping][] = "({$etTable}.tag_id $op (". $value . ") OR {$etCaseTable}.tag_id $op (". $value . ") OR {$etActTable}.tag_id $op (". $value . "))"; + } + $this->_qill[$grouping][] = ts('Tag %1 '.$tagTypesText[2], array( 1 => $op)) . ' ' . $names; + } else { + $this->_tables[$etTable] = + $this->_whereTables[$etTable] = + " LEFT JOIN civicrm_entity_tag {$etTable} ON ( {$etTable}.entity_id = contact_a.id AND {$etTable}.entity_table = 'civicrm_contact') "; + + // CRM-10338 + if ( in_array( $op, array( 'IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY' ) ) ) { + // this converts IS (NOT)? EMPTY to IS (NOT)? NULL + $op = str_replace('EMPTY', 'NULL', $op); + $this->_where[$grouping][] = "{$etTable}.tag_id $op"; + } + else { + $this->_where[$grouping][] = "{$etTable}.tag_id $op (" . $value . ')'; + } + $this->_qill[$grouping][] = ts('Tagged %1', array( 1 => $op)) . ' ' . $names; + } + + } + + /** + * where/qill clause for notes + * + * @return void + * @access public + */ + function notes(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $noteOptionValues = $this->getWhereValues('note_option', $grouping); + $noteOption = CRM_Utils_Array::value('2', $noteOptionValues, '6'); + $noteOption = ($name == 'note_body') ? 2 : (($name == 'note_subject') ? 3 : $noteOption); + + $this->_useDistinct = TRUE; + + $this->_tables['civicrm_note'] = + $this->_whereTables['civicrm_note'] = + " LEFT JOIN civicrm_note ON ( civicrm_note.entity_table = 'civicrm_contact' AND contact_a.id = civicrm_note.entity_id ) "; + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + $n = trim($value); + $value = $strtolower(CRM_Core_DAO::escapeString($n)); + if ($wildcard || $op == 'LIKE') { + if (strpos($value, '%') === FALSE) { + $value = "%$value%"; + } + $op = 'LIKE'; + } + elseif ($op == 'IS NULL' || $op == 'IS NOT NULL') { + $value = NULL; + } + + $label = NULL; + $clauses = array(); + if ( $noteOption % 2 == 0 ) { + $clauses[] = self::buildClause('civicrm_note.note', $op, $value, 'String'); + $label = ts('Note: Body Only'); + } + if ( $noteOption % 3 == 0 ) { + $clauses[] = self::buildClause('civicrm_note.subject', $op, $value, 'String'); + $label = $label ? ts('Note: Body and Subject') : ts('Note: Subject Only'); + } + $this->_where[$grouping][] = "( " . implode(' OR ', $clauses) . " )"; + $this->_qill[$grouping][] = $label . " $op - '$n'"; + } + + function nameNullOrEmptyOp($name, $op, $grouping) { + switch ( $op ) { + case 'IS NULL': + case 'IS NOT NULL': + $this->_where[$grouping][] = "contact_a.$name $op"; + $this->_qill[$grouping][] = ts('Name') . ' ' . $op; + return true; + + case 'IS EMPTY': + $this->_where[$grouping][] = "(contact_a.$name IS NULL OR contact_a.$name = '')"; + $this->_qill[$grouping][] = ts('Name') . ' ' . $op; + return true; + + case 'IS NOT EMPTY': + $this->_where[$grouping][] = "(contact_a.$name IS NOT NULL AND contact_a.$name <> '')"; + $this->_qill[$grouping][] = ts('Name') . ' ' . $op; + return true; + + default: + return false; + } + } + + /** + * where / qill clause for sort_name + * + * @return void + * @access public + */ + function sortName(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + // handle IS NULL / IS NOT NULL / IS EMPTY / IS NOT EMPTY + if ( $this->nameNullOrEmptyOp( $name, $op, $grouping ) ) { + return; + } + + $newName = $name; + $name = trim($value); + + if (empty($name)) { + return; + } + + $config = CRM_Core_Config::singleton(); + + $sub = array(); + + //By default, $sub elements should be joined together with OR statements (don't change this variable). + $subGlue = ' OR '; + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + + if (substr($name, 0, 1) == '"' && + substr($name, -1, 1) == '"' + ) { + //If name is encased in double quotes, the value should be taken to be the string in entirety and the + $value = substr($name, 1, -1); + $value = $strtolower(CRM_Core_DAO::escapeString($value)); + $wc = ($newName == 'sort_name') ? 'LOWER(contact_a.sort_name)' : 'LOWER(contact_a.display_name)'; + $sub[] = " ( $wc = '$value' ) "; + if ($config->includeEmailInName) { + $sub[] = " ( civicrm_email.email = '$value' ) "; + } + } + elseif (strpos($name, ',') !== FALSE) { + // if we have a comma in the string, search for the entire string + $value = $strtolower(CRM_Core_DAO::escapeString($name)); + if ($wildcard) { + if ($config->includeWildCardInName) { + $value = "'%$value%'"; + } + else { + $value = "'$value%'"; + } + $op = 'LIKE'; + } + else { + $value = "'$value'"; + } + if ($newName == 'sort_name') { + $wc = self::caseImportant($op) ? "LOWER(contact_a.sort_name)" : "contact_a.sort_name"; + } + else { + $wc = self::caseImportant($op) ? "LOWER(contact_a.display_name)" : "contact_a.display_name"; + } + $sub[] = " ( $wc $op $value )"; + if ($config->includeNickNameInName) { + $wc = self::caseImportant($op) ? "LOWER(contact_a.nick_name)" : "contact_a.nick_name"; + $sub[] = " ( $wc $op $value )"; + } + if ($config->includeEmailInName) { + $sub[] = " ( civicrm_email.email $op $value ) "; + } + } + else { + // the string should be treated as a series of keywords to be matched with match ANY OR + // match ALL depending on Civi config settings (see CiviAdmin) + + // The Civi configuration setting can be overridden if the string *starts* with the case + // insenstive strings 'AND:' or 'OR:'TO THINK ABOUT: what happens when someone searches + // for the following "AND: 'a string in quotes'"? - probably nothing - it would make the + // AND OR variable reduntant because there is only one search string? + + // Check to see if the $subGlue is overridden in the search text + if (strtolower(substr($name, 0, 4)) == 'and:') { + $name = substr($name, 4); + $subGlue = ' AND '; + } + if (strtolower(substr($name, 0, 3)) == 'or:') { + $name = substr($name, 3); + $subGlue = ' OR '; + } + + $firstChar = substr($name, 0, 1); + $lastChar = substr($name, -1, 1); + $quotes = array("'", '"'); + if ((strlen($name) > 2) && in_array($firstChar, $quotes) && + in_array($lastChar, $quotes) + ) { + $name = substr($name, 1); + $name = substr($name, 0, -1); + $pieces = array($name); + } + else { + $pieces = explode(' ', $name); + } + foreach ($pieces as $piece) { + $value = $strtolower(CRM_Core_DAO::escapeString(trim($piece))); + if (strlen($value)) { + // Added If as a sanitization - without it, when you do an OR search, any string with + // double spaces (i.e. " ") or that has a space after the keyword (e.g. "OR: ") will + // return all contacts because it will include a condition similar to "OR contact + // name LIKE '%'". It might be better to replace this with array_filter. + $fieldsub = array(); + if ($wildcard) { + if ($config->includeWildCardInName) { + $value = "'%$value%'"; + } + else { + $value = "'$value%'"; + } + $op = 'LIKE'; + } + else { + $value = "'$value'"; + } + if ($newName == 'sort_name') { + $wc = self::caseImportant($op) ? "LOWER(contact_a.sort_name)" : "contact_a.sort_name"; + } + else { + $wc = self::caseImportant($op) ? "LOWER(contact_a.display_name)" : "contact_a.display_name"; + } + $fieldsub[] = " ( $wc $op $value )"; + if ($config->includeNickNameInName) { + $wc = self::caseImportant($op) ? "LOWER(contact_a.nick_name)" : "contact_a.nick_name"; + $fieldsub[] = " ( $wc $op $value )"; + } + if ($config->includeEmailInName) { + $fieldsub[] = " ( civicrm_email.email $op $value ) "; + } + $sub[] = ' ( ' . implode(' OR ', $fieldsub) . ' ) '; + // I seperated the glueing in two. The first stage should always be OR because we are searching for matches in *ANY* of these fields + } + } + } + + $sub = ' ( ' . implode($subGlue, $sub) . ' ) '; + + $this->_where[$grouping][] = $sub; + if ($config->includeEmailInName) { + $this->_tables['civicrm_email'] = $this->_whereTables['civicrm_email'] = 1; + $this->_qill[$grouping][] = ts('Name or Email ') . "$op - '$name'"; + } + else { + $this->_qill[$grouping][] = ts('Name like') . " - '$name'"; + } + } + + /** + * where / qill clause for email + * + * @return void + * @access public + */ + function email(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $n = trim($value); + if ($n) { + $config = CRM_Core_Config::singleton(); + + if (substr($n, 0, 1) == '"' && + substr($n, -1, 1) == '"' + ) { + $n = substr($n, 1, -1); + $value = strtolower(CRM_Core_DAO::escapeString($n)); + $value = "'$value'"; + $op = '='; + } + else { + $value = strtolower($n); + if ($wildcard) { + if (strpos($value, '%') === FALSE) { + $value = "%{$value}%"; + } + $op = 'LIKE'; + } + } + $this->_qill[$grouping][] = ts('Email') . " $op '$n'"; + $this->_where[$grouping][] = self::buildClause('civicrm_email.email', $op, $value, 'String'); + } + else { + $this->_qill[$grouping][] = ts('Email') . " $op "; + $this->_where[$grouping][] = self::buildClause('civicrm_email.email', $op, NULL, 'String'); + } + + $this->_tables['civicrm_email'] = $this->_whereTables['civicrm_email'] = 1; + } + + /** + * where / qill clause for phone number + * + * @return void + * @access public + */ + function phone_numeric(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + // Strip non-numeric characters + $number = preg_replace('/[^\d]/', '', $value); + if ($number) { + $this->_qill[$grouping][] = ts('Phone number contains') . " $number"; + $this->_where[$grouping][] = self::buildClause('civicrm_phone.phone_numeric', 'LIKE', "%$number%", 'String'); + $this->_tables['civicrm_phone'] = $this->_whereTables['civicrm_phone'] = 1; + } + } + + /** + * where / qill clause for phone type/location + * + * @return void + * @access public + */ + function phone_option_group($values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + $option = $name == 'phone_phone_type_id' ? 'phoneType' : 'locationType'; + $options = CRM_Core_PseudoConstant::$option(); + $optionName = $options[$value]; + $this->_qill[$grouping][] = ts('Phone') . ' ' . ($name == 'phone_phone_type_id' ? ts('type') : ('location')) . " $op $optionName"; + $this->_where[$grouping][] = self::buildClause('civicrm_phone.' . substr($name, 6), $op, $value, 'Integer'); + $this->_tables['civicrm_phone'] = $this->_whereTables['civicrm_phone'] = 1; + } + + /** + * where / qill clause for street_address + * + * @return void + * @access public + */ + function street_address(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (!$op) { + $op = 'LIKE'; + } + + $n = trim($value); + + if ($n) { + $value = strtolower($n); + if (strpos($value, '%') === FALSE) { + // only add wild card if not there + $value = "%{$value}%"; + } + $op = 'LIKE'; + $this->_where[$grouping][] = self::buildClause('LOWER(civicrm_address.street_address)', $op, $value, 'String'); + $this->_qill[$grouping][] = ts('Street') . " $op '$n'"; + } + else { + $this->_where[$grouping][] = self::buildClause('civicrm_address.street_address', $op, NULL, 'String'); + $this->_qill[$grouping][] = ts('Street') . " $op "; + } + + $this->_tables['civicrm_address'] = $this->_whereTables['civicrm_address'] = 1; + } + + /** + * where / qill clause for street_unit + * + * @return void + * @access public + */ + function street_number(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (!$op) { + $op = '='; + } + + $n = trim($value); + + if (strtolower($n) == 'odd') { + $this->_where[$grouping][] = " ( civicrm_address.street_number % 2 = 1 )"; + $this->_qill[$grouping][] = ts('Street Number is odd'); + } + elseif (strtolower($n) == 'even') { + $this->_where[$grouping][] = " ( civicrm_address.street_number % 2 = 0 )"; + $this->_qill[$grouping][] = ts('Street Number is even'); + } + else { + $value = strtolower($n); + + $this->_where[$grouping][] = self::buildClause('LOWER(civicrm_address.street_number)', $op, $value, 'String'); + $this->_qill[$grouping][] = ts('Street Number') . " $op '$n'"; + } + + $this->_tables['civicrm_address'] = $this->_whereTables['civicrm_address'] = 1; + } + + /** + * where / qill clause for sorting by character + * + * @return void + * @access public + */ + function sortByCharacter(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $name = trim($value); + $cond = " contact_a.sort_name LIKE '" . strtolower(CRM_Core_DAO::escapeWildCardString($name)) . "%'"; + $this->_where[$grouping][] = $cond; + $this->_qill[$grouping][] = ts('Showing only Contacts starting with: \'%1\'', array(1 => $name)); + } + + /** + * where / qill clause for including contact ids + * + * @return void + * @access public + */ + function includeContactIDs() { + if (!$this->_includeContactIds || empty($this->_params)) { + return; + } + + $contactIds = array(); + foreach ($this->_params as $id => $values) { + if (substr($values[0], 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $contactIds[] = substr($values[0], CRM_Core_Form::CB_PREFIX_LEN); + } + } + if (!empty($contactIds)) { + $this->_where[0][] = " ( contact_a.id IN (" . implode(',', $contactIds) . " ) ) "; + } + } + + /** + * where / qill clause for postal code + * + * @return void + * @access public + */ + function postalCode(&$values) { + // skip if the fields dont have anything to do with postal_code + if (!CRM_Utils_Array::value('postal_code', $this->_fields)) { + return; + } + + list($name, $op, $value, $grouping, $wildcard) = $values; + + // Handle numeric postal code range searches properly by casting the column as numeric + if (is_numeric($value)) { + $field = 'ROUND(civicrm_address.postal_code)'; + $val = CRM_Utils_Type::escape($value, 'Integer'); + } + else { + $field = 'civicrm_address.postal_code'; + $val = CRM_Utils_Type::escape($value, 'String'); + } + + $this->_tables['civicrm_address'] = $this->_whereTables['civicrm_address'] = 1; + + if ($name == 'postal_code') { + $this->_where[$grouping][] = self::buildClause($field, $op, $val, 'String'); + $this->_qill[$grouping][] = ts('Postal code') . " {$op} {$value}"; + } + elseif ($name == 'postal_code_low') { + $this->_where[$grouping][] = " ( $field >= '$val' ) "; + $this->_qill[$grouping][] = ts('Postal code greater than or equal to \'%1\'', array(1 => $value)); + } + elseif ($name == 'postal_code_high') { + $this->_where[$grouping][] = " ( $field <= '$val' ) "; + $this->_qill[$grouping][] = ts('Postal code less than or equal to \'%1\'', array(1 => $value)); + } + } + + /** + * where / qill clause for location type + * + * @return void + * @access public + */ + function locationType(&$values, $status = NULL) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (is_array($value)) { + $this->_where[$grouping][] = 'civicrm_address.location_type_id IN (' . implode(',', array_keys($value)) . ')'; + $this->_tables['civicrm_address'] = 1; + $this->_whereTables['civicrm_address'] = 1; + + $locationType = CRM_Core_PseudoConstant::locationType(); + $names = array(); + foreach (array_keys($value) as $id) { + $names[] = $locationType[$id]; + } + + $this->_primaryLocation = FALSE; + + if (!$status) { + $this->_qill[$grouping][] = ts('Location Type') . ' - ' . implode(' ' . ts('or') . ' ', $names); + } + else { + return implode(' ' . ts('or') . ' ', $names); + } + } + } + + function country(&$values, $fromStateProvince = TRUE) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (!$fromStateProvince) { + $stateValues = $this->getWhereValues('state_province', $grouping); + if (!empty($stateValues)) { + // return back to caller if there are state province values + // since that handles this case + return; + } + } + + $countryClause = $countryQill = NULL; + if ( + $values && + !empty($value) + ) { + $this->_tables['civicrm_country'] = 1; + $this->_whereTables['civicrm_country'] = 1; + + $countries = CRM_Core_PseudoConstant::country(); + if (is_numeric($value)) { + $countryClause = self::buildClause( + 'civicrm_country.id', + $op, + $value, + 'Positive' + ); + $countryName = $countries[(int ) $value]; + } + + else { + $intValues = self::parseSearchBuilderString($value); + if ($intValues && ($op == 'IN' || $op == 'NOT IN')) { + $countryClause = self::buildClause( + 'civicrm_country.id', + $op, + $intValues, + 'Positive' + ); + $countryNames = array(); + foreach ($intValues as $v) { + $countryNames[] = $countries[$v]; + } + $countryName = implode(',', $countryNames); + } + else { + $wc = ($op != 'LIKE') ? "LOWER('civicrm_country.name')" : 'civicrm_country.name'; + $countryClause = self::buildClause( + 'civicrm_country.name', + $op, + $value, + 'String' + ); + $countryName = $value; + } + } + $countryQill = ts('Country') . " {$op} '$countryName'"; + + if (!$fromStateProvince) { + $this->_where[$grouping][] = $countryClause; + $this->_qill[$grouping][] = $countryQill; + } + } + + if ($fromStateProvince) { + if (!empty($countryClause)) { + return array( + $countryClause, + " ...AND... " . $countryQill, + ); + } + else { + return array(NULL, NULL); + } + } + } + + /** + * where / qill clause for county (if present) + * + * @return void + * @access public + */ + function county(&$values, $status = null) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (! is_array($value)) { + // force the county to be an array + $value = array($value); + } + + // check if the values are ids OR names of the counties + $inputFormat = 'id'; + foreach ($value as $v) { + if (!is_numeric($v)) { + $inputFormat = 'name'; + break; + } + } + $names = array(); + if ($inputFormat == 'id') { + $clause = 'civicrm_county.id IN (' . implode(',', $value) . ')'; + + $county = CRM_Core_PseudoConstant::county(); + foreach ($value as $id) { + $names[] = CRM_Utils_Array::value($id, $county); + } + } + else { + $inputClause = array(); + foreach ($value as $name) { + $name = trim($name); + $inputClause[] = "'$name'"; + } + $clause = 'civicrm_county.name IN (' . implode(',', $inputClause) . ')'; + $names = $value; + } + $this->_tables['civicrm_county'] = 1; + $this->_whereTables['civicrm_county'] = 1; + + $this->_where[$grouping][] = $clause; + if (! $status) { + $this->_qill[$grouping][] = ts('County') . ' - ' . implode(' ' . ts('or') . ' ', $names); + } else { + return implode(' ' . ts('or') . ' ', $names); + } + } + + /** + * where / qill clause for state/province AND country (if present) + * + * @return void + * @access public + */ + function stateProvince(&$values, $status = NULL) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + // quick escape for IS NULL + if ( in_array( $op, array( 'IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY' ) ) ) { + $value = NULL; + } + else if (!is_array($value)) { + // force the state to be an array + // check if its in the mapper format! + $values = self::parseSearchBuilderString($value); + if (is_array($values)) { + $value = $values; + } + else { + $value = array($value); + } + } + + // check if the values are ids OR names of the states + $inputFormat = 'id'; + if ($value) { + foreach ($value as $v) { + if (!is_numeric($v)) { + $inputFormat = 'name'; + break; + } + } + } + + $names = array(); + if ($op == '=') { + $op = 'IN'; + } + else if ($op == '!=') { + $op = 'NOT IN'; + } + else { + // this converts IS (NOT)? EMPTY to IS (NOT)? NULL + $op = str_replace('EMPTY', 'NULL', $op); + } + if ( in_array( $op, array( 'IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY' ) ) ) { + $stateClause = "civicrm_state_province.id $op"; + } + else if ($inputFormat == 'id') { + if ($op != 'NOT IN') { + $op = 'IN'; + } + $stateClause = "civicrm_state_province.id $op (" . implode(',', $value) . ')'; + + $stateProvince = CRM_Core_PseudoConstant::stateProvince(); + foreach ($value as $id) { + $names[] = CRM_Utils_Array::value($id, $stateProvince); + } + } + else { + $inputClause = array(); + foreach ($value as $name) { + $name = trim($name); + $inputClause[] = "'$name'"; + } + $stateClause = "civicrm_state_province.name $op (" . implode(',', $inputClause) . ')'; + $names = $value; + } + + $this->_tables['civicrm_state_province'] = 1; + $this->_whereTables['civicrm_state_province'] = 1; + + $countryValues = $this->getWhereValues('country', $grouping); + list($countryClause, $countryQill) = $this->country($countryValues, TRUE); + + if ($countryClause) { + $clause = "( $stateClause AND $countryClause )"; + } + else { + $clause = $stateClause; + } + + $this->_where[$grouping][] = $clause; + if (!$status) { + $this->_qill[$grouping][] = ts('State/Province') . " $op " . implode(' ' . ts('or') . ' ', $names) . $countryQill; + } + else { + return implode(' ' . ts('or') . ' ', $names) . $countryQill;; + } + } + + /** + * where / qill clause for change log + * + * @return void + * @access public + */ + function changeLog(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $targetName = $this->getWhereValues('changed_by', $grouping); + if (!$targetName) { + return; + } + + $name = trim($targetName[2]); + $name = strtolower(CRM_Core_DAO::escapeString($name)); + $name = $targetName[4] ? "%$name%" : $name; + $this->_where[$grouping][] = "contact_b_log.sort_name LIKE '%$name%'"; + $this->_tables['civicrm_log'] = $this->_whereTables['civicrm_log'] = 1; + $this->_qill[$grouping][] = ts('Changed by') . ": $name"; + } + + function modifiedDates($values) { + $this->_useDistinct = TRUE; + foreach (array_keys($this->_params) as $id) { + if ($this->_params[$id][0] == 'log_date') { + if ($this->_params[$id][2] == 1) { + $fieldTitle = 'Added Date'; + } + elseif ($this->_params[$id][2] == 2) { + $fieldTitle = 'Modified Date'; + } + } + } + + $this->dateQueryBuilder($values, + 'civicrm_log', 'log_date', 'modified_date', $fieldTitle + ); + } + + function demographics(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (($name == 'birth_date_low') || ($name == 'birth_date_high')) { + + $this->dateQueryBuilder($values, + 'contact_a', 'birth_date', 'birth_date', ts('Birth Date') + ); + } + elseif (($name == 'deceased_date_low') || ($name == 'deceased_date_high')) { + + $this->dateQueryBuilder($values, + 'contact_a', 'deceased_date', 'deceased_date', ts('Deceased Date') + ); + } + + self::$_openedPanes[ts('Demographics')] = TRUE; + } + + function privacy(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + //fixed for profile search listing CRM-4633 + if (strpbrk($value, "[")) { + $value = "'{$value}'"; + $op = "!{$op}"; + $this->_where[$grouping][] = "contact_a.{$name} $op $value"; + } + else { + $this->_where[$grouping][] = "contact_a.{$name} $op $value"; + } + $field = CRM_Utils_Array::value($name, $this->_fields); + $title = $field ? $field['title'] : $name; + $this->_qill[$grouping][] = "$title $op $value"; + } + + function privacyOptions($values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (empty($value) || + !is_array($value) + ) { + continue; + } + + // get the operator and toggle values + $opValues = $this->getWhereValues('privacy_operator', $grouping); + $operator = 'OR'; + if ($opValues && + strtolower($opValues[2] == 'AND') + ) { + $operator = 'AND'; + } + + $toggleValues = $this->getWhereValues('privacy_toggle', $grouping); + $compareOP = '!='; + if ($toggleValues && + $toggleValues[2] == 2 + ) { + $compareOP = '='; + } + + $clauses = array(); + $qill = array(); + foreach ($value as $dontCare => $pOption) { + $clauses[] = " ( contact_a.{$pOption} $compareOP 1 ) "; + $field = CRM_Utils_Array::value($pOption, $this->_fields); + $title = $field ? $field['title'] : $pOption; + $qill[] = " $title $compareOP 1 "; + } + + $this->_where[$grouping][] = '( ' . implode($operator, $clauses) . ' )'; + $this->_qill[$grouping][] = implode($operator, $qill); + } + + function preferredCommunication(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $pref = array(); + if (!is_array($value)) { + $v = array(); + $value = trim($value, ' ()'); + if (strpos($value, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) { + $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + } + else { + $v = explode(",", $value); + } + + foreach ($v as $item) { + if ($item) { + $pref[] = $item; + } + } + } + else { + foreach ($value as $key => $checked) { + if ($checked) { + $pref[] = $key; + } + } + } + + $commPref = CRM_Core_PseudoConstant::pcm(); + + $sqlValue = array(); + $sql = "contact_a.preferred_communication_method"; + foreach ($pref as $val) { + $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $val . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; + $showValue[] = $commPref[$val]; + } + $this->_where[$grouping][] = "( " . implode(' OR ', $sqlValue) . " )"; + $this->_qill[$grouping][] = ts('Preferred Communication Method') . " $op " . implode(' ' . ts('or') . ' ', $showValue); + } + + /** + * where / qill clause for task / task status + * + * @return void + * @access public + */ + function task(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $targetName = $this->getWhereValues('task_id', $grouping); + if (!$targetName) { + return; + } + + $taskID = CRM_Utils_Type::escape($targetName[2], 'Integer'); + $clause = "civicrm_task_status.task_id = $taskID "; + + $statusID = NULL; + if ($value) { + $statusID = CRM_Utils_Type::escape($value, 'Integer'); + $clause .= " AND civicrm_task_status.status_id = $statusID"; + } + + $this->_where[$grouping][] = "civicrm_task_status.task_id = $taskID AND civicrm_task_status.status_id = $statusID"; + $this->_tables['civicrm_task_status'] = $this->_whereTables['civicrm_task_status'] = 1; + + $taskSelect = CRM_Core_PseudoConstant::tasks(); + $this->_qill[$grouping][] = ts('Task') . ": $taskSelect[$taskID]"; + if ($statusID) { + $statusSelect = CRM_Core_OptionGroup::values('task_status'); + $this->_qill[$grouping][] = ts('Task Status') . ": $statusSelect[$statusID]"; + } + } + + /** + * where / qill clause for relationship + * + * @return void + * @access public + */ + function relationship(&$values) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + // also get values array for relation_target_name + // for relatinship search we always do wildcard + $targetName = $this->getWhereValues('relation_target_name', $grouping); + $relStatus = $this->getWhereValues('relation_status', $grouping); + $targetGroup = $this->getWhereValues('relation_target_group', $grouping); + $start = $this->getWhereValues('relation_date_low', $grouping); + $end = $this->getWhereValues('relation_date_high', $grouping); + + $nameClause = $name = NULL; + if ($targetName) { + $name = trim($targetName[2]); + if (substr($name, 0, 1) == '"' && + substr($name, -1, 1) == '"' + ) { + $name = substr($name, 1, -1); + $name = strtolower(CRM_Core_DAO::escapeString($name)); + $nameClause = "= '$name'"; + } + else { + $name = strtolower(CRM_Core_DAO::escapeString($name)); + $nameClause = "LIKE '%{$name}%'"; + } + } + + $rel = explode('_', $value); + + self::$_relType = $rel[1]; + + $params = array('id' => $rel[0]); + $rTypeValues = array(); + $rType = CRM_Contact_BAO_RelationshipType::retrieve($params, $rTypeValues); + if (!$rType) { + return; + } + + if ($rTypeValues['name_a_b'] == $rTypeValues['name_b_a']) { + self::$_relType = 'reciprocal'; + } + + if ($nameClause) { + $this->_where[$grouping][] = "( contact_b.sort_name $nameClause AND contact_b.id != contact_a.id )"; + } + + $relTypeInd = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, 'null', NULL, 'Individual'); + $relTypeOrg = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, 'null', NULL, 'Organization'); + $relTypeHou = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, 'null', NULL, 'Household'); + $allRelationshipType = array(); + $allRelationshipType = array_merge($relTypeInd, $relTypeOrg); + $allRelationshipType = array_merge($allRelationshipType, $relTypeHou); + + if ($nameClause || !$targetGroup) { + $this->_qill[$grouping][] = "$allRelationshipType[$value] $name"; + } + + + //check to see if the target contact is in specified group + if ($targetGroup) { + //add contacts from static groups + $this->_tables['civicrm_relationship_group_contact'] = + $this->_whereTables['civicrm_relationship_group_contact'] = + " LEFT JOIN civicrm_group_contact civicrm_relationship_group_contact ON civicrm_relationship_group_contact.contact_id = contact_b.id"; + $groupWhere[] = "( civicrm_relationship_group_contact.group_id IN (" . implode(",", $targetGroup[2]) . ") )"; + + //add contacts from saved searches + $ssWhere = $this->addGroupContactCache($targetGroup[2], "civicrm_relationship_group_contact_cache", "contact_b"); + + //set the group where clause + if ($ssWhere) { + $groupWhere[] = "( " . $ssWhere . " )"; + } + $this->_where[$grouping][] = "( " . implode(" OR ", $groupWhere) . " )"; + + //Get the names of the target groups for the qill + $groupNames = &CRM_Core_PseudoConstant::group(); + $qillNames = array(); + foreach ($targetGroup[2] as $groupId) { + if (array_key_exists($groupId, $groupNames)) { + $qillNames[] = $groupNames[$groupId]; + } + } + $this->_qill[$grouping][] = "$allRelationshipType[$value] ( " . implode(", ", $qillNames) . " )"; + } + + + //check for active, inactive and all relation status + if ($relStatus[2] == 0) { + $this->_where[$grouping][] = "( +civicrm_relationship.is_active = 1 AND +( civicrm_relationship.end_date IS NULL OR civicrm_relationship.end_date >= CURDATE() ) AND +( civicrm_relationship.start_date IS NULL OR civicrm_relationship.start_date <= CURDATE() ) +)"; + $this->_qill[$grouping][] = ts('Relationship - Active and Current'); + } + elseif ($relStatus[2] == 1) { + $this->_where[$grouping][] = "( +civicrm_relationship.is_active = 0 OR +civicrm_relationship.end_date < CURDATE() OR +civicrm_relationship.start_date > CURDATE() +)"; + $this->_qill[$grouping][] = ts('Relationship - Inactive or not Current'); + } + + // Search by dates + if ($start || $end) { + foreach (array('start' => '>=', 'end' => '<=') as $d => $op) { + if (!empty(${$d}[2])) { + $date = date('Ymd', strtotime(${$d}[2])); + $this->_where[$grouping][] = "civicrm_relationship.{$d}_date $op $date"; + $this->_qill[$grouping][] = ($d == 'end' ? ts('Relationship Ended by') : ts('Relationship Started On or After')) . " " . CRM_Utils_Date::customFormat($date); + } + } + } + + $this->_where[$grouping][] = 'civicrm_relationship.relationship_type_id = ' . $rel[0]; + $this->_tables['civicrm_relationship'] = $this->_whereTables['civicrm_relationship'] = 1; + $this->_useDistinct = TRUE; + } + + /** + * default set of return properties + * + * @return void + * @access public + */ + static function &defaultReturnProperties($mode = 1) { + if (!isset(self::$_defaultReturnProperties)) { + self::$_defaultReturnProperties = array(); + } + + if (!isset(self::$_defaultReturnProperties[$mode])) { + // add activity return properties + if ($mode & CRM_Contact_BAO_Query::MODE_ACTIVITY) { + self::$_defaultReturnProperties[$mode] = CRM_Activity_BAO_Query::defaultReturnProperties($mode, FALSE); + } + else { + self::$_defaultReturnProperties[$mode] = CRM_Core_Component::defaultReturnProperties($mode, FALSE); + } + + if (empty(self::$_defaultReturnProperties[$mode])) { + self::$_defaultReturnProperties[$mode] = array( + 'home_URL' => 1, + 'image_URL' => 1, + 'legal_identifier' => 1, + 'external_identifier' => 1, + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'sort_name' => 1, + 'display_name' => 1, + 'preferred_mail_format' => 1, + 'nick_name' => 1, + 'first_name' => 1, + 'middle_name' => 1, + 'last_name' => 1, + 'individual_prefix' => 1, + 'individual_suffix' => 1, + 'birth_date' => 1, + 'gender' => 1, + 'street_address' => 1, + 'supplemental_address_1' => 1, + 'supplemental_address_2' => 1, + 'city' => 1, + 'postal_code' => 1, + 'postal_code_suffix' => 1, + 'state_province' => 1, + 'country' => 1, + 'world_region' => 1, + 'geo_code_1' => 1, + 'geo_code_2' => 1, + 'email' => 1, + 'on_hold' => 1, + 'phone' => 1, + 'im' => 1, + 'household_name' => 1, + 'organization_name' => 1, + 'deceased_date' => 1, + 'is_deceased' => 1, + 'job_title' => 1, + 'legal_name' => 1, + 'sic_code' => 1, + 'current_employer' => 1, + // FIXME: should we use defaultHierReturnProperties() for the below? + 'do_not_email' => 1, + 'do_not_mail' => 1, + 'do_not_sms' => 1, + 'do_not_phone' => 1, + 'do_not_trade' => 1, + 'is_opt_out' => 1, + 'contact_is_deleted' => 1, + ); + } + } + return self::$_defaultReturnProperties[$mode]; + } + + /** + * get primary condition for a sql clause + * + * @param int $value + * + * @return void + * @access public + */ + static function getPrimaryCondition($value) { + if (is_numeric($value)) { + $value = (int ) $value; + return ($value == 1) ? 'is_primary = 1' : 'is_primary = 0'; + } + return NULL; + } + + /** + * wrapper for a simple search query + * + * @param array $params + * @param array $returnProperties + * @param bolean $count + * + * @return void + * @access public + */ + static function getQuery($params = NULL, $returnProperties = NULL, $count = FALSE) { + $query = new CRM_Contact_BAO_Query($params, $returnProperties); + list($select, $from, $where, $having) = $query->query(); + + return "$select $from $where $having"; + } + + /** + * These are stub comments as this function needs more explanation - particularly in terms of how it + * relates to $this->searchQuery and why it replicates rather than calles $this->searchQuery. + * + * This function was originally written as a wrapper for the api query but is called from multiple places + * in the core code directly so the name is misleading. This function does not use the searchQuery function + * but it is unclear as to whehter that is historical or there is a reason + * CRM-11290 led to the permissioning action being extracted from searchQuery & shared with this function + * + * @param array $params + * @param array $returnProperties + * @param string $sort + * @param int $offset + * @param int $row_count + * @params bool $smartGroupCache ?? update smart group cache? + * @param bool $count return count obnly + * @param bool $skipPermissions Should permissions be ignored or should the logged in user's permissions be applied + * + * @return void + * @access public + */ + static function apiQuery( + $params = NULL, + $returnProperties = NULL, + $fields = NULL, + $sort = NULL, + $offset = 0, + $row_count = 25, + $smartGroupCache = TRUE, + $count = FALSE, + $skipPermissions = True + ) { + + $query = new CRM_Contact_BAO_Query( + $params, $returnProperties, + NULL, TRUE, FALSE, 1, + $skipPermissions, + TRUE, $smartGroupCache + ); + + //this should add a check for view deleted if permissions are enabled + if ($skipPermissions){ + $query->_skipDeleteClause = TRUE; + } + $query->generatePermissionClause(FALSE, $count); + list($select, $from, $where, $having) = $query->query($count); + + $options = $query->_options; + if(!empty($query->_permissionWhereClause)){ + if (empty($where)) { + $where = "WHERE $query->_permissionWhereClause"; + } + else { + $where = "$where AND $query->_permissionWhereClause"; + } + } + + $sql = "$select $from $where $having"; + + // add group by + if ($query->_useGroupBy) { + $sql .= ' GROUP BY contact_a.id'; + } + if (!empty($sort)) { + $sql .= " ORDER BY $sort "; + } + if ($row_count > 0 && $offset >= 0) { + $sql .= " LIMIT $offset, $row_count "; + } + + $dao = CRM_Core_DAO::executeQuery($sql); + + $values = array(); + while ($dao->fetch()) { + if ($count) { + $noRows = $dao->rowCount; + $dao->free(); + return array($noRows,NULL); + } + $values[$dao->contact_id] = $query->store($dao); + } + $dao->free(); + return array($values, $options); + } + + /** + * create and query the db for an contact search + * + * @param int $offset the offset for the query + * @param int $rowCount the number of rows to return + * @param string $sort the order by string + * @param boolean $count is this a count only query ? + * @param boolean $includeContactIds should we include contact ids? + * @param boolean $sortByChar if true returns the distinct array of first characters for search results + * @param boolean $groupContacts if true, return only the contact ids + * @param boolean $returnQuery should we return the query as a string + * @param string $additionalWhereClause if the caller wants to further restrict the search (used for components) + * @param string $additionalFromClause should be clause with proper joins, effective to reduce where clause load. + * + * @return CRM_Contact_DAO_Contact + * @access public + */ + function searchQuery( + $offset = 0, $rowCount = 0, $sort = NULL, + $count = FALSE, $includeContactIds = FALSE, + $sortByChar = FALSE, $groupContacts = FALSE, + $returnQuery = FALSE, + $additionalWhereClause = NULL, $sortOrder = NULL, + $additionalFromClause = NULL, $skipOrderAndLimit = FALSE + ) { + + if ($includeContactIds) { + $this->_includeContactIds = TRUE; + $this->_whereClause = $this->whereClause(); + } + + // hack for now, add permission only if we are in search + // FIXME: we should actually filter out deleted contacts (unless requested to do the opposite) + $permission = ' ( 1 ) '; + $onlyDeleted = FALSE; + $onlyDeleted = in_array(array('deleted_contacts', '=', '1', '0', '0'), $this->_params); + + // if we’re explicitely looking for a certain contact’s contribs, events, etc. + // and that contact happens to be deleted, set $onlyDeleted to true + foreach ($this->_params as $values) { + $name = CRM_Utils_Array::value(0, $values); + $op = CRM_Utils_Array::value(1, $values); + $value = CRM_Utils_Array::value(2, $values); + if ($name == 'contact_id' and $op == '=') { + if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'is_deleted')) { + $onlyDeleted = TRUE; + } + break; + } + } + $this->generatePermissionClause($onlyDeleted, $count); + + list($select, $from, $where, $having) = $this->query($count, $sortByChar, $groupContacts); + + //additional from clause should be w/ proper joins. + if ($additionalFromClause) { + $from .= "\n" . $additionalFromClause; + } + + if (empty($where)) { + $where = "WHERE $this->_permissionWhereClause"; + } + else { + $where = "$where AND $this->_permissionWhereClause"; + } + + if ($additionalWhereClause) { + $where = $where . ' AND ' . $additionalWhereClause; + } + + // building the query string + $groupBy = NULL; + if (!$count) { + if (isset($this->_groupByComponentClause)) { + $groupBy = $this->_groupByComponentClause; + } + elseif ($this->_useGroupBy) { + $groupBy = ' GROUP BY contact_a.id'; + } + } + if ($this->_mode & CRM_Contact_BAO_Query::MODE_ACTIVITY && (!$count)) { + $groupBy = 'GROUP BY civicrm_activity.id '; + } + + $order = $orderBy = $limit = ''; + if (!$count) { + $config = CRM_Core_Config::singleton(); + if ($config->includeOrderByClause || + isset($this->_distinctComponentClause) + ) { + if ($sort) { + if (is_string($sort)) { + $orderBy = $sort; + } + else { + $orderBy = trim($sort->orderBy()); + } + if (!empty($orderBy)) { + // this is special case while searching for + // changelog CRM-1718 + if (preg_match('/sort_name/i', $orderBy)) { + $orderBy = str_replace('sort_name', 'contact_a.sort_name', $orderBy); + } + + $order = " ORDER BY $orderBy"; + + if ($sortOrder) { + $order .= " $sortOrder"; + } + + // always add contact_a.id to the ORDER clause + // so the order is deterministic + if (strpos('contact_a.id', $order) === FALSE) { + $order .= ", contact_a.id"; + } + } + } + elseif ($sortByChar) { + $order = " ORDER BY UPPER(LEFT(contact_a.sort_name, 1)) asc"; + } + else { + $order = " ORDER BY contact_a.sort_name asc, contact_a.id"; + } + } + + $doOpt = TRUE; + // hack for order clause + if ($order) { + $fieldStr = trim(str_replace('ORDER BY', '', $order)); + $fieldOrder = explode(' ', $fieldStr); + $field = $fieldOrder[0]; + + if ($field) { + switch ($field) { + case 'sort_name': + case 'id': + case 'contact_a.sort_name': + case 'contact_a.id': + break; + + case 'city': + case 'postal_code': + $this->_whereTables["civicrm_address"] = 1; + $order = str_replace($field, "civicrm_address.{$field}", $order); + break; + + case 'country': + case 'state_province': + $this->_whereTables["civicrm_{$field}"] = 1; + $order = str_replace($field, "civicrm_{$field}.name", $order); + break; + + case 'email': + $this->_whereTables["civicrm_email"] = 1; + $order = str_replace($field, "civicrm_email.{$field}", $order); + break; + + default: + $doOpt = FALSE; + } + } + } + + + if ($rowCount > 0 && $offset >= 0) { + $limit = " LIMIT $offset, $rowCount "; + + // ok here is a first hack at an optimization, lets get all the contact ids + // that are restricted and we'll then do the final clause with it + // CRM-5954 + if (isset($this->_distinctComponentClause)) { + if (strpos($this->_distinctComponentClause, 'DISTINCT') == FALSE) { + $limitSelect = "SELECT DISTINCT {$this->_distinctComponentClause}"; + } + else { + $limitSelect = "SELECT {$this->_distinctComponentClause}"; + } + } + else { + $limitSelect = 'SELECT DISTINCT contact_a.id as id'; + } + + if ($doOpt) { + $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, + $this->_primaryLocation, $this->_mode + ); + + if ($additionalFromClause) { + $this->_simpleFromClause .= "\n" . $additionalFromClause; + } + // if we are doing a transform, do it here + // CRM-7969 + $having = NULL; + if ($this->_displayRelationshipType) { + $this->filterRelatedContacts($this->_simpleFromClause, $where, $having); + } + + $limitQuery = "$limitSelect {$this->_simpleFromClause} $where $groupBy $order $limit"; + $limitDAO = CRM_Core_DAO::executeQuery($limitQuery); + $limitIDs = array(); + while ($limitDAO->fetch()) { + if ($limitDAO->id) { + $limitIDs[] = $limitDAO->id; + } + } + if (empty($limitIDs)) { + $limitClause = ' AND ( 0 ) '; + } + else { + if (isset($this->_distinctComponentClause)) { + $limitClause = " AND {$this->_distinctComponentClause} IN ( "; + } + else { + $limitClause = ' AND contact_a.id IN ( '; + } + $limitClause .= implode(',', $limitIDs) . ' ) '; + } + $where .= $limitClause; + // reset limit clause since we already restrict what records we want + $limit = NULL; + } + } + } + + // if we are doing a transform, do it here + // use the $from, $where and $having to get the contact ID + if ($this->_displayRelationshipType) { + $this->filterRelatedContacts($from, $where, $having); + } + + if ($skipOrderAndLimit) { + $query = "$select $from $where $having $groupBy"; + } + else { + $query = "$select $from $where $having $groupBy $order $limit"; + } + + if ($returnQuery) { + return $query; + } + + if ($count) { + return CRM_Core_DAO::singleValueQuery($query); + } + + //crm_core_error::debug('$query', $query); //exit; + + $dao = CRM_Core_DAO::executeQuery($query); + if ($groupContacts) { + $ids = array(); + while ($dao->fetch()) { + $ids[] = $dao->id; + } + return implode(',', $ids); + } + + return $dao; + } + + /** + * Populate $this->_permissionWhereClause with permission related clause and update other + * query related properties. + * + * Function calls ACL permission class and hooks to filter the query appropriately + * + * Note that these 2 params were in the code when extracted from another function + * and a second round extraction would be to make them properties of the class + * + * @param bool $onlyDeleted Only get deleted contacts + * @param bool $count Return Count only + * + * @return null + */ + function generatePermissionClause($onlyDeleted = FALSE, $count = FALSE) { + if (!$this->_skipPermission) { + $this->_permissionWhereClause = CRM_ACL_API::whereClause( + CRM_Core_Permission::VIEW, + $this->_tables, + $this->_whereTables, + NULL, + $onlyDeleted, + $this->_skipDeleteClause + ); + + // regenerate fromClause since permission might have added tables + if ($this->_permissionWhereClause) { + //fix for row count in qill (in contribute/membership find) + if (!$count) { + $this->_useDistinct = TRUE; + } + $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode); + $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode); + } + } + else { + // add delete clause if needed even if we are skipping permission + // CRM-7639 + if (!$this->_skipDeleteClause) { + if (CRM_Core_Permission::check('access deleted contacts') and $onlyDeleted) { + $this->_permissionWhereClause = '(contact_a.is_deleted)'; + } + else { + // CRM-6181 + $this->_permissionWhereClause = '(contact_a.is_deleted = 0)'; + } + } + } + } + + function setSkipPermission($val) { + $this->_skipPermission = $val; + } + + function &summaryContribution($context = NULL) { + list($select, $from, $where, $having) = $this->query(TRUE); + + // hack $select + $select = " +SELECT COUNT( civicrm_contribution.total_amount ) as total_count, + SUM( civicrm_contribution.total_amount ) as total_amount, + AVG( civicrm_contribution.total_amount ) as total_avg, + civicrm_contribution.currency as currency"; + + // make sure contribution is completed - CRM-4989 + $where .= " AND civicrm_contribution.contribution_status_id = 1 "; + if ($context == 'search') { + $where .= " AND contact_a.is_deleted = 0 "; + } + + $summary = array(); + $summary['total'] = array(); + $summary['total']['count'] = $summary['total']['amount'] = $summary['total']['avg'] = "n/a"; + + $query = "$select $from $where GROUP BY currency"; + $params = array(); + + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $summary['total']['count'] = 0; + $summary['total']['amount'] = $summary['total']['avg'] = array(); + while ($dao->fetch()) { + $summary['total']['count'] += $dao->total_count; + $summary['total']['amount'][] = CRM_Utils_Money::format($dao->total_amount, $dao->currency); + $summary['total']['avg'][] = CRM_Utils_Money::format($dao->total_avg, $dao->currency); + } + if (!empty($summary['total']['amount'])) { + $summary['total']['amount'] = implode(', ', $summary['total']['amount']); + $summary['total']['avg'] = implode(', ', $summary['total']['avg']); + } + else { + $summary['total']['amount'] = $summary['total']['avg'] = 0; + } + + // hack $select + $select = " +SELECT COUNT( civicrm_contribution.total_amount ) as cancel_count, + SUM( civicrm_contribution.total_amount ) as cancel_amount, + AVG( civicrm_contribution.total_amount ) as cancel_avg, + civicrm_contribution.currency as currency"; + + $where .= " AND civicrm_contribution.cancel_date IS NOT NULL "; + if ($context == 'search') { + $where .= " AND contact_a.is_deleted = 0 "; + } + + $query = "$select $from $where GROUP BY currency"; + $dao = CRM_Core_DAO::executeQuery($query, $params); + + if ($dao->N <= 1) { + if ($dao->fetch()) { + $summary['cancel']['count'] = $dao->cancel_count; + $summary['cancel']['amount'] = $dao->cancel_amount; + $summary['cancel']['avg'] = $dao->cancel_avg; + } + } + else { + $summary['cancel']['count'] = 0; + $summary['cancel']['amount'] = $summary['cancel']['avg'] = array(); + while ($dao->fetch()) { + $summary['cancel']['count'] += $dao->cancel_count; + $summary['cancel']['amount'][] = CRM_Utils_Money::format($dao->cancel_amount, $dao->currency); + $summary['cancel']['avg'][] = CRM_Utils_Money::format($dao->cancel_avg, $dao->currency); + } + $summary['cancel']['amount'] = implode(', ', $summary['cancel']['amount']); + $summary['cancel']['avg'] = implode(', ', $summary['cancel']['avg']); + } + + return $summary; + } + + /** + * getter for the qill object + * + * @return string + * @access public + */ + function qill() { + return $this->_qill; + } + + /** + * default set of return default hier return properties + * + * @return void + * @access public + */ + static function &defaultHierReturnProperties() { + if (!isset(self::$_defaultHierReturnProperties)) { + self::$_defaultHierReturnProperties = array( + 'home_URL' => 1, + 'image_URL' => 1, + 'legal_identifier' => 1, + 'external_identifier' => 1, + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'sort_name' => 1, + 'display_name' => 1, + 'nick_name' => 1, + 'first_name' => 1, + 'middle_name' => 1, + 'last_name' => 1, + 'individual_prefix' => 1, + 'individual_suffix' => 1, + 'email_greeting' => 1, + 'postal_greeting' => 1, + 'addressee' => 1, + 'birth_date' => 1, + 'gender' => 1, + 'preferred_communication_method' => 1, + 'do_not_phone' => 1, + 'do_not_email' => 1, + 'do_not_mail' => 1, + 'do_not_sms' => 1, + 'do_not_trade' => 1, + 'location' => + array( + '1' => array('location_type' => 1, + 'street_address' => 1, + 'city' => 1, + 'state_province' => 1, + 'postal_code' => 1, + 'postal_code_suffix' => 1, + 'country' => 1, + 'phone-Phone' => 1, + 'phone-Mobile' => 1, + 'phone-Fax' => 1, + 'phone-1' => 1, + 'phone-2' => 1, + 'phone-3' => 1, + 'im-1' => 1, + 'im-2' => 1, + 'im-3' => 1, + 'email-1' => 1, + 'email-2' => 1, + 'email-3' => 1, + ), + '2' => array( + 'location_type' => 1, + 'street_address' => 1, + 'city' => 1, + 'state_province' => 1, + 'postal_code' => 1, + 'postal_code_suffix' => 1, + 'country' => 1, + 'phone-Phone' => 1, + 'phone-Mobile' => 1, + 'phone-1' => 1, + 'phone-2' => 1, + 'phone-3' => 1, + 'im-1' => 1, + 'im-2' => 1, + 'im-3' => 1, + 'email-1' => 1, + 'email-2' => 1, + 'email-3' => 1, + ), + ), + ); + } + return self::$_defaultHierReturnProperties; + } + + function dateQueryBuilder( + &$values, $tableName, $fieldName, + $dbFieldName, $fieldTitle, + $appendTimeStamp = TRUE + ) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if (!$value) { + return; + } + + if ($name == "{$fieldName}_low" || + $name == "{$fieldName}_high" + ) { + if (isset($this->_rangeCache[$fieldName])) { + return; + } + $this->_rangeCache[$fieldName] = 1; + + $secondOP = $secondPhrase = $secondValue = $secondDate = $secondDateFormat = NULL; + + if ($name == $fieldName . '_low') { + $firstOP = '>='; + $firstPhrase = 'greater than or equal to'; + $firstDate = CRM_Utils_Date::processDate($value); + + $secondValues = $this->getWhereValues("{$fieldName}_high", $grouping); + if (!empty($secondValues) && + $secondValues[2] + ) { + $secondOP = '<='; + $secondPhrase = 'less than or equal to'; + $secondValue = $secondValues[2]; + + if ($appendTimeStamp && + strlen($secondValue) == 10 + ) { + $secondValue .= ' 23:59:59'; + } + $secondDate = CRM_Utils_Date::processDate($secondValue); + } + } + elseif ($name == $fieldName . '_high') { + $firstOP = '<='; + $firstPhrase = 'less than or equal to'; + + if ($appendTimeStamp && + strlen($value) == 10 + ) { + $value .= ' 23:59:59'; + } + $firstDate = CRM_Utils_Date::processDate($value); + + $secondValues = $this->getWhereValues("{$fieldName}_low", $grouping); + if (!empty($secondValues) && + $secondValues[2] + ) { + $secondOP = '>='; + $secondPhrase = 'greater than or equal to'; + $secondValue = $secondValues[2]; + $secondDate = CRM_Utils_Date::processDate($secondValue); + } + } + + if (!$appendTimeStamp) { + $firstDate = substr($firstDate, 0, 8); + } + $firstDateFormat = CRM_Utils_Date::customFormat($firstDate); + + if ($secondDate) { + if (!$appendTimeStamp) { + $secondDate = substr($secondDate, 0, 8); + } + $secondDateFormat = CRM_Utils_Date::customFormat($secondDate); + } + + $this->_tables[$tableName] = $this->_whereTables[$tableName] = 1; + if ($secondDate) { + $this->_where[$grouping][] = " +( {$tableName}.{$dbFieldName} $firstOP '$firstDate' ) AND +( {$tableName}.{$dbFieldName} $secondOP '$secondDate' ) +"; + $this->_qill[$grouping][] = "$fieldTitle - $firstPhrase \"$firstDateFormat\" " . ts('AND') . " $secondPhrase \"$secondDateFormat\""; + } + else { + $this->_where[$grouping][] = "{$tableName}.{$dbFieldName} $firstOP '$firstDate'"; + $this->_qill[$grouping][] = "$fieldTitle - $firstPhrase \"$firstDateFormat\""; + } + } + + if ($name == $fieldName) { + // $op = '='; + $phrase = $op; + + $date = CRM_Utils_Date::processDate($value); + + if (!$appendTimeStamp) { + $date = substr($date, 0, 8); + } + + $format = CRM_Utils_Date::customFormat($date); + + if ($date) { + $this->_where[$grouping][] = "{$tableName}.{$dbFieldName} $op '$date'"; + } + else { + $this->_where[$grouping][] = "{$tableName}.{$dbFieldName} $op"; + } + $this->_tables[$tableName] = $this->_whereTables[$tableName] = 1; + $this->_qill[$grouping][] = "$fieldTitle - $phrase \"$format\""; + } + + if ( + $tableName == 'civicrm_log' && + $fieldTitle == 'Added Date' + ) { + //CRM-6903 --hack to check modified date of first record. + //as added date means first modified date of object. + $addedDateQuery = 'select id from civicrm_log group by entity_id order by id'; + $this->_where[$grouping][] = "civicrm_log.id IN ( {$addedDateQuery} )"; + } + } + + function numberRangeBuilder(&$values, + $tableName, $fieldName, + $dbFieldName, $fieldTitle, + $options = NULL + ) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + if ($name == "{$fieldName}_low" || + $name == "{$fieldName}_high" + ) { + if (isset($this->_rangeCache[$fieldName])) { + return; + } + $this->_rangeCache[$fieldName] = 1; + + $secondOP = $secondPhrase = $secondValue = NULL; + + if ($name == "{$fieldName}_low") { + $firstOP = '>='; + $firstPhrase = 'greater than'; + + $secondValues = $this->getWhereValues("{$fieldName}_high", $grouping); + if (!empty($secondValues)) { + $secondOP = '<='; + $secondPhrase = 'less than'; + $secondValue = $secondValues[2]; + } + } + else { + $firstOP = '<='; + $firstPhrase = 'less than'; + + $secondValues = $this->getWhereValues("{$fieldName}_low", $grouping); + if (!empty($secondValues)) { + $secondOP = '>='; + $secondPhrase = 'greater than'; + $secondValue = $secondValues[2]; + } + } + + if ($secondOP) { + $this->_where[$grouping][] = " +( {$tableName}.{$dbFieldName} $firstOP {$value} ) AND +( {$tableName}.{$dbFieldName} $secondOP {$secondValue} ) +"; + $displayValue = $options ? $options[$value] : $value; + $secondDisplayValue = $options ? $options[$secondValue] : $secondValue; + + $this->_qill[$grouping][] = "$fieldTitle - $firstPhrase \"$displayValue\" " . ts('AND') . " $secondPhrase \"$secondDisplayValue\""; + } + else { + $this->_where[$grouping][] = "{$tableName}.{$dbFieldName} $firstOP {$value}"; + $displayValue = $options ? $options[$value] : $value; + $this->_qill[$grouping][] = "$fieldTitle - $firstPhrase \"$displayValue\""; + } + $this->_tables[$tableName] = $this->_whereTables[$tableName] = 1; + + return; + } + + if ($name == $fieldName) { + $op = '='; + $phrase = '='; + + $this->_where[$grouping][] = "{$tableName}.{$dbFieldName} $op {$value}"; + + $this->_tables[$tableName] = $this->_whereTables[$tableName] = 1; + $displayValue = $options ? $options[$value] : $value; + $this->_qill[$grouping][] = "$fieldTitle - $phrase \"$displayValue\""; + } + + return; + } + + /** + * Given the field name, operator, value & its data type + * builds the where Clause for the query + * used for handling 'IS NULL'/'IS NOT NULL' operators + * + * @param string $field fieldname + * @param string $op operator + * @param string $value value + * @param string $dataType data type of the field + * + * @return where clause for the query + * @access public + */ + static function buildClause($field, $op, $value = NULL, $dataType = NULL) { + $op = trim($op); + $clause = "$field $op"; + + switch ($op) { + case 'IS NULL': + case 'IS NOT NULL': + return $clause; + + case 'IS EMPTY': + $clause = " ( $field IS NULL OR $field = '' ) "; + return $clause; + + case 'IS NOT EMPTY': + $clause = " ( $field IS NOT NULL AND $field <> '' ) "; + return $clause; + + case 'IN': + case 'NOT IN': + if (isset($dataType)) { + if (is_array($value)) { + $values = $value; + } + else { + $value = CRM_Utils_Type::escape($value, "String"); + $values = explode(',', CRM_Utils_Array::value(0, explode(')', CRM_Utils_Array::value(1, explode('(', $value))))); + } + // supporting multiple values in IN clause + $val = array(); + foreach ($values as $v) { + $v = trim($v); + $val[] = "'" . CRM_Utils_Type::escape($v, $dataType) . "'"; + } + $value = "(" . implode($val, ",") . ")"; + } + return "$clause $value"; + + default: + if (empty($dataType)) { + $dataType = 'String'; + } + + $value = CRM_Utils_Type::escape($value, $dataType); + + // if we dont have a dataType we should assume + if ($dataType == 'String') { + $value = "'" . strtolower($value) . "'"; + } + return "$clause $value"; + } + } + + function openedSearchPanes($reset = FALSE) { + if (!$reset || empty($this->_whereTables)) { + return self::$_openedPanes; + } + + // pane name to table mapper + $panesMapper = array( + ts('Contributions') => 'civicrm_contribution', + ts('Memberships') => 'civicrm_membership', + ts('Events') => 'civicrm_participant', + ts('Relationships') => 'civicrm_relationship', + ts('Activities') => 'civicrm_activity', + ts('Pledges') => 'civicrm_pledge', + ts('Cases') => 'civicrm_case', + ts('Grants') => 'civicrm_grant', + ts('Address Fields') => 'civicrm_address', + ts('Notes') => 'civicrm_note', + ts('Change Log') => 'civicrm_log', + ts('Mailings') => 'civicrm_mailing_event_queue', + ); + + foreach (array_keys($this->_whereTables) as $table) { + if ($panName = array_search($table, $panesMapper)) { + self::$_openedPanes[$panName] = TRUE; + } + } + + return self::$_openedPanes; + } + + function setOperator($operator) { + $validOperators = array('AND', 'OR'); + if (!in_array($operator, $validOperators)) { + $operator = 'AND'; + } + $this->_operator = $operator; + } + + function getOperator() { + return $this->_operator; + } + + function filterRelatedContacts(&$from, &$where, &$having) { + static $_rTypeProcessed = NULL; + static $_rTypeFrom = NULL; + static $_rTypeWhere = NULL; + + if (!$_rTypeProcessed) { + $_rTypeProcessed = TRUE; + + // create temp table with contact ids + $tableName = CRM_Core_DAO::createTempTableName('civicrm_transform', TRUE); + $sql = "CREATE TEMPORARY TABLE $tableName ( contact_id int primary key) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql); + + $sql = " +REPLACE INTO $tableName ( contact_id ) +SELECT contact_a.id + $from + $where + $having +"; + CRM_Core_DAO::executeQuery($sql); + + $qillMessage = ts('Contacts with a Relationship Type of: '); + $rTypes = CRM_Core_PseudoConstant::relationshipType(); + + if (is_numeric($this->_displayRelationshipType)) { + $relationshipTypeLabel = $rTypes[$this->_displayRelationshipType]['label_a_b']; + $_rTypeFrom = " +INNER JOIN civicrm_relationship displayRelType ON ( displayRelType.contact_id_a = contact_a.id OR displayRelType.contact_id_b = contact_a.id ) +INNER JOIN $tableName transform_temp ON ( transform_temp.contact_id = displayRelType.contact_id_a OR transform_temp.contact_id = displayRelType.contact_id_b ) +"; + $_rTypeWhere = " +WHERE displayRelType.relationship_type_id = {$this->_displayRelationshipType} +AND displayRelType.is_active = 1 +"; + } + else { + list($relType, $dirOne, $dirTwo) = explode('_', $this->_displayRelationshipType); + if ($dirOne == 'a') { + $relationshipTypeLabel = $rTypes[$relType]['label_a_b']; + $_rTypeFrom .= " +INNER JOIN civicrm_relationship displayRelType ON ( displayRelType.contact_id_a = contact_a.id ) +INNER JOIN $tableName transform_temp ON ( transform_temp.contact_id = displayRelType.contact_id_b ) +"; + } + else { + $relationshipTypeLabel = $rTypes[$relType]['label_b_a']; + $_rTypeFrom .= " +INNER JOIN civicrm_relationship displayRelType ON ( displayRelType.contact_id_b = contact_a.id ) +INNER JOIN $tableName transform_temp ON ( transform_temp.contact_id = displayRelType.contact_id_a ) +"; + } + $_rTypeWhere = " +WHERE displayRelType.relationship_type_id = $relType +AND displayRelType.is_active = 1 +"; + } + + $this->_qill[0][] = $qillMessage . "'" . $relationshipTypeLabel . "'"; + } + + if (strpos($from, $_rTypeFrom) === FALSE) { + // lets replace all the INNER JOIN's in the $from so we dont exclude other data + // this happens when we have an event_type in the quert (CRM-7969) + $from = str_replace("INNER JOIN", "LEFT JOIN", $from); + $from .= $_rTypeFrom; + $where = $_rTypeWhere; + } + + $having = NULL; + } + + static function caseImportant( $op ) { + return + in_array($op, array('LIKE', 'IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY')) ? FALSE : TRUE; + } + + static function componentPresent( &$returnProperties, $prefix ) { + foreach ($returnProperties as $name => $dontCare ) { + if (substr($name, 0, strlen($prefix)) == $prefix) { + return TRUE; + } + } + return FALSE; + } + + /** + * Builds the necessary structures for all fields that are similar to option value lookups + * + * @param $name string the name of the field + * @param $op string the sql operator, this function should handle ALL SQL operators + * @param $value any string / integer / array depends on the operator and whos calling the query builder + * @param $grouping int the index where to place the where clause + * @param $selectValue array the key value pairs for this element. This allows us to use this function for things besides option-value pairs + * @param $field array an array that contains various properties of the field identified by $name + * @param $label string The label for this field element + * @param $dataType string The data type for this element + * + * @return void adds the where clause and qill to the query object + */ + function optionValueQuery( + $name, + $op, + $value, + $grouping, + $selectValues, + $field, + $label, + $dataType = 'String' + ) { + $qill = $value; + if (is_numeric($value)) { + $qill = $value = $selectValues[(int ) $value]; + } + elseif ($op == 'IN' || $op == 'NOT IN') { + $values = self::parseSearchBuilderString($value); + if (is_array($values)) { + $newValues = array(); + foreach ($values as $v) { + $newValues[] = $selectValues[(int ) $v]; + } + $value = $newValues; + $qill = implode(', ', $value); + } + } + $wc = self::caseImportant($op) ? "LOWER({$field['where']})" : "{$field['where']}"; + $this->_where[$grouping][] = self::buildClause($wc, $op, $value, $dataType); + $this->_qill[$grouping][] = $label . " $op '$qill'"; + } + + /** function to check and explode a user defined numeric string into an array + * this was the protocol used by search builder in the old old days before we had + * super nice js widgets to do the hard work + * + * @param string the string to check + * @param string the dataType we should check for the values, default integer + * + * @return FALSE if string does not match the patter + * array of numeric values if string does match the pattern + * @static + */ + static function parseSearchBuilderString($string, $dataType = 'Integer') { + $string = trim($string); + if (substr($string, 0, 1) != '(' || substr($string, -1, 1) != ')') { + Return FALSE; + } + + $string = substr($string, 1, -1); + $values = explode(',', $string); + if (empty($values)) { + return FALSE; + } + + $returnValues = array(); + foreach ($values as $v) { + if ($dataType == 'Integer' && ! is_numeric($v)) { + return FALSE; + } + else if ($dataType == 'String' && ! is_string($v)) { + return FALSE; + } + $returnValues[] = trim($v); + } + + if (empty($returnValues)) { + return FALSE; + } + + return $returnValues; + } +} + diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php new file mode 100644 index 0000000000..ca17b63b20 --- /dev/null +++ b/CRM/Contact/BAO/Relationship.php @@ -0,0 +1,1518 @@ + $value) { + $errors = ''; + // check if the relationship is valid between contacts. + // step 1: check if the relationship is valid if not valid skip and keep the count + // step 2: check the if two contacts already have a relationship if yes skip and keep the count + // step 3: if valid relationship then add the relation and keep the count + + // step 1 + $errors = self::checkValidRelationship($params, $ids, $key); + if ($errors) { + $invalid++; + continue; + } + + if ( + self::checkDuplicateRelationship( + $params, + CRM_Utils_Array::value('contact', $ids), + // step 2 + $key + ) + ) { + $duplicate++; + continue; + } + + $relationship = self::add($params, $ids, $key); + $relationshipIds[] = $relationship->id; + $valid++; + } + // editing the relationship + } + else { + // check for duplicate relationship + + if ( + self::checkDuplicateRelationship( + $params, + CRM_Utils_Array::value('contact', $ids), + $ids['contactTarget'], + $relationshipId + ) + ) { + $duplicate++; + return array($valid, $invalid, $duplicate); + } + + $validContacts = TRUE; + //validate contacts in update mode also. + if (CRM_Utils_Array::value('contact', $ids) && + CRM_Utils_Array::value('contactTarget', $ids) + ) { + if (self::checkValidRelationship($params, $ids, $ids['contactTarget'])) { + $validContacts = FALSE; + $invalid++; + } + } + if ($validContacts) { + // editing an existing relationship + $relationship = self::add($params, $ids, $ids['contactTarget']); + $relationshipIds[] = $relationship->id; + $saved++; + } + } + + // do not add to recent items for import, CRM-4399 + if (!(CRM_Utils_Array::value('skipRecentView', $params) || $invalid || $duplicate)) { + $url = CRM_Utils_System::url('civicrm/contact/view/rel', + "action=view&reset=1&id={$relationship->id}&cid={$relationship->contact_id_a}&context=home" + ); + + + $session = CRM_Core_Session::singleton(); + $recentOther = array(); + if (($session->get('userID') == $relationship->contact_id_a) || + CRM_Contact_BAO_Contact_Permission::allow($relationship->contact_id_a, CRM_Core_Permission::EDIT) + ) { + $rType = substr(CRM_Utils_Array::value('relationship_type_id', $params), -3); + $recentOther = array( + 'editUrl' => CRM_Utils_System::url('civicrm/contact/view/rel', + "action=update&reset=1&id={$relationship->id}&cid={$relationship->contact_id_a}&rtype={$rType}&context=home" + ), + 'deleteUrl' => CRM_Utils_System::url('civicrm/contact/view/rel', + "action=delete&reset=1&id={$relationship->id}&cid={$relationship->contact_id_a}&rtype={$rType}&context=home" + ), + ); + } + + $title = CRM_Contact_BAO_Contact::displayName($relationship->contact_id_a) . ' (' . CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', + $relationship->relationship_type_id, 'label_a_b' + ) . ' ' . CRM_Contact_BAO_Contact::displayName($relationship->contact_id_b) . ')'; + + // add the recently created Relationship + CRM_Utils_Recent::add($title, + $url, + $relationship->id, + 'Relationship', + $relationship->contact_id_a, + NULL, + $recentOther + ); + } + + return array($valid, $invalid, $duplicate, $saved, $relationshipIds); + } + + /** + * This is the function that check/add if the relationship created is valid + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param integer $contactId this is contact id for adding relationship + * @param array $ids the array that holds all the db ids + * + * @return object CRM_Contact_BAO_Relationship + * @access public + * @static + */ + static function add(&$params, &$ids, $contactId) { + if (CRM_Utils_Array::value('relationship', $ids)) { + CRM_Utils_Hook::pre('edit', 'Relationship', $ids['relationship'], $params); + } + else { + CRM_Utils_Hook::pre('create', 'Relationship', NULL, $params); + } + + $relationshipTypes = CRM_Utils_Array::value('relationship_type_id', $params); + + // expolode the string with _ to get the relationship type id and to know which contact has to be inserted in + // contact_id_a and which one in contact_id_b + list($type, $first, $second) = explode('_', $relationshipTypes); + + ${'contact_' . $first} = CRM_Utils_Array::value('contact', $ids); + ${'contact_' . $second} = $contactId; + + //check if the relationship type is Head of Household then update the household's primary contact with this contact. + if ($type == 6) { + CRM_Contact_BAO_Household::updatePrimaryContact($contact_b, $contact_a); + } + + $relationship = new CRM_Contact_BAO_Relationship(); + $relationship->contact_id_b = $contact_b; + $relationship->contact_id_a = $contact_a; + $relationship->relationship_type_id = $type; + $relationship->id = CRM_Utils_Array::value('relationship', $ids); + + $dateFields = array('end_date', 'start_date'); + + foreach (self::getdefaults() as $defaultField => $defaultValue){ + if(isset($params[$defaultField])){ + if(in_array($defaultField, $dateFields)){ + $relationship->$defaultField = CRM_Utils_Date::format(CRM_Utils_Array::value($defaultField, $params)); + if(!$relationship->$defaultField){ + $relationship->$defaultField = 'NULL'; + } + } + else{ + $relationship->$defaultField = $params[$defaultField]; + } + } + elseif(empty($relationship->id)){ + $relationship->$defaultField = $defaultValue; + } + } + + $relationship->save(); + + // add custom field values + if (CRM_Utils_Array::value('custom', $params)) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_relationship', $relationship->id); + } + + $relationship->free(); + + if (CRM_Utils_Array::value('relationship', $ids)) { + CRM_Utils_Hook::post('edit', 'Relationship', $relationship->id, $relationship); + } + else { + CRM_Utils_Hook::post('create', 'Relationship', $relationship->id, $relationship); + } + + return $relationship; + } + /** + * Specifiy defaults for creating a relationship + * + * @return array $defaults array of defaults for creating relationship + * @access public + * @static + */ + static function getdefaults() { + return array( + 'is_active' => 0, + 'is_permission_a_b' => 0, + 'is_permission_b_a' => 0, + 'description' => '', + 'start_date' => 'NULL', + 'case_id' => NULL, + 'end_date' => 'NULL', + ); + } + + + /** + * Check if there is data to create the object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * @access public + * @static + */ + static function dataExists(&$params) { + // return if no data present + if (!is_array(CRM_Utils_Array::value('contact_check', $params))) { + return FALSE; + } + return TRUE; + } + + /** + * Function to get get list of relationship type based on the contact type. + * + * @param int $contactId this is the contact id of the current contact. + * @param string $strContact this value is currently ignored, keeping it there for legacy reasons + * @param string $relationshipId the id of the existing relationship if any + * @param string $contactType contact type + * @param boolean $all if true returns relationship types in both the direction + * @param string $column name/label that going to retrieve from db. + * + * + * @param string $contactSubType includes relationshiptypes between this subtype + * + * @param boolean $onlySubTypeRelationTypes if set only subtype which is passed by $contactSubType + * related relationshiptypes get return + * @access public + * @static + * + * @return array - array reference of all relationship types with context to current contact. + */ + static function getContactRelationshipType($contactId = NULL, + $contactSuffix = NULL, + $relationshipId = NULL, + $contactType = NULL, + $all = FALSE, + $column = 'label', + $biDirectional = TRUE, + $contactSubType = NULL, + $onlySubTypeRelationTypes = FALSE + ) { + $allRelationshipType = array(); + $relationshipType = array(); + $allRelationshipType = CRM_Core_PseudoConstant::relationshipType($column); + + $otherContactType = NULL; + if ($relationshipId) { + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->id = $relationshipId; + if ($relationship->find(TRUE)) { + $contact = new CRM_Contact_DAO_Contact(); + $contact->id = ($relationship->contact_id_a === $contactId) ? $relationship->contact_id_b : $relationship->contact_id_a; + + if ($contact->find(TRUE)) { + $otherContactType = $contact->contact_type; + //CRM-5125 for contact subtype specific relationshiptypes + if ($contact->contact_sub_type) { + $otherContactSubType = $contact->contact_sub_type; + } + } + } + } + + $contactSubType = array(); + if ($contactId) { + $contactType = CRM_Contact_BAO_Contact::getContactType($contactId); + $contactSubType = CRM_Contact_BAO_Contact::getContactSubType($contactId); + } + + foreach ($allRelationshipType as $key => $value) { + // the contact type is required or matches + if (((!$value['contact_type_a']) || + $value['contact_type_a'] == $contactType + ) && + // the other contact type is required or present or matches + ((!$value['contact_type_b']) || + (!$otherContactType) || + $value['contact_type_b'] == $otherContactType + ) && + (!$contactSubType || + (in_array($value['contact_sub_type_a'], $contactSubType) || + ((!$value['contact_sub_type_b'] && + !$value['contact_sub_type_a'] + ) && + !$onlySubTypeRelationTypes + ) + ) + ) + ) { + $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"]; + } + elseif (empty($value['contact_type_b'])) { + // case contact_type_b is "all contacts", CRM-9877 + $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"]; + } + + if (((!$value['contact_type_b']) || + $value['contact_type_b'] == $contactType + ) && + ((!$value['contact_type_a']) || + (!$otherContactType) || + $value['contact_type_a'] == $otherContactType + ) && + (!$contactSubType || + (in_array($value['contact_sub_type_b'], $contactSubType) || + ((!$value['contact_sub_type_a'] && + !$value['contact_sub_type_b'] + ) && + !$onlySubTypeRelationTypes + ) + ) + ) + ) { + $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"]; + } + elseif (empty($value['contact_type_a'])) { + // case contact_type_a is "all contacts", CRM-9877 + $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"]; + } + + if ($all) { + $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"]; + $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"]; + } + } + + if ($biDirectional) { + // lets clean up the data and eliminate all duplicate values + // (i.e. the relationship is bi-directional) + $relationshipType = array_unique($relationshipType); + } + + // sort the relationshipType in ascending order CRM-7736 + asort($relationshipType); + return $relationshipType; + } + + static function clearCurrentEmployer($id, $action) { + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->id = $id; + $relationship->find(TRUE); + + //to delete relationship between household and individual \ + //or between individual and orgnization + if (($action & CRM_Core_Action::DISABLE) || ($action & CRM_Core_Action::DELETE)) { + if ($relationship->relationship_type_id == 4 || $relationship->relationship_type_id == 7) { + $sharedContact = new CRM_Contact_DAO_Contact(); + $sharedContact->id = $relationship->contact_id_a; + $sharedContact->find(TRUE); + + if ($relationship->relationship_type_id == 4 && $relationship->contact_id_b == $sharedContact->employer_id) { + CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($relationship->contact_id_a); + } + } + } + return $relationship; + } + + /** + * Function to delete the relationship + * + * @param int $id relationship id + * + * @return null + * @access public + * + * @static + */ + static function del($id) { + // delete from relationship table + CRM_Utils_Hook::pre('delete', 'Relationship', $id, CRM_Core_DAO::$_nullArray); + + $relationship = self::clearCurrentEmployer($id, CRM_Core_Action::DELETE); + if (CRM_Core_Permission::access('CiviMember')) { + // create $params array which isrequired to delete memberships + // of the related contacts. + $params = array( + 'relationship_type_id' => "{$relationship->relationship_type_id}_a_b", + 'contact_check' => array($relationship->contact_id_b => 1), + ); + + $ids = array(); + // calling relatedMemberships to delete the memberships of + // related contacts. + self::relatedMemberships($relationship->contact_id_a, + $params, + $ids, + CRM_Core_Action::DELETE, + FALSE + ); + } + + $relationship->delete(); + CRM_Core_Session::setStatus(ts('Selected relationship has been deleted successfully.'), ts('Record Deleted'), 'success'); + + CRM_Utils_Hook::post('delete', 'Relationship', $relationship->id, $relationship); + + // delete the recently created Relationship + $relationshipRecent = array( + 'id' => $id, + 'type' => 'Relationship', + ); + CRM_Utils_Recent::del($relationshipRecent); + + return $relationship; + } + + /** + * Function to disable/enable the relationship + * + * @param int $id relationship id + * + * @return null + * @access public + + * @static + */ + static function disableEnableRelationship($id, $action) { + $relationship = self::clearCurrentEmployer($id, $action); + if (CRM_Core_Permission::access('CiviMember')) { + // create $params array which isrequired to delete memberships + // of the related contacts. + $params = array( + 'relationship_type_id' => "{$relationship->relationship_type_id}_a_b", + 'contact_check' => array($relationship->contact_id_b => 1), + ); + + $ids = array(); + // calling relatedMemberships to delete/add the memberships of + // related contacts. + if ($action & CRM_Core_Action::DISABLE) { + CRM_Contact_BAO_Relationship::relatedMemberships($relationship->contact_id_a, + $params, + $ids, + CRM_Core_Action::DELETE, + FALSE + ); + } + elseif ($action & CRM_Core_Action::ENABLE) { + $ids['contact'] = $relationship->contact_id_a; + CRM_Contact_BAO_Relationship::relatedMemberships($relationship->contact_id_a, + $params, + $ids, + CRM_Core_Action::ADD, + FALSE + ); + } + } + } + + /** + * Delete the object records that are associated with this contact + * + * @param int $contactId id of the contact to delete + * + * @return void + * @access public + * @static + */ + static function deleteContact($contactId) { + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->contact_id_a = $contactId; + $relationship->delete(); + + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->contact_id_b = $contactId; + $relationship->delete(); + + CRM_Contact_BAO_Household::updatePrimaryContact(NULL, $contactId); + } + + /** + * Function to get the other contact in a relationship + * + * @param int $id relationship id + * + * $returns returns the contact ids in the realtionship + * @access public + * @static + */ + static function getContactIds($id) { + $relationship = new CRM_Contact_DAO_Relationship(); + + $relationship->id = $id; + $relationship->selectAdd(); + $relationship->selectAdd('contact_id_a, contact_id_b'); + $relationship->find(TRUE); + + return $relationship; + } + + /** + * Function to check if the relationship type selected between two contacts is correct + * + * @param int $contact_a 1st contact id + * @param int $contact_b 2nd contact id + * @param int $relationshipTypeId relationship type id + * + * @return boolean true if it is valid relationship else false + * @access public + * @static + */ + static function checkRelationshipType($contact_a, $contact_b, $relationshipTypeId) { + $relationshipType = new CRM_Contact_DAO_RelationshipType(); + $relationshipType->id = $relationshipTypeId; + $relationshipType->selectAdd(); + $relationshipType->selectAdd('contact_type_a, contact_type_b, contact_sub_type_a, contact_sub_type_b'); + if ($relationshipType->find(TRUE)) { + $contact_type_a = CRM_Contact_BAO_Contact::getContactType($contact_a); + $contact_type_b = CRM_Contact_BAO_Contact::getContactType($contact_b); + + $contact_sub_type_a = CRM_Contact_BAO_Contact::getContactSubType($contact_a); + $contact_sub_type_b = CRM_Contact_BAO_Contact::getContactSubType($contact_b); + + if (((!$relationshipType->contact_type_a) || ($relationshipType->contact_type_a == $contact_type_a)) && + ((!$relationshipType->contact_type_b) || ($relationshipType->contact_type_b == $contact_type_b)) && + ((!$relationshipType->contact_sub_type_a) || (in_array($relationshipType->contact_sub_type_a, + $contact_sub_type_a + ))) && + ((!$relationshipType->contact_sub_type_b) || (in_array($relationshipType->contact_sub_type_b, + $contact_sub_type_b + ))) + ) { + return TRUE; + } + else { + return FALSE; + } + } + return FALSE; + } + + /** + * this function does the validtion for valid relationship + * + * @param array $params this array contains the values there are subitted by the form + * @param array $ids the array that holds all the db ids + * @param integer $contactId this is contact id for adding relationship + * + * @return + * @access public + * @static + */ + static function checkValidRelationship(&$params, &$ids, $contactId) { + $errors = ''; + + // get the string of relationship type + $relationshipTypes = CRM_Utils_Array::value('relationship_type_id', $params); + list($type, $first, $second) = explode('_', $relationshipTypes); + ${'contact_' . $first} = CRM_Utils_Array::value('contact', $ids); + ${'contact_' . $second} = $contactId; + // function to check if the relationship selected is correct + // i.e. employer relationship can exit between Individual and Organization (not between Individual and Individual) + if (!CRM_Contact_BAO_Relationship::checkRelationshipType($contact_a, $contact_b, $type)) { + $errors = 'Please select valid relationship between these two contacts.'; + } + return $errors; + } + + /** + * this function checks for duplicate relationship + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param integer $id this the id of the contact whom we are adding relationship + * @param integer $contactId this is contact id for adding relationship + * @param integer $relationshipId this is relationship id for the contact + * + * @return boolean true if record exists else false + * @access public + * @static + */ + static function checkDuplicateRelationship(&$params, $id, $contactId = 0, $relationshipId = 0) { + $relationshipTypeId = CRM_Utils_Array::value('relationship_type_id', $params); + list($type, $first, $second) = explode('_', $relationshipTypeId); + + $queryString = " SELECT id + FROM civicrm_relationship + WHERE relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer'); + + /* + * CRM-11792 - date fields from API are in ISO format, but this function supports date arrays + * BAO has increasingly standardised to ISO format so I believe this function should support + * ISO rather than make API format it - however, need to support array format for now to avoid breakage + * @ time of writing this function is called from Relationship::create (twice) + * CRM_BAO_Contact_Utils::clearCurrentEmployer (seemingly without dates) + * CRM_Contact_Form_Task_AddToOrganization::postProcess & + * CRM_Contact_Form_Task_AddToHousehold::postProcess + * (I don't think the last 2 support dates but not sure + */ + + $dateFields = array('end_date', 'start_date'); + foreach ($dateFields as $dateField){ + if(array_key_exists($dateField, $params)) { + if (empty($params[$dateField]) || $params[$dateField] == 'null'){ + //this is most likely coming from an api call & probably loaded from the DB to deal with some of the + //other myriad of excessive checks still in place both in the api & the create functions + $queryString .= " AND $dateField IS NULL"; + continue; + } + elseif (is_array($params[$dateField])){ + $queryString .= " AND $dateField = " . CRM_Utils_Type::escape(CRM_Utils_Date::format($params[$dateField]), 'Date'); + } + else{ + $queryString .= " AND $dateField = " . CRM_Utils_Type::escape($params[$dateField], 'Date'); + } + } + } + + $queryString .= + " AND ( ( contact_id_a = " . CRM_Utils_Type::escape($id, 'Integer') . + " AND contact_id_b = " . CRM_Utils_Type::escape($contactId, 'Integer') . + " ) OR ( contact_id_a = " . CRM_Utils_Type::escape($contactId, 'Integer') . + " AND contact_id_b = " . CRM_Utils_Type::escape($id, 'Integer') . " ) ) "; + + //if caseId is provided, include it duplicate checking. + if ($caseId = CRM_Utils_Array::value('case_id', $params)) { + $queryString .= " AND case_id = " . CRM_Utils_Type::escape($caseId, 'Integer'); + } + + if ($relationshipId) { + $queryString .= " AND id !=" . CRM_Utils_Type::escape($relationshipId, 'Integer'); + } + + $relationship = new CRM_Contact_BAO_Relationship(); + $relationship->query($queryString); + $relationship->fetch(); + $relationship->free(); + return ($relationship->id) ? TRUE : FALSE; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on success, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Relationship', $id, 'is_active', $is_active); + + // call hook + CRM_Utils_Hook::enableDisable('CRM_Contact_BAO_Relationship', $id, $is_active); + + return TRUE; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $params input parameters to find object + * @param array $values output values of the object + * @param array $ids the array that holds all the db ids + * + * @return array (reference) the values that could be potentially assigned to smarty + * @access public + * @static + */ + static function &getValues(&$params, &$values) { + if (empty($params)) { + return NULL; + } + $v = array(); + + // get the specific number of relationship or all relationships. + if (CRM_Utils_Array::value('numRelationship', $params)) { + $v['data'] = &CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'], NULL, $params['numRelationship']); + } + else { + $v['data'] = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id']); + } + + // get the total count of relationships + $v['totalCount'] = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'], NULL, NULL, TRUE); + + $values['relationship']['data'] = &$v['data']; + $values['relationship']['totalCount'] = &$v['totalCount']; + + return $v; + } + + /** + * helper function to form the sql for relationship retrieval + * + * @param int $contactId contact id + * @param int $status (check const at top of file) + * @param int $numRelationship no of relationships to display (limit) + * @param int $count get the no of relationships + * $param int $relationshipId relationship id + * @param string $direction the direction we are interested in a_b or b_a + * + * return string the query for this diretion + * @static + * @access public + */ + static function makeURLClause($contactId, $status, $numRelationship, $count, $relationshipId, $direction) { + $select = $from = $where = ''; + + $select = '( '; + if ($count) { + if ($direction == 'a_b') { + $select .= ' SELECT count(DISTINCT civicrm_relationship.id) as cnt1, 0 as cnt2 '; + } + else { + $select .= ' SELECT 0 as cnt1, count(DISTINCT civicrm_relationship.id) as cnt2 '; + } + } + else { + $select .= ' SELECT civicrm_relationship.id as civicrm_relationship_id, + civicrm_contact.sort_name as sort_name, + civicrm_contact.display_name as display_name, + civicrm_contact.job_title as job_title, + civicrm_contact.employer_id as employer_id, + civicrm_contact.organization_name as organization_name, + civicrm_address.street_address as street_address, + civicrm_address.city as city, + civicrm_address.postal_code as postal_code, + civicrm_state_province.abbreviation as state, + civicrm_country.name as country, + civicrm_email.email as email, + civicrm_phone.phone as phone, + civicrm_contact.id as civicrm_contact_id, + civicrm_contact.contact_type as contact_type, + civicrm_relationship.contact_id_b as contact_id_b, + civicrm_relationship.contact_id_a as contact_id_a, + civicrm_relationship_type.id as civicrm_relationship_type_id, + civicrm_relationship.start_date as start_date, + civicrm_relationship.end_date as end_date, + civicrm_relationship.description as description, + civicrm_relationship.is_active as is_active, + civicrm_relationship.is_permission_a_b as is_permission_a_b, + civicrm_relationship.is_permission_b_a as is_permission_b_a, + civicrm_relationship.case_id as case_id'; + + if ($direction == 'a_b') { + $select .= ', civicrm_relationship_type.label_a_b as label_a_b, + civicrm_relationship_type.label_b_a as relation '; + } + else { + $select .= ', civicrm_relationship_type.label_a_b as label_a_b, + civicrm_relationship_type.label_a_b as relation '; + } + } + + $from = " + FROM civicrm_relationship +INNER JOIN civicrm_relationship_type ON ( civicrm_relationship.relationship_type_id = civicrm_relationship_type.id ) +INNER JOIN civicrm_contact "; + if ($direction == 'a_b') { + $from .= 'ON ( civicrm_contact.id = civicrm_relationship.contact_id_a ) '; + } + else { + $from .= 'ON ( civicrm_contact.id = civicrm_relationship.contact_id_b ) '; + } + $from .= " +LEFT JOIN civicrm_address ON (civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1) +LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary = 1) +LEFT JOIN civicrm_email ON (civicrm_email.contact_id = civicrm_contact.id AND civicrm_email.is_primary = 1) +LEFT JOIN civicrm_state_province ON (civicrm_address.state_province_id = civicrm_state_province.id) +LEFT JOIN civicrm_country ON (civicrm_address.country_id = civicrm_country.id) +"; + $where = 'WHERE ( 1 )'; + if ($contactId) { + if ($direction == 'a_b') { + $where .= ' AND civicrm_relationship.contact_id_b = ' . CRM_Utils_Type::escape($contactId, 'Positive'); + } + else { + $where .= ' AND civicrm_relationship.contact_id_a = ' . CRM_Utils_Type::escape($contactId, 'Positive'); + } + } + if ($relationshipId) { + $where .= ' AND civicrm_relationship.id = ' . CRM_Utils_Type::escape($relationshipId, 'Positive'); + } + + $date = date('Y-m-d'); + if ($status == self::PAST) { + //this case for showing past relationship + $where .= ' AND civicrm_relationship.is_active = 1 '; + $where .= " AND civicrm_relationship.end_date < '" . $date . "'"; + } + elseif ($status == self::DISABLED) { + // this case for showing disabled relationship + $where .= ' AND civicrm_relationship.is_active = 0 '; + } + elseif ($status == self::CURRENT) { + //this case for showing current relationship + $where .= ' AND civicrm_relationship.is_active = 1 '; + $where .= " AND (civicrm_relationship.end_date >= '" . $date . "' OR civicrm_relationship.end_date IS NULL) "; + } + elseif ($status == self::INACTIVE) { + //this case for showing inactive relationships + $where .= " AND (civicrm_relationship.end_date < '" . $date . "'"; + $where .= ' OR civicrm_relationship.is_active = 0 )'; + } + + // CRM-6181 + $where .= ' AND civicrm_contact.is_deleted = 0'; + + if ($direction == 'a_b') { + $where .= ' ) UNION '; + } + else { + $where .= ' ) '; + } + + return array($select, $from, $where); + } + + /** + * This is the function to get the list of relationships + * + * @param int $contactId contact id + * @param int $status 1: Past 2: Disabled 3: Current + * @param int $numRelationship no of relationships to display (limit) + * @param int $count get the no of relationships + * $param int $relationshipId relationship id + * $param array $links the list of links to display + * $param int $permissionMask the permission mask to be applied for the actions + * $param boolean $permissionedContact to return only permissioned Contact + * + * return array $values relationship records + * @static + * @access public + */ + static function getRelationship($contactId = NULL, + $status = 0, $numRelationship = 0, + $count = 0, $relationshipId = 0, + $links = NULL, $permissionMask = NULL, + $permissionedContact = FALSE + ) { + $values = array(); + if (!$contactId && !$relationshipId) { + return $values; + } + + list($select1, $from1, $where1) = self::makeURLClause($contactId, $status, $numRelationship, + $count, $relationshipId, 'a_b' + ); + list($select2, $from2, $where2) = self::makeURLClause($contactId, $status, $numRelationship, + $count, $relationshipId, 'b_a' + ); + + $order = $limit = ''; + if (!$count) { + $order = ' ORDER BY civicrm_relationship_type_id, sort_name '; + + if ($numRelationship) { + $limit = " LIMIT 0, $numRelationship"; + } + } + + // building the query string + $queryString = ''; + $queryString = $select1 . $from1 . $where1 . $select2 . $from2 . $where2 . $order . $limit; + + $relationship = new CRM_Contact_DAO_Relationship(); + + $relationship->query($queryString); + $row = array(); + if ($count) { + $relationshipCount = 0; + while ($relationship->fetch()) { + $relationshipCount += $relationship->cnt1 + $relationship->cnt2; + } + return $relationshipCount; + } + else { + + $mask = NULL; + if ($status != self::INACTIVE) { + if ($links) { + $mask = array_sum(array_keys($links)); + if ($mask & CRM_Core_Action::DISABLE) { + $mask -= CRM_Core_Action::DISABLE; + } + if ($mask & CRM_Core_Action::ENABLE) { + $mask -= CRM_Core_Action::ENABLE; + } + + if ($status == self::CURRENT) { + $mask |= CRM_Core_Action::DISABLE; + } + elseif ($status == self::DISABLED) { + $mask |= CRM_Core_Action::ENABLE; + } + $mask = $mask & $permissionMask; + } + } + while ($relationship->fetch()) { + $rid = $relationship->civicrm_relationship_id; + $cid = $relationship->civicrm_contact_id; + if (($permissionedContact) && + (!CRM_Contact_BAO_Contact_Permission::relationship($cid, $contactId)) + ) { + continue; + } + $values[$rid]['id'] = $rid; + $values[$rid]['cid'] = $cid; + $values[$rid]['contact_id_a'] = $relationship->contact_id_a; + $values[$rid]['contact_id_b'] = $relationship->contact_id_b; + $values[$rid]['relationship_type_id'] = $relationship->civicrm_relationship_type_id; + $values[$rid]['relation'] = $relationship->relation; + $values[$rid]['name'] = $relationship->sort_name; + $values[$rid]['display_name'] = $relationship->display_name; + $values[$rid]['job_title'] = $relationship->job_title; + $values[$rid]['email'] = $relationship->email; + $values[$rid]['phone'] = $relationship->phone; + $values[$rid]['employer_id'] = $relationship->employer_id; + $values[$rid]['organization_name'] = $relationship->organization_name; + $values[$rid]['country'] = $relationship->country; + $values[$rid]['city'] = $relationship->city; + $values[$rid]['state'] = $relationship->state; + $values[$rid]['start_date'] = $relationship->start_date; + $values[$rid]['end_date'] = $relationship->end_date; + $values[$rid]['description'] = $relationship->description; + $values[$rid]['is_active'] = $relationship->is_active; + $values[$rid]['is_permission_a_b'] = $relationship->is_permission_a_b; + $values[$rid]['is_permission_b_a'] = $relationship->is_permission_b_a; + $values[$rid]['case_id'] = $relationship->case_id; + + if ($status) { + $values[$rid]['status'] = $status; + } + + $values[$rid]['civicrm_relationship_type_id'] = $relationship->civicrm_relationship_type_id; + + if ($relationship->contact_id_a == $contactId) { + $values[$rid]['rtype'] = 'a_b'; + } + else { + $values[$rid]['rtype'] = 'b_a'; + } + + if ($links) { + $replace = array( + 'id' => $rid, + 'rtype' => $values[$rid]['rtype'], + 'cid' => $contactId, + 'cbid' => $values[$rid]['cid'], + 'caseid' => $values[$rid]['case_id'], + 'clientid' => $contactId, + ); + + if ($status == self::INACTIVE) { + // setting links for inactive relationships + $mask = array_sum(array_keys($links)); + if (!$values[$rid]['is_active']) { + $mask -= CRM_Core_Action::DISABLE; + } + else { + $mask -= CRM_Core_Action::ENABLE; + $mask -= CRM_Core_Action::DISABLE; + } + } + + // Give access to manage case link by copying to MAX_ACTION index temporarily, depending on case permission of user. + if ($values[$rid]['case_id']) { + // Borrowed logic from CRM_Case_Page_Tab + $hasCaseAccess = FALSE; + if (CRM_Core_Permission::check('access all cases and activities')) { + $hasCaseAccess = TRUE; + } + else { + $userCases = CRM_Case_BAO_Case::getCases(FALSE); + if (array_key_exists($values[$rid]['case_id'], $userCases)) { + $hasCaseAccess = TRUE; + } + } + + if ($hasCaseAccess) { + // give access by copying to MAX_ACTION temporarily, otherwise leave at NONE which won't display + $links[CRM_Core_Action::MAX_ACTION] = $links[CRM_Core_Action::NONE]; + $links[CRM_Core_Action::MAX_ACTION]['name'] = ts('Manage Case #%1', array(1 => $values[$rid]['case_id'])); + + // Also make sure we have the right client cid since can get here from multiple relationship tabs. + if ($values[$rid]['rtype'] == 'b_a') { + $replace['clientid'] = $values[$rid]['cid']; + } + } + } + + $values[$rid]['action'] = CRM_Core_Action::formLink($links, $mask, $replace); + unset($links[CRM_Core_Action::MAX_ACTION]); + } + } + + $relationship->free(); + return $values; + } + } + + /** + * Function to get get list of relationship type based on the target contact type. + * + * @param string $targetContactType it's valid contact tpye(may be Individual , Organization , Household) + * + * @return array - array reference of all relationship types with context to current contact type . + * + */ + function getRelationType($targetContactType) { + $relationshipType = array(); + $allRelationshipType = CRM_Core_PseudoConstant::relationshipType(); + + foreach ($allRelationshipType as $key => $type) { + if ($type['contact_type_b'] == $targetContactType) { + $relationshipType[$key . '_a_b'] = $type['label_a_b']; + } + } + + return $relationshipType; + } + + /** + * Function to create / update / delete membership for related contacts. + * + * This function will create/update/delete membership for related + * contact based on 1) contact have active membership 2) that + * membership is is extedned by the same relationship type to that + * of the existing relationship. + * + * @param $contactId Int contact id + * @param $params array array of values submitted by POST + * @param $ids array array of ids + * @param $action which action called this function + * + * @static + * + */ + static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) { + // Check the end date and set the status of the relationship + // accrodingly. + $status = self::CURRENT; + + if (!empty($params['end_date'])) { + $endDate = CRM_Utils_Date::setDateDefaults(CRM_Utils_Date::format($params['end_date']), NULL, 'Ymd'); + $today = date('Ymd'); + + if ($today > $endDate) { + $status = self::PAST; + } + } + + if (($action & CRM_Core_Action::ADD) && + ($status & self::PAST) + ) { + // if relationship is PAST and action is ADD, no qustion + // of creating RELATED membership and return back to + // calling method + return; + } + + $rel = explode('_', $params['relationship_type_id']); + + $relTypeId = $rel[0]; + $relDirection = "_{$rel[1]}_{$rel[2]}"; + $targetContact = array(); + if (($action & CRM_Core_Action::ADD) || + ($action & CRM_Core_Action::DELETE) + ) { + $contact = $contactId; + $targetContact = CRM_Utils_Array::value('contact_check', $params); + } + elseif ($action & CRM_Core_Action::UPDATE) { + $contact = $ids['contact']; + $targetContact = array($ids['contactTarget'] => 1); + } + + // Build the 'values' array for + // 1. ContactA + // 2. ContactB + // This will allow us to check if either of the contacts in + // relationship have active memberships. + + $values = array(); + + // 1. ContactA + $values[$contact] = array( + 'relatedContacts' => $targetContact, + 'relationshipTypeId' => $relTypeId, + 'relationshipTypeDirection' => $relDirection, + ); + // 2. ContactB + if (!empty($targetContact)) { + foreach ($targetContact as $cid => $donCare) { + $values[$cid] = array( + 'relatedContacts' => array($contact => 1), + 'relationshipTypeId' => $relTypeId, + ); + + $relTypeParams = array('id' => $relTypeId); + $relTypeValues = array(); + CRM_Contact_BAO_RelationshipType::retrieve($relTypeParams, $relTypeValues); + + if (CRM_Utils_Array::value('name_a_b', $relTypeValues) == CRM_Utils_Array::value('name_b_a', $relTypeValues)) { + $values[$cid]['relationshipTypeDirection'] = '_a_b'; + } + else { + $values[$cid]['relationshipTypeDirection'] = ($relDirection == '_a_b') ? '_b_a' : '_a_b'; + } + } + } + + // Now get the active memberships for all the contacts. + // If contact have any valid membership(s), then add it to + // 'values' array. + foreach ($values as $cid => $subValues) { + $memParams = array('contact_id' => $cid); + $memberships = array(); + + CRM_Member_BAO_Membership::getValues($memParams, $memberships, $active); + + if (empty($memberships)) { + continue; + } + + $values[$cid]['memberships'] = $memberships; + } + $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus()); + + // done with 'values' array. + // Finally add / edit / delete memberships for the related contacts + foreach ($values as $cid => $details) { + if (!array_key_exists('memberships', $details)) { + continue; + } + + $mainRelatedContactId = key(CRM_Utils_Array::value('relatedContacts', $details, array())); + + foreach ($details['memberships'] as $membershipId => $membershipValues) { + $relTypeIds = array(); + if ($action & CRM_Core_Action::DELETE) { + // Delete memberships of the related contacts only if relationship type exists for membership type + $query = " +SELECT relationship_type_id, relationship_direction + FROM civicrm_membership_type + WHERE id = {$membershipValues['membership_type_id']}"; + $dao = CRM_Core_DAO::executeQuery($query); + $relTypeDirs = array(); + while ($dao->fetch()) { + $relTypeId = $dao->relationship_type_id; + $relDirection = $dao->relationship_direction; + } + $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $relTypeId); + if (in_array($values[$cid]['relationshipTypeId'], $relTypeIds)) { + CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $mainRelatedContactId); + } + continue; + } + if (($action & CRM_Core_Action::UPDATE) && + ($status & self::PAST) && + ($membershipValues['owner_membership_id']) + ) { + // If relationship is PAST and action is UPDATE + // then delete the RELATED membership + CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], + $membershipValues['membership_contact_id'] + ); + continue; + } + + // add / edit the memberships for related + // contacts. + + // Get the Membership Type Details. + $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipValues['membership_type_id']); + // Check if contact's relationship type exists in membership type + $relTypeDirs = array(); + if (CRM_Utils_Array::value('relationship_type_id', $membershipType)) { + $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']); + } + if (CRM_Utils_Array::value('relationship_direction', $membershipType)) { + $relDirections = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']); + } + foreach ($relTypeIds as $key => $value) { + $relTypeDirs[] = $value . '_' . $relDirections[$key]; + } + $relTypeDir = $details['relationshipTypeId'] . $details['relationshipTypeDirection']; + if (in_array($relTypeDir, $relTypeDirs)) { + // Check if relationship being created/updated is + // similar to that of membership type's + // relationship. + + $membershipValues['owner_membership_id'] = $membershipId; + unset($membershipValues['id']); + unset($membershipValues['membership_contact_id']); + unset($membershipValues['contact_id']); + unset($membershipValues['membership_id']); + foreach ($details['relatedContacts'] as $relatedContactId => $donCare) { + $membershipValues['contact_id'] = $relatedContactId; + if ($deceasedStatusId && + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $relatedContactId, 'is_deceased') + ) { + $membershipValues['status_id'] = $deceasedStatusId; + $membershipValues['skipStatusCal'] = TRUE; + } + foreach (array( + 'join_date', 'start_date', 'end_date') as $dateField) { + if (CRM_Utils_Array::value($dateField, $membershipValues)) { + $membershipValues[$dateField] = CRM_Utils_Date::processDate($membershipValues[$dateField]); + } + } + + if ($action & CRM_Core_Action::UPDATE) { + //delete the membership record for related + //contact before creating new membership record. + CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $relatedContactId); + } + + // check whether we have some related memberships still available + $query = " +SELECT count(*) + FROM civicrm_membership + LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id) + WHERE membership_type_id = {$membershipValues['membership_type_id']} AND owner_membership_id = {$membershipValues['owner_membership_id']} + AND is_current_member = 1"; + $result = CRM_Core_DAO::singleValueQuery($query); + if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) { + CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray); + } + } + } + elseif ($action & CRM_Core_Action::UPDATE) { + // if action is update and updated relationship do + // not match with the existing + // membership=>relationship then we need to + // delete the membership record created for + // previous relationship. + + if (self::isDeleteRelatedMembership($relTypeIds, $contactId, $mainRelatedContactId, $relTypeId, CRM_Utils_Array::value('relationship_ids', $params))) { + CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $mainRelatedContactId); + } + } + } + } + } + + /** + * Helper function to check whether to delete the membership or + * not. + * + */ + function isDeleteRelatedMembership($relTypeIds, $contactId, $mainRelatedContactId, $relTypeId, $relIds) { + if (in_array($relTypeId, $relTypeIds)) { + return TRUE; + } + + if (empty($relIds)) { + return FALSE; + } + + $relParamas = array(1 => array($contactId, 'Integer'), + 2 => array($mainRelatedContactId, 'Integer'), + ); + + if ($contactId == $mainRelatedContactId) { + $recordsFound = (int)CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM civicrm_relationship WHERE relationship_type_id IN ( " . implode(',', $relTypeIds) . " ) AND contact_id_a IN ( %1 ) OR contact_id_b IN ( %1 ) AND id IN (" . implode(',', $relIds) . ")", $relParamas); + if ($recordsFound) { + return FALSE; + } + return TRUE; + } + + $recordsFound = (int)CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM civicrm_relationship WHERE relationship_type_id IN ( " . implode(',', $relTypeIds) . " ) AND contact_id_a IN ( %1, %2 ) AND contact_id_b IN ( %1, %2 ) AND id NOT IN (" . implode(',', $relIds) . ")", $relParamas); + + if ($recordsFound) { + return FALSE; + } + + return TRUE; + } + + /** + * Function to get Current Employer for Contact + * + * @param $contactIds Contact Ids + * + * @return $currentEmployer array of the current employer + * + * @static + * + */ + static function getCurrentEmployer($contactIds) { + $contacts = implode(',', $contactIds); + + $query = " +SELECT organization_name, id, employer_id +FROM civicrm_contact +WHERE id IN ( {$contacts} ) +"; + + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + $currentEmployer = array(); + while ($dao->fetch()) { + $currentEmployer[$dao->id]['org_id'] = $dao->employer_id; + $currentEmployer[$dao->id]['org_name'] = $dao->organization_name; + } + + return $currentEmployer; + } + + /** + * Function to return list of permissioned employer for a given contact. + * + * @param $contactID int contact id whose employers + * are to be found. + * @param $name string employers sort name + * + * @static + * + * @return array array of employers. + * + */ + static function getPermissionedEmployer($contactID, $name = '%') { + $employers = array(); + + //get the relationship id + $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', + 'Employee of', 'id', 'name_a_b' + ); + + if ($relTypeId) { + $query = " +SELECT cc.id as id, cc.sort_name as name +FROM civicrm_relationship cr, civicrm_contact cc +WHERE cr.contact_id_a = $contactID AND +cr.relationship_type_id = $relTypeId AND +cr.is_permission_a_b = 1 AND +IF(cr.end_date IS NULL, 1, (DATEDIFF( CURDATE( ), cr.end_date ) <= 0)) AND +cr.is_active = 1 AND +cc.id = cr.contact_id_b AND +cc.sort_name LIKE '%$name%'"; + + $nullArray = array(); + $dao = CRM_Core_DAO::executeQuery($query, $nullArray); + + while ($dao->fetch()) { + $employers[$dao->id] = array( + 'name' => $dao->name, + 'value' => $dao->id, + ); + } + } + + return $employers; + } + + static function getValidContactTypeList($relType) { + // string looks like 4_a_b + $rel_parts = explode('_', $relType); + $allRelationshipType = CRM_Core_PseudoConstant::relationshipType('label'); + $contactProfiles = CRM_Core_BAO_UFGroup::getReservedProfiles('Contact', NULL); + + if ($rel_parts[1] == 'a') { + $leftType = $allRelationshipType[$rel_parts[0]]['contact_type_b']; + } + else { + $leftType = $allRelationshipType[$rel_parts[0]]['contact_type_a']; + } + + // Handle 'All Contacts' contact type for left side of relationship ($leftType is empty in this case) + // In this case all reserved profiles are available + if ($leftType == '') { + $contactTypes = $contactProfiles; + } else { + $contactTypes = array(); + foreach ($contactProfiles as $key => $value) { + if (strpos($value, $leftType) !== FALSE) { + $contactTypes = array($key => $value); + } + } + } + + return $contactTypes; + } + + /** + * Merge relationships from otherContact to mainContact + * Called during contact merge operation + * + * @param int $mainId contact id of main contact record. + * @param int $otherId contact id of record which is going to merge. + * @param array $sqls (reference) array of sql statements to append to. + * + * @see CRM_Dedupe_Merger::cpTables() + * + * @static + */ + static function mergeRelationships($mainId, $otherId, &$sqls) { + // Delete circular relationships + $sqls[] = "DELETE FROM civicrm_relationship + WHERE (contact_id_a = $mainId AND contact_id_b = $otherId) + OR (contact_id_b = $mainId AND contact_id_a = $otherId)"; + + // Delete relationship from other contact if main contact already has that relationship + $sqls[] = "DELETE r2 + FROM civicrm_relationship r1, civicrm_relationship r2 + WHERE r1.relationship_type_id = r2.relationship_type_id + AND r1.id <> r2.id + AND ( + r1.contact_id_a = $mainId AND r2.contact_id_a = $otherId AND r1.contact_id_b = r2.contact_id_b + OR r1.contact_id_b = $mainId AND r2.contact_id_b = $otherId AND r1.contact_id_a = r2.contact_id_a + OR ( + (r1.contact_id_a = $mainId AND r2.contact_id_b = $otherId AND r1.contact_id_b = r2.contact_id_a + OR r1.contact_id_b = $mainId AND r2.contact_id_a = $otherId AND r1.contact_id_a = r2.contact_id_b) + AND r1.relationship_type_id IN (SELECT id FROM civicrm_relationship_type WHERE name_b_a = name_a_b) + ) + )"; + + // Move relationships + $sqls[] = "UPDATE IGNORE civicrm_relationship SET contact_id_a = $mainId WHERE contact_id_a = $otherId"; + $sqls[] = "UPDATE IGNORE civicrm_relationship SET contact_id_b = $mainId WHERE contact_id_b = $otherId"; + + // Move current employer id (name will get updated later) + $sqls[] = "UPDATE civicrm_contact SET employer_id = $mainId WHERE employer_id = $otherId"; + } + + /** + * Set 'is_valid' field to false for all relationships whose end date is in the past, ie. are expired. + * + * @return True on success, false if error is encountered. + */ + static function disableExpiredRelationships() { + $query = "SELECT id FROM civicrm_relationship WHERE is_active = 1 AND end_date < CURDATE()"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $result = CRM_Contact_BAO_Relationship::setIsActive($dao->id, FALSE); + // Result will be NULL if error occurred. We abort early if error detected. + if ($result == NULL) { + return FALSE; + } + } + return TRUE; + } +} + diff --git a/CRM/Contact/BAO/RelationshipType.php b/CRM/Contact/BAO/RelationshipType.php new file mode 100644 index 0000000000..4a0e1b2192 --- /dev/null +++ b/CRM/Contact/BAO/RelationshipType.php @@ -0,0 +1,174 @@ +copyValues($params); + if ($relationshipType->find(TRUE)) { + CRM_Core_DAO::storeValues($relationshipType, $defaults); + $relationshipType->free(); + return $relationshipType; + } + return NULL; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_RelationshipType', $id, 'is_active', $is_active); + } + + /** + * Function to add the relationship type in the db + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $ids the array that holds all the db ids + * + * @return object CRM_Contact_DAO_RelationshipType + * @access public + * @static + * + */ + static function add(&$params, &$ids) { + //to change name, CRM-3336 + if (!CRM_Utils_Array::value('label_a_b', $params) && CRM_Utils_Array::value('name_a_b', $params)) { + $params['label_a_b'] = $params['name_a_b']; + } + + if (!CRM_Utils_Array::value('label_b_a', $params) && CRM_Utils_Array::value('name_b_a', $params)) { + $params['label_b_a'] = $params['name_b_a']; + } + + // set label to name if it's not set - but *only* for + // ADD action. CRM-3336 as part from (CRM-3522) + if (!CRM_Utils_Array::value('relationshipType', $ids)) { + if (!CRM_Utils_Array::value('name_a_b', $params) && CRM_Utils_Array::value('label_a_b', $params)) { + $params['name_a_b'] = $params['label_a_b']; + } + if (!CRM_Utils_Array::value('name_b_a', $params) && CRM_Utils_Array::value('label_b_a', $params)) { + $params['name_b_a'] = $params['label_b_a']; + } + } + + // action is taken depending upon the mode + $relationshipType = new CRM_Contact_DAO_RelationshipType(); + + $relationshipType->copyValues($params); + + // if label B to A is blank, insert the value label A to B for it + if (!strlen(trim($strName = CRM_Utils_Array::value('name_b_a', $params)))) { + $relationshipType->name_b_a = CRM_Utils_Array::value('name_a_b', $params); + } + if (!strlen(trim($strName = CRM_Utils_Array::value('label_b_a', $params)))) { + $relationshipType->label_b_a = CRM_Utils_Array::value('label_a_b', $params); + } + + $relationshipType->id = CRM_Utils_Array::value('relationshipType', $ids); + + return $relationshipType->save(); + } + + /** + * Function to delete Relationship Types + * + * @param int $relationshipTypeId + * @static + */ + static function del($relationshipTypeId) { + // make sure relationshipTypeId is an integer + if (!CRM_Utils_Rule::positiveInteger($relationshipTypeId)) { + CRM_Core_Error::fatal(ts('Invalid relationship type')); + } + + + //check dependencies + + // delete all relationships + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->relationship_type_id = $relationshipTypeId; + $relationship->delete(); + + // set all membership_type to null + $query = " +UPDATE civicrm_membership_type + SET relationship_type_id = NULL + WHERE relationship_type_id = %1 +"; + $params = array(1 => array($relationshipTypeId, 'Integer')); + CRM_Core_DAO::executeQuery($query, $params); + + //fixed for CRM-3323 + $mappingField = new CRM_Core_DAO_MappingField(); + $mappingField->relationship_type_id = $relationshipTypeId; + $mappingField->find(); + while ($mappingField->fetch()) { + $mappingField->delete(); + } + + $relationshipType = new CRM_Contact_DAO_RelationshipType(); + $relationshipType->id = $relationshipTypeId; + return $relationshipType->delete(); + } +} + diff --git a/CRM/Contact/BAO/SavedSearch.php b/CRM/Contact/BAO/SavedSearch.php new file mode 100644 index 0000000000..ccd2c77fdf --- /dev/null +++ b/CRM/Contact/BAO/SavedSearch.php @@ -0,0 +1,296 @@ +selectAdd(); + $savedSearch->selectAdd('id, name'); + $savedSearch->find(); + while ($savedSearch->fetch()) { + $aSavedSearch[$savedSearch->id] = $savedSearch->name; + } + return $aSavedSearch; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Contact_BAO_SavedSearch + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + $savedSearch = new CRM_Contact_DAO_SavedSearch(); + $savedSearch->copyValues($params); + if ($savedSearch->find(TRUE)) { + CRM_Core_DAO::storeValues($savedSearch, $defaults); + return $savedSearch; + } + return NULL; + } + + /** + * given an id, extract the formValues of the saved search + * + * @param int $id the id of the saved search + * + * @return array the values of the posted saved search + * @access public + * @static + */ + static function &getFormValues($id) { + $fv = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $id, 'form_values'); + $result = NULL; + if ($fv) { + // make sure u unserialize - since it's stored in serialized form + $result = unserialize($fv); + } + + // check to see if we need to convert the old privacy array + // CRM-9180 + if (isset($result['privacy'])) { + if (is_array($result['privacy'])) { + $result['privacy_operator'] = 'AND'; + $result['privacy_toggle'] = 1; + if (isset($result['privacy']['do_not_toggle'])) { + if ($result['privacy']['do_not_toggle']) { + $result['privacy_toggle'] = 2; + } + unset($result['privacy']['do_not_toggle']); + } + + $result['privacy_options'] = array(); + foreach ($result['privacy'] as $name => $value) { + if ($value) { + $result['privacy_options'][] = $name; + } + } + } + unset($result['privacy']); + } + + return $result; + } + + static function getSearchParams($id) { + $fv = self::getFormValues($id); + //check if the saved seach has mapping id + if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $id, 'mapping_id')) { + return CRM_Core_BAO_Mapping::formattedFields($fv); + } + elseif (CRM_Utils_Array::value('customSearchID', $fv)) { + return $fv; + } + else { + return CRM_Contact_BAO_Query::convertFormValues($fv); + } + } + + /** + * get the where clause for a saved search + * + * @param int $id saved search id + * @param array $tables (reference ) add the tables that are needed for the select clause + * @param array $whereTables (reference ) add the tables that are needed for the where clause + * + * @return string the where clause for this saved search + * @access public + * @static + */ + static function whereClause($id, &$tables, &$whereTables) { + $params = self::getSearchParams($id); + if ($params) { + if (CRM_Utils_Array::value('customSearchID', $params)) { + // this has not yet been implemented + } else { + return CRM_Contact_BAO_Query::getWhereClause($params, NULL, $tables, $whereTables); + } + } + return NULL; + } + + static function contactIDsSQL($id) { + $params = self::getSearchParams($id); + if ($params && + CRM_Utils_Array::value('customSearchID', $params) + ) { + return CRM_Contact_BAO_SearchCustom::contactIDSQL(NULL, $id); + } + else { + $tables = $whereTables = array('civicrm_contact' => 1); + $where = CRM_Contact_BAO_SavedSearch::whereClause($id, $tables, $whereTables); + if (!$where) { + $where = '( 1 )'; + } + $from = CRM_Contact_BAO_Query::fromClause($whereTables); + return " +SELECT contact_a.id +$from +WHERE $where"; + } + } + + static function fromWhereEmail($id) { + $params = self::getSearchParams($id); + + if ($params) { + if (CRM_Utils_Array::value('customSearchID', $params)) { + return CRM_Contact_BAO_SearchCustom::fromWhereEmail(NULL, $id); + } + else { + $tables = $whereTables = array('civicrm_contact' => 1, 'civicrm_email' => 1); + $where = CRM_Contact_BAO_SavedSearch::whereClause($id, $tables, $whereTables); + $from = CRM_Contact_BAO_Query::fromClause($whereTables); + return array($from, $where); + } + } + else { + // fix for CRM-7240 + $from = " +FROM civicrm_contact contact_a +LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1) +"; + $where = " ( 1 ) "; + $tables['civicrm_contact'] = $whereTables['civicrm_contact'] = 1; + $tables['civicrm_email'] = $whereTables['civicrm_email'] = 1; + return array($from, $where); + } + } + + /** + * given a saved search compute the clause and the tables + * and store it for future use + */ + function buildClause() { + $fv = unserialize($this->form_values); + + if ($this->mapping_id) { + $params = CRM_Core_BAO_Mapping::formattedFields($fv); + } + else { + $params = CRM_Contact_BAO_Query::convertFormValues($fv); + } + + if (!empty($params)) { + $tables = $whereTables = array(); + $this->where_clause = CRM_Contact_BAO_Query::getWhereClause($params, NULL, $tables, $whereTables); + if (!empty($tables)) { + $this->select_tables = serialize($tables); + } + if (!empty($whereTables)) { + $this->where_tables = serialize($whereTables); + } + } + + return; + } + + function save() { + // first build the computed fields + $this->buildClause(); + + parent::save(); + } + + /** + * given an id, get the name of the saved search + * + * @param int $id the id of the saved search + * + * @return string the name of the saved search + * @access public + * @static + */ + static function getName($id, $value = 'name') { + $group = new CRM_Contact_DAO_Group(); + $group->saved_search_id = $id; + if ($group->find(TRUE)) { + return $group->$value; + } + return NULL; + } + + /** + * Given a label and a set of normalized POST + * formValues, create a smart group with that + */ + static function create(&$params) { + $savedSearch = new CRM_Contact_DAO_SavedSearch(); + if (isset($params['formValues']) && + !empty($params['formValues']) + ) { + $savedSearch->form_values = serialize($params['formValues']); + } + else { + $savedSearch->form_values = 'null'; + } + + $savedSearch->is_active = CRM_Utils_Array::value('is_active', $params, 1); + $savedSearch->mapping_id = CRM_Utils_Array::value('mapping_id', $params, 'null'); + $savedSearch->custom_search_id = CRM_Utils_Array::value('custom_search_id', $params, 'null'); + $savedSearch->id = CRM_Utils_Array::value('id', $params, NULL); + + $savedSearch->save(); + + return $savedSearch; + } +} + diff --git a/CRM/Contact/BAO/SearchCustom.php b/CRM/Contact/BAO/SearchCustom.php new file mode 100644 index 0000000000..aa341e12a9 --- /dev/null +++ b/CRM/Contact/BAO/SearchCustom.php @@ -0,0 +1,136 @@ +getMapper(); + + if (!$ext->isExtensionKey($customSearchClass)) { + $customSearchFile = str_replace('_', + DIRECTORY_SEPARATOR, + $customSearchClass + ) . '.php'; + } + else { + $customSearchFile = $ext->keyToPath($customSearchClass); + $customSearchClass = $ext->keyToClass($customSearchClass); + } + + $error = include_once ($customSearchFile); + if ($error == FALSE) { + CRM_Core_Error::fatal('Custom search file: ' . $customSearchFile . ' does not exist. Please verify your custom search settings in CiviCRM administrative panel.'); + } + + return array($customSearchID, $customSearchClass, $formValues); + } + + static function customClass($csID, $ssID) { + list($customSearchID, $customSearchClass, $formValues) = self::details($csID, $ssID); + + if (!$customSearchID) { + CRM_Core_Error::fatal('Could not resolve custom search ID'); + } + + // instantiate the new class + eval('$customClass = new ' . $customSearchClass . '( $formValues );'); + + return $customClass; + } + + static function contactIDSQL($csID, $ssID) { + $customClass = self::customClass($csID, $ssID); + return $customClass->contactIDs(); + } + + static function &buildFormValues($args) { + $args = trim($args); + + $values = explode("\n", $args); + $formValues = array(); + foreach ($values as $value) { + list($n, $v) = CRM_Utils_System::explode('=', $value, 2); + if (!empty($v)) { + $formValues[$n] = $v; + } + } + return $formValues; + } + + static function fromWhereEmail($csID, $ssID) { + $customClass = self::customClass($csID, $ssID); + + $from = $customClass->from(); + $where = $customClass->where(); + + + return array($from, $where); + } +} + diff --git a/CRM/Contact/BAO/SubscriptionHistory.php b/CRM/Contact/BAO/SubscriptionHistory.php new file mode 100644 index 0000000000..3429cb09fa --- /dev/null +++ b/CRM/Contact/BAO/SubscriptionHistory.php @@ -0,0 +1,76 @@ +date = date('Ymd'); + $history->copyValues($params); + $history->save(); + return $history; + } + + /** + * Erase a contact's subscription history records + * + * @param int $id The contact id + * + * @return none + * @access public + * @static + */ + public static function deleteContact($id) { + $history = new CRM_Contact_BAO_SubscriptionHistory(); + $history->contact_id = $id; + $history->delete(); + } +} + diff --git a/CRM/Contact/Controller/Search.php b/CRM/Contact/Controller/Search.php new file mode 100644 index 0000000000..bfaa69f211 --- /dev/null +++ b/CRM/Contact/Controller/Search.php @@ -0,0 +1,68 @@ +_stateMachine = new CRM_Contact_StateMachine_Search($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $this->addActions(); + } + + public function selectorName() { + return $this->get('selectorName'); + } +} + diff --git a/CRM/Contact/DAO/Factory.php b/CRM/Contact/DAO/Factory.php new file mode 100644 index 0000000000..233a78356e --- /dev/null +++ b/CRM/Contact/DAO/Factory.php @@ -0,0 +1,61 @@ + 'data', + 'Contact' => 'data', + 'Email' => 'data', + 'Household' => 'data', + 'IM' => 'data', + 'Individual' => 'data', + 'Location' => 'data', + 'LocationType' => 'data', + 'Organization' => 'data', + 'Phone' => 'data', + 'Relationship' => 'data', + ); + + static $_prefix = array( + 'business' => 'CRM/Contact/BAO/', + 'data' => 'CRM/Contact/DAO/', + ); + + static $_suffix = '.php'; + + static $_preCall = array( + 'singleton' => '', + 'business' => 'new', + 'data' => 'new', + ); + + static $_extCall = array( + 'singleton' => '::singleton', + 'business' => '', + 'data' => '', + ); + + + static + function &create($className) { + $type = CRM_Utils_Array::value($className, self::$_classes); + if (!$type) { + return CRM_Core_DAO_Factory::create($className); + } + + $file = self::$_prefix[$type] . $className; + $class = str_replace('/', '_', $file); + + require_once ($file . self::$_suffix); + + $newObj = eval(sprintf("return %s %s%s();", + self::$_preCall[$type], + $class, + self::$_extCall[$type] + )); + + return $newObj; + } +} + diff --git a/CRM/Contact/Form/Contact.php b/CRM/Contact/Form/Contact.php new file mode 100644 index 0000000000..50a5b2415b --- /dev/null +++ b/CRM/Contact/Form/Contact.php @@ -0,0 +1,1448 @@ +_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add'); + + $this->_dedupeButtonName = $this->getButtonName('refresh', 'dedupe'); + $this->_duplicateButtonName = $this->getButtonName('upload', 'duplicate'); + + $session = CRM_Core_Session::singleton(); + if ($this->_action == CRM_Core_Action::ADD) { + // check for add contacts permissions + if (!CRM_Core_Permission::check('add contacts')) { + CRM_Utils_System::permissionDenied(); + CRM_Utils_System::civiExit(); + } + $this->_contactType = CRM_Utils_Request::retrieve('ct', 'String', + $this, TRUE, NULL, 'REQUEST' + ); + if (!in_array($this->_contactType, + array('Individual', 'Household', 'Organization') + )) { + CRM_Core_Error::statusBounce(ts('Could not get a contact id and/or contact type')); + } + + $this->_isContactSubType = FALSE; + if ($this->_contactSubType = CRM_Utils_Request::retrieve('cst', 'String', $this)) { + $this->_isContactSubType = TRUE; + } + + if ( + $this->_contactSubType && + !(CRM_Contact_BAO_ContactType::isExtendsContactType($this->_contactSubType, $this->_contactType, TRUE))) { + CRM_Core_Error::statusBounce(ts("Could not get a valid contact subtype for contact type '%1'", array(1 => $this->_contactType))); + } + + $this->_gid = CRM_Utils_Request::retrieve('gid', 'Integer', + CRM_Core_DAO::$_nullObject, + FALSE, NULL, 'GET' + ); + $this->_tid = CRM_Utils_Request::retrieve('tid', 'Integer', + CRM_Core_DAO::$_nullObject, + FALSE, NULL, 'GET' + ); + $typeLabel = CRM_Contact_BAO_ContactType::contactTypePairs(TRUE, $this->_contactSubType ? + $this->_contactSubType : $this->_contactType + ); + $typeLabel = implode(' / ', $typeLabel); + + CRM_Utils_System::setTitle(ts('New %1', array(1 => $typeLabel))); + $session->pushUserContext(CRM_Utils_System::url('civicrm/dashboard', 'reset=1')); + $this->_contactId = NULL; + } + else { + //update mode + if (!$this->_contactId) { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + } + + if ($this->_contactId) { + $defaults = array(); + $params = array('id' => $this->_contactId); + $returnProperities = array('id', 'contact_type', 'contact_sub_type', 'modified_date'); + CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_Contact', $params, $defaults, $returnProperities); + + if (!CRM_Utils_Array::value('id', $defaults)) { + CRM_Core_Error::statusBounce(ts('A Contact with that ID does not exist: %1', array(1 => $this->_contactId))); + } + + $this->_contactType = CRM_Utils_Array::value('contact_type', $defaults); + $this->_contactSubType = CRM_Utils_Array::value('contact_sub_type', $defaults); + + // check for permissions + $session = CRM_Core_Session::singleton(); + if ($session->get('userID') != $this->_contactId && + !CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT) + ) { + CRM_Core_Error::statusBounce(ts('You do not have the necessary permission to edit this contact.')); + } + + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + $displayName = ts('Edit %1', array(1 => $displayName)); + + // Check if this is default domain contact CRM-10482 + if (CRM_Contact_BAO_Contact::checkDomainContact($this->_contactId)) { + $displayName .= ' (' . ts('default organization') . ')'; + } + + // omitting contactImage from title for now since the summary overlay css doesn't work outside of our crm-container + CRM_Utils_System::setTitle($displayName); + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + + $urlParams = 'reset=1&cid=' . $this->_contactId; + if ($context) { + $urlParams .= "&context=$context"; + } + + if (CRM_Utils_Rule::qfKey($qfKey)) { + + $urlParams .= "&key=$qfKey"; + + } + $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/view', $urlParams)); + + $values = $this->get('values'); + // get contact values. + if (!empty($values)) { + $this->_values = $values; + } + else { + $params = array( + 'id' => $this->_contactId, + 'contact_id' => $this->_contactId, + 'noRelationships' => TRUE, + 'noNotes' => TRUE, + 'noGroups' => TRUE, + ); + + $contact = CRM_Contact_BAO_Contact::retrieve($params, $this->_values, TRUE); + $this->set('values', $this->_values); + } + } + else { + CRM_Core_Error::statusBounce(ts('Could not get a contact_id and/or contact_type')); + } + } + + // parse street address, CRM-5450 + $this->_parseStreetAddress = $this->get('parseStreetAddress'); + if (!isset($this->_parseStreetAddress)) { + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options' + ); + $this->_parseStreetAddress = FALSE; + if (CRM_Utils_Array::value('street_address', $addressOptions) && + CRM_Utils_Array::value('street_address_parsing', $addressOptions) + ) { + $this->_parseStreetAddress = TRUE; + } + $this->set('parseStreetAddress', $this->_parseStreetAddress); + } + $this->assign('parseStreetAddress', $this->_parseStreetAddress); + + $this->_editOptions = $this->get('contactEditOptions'); + if (CRM_Utils_System::isNull($this->_editOptions)) { + $this->_editOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_edit_options', TRUE, NULL, + FALSE, 'name', TRUE, 'AND v.filter = 0' + ); + $this->set('contactEditOptions', $this->_editOptions); + } + + // build demographics only for Individual contact type + if ($this->_contactType != 'Individual' && + array_key_exists('Demographics', $this->_editOptions) + ) { + unset($this->_editOptions['Demographics']); + } + + // in update mode don't show notes + if ($this->_contactId && array_key_exists('Notes', $this->_editOptions)) { + unset($this->_editOptions['Notes']); + } + + $this->assign('editOptions', $this->_editOptions); + $this->assign('contactType', $this->_contactType); + $this->assign('contactSubType', $this->_contactSubType); + + //build contact subtype form element, CRM-6864 + $buildContactSubType = TRUE; + if ($this->_contactSubType && ($this->_action & CRM_Core_Action::ADD)) { + $buildContactSubType = FALSE; + } + $this->assign('buildContactSubType', $buildContactSubType); + + // get the location blocks. + $this->_blocks = $this->get('blocks'); + if (CRM_Utils_System::isNull($this->_blocks)) { + $this->_blocks = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_edit_options', TRUE, NULL, + FALSE, 'name', TRUE, 'AND v.filter = 1' + ); + $this->set('blocks', $this->_blocks); + } + $this->assign('blocks', $this->_blocks); + + // this is needed for custom data. + $this->assign('entityID', $this->_contactId); + + // also keep the convention. + $this->assign('contactId', $this->_contactId); + + // location blocks. + CRM_Contact_Form_Location::preProcess($this); + + // retain the multiple count custom fields value + if(CRM_Utils_Array::value('hidden_custom', $_POST)) { + $customGroupCount = CRM_Utils_Array::value('hidden_custom_group_count', $_POST); + + if ($contactSubType = CRM_Utils_Array::value( 'contact_sub_type', $_POST)) { + $paramSubType = implode(',', $contactSubType); + } + + $this->_getCachedTree = FALSE; + unset($customGroupCount[0]); + foreach ($customGroupCount as $groupID => $groupCount) { + if ($groupCount > 1) { + $this->set('groupID', $groupID); + //loop the group + for ($i = 0; $i <= $groupCount; $i++) { + CRM_Custom_Form_CustomData::preProcess($this, NULL, $contactSubType, + $i, $this->_contactType + ); + CRM_Contact_Form_Edit_CustomData::buildQuickForm($this); + } + } + } + + //reset all the ajax stuff, for normal processing + if (isset($this->_groupTree)) { + $this->_groupTree = NULL; + } + $this->set('groupID', NULL); + $this->_getCachedTree = TRUE; + } + + // execute preProcess dynamically by js else execute normal preProcess + if (array_key_exists('CustomData', $this->_editOptions)) { + //assign a parameter to pass for sub type multivalue + //custom field to load + if ($this->_contactSubType || isset($paramSubType)) { + $paramSubType = (isset($paramSubType)) ? $paramSubType : + str_replace( CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($this->_contactSubType, CRM_Core_DAO::VALUE_SEPARATOR)); + + $this->assign('paramSubType', $paramSubType); + } + + if (CRM_Utils_Request::retrieve('type', 'String', CRM_Core_DAO::$_nullObject)) { + CRM_Contact_Form_Edit_CustomData::preProcess($this); + } + else { + $contactSubType = $this->_contactSubType; + // need contact sub type to build related grouptree array during post process + if (CRM_Utils_Array::value('contact_sub_type', $_POST)) { + $contactSubType = $_POST['contact_sub_type']; + } + //only custom data has preprocess hence directly call it + CRM_Custom_Form_CustomData::preProcess($this, NULL, $contactSubType, + 1, $this->_contactType, $this->_contactId + ); + $this->assign('customValueCount', $this->_customValueCount); + } + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = $this->_values; + $params = array(); + + if ($this->_action & CRM_Core_Action::ADD) { + if (array_key_exists('TagsAndGroups', $this->_editOptions)) { + // set group and tag defaults if any + if ($this->_gid) { + $defaults['group'][$this->_gid] = 1; + } + if ($this->_tid) { + $defaults['tag'][$this->_tid] = 1; + } + } + if ($this->_contactSubType) { + $defaults['contact_sub_type'] = $this->_contactSubType; + } + } + else { + $currentEmployer = CRM_Contact_BAO_Relationship::getCurrentEmployer(array($this->_contactId)); + $defaults['current_employer_id'] = CRM_Utils_Array::value('org_id', $currentEmployer[$this->_contactId]); + + foreach ($defaults['email'] as $dontCare => & $val) { + if (isset($val['signature_text'])) { + $val['signature_text_hidden'] = $val['signature_text']; + } + if (isset($val['signature_html'])) { + $val['signature_html_hidden'] = $val['signature_html']; + } + } + + if (CRM_Utils_Array::value('contact_sub_type', $defaults)) { + $defaults['contact_sub_type'] = $this->_oldSubtypes; + } + } + $this->assign('currentEmployer', CRM_Utils_Array::value('current_employer_id', $defaults)); + + // set defaults for blocks ( custom data, address, communication preference, notes, tags and groups ) + foreach ($this->_editOptions as $name => $label) { + if (!in_array($name, array( + 'Address', 'Notes'))) { + eval('CRM_Contact_Form_Edit_' . $name . '::setDefaultValues( $this, $defaults );'); + } + } + + //set address block defaults + CRM_Contact_Form_Edit_Address::setDefaultValues( $defaults, $this ); + + if (CRM_Utils_Array::value('image_URL', $defaults)) { + list($imageWidth, $imageHeight) = getimagesize($defaults['image_URL']); + list($imageThumbWidth, $imageThumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($imageWidth, $imageHeight); + $this->assign('imageWidth', $imageWidth); + $this->assign('imageHeight', $imageHeight); + $this->assign('imageThumbWidth', $imageThumbWidth); + $this->assign('imageThumbHeight', $imageThumbHeight); + $this->assign('imageURL', $defaults['image_URL']); + } + + //set location type and country to default for each block + $this->blockSetDefaults($defaults); + + $this->_preEditValues = $defaults; + return $defaults; + } + + /** + * do the set default related to location type id, + * primary location, default country + * + */ + function blockSetDefaults(&$defaults) { + $locationTypeKeys = array_filter(array_keys(CRM_Core_PseudoConstant::locationType()), 'is_int'); + sort($locationTypeKeys); + + // get the default location type + $locationType = CRM_Core_BAO_LocationType::getDefault(); + + // unset primary location type + $primaryLocationTypeIdKey = CRM_Utils_Array::key($locationType->id, $locationTypeKeys); + unset($locationTypeKeys[$primaryLocationTypeIdKey]); + + // reset the array sequence + $locationTypeKeys = array_values($locationTypeKeys); + + // get default phone and im provider id. + $defPhoneTypeId = key(CRM_Core_OptionGroup::values('phone_type', FALSE, FALSE, FALSE, ' AND is_default = 1')); + $defIMProviderId = key(CRM_Core_OptionGroup::values('instant_messenger_service', + FALSE, FALSE, FALSE, ' AND is_default = 1' + )); + + $allBlocks = $this->_blocks; + if (array_key_exists('Address', $this->_editOptions)) { + $allBlocks['Address'] = $this->_editOptions['Address']; + } + + $config = CRM_Core_Config::singleton(); + foreach ($allBlocks as $blockName => $label) { + $name = strtolower($blockName); + $hasPrimary = $updateMode = FALSE; + + // user is in update mode. + if (array_key_exists($name, $defaults) && + !CRM_Utils_System::isNull($defaults[$name]) + ) { + $updateMode = TRUE; + } + + for ($instance = 1; $instance <= $this->get($blockName . '_Block_Count'); $instance++) { + // make we require one primary block, CRM-5505 + if ($updateMode) { + if (!$hasPrimary) { + $hasPrimary = + CRM_Utils_Array::value( + 'is_primary', + CRM_Utils_Array::value($instance, $defaults[$name]) + ); + } + continue; + } + + //set location to primary for first one. + if ($instance == 1) { + $hasPrimary = TRUE; + $defaults[$name][$instance]['is_primary'] = TRUE; + $defaults[$name][$instance]['location_type_id'] = $locationType->id; + } + else { + $locTypeId = isset($locationTypeKeys[$instance - 1]) ? $locationTypeKeys[$instance - 1] : $locationType->id; + $defaults[$name][$instance]['location_type_id'] = $locTypeId; + } + + //set default country + if ($name == 'address' && $config->defaultContactCountry) { + $defaults[$name][$instance]['country_id'] = $config->defaultContactCountry; + } + + //set default state/province + if ($name == 'address' && $config->defaultContactStateProvince) { + $defaults[$name][$instance]['state_province_id'] = $config->defaultContactStateProvince; + } + + //set default phone type. + if ($name == 'phone' && $defPhoneTypeId) { + $defaults[$name][$instance]['phone_type_id'] = $defPhoneTypeId; + } + + //set default im provider. + if ($name == 'im' && $defIMProviderId) { + $defaults[$name][$instance]['provider_id'] = $defIMProviderId; + } + } + + if (!$hasPrimary) { + $defaults[$name][1]['is_primary'] = TRUE; + } + } + + // set defaults for country-state widget + if (CRM_Utils_Array::value('address', $defaults) && is_array($defaults['address'])) { + foreach ($defaults['address'] as $blockId => $values) { + CRM_Contact_Form_Edit_Address::fixStateSelect($this, + "address[$blockId][country_id]", + "address[$blockId][state_province_id]", + "address[$blockId][county_id]", + CRM_Utils_Array::value('country_id', + $values, $config->defaultContactCountry + ), + CRM_Utils_Array::value('state_province_id', + $values, $config->defaultContactStateProvince + ) + ); + } + } + } + + /** + * This function is used to add the rules (mainly global rules) for form. + * All local rules are added near the element + * + * @return None + * @access public + * @see valid_date + */ + function addRules() { + // skip adding formRules when custom data is build + if ($this->_addBlockName || ($this->_action & CRM_Core_Action::DELETE)) { + return; + } + + $this->addFormRule(array('CRM_Contact_Form_Edit_' . $this->_contactType, 'formRule'), $this->_contactId); + + // Call Locking check if editing existing contact + if ($this->_contactId) { + $this->addFormRule(array('CRM_Contact_Form_Edit_Lock', 'formRule'), $this->_contactId); + } + + if (array_key_exists('Address', $this->_editOptions)) { + $this->addFormRule(array('CRM_Contact_Form_Edit_Address', 'formRule')); + } + + if (array_key_exists('CommunicationPreferences', $this->_editOptions)) { + $this->addFormRule(array('CRM_Contact_Form_Edit_CommunicationPreferences', 'formRule'), $this); + } + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * @param int $contactId contact id if doing update. + * + * @return $primaryID email/openId + * @static + * @access public + */ + static function formRule($fields, &$errors, $contactId = NULL) { + $config = CRM_Core_Config::singleton(); + + // validations. + //1. for each block only single value can be marked as is_primary = true. + //2. location type id should be present if block data present. + //3. check open id across db and other each block for duplicate. + //4. at least one location should be primary. + //5. also get primaryID from email or open id block. + + // take the location blocks. + $blocks = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_edit_options', TRUE, NULL, + FALSE, 'name', TRUE, 'AND v.filter = 1' + ); + + $otherEditOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_edit_options', TRUE, NULL, + FALSE, 'name', TRUE, 'AND v.filter = 0' + ); + //get address block inside. + if (array_key_exists('Address', $otherEditOptions)) { + $blocks['Address'] = $otherEditOptions['Address']; + } + + $openIds = array(); + $primaryID = FALSE; + foreach ($blocks as $name => $label) { + $hasData = $hasPrimary = array(); + $name = strtolower($name); + if (CRM_Utils_Array::value($name, $fields) && is_array($fields[$name])) { + foreach ($fields[$name] as $instance => $blockValues) { + $dataExists = self::blockDataExists($blockValues); + + if (!$dataExists && $name == 'address') { + $dataExists = CRM_Utils_Array::value('use_shared_address', $fields['address'][$instance]); + } + + if ($dataExists) { + // skip remaining checks for website + if ($name == 'website') { + continue; + } + + $hasData[] = $instance; + if (CRM_Utils_Array::value('is_primary', $blockValues)) { + $hasPrimary[] = $instance; + if (!$primaryID && + in_array($name, array( + 'email', 'openid')) && + CRM_Utils_Array::value($name, $blockValues) + ) { + $primaryID = $blockValues[$name]; + } + } + + if (!CRM_Utils_Array::value('location_type_id', $blockValues)) { + $errors["{$name}[$instance][location_type_id]"] = ts('The Location Type should be set if there is %1 information.', array(1 => $label)); + } + } + + if ($name == 'openid' && CRM_Utils_Array::value($name, $blockValues)) { + $oid = new CRM_Core_DAO_OpenID(); + $oid->openid = $openIds[$instance] = CRM_Utils_Array::value($name, $blockValues); + $cid = isset($contactId) ? $contactId : 0; + if ($oid->find(TRUE) && ($oid->contact_id != $cid)) { + $errors["{$name}[$instance][openid]"] = ts('%1 already exist.', array(1 => $blocks['OpenID'])); + } + } + } + + if (empty($hasPrimary) && !empty($hasData)) { + $errors["{$name}[1][is_primary]"] = ts('One %1 should be marked as primary.', array(1 => $label)); + } + + if (count($hasPrimary) > 1) { + $errors["{$name}[" . array_pop($hasPrimary) . "][is_primary]"] = ts('Only one %1 can be marked as primary.', + array(1 => $label) + ); + } + } + } + + //do validations for all opend ids they should be distinct. + if (!empty($openIds) && (count(array_unique($openIds)) != count($openIds))) { + foreach ($openIds as $instance => $value) { + if (!array_key_exists($instance, array_unique($openIds))) { + $errors["openid[$instance][openid]"] = ts('%1 already used.', array(1 => $blocks['OpenID'])); + } + } + } + + // street number should be digit + suffix, CRM-5450 + $parseStreetAddress = CRM_Utils_Array::value('street_address_parsing', + CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options' + ) + ); + if ($parseStreetAddress) { + if (isset($fields['address']) && + is_array($fields['address']) + ) { + $invalidStreetNumbers = array(); + foreach ($fields['address'] as $cnt => $address) { + if ($streetNumber = CRM_Utils_Array::value('street_number', $address)) { + $parsedAddress = CRM_Core_BAO_Address::parseStreetAddress($address['street_number']); + if (!CRM_Utils_Array::value('street_number', $parsedAddress)) { + $invalidStreetNumbers[] = $cnt; + } + } + } + + if (!empty($invalidStreetNumbers)) { + $first = $invalidStreetNumbers[0]; + foreach ($invalidStreetNumbers as & $num) $num = CRM_Contact_Form_Contact::ordinalNumber($num); + $errors["address[$first][street_number]"] = ts('The street number you entered for the %1 address block(s) is not in an expected format. Street numbers may include numeric digit(s) followed by other characters. You can still enter the complete street address (unparsed) by clicking "Edit Complete Street Address".', array(1 => implode(', ', $invalidStreetNumbers))); + } + } + } + + return $primaryID; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + //load form for child blocks + if ($this->_addBlockName) { + $class = 'CRM_Contact_Form_Edit_' . $this->_addBlockName; + return $class::buildQuickForm($this); + } + + if ($this->_action == CRM_Core_Action::UPDATE) { + $deleteExtra = ts('Are you sure you want to delete contact image.'); + $deleteURL = array( + CRM_Core_Action::DELETE => + array( + 'name' => ts('Delete Contact Image'), + 'url' => 'civicrm/contact/image', + 'qs' => 'reset=1&cid=%%id%%&action=delete', + 'extra' => + 'onclick = "if (confirm( \'' . $deleteExtra . '\' ) ) this.href+=\'&confirmed=1\'; else return false;"', + ), + ); + $deleteURL = CRM_Core_Action::formLink($deleteURL, + CRM_Core_Action::DELETE, + array( + 'id' => $this->_contactId, + ) + ); + $this->assign('deleteURL', $deleteURL); + } + + //build contact type specific fields + eval('CRM_Contact_Form_Edit_' . $this->_contactType . '::buildQuickForm( $this );'); + + // build Custom data if Custom data present in edit option + $buildCustomData = 'noCustomDataPresent'; + if (array_key_exists('CustomData', $this->_editOptions)) { + $buildCustomData = "customDataPresent"; + } + + // subtype is a common field. lets keep it here + $subtypes = CRM_Contact_BAO_ContactType::subTypePairs($this->_contactType); + if (!empty($subtypes)) { + $sel = $this->add('select', 'contact_sub_type', ts('Contact Type'), + $subtypes, FALSE, + array( + 'id' => 'contact_sub_type', + 'multiple' => 'multiple', + 'title' => '- ' . ts('select') . ' -', + 'class' => $buildCustomData, + ) + ); + } + + // build edit blocks ( custom data, demographics, communication preference, notes, tags and groups ) + foreach ($this->_editOptions as $name => $label) { + if ($name == 'Address') { + $this->_blocks['Address'] = $this->_editOptions['Address']; + continue; + } + + eval('CRM_Contact_Form_Edit_' . $name . '::buildQuickForm( $this );'); + } + + // build location blocks. + CRM_Contact_Form_Edit_Lock::buildQuickForm($this); + CRM_Contact_Form_Location::buildQuickForm($this); + + // add attachment + $this->addElement('file', 'image_URL', ts('Browse/Upload Image'), 'size=30 maxlength=60'); + $this->addUploadElement('image_URL'); + + // add the dedupe button + $this->addElement('submit', + $this->_dedupeButtonName, + ts('Check for Matching Contact(s)') + ); + $this->addElement('submit', + $this->_duplicateButtonName, + ts('Save Matching Contact') + ); + $this->addElement('submit', + $this->getButtonName('next', 'sharedHouseholdDuplicate'), + ts('Save With Duplicate Household') + ); + + $buttons = array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'subName' => 'view', + 'isDefault' => TRUE, + ), + array( + 'type' => 'upload', + 'name' => ts('Save and New'), + 'spacing' => '                 ', + 'subName' => 'new', + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ); + + if (CRM_Utils_Array::value('contact_sub_type', $this->_values)) { + $this->_oldSubtypes = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($this->_values['contact_sub_type'], CRM_Core_DAO::VALUE_SEPARATOR) + ); + } + $this->assign('oldSubtypes', json_encode($this->_oldSubtypes)); + + $this->addButtons($buttons); + } + + /** + * Form submission of new/edit contact is processed. + * + * @access public + * + * @return None + */ + public function postProcess() { + // check if dedupe button, if so return. + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->_dedupeButtonName) { + return; + } + + //get the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + CRM_Contact_BAO_Contact_Optimizer::edit( $params, $this->_preEditValues ); + + if (CRM_Utils_Array::value('image_URL', $params)) { + CRM_Contact_BAO_Contact::processImageParams($params); + } + + if (is_numeric(CRM_Utils_Array::value('current_employer_id', $params)) + && CRM_Utils_Array::value('current_employer', $params) + ) { + $params['current_employer'] = $params['current_employer_id']; + } + + // don't carry current_employer_id field, + // since we don't want to directly update DAO object without + // handling related business logic ( eg related membership ) + if (isset($params['current_employer_id'])) { + unset($params['current_employer_id']); + } + + $params['contact_type'] = $this->_contactType; + if (empty($params['contact_sub_type']) && $this->_isContactSubType) { + $params['contact_sub_type'] = array($this->_contactSubType); + } + + if ($this->_contactId) { + $params['contact_id'] = $this->_contactId; + } + + //make deceased date null when is_deceased = false + if ($this->_contactType == 'Individual' && + CRM_Utils_Array::value('Demographics', $this->_editOptions) && + !CRM_Utils_Array::value('is_deceased', $params) + ) { + $params['is_deceased'] = FALSE; + $params['deceased_date'] = NULL; + } + + if (isset($params['contact_id'])) { + // process membership status for deceased contact + $deceasedParams = array('contact_id' => CRM_Utils_Array::value('contact_id', $params), + 'is_deceased' => CRM_Utils_Array::value('is_deceased', $params, FALSE), + 'deceased_date' => CRM_Utils_Array::value('deceased_date', $params, NULL), + ); + $updateMembershipMsg = $this->updateMembershipStatus($deceasedParams); + } + + // action is taken depending upon the mode + if ($this->_action & CRM_Core_Action::UPDATE) { + CRM_Utils_Hook::pre('edit', $params['contact_type'], $params['contact_id'], $params); + } + else { + CRM_Utils_Hook::pre('create', $params['contact_type'], NULL, $params); + } + + $customFields = CRM_Core_BAO_CustomField::getFields($params['contact_type'], FALSE, TRUE); + + //CRM-5143 + //if subtype is set, send subtype as extend to validate subtype customfield + $customFieldExtends = (CRM_Utils_Array::value('contact_sub_type', $params)) ? $params['contact_sub_type'] : $params['contact_type']; + + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_contactId, + $customFieldExtends, + TRUE + ); + if ($this->_contactId && !empty($this->_oldSubtypes)) { + CRM_Contact_BAO_ContactType::deleteCustomSetForSubtypeMigration($this->_contactId, + $params['contact_type'], + $this->_oldSubtypes, + $params['contact_sub_type'] + ); + } + + if (array_key_exists('CommunicationPreferences', $this->_editOptions)) { + // this is a chekbox, so mark false if we dont get a POST value + $params['is_opt_out'] = CRM_Utils_Array::value('is_opt_out', $params, FALSE); + } + + // process shared contact address. + CRM_Contact_BAO_Contact_Utils::processSharedAddress($params['address']); + + if (!array_key_exists('TagsAndGroups', $this->_editOptions)) { + unset($params['group']); + } + + if (CRM_Utils_Array::value('contact_id', $params) && ($this->_action & CRM_Core_Action::UPDATE)) { + // figure out which all groups are intended to be removed + if (!empty($params['group'])) { + $contactGroupList = CRM_Contact_BAO_GroupContact::getContactGroup($params['contact_id'], 'Added'); + if (is_array($contactGroupList)) { + foreach ($contactGroupList as $key) { + if ($params['group'][$key['group_id']] != 1 && + !CRM_Utils_Array::value('is_hidden', $key) + ) { + $params['group'][$key['group_id']] = -1; + } + } + } + } + } + + // parse street address, CRM-5450 + $parseStatusMsg = NULL; + if ($this->_parseStreetAddress) { + $parseResult = self::parseAddress($params); + $parseStatusMsg = self::parseAddressStatusMsg($parseResult); + } + + // Allow un-setting of location info, CRM-5969 + $params['updateBlankLocInfo'] = TRUE; + + $contact = CRM_Contact_BAO_Contact::create($params, TRUE, FALSE, TRUE); + + // status message + if ($this->_contactId) { + $message = ts('%1 has been updated.', array(1 => $contact->display_name)); + } + else { + $message = ts('%1 has been created.', array(1 => $contact->display_name)); + } + + // set the contact ID + $this->_contactId = $contact->id; + + if (array_key_exists('TagsAndGroups', $this->_editOptions)) { + //add contact to tags + CRM_Core_BAO_EntityTag::create($params['tag'], 'civicrm_contact', $params['contact_id']); + + //save free tags + if (isset($params['contact_taglist']) && !empty($params['contact_taglist'])) { + CRM_Core_Form_Tag::postProcess($params['contact_taglist'], $params['contact_id'], 'civicrm_contact', $this); + } + } + + if (!empty($parseStatusMsg)) { + $message .= "
    $parseStatusMsg"; + } + if (!empty($updateMembershipMsg)) { + $message .= "
    $updateMembershipMsg"; + } + + $session = CRM_Core_Session::singleton(); + $session->setStatus($message, ts('Contact Saved'), 'success'); + + // add the recently viewed contact + $recentOther = array(); + if (($session->get('userID') == $contact->id) || + CRM_Contact_BAO_Contact_Permission::allow($contact->id, CRM_Core_Permission::EDIT) + ) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/contact/add', 'reset=1&action=update&cid=' . $contact->id); + } + + if (($session->get('userID') != $this->_contactId) && CRM_Core_Permission::check('delete contacts')) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/delete', 'reset=1&delete=1&cid=' . $contact->id); + } + + CRM_Utils_Recent::add($contact->display_name, + CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $contact->id), + $contact->id, + $this->_contactType, + $contact->id, + $contact->display_name, + $recentOther + ); + + // here we replace the user context with the url to view this contact + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->getButtonName('upload', 'new')) { + $resetStr = "reset=1&ct={$contact->contact_type}"; + $resetStr .= $this->_contactSubType ? "&cst={$this->_contactSubType}" : ''; + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/add', $resetStr)); + } + else { + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + //validate the qfKey + $urlParams = 'reset=1&cid=' . $contact->id; + if ($context) { + $urlParams .= "&context=$context"; + } + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&key=$qfKey"; + } + + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', $urlParams)); + } + + // now invoke the post hook + if ($this->_action & CRM_Core_Action::UPDATE) { + CRM_Utils_Hook::post('edit', $params['contact_type'], $contact->id, $contact); + } + else { + CRM_Utils_Hook::post('create', $params['contact_type'], $contact->id, $contact); + } + } + + /** + * is there any real significant data in the hierarchical location array + * + * @param array $fields the hierarchical value representation of this location + * + * @return boolean true if data exists, false otherwise + * @static + * @access public + */ + static function blockDataExists(&$fields) { + if (!is_array($fields)) { + return FALSE; + } + + static $skipFields = array('location_type_id', 'is_primary', 'phone_type_id', 'provider_id', 'country_id', 'website_type_id', 'master_id'); + foreach ($fields as $name => $value) { + $skipField = FALSE; + foreach ($skipFields as $skip) { + if (strpos("[$skip]", $name) !== FALSE) { + if ($name == 'phone') { + continue; + } + $skipField = TRUE; + break; + } + } + if ($skipField) { + continue; + } + if (is_array($value)) { + if (self::blockDataExists($value)) { + return TRUE; + } + } + else { + if (!empty($value)) { + return TRUE; + } + } + } + + return FALSE; + } + + /** + * Function to that checks for duplicate contacts + * + * @param array $fields fields array which are submitted + * @param array $error error message array + * @param int $contactID contact id + * @param string $contactType contact type + */ + static function checkDuplicateContacts(&$fields, &$errors, $contactID, $contactType) { + // if this is a forced save, ignore find duplicate rule + if (!CRM_Utils_Array::value('_qf_Contact_upload_duplicate', $fields)) { + + $dedupeParams = CRM_Dedupe_Finder::formatParams($fields, $contactType); + $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $contactType, 'Supervised', array($contactID)); + if ($ids) { + + $contactLinks = CRM_Contact_BAO_Contact_Utils::formatContactIDSToLinks($ids, TRUE, TRUE, $contactID); + + $duplicateContactsLinks = '
    '; + $duplicateContactsLinks .= ts('One matching contact was found. ', array('count' => count($contactLinks['rows']), 'plural' => '%count matching contacts were found.
    ')); + if ($contactLinks['msg'] == 'view') { + $duplicateContactsLinks .= ts('You can View the existing contact', array('count' => count($contactLinks['rows']), 'plural' => 'You can View the existing contacts')); + } + else { + $duplicateContactsLinks .= ts('You can View or Edit the existing contact', array('count' => count($contactLinks['rows']), 'plural' => 'You can View or Edit the existing contacts')); + } + if ($contactLinks['msg'] == 'merge') { + // We should also get a merge link if this is for an existing contact + $duplicateContactsLinks .= ts(', or Merge this contact with an existing contact'); + } + $duplicateContactsLinks .= '.'; + $duplicateContactsLinks .= '
    '; + $duplicateContactsLinks .= ''; + $row = ''; + for ($i = 0; $i < count($contactLinks['rows']); $i++) { + $row .= ' '; + $row .= ' '; + $row .= ' '; + $row .= ' '; + $row .= ' '; + } + + $duplicateContactsLinks .= $row . '
    '; + $row .= $contactLinks['rows'][$i]['display_name']; + $row .= ' '; + $row .= $contactLinks['rows'][$i]['primary_email']; + $row .= ' '; + $row .= $contactLinks['rows'][$i]['view']; + $row .= $contactLinks['rows'][$i]['edit']; + $row .= CRM_Utils_Array::value('merge', $contactLinks['rows'][$i]); + $row .= '
    '; + $duplicateContactsLinks .= ts("If you're sure this record is not a duplicate, click the 'Save Matching Contact' button below."); + + $errors['_qf_default'] = $duplicateContactsLinks; + + + + // let smarty know that there are duplicates + $template = CRM_Core_Smarty::singleton(); + $template->assign('isDuplicate', 1); + } + elseif (CRM_Utils_Array::value('_qf_Contact_refresh_dedupe', $fields)) { + // add a session message for no matching contacts + CRM_Core_Session::setStatus(ts('No matching contact found.'), ts('None Found'), 'info'); + } + } + } + + function getTemplateFileName() { + if ($this->_contactSubType) { + $templateFile = "CRM/Contact/Form/Edit/SubType/{$this->_contactSubType}.tpl"; + $template = CRM_Core_Form::getTemplate(); + if ($template->template_exists($templateFile)) { + return $templateFile; + } + } + return parent::getTemplateFileName(); + } + + /** + * Parse all address blocks present in given params + * and return parse result for all address blocks, + * This function either parse street address in to child + * elements or build street address from child elements. + * + * @params $params an array of key value consist of address blocks. + * + * @return $parseSuccess as array of sucess/fails for each address block + * @static + */ + function parseAddress(&$params) { + $parseSuccess = $parsedFields = array(); + if (!is_array($params['address']) || + CRM_Utils_System::isNull($params['address']) + ) { + return $parseSuccess; + } + + foreach ($params['address'] as $instance => & $address) { + $buildStreetAddress = FALSE; + $parseFieldName = 'street_address'; + foreach (array( + 'street_number', 'street_name', 'street_unit') as $fld) { + if (CRM_Utils_Array::value($fld, $address)) { + $parseFieldName = 'street_number'; + $buildStreetAddress = TRUE; + break; + } + } + + // main parse string. + $parseString = CRM_Utils_Array::value($parseFieldName, $address); + + // parse address field. + $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($parseString); + + if ($buildStreetAddress) { + //hack to ignore spaces between number and suffix. + //here user gives input as street_number so it has to + //be street_number and street_number_suffix, but + //due to spaces though preg detect string as street_name + //consider it as 'street_number_suffix'. + $suffix = $parsedFields['street_number_suffix']; + if (!$suffix) { + $suffix = $parsedFields['street_name']; + } + $address['street_number_suffix'] = $suffix; + $address['street_number'] = $parsedFields['street_number']; + + $streetAddress = NULL; + foreach (array( + 'street_number', 'street_number_suffix', 'street_name', 'street_unit') as $fld) { + if (in_array($fld, array( + 'street_name', 'street_unit'))) { + $streetAddress .= ' '; + } + $streetAddress .= CRM_Utils_Array::value($fld, $address); + } + $address['street_address'] = trim($streetAddress); + $parseSuccess[$instance] = TRUE; + } + else { + $success = TRUE; + // consider address is automatically parseable, + // when we should found street_number and street_name + if (!CRM_Utils_Array::value('street_name', $parsedFields) || + !CRM_Utils_Array::value('street_number', $parsedFields) + ) { + $success = FALSE; + } + + // check for original street address string. + if (empty($parseString)) { + $success = TRUE; + } + + $parseSuccess[$instance] = $success; + + // we do not reset element values, but keep what we've parsed + // in case of partial matches: CRM-8378 + + // merge parse address in to main address block. + $address = array_merge($address, $parsedFields); + } + } + + return $parseSuccess; + } + + /** + * check parse result and if some address block fails then this + * function return the status message for all address blocks. + * + * @param $parseResult an array of address blk instance and its status. + * + * @return $statusMsg string status message for all address blocks. + * @static + */ + static function parseAddressStatusMsg($parseResult) { + $statusMsg = NULL; + if (!is_array($parseResult) || empty($parseResult)) { + return $statusMsg; + } + + $parseFails = array(); + foreach ($parseResult as $instance => $success) { + if (!$success) { + $parseFails[] = self::ordinalNumber($instance); + } + } + + if (!empty($parseFails)) { + $statusMsg = ts("Complete street address(es) have been saved. However we were unable to split the address in the %1 address block(s) into address elements (street number, street name, street unit) due to an unrecognized address format. You can set the address elements manually by clicking 'Edit Address Elements' next to the Street Address field while in edit mode.", + array(1 => implode(', ', $parseFails)) + ); + } + + return $statusMsg; + } + + /** + * Convert normal number to ordinal number format. + * like 1 => 1st, 2 => 2nd and so on... + * + * @param $number int number to convert in to ordinal number. + * + * @return ordinal number for given number. + * @static + */ + static function ordinalNumber($number) { + if (empty($number)) { + return NULL; + } + + $str = 'th'; + switch (floor($number / 10) % 10) { + case 1: + default: + switch ($number % 10) { + case 1: + $str = 'st'; + break; + + case 2: + $str = 'nd'; + break; + + case 3: + $str = 'rd'; + break; + } + } + + return "$number$str"; + } + + /** + * Update membership status to deceased + * function return the status message for updated membership. + * + * @param $deceasedParams array having contact id and deceased value. + * + * @return $updateMembershipMsg string status message for updated membership. + */ + function updateMembershipStatus($deceasedParams) { + $updateMembershipMsg = NULL; + $contactId = CRM_Utils_Array::value('contact_id', $deceasedParams); + $deceasedDate = CRM_Utils_Array::value('deceased_date', $deceasedParams); + + // process to set membership status to deceased for both active/inactive membership + if ($contactId && + $this->_contactType == 'Individual' && + CRM_Utils_Array::value('is_deceased', $deceasedParams) + ) { + + $session = CRM_Core_Session::singleton(); + $userId = $session->get('userID'); + if (!$userId) { + $userId = $contactId; + } + + + // get deceased status id + $allStatus = CRM_Member_PseudoConstant::membershipStatus(); + $deceasedStatusId = array_search('Deceased', $allStatus); + if (!$deceasedStatusId) { + return $updateMembershipMsg; + } + + $today = time(); + if ($deceasedDate && strtotime($deceasedDate) > $today) { + return $updateMembershipMsg; + } + + // get non deceased membership + $dao = new CRM_Member_DAO_Membership(); + $dao->contact_id = $contactId; + $dao->whereAdd("status_id != $deceasedStatusId"); + $dao->find(); + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name'); + $allStatus = CRM_Member_PseudoConstant::membershipStatus(); + $memCount = 0; + while ($dao->fetch()) { + // update status to deceased (for both active/inactive membership ) + CRM_Core_DAO::setFieldValue('CRM_Member_DAO_Membership', $dao->id, + 'status_id', $deceasedStatusId + ); + + // add membership log + $membershipLog = array( + 'membership_id' => $dao->id, + 'status_id' => $deceasedStatusId, + 'start_date' => CRM_Utils_Date::isoToMysql($dao->start_date), + 'end_date' => CRM_Utils_Date::isoToMysql($dao->end_date), + 'modified_id' => $userId, + 'modified_date' => date('Ymd'), + 'membership_type_id' => $dao->membership_type_id, + 'max_related' => $dao->max_related, + ); + + + CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray); + + //create activity when membership status is changed + $activityParam = array( + 'subject' => "Status changed from {$allStatus[$dao->status_id]} to {$allStatus[$deceasedStatusId]}", + 'source_contact_id' => $userId, + 'target_contact_id' => $dao->contact_id, + 'source_record_id' => $dao->id, + 'activity_type_id' => array_search('Change Membership Status', $activityTypes), + 'status_id' => 2, + 'version' => 3, + 'priority_id' => 2, + 'activity_date_time' => date('Y-m-d H:i:s'), + 'is_auto' => 0, + 'is_current_revision' => 1, + 'is_deleted' => 0, + ); + $activityResult = civicrm_api('activity', 'create', $activityParam); + + $memCount++; + } + + // set status msg + if ($memCount) { + $updateMembershipMsg = ts("%1 Current membership(s) for this contact have been set to 'Deceased' status.", + array(1 => $memCount) + ); + } + } + + return $updateMembershipMsg; + } +} + diff --git a/CRM/Contact/Form/CustomData.php b/CRM/Contact/Form/CustomData.php new file mode 100644 index 0000000000..596b097c3d --- /dev/null +++ b/CRM/Contact/Form/CustomData.php @@ -0,0 +1,234 @@ +_cdType = CRM_Utils_Array::value('type', $_GET); + + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + return CRM_Custom_Form_CustomData::preProcess($this); + } + + $this->_groupID = CRM_Utils_Request::retrieve('groupID', 'Positive', $this, TRUE); + $this->_tableID = CRM_Utils_Request::retrieve('tableId', 'Positive', $this, TRUE); + + $this->_contactType = CRM_Contact_BAO_Contact::getContactType($this->_tableID); + $this->_contactSubType = CRM_Contact_BAO_Contact::getContactSubType($this->_tableID, ','); + $this->assign('contact_type', $this->_contactType); + $this->assign('contact_subtype', $this->_contactSubType); + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($this->_tableID); + CRM_Utils_System::setTitle($displayName, $contactImage . ' ' . $displayName); + + // when custom data is included in this page + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + for ($i = 0; $i <= $_POST['hidden_custom_group_count'][$this->_groupID]; $i++) { + CRM_Custom_Form_CustomData::preProcess($this, NULL, NULL, $i); + CRM_Custom_Form_CustomData::buildQuickForm($this); + CRM_Custom_Form_CustomData::setDefaultValues($this); + } + } + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + //need to assign custom data type and subtype to the template + $this->assign('entityID', $this->_tableID); + $this->assign('groupID', $this->_groupID); + + // make this form an upload since we dont know if the custom data injected dynamically + // is of type file etc + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + if ($this->_cdType) { + $customDefaultValue = CRM_Custom_Form_CustomData::setDefaultValues($this); + return $customDefaultValue; + } + + $groupTree = &CRM_Core_BAO_CustomGroup::getTree($this->_contactType, + $this, + $this->_tableID, + $this->_groupID, + $this->_contactSubType + ); + + if (!CRM_Utils_Array::value('hidden_custom_group_count', $_POST)) { + // custom data building in edit mode (required to handle multi-value) + $groupTree = &CRM_Core_BAO_CustomGroup::getTree($this->_contactType, $this, $this->_tableID, + $this->_groupID, $this->_contactSubType + ); + $customValueCount = CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree, TRUE, $this->_groupID); + } + else { + $customValueCount = $_POST['hidden_custom_group_count'][$this->_groupID]; + } + + $this->assign('customValueCount', $customValueCount); + + $defaults = array(); + return $defaults; + } + + /** + * Process the user submitted custom data values. + * + * @access public + * + * @return void + */ + public function postProcess() { + // Get the form values and groupTree + $params = $this->controller->exportValues($this->_name); + CRM_Core_BAO_CustomValueTable::postProcess($params, + $this->_groupTree[$this->_groupID]['fields'], + 'civicrm_contact', + $this->_tableID, + $this->_entityType + ); + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + } +} + diff --git a/CRM/Contact/Form/DedupeFind.php b/CRM/Contact/Form/DedupeFind.php new file mode 100644 index 0000000000..89f4c63b6d --- /dev/null +++ b/CRM/Contact/Form/DedupeFind.php @@ -0,0 +1,114 @@ +rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + $groupList = CRM_Core_PseudoConstant::group(); + $groupList[''] = ts('- All Contacts -'); + asort($groupList); + + $this->add('select', 'group_id', ts('Select Group'), $groupList); + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Continue'), + 'isDefault' => TRUE, + ), + //hack to support cancel button functionality + array( + 'type' => 'submit', + 'name' => ts('Cancel'), + ), + ) + ); + } + + function setDefaultValues() { + return $this->_defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $values = $this->exportValues(); + if (CRM_Utils_Array::value('_qf_DedupeFind_submit', $_POST)) { + //used for cancel button + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/deduperules', 'reset=1')); + return; + } + if ($values['group_id']) { + $url = CRM_Utils_System::url('civicrm/contact/dedupefind', "reset=1&action=update&rgid={$this->rgid}&gid={$values['group_id']}"); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/dedupefind', "reset=1&action=update&rgid={$this->rgid}"); + } + + CRM_Utils_System::redirect($url); + } +} + diff --git a/CRM/Contact/Form/DedupeRules.php b/CRM/Contact/Form/DedupeRules.php new file mode 100644 index 0000000000..8e8739b945 --- /dev/null +++ b/CRM/Contact/Form/DedupeRules.php @@ -0,0 +1,284 @@ +_options = array(ts('Unsupervised'), ts('Supervised'), ts('General')); + $this->_rgid = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, 0); + $this->_contactType = CRM_Utils_Request::retrieve('contact_type', 'String', $this, FALSE, 0); + if ($this->_rgid) { + $rgDao = new CRM_Dedupe_DAO_RuleGroup(); + $rgDao->id = $this->_rgid; + $rgDao->find(TRUE); + + $this->_defaults['threshold'] = $rgDao->threshold; + $this->_contactType = $rgDao->contact_type; + $this->_defaults['used'] = CRM_Utils_Array::key($rgDao->used, $this->_options); + $this->_defaults['title'] = $rgDao->title; + $this->_defaults['name'] = $rgDao->name; + $this->_defaults['is_reserved'] = $rgDao->is_reserved; + $this->assign('isReserved', $rgDao->is_reserved); + $this->assign('ruleName', $rgDao->name); + $ruleDao = new CRM_Dedupe_DAO_Rule(); + $ruleDao->dedupe_rule_group_id = $this->_rgid; + $ruleDao->find(); + $count = 0; + while ($ruleDao->fetch()) { + $this->_defaults["where_$count"] = "{$ruleDao->rule_table}.{$ruleDao->rule_field}"; + $this->_defaults["length_$count"] = $ruleDao->rule_length; + $this->_defaults["weight_$count"] = $ruleDao->rule_weight; + $count++; + } + } + $supported = CRM_Dedupe_BAO_RuleGroup::supportedFields($this->_contactType); + if (is_array($supported)) { + foreach ($supported as $table => $fields) { + foreach ($fields as $field => $title) { + $this->_fields["$table.$field"] = $title; + } + } + } + asort($this->_fields); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $foo = CRM_Core_DAO::getAttribute('CRM_Dedupe_DAO_Rule', 'title'); + + $this->add('text', 'title', ts('Rule Name'), array('maxlength' => 255, 'class' => 'huge'), TRUE); + $this->addRule('title', ts('A duplicate matching rule with this name already exists. Please select another name.'), + 'objectExists', array('CRM_Dedupe_DAO_RuleGroup', $this->_rgid, 'title') + ); + + $this->addRadio('used', ts('Usage'), $this->_options); + + $disabled = array(); + $reserved = $this->add('checkbox', 'is_reserved', ts('Reserved?')); + if (CRM_Utils_Array::value('is_reserved', $this->_defaults)) { + $reserved->freeze(); + $disabled = array('disabled' => TRUE); + } + + $attributes = array('class' => 'two'); + if (!empty($disabled)) { + $attributes = array_merge($attributes, $disabled); + } + + for ($count = 0; $count < self::RULES_COUNT; $count++) { + $this->add('select', "where_$count", ts('Field'), + array( + NULL => ts('- none -')) + $this->_fields, FALSE, $disabled + ); + $this->add('text', "length_$count", ts('Length'), $attributes); + $this->add('text', "weight_$count", ts('Weight'), $attributes); + } + + $this->add('text', 'threshold', ts("Weight Threshold to Consider Contacts 'Matching':"), $attributes); + $this->addButtons(array( + array('type' => 'next', 'name' => ts('Save'), 'isDefault' => TRUE), + array('type' => 'cancel', 'name' => ts('Cancel')), + )); + + $this->assign('contact_type', $this->_contactType); + + $this->addFormRule(array('CRM_Contact_Form_DedupeRules', 'formRule'), $this); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields, $files, $self) { + $errors = array(); + if (CRM_Utils_Array::value('is_reserved', $fields)) { + return TRUE; + } + + $fieldSelected = FALSE; + for ($count = 0; $count < self::RULES_COUNT; $count++) { + if (CRM_Utils_Array::value("where_$count", $fields)) { + $fieldSelected = TRUE; + break; + } + } + + if (!$fieldSelected) { + $errors['_qf_default'] = ts('Please select at least one field.'); + } + + return empty($errors) ? TRUE : $errors; + } + + function setDefaultValues() { + return $this->_defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $values = $this->exportValues(); + + //FIXME: Handle logic to replace is_default column by usage + $used = CRM_Utils_Array::value('used', $values, FALSE); + // reset used column to General (since there can only + // be one 'Supervised' or 'Unsupervised' rule) + if ($this->_options[$used] != 'General') { + $query = " +UPDATE civicrm_dedupe_rule_group + SET used = 'General' + WHERE contact_type = %1 + AND used = %2"; + $queryParams = array(1 => array($this->_contactType, 'String'), + 2 => array($this->_options[$used], 'String'), + ); + + CRM_Core_DAO::executeQuery($query, $queryParams); + } + + $rgDao = new CRM_Dedupe_DAO_RuleGroup(); + if ($this->_action & CRM_Core_Action::UPDATE) { + $rgDao->id = $this->_rgid; + } + + $rgDao->title = $values['title']; + $rgDao->is_reserved = CRM_Utils_Array::value('is_reserved', $values, FALSE); + $rgDao->used = $this->_options[$values['used']]; + $rgDao->contact_type = $this->_contactType; + $rgDao->threshold = $values['threshold']; + $rgDao->save(); + + // make sure name is set only during insert + if ($this->_action & CRM_Core_Action::ADD) { + // generate name based on title + $rgDao->name = CRM_Utils_String::titleToVar($values['title']) . "_{$rgDao->id}"; + $rgDao->save(); + } + + // lets skip updating of fields for reserved dedupe group + if ($rgDao->is_reserved) { + CRM_Core_Session::setStatus(ts("The rule '%1' has been saved.", array(1 => $rgDao->title)), ts('Saved'), 'success'); + return; + } + + $ruleDao = new CRM_Dedupe_DAO_Rule(); + $ruleDao->dedupe_rule_group_id = $rgDao->id; + $ruleDao->delete(); + $ruleDao->free(); + + $substrLenghts = array(); + + $tables = array(); + for ($count = 0; $count < self::RULES_COUNT; $count++) { + if (!CRM_Utils_Array::value("where_$count", $values)) { + continue; + } + list($table, $field) = explode('.', CRM_Utils_Array::value("where_$count", $values)); + $length = CRM_Utils_Array::value("length_$count", $values) ? CRM_Utils_Array::value("length_$count", $values) : NULL; + $weight = $values["weight_$count"]; + if ($table and $field) { + $ruleDao = new CRM_Dedupe_DAO_Rule(); + $ruleDao->dedupe_rule_group_id = $rgDao->id; + $ruleDao->rule_table = $table; + $ruleDao->rule_field = $field; + $ruleDao->rule_length = $length; + $ruleDao->rule_weight = $weight; + $ruleDao->save(); + $ruleDao->free(); + + if (!array_key_exists($table, $tables)) { + $tables[$table] = array(); + } + $tables[$table][] = $field; + } + + // CRM-6245: we must pass table/field/length triples to the createIndexes() call below + if ($length) { + if (!isset($substrLenghts[$table])) { + $substrLenghts[$table] = array(); + } + $substrLenghts[$table][$field] = $length; + } + } + + // also create an index for this dedupe rule + // CRM-3837 + CRM_Core_BAO_SchemaHandler::createIndexes($tables, 'dedupe_index', $substrLenghts); + + //need to clear cache of deduped contacts + //based on the previous rule + $cacheKey = "merge {$this->_contactType}_{$this->_rgid}_%"; + + CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey); + + CRM_Core_Session::setStatus(ts("The rule '%1' has been saved.", array(1 => $rgDao->title)), ts('Saved'), 'success'); + } +} + diff --git a/CRM/Contact/Form/Domain.php b/CRM/Contact/Form/Domain.php new file mode 100644 index 0000000000..3bac77102f --- /dev/null +++ b/CRM/Contact/Form/Domain.php @@ -0,0 +1,298 @@ +replaceUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + + $this->_id = CRM_Core_Config::domainID(); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 'view' + ); + //location blocks. + $location = new CRM_Contact_Form_Location(); + $location->preProcess($this); + } + + /* + * This function sets the default values for the form. + * the default values are retrieved from the database + * + * @access public + * @return None + */ + function setDefaultValues() { + $defaults = array(); + $params = array(); + $locParams = array(); + + if (isset($this->_id)) { + $params['id'] = $this->_id; + CRM_Core_BAO_Domain::retrieve($params, $domainDefaults); + $this->_contactId = $domainDefaults['contact_id']; + //get the default domain from email address. fix CRM-3552 + $optionValues = array(); + $grpParams['name'] = 'from_email_address'; + CRM_Core_OptionValue::getValues($grpParams, $optionValues); + foreach ($optionValues as $Id => $value) { + if ($value['is_default'] && $value['is_active']) { + $this->_fromEmailId = $Id; + $list = explode('"', $value['label']); + $domainDefaults['email_name'] = CRM_Utils_Array::value(1, $list); + $domainDefaults['email_address'] = CRM_Utils_Mail::pluckEmailFromHeader($value['label']); + break; + } + } + + unset($params['id']); + $locParams = array('contact_id' => $domainDefaults['contact_id']); + $defaults = CRM_Core_BAO_Location::getValues($locParams); + + $config = CRM_Core_Config::singleton(); + if (!isset($defaults['address'][1]['country_id'])) { + $defaults['address'][1]['country_id'] = $config->defaultContactCountry; + } + + if (!isset($defaults['address'][1]['state_province_id'])) { + $defaults['address'][1]['state_province_id'] = $config->defaultContactStateProvince; + } + + if (!empty($defaults['address'])) { + foreach ($defaults['address'] as $key => $value) { + CRM_Contact_Form_Edit_Address::fixStateSelect($this, + "address[$key][country_id]", + "address[$key][state_province_id]", + "address[$key][county_id]", + CRM_Utils_Array::value('country_id', $value, + $config->defaultContactCountry + ), + CRM_Utils_Array::value('state_province_id', $value, + $config->defaultContactStateProvince + ) + ); + } + } + } + $defaults = array_merge($defaults, $domainDefaults); + return $defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + $this->add('text', 'name', ts('Organization Name'), array('size' => 25), TRUE); + $this->add('text', 'description', ts('Description'), array('size' => 25)); + + $this->add('text', 'email_name', ts('FROM Name'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', 'email'), TRUE); + + $this->add('text', 'email_address', ts('FROM Email Address'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', 'email'), TRUE); + $this->addRule('email_address', ts('Domain Email Address must use a valid email address format (e.g. \'info@example.org\').'), 'email'); + + //build location blocks. + CRM_Contact_Form_Location::buildQuickForm($this); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'subName' => 'view', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + )); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->freeze(); + } + $this->assign('emailDomain', TRUE); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Domain', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + $errors = array(); + // check for state/country mapping + CRM_Contact_Form_Edit_Address::formRule($fields, $errors); + + //fix for CRM-3552, + //as we use "fromName" format for domain email. + if (strpos($fields['email_name'], '"') !== FALSE) { + $errors['email_name'] = ts('Double quotes are not allow in from name.'); + } + + // Check for default from email address and organization (domain) name. Force them to change it. + if ($fields['email_address'] == 'info@EXAMPLE.ORG') { + $errors['email_address'] = ts('Please enter a valid default FROM email address for system-generated emails.'); + } + if ($fields['name'] == 'Default Domain Name') { + $errors['name'] = ts('Please enter the name of the organization or entity which owns this CiviCRM site.'); + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Process the form when submitted + * + * @return void + * @access public + */ + public function postProcess() { + $params = array(); + $params = $this->exportValues(); + $params['entity_id'] = $this->_id; + $params['entity_table'] = CRM_Core_BAO_Domain::getTableName(); + $domain = CRM_Core_BAO_Domain::edit($params, $this->_id); + + $defaultLocationType = CRM_Core_BAO_LocationType::getDefault(); + + $location = array(); + $params['address'][1]['location_type_id'] = $defaultLocationType->id; + $params['phone'][1]['location_type_id'] = $defaultLocationType->id; + $params['email'][1]['location_type_id'] = $defaultLocationType->id; + $params += array('contact_id' => $this->_contactId); + $contactParams = array ( + 'sort_name' => $domain->name, + 'display_name' => $domain->name, + 'legal_name' => $domain->name, + 'organization_name' => $domain->name, + 'contact_id' => $this->_contactId, + ); + CRM_Contact_BAO_Contact::add($contactParams); + $location = CRM_Core_BAO_Location::create($params, TRUE); + + + CRM_Core_BAO_Domain::edit($params, $this->_id); + + //set domain from email address, CRM-3552 + $emailName = '"' . $params['email_name'] . '" <' . $params['email_address'] . '>'; + + $emailParams = array( + 'label' => $emailName, + 'description' => $params['description'], + 'is_active' => 1, + 'is_default' => 1, + ); + + $groupParams = array('name' => 'from_email_address'); + + //get the option value wt. + if ($this->_fromEmailId) { + $action = $this->_action; + $emailParams['weight'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_fromEmailId, 'weight'); + } + else { + //add from email address. + $action = CRM_Core_Action::ADD; + $grpId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'from_email_address', 'id', 'name'); + $fieldValues = array('option_group_id' => $grpId); + $emailParams['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', $fieldValues); + } + + + //reset default within domain. + $emailParams['reset_default_for'] = array('domain_id' => CRM_Core_Config::domainID()); + + CRM_Core_OptionValue::addOptionValue($emailParams, $groupParams, $action, $this->_fromEmailId); + + CRM_Core_Session::setStatus(ts("Domain information for '%1' has been saved.", array(1 => $domain->name)), ts('Saved'), 'success'); + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + } +} + diff --git a/CRM/Contact/Form/Edit/Address.php b/CRM/Contact/Form/Edit/Address.php new file mode 100644 index 0000000000..2fe49ac9f2 --- /dev/null +++ b/CRM/Contact/Form/Edit/Address.php @@ -0,0 +1,551 @@ +get('Address_Block_Count')) ? $form->get('Address_Block_Count') : 1; + } + else { + $blockId = $addressBlockCount; + } + + $config = CRM_Core_Config::singleton(); + $countryDefault = $config->defaultContactCountry; + + $form->applyFilter('__ALL__', 'trim'); + + $js = array(); + if ( !$inlineEdit ) { + $js = array('onChange' => 'checkLocation( this.id );'); + } + + $form->addElement('select', + "address[$blockId][location_type_id]", + ts('Location Type'), + array( + '' => ts('- select -')) + CRM_Core_PseudoConstant::locationType(), + $js + ); + + if ( !$inlineEdit ) { + $js = array('id' => 'Address_' . $blockId . '_IsPrimary', 'onClick' => 'singleSelect( this.id );'); + } + else { + //make location type required for inline edit + $form->addRule( "address[$blockId][location_type_id]", ts('%1 is a required field.', array(1 => ts('Location Type'))), 'required'); + } + + $form->addElement( + 'checkbox', + "address[$blockId][is_primary]", + ts('Primary location for this contact'), + ts('Primary location for this contact'), + $js + ); + + if ( !$inlineEdit ) { + $js = array('id' => 'Address_' . $blockId . '_IsBilling', 'onClick' => 'singleSelect( this.id );'); + } + + $form->addElement( + 'checkbox', + "address[$blockId][is_billing]", + ts('Billing location for this contact'), + ts('Billing location for this contact'), + $js + ); + + // hidden element to store master address id + $form->addElement('hidden', "address[$blockId][master_id]"); + + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options', TRUE, NULL, TRUE + ); + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_Address'); + + $elements = array( + 'address_name' => array(ts('Address Name'), $attributes['address_name'], NULL), + 'street_address' => array(ts('Street Address'), $attributes['street_address'], NULL), + 'supplemental_address_1' => array(ts('Addt\'l Address 1'), $attributes['supplemental_address_1'], NULL), + 'supplemental_address_2' => array(ts('Addt\'l Address 2'), $attributes['supplemental_address_2'], NULL), + 'city' => array(ts('City'), $attributes['city'], NULL), + 'postal_code' => array(ts('Zip / Postal Code'), array_merge($attributes['postal_code'], array('class' => 'crm_postal_code')), NULL), + 'postal_code_suffix' => array(ts('Postal Code Suffix'), array('size' => 4, 'maxlength' => 12, 'class' => 'crm_postal_code_suffix'), NULL), + 'county_id' => array(ts('County'), $attributes['county_id'], NULL), + 'state_province_id' => array(ts('State / Province'), $attributes['state_province_id'], NULL), + 'country_id' => array(ts('Country'), $attributes['country_id'], NULL), + 'geo_code_1' => array(ts('Latitude'), array('size' => 9, 'maxlength' => 11), NULL), + 'geo_code_2' => array(ts('Longitude'), array('size' => 9, 'maxlength' => 11), NULL), + 'street_number' => array(ts('Street Number'), $attributes['street_number'], NULL), + 'street_name' => array(ts('Street Name'), $attributes['street_name'], NULL), + 'street_unit' => array(ts('Apt/Unit/Suite'), $attributes['street_unit'], NULL), + ); + + $stateCountryMap = array(); + foreach ($elements as $name => $v) { + list($title, $attributes, $select) = $v; + + $nameWithoutID = strpos($name, '_id') !== FALSE ? substr($name, 0, -3) : $name; + if (!CRM_Utils_Array::value($nameWithoutID, $addressOptions)) { + $continue = TRUE; + if (in_array($nameWithoutID, array( + 'street_number', 'street_name', 'street_unit')) && + CRM_Utils_Array::value('street_address_parsing', $addressOptions) + ) { + $continue = FALSE; + } + if ($continue) { + continue; + } + } + + if (!$attributes) { + $attributes = $attributes[$name]; + } + + //build normal select if country is not present in address block + if ($name == 'state_province_id' && !$addressOptions['country']) { + $select = 'stateProvince'; + } + + if (!$select) { + if ($name == 'country_id' || $name == 'state_province_id' || $name == 'county_id') { + if ($name == 'country_id') { + $stateCountryMap[$blockId]['country'] = "address_{$blockId}_{$name}"; + $selectOptions = array('' => ts('- select -')) + CRM_Core_PseudoConstant::country(); + } + elseif ($name == 'state_province_id') { + $stateCountryMap[$blockId]['state_province'] = "address_{$blockId}_{$name}"; + if ($countryDefault) { + $selectOptions = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($countryDefault); + } + else { + $selectOptions = array('' => ts('- select a country -')); + } + } + elseif ($name == 'county_id') { + $stateCountryMap[$blockId]['county'] = "address_{$blockId}_{$name}"; + if ($form->getSubmitValue("address[{$blockId}][state_province_id]")) { + $selectOptions = array('' => ts('- select -')) + CRM_Core_PseudoConstant::countyForState($form->getSubmitValue("address[{$blockId}][state_province_id]")); + } + elseif ($form->getSubmitValue("address[{$blockId}][county_id]")) { + $selectOptions = array('' => ts('- select a state -')) + CRM_Core_PseudoConstant::county(); + } + else { + $selectOptions = array('' => ts('- select a state -')); + } + } + $form->addElement('select', + "address[$blockId][$name]", + $title, + $selectOptions + ); + } + else { + if ($name == 'address_name') { + $name = 'name'; + } + + $form->addElement('text', + "address[$blockId][$name]", + $title, + $attributes + ); + } + } + else { + $form->addElement('select', + "address[$blockId][$name]", + $title, + array('' => ts('- select -')) + CRM_Core_PseudoConstant::$select() + ); + } + } + + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + + $entityId = NULL; + if (!empty($form->_values['address']) && CRM_Utils_Array::value($blockId, $form->_values['address'])) { + $entityId = $form->_values['address'][$blockId]['id']; + } + + // CRM-11665 geocode override option + $geoCode = FALSE; + if (!empty($config->geocodeMethod)) { + $geoCode = TRUE; + $form->addElement('checkbox', + "address[$blockId][manual_geo_code]", + ts('Override automatic geocoding') + ); + } + $form->assign('geoCode', $geoCode); + + // Process any address custom data - + $groupTree = CRM_Core_BAO_CustomGroup::getTree('Address', + $form, + $entityId + ); + + if (isset($groupTree) && is_array($groupTree)) { + // use simplified formatted groupTree + $groupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree, 1, $form); + + // make sure custom fields are added /w element-name in the format - 'address[$blockId][custom-X]' + foreach ($groupTree as $id => $group) { + foreach ($group['fields'] as $fldId => $field) { + $groupTree[$id]['fields'][$fldId]['element_custom_name'] = $field['element_name']; + $groupTree[$id]['fields'][$fldId]['element_name'] = "address[$blockId][{$field['element_name']}]"; + } + } + + $defaults = array(); + CRM_Core_BAO_CustomGroup::setDefaults($groupTree, $defaults); + + // since we change element name for address custom data, we need to format the setdefault values + $addressDefaults = array(); + foreach ($defaults as $key => $val) { + if ( empty( $val ) ) { + continue; + } + + // inorder to set correct defaults for checkbox custom data, we need to converted flat key to array + // this works for all types custom data + $keyValues = explode('[', str_replace(']', '', $key)); + $addressDefaults[$keyValues[0]][$keyValues[1]][$keyValues[2]] = $val; + } + + $form->setDefaults($addressDefaults); + + // we setting the prefix to 'dnc_' below, so that we don't overwrite smarty's grouptree var. + // And we can't set it to 'address_' because we want to set it in a slightly different format. + CRM_Core_BAO_CustomGroup::buildQuickForm($form, $groupTree, FALSE, 1, 'dnc_'); + + $template = CRM_Core_Smarty::singleton(); + $tplGroupTree = $template->get_template_vars('address_groupTree'); + $tplGroupTree = empty($tplGroupTree) ? array( + ) : $tplGroupTree; + + $form->assign('address_groupTree', $tplGroupTree + array($blockId => $groupTree)); + // unset the temp smarty var that got created + $form->assign('dnc_groupTree', NULL); + } + // address custom data processing ends .. + + if ($sharing) { + // shared address + $form->addElement('checkbox', "address[$blockId][use_shared_address]", NULL, ts('Use another contact\'s address')); + + // get the reserved for address + $profileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', 'shared_address', 'id', 'name'); + + if (!$profileId) { + CRM_Core_Error::fatal(ts('Your install is missing required "Shared Address" profile.')); + } + + CRM_Contact_Form_NewContact::buildQuickForm($form, $blockId, array($profileId)); + } + } + + /** + * check for correct state / country mapping. + * + * @param array reference $fields - submitted form values. + * @param array reference $errors - if any errors found add to this array. please. + * + * @return true if no errors + * array of errors if any present. + * + * @access public + * @static + */ + static function formRule($fields) { + $errors = array(); + // check for state/county match if not report error to user. + if (CRM_Utils_Array::value('address', $fields) && is_array($fields['address'])) { + foreach ($fields['address'] as $instance => $addressValues) { + if (CRM_Utils_System::isNull($addressValues)) { + continue; + } + + $countryId = CRM_Utils_Array::value('country_id', $addressValues); + $stateProvinceId = CRM_Utils_Array::value('state_province_id', $addressValues); + + //do check for mismatch countries + if ($stateProvinceId && $countryId) { + $stateProvinceDAO = new CRM_Core_DAO_StateProvince(); + $stateProvinceDAO->id = $stateProvinceId; + $stateProvinceDAO->find(TRUE); + if ($stateProvinceDAO->country_id != $countryId) { + // countries mismatch hence display error + $stateProvinces = CRM_Core_PseudoConstant::stateProvince(); + $countries = CRM_Core_PseudoConstant::country(); + $errors["address[$instance][state_province_id]"] = ts('State/Province %1 is not part of %2. It belongs to %3.', + array( + 1 => $stateProvinces[$stateProvinceId], + 2 => $countries[$countryId], + 3 => $countries[$stateProvinceDAO->country_id] + ) + ); + } + } + + $countyId = CRM_Utils_Array::value('county_id', $addressValues); + + //state county validation + if ($stateProvinceId && $countyId) { + $countyDAO = new CRM_Core_DAO_County(); + $countyDAO->id = $countyId; + $countyDAO->find(TRUE); + if ($countyDAO->state_province_id != $stateProvinceId) { + $counties = CRM_Core_PseudoConstant::county(); + $errors["address[$instance][county_id]"] = ts('County %1 is not part of %2. It belongs to %3.', + array( + 1 => $counties[$countyId], + 2 => $stateProvinces[$stateProvinceId], + 3 => $stateProvinces[$countyDAO->state_province_id] + ) + ); + } + } + + if (CRM_Utils_Array::value('use_shared_address', $addressValues) && !CRM_Utils_Array::value('master_id', $addressValues)) { + $errors["address[$instance][use_shared_address]"] = ts('Please select valid shared contact or a contact with valid address.'); + } + } + } + + return empty($errors) ? TRUE : $errors; + } + + static function fixStateSelect(&$form, + $countryElementName, + $stateElementName, + $countyElementName, + $countryDefaultValue, + $stateDefaultValue = NULL + ) { + $countryID = $stateID = NULL; + if (isset($form->_elementIndex[$countryElementName])) { + //get the country id to load states - + //first check for submitted value, + //then check for user passed value. + //finally check for element default val. + $submittedVal = $form->getSubmitValue($countryElementName); + if ($submittedVal) { + $countryID = $submittedVal; + } + elseif ($countryDefaultValue) { + $countryID = $countryDefaultValue; + } + else { + $countryID = CRM_Utils_Array::value(0, $form->getElementValue($countryElementName)); + } + } + + $stateTitle = ts('State/Province'); + if (isset($form->_fields[$stateElementName]['title'])) { + $stateTitle = $form->_fields[$stateElementName]['title']; + } + + if ($countryID && + isset($form->_elementIndex[$stateElementName]) + ) { + + $submittedValState = $form->getSubmitValue($stateElementName); + if ($submittedValState) { + $stateID = $submittedValState; + } + elseif ($stateDefaultValue) { + $stateID = $stateDefaultValue; + } + else { + $stateID = CRM_Utils_Array::value(0, $form->getElementValue($stateElementName)); + } + + $stateSelect = &$form->addElement('select', + $stateElementName, + $stateTitle, + array( + '' => ts('- select -')) + + CRM_Core_PseudoConstant::stateProvinceForCountry($countryID) + ); + + + if ($stateID && + isset($form->_elementIndex[$stateElementName]) && + isset($form->_elementIndex[$countyElementName]) + ) { + $form->addElement('select', + $countyElementName, + ts('County'), + array( + '' => ts('- select -')) + + CRM_Core_PseudoConstant::countyForState($stateID) + ); + } + + // CRM-7296 freeze the select for state if address is shared with household + // CRM-9070 freeze the select for state if it is view only + if (isset($form->_fields) && + CRM_Utils_Array::value($stateElementName, $form->_fields) && + (CRM_Utils_Array::value('is_shared', $form->_fields[$stateElementName]) || + CRM_Utils_Array::value('is_view', $form->_fields[$stateElementName])) + ) { + $stateSelect->freeze(); + } + } + } + + /** + * function to set default values for address block + * + * @param array $defaults defaults associated array + * @param object $form form object + * + * @static + * @access public + */ + static function setDefaultValues( &$defaults, &$form ) { + $addressValues = array(); + if (isset($defaults['address']) && is_array($defaults['address']) && + !CRM_Utils_system::isNull($defaults['address']) + ) { + + // start of contact shared adddress defaults + $sharedAddresses = array(); + $masterAddress = array(); + + // get contact name of shared contact names + $shareAddressContactNames = CRM_Contact_BAO_Contact_Utils::getAddressShareContactNames($defaults['address']); + + foreach ($defaults['address'] as $key => $addressValue) { + if (CRM_Utils_Array::value('master_id', $addressValue) && !$shareAddressContactNames[$addressValue['master_id']]['is_deleted']) { + $sharedAddresses[$key]['shared_address_display'] = array( + 'address' => $addressValue['display'], + 'name' => $shareAddressContactNames[$addressValue['master_id']]['name'], + ); + } + else { + $defaults['address'][$key]['use_shared_address'] = 0; + } + + //check if any address is shared by any other contacts + $masterAddress[$key] = CRM_Core_BAO_Address::checkContactSharedAddress($addressValue['id']); + } + + $form->assign('sharedAddresses', $sharedAddresses); + $form->assign('masterAddress', $masterAddress); + // end of shared address defaults + + // start of parse address functionality + // build street address, CRM-5450. + if ($form->_parseStreetAddress) { + $parseFields = array('street_address', 'street_number', 'street_name', 'street_unit'); + foreach ($defaults['address'] as $cnt => & $address) { + $streetAddress = NULL; + foreach (array( + 'street_number', 'street_number_suffix', 'street_name', 'street_unit') as $fld) { + if (in_array($fld, array( + 'street_name', 'street_unit'))) { + $streetAddress .= ' '; + } + $streetAddress .= CRM_Utils_Array::value($fld, $address); + } + $streetAddress = trim($streetAddress); + if (!empty($streetAddress)) { + $address['street_address'] = $streetAddress; + } + if (isset($address['street_number'])) { + $address['street_number'] .= CRM_Utils_Array::value('street_number_suffix', $address); + } + + // build array for set default. + foreach ($parseFields as $field) { + $addressValues["{$field}_{$cnt}"] = CRM_Utils_Array::value($field, $address); + } + + // don't load fields, use js to populate. + foreach (array('street_number', 'street_name', 'street_unit') as $f) { + if (isset($address[$f])) { + unset($address[$f]); + } + } + } + $form->assign('allAddressFieldValues', json_encode($addressValues)); + + //hack to handle show/hide address fields. + $parsedAddress = array(); + if ($form->_contactId && + CRM_Utils_Array::value('address', $_POST) + && is_array($_POST['address']) + ) { + foreach ($_POST['address'] as $cnt => $values) { + $showField = 'streetAddress'; + foreach (array('street_number', 'street_name', 'street_unit') as $fld) { + if (CRM_Utils_Array::value($fld, $values)) { + $showField = 'addressElements'; + break; + } + } + $parsedAddress[$cnt] = $showField; + } + } + $form->assign('showHideAddressFields', $parsedAddress); + $form->assign('loadShowHideAddressFields', empty($parsedAddress) ? FALSE : TRUE); + } + // end of parse address functionality + } + } +} + diff --git a/CRM/Contact/Form/Edit/CommunicationPreferences.php b/CRM/Contact/Form/Edit/CommunicationPreferences.php new file mode 100644 index 0000000000..3c784c66e6 --- /dev/null +++ b/CRM/Contact/Form/Edit/CommunicationPreferences.php @@ -0,0 +1,238 @@ + $label) { + $privacy[] = $form->createElement('advcheckbox', $name, NULL, $label); + } + $form->addGroup($privacy, 'privacy', ts('Privacy'), ' '); + + // preferred communication method + $comm = CRM_Core_PseudoConstant::pcm(TRUE); + foreach ($comm as $value => $title) { + $commPreff[] = $form->createElement('advcheckbox', $value, NULL, $title); + } + $form->addGroup($commPreff, 'preferred_communication_method', ts('Preferred Method(s)')); + + $form->add('select', 'preferred_language', + ts('Preferred Language'), + array( + '' => ts('- select -')) + + CRM_Core_PseudoConstant::languages() + ); + + if (!empty($privacyOptions)) { + $commPreference['privacy'] = $privacyOptions; + } + if (!empty($comm)) { + $commPreference['preferred_communication_method'] = $comm; + } + + //using for display purpose. + $form->assign('commPreference', $commPreference); + + $form->add('select', 'preferred_mail_format', ts('Email Format'), CRM_Core_SelectValues::pmf()); + $form->add('checkbox', 'is_opt_out', ts('NO BULK EMAILS (User Opt Out)')); + + //check contact type and build filter clause accordingly for greeting types, CRM-4575 + $greetings = self::getGreetingFields($form->_contactType); + + foreach ($greetings as $greeting => $fields) { + $filter = array( + 'contact_type' => $form->_contactType, + 'greeting_type' => $greeting, + ); + + //add addressee in Contact form + $greetingTokens = CRM_Core_PseudoConstant::greeting($filter); + if (!empty($greetingTokens)) { + $form->addElement('select', $fields['field'], $fields['label'], + array( + '' => ts('- select -')) + $greetingTokens + ); + //custom addressee + $form->addElement('text', $fields['customField'], $fields['customLabel'], + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', $fields['customField']), $fields['js'] + ); + } + } + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + //CRM-4575 + + $greetings = self::getGreetingFields($self->_contactType); + foreach ($greetings as $greeting => $details) { + $customizedValue = CRM_Core_OptionGroup::getValue($greeting, 'Customized', 'name'); + if (CRM_Utils_Array::value($details['field'], $fields) == $customizedValue + && !CRM_Utils_Array::value($details['customField'], $fields) + ) { + $errors[$details['customField']] = ts('Custom %1 is a required field if %1 is of type Customized.', + array(1 => $details['label']) + ); + } + } + return empty($errors) ? TRUE : $errors; + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form, &$defaults) { + + if (!empty($defaults['preferred_language'])) { + $languages = array_flip(CRM_Core_PseudoConstant::languages()); + $defaults['preferred_language'] = $languages[$defaults['preferred_language']]; + } + + // CRM-7119: set preferred_language to default if unset + if (empty($defaults['preferred_language'])) { + $config = CRM_Core_Config::singleton(); + $defaults['preferred_language'] = $config->lcMessages; + } + + //set default from greeting types CRM-4575, CRM-9739 + if ($form->_action & CRM_Core_Action::ADD) { + foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) { + if (empty($defaults[$greeting . '_id'])) { + if ($defaultGreetingTypeId = + CRM_Contact_BAO_Contact_Utils::defaultGreeting($form->_contactType, $greeting) + ) { + $defaults[$greeting . '_id'] = $defaultGreetingTypeId; + } + } + } + } + else { + foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) { + $name = "{$greeting}_display"; + $form->assign($name, CRM_Utils_Array::value($name, $defaults)); + } + } + } + + /** + * set array of greeting fields + * + * @return None + * @access public + */ + static function getGreetingFields($contactType) { + if (empty(self::$greetings[$contactType])) { + self::$greetings[$contactType] = array(); + + $js = array( + 'onfocus' => "if (!this.value) { this.value='Dear ';} else return false", + 'onblur' => "if ( this.value == 'Dear') { this.value='';} else return false", + ); + + self::$greetings[$contactType] = array( + 'addressee' => array( + 'field' => 'addressee_id', + 'customField' => 'addressee_custom', + 'label' => ts('Addressee'), + 'customLabel' => ts('Custom Addressee'), + 'js' => NULL, + ), + 'email_greeting' => array( + 'field' => 'email_greeting_id', + 'customField' => 'email_greeting_custom', + 'label' => ts('Email Greeting'), + 'customLabel' => ts('Custom Email Greeting'), + 'js' => $js, + ), + 'postal_greeting' => array( + 'field' => 'postal_greeting_id', + 'customField' => 'postal_greeting_custom', + 'label' => ts('Postal Greeting'), + 'customLabel' => ts('Custom Postal Greeting'), + 'js' => $js, + ), + ); + } + + return self::$greetings[$contactType]; + } +} + diff --git a/CRM/Contact/Form/Edit/CustomData.php b/CRM/Contact/Form/Edit/CustomData.php new file mode 100644 index 0000000000..1492ab1176 --- /dev/null +++ b/CRM/Contact/Form/Edit/CustomData.php @@ -0,0 +1,116 @@ +_type = CRM_Utils_Request::retrieve('type', 'String', CRM_Core_DAO::$_nullObject); + $form->_subType = CRM_Utils_Request::retrieve('subType', 'String', CRM_Core_DAO::$_nullObject); + + //build the custom data as other blocks. + //$form->assign( "addBlock", false ); + if ($form->_type) { + $form->_addBlockName = 'CustomData'; + $form->assign("addBlock", TRUE); + $form->assign("blockName", $form->_addBlockName); + } + + CRM_Custom_Form_CustomData::preProcess($form, NULL, $form->_subType, NULL, + ($form->_type) ? $form->_type : $form->_contactType + ); + + //assign group tree after build. + $form->assign('groupTree', $form->_groupTree); + } + + /** + * build the form elements for CustomData object + * + * @param CRM_Core_Form $form reference to the form object + * + * @return void + * @access public + * @static + */ + static function buildQuickForm(&$form) { + if(!empty($form->_submitValues)) { + if ($customValueCount = CRM_Utils_Array::value('hidden_custom_group_count', $form->_submitValues)) { + if (is_array($customValueCount)) { + if (array_key_exists(0, $customValueCount)) { + unset($customValueCount[0]); + } + $form->_customValueCount = $customValueCount; + $form->assign( 'customValueCount', $customValueCount); + } + } + } + CRM_Custom_Form_CustomData::buildQuickForm($form); + + //build custom data. + $contactSubType = NULL; + if (CRM_Utils_Array::value("hidden_custom", $_POST) && + CRM_Utils_Array::value('contact_sub_type', $_POST) + ) { + $contactSubType = $_POST['contact_sub_type']; + } + else { + $contactSubType = CRM_Utils_Array::value('contact_sub_type', $form->_values); + } + $form->assign('contactType', $form->_contactType); + $form->assign('contactSubType', $contactSubType); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form, &$defaults) { + $defaults += CRM_Custom_Form_CustomData::setDefaultValues($form); + } +} + diff --git a/CRM/Contact/Form/Edit/Demographics.php b/CRM/Contact/Form/Edit/Demographics.php new file mode 100644 index 0000000000..6be0f77597 --- /dev/null +++ b/CRM/Contact/Form/Edit/Demographics.php @@ -0,0 +1,78 @@ + $var) { + $genderOptions[$key] = $form->createElement('radio', NULL, + ts('Gender'), $var, $key, + array('id' => "civicrm_gender_{$var}_{$key}") + ); + } + $form->addGroup($genderOptions, 'gender_id', ts('Gender')); + + $form->addDate('birth_date', ts('Date of birth'), FALSE, array('formatType' => 'birth')); + + $form->addElement('checkbox', 'is_deceased', NULL, ts('Contact is deceased'), array('onclick' => "showDeceasedDate()")); + $form->addDate('deceased_date', ts('Deceased date'), FALSE, array('formatType' => 'birth')); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + static function setDefaultValues(&$form, &$defaults) {} +} + diff --git a/CRM/Contact/Form/Edit/Email.php b/CRM/Contact/Form/Edit/Email.php new file mode 100644 index 0000000000..b272d5da82 --- /dev/null +++ b/CRM/Contact/Form/Edit/Email.php @@ -0,0 +1,119 @@ +get('Email_Block_Count')) ? $form->get('Email_Block_Count') : 1; + } + else { + $blockId = $blockCount; + } + + $form->applyFilter('__ALL__', 'trim'); + + //Email box + $form->addElement('text', "email[$blockId][email]", ts('Email'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', 'email')); + $form->addRule("email[$blockId][email]", ts('Email is not valid.'), 'email'); + if (isset($form->_contactType) || $blockEdit) { + //Block type + $form->addElement('select', "email[$blockId][location_type_id]", '', CRM_Core_PseudoConstant::locationType()); + + $multipleBulk = CRM_Core_BAO_Email::isMultipleBulkMail(); + + //On-hold select + if ($multipleBulk) { + $holdOptions = array(0 => ts('- select -'), + 1 => ts('On Hold Bounce'), + 2 => ts('On Hold Opt Out'), + ); + $form->addElement('select', "email[$blockId][on_hold]", '', $holdOptions); + } + else { + $form->addElement('advcheckbox', "email[$blockId][on_hold]", NULL); + } + + //Bulkmail checkbox + $form->assign('multipleBulk', $multipleBulk); + if ($multipleBulk) { + $js = array('id' => "Email_" . $blockId . "_IsBulkmail"); + $form->addElement('advcheckbox', "email[$blockId][is_bulkmail]", NULL, '', $js); + } + else { + $js = array('id' => "Email_" . $blockId . "_IsBulkmail"); + if (!$blockEdit) { + $js['onClick'] = 'singleSelect( this.id );'; + } + $form->addElement('radio', "email[$blockId][is_bulkmail]", '', '', '1', $js); + } + + //is_Primary radio + $js = array('id' => "Email_" . $blockId . "_IsPrimary"); + if (!$blockEdit) { + $js['onClick'] = 'singleSelect( this.id );'; + } + + $form->addElement('radio', "email[$blockId][is_primary]", '', '', '1', $js); + + if (CRM_Utils_System::getClassName($form) == 'CRM_Contact_Form_Contact') { + + $form->add('textarea', "email[$blockId][signature_text]", ts('Signature (Text)'), + array('rows' => 2, 'cols' => 40) + ); + + $form->addWysiwyg("email[$blockId][signature_html]", ts('Signature (HTML)'), + array('rows' => 2, 'cols' => 40) + ); + } + } + } +} + diff --git a/CRM/Contact/Form/Edit/Household.php b/CRM/Contact/Form/Edit/Household.php new file mode 100644 index 0000000000..c122d2a933 --- /dev/null +++ b/CRM/Contact/Form/Edit/Household.php @@ -0,0 +1,104 @@ +applyFilter('__ALL__', 'trim'); + + if ( !$inlineEditMode || $inlineEditMode == 1 ) { + // household_name + $form->add('text', 'household_name', ts('Household Name'), $attributes['household_name']); + } + + if ( !$inlineEditMode || $inlineEditMode == 2 ) { + // nick_name + $form->addElement('text', 'nick_name', ts('Nickname'), $attributes['nick_name']); + $form->addElement('text', 'contact_source', ts('Source'), CRM_Utils_Array::value('source', $attributes)); + } + + if ( !$inlineEditMode ) { + $form->add('text', 'external_identifier', ts('External Id'), $attributes['external_identifier'], FALSE); + $form->addRule('external_identifier', + ts('External ID already exists in Database.'), + 'objectExists', + array('CRM_Contact_DAO_Contact', $form->_contactId, 'external_identifier') + ); + } + } + + /** + * add rule for household + * + * @params array $fields array of form values + * + * @return $error + * @static + * @public + */ + static function formRule($fields, $files, $contactID = NULL) { + $errors = array(); + $primaryID = CRM_Contact_Form_Contact::formRule($fields, $errors, $contactID); + + // make sure that household name is set + if (!CRM_Utils_Array::value('household_name', $fields)) { + $errors['household_name'] = 'Household Name should be set.'; + } + + //check for duplicate - dedupe rules + CRM_Contact_Form_Contact::checkDuplicateContacts($fields, $errors, $contactID, 'Household'); + + return empty($errors) ? TRUE : $errors; + } +} + diff --git a/CRM/Contact/Form/Edit/IM.php b/CRM/Contact/Form/Edit/IM.php new file mode 100644 index 0000000000..f0eb69d6bb --- /dev/null +++ b/CRM/Contact/Form/Edit/IM.php @@ -0,0 +1,81 @@ +get('IM_Block_Count')) ? $form->get('IM_Block_Count') : 1; + } + else { + $blockId = $blockCount; + } + $form->applyFilter('__ALL__', 'trim'); + + //IM provider select + $form->addElement('select', "im[$blockId][provider_id]", '', CRM_Core_PseudoConstant::IMProvider()); + + //Block type select + $form->addElement('select', "im[$blockId][location_type_id]", '', CRM_Core_PseudoConstant::locationType()); + + //IM box + $form->addElement('text', "im[$blockId][name]", ts('Instant Messenger'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_IM', 'name') + ); + + //is_Primary radio + $js = array('id' => 'IM_' . $blockId . '_IsPrimary'); + if (!$blockEdit) { + $js['onClick'] = 'singleSelect( this.id );'; + } + + $form->addElement('radio', "im[$blockId][is_primary]", '', '', '1', $js); + } +} + diff --git a/CRM/Contact/Form/Edit/Individual.php b/CRM/Contact/Form/Edit/Individual.php new file mode 100644 index 0000000000..975c8bdae9 --- /dev/null +++ b/CRM/Contact/Form/Edit/Individual.php @@ -0,0 +1,157 @@ +applyFilter('__ALL__', 'trim'); + + if ( !$inlineEditMode || $inlineEditMode == 1 ) { + //prefix + $prefix = CRM_Core_PseudoConstant::individualPrefix(); + if (!empty($prefix)) { + $form->addElement('select', 'prefix_id', ts('Prefix'), array('' => '') + $prefix); + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact'); + + // first_name + $form->addElement('text', 'first_name', ts('First Name'), $attributes['first_name']); + + //middle_name + $form->addElement('text', 'middle_name', ts('Middle Name'), $attributes['middle_name']); + + // last_name + $form->addElement('text', 'last_name', ts('Last Name'), $attributes['last_name']); + + // suffix + $suffix = CRM_Core_PseudoConstant::individualSuffix(); + if ($suffix) { + $form->addElement('select', 'suffix_id', ts('Suffix'), array('' => '') + $suffix); + } + } + + if ( !$inlineEditMode || $inlineEditMode == 2 ) { + // nick_name + $form->addElement('text', 'nick_name', ts('Nickname'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'nick_name') + ); + + // job title + // override the size for UI to look better + $attributes['job_title']['size'] = 30; + $form->addElement('text', 'job_title', ts('Job Title'), $attributes['job_title'], 'size="30"'); + + //Current Employer Element + $employerDataURL = CRM_Utils_System::url('civicrm/ajax/rest', 'className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&context=contact&org=1&employee_id=' . $form->_contactId, FALSE, NULL, FALSE); + $form->assign('employerDataURL', $employerDataURL); + + $form->addElement('text', 'current_employer', ts('Current Employer'), ''); + $form->addElement('hidden', 'current_employer_id', '', array('id' => 'current_employer_id')); + $form->addElement('text', 'contact_source', ts('Source'), CRM_Utils_Array::value('source', $attributes)); + } + + if ( !$inlineEditMode ) { + $checkSimilar = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_ajax_check_similar', + NULL, + TRUE + ); + + if ( $checkSimilar == null ) { + $checkSimilar = 0; + } + $form->assign('checkSimilar', $checkSimilar); + + //External Identifier Element + $form->add('text', 'external_identifier', ts('External Id'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'external_identifier'), FALSE + ); + + $form->addRule('external_identifier', + ts('External ID already exists in Database.'), + 'objectExists', + array('CRM_Contact_DAO_Contact', $form->_contactId, 'external_identifier') + ); + $config = CRM_Core_Config::singleton(); + CRM_Core_ShowHideBlocks::links($form, 'demographics', '', ''); + } + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $contactID = NULL) { + $errors = array(); + $primaryID = CRM_Contact_Form_Contact::formRule($fields, $errors, $contactID); + + // make sure that firstName and lastName or a primary OpenID is set + if (!$primaryID && (!CRM_Utils_Array::value('first_name', $fields) || + !CRM_Utils_Array::value('last_name', $fields) + )) { + $errors['_qf_default'] = ts('First Name and Last Name OR an email OR an OpenID in the Primary Location should be set.'); + } + + //check for duplicate - dedupe rules + CRM_Contact_Form_Contact::checkDuplicateContacts($fields, $errors, $contactID, 'Individual'); + + return empty($errors) ? TRUE : $errors; + } +} + diff --git a/CRM/Contact/Form/Edit/Lock.php b/CRM/Contact/Form/Edit/Lock.php new file mode 100644 index 0000000000..d45b7d1d2c --- /dev/null +++ b/CRM/Contact/Form/Edit/Lock.php @@ -0,0 +1,80 @@ +addElement('hidden', 'modified_date', '', array('id' => 'modified_date')); + } + + /** + * Ensure that modified_date hasn't changed in the underlying DB + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $contactID = NULL) { + $errors = array(); + + $timestamps = CRM_Contact_BAO_Contact::getTimestamps($contactID); + if ($fields['modified_date'] != $timestamps['modified_date']) { + // Inline buttons generated via JS + $open = sprintf("", $timestamps['modified_date']); + $close = ""; + $errors['modified_date'] = $open . ts('This record was modified by another user!') . $close; + } + + return empty($errors) ? TRUE : $errors; + } +} diff --git a/CRM/Contact/Form/Edit/Notes.php b/CRM/Contact/Form/Edit/Notes.php new file mode 100644 index 0000000000..35027aa5af --- /dev/null +++ b/CRM/Contact/Form/Edit/Notes.php @@ -0,0 +1,50 @@ +applyFilter('__ALL__', 'trim'); + $form->add('text', 'subject', ts('Subject'), array('size' => 60, 'maxlength' => 254)); + $form->add('textarea', 'note', ts('Notes'), array('cols' => '60', 'rows' => '3')); + } +} + diff --git a/CRM/Contact/Form/Edit/OpenID.php b/CRM/Contact/Form/Edit/OpenID.php new file mode 100644 index 0000000000..97338e75f3 --- /dev/null +++ b/CRM/Contact/Form/Edit/OpenID.php @@ -0,0 +1,78 @@ +get('OpenID_Block_Count')) ? $form->get('OpenID_Block_Count') : 1; + } + else { + $blockId = $blockCount; + } + $form->applyFilter('__ALL__', 'trim'); + + $form->addElement('text', "openid[$blockId][openid]", ts('OpenID'), + CRM_Core_DAO::getAttribute('CRM_Core_DAO_OpenID', 'openid') + ); + $form->addRule("openid[$blockId][openid]", ts('OpenID is not a valid URL.'), 'url'); + + //Block type + $form->addElement('select', "openid[$blockId][location_type_id]", '', CRM_Core_PseudoConstant::locationType()); + + //is_Primary radio + $js = array('id' => "OpenID_" . $blockId . "_IsPrimary"); + if (!$blockEdit) { + $js['onClick'] = 'singleSelect( this.id );'; + } + + $form->addElement('radio', "openid[$blockId][is_primary]", '', '', '1', $js); + } +} + diff --git a/CRM/Contact/Form/Edit/Organization.php b/CRM/Contact/Form/Edit/Organization.php new file mode 100644 index 0000000000..c895e833aa --- /dev/null +++ b/CRM/Contact/Form/Edit/Organization.php @@ -0,0 +1,105 @@ +applyFilter('__ALL__', 'trim'); + + if ( !$inlineEditMode || $inlineEditMode == 1 ) { + // Organization_name + $form->add('text', 'organization_name', ts('Organization Name'), $attributes['organization_name']); + } + + if ( !$inlineEditMode || $inlineEditMode == 2 ) { + // legal_name + $form->addElement('text', 'legal_name', ts('Legal Name'), $attributes['legal_name']); + + // nick_name + $form->addElement('text', 'nick_name', ts('Nickname'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'nick_name') + ); + + // sic_code + $form->addElement('text', 'sic_code', ts('SIC Code'), $attributes['sic_code']); + + $form->addElement('text', 'contact_source', ts('Source'), CRM_Utils_Array::value('source', $attributes)); + } + + if ( !$inlineEditMode ) { + $form->add('text', 'external_identifier', ts('External Id'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'external_identifier'), FALSE); + $form->addRule('external_identifier', + ts('External ID already exists in Database.'), + 'objectExists', + array('CRM_Contact_DAO_Contact', $form->_contactId, 'external_identifier') + ); + } + } + + static function formRule($fields, $files, $contactID = NULL) { + $errors = array(); + $primaryID = CRM_Contact_Form_Contact::formRule($fields, $errors, $contactID); + + // make sure that organization name is set + if (!CRM_Utils_Array::value('organization_name', $fields)) { + $errors['organization_name'] = 'Organization Name should be set.'; + } + + //check for duplicate - dedupe rules + CRM_Contact_Form_Contact::checkDuplicateContacts($fields, $errors, $contactID, 'Organization'); + + // add code to make sure that the uniqueness criteria is satisfied + return empty($errors) ? TRUE : $errors; + } +} + diff --git a/CRM/Contact/Form/Edit/Phone.php b/CRM/Contact/Form/Edit/Phone.php new file mode 100644 index 0000000000..1cd598eb2b --- /dev/null +++ b/CRM/Contact/Form/Edit/Phone.php @@ -0,0 +1,83 @@ +get('Phone_Block_Count')) ? $form->get('Phone_Block_Count') : 1; + } + else { + $blockId = $addressBlockCount; + } + + $form->applyFilter('__ALL__', 'trim'); + + //phone type select + $form->addElement('select', "phone[$blockId][phone_type_id]", ts('Phone'), CRM_Core_PseudoConstant::phoneType()); + + //main phone number with crm_phone class + $form->addElement('text', "phone[$blockId][phone]", ts('Phone'), array_merge(CRM_Core_DAO::getAttribute('CRM_Core_DAO_Phone', 'phone'), array('class' => 'crm_phone twelve'))); + // phone extension + $form->addElement('text', "phone[$blockId][phone_ext]", ts('Extension'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Phone', 'phone_ext')); + + if (isset($form->_contactType) || $blockEdit) { + //Block type select + $form->addElement('select', "phone[$blockId][location_type_id]", '', CRM_Core_PseudoConstant::locationType()); + + //is_Primary radio + $js = array('id' => 'Phone_' . $blockId . '_IsPrimary', 'onClick' => 'singleSelect( this.id );'); + $form->addElement('radio', "phone[$blockId][is_primary]", '', '', '1', $js); + } + // TODO: set this up as a group, we need a valid phone_type_id if we have a phone number + // $form->addRule( "location[$locationId][phone][$locationId][phone]", ts('Phone number is not valid.'), 'phone' ); + } +} + diff --git a/CRM/Contact/Form/Edit/TagsAndGroups.php b/CRM/Contact/Form/Edit/TagsAndGroups.php new file mode 100644 index 0000000000..1a1fc24564 --- /dev/null +++ b/CRM/Contact/Form/Edit/TagsAndGroups.php @@ -0,0 +1,227 @@ +_tagGroup)) { + $form->_tagGroup = array(); + } + + // NYSS 5670 + if (!$contactId && !empty($form->_contactId)) { + $contactId = $form->_contactId; + } + + $type = (int ) $type; + if ($type & CRM_Contact_Form_Edit_TagsandGroups::GROUP) { + + $fName = 'group'; + if ($fieldName) { + $fName = $fieldName; + } + + $elements = array(); + $groupID = isset($form->_grid) ? $form->_grid : NULL; + if ($groupID && $visibility) { + $ids = "= {$groupID}"; + } + else { + if ($visibility) { + $group = CRM_Core_PseudoConstant::allGroup(); + } + else { + $group = CRM_Core_PseudoConstant::group(); + } + $ids = implode(',', array_keys($group)); + $ids = 'IN (' . $ids . ')'; + } + + if ($groupID || !empty($group)) { + $groups = CRM_Contact_BAO_Group::getGroupsHierarchy($ids); + + $attributes['skiplabel'] = TRUE; + foreach ($groups as $id => $group) { + // make sure that this group has public visibility + if ($visibility && + $group['visibility'] == 'User and User Admin Only' + ) { + continue; + } + $form->_tagGroup[$fName][$id]['description'] = $group['description']; + $elements[] = &$form->addElement('advcheckbox', $id, NULL, $group['title'], $attributes); + } + + if (!empty($elements)) { + $form->addGroup($elements, $fName, $groupName, ' 
    '); + $form->assign('groupCount', count($elements)); + if ($isRequired) { + $form->addRule($fName, ts('%1 is a required field.', array(1 => $groupName)), 'required'); + } + } + } + } + + if ($type & CRM_Contact_Form_Edit_TagsandGroups::TAG) { + $fName = 'tag'; + if ($fieldName) { + $fName = $fieldName; + } + $form->_tagGroup[$fName] = 1; + $elements = array(); + $tag = CRM_Core_BAO_Tag::getTags(); + + foreach ($tag as $id => $name) { + $elements[] = $form->createElement('checkbox', $id, NULL, $name); + } + if (!empty($elements)) { + $form->addGroup($elements, $fName, $tagName, '
    '); + $form->assign('tagCount', count($elements)); + } + + if ($isRequired) { + $form->addRule($fName, ts('%1 is a required field.', array(1 => $tagName)), 'required'); + } + + // build tag widget + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_contact'); + + CRM_Core_Form_Tag::buildQuickForm($form, $parentNames, 'civicrm_contact', $contactId, FALSE, TRUE); + } + $form->assign('tagGroup', $form->_tagGroup); + } + + /** + * set defaults for relevant form elements + * + * @param int $id the contact id + * @param array $defaults the defaults array to store the values in + * @param int $type what components are we interested in + * @param string $fieldName this is used in batch profile(i.e to build multiple blocks) + * + * @return void + * @access public + * @static + */ + static function setDefaults($id, &$defaults, $type = CRM_Contact_Form_Edit_TagsandGroups::ALL, $fieldName = NULL) { + $type = (int ) $type; + if ($type & self::GROUP) { + $fName = 'group'; + if ($fieldName) { + $fName = $fieldName; + } + + $contactGroup = CRM_Contact_BAO_GroupContact::getContactGroup($id, 'Added', NULL, FALSE, TRUE); + if ($contactGroup) { + foreach ($contactGroup as $group) { + $defaults[$fName . '[' . $group['group_id'] . ']'] = 1; + } + } + } + + if ($type & self::TAG) { + $fName = 'tag'; + if ($fieldName) { + $fName = $fieldName; + } + + $contactTag = CRM_Core_BAO_EntityTag::getTag($id); + if ($contactTag) { + foreach ($contactTag as $tag) { + $defaults[$fName . '[' . $tag . ']'] = 1; + } + } + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + public static function setDefaultValues(&$form, &$defaults) { + $contactEditOptions = $form->get('contactEditOptions'); + if ($form->_action & CRM_Core_Action::ADD) { + if (array_key_exists('TagsAndGroups', $contactEditOptions)) { + // set group and tag defaults if any + if ($form->_gid) { + $defaults['group'][$form->_gid] = 1; + } + if ($form->_tid) { + $defaults['tag'][$form->_tid] = 1; + } + } + } + else { + if (array_key_exists('TagsAndGroups', $contactEditOptions)) { + // set the group and tag ids + self::setDefaults($form->_contactId, $defaults, self::ALL); + } + } + } +} + diff --git a/CRM/Contact/Form/Edit/Website.php b/CRM/Contact/Form/Edit/Website.php new file mode 100644 index 0000000000..a2c4de4d81 --- /dev/null +++ b/CRM/Contact/Form/Edit/Website.php @@ -0,0 +1,78 @@ +get('Website_Block_Count')) ? $form->get('Website_Block_Count') : 1; + } + else { + $blockId = $blockCount; + } + + $form->applyFilter('__ALL__', 'trim'); + + //Website type select + $form->addElement('select', "website[$blockId][website_type_id]", '', CRM_Core_PseudoConstant::websiteType()); + + //Website box + $form->addElement('text', "website[$blockId][url]", ts('Website'), + array_merge( + CRM_Core_DAO::getAttribute('CRM_Core_DAO_Website', 'url'), + array( + 'onfocus' => "if (!this.value) { this.value='http://';} else return false", + 'onblur' => "if ( this.value == 'http://') { this.value='';} else return false", + ) + ) + ); + + $form->addRule("website[$blockId][url]", ts('Enter a valid web location beginning with \'http://\' or \'https://\'. EXAMPLE: http://www.mysite.org/'), 'url'); + } +} + diff --git a/CRM/Contact/Form/GroupContact.php b/CRM/Contact/Form/GroupContact.php new file mode 100644 index 0000000000..ba7ec81bed --- /dev/null +++ b/CRM/Contact/Form/GroupContact.php @@ -0,0 +1,170 @@ +_contactId = $this->get('contactId'); + $this->_groupContactId = $this->get('groupContactId'); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + } + + /** + * This function sets the default values for the form. GroupContact that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + $params = array(); + + return $defaults; + } + + /** + * This function is used to add the rules for form. + * + * @return None + * @access public + */ + function addRules() {} + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + // get the list of all the groups + if ($this->_context == 'user') { + $onlyPublicGroups = CRM_Utils_Request::retrieve('onlyPublicGroups', 'Boolean', $this, FALSE); + $allGroups = CRM_Core_PseudoConstant::staticGroup($onlyPublicGroups); + } + else { + $allGroups = CRM_Core_PseudoConstant::group(); + } + + // Arrange groups into hierarchical listing (child groups follow their parents and have indentation spacing in title) + $ids = implode(',', array_keys($allGroups)); + $ids = 'IN (' . $ids . ')'; + $groupHierarchy = CRM_Contact_BAO_Group::getGroupsHierarchy($ids, NULL, '  ', TRUE); + + // get the list of groups contact is currently in ("Added") or unsubscribed ("Removed"). + $currentGroups = CRM_Contact_BAO_GroupContact::getGroupList($this->_contactId); + + // Remove current groups from drowdown options ($groupSelect) + if (is_array($currentGroups)) { + // Compare array keys, since the array values (group title) in $groupList may have extra spaces for indenting child groups + $groupSelect = array_diff_key($groupHierarchy, $currentGroups); + } + else { + $groupSelect = $groupHierarchy; + } + + $groupSelect = array( '' => ts('- select group -')) + $groupSelect; + + if (count($groupSelect) > 1) { + $session = CRM_Core_Session::singleton(); + // user dashboard + if (strstr($session->readUserContext(), 'user')) { + $msg = ts('Join a Group'); + } + else { + $msg = ts('Add to a group'); + } + + $this->add('select', 'group_id', $msg, $groupSelect, TRUE); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Add'), + 'isDefault' => TRUE, + ), + ) + ); + } + } + + /** + * + * @access public + * + * @return None + */ + public function postProcess() { + $contactID = array($this->_contactId); + $groupId = $this->controller->exportValue('GroupContact', 'group_id'); + $method = 'Admin'; + $method = ($this->_context == 'user') ? 'Web' : 'Admin'; + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + + if ($userID == $this->_contactId) { + $method = 'Web'; + } + $groupContact = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactID, $groupId, $method); + + if ($groupContact && $this->_context != 'user') { + $groups = CRM_Core_PseudoConstant::group(); + CRM_Core_Session::setStatus(ts("Contact has been added to '%1'.", array(1 => $groups[$groupId])), ts('Added to Group'), 'success'); + } + } + //end of function +} + diff --git a/CRM/Contact/Form/Inline.php b/CRM/Contact/Form/Inline.php new file mode 100644 index 0000000000..401e0ebc7b --- /dev/null +++ b/CRM/Contact/Form/Inline.php @@ -0,0 +1,183 @@ +_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE, NULL, $_REQUEST); + $this->assign('contactId', $this->_contactId); + + // get contact type and subtype + if (empty($this->_contactType)) { + $contactTypeInfo = CRM_Contact_BAO_Contact::getContactTypes($this->_contactId); + $this->_contactType = $contactTypeInfo[0]; + + // check if subtype is set + if (isset($contactTypeInfo[1])) { + // unset contact type which is 0th element + unset($contactTypeInfo[0]); + $this->_contactSubType = $contactTypeInfo; + } + } + + $this->assign('contactType', $this->_contactType); + } + + /** + * Common form elements + * + * @return void + * @access public + */ + public function buildQuickForm() { + CRM_Contact_Form_Inline_Lock::buildQuickForm($this, $this->_contactId); + + $buttons = array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ); + $this->addButtons($buttons); + } + + /** + * Override default cancel action + * + * @return void + * @access public + */ + public function cancelAction() { + $response = array('status' => 'cancel'); + echo json_encode($response); + CRM_Utils_System::civiExit(); + } + + /** + * Set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = $params = array(); + $params['id'] = $this->_contactId; + + CRM_Contact_BAO_Contact::getValues($params, $defaults); + + return $defaults; + } + + /** + * Add entry to log table + * + * @return void + * @protected + */ + protected function log() { + CRM_Core_BAO_Log::register($this->_contactId, + 'civicrm_contact', + $this->_contactId + ); + } + + /** + * Final response from successful form submit + * + * @param response: array - data to send to the client + * + * @return void + * @protected + */ + protected function response($response = array()) { + // Load changelog footer from template + $smarty = CRM_Core_Smarty::singleton(); + $smarty->assign('contactId', $this->_contactId); + $smarty->assign('external_identifier', CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactId, 'external_identifier')); + $smarty->assign('lastModified', CRM_Core_BAO_Log::lastModified($this->_contactId, 'civicrm_contact')); + $viewOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_view_options', TRUE + ); + $smarty->assign('changeLog', $viewOptions['log']); + $response = array_merge( + array( + 'status' => 'save', + 'changeLog' => array( + 'count' => CRM_Contact_BAO_Contact::getCountComponent('log', $this->_contactId), + 'markup' => $smarty->fetch('CRM/common/contactFooter.tpl'), + ), + ), + $response, + CRM_Contact_Form_Inline_Lock::getResponse($this->_contactId) + ); + $this->postProcessHook(); + // CRM-11831 @see http://www.malsup.com/jquery/form/#file-upload + $xhr = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'; + if (!$xhr) { + echo ''; + } + CRM_Utils_System::civiExit(); + } +} diff --git a/CRM/Contact/Form/Inline/Address.php b/CRM/Contact/Form/Inline/Address.php new file mode 100644 index 0000000000..21d078cf0d --- /dev/null +++ b/CRM/Contact/Form/Inline/Address.php @@ -0,0 +1,209 @@ +_locBlockNo = CRM_Utils_Request::retrieve('locno', 'Positive', $this, TRUE, NULL, $_REQUEST); + $this->assign('blockId', $this->_locBlockNo); + + $addressSequence = CRM_Core_BAO_Address::addressSequence(); + $this->assign('addressSequence', $addressSequence); + + $this->_values = array(); + $this->_addressId = CRM_Utils_Request::retrieve('aid', 'Positive', $this, FALSE, NULL, $_REQUEST); + + $this->_action = CRM_Core_Action::ADD; + if ($this->_addressId) { + $params = array('id' => $this->_addressId); + $address = CRM_Core_BAO_Address::getValues($params, FALSE, 'id'); + $this->_values['address'][$this->_locBlockNo] = array_pop($address); + $this->_action = CRM_Core_Action::UPDATE; + } + else { + $this->_addressId = 0; + } + + $this->assign('action', $this->_action); + $this->assign('addressId', $this->_addressId); + + // parse street address, CRM-5450 + $this->_parseStreetAddress = $this->get('parseStreetAddress'); + if (!isset($this->_parseStreetAddress)) { + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options' + ); + $this->_parseStreetAddress = FALSE; + if (CRM_Utils_Array::value('street_address', $addressOptions) && + CRM_Utils_Array::value('street_address_parsing', $addressOptions) + ) { + $this->_parseStreetAddress = TRUE; + } + $this->set('parseStreetAddress', $this->_parseStreetAddress); + } + $this->assign('parseStreetAddress', $this->_parseStreetAddress); + } + + /** + * build the form elements for an address object + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + CRM_Contact_Form_Edit_Address::buildQuickForm($this, $this->_locBlockNo, TRUE, TRUE); + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = $this->_values; + + $config = CRM_Core_Config::singleton(); + //set address block defaults + if (CRM_Utils_Array::value('address', $defaults)) { + CRM_Contact_Form_Edit_Address::setDefaultValues($defaults, $this); + } + else { + // get the default location type + $locationType = CRM_Core_BAO_LocationType::getDefault(); + + if ($this->_locBlockNo == 1) { + $address['is_primary'] = TRUE; + $address['location_type_id'] = $locationType->id; + } + + $address['country_id'] = $config->defaultContactCountry; + $defaults['address'][$this->_locBlockNo] = $address; + } + + $values = $defaults['address'][$this->_locBlockNo]; + + CRM_Contact_Form_Edit_Address::fixStateSelect($this, + "address[$this->_locBlockNo][country_id]", + "address[$this->_locBlockNo][state_province_id]", + "address[$this->_locBlockNo][county_id]", + CRM_Utils_Array::value('country_id', + $values, $config->defaultContactCountry + ), + CRM_Utils_Array::value('state_province_id', + $values, $config->defaultContactStateProvince + ) + ); + + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save address + $params['contact_id'] = $this->_contactId; + $params['updateBlankLocInfo'] = TRUE; + + // process shared contact address. + CRM_Contact_BAO_Contact_Utils::processSharedAddress($params['address']); + + if ($this->_parseStreetAddress) { + CRM_Contact_Form_Contact::parseAddress($params); + } + + if ($this->_addressId > 0) { + $params['address'][$this->_locBlockNo]['id'] = $this->_addressId; + } + + // save address changes + $address = CRM_Core_BAO_Address::create($params, TRUE); + + $this->log(); + $this->response(array('addressId' => $address[0]->id)); + } +} diff --git a/CRM/Contact/Form/Inline/CommunicationPreferences.php b/CRM/Contact/Form/Inline/CommunicationPreferences.php new file mode 100644 index 0000000000..58bc83b341 --- /dev/null +++ b/CRM/Contact/Form/Inline/CommunicationPreferences.php @@ -0,0 +1,104 @@ +addFormRule(array('CRM_Contact_Form_Edit_CommunicationPreferences', 'formRule'), $this); + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = parent::setDefaultValues(); + + if (!empty($defaults['preferred_language'])) { + $languages = array_flip(CRM_Core_PseudoConstant::languages()); + $defaults['preferred_language'] = $languages[$defaults['preferred_language']]; + } + + // CRM-7119: set preferred_language to default if unset + if (empty($defaults['preferred_language'])) { + $config = CRM_Core_Config::singleton(); + $defaults['preferred_language'] = $config->lcMessages; + } + + foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) { + $name = "{$greeting}_display"; + $this->assign($name, CRM_Utils_Array::value($name, $defaults)); + } + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save communication preferences + + // this is a chekbox, so mark false if we dont get a POST value + $params['is_opt_out'] = CRM_Utils_Array::value('is_opt_out', $params, FALSE); + $params['contact_type'] = $this->_contactType; + $params['contact_id'] = $this->_contactId; + + if (!empty($this->_contactSubType)) { + $params['contact_sub_type'] = $this->_contactSubType; + } + + CRM_Contact_BAO_Contact::create($params); + + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/ContactInfo.php b/CRM/Contact/Form/Inline/ContactInfo.php new file mode 100644 index 0000000000..a93570ee32 --- /dev/null +++ b/CRM/Contact/Form/Inline/ContactInfo.php @@ -0,0 +1,96 @@ +_contactType; + $class::buildQuickForm($this, 2); + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = parent::setDefaultValues(); + + if ($this->_contactType == 'Individual') { + // set current employer details + $currentEmployer = CRM_Contact_BAO_Relationship::getCurrentEmployer(array($this->_contactId)); + $defaults['current_employer_id'] = CRM_Utils_Array::value('org_id', $currentEmployer[$this->_contactId]); + + $this->assign('currentEmployer', CRM_Utils_Array::value('current_employer_id', $defaults)); + } + + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save contact info + $params['contact_type'] = $this->_contactType; + $params['contact_id'] = $this->_contactId; + + if (!empty($this->_contactSubType)) { + $params['contact_sub_type'] = $this->_contactSubType; + } + + CRM_Contact_BAO_Contact::create($params); + + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/ContactName.php b/CRM/Contact/Form/Inline/ContactName.php new file mode 100644 index 0000000000..63c2bd3606 --- /dev/null +++ b/CRM/Contact/Form/Inline/ContactName.php @@ -0,0 +1,76 @@ +_contactType; + $class::buildQuickForm($this, 1); + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save contact info + $params['contact_type'] = $this->_contactType; + $params['contact_id'] = $this->_contactId; + + if (!empty($this->_contactSubType)) { + $params['contact_sub_type'] = $this->_contactSubType; + } + + CRM_Contact_BAO_Contact::create($params); + + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/CustomData.php b/CRM/Contact/Form/Inline/CustomData.php new file mode 100644 index 0000000000..ad9e73ae2e --- /dev/null +++ b/CRM/Contact/Form/Inline/CustomData.php @@ -0,0 +1,113 @@ +_groupID = CRM_Utils_Request::retrieve('groupID', 'Positive', $this, TRUE, NULL, $_REQUEST); + $this->assign('customGroupId', $this->_groupID); + + $subType = CRM_Contact_BAO_Contact::getContactSubType($this->_contactId, ','); + CRM_Custom_Form_CustomData::preProcess($this, null, $subType, 1, + $this->_contactType, $this->_contactId); + } + + /** + * build the form elements for custom data + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + return CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + // Process / save custom data + // Get the form values and groupTree + $params = $this->controller->exportValues($this->_name); + CRM_Core_BAO_CustomValueTable::postProcess($params, + $this->_groupTree[$this->_groupID]['fields'], + 'civicrm_contact', + $this->_contactId, + $this->_entityType + ); + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/Demographics.php b/CRM/Contact/Form/Inline/Demographics.php new file mode 100644 index 0000000000..f50c968357 --- /dev/null +++ b/CRM/Contact/Form/Inline/Demographics.php @@ -0,0 +1,78 @@ +exportValues(); + + // Process / save demographics + if (!CRM_Utils_Array::value('is_deceased', $params)) { + $params['is_deceased'] = FALSE; + $params['deceased_date'] = NULL; + } + + $params['contact_type'] = 'Individual'; + $params['contact_id'] = $this->_contactId; + + if (!empty($this->_contactSubType)) { + $params['contact_sub_type'] = $this->_contactSubType; + } + + CRM_Contact_BAO_Contact::create($params); + + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/Email.php b/CRM/Contact/Form/Inline/Email.php new file mode 100644 index 0000000000..f75d2dcdde --- /dev/null +++ b/CRM/Contact/Form/Inline/Email.php @@ -0,0 +1,174 @@ +contact_id = $this->_contactId; + + $this->_emails = CRM_Core_BAO_Block::retrieveBlock($email, NULL); + } + + /** + * build the form elements for an email object + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + $totalBlocks = $this->_blockCount; + $actualBlockCount = 1; + if (count($this->_emails) > 1) { + $actualBlockCount = $totalBlocks = count($this->_emails); + if ($totalBlocks < $this->_blockCount) { + $additionalBlocks = $this->_blockCount - $totalBlocks; + $totalBlocks += $additionalBlocks; + } + else { + $actualBlockCount++; + $totalBlocks++; + } + } + + $this->assign('actualBlockCount', $actualBlockCount); + $this->assign('totalBlocks', $totalBlocks); + + $this->applyFilter('__ALL__', 'trim'); + + for ($blockId = 1; $blockId < $totalBlocks; $blockId++) { + CRM_Contact_Form_Edit_Email::buildQuickForm($this, $blockId, TRUE); + } + + $this->addFormRule(array('CRM_Contact_Form_Inline_Email', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * + * @return $errors + * @static + * @access public + */ + static function formRule($fields, $errors) { + $hasData = $hasPrimary = $errors = array(); + if (CRM_Utils_Array::value('email', $fields) && is_array($fields['email'])) { + foreach ($fields['email'] as $instance => $blockValues) { + $dataExists = CRM_Contact_Form_Contact::blockDataExists($blockValues); + + if ($dataExists) { + $hasData[] = $instance; + if (CRM_Utils_Array::value('is_primary', $blockValues)) { + $hasPrimary[] = $instance; + } + } + } + + + if (empty($hasPrimary) && !empty($hasData)) { + $errors["email[1][is_primary]"] = ts('One email should be marked as primary.'); + } + + if (count($hasPrimary) > 1) { + $errors["email[".array_pop($hasPrimary)."][is_primary]"] = ts('Only one email can be marked as primary.'); + } + } + return $errors; + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = array(); + if (!empty($this->_emails)) { + foreach ($this->_emails as $id => $value) { + $defaults['email'][$id] = $value; + } + } + else { + // get the default location type + $locationType = CRM_Core_BAO_LocationType::getDefault(); + $defaults['email'][1]['location_type_id'] = $locationType->id; + } + + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save emails + $params['contact_id'] = $this->_contactId; + $params['updateBlankLocInfo'] = TRUE; + CRM_Core_BAO_Block::create('email', $params); + + $this->log(); + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/IM.php b/CRM/Contact/Form/Inline/IM.php new file mode 100644 index 0000000000..9e4b893eb1 --- /dev/null +++ b/CRM/Contact/Form/Inline/IM.php @@ -0,0 +1,176 @@ +contact_id = $this->_contactId; + + $this->_ims = CRM_Core_BAO_Block::retrieveBlock($im, NULL); + } + + /** + * build the form elements for im object + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + $totalBlocks = $this->_blockCount; + $actualBlockCount = 1; + if (count($this->_ims) > 1) { + $actualBlockCount = $totalBlocks = count($this->_ims); + if ($totalBlocks < $this->_blockCount) { + $additionalBlocks = $this->_blockCount - $totalBlocks; + $totalBlocks += $additionalBlocks; + } + else { + $actualBlockCount++; + $totalBlocks++; + } + } + + $this->assign('actualBlockCount', $actualBlockCount); + $this->assign('totalBlocks', $totalBlocks); + + $this->applyFilter('__ALL__', 'trim'); + + for ($blockId = 1; $blockId < $totalBlocks; $blockId++) { + CRM_Contact_Form_Edit_IM::buildQuickForm($this, $blockId, TRUE); + } + + $this->addFormRule(array('CRM_Contact_Form_Inline_IM', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * + * @return $errors + * @static + * @access public + */ + static function formRule($fields, $errors) { + $hasData = $hasPrimary = $errors = array(); + if (CRM_Utils_Array::value('im', $fields) && is_array($fields['im'])) { + foreach ($fields['im'] as $instance => $blockValues) { + $dataExists = CRM_Contact_Form_Contact::blockDataExists($blockValues); + + if ($dataExists) { + $hasData[] = $instance; + if (CRM_Utils_Array::value('is_primary', $blockValues)) { + $hasPrimary[] = $instance; + if (!$primaryID && + CRM_Utils_Array::value('im', $blockValues)) { + $primaryID = $blockValues['im']; + } + } + } + } + + if (empty($hasPrimary) && !empty($hasData)) { + $errors["im[1][is_primary]"] = ts('One IM should be marked as primary.'); + } + + if (count($hasPrimary) > 1) { + $errors["im[".array_pop($hasPrimary)."][is_primary]"] = ts('Only one IM can be marked as primary.'); + } + } + return $errors; + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = array(); + if (!empty($this->_ims)) { + foreach ($this->_ims as $id => $value) { + $defaults['im'][$id] = $value; + } + } + else { + // get the default location type + $locationType = CRM_Core_BAO_LocationType::getDefault(); + $defaults['im'][1]['location_type_id'] = $locationType->id; + } + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save IMs + $params['contact_id'] = $this->_contactId; + $params['updateBlankLocInfo'] = TRUE; + CRM_Core_BAO_Block::create('im', $params); + + $this->log(); + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/Lock.php b/CRM/Contact/Form/Inline/Lock.php new file mode 100644 index 0000000000..9978e9f572 --- /dev/null +++ b/CRM/Contact/Form/Inline/Lock.php @@ -0,0 +1,100 @@ +addElement('hidden', 'oplock_ts', $timestamps['modified_date'], array('id' => 'oplock_ts')); + $form->addFormRule(array('CRM_Contact_Form_Inline_Lock', 'formRule'), $contactID); + } + + /** + * Ensure that oplock_ts hasn't changed in the underlying DB + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $contactID = NULL) { + $errors = array(); + + $timestamps = CRM_Contact_BAO_Contact::getTimestamps($contactID); + if ($fields['oplock_ts'] != $timestamps['modified_date']) { + // Inline buttons generated via JS + $open = sprintf("
    ", $timestamps['modified_date']); + $close = "
    "; + $errors['oplock_ts'] = $open . ts('This record was modified by another user!') . $close; + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Return any post-save data + * + * @return array extra options to return in JSON + */ + static function getResponse($contactID) { + $timestamps = CRM_Contact_BAO_Contact::getTimestamps($contactID); + return array('oplock_ts' => $timestamps['modified_date']); + } +} diff --git a/CRM/Contact/Form/Inline/OpenID.php b/CRM/Contact/Form/Inline/OpenID.php new file mode 100644 index 0000000000..3472d632d7 --- /dev/null +++ b/CRM/Contact/Form/Inline/OpenID.php @@ -0,0 +1,176 @@ +contact_id = $this->_contactId; + + $this->_openids = CRM_Core_BAO_Block::retrieveBlock($openid, NULL); + } + + /** + * build the form elements for openID object + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + $totalBlocks = $this->_blockCount; + $actualBlockCount = 1; + if (count($this->_openids) > 1) { + $actualBlockCount = $totalBlocks = count($this->_openids); + if ($totalBlocks < $this->_blockCount) { + $additionalBlocks = $this->_blockCount - $totalBlocks; + $totalBlocks += $additionalBlocks; + } + else { + $actualBlockCount++; + $totalBlocks++; + } + } + + $this->assign('actualBlockCount', $actualBlockCount); + $this->assign('totalBlocks', $totalBlocks); + + $this->applyFilter('__ALL__', 'trim'); + + for ($blockId = 1; $blockId < $totalBlocks; $blockId++) { + CRM_Contact_Form_Edit_OpenID::buildQuickForm($this, $blockId, TRUE); + } + + $this->addFormRule(array('CRM_Contact_Form_Inline_OpenID', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * + * @return $errors + * @static + * @access public + */ + static function formRule($fields, $errors) { + $hasData = $hasPrimary = $errors = array(); + if (CRM_Utils_Array::value('openid', $fields) && is_array($fields['openid'])) { + foreach ($fields['openid'] as $instance => $blockValues) { + $dataExists = CRM_Contact_Form_Contact::blockDataExists($blockValues); + + if ($dataExists) { + $hasData[] = $instance; + if (CRM_Utils_Array::value('is_primary', $blockValues)) { + $hasPrimary[] = $instance; + if (!$primaryID && + CRM_Utils_Array::value('openid', $blockValues)) { + $primaryID = $blockValues['openid']; + } + } + } + } + + if (empty($hasPrimary) && !empty($hasData)) { + $errors["openid[1][is_primary]"] = ts('One OpenID should be marked as primary.'); + } + + if (count($hasPrimary) > 1) { + $errors["openid[".array_pop($hasPrimary)."][is_primary]"] = ts('Only one OpenID can be marked as primary.'); + } + } + return $errors; + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = array(); + if (!empty($this->_openids)) { + foreach ($this->_openids as $id => $value) { + $defaults['openid'][$id] = $value; + } + } + else { + // get the default location type + $locationType = CRM_Core_BAO_LocationType::getDefault(); + $defaults['openid'][1]['location_type_id'] = $locationType->id; + } + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save openID + $params['contact_id'] = $this->_contactId; + $params['updateBlankLocInfo'] = TRUE; + CRM_Core_BAO_Block::create('openid', $params); + + $this->log(); + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/Phone.php b/CRM/Contact/Form/Inline/Phone.php new file mode 100644 index 0000000000..56b32a8cbc --- /dev/null +++ b/CRM/Contact/Form/Inline/Phone.php @@ -0,0 +1,177 @@ +contact_id = $this->_contactId; + + $this->_phones = CRM_Core_BAO_Block::retrieveBlock($phone, NULL); + } + + /** + * build the form elements for phone object + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + $totalBlocks = $this->_blockCount; + $actualBlockCount = 1; + if (count($this->_phones) > 1) { + $actualBlockCount = $totalBlocks = count($this->_phones); + if ($totalBlocks < $this->_blockCount) { + $additionalBlocks = $this->_blockCount - $totalBlocks; + $totalBlocks += $additionalBlocks; + } + else { + $actualBlockCount++; + $totalBlocks++; + } + } + + $this->assign('actualBlockCount', $actualBlockCount); + $this->assign('totalBlocks', $totalBlocks); + + $this->applyFilter('__ALL__', 'trim'); + + for ($blockId = 1; $blockId < $totalBlocks; $blockId++) { + CRM_Contact_Form_Edit_Phone::buildQuickForm($this, $blockId, TRUE); + } + + $this->addFormRule(array('CRM_Contact_Form_Inline_Phone', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * @param array $errors list of errors to be posted back to the form + * + * @return $errors + * @static + * @access public + */ + static function formRule($fields, $errors) { + $hasData = $hasPrimary = $errors = array(); + if (CRM_Utils_Array::value('phone', $fields) && is_array($fields['phone'])) { + $primaryID = null; + foreach ($fields['phone'] as $instance => $blockValues) { + $dataExists = CRM_Contact_Form_Contact::blockDataExists($blockValues); + + if ($dataExists) { + $hasData[] = $instance; + if (CRM_Utils_Array::value('is_primary', $blockValues)) { + $hasPrimary[] = $instance; + if (!$primaryID && + CRM_Utils_Array::value('phone', $blockValues)) { + $primaryID = $blockValues['phone']; + } + } + } + } + + if (empty($hasPrimary) && !empty($hasData)) { + $errors["phone[1][is_primary]"] = ts('One phone should be marked as primary.'); + } + + if (count($hasPrimary) > 1) { + $errors["phone[".array_pop($hasPrimary)."][is_primary]"] = ts('Only one phone can be marked as primary.'); + } + } + return $errors; + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = array(); + if (!empty($this->_phones)) { + foreach ($this->_phones as $id => $value) { + $defaults['phone'][$id] = $value; + } + } + else { + // get the default location type + $locationType = CRM_Core_BAO_LocationType::getDefault(); + $defaults['phone'][1]['location_type_id'] = $locationType->id; + } + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save phones + $params['contact_id'] = $this->_contactId; + $params['updateBlankLocInfo'] = TRUE; + CRM_Core_BAO_Block::create('phone', $params); + + $this->log(); + $this->response(); + } +} diff --git a/CRM/Contact/Form/Inline/Website.php b/CRM/Contact/Form/Inline/Website.php new file mode 100644 index 0000000000..68cc77bba8 --- /dev/null +++ b/CRM/Contact/Form/Inline/Website.php @@ -0,0 +1,128 @@ + $this->_contactId); + $values = array(); + $this->_websites = CRM_Core_BAO_Website::getValues($params, $values); + } + + /** + * build the form elements for website object + * + * @return void + * @access public + */ + public function buildQuickForm() { + parent::buildQuickForm(); + + $totalBlocks = $this->_blockCount; + $actualBlockCount = 1; + if (count($this->_websites) > 1) { + $actualBlockCount = $totalBlocks = count($this->_websites); + if ($totalBlocks < $this->_blockCount) { + $additionalBlocks = $this->_blockCount - $totalBlocks; + $totalBlocks += $additionalBlocks; + } + else { + $actualBlockCount++; + $totalBlocks++; + } + } + + $this->assign('actualBlockCount', $actualBlockCount); + $this->assign('totalBlocks', $totalBlocks); + + $this->applyFilter('__ALL__', 'trim'); + + for ($blockId = 1; $blockId < $totalBlocks; $blockId++) { + CRM_Contact_Form_Edit_Website::buildQuickForm($this, $blockId, TRUE); + } + + } + + /** + * set defaults for the form + * + * @return array + * @access public + */ + public function setDefaultValues() { + $defaults = array(); + if (!empty($this->_websites)) { + foreach ($this->_websites as $id => $value) { + $defaults['website'][$id] = $value; + } + } + return $defaults; + } + + /** + * process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->exportValues(); + + // Process / save websites + CRM_Core_BAO_Website::create($params['website'], $this->_contactId, true); + + $this->log(); + $this->response(); + } +} diff --git a/CRM/Contact/Form/Location.php b/CRM/Contact/Form/Location.php new file mode 100644 index 0000000000..03ea2dfb23 --- /dev/null +++ b/CRM/Contact/Form/Location.php @@ -0,0 +1,119 @@ +_addBlockName = CRM_Utils_Request::retrieve('block', 'String', CRM_Core_DAO::$_nullObject); + $additionalblockCount = CRM_Utils_Request::retrieve('count', 'Positive', CRM_Core_DAO::$_nullObject); + + $form->assign('addBlock', FALSE); + if ($form->_addBlockName && $additionalblockCount) { + $form->assign('addBlock', TRUE); + $form->assign('blockName', $form->_addBlockName); + $form->assign('blockId', $additionalblockCount); + $form->set($form->_addBlockName . '_Block_Count', $additionalblockCount); + } + + $className = CRM_Utils_System::getClassName($form); + if (in_array($className, array( + 'CRM_Event_Form_ManageEvent_Location', 'CRM_Contact_Form_Domain'))) { + $form->_blocks = array('Address' => ts('Address'), + 'Email' => ts('Email'), + 'Phone' => ts('Phone'), + ); + } + + $form->assign('blocks', $form->_blocks); + $form->assign('className', $className); + + // get address sequence. + if (!$addressSequence = $form->get('addressSequence')) { + $addressSequence = CRM_Core_BAO_Address::addressSequence(); + $form->set('addressSequence', $addressSequence); + } + $form->assign('addressSequence', $addressSequence); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + static function buildQuickForm(&$form) { + // required for subsequent AJAX requests. + $ajaxRequestBlocks = array(); + $generateAjaxRequest = 0; + + //build 1 instance of all blocks, without using ajax ... + foreach ($form->_blocks as $blockName => $label) { + require_once (str_replace('_', DIRECTORY_SEPARATOR, 'CRM_Contact_Form_Edit_' . $blockName) . '.php'); + $name = strtolower($blockName); + + $instances = array(1); + if (CRM_Utils_Array::value($name, $_POST) && is_array($_POST[$name])) { + $instances = array_keys($_POST[$name]); + } + elseif (property_exists($form, '_values') && CRM_Utils_Array::value($name, $form->_values) && is_array($form->_values[$name])) { + $instances = array_keys($form->_values[$name]); + } + + foreach ($instances as $instance) { + if ($instance == 1) { + $form->assign('addBlock', FALSE); + $form->assign('blockId', $instance); + } + else { + //we are going to build other block instances w/ AJAX + $generateAjaxRequest++; + $ajaxRequestBlocks[$blockName][$instance] = TRUE; + } + + $form->set($blockName . '_Block_Count', $instance); + eval('CRM_Contact_Form_Edit_' . $blockName . '::buildQuickForm( $form );'); + } + } + + //assign to generate AJAX request for building extra blocks. + $form->assign('generateAjaxRequest', $generateAjaxRequest); + $form->assign('ajaxRequestBlocks', $ajaxRequestBlocks); + } +} + diff --git a/CRM/Contact/Form/Merge.php b/CRM/Contact/Form/Merge.php new file mode 100644 index 0000000000..e35351d607 --- /dev/null +++ b/CRM/Contact/Form/Merge.php @@ -0,0 +1,361 @@ +_rgid = $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE); + $this->_gid = $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE); + $this->_mergeId = CRM_Utils_Request::retrieve('mergeId', 'Positive', $this, FALSE); + + if (!CRM_Dedupe_BAO_Rule::validateContacts($cid, $oid)) { + CRM_Core_Error::statusBounce(ts('The selected pair of contacts are marked as non duplicates. If these records should be merged, you can remove this exception on the Dedupe Exceptions page.', array(1 => CRM_Utils_System::url('civicrm/dedupe/exception', 'reset=1')))); + } + + //load cache mechanism + $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'contact_type'); + $cacheKey = "merge $contactType"; + $cacheKey .= $rgid ? "_{$rgid}" : '_0'; + $cacheKey .= $gid ? "_{$gid}" : '_0'; + + $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND + pn.entity_id2 = de.contact_id2 )"; + $where = "de.id IS NULL"; + + $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, $cid, $oid, $this->_mergeId, $join, $where, $flip); + + // Block access if user does not have EDIT permissions for both contacts. + if (!(CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT) && + CRM_Contact_BAO_Contact_Permission::allow($oid, CRM_Core_Permission::EDIT) + )) { + CRM_Utils_System::permissionDenied(); + } + + // get user info of main contact. + $config = CRM_Core_Config::singleton(); + $config->doNotResetCache = 1; + + $viewUser = CRM_Core_Permission::check('access user profiles'); + $mainUfId = CRM_Core_BAO_UFMatch::getUFId($cid); + $mainUser = NULL; + if ($mainUfId) { + // d6 compatible + if ($config->userSystem->is_drupal == '1') { + $mainUser = user_load($mainUfId); + } + elseif ($config->userFramework == 'Joomla') { + $mainUser = JFactory::getUser($mainUfId); + } + + $this->assign('mainUfId', $mainUfId); + $this->assign('mainUfName', $mainUser ? $mainUser->name : NULL); + } + + $flipUrl = CRM_Utils_system::url('civicrm/contact/merge', + "reset=1&action=update&cid={$oid}&oid={$cid}&rgid={$rgid}&gid={$gid}" + ); + if (!$flip) { + $flipUrl .= '&flip=1'; + } + $this->assign('flip', $flipUrl); + + $this->prev = $this->next = NULL; + foreach (array( + 'prev', 'next') as $position) { + if (!empty($pos[$position])) { + if ($pos[$position]['id1'] && $pos[$position]['id2']) { + $urlParam = "reset=1&cid={$pos[$position]['id1']}&oid={$pos[$position]['id2']}&mergeId={$pos[$position]['mergeId']}&action=update"; + + if ($rgid) { + $urlParam .= "&rgid={$rgid}"; + } + if ($gid) { + $urlParam .= "&gid={$gid}"; + } + + $this->$position = CRM_Utils_system::url('civicrm/contact/merge', $urlParam); + $this->assign($position, $this->$position); + } + } + } + + // get user info of other contact. + $otherUfId = CRM_Core_BAO_UFMatch::getUFId($oid); + $otherUser = NULL; + + if ($otherUfId) { + // d6 compatible + if ($config->userSystem->is_drupal == '1') { + $otherUser = user_load($otherUfId); + } + elseif ($config->userFramework == 'Joomla') { + $otherUser = JFactory::getUser($otherUfId); + } + + $this->assign('otherUfId', $otherUfId); + $this->assign('otherUfName', $otherUser ? $otherUser->name : NULL); + } + + $cmsUser = ($mainUfId && $otherUfId) ? TRUE : FALSE; + $this->assign('user', $cmsUser); + + $session = CRM_Core_Session::singleton(); + + // context fixed. + if ($rgid) { + $urlParam = "reset=1&action=browse&rgid={$rgid}"; + if ($gid) { + $urlParam .= "&gid={$gid}"; + } + $session->pushUserContext(CRM_Utils_system::url('civicrm/contact/dedupefind', $urlParam)); + } + + // ensure that oid is not the current user, if so refuse to do the merge + if ($session->get('userID') == $oid) { + $display_name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $oid, 'display_name'); + $message = ts('The contact record which is linked to the currently logged in user account - \'%1\' - cannot be deleted.', + array(1 => $display_name) + ); + CRM_Core_Error::statusBounce($message); + } + + $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($cid, $oid); + $main = &$rowsElementsAndInfo['main_details']; + $other = &$rowsElementsAndInfo['other_details']; + + if ($main['contact_id'] != $cid) { + CRM_Core_Error::fatal(ts('The main contact record does not exist')); + } + + if ($other['contact_id'] != $oid) { + CRM_Core_Error::fatal(ts('The other contact record does not exist')); + } + + $subtypes = CRM_Contact_BAO_ContactType::subTypePairs(NULL, TRUE, ''); + + $this->assign('contact_type', $main['contact_type']); + if (isset($main['contact_sub_type'])) { + $this->assign('main_contact_subtype', + CRM_Utils_Array::value('contact_sub_type', $subtypes[$main['contact_sub_type'][0]]) + ); + } + if (isset($other['contact_sub_type'])) { + $this->assign('other_contact_subtype', + CRM_Utils_Array::value('contact_sub_type', $subtypes[$other['contact_sub_type'][0]]) + ); + } + $this->assign('main_name', $main['display_name']); + $this->assign('other_name', $other['display_name']); + $this->assign('main_cid', $main['contact_id']); + $this->assign('other_cid', $other['contact_id']); + + $this->_cid = $cid; + $this->_oid = $oid; + $this->_rgid = $rgid; + $this->_contactType = $main['contact_type']; + $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('onclick' => "return toggleCheckboxVals('move_',this);")); + + $this->assign('mainLocBlock', json_encode($rowsElementsAndInfo['main_loc_block'])); + $this->assign('rows', $rowsElementsAndInfo['rows']); + + $this->_locBlockIds = array( + 'main' => $rowsElementsAndInfo['main_details']['loc_block_ids'], + 'other' => $rowsElementsAndInfo['other_details']['loc_block_ids'] + ); + + // add elements + foreach ($rowsElementsAndInfo['elements'] as $element) { + $this->addElement($element[0], + $element[1], + array_key_exists('2', $element) ? $element[2] : NULL, + array_key_exists('3', $element) ? $element[3] : NULL, + array_key_exists('4', $element) ? $element[4] : NULL, + array_key_exists('5', $element) ? $element[5] : NULL + ); + } + + // add related table elements + foreach ($rowsElementsAndInfo['rel_table_elements'] as $relTableElement) { + $element = $this->addElement($relTableElement[0], $relTableElement[1]); + $element->setChecked(TRUE); + } + + $this->assign('rel_tables', $rowsElementsAndInfo['rel_tables']); + $this->assign('userContextURL', $session->readUserContext()); + } + + function setDefaultValues() { + return array('deleteOther' => 1); + } + + function addRules() {} + + public function buildQuickForm() { + CRM_Utils_System::setTitle(ts('Merge %1s', array(1 => $this->_contactType))); + $name = ts('Merge'); + if ($this->next) { + $name = ts('Merge and Goto Next Pair'); + } + + if ($this->next || $this->prev) { + $button = array( + array( + 'type' => 'next', + 'name' => $name, + 'isDefault' => TRUE, + ), + array( + 'type' => 'submit', + 'name' => ts('Merge and Goto Listing'), + ), + array( + 'type' => 'done', + 'name' => ts('Merge and View Result'), + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ); + } + else { + $button = array( + array( + 'type' => 'next', + 'name' => $name, + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ); + } + + $this->addButtons($button); + } + + public function postProcess() { + $formValues = $this->exportValues(); + + // reset all selected contact ids from session + // when we came from search context, CRM-3526 + $session = CRM_Core_Session::singleton(); + if ($session->get('selectedSearchContactIds')) { + $session->resetScope('selectedSearchContactIds'); + } + + $formValues['main_details'] = $formValues['other_details'] = array(); + $formValues['main_details']['contact_type'] = $this->_contactType; + $formValues['main_details']['loc_block_ids'] = $this->_locBlockIds['main']; + $formValues['other_details']['loc_block_ids'] = $this->_locBlockIds['other']; + + CRM_Dedupe_Merger::moveAllBelongings($this->_cid, $this->_oid, $formValues); + + CRM_Core_Session::setStatus(ts('Contact id %1 has been updated and contact id %2 has been deleted.', array(1 => $this->_cid, 2 => $this->_oid)), ts('Contacts Merged'), 'success'); + $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_cid}"); + if (CRM_Utils_Array::value('_qf_Merge_submit', $formValues)) { + $listParamsURL = "reset=1&action=update&rgid={$this->_rgid}"; + if ($this->_gid) { + $listParamsURL .= "&gid={$this->_gid}"; + } + $lisitingURL = CRM_Utils_System::url('civicrm/contact/dedupefind', + $listParamsURL + ); + CRM_Utils_System::redirect($lisitingURL); + } + if (CRM_Utils_Array::value('_qf_Merge_done', $formValues)) { + CRM_Utils_System::redirect($url); + } + + if ($this->next && $this->_mergeId) { + $cacheKey = "merge {$this->_contactType}"; + $cacheKey .= $this->_rgid ? "_{$this->_rgid}" : '_0'; + $cacheKey .= $this->_gid ? "_{$this->_gid}" : '_0'; + + $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND + pn.entity_id2 = de.contact_id2 )"; + $where = "de.id IS NULL"; + + $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, NULL, NULL, $this->_mergeId, $join, $where); + + if (!empty($pos) && + $pos['next']['id1'] && + $pos['next']['id2'] + ) { + + $urlParam = "reset=1&cid={$pos['next']['id1']}&oid={$pos['next']['id2']}&mergeId={$pos['next']['mergeId']}&action=update"; + if ($this->_rgid) { + $urlParam .= "&rgid={$this->_rgid}"; + } + if ($this->_gid) { + $urlParam .= "&gid={$this->_gid}"; + } + + $url = CRM_Utils_system::url('civicrm/contact/merge', $urlParam); + } + } + + CRM_Utils_System::redirect($url); + } +} + diff --git a/CRM/Contact/Form/NewContact.php b/CRM/Contact/Form/NewContact.php new file mode 100644 index 0000000000..2c4a0e43ee --- /dev/null +++ b/CRM/Contact/Form/NewContact.php @@ -0,0 +1,80 @@ + '200px'); + + $selectContacts = $form->add('text', "{$prefix}contact[{$blockNo}]", ts('Select Contact'), $attributes, $required); + + // use submitted values to set default if form submit fails dues to form rules + if ($selectContacts->getValue()) { + $form->assign("selectedContacts", $selectContacts->getValue()); + } + + $form->addElement('hidden', "{$prefix}contact_select_id[{$blockNo}]"); + + if (CRM_Core_Permission::check('edit all contacts') || CRM_Core_Permission::check('add contacts')) { + // build select for new contact + $contactProfiles = CRM_Core_BAO_UFGroup::getReservedProfiles('Contact', $extraProfiles); + $form->add('select', "{$prefix}profiles[{$blockNo}]", ts('Create New Contact'), array( + '' => ts('- create new contact -'), + ) + $contactProfiles, FALSE, array( + 'onChange' => "if (this.value) { newContact{$prefix}{$blockNo}( this.value, {$blockNo}, '{$prefix}' );}", + )); + } + + $form->assign('blockNo', $blockNo); + $form->assign('prefix', $prefix); + } +} + diff --git a/CRM/Contact/Form/RelatedContact.php b/CRM/Contact/Form/RelatedContact.php new file mode 100644 index 0000000000..a52d6b6761 --- /dev/null +++ b/CRM/Contact/Form/RelatedContact.php @@ -0,0 +1,195 @@ +_action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 'update' + ); + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + + $rcid = CRM_Utils_Request::retrieve('rcid', 'Positive', $this); + $rcid = $rcid ? "&id={$rcid}" : ''; + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/user', "reset=1{$rcid}")); + + if ($this->_contactId) { + $contact = new CRM_Contact_DAO_Contact(); + $contact->id = $this->_contactId; + if (!$contact->find(TRUE)) { + CRM_Core_Error::statusBounce(ts('contact does not exist: %1', array(1 => $this->_contactId))); + } + $this->_contactType = $contact->contact_type; + + // check for permissions + if (!CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT)) { + CRM_Core_Error::statusBounce(ts('You do not have the necessary permission to edit this contact.')); + } + + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($this->_contactId); + CRM_Utils_System::setTitle($displayName, $contactImage . ' ' . $displayName); + } + else { + CRM_Core_Error::statusBounce(ts('Could not get a contact_id and/or contact_type')); + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + return $this->_defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $params = array(); + $params['id'] = $params['contact_id'] = $this->_contactId; + $contact = CRM_Contact_BAO_Contact::retrieve($params, $this->_defaults); + + $countryID = CRM_Utils_Array::value('country_id', + $this->_defaults['address'][1] + ); + $stateID = CRM_Utils_Array::value('state_province_id', + $this->_defaults['address'][1] + ); + CRM_Contact_BAO_Contact_Utils::buildOnBehalfForm($this, + $this->_contactType, + $countryID, + $stateID, + 'Contact Information', + TRUE + ); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + )); + } + + /** + * Form submission of new/edit contact is processed. + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $locType = CRM_Core_BAO_LocationType::getDefault(); + foreach (array( + 'phone', 'email', 'address') as $locFld) { + if (!empty($this->_defaults[$locFld]) && $this->_defaults[$locFld][1]['location_type_id']) { + $params[$locFld][1]['is_primary'] = $this->_defaults[$locFld][1]['is_primary']; + $params[$locFld][1]['location_type_id'] = $this->_defaults[$locFld][1]['location_type_id']; + } + else { + $params[$locFld][1]['is_primary'] = 1; + $params[$locFld][1]['location_type_id'] = $locType->id; + } + } + + $params['contact_type'] = $this->_contactType; + $params['contact_id'] = $this->_contactId; + + $contact = CRM_Contact_BAO_Contact::create($params, TRUE); + + // set status message. + if ($this->_contactId) { + $message = ts('%1 has been updated.', array(1 => $contact->display_name)); + } + else { + $message = ts('%1 has been created.', array(1 => $contact->display_name)); + } + CRM_Core_Session::setStatus($message, ts('Contact Saved'), 'success'); + } +} + diff --git a/CRM/Contact/Form/Relationship.php b/CRM/Contact/Form/Relationship.php new file mode 100644 index 0000000000..30a8ee2123 --- /dev/null +++ b/CRM/Contact/Form/Relationship.php @@ -0,0 +1,832 @@ +_cdType = CRM_Utils_Array::value('type', $_GET); + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + return CRM_Custom_Form_CustomData::preProcess($this); + } + + $this->_contactId = $this->get('contactId'); + + $this->_relationshipId = $this->get('id'); + + $this->_rtype = CRM_Utils_Request::retrieve('rtype', 'String', $this); + + $this->_rtypeId = CRM_Utils_Request::retrieve('relTypeId', 'String', $this); + + $this->_display_name_a = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactId, 'display_name'); + + $this->assign('sort_name_a', $this->_display_name_a); + CRM_Utils_System::setTitle(ts('Relationships for') . ' ' . $this->_display_name_a); + + $this->_caseId = CRM_Utils_Request::retrieve('caseID', 'Integer', $this); + + //get the relationship values. + $this->_values = array(); + if ($this->_relationshipId) { + $params = array('id' => $this->_relationshipId); + CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_Relationship', $params, $this->_values); + } + + if (!$this->_rtypeId) { + $params = $this->controller->exportValues($this->_name); + if (isset($params['relationship_type_id'])) { + $this->_rtypeId = $params['relationship_type_id']; + } + elseif (!empty($this->_values)) { + $this->_rtypeId = $this->_values['relationship_type_id'] . '_' . $this->_rtype; + } + } + + //get the relationship type id + $this->_relationshipTypeId = str_replace(array('_a_b', '_b_a'), array('', ''), $this->_rtypeId); + + //get the relationship type + if (!$this->_rtype) { + $this->_rtype = str_replace($this->_relationshipTypeId . '_', '', $this->_rtypeId); + } + $this->assign('rtype', $this->_rtype); + + + //use name as it remain constant, CRM-3336 + $this->_allRelationshipNames = CRM_Core_PseudoConstant::relationshipType('name'); + + // when custom data is included in this page + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + CRM_Custom_Form_CustomData::preProcess($this); + CRM_Custom_Form_CustomData::buildQuickForm($this); + CRM_Custom_Form_CustomData::setDefaultValues($this); + } + } + + /** + * This function sets the default values for the form. Relationship that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + $defaults = array(); + + if ($this->_action & CRM_Core_Action::UPDATE) { + if (!empty($this->_values)) { + $defaults['relationship_type_id'] = $this->_rtypeId; + if (CRM_Utils_Array::value('start_date', $this->_values)) { + list($defaults['start_date']) = CRM_Utils_Date::setDateDefaults($this->_values['start_date']); + } + if (CRM_Utils_Array::value('end_date', $this->_values)) { + list($defaults['end_date']) = CRM_Utils_Date::setDateDefaults($this->_values['end_date']); + } + $defaults['description'] = CRM_Utils_Array::value('description', $this->_values); + $defaults['is_active'] = CRM_Utils_Array::value('is_active', $this->_values); + $defaults['is_permission_a_b'] = CRM_Utils_Array::value('is_permission_a_b', $this->_values); + $defaults['is_permission_b_a'] = CRM_Utils_Array::value('is_permission_b_a', $this->_values); + $contact = new CRM_Contact_DAO_Contact(); + if ($this->_rtype == 'a_b' && $this->_values['contact_id_a'] == $this->_contactId) { + $contact->id = $this->_values['contact_id_b']; + } + else { + $contact->id = $this->_values['contact_id_a']; + } + if ($contact->find(TRUE)) { + $this->_display_name_b = $contact->display_name; + $this->assign('sort_name_b', $this->_display_name_b); + + //is current employee/employer. + if ($this->_allRelationshipNames[$this->_relationshipTypeId]["name_{$this->_rtype}"] == 'Employee of' && + $contact->id == CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactId, 'employer_id') + ) { + $defaults['is_current_employer'] = 1; + $this->_values['current_employee_id'] = $this->_contactId; + $this->_values['current_employer_id'] = $contact->id; + } + elseif ($this->_allRelationshipNames[$this->_relationshipTypeId]["name_{$this->_rtype}"] == 'Employer of' && + $this->_contactId == $contact->employer_id + ) { + $defaults['is_current_employer'] = 1; + $this->_values['current_employee_id'] = $contact->id; + $this->_values['current_employer_id'] = $this->_contactId; + } + } + + $relationshipID = $this->_values['id']; + $query = "SELECT id, note FROM civicrm_note where entity_table = 'civicrm_relationship' and entity_id = $relationshipID order by modified_date desc"; + $dao = new CRM_Core_DAO(); + $dao->query($query); + if ($dao->fetch($query)) { + $defaults['note'] = $dao->note; + } + } + } + else { + $defaults['is_active'] = 1; + $defaults['relationship_type_id'] = $this->_rtypeId; + } + + $this->_enabled = $defaults['is_active']; + return $defaults; + } + + /** + * This function is used to add the rules for form. + * + * @return None + * @access public + */ + function addRules() { + if ($this->_cdType) { + return; + } + + if (!($this->_action & CRM_Core_Action::DELETE)) { + $this->addRule('relationship_type_id', ts('Please select a relationship type.'), 'required'); + + // add a form rule only when creating a new relationship + // edit is severely limited, so add a simpleer form rule + if ($this->_action & CRM_Core_Action::ADD) { + $this->addFormRule(array('CRM_Contact_Form_Relationship', 'formRule'), $this); + $this->addFormRule(array('CRM_Contact_Form_Relationship', 'dateRule')); + } + elseif ($this->_action & CRM_Core_Action::UPDATE) { + $this->addFormRule(array('CRM_Contact_Form_Relationship', 'dateRule')); + } + } + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::buildQuickForm($this); + } + + $relTypeID = explode('_', $this->_rtypeId, 3); + + if ($this->_action & CRM_Core_Action::DELETE) { + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + return; + } + + $callAjax = $this->get('callAjax'); + + $searchRows = NULL; + if (!$callAjax) { + $searchRows = $this->get('searchRows'); + } + else { + + $this->addElement('hidden', 'store_contacts', '', array('id' => 'store_contacts')); + $sourceUrl = 'snippet=4&relType=' . $this->get('relType'); + $sourceUrl .= '&relContact=' . $this->get('relContact'); + $sourceUrl .= '&cid=' . $this->_contactId; + + $this->assign('searchCount', TRUE); + + // To handle employee of and employer of + if (!empty($this->_relationshipTypeId) && + !empty($this->_rtype) + ) { + $sourceUrl .= '&typeName=' . $this->_allRelationshipNames[$this->_relationshipTypeId]["name_{$this->_rtype}"]; + } + $this->assign('sourceUrl', CRM_Utils_System::url('civicrm/ajax/relationshipcontacts', $sourceUrl, FALSE, NULL, FALSE)); + } + + $this->assign('callAjax', $callAjax); + $this->_callAjax = $callAjax; + + $this->addElement('select', + 'relationship_type_id', + ts('Relationship Type'), + array( + '' => ts('- select -')) + + CRM_Contact_BAO_Relationship::getContactRelationshipType($this->_contactId, + $this->_rtype, + $this->_relationshipId, + NULL, FALSE, 'label' + ) + ); + + // add a ajax facility for searching contacts + $dataUrl = CRM_Utils_System::url('civicrm/ajax/search', 'reset=1', TRUE, NULL, FALSE); + $this->assign('dataUrl', $dataUrl); + CRM_Contact_Form_NewContact::buildQuickForm($this); + + $this->addDate('start_date', ts('Start Date'), FALSE, array('formatType' => 'searchDate')); + $this->addDate('end_date', ts('End Date'), FALSE, array('formatType' => 'searchDate')); + $this->addElement('checkbox', 'is_active', ts('Enabled?'), NULL, NULL); + + $this->addElement('checkbox', 'is_permission_a_b', ts('Permission for contact a to view and update information for contact b'), NULL); + $this->addElement('checkbox', 'is_permission_b_a', ts('permission for contact b to view and update information for contact a'), NULL); + + $this->add('text', 'description', ts('Description'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Relationship', 'description')); + + CRM_Contact_Form_Edit_Notes::buildQuickForm($this); + + $searchCount = $this->get('searchCount'); + $duplicateRelationship = $this->get('duplicateRelationship'); + $searchDone = $this->get('searchDone'); + + $isEmployeeOf = $isEmployerOf = FALSE; + if (!empty($this->_relationshipTypeId) && + !empty($this->_rtype) + ) { + if ($this->_allRelationshipNames[$this->_relationshipTypeId]["name_{$this->_rtype}"] == 'Employee of') { + $isEmployeeOf = TRUE; + } + elseif ($this->_allRelationshipNames[$this->_relationshipTypeId]["name_{$this->_rtype}"] == 'Employer of') { + $isEmployerOf = TRUE; + } + } + + $employers = $checkBoxes = $employees = array(); + if ($searchRows) { + foreach ($searchRows as $id => $row) { + $checkBoxes[$id] = $this->createElement('checkbox', $id, NULL, ''); + if ($isEmployeeOf) { + $employers[$id] = $this->createElement('radio', NULL, $id, NULL, $id); + } + elseif ($isEmployerOf) { + $employees[$id] = $this->createElement('checkbox', $id, NULL, ''); + } + } + + $this->addGroup($checkBoxes, 'contact_check'); + $this->assign('searchRows', $searchRows); + } + + if ($isEmployeeOf) { + $this->assign('isEmployeeOf', $isEmployeeOf); + if (!$callAjax) { + $this->addGroup($employers, 'employee_of'); + } + } + elseif ($isEmployerOf) { + $this->assign('isEmployerOf', $isEmployerOf); + if (!$callAjax) { + $this->addGroup($employees, 'employer_of'); + } + } + + if ($callAjax && ($isEmployeeOf || $isEmployerOf)) { + $this->addElement('hidden', 'store_employers', '', array('id' => 'store_employers')); + } + + if ($this->_action & CRM_Core_Action::UPDATE) { + $this->addElement('checkbox', 'is_current_employer'); + } + + $this->assign('duplicateRelationship', $duplicateRelationship); + $this->assign('searchCount', $searchCount); + $this->assign('searchDone', $searchDone); + + if ($this->get('contact_type')) { + $typeLabel = CRM_Contact_BAO_ContactType::getLabel($this->get('contact_type')); + $this->assign('contact_type', $this->get('contact_type')); + $this->assign('contact_type_display', $typeLabel); + } + + if ($searchDone) { + $searchBtn = ts('Search Again'); + } + else { + $searchBtn = ts('Search'); + } + $this->addElement('submit', $this->getButtonName('refresh'), $searchBtn, array('class' => 'form-submit', 'id' => 'search-button')); + $this->addElement('submit', $this->getButtonName('refresh', 'save'), 'Quick Save', array('class' => 'form-submit', 'id' => 'quick-save')); + $this->addElement('submit', $this->getButtonName('cancel'), ts('Cancel'), array('class' => 'form-submit')); + + $this->addElement('submit', $this->getButtonName('refresh', 'savedetails'), 'Save Relationship', array('class' => 'form-submit hiddenElement', 'id' => 'details-save')); + $this->addElement('checkbox', 'add_current_employer', ts('Current Employer'), NULL); + $this->addElement('checkbox', 'add_current_employee', ts('Current Employee'), NULL); + + //need to assign custom data type and subtype to the template + $this->assign('customDataType', 'Relationship'); + $this->assign('customDataSubType', $this->_relationshipTypeId); + $this->assign('entityID', $this->_relationshipId); + + // make this form an upload since we dont know if the custom data injected dynamically + // is of type file etc $uploadNames = $this->get( + // 'uploadNames' ); + $buttonParams = array( + 'type' => 'upload', + 'name' => ts('Save Relationship'), + 'isDefault' => TRUE, + ); + if ($callAjax) { + $buttonParams['js'] = array('onclick' => ' submitAjaxData();'); + } + + $this->addButtons(array( + $buttonParams + , + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * This function is called when the form is submitted + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + $quickSave = FALSE; + if (CRM_Utils_Array::value('_qf_Relationship_refresh_save', $_POST) || + CRM_Utils_Array::value('_qf_Relationship_refresh_savedetails', $_POST) + ) { + $quickSave = TRUE; + } + + $this->set('searchDone', 0); + $this->set('callAjax', FALSE); + if (CRM_Utils_Array::value('_qf_Relationship_refresh', $_POST) || $quickSave) { + if (is_numeric($params['contact_select_id'][1])) { + if ($quickSave) { + $params['contact_check'] = array($params['contact_select_id'][1] => 1); + } + } + else { + $this->set('callAjax', TRUE); + $this->set('relType', $params['relationship_type_id']); + $this->set('relContact', $params['contact'][1]); + $quickSave = FALSE; + } + $this->set('searchDone', 1); + if (!$quickSave) { + return; + } + } + + // action is taken depending upon the mode + $ids = array(); + $ids['contact'] = $this->_contactId; + + // modify params for ajax call + $this->modifyParams($params); + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Contact_BAO_Relationship::del($this->_relationshipId); + return; + } + + $relationshipTypeId = str_replace(array('_a_b', '_b_a'), array('', ''), $params['relationship_type_id']); + if ($this->_action & CRM_Core_Action::UPDATE) { + $ids['relationship'] = $this->_relationshipId; + $relation = CRM_Contact_BAO_Relationship::getContactIds($this->_relationshipId); + $ids['contactTarget'] = ($relation->contact_id_a == $this->_contactId) ? $relation->contact_id_b : $relation->contact_id_a; + + //if relationship type change and previously it was + //employer / emplyee relationship with current employer + //than clear the current employer. CRM-3235. + + //make sure we has to have employer id before firing queries, CRM-7306 + $employerId = CRM_Utils_Array::value('current_employee_id', $this->_values); + $isDisabled = TRUE; + if (CRM_Utils_Array::value('is_active', $params)) { + $isDisabled = FALSE; + } + $relChanged = TRUE; + if ($relationshipTypeId == $this->_values['relationship_type_id']) { + $relChanged = FALSE; + } + if ($employerId && ($isDisabled || $relChanged)) { + CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($this->_values['current_employee_id']); + } + + //if field key doesn't exists in params that means the user has unchecked checkbox, + //hence fill FALSE to params + $params['is_active'] = $isDisabled ? FALSE : TRUE; + $params['is_permission_a_b'] = CRM_Utils_Array::value('is_permission_a_b', $params, FALSE); + $params['is_permission_b_a'] = CRM_Utils_Array::value('is_permission_b_a', $params, FALSE); + } + elseif ($quickSave) { + if (CRM_Utils_Array::value('add_current_employee', $params) && + $this->_allRelationshipNames[$relationshipTypeId]['name_a_b'] == 'Employee of' + ) { + $params['employee_of'] = $params['contact_select_id'][1]; + } + elseif (CRM_Utils_Array::value('add_current_employer', $params) && + $this->_allRelationshipNames[$relationshipTypeId]['name_b_a'] == 'Employer of' + ) { + $params['employer_of'] = array($params['contact_select_id'][1] => 1); + } + if (!$this->_rtype) { + $this->_rtype = str_replace($relationshipTypeId . '_', '', $params['relationship_type_id']); + } + } + + if (!$params['note']) { + $params['note'] = 'null'; + } + $params['start_date'] = CRM_Utils_Date::processDate($params['start_date'], NULL, TRUE); + $params['end_date'] = CRM_Utils_Date::processDate($params['end_date'], NULL, TRUE); + + //special case to handle if all checkboxes are unchecked + $customFields = CRM_Core_BAO_CustomField::getFields('Relationship', FALSE, FALSE, $relationshipTypeId); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_relationshipId, + 'Relationship' + ); + + list($valid, $invalid, $duplicate, $saved, $relationshipIds) = CRM_Contact_BAO_Relationship::create($params, $ids); + + // if this is called from case view, + //create an activity for case role removal.CRM-4480 + if ($this->_caseId) { + CRM_Case_BAO_Case::createCaseRoleActivity($this->_caseId, $relationshipIds, $params['contact_check'], $this->_contactId); + } + + $status = ''; + if ($valid) { + CRM_Core_Session::setStatus(ts('New relationship created.', array('count' => $valid, 'plural' => '%count new relationships created.')), ts('Saved'), 'success'); + } + if ($invalid) { + CRM_Core_Session::setStatus(ts('%count relationship record was not created due to an invalid target contact type.', array('count' => $invalid, 'plural' => '%count relationship records were not created due to invalid target contact types.')), ts('%count invalid relationship record', array('count' => $invalid, 'plural' => '%count invalid relationship records'))); + } + if ($duplicate) { + CRM_Core_Session::setStatus(ts('One relationship was not created because it already exists.', array('count' => $duplicate, 'plural' => '%count relationships were not created because they already exist.')), ts('%count duplicate relationship', array('count' => $duplicate, 'plural' => '%count duplicate relationships'))); + } + if ($saved) { + CRM_Core_Session::setStatus(ts('Relationship record has been updated.'), ts('Saved'), 'success'); + } + + if (!empty($relationshipIds)) { + $note = new CRM_Core_DAO_Note(); + $note->entity_id = $relationshipIds[0]; + $note->entity_table = 'civicrm_relationship'; + $noteIds = array(); + if ($note->find(TRUE)) { + $id = $note->id; + $noteIds['id'] = $id; + } + + $noteParams = array( + 'entity_id' => $relationshipIds[0], + 'entity_table' => 'civicrm_relationship', + 'note' => $params['note'], + 'contact_id' => $this->_contactId, + ); + CRM_Core_BAO_Note::add($noteParams, $noteIds); + + $params['relationship_ids'] = $relationshipIds; + } + + // Membership for related contacts CRM-1657 + if (CRM_Core_Permission::access('CiviMember') && (!$duplicate)) { + if ($this->_action & CRM_Core_Action::ADD) { + CRM_Contact_BAO_Relationship::relatedMemberships($this->_contactId, + $params, $ids, + $this->_action + ); + } + elseif ($this->_action & CRM_Core_Action::UPDATE) { + //fixes for CRM-7985 + //only if the relationship has been toggled to enable /disable + if (CRM_Utils_Array::value('is_active', $params) != $this->_enabled) { + $active = CRM_Utils_Array::value('is_active', $params) ? CRM_Core_Action::ENABLE : CRM_Core_Action::DISABLE; + CRM_Contact_BAO_Relationship::disableEnableRelationship($this->_relationshipId, $active); + } + } + } + //handle current employee/employer relationship, CRM-3532 + if ($this->_allRelationshipNames[$relationshipTypeId]["name_{$this->_rtype}"] == 'Employee of') { + $orgId = NULL; + if (CRM_Utils_Array::value('employee_of', $params)) { + $orgId = $params['employee_of']; + } + elseif ($this->_action & CRM_Core_Action::UPDATE) { + if (CRM_Utils_Array::value('is_current_employer', $params) && + CRM_Utils_Array::value('is_active', $params) + ) { + if (CRM_Utils_Array::value('contactTarget', $ids) != + CRM_Utils_Array::value('current_employer_id', $this->_values) + ) { + $orgId = CRM_Utils_Array::value('contactTarget', $ids); + } + } + elseif (CRM_Utils_Array::value('contactTarget', $ids) == + CRM_Utils_Array::value('current_employer_id', $this->_values) + ) { + //clear current employer. + CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($this->_contactId); + } + } + + //set current employer + if ($orgId) { + $currentEmpParams[$this->_contactId] = $orgId; + CRM_Contact_BAO_Contact_Utils::setCurrentEmployer($currentEmpParams); + } + } + elseif ($this->_allRelationshipNames[$relationshipTypeId]["name_{$this->_rtype}"] == 'Employer of') { + $individualIds = array(); + if (CRM_Utils_Array::value('employer_of', $params)) { + $individualIds = array_keys($params['employer_of']); + } + elseif ($this->_action & CRM_Core_Action::UPDATE) { + if (CRM_Utils_Array::value('is_current_employer', $params)) { + if (CRM_Utils_Array::value('contactTarget', $ids) != + CRM_Utils_Array::value('current_employee_id', $this->_values) + ) { + $individualIds[] = CRM_Utils_Array::value('contactTarget', $ids); + } + } + elseif (CRM_Utils_Array::value('contactTarget', $ids) == + CRM_Utils_Array::value('current_employee_id', $this->_values) + ) { + // clear current employee + CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($ids['contactTarget']); + } + } + + //set current employee + if (!empty($individualIds)) { + + //build the employee params. + foreach ($individualIds as $key => $Id) { + $currentEmpParams[$Id] = $this->_contactId; + } + + CRM_Contact_BAO_Contact_Utils::setCurrentEmployer($currentEmpParams); + } + } + + if ($quickSave) { + $session = CRM_Core_Session::singleton(); + CRM_Utils_System::redirect($session->popUserContext()); + } + } + //end of function + + /** + * function for validation + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return mixed true or array of errors + * @access public + * @static + */ + static function formRule($params, $files, $form) { + // hack, no error check for refresh + if (CRM_Utils_Array::value('_qf_Relationship_refresh', $_POST) || + CRM_Utils_Array::value('_qf_Relationship_refresh_save', $_POST) || + CRM_Utils_Array::value('_qf_Relationship_refresh_savedetails', $_POST) + ) { + return TRUE; + } + + $form->modifyParams($params); + + $ids = array(); + $session = CRM_Core_Session::singleton(); + $ids['contact'] = $form->get('contactId'); + $ids['relationship'] = $form->get('relationshipId'); + + $errors = array(); + $employerId = NULL; + if (CRM_Utils_Array::value('contact_check', $params) && is_array($params['contact_check'])) { + foreach ($params['contact_check'] as $cid => $dontCare) { + $message = CRM_Contact_BAO_Relationship::checkValidRelationship($params, $ids, $cid); + if ($message) { + $errors['relationship_type_id'] = $message; + break; + } + + if ($cid == CRM_Utils_Array::value('employee_of', $params)) { + $employerId = $cid; + } + } + } + else { + if ($form->_callAjax) { + $errors['store_contacts'] = ts('Select select at least one contact from Target Contact(s).'); + } + else { + $errors['contact_check'] = ts('Please select at least one contact.'); + } + } + + if (CRM_Utils_Array::value('employee_of', $params) && + !$employerId + ) { + if ($form->_callAjax) { + $errors['store_employer'] = ts('Current employer should be one of the selected contacts.'); + } + else { + $errors['employee_of'] = ts('Current employer should be one of the selected contacts.'); + } + } + + if (CRM_Utils_Array::value('employer_of', $params) && + CRM_Utils_Array::value('contact_check', $params) && + array_diff(array_keys($params['employer_of']), array_keys($params['contact_check'])) + ) { + if ($form->_callAjax) { + $errors['store_employer'] = ts('Current employee should be among the selected contacts.'); + } + else { + $errors['employer_of'] = ts('Current employee should be among the selected contacts.'); + } + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * function for date validation + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return mixed true or array of errors + * @access public + * @static + */ + static function dateRule($params) { + $errors = array(); + + // check start and end date + if (CRM_Utils_Array::value('start_date', $params) && + CRM_Utils_Array::value('end_date', $params) + ) { + $start_date = CRM_Utils_Date::format(CRM_Utils_Array::value('start_date', $params)); + $end_date = CRM_Utils_Date::format(CRM_Utils_Array::value('end_date', $params)); + if ($start_date && $end_date && (int ) $end_date < (int ) $start_date) { + $errors['end_date'] = ts('The relationship end date cannot be prior to the start date.'); + } + } + + return empty($errors) ? TRUE : $errors; + } + + function modifyParams(&$params) { + if (!$this->_callAjax) { + return; + } + + if (CRM_Utils_Array::value('store_contacts', $params)) { + $storedContacts = array(); + foreach (explode(',', $params['store_contacts']) as $value) { + if ($value) { + $storedContacts[$value] = 1; + } + } + $params['contact_check'] = $storedContacts; + } + + if (CRM_Utils_Array::value('store_employers', $params)) { + $employeeContacts = array(); + foreach (explode(',', $params['store_employers']) as $value) { + if ($value) { + $employeeContacts[$value] = $value; + } + } + if ($this->_allRelationshipNames[$this->_relationshipTypeId]["name_{$this->_rtype}"] == 'Employee of') { + $params['employee_of'] = current($employeeContacts); + } + else { + $params['employer_of'] = $employeeContacts; + } + } + } +} + diff --git a/CRM/Contact/Form/Search.php b/CRM/Contact/Form/Search.php new file mode 100644 index 0000000000..4764ce9fed --- /dev/null +++ b/CRM/Contact/Form/Search.php @@ -0,0 +1,974 @@ + 'Show members of group', + 'amtg' => 'Add members to group', + 'basic' => 'Basic Search', + 'search' => 'Search', + 'builder' => 'Search Builder', + 'advanced' => 'Advanced Search', + 'custom' => 'Custom Search', + ); + } + return self::$_validContext; + } + + static function isSearchContext($context) { + $searchContext = CRM_Utils_Array::value($context, self::validContext()); + return $searchContext ? TRUE : FALSE; + } + + static function setModeValues() { + if (!self::$_modeValues) { + self::$_modeValues = array( + 1 => array( + 'selectorName' => self::$_selectorName, + 'selectorLabel' => ts('Contacts'), + 'taskFile' => 'CRM/Contact/Form/Search/ResultTasks.tpl', + 'taskContext' => NULL, + 'resultFile' => 'CRM/Contact/Form/Selector.tpl', + 'resultContext' => NULL, + 'taskClassName' => 'CRM_Contact_Task', + ), + 2 => array( + 'selectorName' => 'CRM_Contribute_Selector_Search', + 'selectorLabel' => ts('Contributions'), + 'taskFile' => 'CRM/common/searchResultTasks.tpl', + 'taskContext' => 'Contribution', + 'resultFile' => 'CRM/Contribute/Form/Selector.tpl', + 'resultContext' => 'Search', + 'taskClassName' => 'CRM_Contribute_Task', + ), + 3 => array( + 'selectorName' => 'CRM_Event_Selector_Search', + 'selectorLabel' => ts('Event Participants'), + 'taskFile' => 'CRM/common/searchResultTasks.tpl', + 'taskContext' => NULL, + 'resultFile' => 'CRM/Event/Form/Selector.tpl', + 'resultContext' => 'Search', + 'taskClassName' => 'CRM_Event_Task', + ), + 4 => array( + 'selectorName' => 'CRM_Activity_Selector_Search', + 'selectorLabel' => ts('Activities'), + 'taskFile' => 'CRM/common/searchResultTasks.tpl', + 'taskContext' => NULL, + 'resultFile' => 'CRM/Activity/Form/Selector.tpl', + 'resultContext' => 'Search', + 'taskClassName' => 'CRM_Activity_Task', + ), + 5 => array( + 'selectorName' => 'CRM_Member_Selector_Search', + 'selectorLabel' => ts('Memberships'), + 'taskFile' => "CRM/common/searchResultTasks.tpl", + 'taskContext' => NULL, + 'resultFile' => 'CRM/Member/Form/Selector.tpl', + 'resultContext' => 'Search', + 'taskClassName' => 'CRM_Member_Task', + ), + 6 => array( + 'selectorName' => 'CRM_Case_Selector_Search', + 'selectorLabel' => ts('Cases'), + 'taskFile' => "CRM/common/searchResultTasks.tpl", + 'taskContext' => NULL, + 'resultFile' => 'CRM/Case/Form/Selector.tpl', + 'resultContext' => 'Search', + 'taskClassName' => 'CRM_Case_Task', + ), + 7 => array( + 'selectorName' => self::$_selectorName, + 'selectorLabel' => ts('Related Contacts'), + 'taskFile' => 'CRM/Contact/Form/Search/ResultTasks.tpl', + 'taskContext' => NULL, + 'resultFile' => 'CRM/Contact/Form/Selector.tpl', + 'resultContext' => NULL, + 'taskClassName' => 'CRM_Contact_Task', + ), + ); + } + } + + static function getModeValue($mode = 1) { + self::setModeValues(); + + if (!array_key_exists($mode, self::$_modeValues)) { + $mode = 1; + } + + return self::$_modeValues[$mode]; + } + + static function getModeSelect() { + self::setModeValues(); + + $select = array(); + foreach (self::$_modeValues as $id => & $value) { + $select[$id] = $value['selectorLabel']; + } + + // unset contributions or participants if user does not have + // permission on them + if (!CRM_Core_Permission::access('CiviContribute')) { + unset($select['2']); + } + + if (!CRM_Core_Permission::access('CiviEvent')) { + unset($select['3']); + } + + if (!CRM_Core_Permission::check('view all activities')) { + unset($select['4']); + } + return $select; + } + + /** + * Build the common elements between the search/advanced form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $permission = CRM_Core_Permission::getPermission(); + // some tasks.. what do we want to do with the selected contacts ? + $tasks = array('' => ts('- actions -')); + if ($this->_componentMode == 1 || $this->_componentMode == 7) { + $tasks += CRM_Contact_Task::permissionedTaskTitles($permission, + CRM_Utils_Array::value('deleted_contacts', $this->_formValues) + ); + } + else { + $className = $this->_modeValue['taskClassName']; + $tasks += $className::permissionedTaskTitles($permission, false); + } + + if (isset($this->_ssID)) { + if ($permission == CRM_Core_Permission::EDIT) { + $tasks = $tasks + CRM_Contact_Task::optionalTaskTitle(); + } + + $search_custom_id = + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'search_custom_id'); + + $savedSearchValues = array( + 'id' => $this->_ssID, + 'name' => CRM_Contact_BAO_SavedSearch::getName($this->_ssID, 'title'), + 'search_custom_id' => $search_custom_id, + ); + $this->assign_by_ref('savedSearch', $savedSearchValues); + $this->assign('ssID', $this->_ssID); + } + + if ($this->_context === 'smog') { + // CRM-11788, we might want to do this for all of search where force=1 + $formQFKey = CRM_Utils_Array::value('qfKey', $this->_formValues); + $getQFKey = CRM_Utils_Array::value('qfKey', $_GET); + $postQFKey = CRM_Utils_Array::value('qfKey', $_POST); + if ($formQFKey && empty($getQFKey) && empty($postQFKey)) { + $url = CRM_Utils_System::makeURL('qfKey') . $formQFKey; + CRM_Utils_System::redirect($url); + } + + if (!empty($this->_groupID)) { + $permissionForGroup = FALSE; + + // check if user has permission to edit members of this group + $permission = CRM_Contact_BAO_Group::checkPermission($this->_groupID); + if ($permission && in_array(CRM_Core_Permission::EDIT, $permission)) { + $permissionForGroup = TRUE; + } + + // check if _groupID exists, it might not if + // we are displaying a hidden group + if (!isset($this->_group[$this->_groupID])) { + $permissionForGroup = FALSE; + $this->_group[$this->_groupID] = + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'title'); + } + + $this->assign('permissionedForGroup', $permissionForGroup); + + // set the group title + $groupValues = array('id' => $this->_groupID, 'title' => $this->_group[$this->_groupID]); + $this->assign_by_ref('group', $groupValues); + + // also set ssID if this is a saved search + $ssID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'saved_search_id'); + $this->assign('ssID', $ssID); + + //get the saved search mapping id + if ($ssID) { + $this->_ssID = $ssID; + $ssMappingId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $ssID, 'mapping_id'); + $this->assign('ssMappingID', $ssMappingId); + } + + // Set dynamic page title for 'Show Members of Group' + CRM_Utils_System::setTitle(ts('Contacts in Group: %1', array(1 => $this->_group[$this->_groupID]))); + } + + $group_contact_status = array(); + foreach (CRM_Core_SelectValues::groupContactStatus() as $k => $v) { + if (!empty($k)) { + $group_contact_status[] = $this->createElement('checkbox', $k, NULL, $v); + } + } + $this->addGroup($group_contact_status, + 'group_contact_status', ts('Group Status') + ); + + $this->assign('permissionedForGroup', FALSE); + } + + // add the go button for the action form, note it is of type 'next' rather than of type 'submit' + if ($this->_context === 'amtg') { + // check if _groupID exists, it might not if + // we are displaying a hidden group + if (!isset($this->_group[$this->_amtgID])) { + $this->assign('permissionedForGroup', FALSE); + $this->_group[$this->_amtgID] = + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_amtgID, 'title'); + } + + // Set dynamic page title for 'Add Members Group' + CRM_Utils_System::setTitle(ts('Add to Group: %1', array(1 => $this->_group[$this->_amtgID]))); + // also set the group title and freeze the action task with Add Members to Group + $groupValues = array('id' => $this->_amtgID, 'title' => $this->_group[$this->_amtgID]); + $this->assign_by_ref('group', $groupValues); + $this->add('submit', $this->_actionButtonName, ts('Add Contacts to %1', array(1 => $this->_group[$this->_amtgID])), + array( + 'class' => 'form-submit', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 1);", + ) + ); + $this->add('hidden', 'task', CRM_Contact_Task::GROUP_CONTACTS); + } + else { + $this->add('select', 'task', ts('Actions:') . ' ', $tasks); + $this->add('submit', $this->_actionButtonName, ts('Go'), + array( + 'class' => 'form-submit', + 'id' => 'Go', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 0, 1);", + ) + ); + } + + // need to perform tasks on all or selected items ? using radio_ts(task selection) for it + $selectedRowsRadio = $this->addElement('radio', 'radio_ts', NULL, '', 'ts_sel', array( + 'checked' => 'checked', + 'onclick' => 'toggleTaskAction( true );', + )); + $this->assign('ts_sel_id', $selectedRowsRadio->_attributes['id']); + + + if ($qfKeyParam = CRM_Utils_Array::value('qfKey', $this->_formValues)) { + $qfKeyParam = "civicrm search {$qfKeyParam}"; + $selectedContactIdsArr = CRM_Core_BAO_PrevNextCache::getSelection($qfKeyParam); + $selectedContactIds = array_keys($selectedContactIdsArr[$qfKeyParam]); + } + + $this->assign_by_ref('selectedContactIds', $selectedContactIds); + + $allRowsRadio = $this->addElement('radio', 'radio_ts', NULL, '', 'ts_all', array('onclick' => $this->getName() . ".toggleSelect.checked = false; toggleCheckboxVals('mark_x_', this);toggleTaskAction( true );toggleContactSelection( 'resetSel', '{$qfKeyParam}', 'reset' );")); + $this->assign('ts_all_id', $allRowsRadio->_attributes['id']); + + /* + * add form checkboxes for each row. This is needed out here to conform to QF protocol + * of all elements being declared in builQuickForm + */ + + $rows = $this->get('rows'); + + if (is_array($rows)) { + $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('onclick' => "toggleTaskAction( true ); toggleCheckboxVals('mark_x_',this);return toggleContactSelection( 'toggleSelect', '" . $qfKeyParam . "' , 'multiple' );")); + + $unselectedContactIds = array(); + foreach ($rows as $row) { + $this->addElement('checkbox', $row['checkbox'], + NULL, NULL, + array('onclick' => "toggleContactSelection( '" . $row['checkbox'] . "', '" . $qfKeyParam . "' , 'single' );toggleTaskAction( true ); return checkSelectedBox('" . $row['checkbox'] . "');") + ); + + if (!in_array($row['contact_id'], $selectedContactIds)) { + $unselectedContactIds[] = $row['contact_id']; + } + } + $this->assign_by_ref('unselectedContactIds', $unselectedContactIds); + } + + // add buttons + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + ) + ); + + $this->add('submit', $this->_printButtonName, ts('Print'), + array( + 'class' => 'form-submit', + 'id' => 'Print', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 1, 1);", + ) + ); + + $this->setDefaultAction('refresh'); + } + + /** + * processing needed for buildForm and later + * + * @return void + * @access public + */ + function preProcess() { + // set the various class variables + + $this->_group = CRM_Core_PseudoConstant::group(); + + $this->_groupIterator = CRM_Core_PseudoConstant::groupIterator(); + $this->_tag = CRM_Core_BAO_Tag::getTags(); + $this->_done = FALSE; + + /* + * we allow the controller to set force/reset externally, useful when we are being + * driven by the wizard framework + */ + + $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean', + CRM_Core_DAO::$_nullObject + ); + + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', CRM_Core_DAO::$_nullObject); + $this->_groupID = CRM_Utils_Request::retrieve('gid', 'Positive', $this); + $this->_amtgID = CRM_Utils_Request::retrieve('amtgID', 'Positive', $this); + $this->_ssID = CRM_Utils_Request::retrieve('ssID', 'Positive', $this); + $this->_sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String', $this); + $this->_ufGroupID = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $this->_componentMode = CRM_Utils_Request::retrieve('component_mode', 'Positive', $this, FALSE, 1, $_REQUEST); + $this->_operator = CRM_Utils_Request::retrieve('operator', 'String', $this, FALSE, 1, $_REQUEST, 'AND'); + + /** + * set the button names + */ + $this->_searchButtonName = $this->getButtonName('refresh'); + $this->_printButtonName = $this->getButtonName('next', 'print'); + $this->_actionButtonName = $this->getButtonName('next', 'action'); + + $this->assign('printButtonName', $this->_printButtonName); + + $this->assign('actionButtonName', $this->_actionButtonName); + + // reset from session, CRM-3526 + $session = CRM_Core_Session::singleton(); + if ($this->_force && $session->get('selectedSearchContactIds')) { + $session->resetScope('selectedSearchContactIds'); + } + + // if we dont get this from the url, use default if one exsts + $config = CRM_Core_Config::singleton(); + if ($this->_ufGroupID == NULL && + $config->defaultSearchProfileID != NULL + ) { + $this->_ufGroupID = $config->defaultSearchProfileID; + } + + // assign context to drive the template display, make sure context is valid + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'search'); + if (!CRM_Utils_Array::value($this->_context, self::validContext())) { + $this->_context = 'search'; + } + $this->set('context', $this->_context); + $this->assign('context', $this->_context); + + $this->_modeValue = self::getModeValue($this->_componentMode); + $this->assign($this->_modeValue); + + $this->set('selectorName', self::$_selectorName); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + // $this->controller->isModal( ) returns true if page is + // valid, i.e all the validations are true + + if (!empty($_POST) && !$this->controller->isModal()) { + $this->_formValues = $this->controller->exportValues($this->_name); + + $this->normalizeFormValues(); + $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $this->_returnProperties = &$this->returnProperties(); + + // also get the uf group id directly from the post value + $this->_ufGroupID = CRM_Utils_Array::value('uf_group_id', $_POST, $this->_ufGroupID); + $this->_formValues['uf_group_id'] = $this->_ufGroupID; + $this->set('id', $this->_ufGroupID); + + // also get the object mode directly from the post value + $this->_componentMode = CRM_Utils_Array::value('component_mode', $_POST, $this->_componentMode); + + // also get the operator from the post value if set + $this->_operator = CRM_Utils_Array::value('operator', $_POST, $this->_operator); + $this->_formValues['operator'] = $this->_operator; + $this->set('operator', $this->_operator); + } + else { + $this->_formValues = $this->get('formValues'); + $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $this->_returnProperties = &$this->returnProperties(); + if (!empty($this->_ufGroupID)) { + $this->set('id', $this->_ufGroupID); + } + } + + if (empty($this->_formValues)) { + //check if group is a smart group (fix for CRM-1255) + if ($this->_groupID) { + if ($ssId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $this->_groupID, 'saved_search_id')) { + $this->_ssID = $ssId; + } + } + + // fix for CRM-1907 + if (isset($this->_ssID) && $this->_context != 'smog') { + // we only retrieve the saved search values if out current values are null + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + + //fix for CRM-1505 + if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'mapping_id')) { + $this->_params = CRM_Contact_BAO_SavedSearch::getSearchParams($this->_ssID); + } + else { + $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + } + $this->_returnProperties = &$this->returnProperties(); + } + else { + if (isset($this->_ufGroupID)) { + // also set the uf group id if not already present + $this->_formValues['uf_group_id'] = $this->_ufGroupID; + } + if (isset($this->_componentMode)) { + $this->_formValues['component_mode'] = $this->_componentMode; + } + if (isset($this->_operator)) { + $this->_formValues['operator'] = $this->_operator; + } + + // FIXME: we should generalise in a way that components could inject url-filters + // just like they build their own form elements + foreach (array( + 'mailing_id', 'mailing_delivery_status', 'mailing_open_status', + 'mailing_click_status', 'mailing_reply_status', 'mailing_optout', + 'mailing_forward', 'mailing_unsubscribe', 'mailing_date_low', + 'mailing_date_high', + ) as $mailingFilter) { + $type = 'String'; + if ($mailingFilter == 'mailing_id' && + $filterVal = CRM_Utils_Request::retrieve('mailing_id', 'Positive', $this) + ) { + $this->_formValues[$mailingFilter] = array($filterVal); + } + elseif ($filterVal = CRM_Utils_Request::retrieve($mailingFilter, $type, $this)) { + $this->_formValues[$mailingFilter] = $filterVal; + } + if ($filterVal) { + $this->_openedPanes['Mailings'] = 1; + $this->_formValues['hidden_CiviMail'] = 1; + } + } + } + } + $this->assign('id', + CRM_Utils_Array::value('uf_group_id', $this->_formValues) + ); + $operator = CRM_Utils_Array::value('operator', $this->_formValues, 'AND'); + $this->set('queryOperator', $operator); + if ($operator == 'OR') { + $this->assign('operator', ts('OR')); + } + else { + $this->assign('operator', ts('AND')); + } + + // show the context menu only when we’re not searching for deleted contacts; CRM-5673 + if (!CRM_Utils_Array::value('deleted_contacts', $this->_formValues)) { + $menuItems = CRM_Contact_BAO_Contact::contextMenu(); + $primaryActions = CRM_Utils_Array::value('primaryActions', $menuItems, array()); + $this->_contextMenu = CRM_Utils_Array::value('moreActions', $menuItems, array()); + $this->assign('contextMenu', $primaryActions + $this->_contextMenu); + } + + if (!isset($this->_componentMode)) { + $this->_componentMode = CRM_Contact_BAO_Query::MODE_CONTACTS; + } + $modeValues = self::getModeValue($this->_componentMode); + + self::$_selectorName = $this->_modeValue['selectorName']; + + $setDynamic = FALSE; + if (strpos(self::$_selectorName, 'CRM_Contact_Selector') !== FALSE) { + $selector = new self::$_selectorName( + $this->_customSearchClass, + $this->_formValues, + $this->_params, + $this->_returnProperties, + $this->_action, + false, true, + $this->_context, + $this->_contextMenu + ); + $setDynamic = TRUE; + } + else { + $selector = new self::$_selectorName( + $this->_params, + $this->_action, + null, false, null, + "search", "advanced" + ); + } + + $selector->setKey($this->controller->_key); + + $controller = new CRM_Contact_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $this->get(CRM_Utils_Sort::SORT_ID), + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::TRANSFER + ); + $controller->setEmbedded(TRUE); + $controller->setDynamicAction($setDynamic); + + if ($this->_force) { + + $this->postProcess(); + + /* + * Note that we repeat this, since the search creates and stores + * values that potentially change the controller behavior. i.e. things + * like totalCount etc + */ + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + $controller = new CRM_Contact_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::TRANSFER + ); + $controller->setEmbedded(TRUE); + $controller->setDynamicAction($setDynamic); + } + + $controller->moveFromSessionToTemplate(); + } + + function &getFormValues() { + return $this->_formValues; + } + + /** + * Common post processing + * + * @return void + * @access public + */ + function postProcess() { + /* + * sometime we do a postProcess early on, so we dont need to repeat it + * this will most likely introduce some more bugs :( + */ + + if ($this->_done) { + return; + } + $this->_done = TRUE; + + //for prev/next pagination + $crmPID = CRM_Utils_Request::retrieve('crmPID', 'Integer', CRM_Core_DAO::$_nullObject); + + if (array_key_exists($this->_searchButtonName, $_POST) || + ($this->_force && !$crmPID)) { + //reset the cache table for new search + $cacheKey = "civicrm search {$this->controller->_key}"; + CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey); + } + + //get the button name + $buttonName = $this->controller->getButtonName(); + + if (isset($this->_ufGroupID) && + !CRM_Utils_Array::value('uf_group_id', $this->_formValues) + ) { + $this->_formValues['uf_group_id'] = $this->_ufGroupID; + } + + if (isset($this->_componentMode) && + !CRM_Utils_Array::value('component_mode', $this->_formValues) + ) { + $this->_formValues['component_mode'] = $this->_componentMode; + } + + if (isset($this->_operator) && + !CRM_Utils_Array::value('operator', $this->_formValues) + ) { + $this->_formValues['operator'] = $this->_operator; + } + + if (!CRM_Utils_Array::value('qfKey', $this->_formValues)) { + $this->_formValues['qfKey'] = $this->controller->_key; + } + + if (!CRM_Core_Permission::check('access deleted contacts')) { + unset($this->_formValues['deleted_contacts']); + } + + $this->set('type', $this->_action); + $this->set('formValues', $this->_formValues); + $this->set('queryParams', $this->_params); + $this->set('returnProperties', $this->_returnProperties); + + if ($buttonName == $this->_actionButtonName || $buttonName == $this->_printButtonName) { + // check actionName and if next, then do not repeat a search, since we are going to the next page + // hack, make sure we reset the task values + $stateMachine = $this->controller->getStateMachine(); + $formName = $stateMachine->getTaskFormName(); + $this->controller->resetPage($formName); + return; + } + else { + $output = CRM_Core_Selector_Controller::SESSION; + + // create the selector, controller and run - store results in session + $searchChildGroups = TRUE; + if ($this->get('isAdvanced')) { + $searchChildGroups = FALSE; + } + + $setDynamic = FALSE; + + if (strpos(self::$_selectorName, 'CRM_Contact_Selector') !== FALSE) { + $selector = new self::$_selectorName ( + $this->_customSearchClass, + $this->_formValues, + $this->_params, + $this->_returnProperties, + $this->_action, + false, + $searchChildGroups, + $this->_context, + $this->_contextMenu + ); + $setDynamic = TRUE; + } + else { + $selector = new self::$_selectorName ( + $this->_params, + $this->_action, + null, + false, + null, + "search", + "advanced" + ); + } + + $selector->setKey($this->controller->_key); + + // added the sorting character to the form array + // lets recompute the aToZ bar without the sortByCharacter + // we need this in most cases except when just pager or sort values change, which + // we'll ignore for now + $config = CRM_Core_Config::singleton(); + // do this only for contact search + if ($setDynamic && $config->includeAlphabeticalPager) { + if ($this->_reset || + ($this->_sortByCharacter === NULL || $this->_sortByCharacter == '') + ) { + $aToZBar = CRM_Utils_PagerAToZ::getAToZBar($selector, $this->_sortByCharacter); + $this->set('AToZBar', $aToZBar); + } + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + $controller = new CRM_Contact_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + $output + ); + $controller->setEmbedded(TRUE); + $controller->setDynamicAction($setDynamic); + $controller->run(); + } + } + + function &returnProperties() { + return CRM_Core_DAO::$_nullObject; + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + function getTitle() { + return ts('Search'); + } +} + diff --git a/CRM/Contact/Form/Search/Advanced.php b/CRM/Contact/Form/Search/Advanced.php new file mode 100644 index 0000000000..3426f96a88 --- /dev/null +++ b/CRM/Contact/Form/Search/Advanced.php @@ -0,0 +1,394 @@ +set('searchFormName', 'Advanced'); + + parent::preProcess(); + $openedPanes = CRM_Contact_BAO_Query::$_openedPanes; + $openedPanes = array_merge($openedPanes, $this->_openedPanes); + $this->assign('openedPanes', $openedPanes); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->set('context', 'advanced'); + + $this->_searchPane = CRM_Utils_Array::value('searchPane', $_GET); + + $this->_searchOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'advanced_search_options' + ); + + if (!$this->_searchPane || $this->_searchPane == 'basic') { + CRM_Contact_Form_Search_Criteria::basic($this); + } + + $allPanes = array(); + $paneNames = array( + ts('Address Fields') => 'location', + ts('Custom Fields') => 'custom', + ts('Activities') => 'activity', + ts('Relationships') => 'relationship', + ts('Demographics') => 'demographics', + ts('Notes') => 'notes', + ts('Change Log') => 'changeLog', + ); + + //check if there are any custom data searchable fields + $groupDetails = array(); + $extends = array_merge(array('Contact', 'Individual', 'Household', 'Organization'), + CRM_Contact_BAO_ContactType::subTypes() + ); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, + $extends + ); + // if no searchable fields unset panel + if (empty($groupDetails)) { + unset($paneNames[ts('Custom Fields')]); + } + + foreach ($paneNames as $name => $type) { + if (!$this->_searchOptions[$type]) { + unset($paneNames[$name]); + } + } + + $components = CRM_Core_Component::getEnabledComponents(); + + $componentPanes = array(); + foreach ($components as $name => $component) { + if (in_array($name, array_keys($this->_searchOptions)) && + $this->_searchOptions[$name] && + CRM_Core_Permission::access($component->name) + ) { + $componentPanes[$name] = $component->registerAdvancedSearchPane(); + $componentPanes[$name]['name'] = $name; + } + } + + usort($componentPanes, array('CRM_Utils_Sort', 'cmpFunc')); + foreach ($componentPanes as $name => $pane) { + // FIXME: we should change the use of $name here to keyword + $paneNames[$pane['title']] = $pane['name']; + } + + $this->_paneTemplatePath = array(); + + foreach ($paneNames as $name => $type) { + if (!$this->_searchOptions[$type]) { + continue; + } + + $allPanes[$name] = array( + 'url' => CRM_Utils_System::url('civicrm/contact/search/advanced', + "snippet=1&searchPane=$type&qfKey={$this->controller->_key}" + ), + 'open' => 'false', + 'id' => $type, + ); + + // see if we need to include this paneName in the current form + if ($this->_searchPane == $type || + CRM_Utils_Array::value("hidden_{$type}", $_POST) || + CRM_Utils_Array::value("hidden_{$type}", $this->_formValues) + ) { + $allPanes[$name]['open'] = 'true'; + + + if (CRM_Utils_Array::value($type, $components)) { + $c = $components[$type]; + $this->add('hidden', "hidden_$type", 1); + $c->buildAdvancedSearchPaneForm($this); + $this->_paneTemplatePath[$type] = $c->getAdvancedSearchPaneTemplatePath(); + } + else { + eval('CRM_Contact_Form_Search_Criteria::' . $type . '( $this );'); + $template = ucfirst($type); + $this->_paneTemplatePath[$type] = "CRM/Contact/Form/Search/Criteria/{$template}.tpl"; + } + } + } + + $this->assign('allPanes', $allPanes); + if (!$this->_searchPane) { + parent::buildQuickForm(); + } + else { + $this->assign('suppressForm', TRUE); + } + } + + function getTemplateFileName() { + if (!$this->_searchPane) { + return parent::getTemplateFileName(); + } + else { + if (isset($this->_paneTemplatePath[$this->_searchPane])) { + return $this->_paneTemplatePath[$this->_searchPane]; + } + else { + $name = ucfirst($this->_searchPane); + return "CRM/Contact/Form/Search/Criteria/{$name}.tpl"; + } + } + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + $defaults = $this->_formValues; + $this->normalizeDefaultValues($defaults); + + if ($this->_context === 'amtg') { + $defaults['task'] = CRM_Contact_Task::GROUP_CONTACTS; + } + else { + $defaults['task'] = CRM_Contact_Task::PRINT_CONTACTS; + } + + $defaults['privacy_toggle'] = 1; + + return $defaults; + } + + /** + * The post processing of the form gets done here. + * + * Key things done during post processing are + * - check for reset or next request. if present, skip post procesing. + * - now check if user requested running a saved search, if so, then + * the form values associated with the saved search are used for searching. + * - if user has done a submit with new values the regular post submissing is + * done. + * The processing consists of using a Selector / Controller framework for getting the + * search results. + * + * @param + * + * @return void + * @access public + */ + function postProcess() { + $this->set('isAdvanced', '1'); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + $this->normalizeFormValues(); + // FIXME: couldn't figure out a good place to do this, + // FIXME: so leaving this as a dependency for now + if (array_key_exists('contribution_amount_low', $this->_formValues)) { + foreach (array( + 'contribution_amount_low', 'contribution_amount_high') as $f) { + $this->_formValues[$f] = CRM_Utils_Rule::cleanMoney($this->_formValues[$f]); + } + } + + // set the group if group is submitted + if ($this->_formValues['uf_group_id']) { + $this->set('id', $this->_formValues['uf_group_id']); + } + else { + $this->set('id', ''); + } + } + + // retrieve ssID values only if formValues is null, i.e. form has never been posted + if (empty($this->_formValues) && isset($this->_ssID)) { + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + } + + if (isset($this->_groupID) && !CRM_Utils_Array::value('group', $this->_formValues)) { + $this->_formValues['group'] = array($this->_groupID => 1); + } + + + //search for civicase + if (is_array($this->_formValues)) { + $allCases = FALSE; + if (array_key_exists('case_owner', $this->_formValues) && + !$this->_formValues['case_owner'] && + !$this->_force + ) { + foreach (array( + 'case_type_id', 'case_status_id', 'case_deleted', 'case_tags') as $caseCriteria) { + if (CRM_Utils_Array::value($caseCriteria, $this->_formValues)) { + $allCases = TRUE; + $this->_formValues['case_owner'] = 1; + continue; + } + } + if ($allCases) { + if (CRM_Core_Permission::check('access all cases and activities')) { + $this->_formValues['case_owner'] = 1; + } + else { + $this->_formValues['case_owner'] = 2; + } + } + else { + $this->_formValues['case_owner'] = 0; + } + } + } + + // we dont want to store the sortByCharacter in the formValue, it is more like + // a filter on the result set + // this filter is reset if we click on the search button + if ($this->_sortByCharacter !== NULL + && empty($_POST) + ) { + if (strtolower($this->_sortByCharacter) == 'all') { + $this->_formValues['sortByCharacter'] = NULL; + } + else { + $this->_formValues['sortByCharacter'] = $this->_sortByCharacter; + } + } + + CRM_Core_BAO_CustomValue::fixFieldValueOfTypeMemo($this->_formValues); + + $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $this->_returnProperties = &$this->returnProperties(); + parent::postProcess(); + } + + /** + * normalize the form values to make it look similar to the advanced form values + * this prevents a ton of work downstream and allows us to use the same code for + * multiple purposes (queries, save/edit etc) + * + * @return void + * @access private + */ + function normalizeFormValues() { + $contactType = CRM_Utils_Array::value('contact_type', $this->_formValues); + + if ($contactType && is_array($contactType)) { + unset($this->_formValues['contact_type']); + foreach ($contactType as $key => $value) { + $this->_formValues['contact_type'][$value] = 1; + } + } + + $config = CRM_Core_Config::singleton(); + $group = CRM_Utils_Array::value('group', $this->_formValues); + if ($group && is_array($group)) { + unset($this->_formValues['group']); + foreach ($group as $key => $value) { + $this->_formValues['group'][$value] = 1; + } + } + + $tag = CRM_Utils_Array::value('contact_tags', $this->_formValues); + if ($tag && is_array($tag)) { + unset($this->_formValues['contact_tags']); + foreach ($tag as $key => $value) { + $this->_formValues['contact_tags'][$value] = 1; + } + } + + $taglist = CRM_Utils_Array::value('contact_taglist', $this->_formValues); + + if ($taglist && is_array($taglist)) { + unset($this->_formValues['contact_taglist']); + foreach ($taglist as $value) { + if ($value) { + $value = explode(',', $value); + foreach ($value as $tId) { + if (is_numeric($tId)) { + $this->_formValues['contact_tags'][$tId] = 1; + } + } + } + } + } + + return; + } + + /** + * normalize default values for multiselect plugins + * + * @return void + * @access private + */ + function normalizeDefaultValues(&$defaults) { + if (!is_array($defaults)) { + $defaults = array(); + } + + if ($this->_ssID && empty($_POST)) { + $fields = array('contact_type', 'group', 'contact_tags'); + + foreach ($fields as $field) { + $fieldValues = CRM_Utils_Array::value($field, $defaults); + if ($fieldValues && is_array($fieldValues)) { + $defaults[$field] = array_keys($fieldValues); + } + } + } + return $defaults; + } +} + diff --git a/CRM/Contact/Form/Search/Basic.php b/CRM/Contact/Form/Search/Basic.php new file mode 100644 index 0000000000..8326d53643 --- /dev/null +++ b/CRM/Contact/Form/Search/Basic.php @@ -0,0 +1,285 @@ +includeEmailInName) ? ts('Name') : ts('Name or Email'); + $this->add('text', 'sort_name', $label); + + $searchOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'advanced_search_options' + ); + + if (CRM_Utils_Array::value('contactType', $searchOptions)) { + $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements(); + $this->add('select', 'contact_type', + ts('is...'), + $contactTypes + ); + } + + if (CRM_Utils_Array::value('groups', $searchOptions)) { + // Arrange groups into hierarchical listing (child groups follow their parents and have indentation spacing in title) + $groupHierarchy = array(); + if (!empty($this->_group)) { + $ids = implode(',', array_keys($this->_group)); + $ids = 'IN (' . $ids . ')'; + $groupHierarchy = CRM_Contact_BAO_Group::getGroupsHierarchy($ids, NULL, '  ', TRUE); + } + // add select for groups + $group = array( + '' => ts('- any group -')) + $groupHierarchy; + $this->_groupElement = &$this->addElement('select', 'group', ts('in'), $group); + } + + if (CRM_Utils_Array::value('tags', $searchOptions)) { + // tag criteria + if (!empty($this->_tag)) { + $tag = array( + '' => ts('- any tag -')) + $this->_tag; + $this->_tagElement = &$this->addElement('select', 'tag', ts('with'), $tag); + } + } + + parent::buildQuickForm(); + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + $defaults = array(); + + $defaults['sort_name'] = CRM_Utils_Array::value('sort_name', $this->_formValues); + foreach (self::$csv as $v) { + if (CRM_Utils_Array::value($v, $this->_formValues) && is_array($this->_formValues[$v])) { + $tmpArray = array_keys($this->_formValues[$v]); + $defaults[$v] = array_pop($tmpArray); + } + else { + $defaults[$v] = ''; + } + } + + if ($this->_context === 'amtg') { + $defaults['task'] = CRM_Contact_Task::GROUP_CONTACTS; + } + else { + $defaults['task'] = CRM_Contact_Task::PRINT_CONTACTS; + } + + if ($this->_context === 'smog') { + $defaults['group_contact_status[Added]'] = TRUE; + } + + return $defaults; + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Search_Basic', 'formRule')); + } + + /** + * processing needed for buildForm and later + * + * @return void + * @access public + */ + function preProcess() { + $this->set('searchFormName', 'Basic'); + + parent::preProcess(); + } + + function &getFormValues() { + return $this->_formValues; + } + + /** + * this method is called for processing a submitted search form + * + * @return void + * @access public + */ + function postProcess() { + $this->set('isAdvanced', '0'); + $this->set('isSearchBuilder', '0'); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + $this->normalizeFormValues(); + } + + if (isset($this->_groupID) && !CRM_Utils_Array::value('group', $this->_formValues)) { + $this->_formValues['group'][$this->_groupID] = 1; + } + elseif (isset($this->_ssID) && empty($_POST)) { + // if we are editing / running a saved search and the form has not been posted + $this->_formValues = CRM_Contact_BAO_SavedSearch::getFormValues($this->_ssID); + + //fix for CRM-1505 + if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'mapping_id')) { + $this->_params = CRM_Contact_BAO_SavedSearch::getSearchParams($this->_ssID); + } + } + + // we dont want to store the sortByCharacter in the formValue, it is more like + // a filter on the result set + // this filter is reset if we click on the search button + if ($this->_sortByCharacter !== NULL + && empty($_POST) + ) { + if (strtolower($this->_sortByCharacter) == 'all') { + $this->_formValues['sortByCharacter'] = NULL; + } + else { + $this->_formValues['sortByCharacter'] = $this->_sortByCharacter; + } + } + + $this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $this->_returnProperties = &$this->returnProperties(); + + parent::postProcess(); + } + + /** + * normalize the form values to make it look similar to the advanced form values + * this prevents a ton of work downstream and allows us to use the same code for + * multiple purposes (queries, save/edit etc) + * + * @return void + * @access private + */ + function normalizeFormValues() { + $contactType = CRM_Utils_Array::value('contact_type', $this->_formValues); + if ($contactType && !is_array($contactType)) { + unset($this->_formValues['contact_type']); + $this->_formValues['contact_type'][$contactType] = 1; + } + + $config = CRM_Core_Config::singleton(); + + $group = CRM_Utils_Array::value('group', $this->_formValues); + if ($group && !is_array($group)) { + unset($this->_formValues['group']); + $this->_formValues['group'][$group] = 1; + } + + $tag = CRM_Utils_Array::value('tag', $this->_formValues); + if ($tag && !is_array($tag)) { + unset($this->_formValues['tag']); + $this->_formValues['tag'][$tag] = 1; + } + + return; + } + + /** + * Add a form rule for this form. If Go is pressed then we must select some checkboxes + * and an action + */ + static function formRule($fields) { + // check actionName and if next, then do not repeat a search, since we are going to the next page + if (array_key_exists('_qf_Search_next', $fields)) { + if (!CRM_Utils_Array::value('task', $fields)) { + return array('task' => 'Please select a valid action.'); + } + + if (CRM_Utils_Array::value('task', $fields) == CRM_Contact_Task::SAVE_SEARCH) { + // dont need to check for selection of contacts for saving search + return TRUE; + } + + // if the all contact option is selected, ignore the contact checkbox validation + if ($fields['radio_ts'] == 'ts_all') { + return TRUE; + } + + foreach ($fields as $name => $dontCare) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + return TRUE; + } + } + return array('task' => 'Please select one or more checkboxes to perform the action on.'); + } + return TRUE; + } + + function getTitle() { + return ts('Find Contacts'); + } +} + diff --git a/CRM/Contact/Form/Search/Builder.php b/CRM/Contact/Form/Search/Builder.php new file mode 100644 index 0000000000..950c161396 --- /dev/null +++ b/CRM/Contact/Form/Search/Builder.php @@ -0,0 +1,476 @@ +set('searchFormName', 'Builder'); + + $this->set('context', 'builder'); + parent::preProcess(); + + // Get the block count + $this->_blockCount = $this->get('blockCount'); + // Initialize new form + if (!$this->_blockCount) { + $this->_blockCount = 4; + $this->set('newBlock', 1); + } + + //get the column count + $this->_columnCount = $this->get('columnCount'); + + for ($i = 1; $i < $this->_blockCount; $i++) { + if (empty($this->_columnCount[$i])) { + $this->_columnCount[$i] = 5; + } + } + + $this->_loadedMappingId = $this->get('savedMapping'); + + if ($this->get('showSearchForm')) { + $this->assign('showSearchForm', TRUE); + } + else { + $this->assign('showSearchForm', FALSE); + } + } + + public function buildQuickForm() { + $fields = self::fields(); + // Get fields of type date + // FIXME: This is a hack until our fields contain this meta-data + $dateFields = array(); + foreach ($fields as $name => $field) { + if (strpos($name, '_date') || CRM_Utils_Array::value('data_type', $field) == 'Date') { + $dateFields[] = $name; + } + } + // Add javascript + CRM_Core_Resources::singleton() + ->addScriptFile('civicrm', 'templates/CRM/Contact/Form/Search/Builder.js') + ->addSetting(array( + 'searchBuilder' => array( + // Index of newly added/expanded block (1-based index) + 'newBlock' => $this->get('newBlock'), + 'dateFields' => $dateFields, + 'fieldOptions' => self::fieldOptions(), + ), + )); + //get the saved search mapping id + $mappingId = NULL; + if ($this->_ssID) { + $mappingId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $this->_ssID, 'mapping_id'); + } + + CRM_Core_BAO_Mapping::buildMappingForm($this, 'Search Builder', $mappingId, $this->_columnCount, $this->_blockCount); + + parent::buildQuickForm(); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Search_Builder', 'formRule'), $this); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $self) { + if (CRM_Utils_Array::value('addMore', $values) || CRM_Utils_Array::value('addBlock', $values)) { + return TRUE; + } + $fields = self::fields(); + $fld = CRM_Core_BAO_Mapping::formattedFields($values, TRUE); + + $errorMsg = array(); + foreach ($fld as $k => $v) { + if (!$v[1]) { + $errorMsg["operator[$v[3]][$v[4]]"] = ts("Please enter the operator."); + } + else { + // CRM-10338 + $v[2] = self::checkArrayKeyEmpty($v[2]); + + if (in_array($v[1], array('IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY')) && + !empty($v[2])) { + $errorMsg["value[$v[3]][$v[4]]"] = ts('Please clear your value if you want to use %1 operator.', array(1 => $v[1])); + } + elseif (($v[0] == 'group' || $v[0] == 'tag') && !empty($v[2])) { + $grpId = array_keys($v[2]); + if (!key($v[2])) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a value."); + } + + if (count($grpId) > 1) { + if ($v[1] != 'IN' && $v[1] != 'NOT IN') { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a valid value."); + } + foreach ($grpId as $val) { + $error = CRM_Utils_Type::validate($val, 'Integer', FALSE); + if ($error != $val) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter valid value."); + break; + } + } + } + else { + $error = CRM_Utils_Type::validate($grpId[0], 'Integer', FALSE); + if ($error != $grpId[0]) { + $errorMsg["value[$v[3]][$v[4]]"] = ts('Please enter valid %1 id.', array(1 => $v[0])); + } + } + } + elseif (substr($v[0], 0, 7) === 'do_not_' or substr($v[0], 0, 3) === 'is_') { + if (isset($v[2])) { + $v2 = array($v[2]); + if (!isset($v[2])) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a value."); + } + + $error = CRM_Utils_Type::validate($v2[0], 'Integer', FALSE); + if ($error != $v2[0]) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a valid value."); + } + } + else { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a value."); + } + } + else { + if (substr($v[0], 0, 7) == 'custom_') { + $type = $fields[$v[0]]['data_type']; + + // hack to handle custom data of type state and country + if (in_array($type, array( + 'Country', 'StateProvince'))) { + $type = "Integer"; + } + } + else { + $fldName = $v[0]; + // FIXME: no idea at this point what to do with this, + // FIXME: but definitely needs fixing. + if (substr($v[0], 0, 13) == 'contribution_') { + $fldName = substr($v[0], 13); + } + + $fldValue = CRM_Utils_Array::value($fldName, $fields); + $fldType = CRM_Utils_Array::value('type', $fldValue); + $type = CRM_Utils_Type::typeToString($fldType); + // Check Empty values for Integer Or Boolean Or Date type For operators other than IS NULL and IS NOT NULL. + if (!in_array($v[1], + array('IS NULL', 'IS NOT NULL', 'IS EMPTY', 'IS NOT EMPTY'))) { + if ((($type == 'Int' || $type == 'Boolean') && !trim($v[2])) && $v[2] != '0') { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a value."); + } + elseif ($type == 'Date' && !trim($v[2])) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a value."); + } + } + } + + if ($type && empty($errorMsg)) { + // check for valid format while using IN Operator + if ($v[1] == 'IN') { + $inVal = trim($v[2]); + //checking for format to avoid db errors + if ($type == 'Int') { + if (!preg_match('/^[(]([A-Za-z0-9\,]+)[)]$/', $inVal)) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter correct Data (in valid format)."); + } + } + else { + if (!(substr($inVal, 0, 1) == '(' && substr($inVal, -1, 1) == ')') && !preg_match('/^[(]([A-Za-z0-9åäöÅÄÖüÜœŒæÆøØ\,\s]+)[)]$/', $inVal)) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter correct Data (in valid format)."); + } + } + + // Validate each value in parenthesis to avoid db errors + if (empty($errorMsg)) { + $parenValues = array(); + $parenValues = explode(',', trim($inVal, "(..)")); + foreach ($parenValues as $val) { + $val = trim($val); + if (!$val && $val != '0') { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter the values correctly."); + } + if (empty($errorMsg)) { + $error = CRM_Utils_Type::validate($val, $type, FALSE); + if ($error != $val) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a valid value."); + } + } + } + } + } + elseif (trim($v[2])) { + //else check value for rest of the Operators + $error = CRM_Utils_Type::validate($v[2], $type, FALSE); + if ($error != $v[2]) { + $errorMsg["value[$v[3]][$v[4]]"] = ts("Please enter a valid value."); + } + } + } + } + } + } + + if (!empty($errorMsg)) { + $self->set('showSearchForm', TRUE); + $self->assign('rows', NULL); + return $errorMsg; + } + + return TRUE; + } + + public function normalizeFormValues() {} + + public function &convertFormValues(&$formValues) { + return CRM_Core_BAO_Mapping::formattedFields($formValues); + } + + public function &returnProperties() { + return CRM_Core_BAO_Mapping::returnProperties($this->_formValues); + } + + /** + * Process the uploaded file + * + * @return void + * @access public + */ + public function postProcess() { + $this->set('isAdvanced', '2'); + $this->set('isSearchBuilder', '1'); + $this->set('showSearchForm', FALSE); + + $params = $this->controller->exportValues($this->_name); + if (!empty($params)) { + // Add another block + if (!empty($params['addBlock'])) { + $this->set('newBlock', $this->_blockCount); + $this->_blockCount += 3; + $this->set('blockCount', $this->_blockCount); + $this->set('showSearchForm', TRUE); + return; + } + // Add another field + $addMore = CRM_Utils_Array::value('addMore', $params); + for ($x = 1; $x <= $this->_blockCount; $x++) { + if (!empty($addMore[$x])) { + $this->set('newBlock', $x); + $this->_columnCount[$x] = $this->_columnCount[$x] + 5; + $this->set('columnCount', $this->_columnCount); + $this->set('showSearchForm', TRUE); + return; + } + } + $this->set('newBlock', NULL); + $checkEmpty = NULL; + foreach ($params['mapper'] as $key => $value) { + foreach ($value as $k => $v) { + if ($v[0]) { + $checkEmpty++; + } + } + } + + if (!$checkEmpty) { + $this->set('newBlock', 1); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/search/builder', '_qf_Builder_display=true')); + } + } + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + + // set the group if group is submitted + if (CRM_Utils_Array::value('uf_group_id', $this->_formValues)) { + $this->set('id', $this->_formValues['uf_group_id']); + } + else { + $this->set('id', ''); + } + } + + // we dont want to store the sortByCharacter in the formValue, it is more like + // a filter on the result set + // this filter is reset if we click on the search button + if ($this->_sortByCharacter !== NULL && empty($_POST)) { + if (strtolower($this->_sortByCharacter) == 'all') { + $this->_formValues['sortByCharacter'] = NULL; + } + else { + $this->_formValues['sortByCharacter'] = $this->_sortByCharacter; + } + } + + $this->_params = &$this->convertFormValues($this->_formValues); + $this->_returnProperties = &$this->returnProperties(); + + // CRM-10338 check if value is empty array + foreach ($this->_params as $k => $v) { + $this->_params[$k][2] = self::checkArrayKeyEmpty($v[2]); + } + + parent::postProcess(); + } + + static function fields() { + return array_merge( + CRM_Contact_BAO_Contact::exportableFields('All', FALSE, TRUE), + CRM_Core_Component::getQueryFields(), + CRM_Activity_BAO_Activity::exportableFields() + ); + } + + /** + * CRM-9434 Hackish function to fetch fields with options. + * FIXME: When our core fields contain reliable metadata this will be much simpler. + * @return array: (string => string) key: field_name value: api entity name + * Note: options are fetched via ajax using the api "getoptions" method + */ + static function fieldOptions() { + // Hack to add options not retrieved by getfields + // This list could go on and on, but it would be better to fix getfields + $options = array( + 'group' => 'contact', + 'tag' => 'contact', + 'country' => 'contact', + 'state_province' => 'contact', + 'gender' => 'contact', + 'world_region' => 'contact', + 'individual_prefix' => 'contact', + 'individual_suffix' => 'contact', + 'preferred_communication_method' => 'contact', + 'preferred_language' => 'contact', + 'on_hold' => 'yesno', + 'is_bulkmail' => 'yesno', + 'activity_type' => 'activity', + 'activity_status' => 'activity', + 'financial_type' => 'contribution', + 'contribution_page_id' => 'contribution', + 'contribution_status' => 'contribution', + 'payment_instrument' => 'contribution', + 'membership_status' => 'membership', + 'membership_type' => 'membership', + ); + $entities = array('contact', 'activity', 'participant', 'pledge', 'member', 'contribution'); + foreach ($entities as $entity) { + $fields = civicrm_api($entity, 'getfields', array('version' => 3)); + foreach ($fields['values'] as $field => $info) { + if (!empty($info['options']) || !empty($info['pseudoconstant']) || !empty($info['option_group_id'])) { + $options[$field] = $entity; + if (substr($field, -3) == '_id') { + $options[substr($field, 0, -3)] = $entity; + } + } + elseif (in_array(substr($field, 0, 3), array('is_', 'do_')) || CRM_Utils_Array::value('data_type', $info) == 'Boolean') { + $options[$field] = 'yesno'; + if ($entity != 'contact') { + $options[$entity . '_' . $field] = 'yesno'; + } + } + elseif (strpos($field, '_is_')) { + $options[$field] = 'yesno'; + } + } + } + return $options; + } + + /** + * CRM-10338 + * tags and groups use array keys for selection list. + * if using IS NULL/NOT NULL, an array with no array key is created + * convert that to simple null so processing can proceed + */ + static function checkArrayKeyEmpty($val) { + if (is_array($val)) { + $v2empty = true; + foreach ($val as $vk => $vv) { + if (!empty($vk)) { + $v2empty = false; + } + } + if ($v2empty) { + $val = null; + } + } + return $val; + } +} + diff --git a/CRM/Contact/Form/Search/Criteria.php b/CRM/Contact/Form/Search/Criteria.php new file mode 100644 index 0000000000..701f0614f3 --- /dev/null +++ b/CRM/Contact/Form/Search/Criteria.php @@ -0,0 +1,569 @@ +addElement('hidden', 'hidden_basic', 1); + + if ($form->_searchOptions['contactType']) { + // add checkboxes for contact type + $contact_type = array(); + $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(); + + if ($contactTypes) { + $form->add('select', 'contact_type', ts('Contact Type(s)'), $contactTypes, FALSE, + array('id' => 'contact_type', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + } + + if ($form->_searchOptions['groups']) { + // multiselect for groups + if ($form->_group) { + // Arrange groups into hierarchical listing (child groups follow their parents and have indentation spacing in title) + $ids = implode(',', array_keys($form->_group)); + $ids = 'IN (' . $ids . ')'; + $groupHierarchy = CRM_Contact_BAO_Group::getGroupsHierarchy($ids, NULL, '  ', TRUE); + + $form->add('select', 'group', ts('Groups'), $groupHierarchy, FALSE, + array('id' => 'group', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + $groupOptions = CRM_Core_BAO_OptionValue::getOptionValuesAssocArrayFromName('group_type'); + $form->add('select', 'group_type', ts('Group Types'), $groupOptions, FALSE, + array('id' => 'group_type', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + $form->add('hidden','group_search_selected','group'); + } + } + + if ($form->_searchOptions['tags']) { + // multiselect for categories + $contactTags = CRM_Core_BAO_Tag::getTags(); + + if ($contactTags) { + $form->add('select', 'contact_tags', ts('Tags'), $contactTags, FALSE, + array('id' => 'contact_tags', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_contact'); + CRM_Core_Form_Tag::buildQuickForm($form, $parentNames, 'civicrm_contact', NULL, TRUE, FALSE, TRUE); + + $used_for = CRM_Core_OptionGroup::values('tag_used_for'); + $tagsTypes = array(); + $showAllTagTypes = false; + foreach ($used_for as $key => $value) { + //check tags for every type and find if there are any defined + $tags = CRM_Core_BAO_Tag::getTagsUsedFor($key, FALSE, TRUE, NULL); + // check if there are tags other than contact type, if no - keep checkbox hidden on adv search + // we will hide searching contact by attachments tags until it will be implemented in core + if (count($tags) && $key != 'civicrm_file' && $key != 'civicrm_contact') { + //if tags exists then add type to display in adv search form help text + $tagsTypes[] = ts($value); + $showAllTagTypes = true; + } + } + $tagTypesText = implode(" or ", $tagsTypes); + if ($showAllTagTypes) { + $form->add('checkbox', 'all_tag_types', ts('Include tags used for %1', array(1 => $tagTypesText))); + $form->add('hidden','tag_types_text', $tagTypesText); + } + } + + // add text box for last name, first name, street name, city + $form->addElement('text', 'sort_name', ts('Find...'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + + // add text box for last name, first name, street name, city + $form->add('text', 'email', ts('Contact Email'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + + //added contact source + $form->add('text', 'contact_source', ts('Contact Source'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'contact_source')); + + //added job title + $form->addElement('text', 'job_title', ts('Job Title'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'job_title')); + + + //added internal ID + $form->addElement('text', 'id', ts('Contact ID'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'id')); + + //added external ID + $form->addElement('text', 'external_identifier', ts('External ID'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'external_identifier')); + + if (CRM_Core_Permission::check('access deleted contacts') and CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_undelete', NULL)) { + $form->add('checkbox', 'deleted_contacts', ts('Search in Trash') . '
    ' . ts('(deleted contacts)')); + } + + // add checkbox for cms users only + $form->addYesNo('uf_user', ts('CMS User?')); + + // tag all search + $form->add('text', 'tag_search', ts('All Tags')); + + // add search profiles + + // FIXME: This is probably a part of profiles - need to be + // FIXME: eradicated from here when profiles are reworked. + $types = array('Participant', 'Contribution', 'Membership'); + + // get component profiles + $componentProfiles = array(); + $componentProfiles = CRM_Core_BAO_UFGroup::getProfiles($types); + + $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('Search Profile', 1); + $accessibleUfGroups = CRM_Core_Permission::ufGroup(CRM_Core_Permission::VIEW); + + $searchProfiles = array(); + foreach ($ufGroups as $key => $var) { + if (!array_key_exists($key, $componentProfiles) && in_array($key, $accessibleUfGroups)) { + $searchProfiles[$key] = $var['title']; + } + } + + $form->addElement('select', + 'uf_group_id', + ts('Search Views'), + array( + '0' => ts('- default view -')) + $searchProfiles + ); + + $componentModes = CRM_Contact_Form_Search::getModeSelect(); + + // unset contributions or participants if user does not have + // permission on them + if (!CRM_Core_Permission::access('CiviContribute')) { + unset($componentModes['2']); + } + + if (!CRM_Core_Permission::access('CiviEvent')) { + unset($componentModes['3']); + } + + if (!CRM_Core_Permission::access('CiviMember')) { + unset($componentModes['5']); + } + + if (!CRM_Core_Permission::check('view all activities')) { + unset($componentModes['4']); + } + + if (count($componentModes) > 1) { + $form->addElement('select', + 'component_mode', + ts('Display Results As'), + $componentModes + ); + } + + $form->addElement('select', + 'operator', + ts('Search Operator'), + array('AND' => ts('AND'), + 'OR' => ts('OR'), + ) + ); + + // add the option to display relationships + $rTypes = CRM_Core_PseudoConstant::relationshipType(); + $rSelect = array('' => ts('- Select Relationship Type-')); + foreach ($rTypes as $rid => $rValue) { + if ($rValue['label_a_b'] == $rValue['label_b_a']) { + $rSelect[$rid] = $rValue['label_a_b']; + } + else { + $rSelect["{$rid}_a_b"] = $rValue['label_a_b']; + $rSelect["{$rid}_b_a"] = $rValue['label_b_a']; + } + } + + $form->addElement('select', + 'display_relationship_type', + ts('Display Results as Relationship'), + $rSelect + ); + + // checkboxes for DO NOT phone, email, mail + // we take labels from SelectValues + $t = CRM_Core_SelectValues::privacy(); + $form->add('select', + 'privacy_options', + ts('Privacy'), + $t, + FALSE, + array( + 'id' => 'privacy_options', + 'multiple' => 'multiple', + 'title' => ts('- select -'), + ) + ); + + $form->addElement('select', + 'privacy_operator', + ts('Operator'), + array('OR' => ts('OR'), + 'AND' => ts('AND'), + ) + ); + + $options = array( + 1 => ts('Exclude'), + 2 => ts('Include by Privacy Option(s)'), + ); + $form->addRadio('privacy_toggle', ts('Privacy Options'), $options); + + // preferred communication method + $comm = CRM_Core_PseudoConstant::pcm(); + + $commPreff = array(); + foreach ($comm as $k => $v) { + $commPreff[] = $form->createElement('advcheckbox', $k, NULL, $v); + } + + $onHold[] = $form->createElement('advcheckbox', 'on_hold', NULL, ts('')); + $form->addGroup($onHold, 'email_on_hold', ts('Email On Hold')); + + $form->addGroup($commPreff, 'preferred_communication_method', ts('Preferred Communication Method')); + + //CRM-6138 Preferred Language + $langPreff = CRM_Core_PseudoConstant::languages(); + $form->add('select', 'preferred_language', ts('Preferred Language'), array('' => ts('- any -')) + $langPreff); + + // Phone search + $form->addElement('text', 'phone_numeric', ts('Phone Number'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_Phone', 'phone')); + $locationType = CRM_Core_PseudoConstant::locationType(); + $phoneType = CRM_Core_PseudoConstant::phoneType(); + $form->add('select', 'phone_location_type_id', ts('Phone Location'), array('' => ts('- any -')) + $locationType); + $form->add('select', 'phone_phone_type_id', ts('Phone Type'), array('' => ts('- any -')) + $phoneType); + } + + + static function location(&$form) { + // Build location criteria based on _submitValues if + // available; otherwise, use $form->_formValues. + $formValues = $form->_submitValues; + + if (empty($formValues) && !empty($form->_formValues)) { + $formValues = $form->_formValues; + } + + $form->addElement('hidden', 'hidden_location', 1); + + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options', TRUE, NULL, TRUE + ); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_Address'); + + $elements = array( + 'street_address' => array(ts('Street Address'), $attributes['street_address'], NULL, NULL), + 'city' => array(ts('City'), $attributes['city'], NULL, NULL), + 'postal_code' => array(ts('Zip / Postal Code'), $attributes['postal_code'], NULL, NULL), + 'county' => array(ts('County'), $attributes['county_id'], 'county', TRUE), + 'state_province' => array(ts('State / Province'), $attributes['state_province_id'], 'stateProvince', TRUE), + 'country' => array(ts('Country'), $attributes['country_id'], 'country', FALSE), + 'address_name' => array(ts('Address Name'), $attributes['address_name'], NULL, NULL), + 'street_number' => array(ts('Street Number'), $attributes['street_number'], NULL, NULL), + 'street_name' => array(ts('Street Name'), $attributes['street_name'], NULL, NULL), + 'street_unit' => array(ts('Apt/Unit/Suite'), $attributes['street_unit'], NULL, NULL), + ); + + $parseStreetAddress = CRM_Utils_Array::value('street_address_parsing', $addressOptions, 0); + $form->assign('parseStreetAddress', $parseStreetAddress); + foreach ($elements as $name => $v) { + list($title, $attributes, $select, $multiSelect) = $v; + + if (in_array($name, + array('street_number', 'street_name', 'street_unit') + )) { + if (!$parseStreetAddress) { + continue; + } + } + elseif (!$addressOptions[$name]) { + continue; + } + + if (!$attributes) { + $attributes = $attributes[$name]; + } + + if ($select) { + $config = CRM_Core_Config::singleton(); + $countryDefault = $config->defaultContactCountry; + $stateProvinceDefault = $config->defaultContactStateProvince; + $defaultValues = array(); + $stateCountryMap[] = array( + 'state_province' => 'state_province', + 'country' => 'country', + 'county' => 'county', + ); + if ($select == 'stateProvince') { + if ($stateProvinceDefault) { + //for setdefault state/province + $defaultValues[$name] = $stateProvinceDefault; + $form->setDefaults($defaultValues); + } + if ($countryDefault && !isset($formValues['country'])) { + $selectElements = array('' => ts('- any -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($countryDefault); + } + elseif ($formValues['country']) { + $selectElements = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($formValues['country']); + } + else { + //if not setdefault any country + $selectElements = array('' => ts('- any -')) + CRM_Core_PseudoConstant::$select(); + } + $element = $form->addElement('select', $name, $title, $selectElements); + } + elseif ($select == 'country') { + if ($countryDefault) { + //for setdefault country + $defaultValues[$name] = $countryDefault; + $form->setDefaults($defaultValues); + } + $selectElements = array('' => ts('- any -')) + CRM_Core_PseudoConstant::$select(); + $element = $form->addElement('select', $name, $title, $selectElements); + } + elseif ($select == 'county') { + if ( array_key_exists('state_province', $formValues) && !CRM_Utils_System::isNull($formValues['state_province'])) { + $selectElements = array('' => ts('- select -')) + CRM_Core_PseudoConstant::countyForState($formValues['state_province']); + } + else { + $selectElements = array('' => ts('- any -')); + } + $element = $form->addElement('select', $name, $title, $selectElements); + } + else { + $selectElements = array('' => ts('- any -')) + CRM_Core_PseudoConstant::$select(); + $element = $form->addElement('select', $name, $title, $selectElements); + } + if ($multiSelect) { + $element->setMultiple(TRUE); + } + } + else { + $form->addElement('text', $name, $title, $attributes); + } + + if ($addressOptions['postal_code']) { + $form->addElement('text', 'postal_code_low', ts('Range-From'), + CRM_Utils_Array::value('postal_code', $attributes) + ); + $form->addElement('text', 'postal_code_high', ts('To'), + CRM_Utils_Array::value('postal_code', $attributes) + ); + } + } + + // extend addresses with proximity search + $form->addElement('text', 'prox_distance', ts('Find contacts within')); + $form->addElement('select', 'prox_distance_unit', NULL, array('miles' => ts('Miles'), 'kilos' => ts('Kilometers'))); + + // is there another form rule that does decimals besides money ? ... + $form->addRule('prox_distance', ts('Please enter positive number as a distance'), 'numeric'); + + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + $worldRegions = array('' => ts('- any region -')) + CRM_Core_PseudoConstant::worldRegion(); + $form->addElement('select', 'world_region', ts('World Region'), $worldRegions); + + // checkboxes for location type + $location_type = array(); + $locationType = CRM_Core_PseudoConstant::locationType(); + foreach ($locationType as $locationTypeID => $locationTypeName) { + $location_type[] = $form->createElement('checkbox', $locationTypeID, NULL, $locationTypeName); + } + $form->addGroup($location_type, 'location_type', ts('Location Types'), ' '); + + // custom data extending addresses - + $extends = array('Address'); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, $extends); + if ($groupDetails) { + $form->assign('addressGroupTree', $groupDetails); + foreach ($groupDetails as $group) { + foreach ($group['fields'] as $field) { + $elementName = 'custom_' . $field['id']; + CRM_Core_BAO_CustomField::addQuickFormElement($form, + $elementName, + $field['id'], + FALSE, FALSE, TRUE + ); + } + } + } + } + + static function activity(&$form) { + $form->add('hidden', 'hidden_activity', 1); + CRM_Activity_BAO_Query::buildSearchForm($form); + } + + static function changeLog(&$form) { + $form->add('hidden', 'hidden_changeLog', 1); + + // block for change log + $form->addElement('text', 'changed_by', ts('Modified By'), NULL); + + $dates = array(1 => ts('Added'), 2 => ts('Modified')); + $form->addRadio('log_date', NULL, $dates, NULL, '
    '); + + CRM_Core_Form_Date::buildDateRange($form, 'log_date', 1, '_low', '_high', ts('From'), FALSE, FALSE); + } + + static function task(&$form) { + $form->add('hidden', 'hidden_task', 1); + } + + static function relationship(&$form) { + $form->add('hidden', 'hidden_relationship', 1); + + $allRelationshipType = array(); + $allRelationshipType = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, NULL, NULL, NULL, TRUE); + $form->addElement('select', 'relation_type_id', ts('Relationship Type'), array('' => ts('- select -')) + $allRelationshipType); + $form->addElement('text', 'relation_target_name', ts('Target Contact'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + $relStatusOption = array(ts('Active '), ts('Inactive '), ts('All')); + $form->addRadio('relation_status', ts('Relationship Status'), $relStatusOption); + $form->setDefaults(array('relation_status' => 0)); + + //add the target group + if ($form->_group) { + $form->add('select', 'relation_target_group', ts('Target Contact(s) in Group'), $form->_group, FALSE, + array('id' => 'relation_target_group', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + + // Add reltionship dates + CRM_Core_Form_Date::buildDateRange($form, 'relation_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE); + + // add all the custom searchable fields + $relationship = array('Relationship'); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, $relationship); + if ($groupDetails) { + $form->assign('relationshipGroupTree', $groupDetails); + foreach ($groupDetails as $group) { + foreach ($group['fields'] as $field) { + $fieldId = $field['id']; + $elementName = 'custom_' . $fieldId; + CRM_Core_BAO_CustomField::addQuickFormElement($form, + $elementName, + $fieldId, + FALSE, FALSE, TRUE + ); + } + } + } + } + + static function demographics(&$form) { + $form->add('hidden', 'hidden_demographics', 1); + // radio button for gender + $genderOptions = array(); + $gender = CRM_Core_PseudoConstant::gender(); + foreach ($gender as $key => $var) { + $genderOptions[$key] = $form->createElement('radio', NULL, + ts('Gender'), $var, $key, + array('id' => "civicrm_gender_{$var}_{$key}") + ); + } + $form->addGroup($genderOptions, 'gender', ts('Gender')); + + CRM_Core_Form_Date::buildDateRange($form, 'birth_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth'); + + CRM_Core_Form_Date::buildDateRange($form, 'deceased_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth'); + + + // radio button for is_deceased + $form->addYesNo( 'is_deceased', ts('Deceased')); + } + + static function notes(&$form) { + $form->add('hidden', 'hidden_notes', 1); + + $options = array( + 2 => ts('Body Only'), + 3 => ts('Subject Only'), + 6 => ts('Both'), + ); + $form->addRadio('note_option', '', $options); + + $form->addElement('text', 'note', ts('Note Text'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')); + + $form->setDefaults(array('note_option' => 6)); + } + + /** + * Generate the custom Data Fields based + * on the is_searchable + * + * @access private + * + * @return void + */ + static function custom(&$form) { + $form->add('hidden', 'hidden_custom', 1); + $extends = array_merge(array('Contact', 'Individual', 'Household', 'Organization'), + CRM_Contact_BAO_ContactType::subTypes() + ); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, + $extends + ); + + $form->assign('groupTree', $groupDetails); + + foreach ($groupDetails as $key => $group) { + $_groupTitle[$key] = $group['name']; + CRM_Core_ShowHideBlocks::links($form, $group['name'], '', ''); + + $groupId = $group['id']; + foreach ($group['fields'] as $field) { + $fieldId = $field['id']; + $elementName = 'custom_' . $fieldId; + + CRM_Core_BAO_CustomField::addQuickFormElement($form, + $elementName, + $fieldId, + FALSE, FALSE, TRUE + ); + } + } + + //TODO: validate for only one state if prox_distance isset + } + + static function CiviCase(&$form) { + //Looks like obsolete code, since CiviCase is a component, but might be used by HRD + $form->add('hidden', 'hidden_CiviCase', 1); + CRM_Case_BAO_Query::buildSearchForm($form); + } +} + diff --git a/CRM/Contact/Form/Search/Custom.php b/CRM/Contact/Form/Search/Custom.php new file mode 100644 index 0000000000..b1edfc16ff --- /dev/null +++ b/CRM/Contact/Form/Search/Custom.php @@ -0,0 +1,131 @@ +set('searchFormName', 'Custom'); + + $this->set('context', 'custom'); + + $csID = CRM_Utils_Request::retrieve('csid', 'Integer', $this); + $ssID = CRM_Utils_Request::retrieve('ssID', 'Integer', $this); + $gID = CRM_Utils_Request::retrieve('gid', 'Integer', $this); + + list($this->_customSearchID, + $this->_customSearchClass, + $formValues + ) = CRM_Contact_BAO_SearchCustom::details($csID, $ssID, $gID); + + if (!$this->_customSearchID) { + CRM_Core_Error::fatal('Could not get details for custom search.'); + } + + if (!empty($formValues)) { + $this->_formValues = $formValues; + } + + // set breadcrumb to return to Custom Search listings page + $breadCrumb = array(array('title' => ts('Custom Searches'), + 'url' => CRM_Utils_System::url('civicrm/contact/search/custom/list', + 'reset=1' + ), + )); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + + // use the custom selector + self::$_selectorName = 'CRM_Contact_Selector_Custom'; + + $this->set('customSearchID', $this->_customSearchID); + $this->set('customSearchClass', $this->_customSearchClass); + + parent::preProcess(); + + // instantiate the new class + eval('$this->_customClass = new ' . $this->_customSearchClass . '( $this->_formValues );'); + } + + function setDefaultValues() { + if (method_exists($this->_customSearchClass, 'setDefaultValues')) { + return $this->_customClass->setDefaultValues(); + } + return $this->_formValues; + } + + function buildQuickForm() { + $this->_customClass->buildForm($this); + + parent::buildQuickForm(); + } + + function getTemplateFileName() { + + $ext = CRM_Extension_System::singleton()->getMapper(); + + if ($ext->isExtensionClass(CRM_Utils_System::getClassName($this->_customClass))) { + $fileName = $ext->getTemplatePath(CRM_Utils_System::getClassName($this->_customClass)) . '/' . $ext->getTemplateName(CRM_Utils_System::getClassName($this->_customClass)); + } + else { + $fileName = $this->_customClass->templateFile(); + } + + return $fileName ? $fileName : parent::getTemplateFileName(); + } + + function postProcess() { + $this->set('isAdvanced', '3'); + $this->set('isCustom', '1'); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + + $this->_formValues['customSearchID'] = $this->_customSearchID; + $this->_formValues['customSearchClass'] = $this->_customSearchClass; + } + + //use the custom selector + self::$_selectorName = 'CRM_Contact_Selector_Custom'; + + parent::postProcess(); + } + + public function getTitle() { + return ts('Custom Search'); + } +} + diff --git a/CRM/Contact/Form/Search/Custom/ActivitySearch.php b/CRM/Contact/Form/Search/Custom/ActivitySearch.php new file mode 100644 index 0000000000..cc804c7ec4 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/ActivitySearch.php @@ -0,0 +1,352 @@ +_formValues = $formValues; + + /** + * Define the columns for search result rows + */ + $this->_columns = array( + ts('Name') => 'sort_name', + ts('Status') => 'activity_status', + ts('Activity Type') => 'activity_type', + ts('Activity Subject') => 'activity_subject', + ts('Scheduled By') => 'source_contact', + ts('Scheduled Date') => 'activity_date', + ts(' ') => 'activity_id', + ts(' ') => 'activity_type_id', + ts(' ') => 'case_id', + ts('Location') => 'location', + ts('Duration') => 'duration', + ts('Details') => 'details', + ts('Assignee') => 'assignee', + ); + + $this->_groupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', + 'activity_status', + 'id', + 'name' + ); + + //Add custom fields to columns array for inclusion in export + $groupTree = &CRM_Core_BAO_CustomGroup::getTree('Activity', $form, NULL, + NULL, '', NULL + ); + + + //use simplified formatted groupTree + $groupTree = CRM_Core_BAO_CustomGroup::formatGroupTree($groupTree, 1, $form); + + //cycle through custom fields and assign to _columns array + foreach ($groupTree as $key) { + foreach ($key['fields'] as $field) { + $fieldlabel = $key['title'] . ": " . $field['label']; + $this->_columns[$fieldlabel] = $field['column_name']; + } + } + //end custom fields + } + + function buildForm(&$form) { + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Find Latest Activities'); + + /** + * Define the search form fields here + */ + // Allow user to choose which type of contact to limit search on + $form->add('select', 'contact_type', ts('Find...'), CRM_Core_SelectValues::contactType()); + + // Text box for Activity Subject + $form->add('text', + 'activity_subject', + ts('Activity Subject') + ); + + // Select box for Activity Type + $activityType = array('' => ' - select activity - ') + CRM_Core_PseudoConstant::activityType(); + + $form->add('select', 'activity_type_id', ts('Activity Type'), + $activityType, + FALSE + ); + + // textbox for Activity Status + $activityStatus = array('' => ' - select status - ') + CRM_Core_PseudoConstant::activityStatus(); + + $form->add('select', 'activity_status_id', ts('Activity Status'), + $activityStatus, + FALSE + ); + + // Activity Date range + $form->addDate('start_date', ts('Activity Date From'), FALSE, array('formatType' => 'custom')); + $form->addDate('end_date', ts('...through'), FALSE, array('formatType' => 'custom')); + + + // Contact Name field + $form->add('text', 'sort_name', ts('Contact Name')); + + /** + * If you are using the sample template, this array tells the template fields to render + * for the search form. + */ + $form->assign('elements', array( + 'contact_type', 'activity_subject', 'activity_type_id', + 'activity_status_id', 'start_date', 'end_date', 'sort_name', + )); + } + + /** + * Define the smarty template used to layout the search form and results listings. + */ + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/ActivitySearch.tpl'; + } + + /** + * Construct the search query + */ + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + + // SELECT clause must include contact_id as an alias for civicrm_contact.id + if ($justIDs) { + $select = 'contact_a.id as contact_id'; + } + else { + $select = ' + contact_a.id as contact_id, + contact_a.sort_name as sort_name, + contact_a.contact_type as contact_type, + activity.id as activity_id, + activity.activity_type_id as activity_type_id, + contact_b.sort_name as source_contact, + ov1.label as activity_type, + activity.subject as activity_subject, + activity.activity_date_time as activity_date, + ov2.label as activity_status, + cca.case_id as case_id, + activity.location as location, + activity.duration as duration, + activity.details as details, + assignment.activity_id as assignment_activity, + contact_c.display_name as assignee + '; + } + + $from = $this->from(); + + $where = $this->where($includeContactIDs); + + if (!empty($where)) { + $where = "WHERE $where"; + } + + // add custom group fields to SELECT and FROM clause + $groupTree = CRM_Core_BAO_CustomGroup::getTree('Activity', $form, NULL, NULL, '', NULL); + + foreach ($groupTree as $key) { + if ($key['extends'] == 'Activity') { + $select .= ", " . $key['table_name'] . ".*"; + $from .= " LEFT JOIN " . $key['table_name'] . " ON " . $key['table_name'] . ".entity_id = activity.id"; + } + } + // end custom groups add + + $sql = " SELECT $select FROM $from $where "; + + //no need to add order when only contact Ids. + if (!$justIDs) { + // Define ORDER BY for query in $sort, with default value + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= ' ORDER BY ' . trim($sort->orderBy()); + } + } + else { + $sql .= 'ORDER BY contact_a.sort_name, activity.activity_date_time DESC, activity.activity_type_id, activity.status_id, activity.subject'; + } + } + + if ($rowcount > 0 && $offset >= 0) { + $sql .= " LIMIT $offset, $rowcount "; + } + return $sql; + } + + // Alters the date display in the Activity Date Column. We do this after we already have + // the result so that sorting on the date column stays pertinent to the numeric date value + function alterRow(&$row) { + $row['activity_date'] = CRM_Utils_Date::customFormat($row['activity_date'], '%B %E%f, %Y %l:%M %P'); + } + + // Regular JOIN statements here to limit results to contacts who have activities. + function from() { + return " + civicrm_contact contact_a + JOIN civicrm_activity activity + ON contact_a.id = activity.source_contact_id + JOIN civicrm_option_value ov1 + ON activity.activity_type_id = ov1.value AND ov1.option_group_id = 2 + JOIN civicrm_option_value ov2 + ON activity.status_id = ov2.value AND ov2.option_group_id = {$this->_groupId} + JOIN civicrm_contact contact_b + ON activity.source_contact_id = contact_b.id + LEFT JOIN civicrm_case_activity cca + ON activity.id = cca.activity_id + LEFT JOIN civicrm_activity_assignment assignment + ON activity.id = assignment.activity_id + LEFT JOIN civicrm_contact contact_c + ON assignment.assignee_contact_id = contact_c.id "; + } + + /* + * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values + * + */ + function where($includeContactIDs = FALSE) { + $clauses = array(); + + // add contact name search; search on primary name, source contact, assignee + $contactname = $this->_formValues['sort_name']; + if (!empty($contactname)) { + $dao = new CRM_Core_DAO(); + $contactname = $dao->escape($contactname); + $clauses[] = "(contact_a.sort_name LIKE '%{$contactname}%' OR + contact_b.sort_name LIKE '%{$contactname}%' OR + contact_c.display_name LIKE '%{$contactname}%')"; + } + + $subject = $this->_formValues['activity_subject']; + + if (!empty($this->_formValues['contact_type'])) { + $clauses[] = "contact_a.contact_type LIKE '%{$this->_formValues['contact_type']}%'"; + } + + if (!empty($subject)) { + $dao = new CRM_Core_DAO(); + $subject = $dao->escape($subject); + $clauses[] = "activity.subject LIKE '%{$subject}%'"; + } + + if (!empty($this->_formValues['activity_status_id'])) { + $clauses[] = "activity.status_id = {$this->_formValues['activity_status_id']}"; + } + + if (!empty($this->_formValues['activity_type_id'])) { + $clauses[] = "activity.activity_type_id = {$this->_formValues['activity_type_id']}"; + } + + $startDate = $this->_formValues['start_date']; + if (!empty($startDate)) { + $startDate .= '00:00:00'; + $startDateFormatted = CRM_Utils_Date::processDate($startDate); + if ($startDateFormatted) { + $clauses[] = "activity.activity_date_time >= $startDateFormatted"; + } + } + + $endDate = $this->_formValues['end_date']; + if (!empty($endDate)) { + $endDate .= '23:59:59'; + $endDateFormatted = CRM_Utils_Date::processDate($endDate); + if ($endDateFormatted) { + $clauses[] = "activity.activity_date_time <= $endDateFormatted"; + } + } + + if ($includeContactIDs) { + $contactIDs = array(); + foreach ($this->_formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $clauses[] = "contact_a.id IN ( $contactIDs )"; + } + } + + return implode(' AND ', $clauses); + } + + /* + * Functions below generally don't need to be modified + */ + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + return $this->all($offset, $rowcount, $sort, FALSE, TRUE); + } + + function &columns() { + return $this->_columns; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function summary() { + return NULL; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/Base.php b/CRM/Contact/Form/Search/Custom/Base.php new file mode 100644 index 0000000000..9e18c666f4 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/Base.php @@ -0,0 +1,168 @@ +_formValues = &$formValues; + } + + function count() { + return CRM_Core_DAO::singleValueQuery($this->sql('count(distinct contact_a.id) as total')); + } + + function summary() { + return NULL; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL, $returnSQL = FALSE) { + $sql = $this->sql( + 'contact_a.id as contact_id', + $offset, + $rowcount, + $sort + ); + $this->validateUserSQL($sql); + + if ($returnSQL) { + return $sql; + } + + return CRM_Core_DAO::composeQuery($sql, CRM_Core_DAO::$_nullArray); + } + + function sql( + $selectClause, + $offset = 0, + $rowcount = 0, + $sort = NULL, + $includeContactIDs = FALSE, + $groupBy = NULL + ) { + + $sql = "SELECT $selectClause " . $this->from(); + $where = $this->where(); + if (!empty($where)) { + $sql .= " WHERE " . $where; + } + + if ($includeContactIDs) { + $this->includeContactIDs($sql, + $this->_formValues + ); + } + + if ($groupBy) { + $sql .= " $groupBy "; + } + + $this->addSortOffset($sql, $offset, $rowcount, $sort); + return $sql; + } + + function templateFile() { + return NULL; + } + + function &columns() { + return $this->_columns; + } + + static function includeContactIDs(&$sql, &$formValues) { + $contactIDs = array(); + foreach ($formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $sql .= " AND contact_a.id IN ( $contactIDs )"; + } + } + + function addSortOffset(&$sql, $offset, $rowcount, $sort) { + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= " ORDER BY " . trim($sort->orderBy()); + } + } + + if ($rowcount > 0 && $offset >= 0) { + $sql .= " LIMIT $offset, $rowcount "; + } + } + + function validateUserSQL(&$sql, $onlyWhere = FALSE) { + $includeStrings = array('contact_a'); + $excludeStrings = array('insert', 'delete', 'update'); + + if (!$onlyWhere) { + $includeStrings += array('select', 'from', 'where', 'civicrm_contact'); + } + + foreach ($includeStrings as $string) { + if (stripos($sql, $string) === FALSE) { + CRM_Core_Error::fatal(ts('Could not find \'%1\' string in SQL clause.', + array(1 => $string) + )); + } + } + + foreach ($excludeStrings as $string) { + if (preg_match('/(\s' . $string . ')|(' . $string . '\s)/i', $sql)) { + CRM_Core_Error::fatal(ts('Found illegal \'%1\' string in SQL clause.', + array(1 => $string) + )); + } + } + } + + function whereClause(&$where, &$params) { + return CRM_Core_DAO::composeQuery($where, $params, TRUE); + } +} + diff --git a/CRM/Contact/Form/Search/Custom/Basic.php b/CRM/Contact/Form/Search/Custom/Basic.php new file mode 100644 index 0000000000..ddcf2fb2d6 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/Basic.php @@ -0,0 +1,163 @@ +normalize(); + $this->_columns = array( + ts('') => 'contact_type', + ts('Name') => 'sort_name', + ts('Address') => 'street_address', + ts('City') => 'city', + ts('State') => 'state_province', + ts('Postal') => 'postal_code', + ts('Country') => 'country', + ts('Email') => 'email', + ts('Phone') => 'phone', + ); + + $params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $returnProperties = array(); + $returnProperties['contact_sub_type'] = 1; + + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options', TRUE, NULL, TRUE + ); + + foreach ($this->_columns as $name => $field) { + if (in_array($field, array( + 'street_address', 'city', 'state_province', 'postal_code', 'country')) && + !CRM_Utils_Array::value($field, $addressOptions) + ) { + unset($this->_columns[$name]); + continue; + } + $returnProperties[$field] = 1; + } + + $this->_query = new CRM_Contact_BAO_Query($params, $returnProperties, NULL, + FALSE, FALSE, 1, FALSE, FALSE + ); + } + + /** + * normalize the form values to make it look similar to the advanced form values + * this prevents a ton of work downstream and allows us to use the same code for + * multiple purposes (queries, save/edit etc) + * + * @return void + * @access private + */ + function normalize() { + $contactType = CRM_Utils_Array::value('contact_type', $this->_formValues); + if ($contactType && !is_array($contactType)) { + unset($this->_formValues['contact_type']); + $this->_formValues['contact_type'][$contactType] = 1; + } + + $group = CRM_Utils_Array::value('group', $this->_formValues); + if ($group && !is_array($group)) { + unset($this->_formValues['group']); + $this->_formValues['group'][$group] = 1; + } + + $tag = CRM_Utils_Array::value('tag', $this->_formValues); + if ($tag && !is_array($tag)) { + unset($this->_formValues['tag']); + $this->_formValues['tag'][$tag] = 1; + } + + return; + } + + function buildForm(&$form) { + $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements(); + $form->add('select', 'contact_type', ts('Find...'), $contactTypes); + + // add select for groups + $group = array('' => ts('- any group -')) + CRM_Core_PseudoConstant::group(); + $form->addElement('select', 'group', ts('in'), $group); + + // add select for categories + $tag = array('' => ts('- any tag -')) + CRM_Core_PseudoConstant::tag(); + $form->addElement('select', 'tag', ts('Tagged'), $tag); + + // text for sort_name + $form->add('text', 'sort_name', ts('Name')); + + $form->assign('elements', array('sort_name', 'contact_type', 'group', 'tag')); + } + + function count() { + return $this->_query->searchQuery(0, 0, NULL, TRUE); + } + + function all( + $offset = 0, + $rowCount = 0, + $sort = NULL, + $includeContactIDs = FALSE, + $justIDs = FALSE + ) { + return $this->_query->searchQuery( + $offset, + $rowCount, + $sort, + FALSE, + $includeContactIDs, + FALSE, + $justIDs, + TRUE + ); + } + + function from() { + return $this->_query->_fromClause; + } + + function where($includeContactIDs = FALSE) { + if ($whereClause = $this->_query->whereClause()) { + return $whereClause; + } + return ' (1) '; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Basic.tpl'; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/ContribSYBNT.php b/CRM/Contact/Form/Search/Custom/ContribSYBNT.php new file mode 100644 index 0000000000..515698b20e --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/ContribSYBNT.php @@ -0,0 +1,331 @@ +_formValues = $formValues; + + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Name') => 'display_name', + ts('Donation Count') => 'donation_count', + ts('Donation Amount') => 'donation_amount', + ); + + $this->_amounts = array('min_amount_1' => ts('Min Amount One'), + 'max_amount_1' => ts('Max Amount One'), + 'min_amount_2' => ts('Min Amount Two'), + 'max_amount_2' => ts('Max Amount Two'), + 'exclude_min_amount' => ts('Exclusion Min Amount'), + 'exclude_max_amount' => ts('Exclusion Max Amount'), + ); + + $this->_dates = array('start_date_1' => ts('Start Date One'), + 'end_date_1' => ts('End Date One'), + 'start_date_2' => ts('Start Date Two'), + 'end_date_2' => ts('End Date Two'), + 'exclude_start_date' => ts('Exclusion Start Date'), + 'exclude_end_date' => ts('Exclusion End Date'), + ); + + $this->_checkboxes = array('is_first_amount' => ts('First Donation?')); + + foreach ($this->_amounts as $name => $title) { + $this->{$name} = CRM_Utils_Array::value($name, $this->_formValues); + } + + foreach ($this->_checkboxes as $name => $title) { + $this->{$name} = CRM_Utils_Array::value($name, $this->_formValues, FALSE); + } + + foreach ($this->_dates as $name => $title) { + if (CRM_Utils_Array::value($name, $this->_formValues)) { + $this->{$name} = CRM_Utils_Date::processDate($this->_formValues[$name]); + } + } + } + + function buildForm(&$form) { + + foreach ($this->_amounts as $name => $title) { + $form->add('text', + $name, + $title + ); + } + + foreach ($this->_dates as $name => $title) { + $form->addDate($name, $title, FALSE, array('formatType' => 'custom')); + } + + foreach ($this->_checkboxes as $name => $title) { + $form->add('checkbox', + $name, + $title + ); + } + + $this->setTitle('Contributions made in Year X and not Year Y'); + // @TODO: Decide on better names for "Exclusion" + // @TODO: Add rule to ensure that exclusion dates are not in the inclusion range + } + + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + return $this->all($offset, $rowcount, $sort, FALSE, TRUE); + } + + function all( + $offset = 0, + $rowcount = 0, + $sort = NULL, + $includeContactIDs = FALSE, + $justIDs = FALSE + ) { + + $where = $this->where(); + if (!empty($where)) { + $where = " AND $where"; + } + + $having = $this->having(); + if ($having) { + $having = " HAVING $having "; + } + + $from = $this->from(); + + if ($justIDs) { + $select = 'contact_a.id as contact_id'; + } + else { + $select = $this->select(); + $select = " + DISTINCT contact.id as contact_id, + contact.display_name as display_name, + $select +"; + + } + + $sql = " +SELECT $select +FROM civicrm_contact AS contact +LEFT JOIN civicrm_contribution contrib_1 ON contrib_1.contact_id = contact.id + $from +WHERE contrib_1.contact_id = contact.id +AND contrib_1.is_test = 0 + $where +GROUP BY contact.id + $having +ORDER BY donation_amount desc +"; + + // CRM_Core_Error::debug('sql',$sql); exit(); + return $sql; + } + + function select() { + if ($this->start_date_2 || $this->end_date_2) { + return " +sum(contrib_1.total_amount) + sum(contrib_2.total_amount) AS donation_amount, +count(contrib_1.id) + count(contrib_1.id) AS donation_count +"; + } + else { + return " +sum(contrib_1.total_amount) AS donation_amount, +count(contrib_1.id) AS donation_count +"; + } + } + + function from() { + $from = NULL; + if ($this->start_date_2 || $this->end_date_2) { + $from .= " LEFT JOIN civicrm_contribution contrib_2 ON contrib_2.contact_id = contact.id "; + } + + if ($this->exclude_start_date || + $this->exclude_end_date || + $this->is_first_amount + ) { + $from .= " LEFT JOIN XG_CustomSearch_SYBNT xg ON xg.contact_id = contact.id "; + } + + return $from; + } + + function where($includeContactIDs = FALSE) { + $clauses = array(); + + if ($this->start_date_1) { + $clauses[] = "contrib_1.receive_date >= {$this->start_date_1}"; + } + + if ($this->end_date_1) { + $clauses[] = "contrib_1.receive_date <= {$this->end_date_1}"; + } + + if ($this->start_date_2 || + $this->end_date_2 + ) { + $clauses[] = "contrib_2.is_test = 0"; + + if ($this->start_date_2) { + $clauses[] = "contrib_2.receive_date >= {$this->start_date_2}"; + } + + if ($this->end_date_2) { + $clauses[] = "contrib_2.receive_date <= {$this->end_date_2}"; + } + } + + if ($this->exclude_start_date || + $this->exclude_end_date || + $this->is_first_amount + ) { + + // first create temp table to store contact ids + $sql = "DROP TEMPORARY TABLE IF EXISTS XG_CustomSearch_SYBNT"; + CRM_Core_DAO::executeQuery($sql); + + $sql = "CREATE TEMPORARY TABLE XG_CustomSearch_SYBNT ( contact_id int primary key) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql); + + $excludeClauses = array(); + if ($this->exclude_start_date) { + $excludeClauses[] = "c.receive_date >= {$this->exclude_start_date}"; + } + + if ($this->exclude_end_date) { + $excludeClauses[] = "c.receive_date <= {$this->exclude_end_date}"; + } + + $excludeClause = NULL; + if ($excludeClauses) { + $excludeClause = ' AND ' . implode(' AND ', $excludeClauses); + } + + $having = array(); + if ($this->exclude_min_amount) { + $having[] = "sum(c.total_amount) >= {$this->exclude_min_amount}"; + } + + if ($this->exclude_max_amount) { + $having[] = "sum(c.total_amount) <= {$this->exclude_max_amount}"; + } + + $havingClause = NULL; + if (!empty($having)) { + $havingClause = "HAVING " . implode(' AND ', $having); + } + + if ($excludeClause || $havingClause) { + // Run subquery + $query = " +REPLACE INTO XG_CustomSearch_SYBNT +SELECT DISTINCT contact_id AS contact_id +FROM civicrm_contribution c +WHERE c.is_test = 0 + $excludeClause +GROUP BY c.contact_id + $havingClause +"; + + $dao = CRM_Core_DAO::executeQuery($query); + } + + // now ensure we dont consider donors that are not first time + if ($this->is_first_amount) { + $query = " +REPLACE INTO XG_CustomSearch_SYBNT +SELECT DISTINCT contact_id AS contact_id +FROM civicrm_contribution c +WHERE c.is_test = 0 +AND c.receive_date < {$this->start_date_1} +"; + $dao = CRM_Core_DAO::executeQuery($query); + } + + $clauses[] = " xg.contact_id IS NULL "; + } + + return implode(' AND ', $clauses); + } + + function having($includeContactIDs = FALSE) { + $clauses = array(); + $min = CRM_Utils_Array::value('min_amount', $this->_formValues); + if ($min) { + $clauses[] = "sum(contrib_1.total_amount) >= $min"; + } + + $max = CRM_Utils_Array::value('max_amount', $this->_formValues); + if ($max) { + $clauses[] = "sum(contrib_1.total_amount) <= $max"; + } + + return implode(' AND ', $clauses); + } + + function &columns() { + return $this->_columns; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/ContribSYBNT.tpl'; + } + + function summary() { + return NULL; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/ContributionAggregate.php b/CRM/Contact/Form/Search/Custom/ContributionAggregate.php new file mode 100644 index 0000000000..7552ca6152 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/ContributionAggregate.php @@ -0,0 +1,253 @@ +_formValues = $formValues; + + /** + * Define the columns for search result rows + */ + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Name') => 'sort_name', + ts('Donation Count') => 'donation_count', + ts('Donation Amount') => 'donation_amount', + ); + } + + function buildForm(&$form) { + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Find Contributors by Aggregate Totals'); + + /** + * Define the search form fields here + */ + $form->add('text', + 'min_amount', + ts('Aggregate Total Between $') + ); + $form->addRule('min_amount', ts('Please enter a valid amount (numbers and decimal point only).'), 'money'); + + $form->add('text', + 'max_amount', + ts('...and $') + ); + $form->addRule('max_amount', ts('Please enter a valid amount (numbers and decimal point only).'), 'money'); + + $form->addDate('start_date', ts('Contribution Date From'), FALSE, array('formatType' => 'custom')); + $form->addDate('end_date', ts('...through'), FALSE, array('formatType' => 'custom')); + + $financial_types = CRM_Contribute_PseudoConstant::financialType(); + foreach($financial_types as $financial_type_id => $financial_type) { + $form->addElement('checkbox', "financial_type_id[{$financial_type_id}]", 'Financial Type', $financial_type); + } + + /** + * If you are using the sample template, this array tells the template fields to render + * for the search form. + */ + $form->assign('elements', array('min_amount', 'max_amount', 'start_date', 'end_date', 'financial_type_id')); + } + + /** + * Define the smarty template used to layout the search form and results listings. + */ + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/ContributionAggregate.tpl'; + } + + /** + * Construct the search query + */ + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + + // SELECT clause must include contact_id as an alias for civicrm_contact.id + if ($justIDs) { + $select = "contact_a.id as contact_id"; + } + else { + $select = " +DISTINCT contact_a.id as contact_id, +contact_a.sort_name as sort_name, +sum(contrib.total_amount) AS donation_amount, +count(contrib.id) AS donation_count +"; + } + $from = $this->from(); + + $where = $this->where($includeContactIDs); + + $having = $this->having(); + if ($having) { + $having = " HAVING $having "; + } + + $sql = " +SELECT $select +FROM $from +WHERE $where +GROUP BY contact_a.id +$having +"; + //for only contact ids ignore order. + if (!$justIDs) { + // Define ORDER BY for query in $sort, with default value + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= " ORDER BY " . trim($sort->orderBy()); + } + } + else { + $sql .= "ORDER BY donation_amount desc"; + } + } + + if ($rowcount > 0 && $offset >= 0) { + $sql .= " LIMIT $offset, $rowcount "; + } + return $sql; + } + + function from() { + return " +civicrm_contribution AS contrib, +civicrm_contact AS contact_a +"; + } + + /* + * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values + * + */ + function where($includeContactIDs = FALSE) { + $clauses = array(); + + $clauses[] = "contrib.contact_id = contact_a.id"; + $clauses[] = "contrib.is_test = 0"; + + $startDate = CRM_Utils_Date::processDate($this->_formValues['start_date']); + if ($startDate) { + $clauses[] = "contrib.receive_date >= $startDate"; + } + + $endDate = CRM_Utils_Date::processDate($this->_formValues['end_date']); + if ($endDate) { + $clauses[] = "contrib.receive_date <= $endDate"; + } + + if ($includeContactIDs) { + $contactIDs = array(); + foreach ($this->_formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $clauses[] = "contact_a.id IN ( $contactIDs )"; + } + } + + if (!empty($this->_formValues['financial_type_id'])) { + $financial_type_ids = implode(',', array_keys($this->_formValues['financial_type_id'])); + $clauses[] = "contrib.financial_type_id IN ($financial_type_ids)"; + } + + return implode(' AND ', $clauses); + } + + function having($includeContactIDs = FALSE) { + $clauses = array(); + $min = CRM_Utils_Array::value('min_amount', $this->_formValues); + if ($min) { + $min = CRM_Utils_Rule::cleanMoney($min); + $clauses[] = "sum(contrib.total_amount) >= $min"; + } + + $max = CRM_Utils_Array::value('max_amount', $this->_formValues); + if ($max) { + $max = CRM_Utils_Rule::cleanMoney($max); + $clauses[] = "sum(contrib.total_amount) <= $max"; + } + + return implode(' AND ', $clauses); + } + + /* + * Functions below generally don't need to be modified + */ + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + return $this->all($offset, $rowcount, $sort, FALSE, TRUE); + } + + function &columns() { + return $this->_columns; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function summary() { + return NULL; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/DateAdded.php b/CRM/Contact/Form/Search/Custom/DateAdded.php new file mode 100644 index 0000000000..a181df5346 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/DateAdded.php @@ -0,0 +1,394 @@ +_includeGroups = CRM_Utils_Array::value('includeGroups', $formValues, array()); + $this->_excludeGroups = CRM_Utils_Array::value('excludeGroups', $formValues, array()); + + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Contact Type') => 'contact_type', + ts('Name') => 'sort_name', + ts('Date Added') => 'date_added', + ); + } + + function buildForm(&$form) { + $form->addDate('start_date', ts('Start Date'), FALSE, array('formatType' => 'custom')); + $form->addDate('end_date', ts('End Date'), FALSE, array('formatType' => 'custom')); + + $groups = CRM_Core_PseudoConstant::group(); + $inG = &$form->addElement('advmultiselect', 'includeGroups', + ts('Include Group(s)') . ' ', $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $outG = &$form->addElement('advmultiselect', 'excludeGroups', + ts('Exclude Group(s)') . ' ', $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $inG->setButtonAttributes('add', array('value' => ts('Add >>'))); + $outG->setButtonAttributes('add', array('value' => ts('Add >>'))); + $inG->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + $outG->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $this->setTitle('Search by date added to CiviCRM'); + + //redirect if group not available for search criteria + if (count($groups) == 0) { + CRM_Core_Error::statusBounce(ts("Atleast one Group must be present for search."), + CRM_Utils_System::url('civicrm/contact/search/custom/list', + 'reset=1' + ) + ); + } + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('start_date', 'end_date', 'includeGroups', 'excludeGroups')); + } + + function summary() { + return NULL; + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + + $this->_includeGroups = CRM_Utils_Array::value('includeGroups', $this->_formValues, array()); + + $this->_excludeGroups = CRM_Utils_Array::value('excludeGroups', $this->_formValues, array()); + + $this->_allSearch = FALSE; + $this->_groups = FALSE; + + if (empty($this->_includeGroups) && empty($this->_excludeGroups)) { + //empty search + $this->_allSearch = TRUE; + } + + if (!empty($this->_includeGroups) || !empty($this->_excludeGroups)) { + //group(s) selected + $this->_groups = TRUE; + } + + if ($justIDs) { + $select = "contact_a.id as contact_id"; + } + else { + $selectClause = "contact_a.id as contact_id, + contact_a.contact_type as contact_type, + contact_a.sort_name as sort_name, + d.date_added as date_added"; + } + + $groupBy = " GROUP BY contact_id "; + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, $groupBy + ); + } + + function from() { + //define table name + $randomNum = md5(uniqid()); + $this->_tableName = "civicrm_temp_custom_{$randomNum}"; + + //grab the contacts added in the date range first + $sql = "CREATE TEMPORARY TABLE dates_{$this->_tableName} ( id int primary key, date_added date ) ENGINE=HEAP"; + if ($this->_debug > 0) { + print "-- Date range query:
    ";
    +      print "$sql;";
    +      print "
    "; + } + CRM_Core_DAO::executeQuery($sql); + + $startDate = CRM_Utils_Date::mysqlToIso(CRM_Utils_Date::processDate($this->_formValues['start_date'])); + $endDateFix = NULL; + if (!empty($this->_formValues['end_date'])) { + $endDate = CRM_Utils_Date::mysqlToIso(CRM_Utils_Date::processDate($this->_formValues['end_date'])); + # tack 11:59pm on to make search inclusive of the end date + $endDateFix = "AND date_added <= '" . substr($endDate, 0, 10) . " 23:59:00'"; + } + + $dateRange = "INSERT INTO dates_{$this->_tableName} ( id, date_added ) + SELECT + civicrm_contact.id, + min(civicrm_log.modified_date) AS date_added + FROM + civicrm_contact LEFT JOIN civicrm_log + ON (civicrm_contact.id = civicrm_log.entity_id AND + civicrm_log.entity_table = 'civicrm_contact') + GROUP BY + civicrm_contact.id + HAVING + date_added >= '$startDate' + $endDateFix"; + + if ($this->_debug > 0) { + print "-- Date range query:
    ";
    +      print "$dateRange;";
    +      print "
    "; + } + + CRM_Core_DAO::executeQuery($dateRange, CRM_Core_DAO::$_nullArray); + + // Only include groups in the search query of one or more Include OR Exclude groups has been selected. + // CRM-6356 + if ($this->_groups) { + //block for Group search + $smartGroup = array(); + $group = new CRM_Contact_DAO_Group(); + $group->is_active = 1; + $group->find(); + while ($group->fetch()) { + $allGroups[] = $group->id; + if ($group->saved_search_id) { + $smartGroup[$group->saved_search_id] = $group->id; + } + } + $includedGroups = implode(',', $allGroups); + + if (!empty($this->_includeGroups)) { + $iGroups = implode(',', $this->_includeGroups); + } + else { + //if no group selected search for all groups + $iGroups = $includedGroups; + } + if (is_array($this->_excludeGroups)) { + $xGroups = implode(',', $this->_excludeGroups); + } + else { + $xGroups = 0; + } + + $sql = "DROP TEMPORARY TABLE IF EXISTS Xg_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + + //used only when exclude group is selected + if ($xGroups != 0) { + $excludeGroup = "INSERT INTO Xg_{$this->_tableName} ( contact_id ) + SELECT DISTINCT civicrm_group_contact.contact_id + FROM civicrm_group_contact, dates_{$this->_tableName} AS d + WHERE + d.id = civicrm_group_contact.contact_id AND + civicrm_group_contact.status = 'Added' AND + civicrm_group_contact.group_id IN( {$xGroups})"; + + CRM_Core_DAO::executeQuery($excludeGroup, CRM_Core_DAO::$_nullArray); + + //search for smart group contacts + foreach ($this->_excludeGroups as $keys => $values) { + if (in_array($values, $smartGroup)) { + $ssId = CRM_Utils_Array::key($values, $smartGroup); + + $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId); + + $smartSql = $smartSql . " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')"; + + $smartGroupQuery = " INSERT IGNORE INTO Xg_{$this->_tableName}(contact_id) $smartSql"; + + CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray); + } + } + } + + $sql = "DROP TEMPORARY TABLE IF EXISTS Ig_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + $sql = "CREATE TEMPORARY TABLE Ig_{$this->_tableName} + ( id int PRIMARY KEY AUTO_INCREMENT, + contact_id int, + group_names varchar(64)) ENGINE=HEAP"; + + if ($this->_debug > 0) { + print "-- Include groups query:
    ";
    +        print "$sql;";
    +        print "
    "; + } + + CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + + $includeGroup = "INSERT INTO Ig_{$this->_tableName} (contact_id, group_names) + SELECT d.id as contact_id, civicrm_group.name as group_name + FROM dates_{$this->_tableName} AS d + INNER JOIN civicrm_group_contact + ON civicrm_group_contact.contact_id = d.id + LEFT JOIN civicrm_group + ON civicrm_group_contact.group_id = civicrm_group.id"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $includeGroup .= " LEFT JOIN Xg_{$this->_tableName} + ON d.id = Xg_{$this->_tableName}.contact_id"; + } + $includeGroup .= " WHERE + civicrm_group_contact.status = 'Added' AND + civicrm_group_contact.group_id IN($iGroups)"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $includeGroup .= " AND Xg_{$this->_tableName}.contact_id IS null"; + } + + if ($this->_debug > 0) { + print "-- Include groups query:
    ";
    +        print "$includeGroup;";
    +        print "
    "; + } + + CRM_Core_DAO::executeQuery($includeGroup, CRM_Core_DAO::$_nullArray); + + //search for smart group contacts + foreach ($this->_includeGroups as $keys => $values) { + if (in_array($values, $smartGroup)) { + + $ssId = CRM_Utils_Array::key($values, $smartGroup); + + $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId); + + $smartSql .= " AND contact_a.id IN ( + SELECT id AS contact_id + FROM dates_{$this->_tableName} )"; + + $smartSql .= " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $smartSql .= " AND contact_a.id NOT IN (SELECT contact_id FROM Xg_{$this->_tableName})"; + } + + $smartGroupQuery = " INSERT IGNORE INTO + Ig_{$this->_tableName}(contact_id) + $smartSql"; + + CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray); + if ($this->_debug > 0) { + print "-- Smart group query:
    ";
    +            print "$smartGroupQuery;";
    +            print "
    "; + } + $insertGroupNameQuery = "UPDATE IGNORE Ig_{$this->_tableName} + SET group_names = (SELECT title FROM civicrm_group + WHERE civicrm_group.id = $values) + WHERE Ig_{$this->_tableName}.contact_id IS NOT NULL + AND Ig_{$this->_tableName}.group_names IS NULL"; + CRM_Core_DAO::executeQuery($insertGroupNameQuery, CRM_Core_DAO::$_nullArray); + if ($this->_debug > 0) { + print "-- Smart group query:
    ";
    +            print "$insertGroupNameQuery;";
    +            print "
    "; + } + } + } + } + // end if( $this->_groups ) condition + + $from = "FROM civicrm_contact contact_a"; + + /* We need to join to this again to get the date_added value */ + + $from .= " INNER JOIN dates_{$this->_tableName} d ON (contact_a.id = d.id)"; + + // Only include groups in the search query of one or more Include OR Exclude groups has been selected. + // CRM-6356 + if ($this->_groups) { + $from .= " INNER JOIN Ig_{$this->_tableName} temptable1 ON (contact_a.id = temptable1.contact_id)"; + } + + return $from; + } + + function where($includeContactIDs = FALSE) { + return '(1)'; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + return $dao->N; + } + + function __destruct() { + //drop the temp. tables if they exist + if (!empty($this->_includeGroups)) { + $sql = "DROP TEMPORARY TABLE IF EXISTS Ig_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + } + + if (!empty($this->_excludeGroups)) { + $sql = "DROP TEMPORARY TABLE IF EXISTS Xg_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/EmployerListing.php b/CRM/Contact/Form/Search/Custom/EmployerListing.php new file mode 100644 index 0000000000..2b304afabb --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/EmployerListing.php @@ -0,0 +1,258 @@ +_formValues = $formValues; + + /** + * Define the columns for search result rows + */ + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Individual Name') => 'sort_name', + ts('Individual State') => 'indState', + ts('Employer') => 'employer', + ts('Employer State') => 'empState', + ); + } + + function buildForm(&$form) { + + /** + * You can define a custom title for the search form + */ + $this->setTitle('List Employers for Individual Contacts'); + + /** + * Define the search form fields here + */ + $form->add('text', + 'sort_name', + ts('Individual\'s Name (last, first)') + ); + + $stateProvince = array('' => ts('- any state/province -')) + CRM_Core_PseudoConstant::stateProvince(); + $form->addElement('select', 'state_province_id', ts('Individual\'s Home State'), $stateProvince); + + /** + * If you are using the sample template, this array tells the template fields to render + * for the search form. + */ + $form->assign('elements', array('sort_name', 'state_province_id')); + } + + /* + * Set search form field defaults here. + */ + function setDefaultValues() { + // Setting default search state to California + return array( + 'state_province_id' => 1004, + ); + } + + /** + * Define the smarty template used to layout the search form and results listings. + */ + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + /** + * Construct the search query + */ + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $select = "cInd.id as contact_id"; + } + else { + $select = " + DISTINCT cInd.id as contact_id, + cInd.sort_name as sort_name, + indSP.name as indState, + cEmp.sort_name as employer, + empSP.name as empState + "; + } + + $from = $this->from(); + + $where = $this->where($includeContactIDs); + + $having = $this->having(); + if ($having) { + $having = " HAVING $having "; + } + + // Define GROUP BY here if needed. + $grouping = ""; + + $sql = " + SELECT $select + FROM $from + WHERE $where + $grouping + $having + "; + // Define ORDER BY for query in $sort, with default value + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= " ORDER BY " . trim($sort->orderBy()); + } + } + else { + $sql .= "ORDER BY sort_name asc"; + } + + /* Uncomment the next 2 lines to see the exact query you're generating */ + + // CRM_Core_Error::debug('sql',$sql); + // exit(); + + return $sql; + } + + function from() { + return " + civicrm_relationship cR, + civicrm_contact cInd + LEFT JOIN civicrm_address indAddress ON ( indAddress.contact_id = cInd.id AND + indAddress.is_primary = 1 ) + LEFT JOIN civicrm_state_province indSP ON indSP.id = indAddress.state_province_id, + civicrm_contact cEmp + LEFT JOIN civicrm_address empAddress ON ( empAddress.contact_id = cEmp.id AND + empAddress.is_primary = 1 ) + LEFT JOIN civicrm_state_province empSP ON empSP.id = empAddress.state_province_id + "; + } + + /* + * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values + * + */ + function where($includeContactIDs = FALSE) { + $clauses = array(); + + // These are required filters for our query. + $clauses[] = "cInd.contact_type = 'Individual'"; + $clauses[] = "cR.relationship_type_id = 4"; + $clauses[] = "cR.contact_id_a = cInd.id"; + $clauses[] = "cR.contact_id_b = cEmp.id"; + $clauses[] = "cR.is_active = 1"; + + // These are conditional filters based on user input + $name = CRM_Utils_Array::value('sort_name', + $this->_formValues + ); + if ($name != NULL) { + if (strpos($name, '%') === FALSE) { + $name = "%{$name}%"; + } + $clauses[] = "cInd.sort_name LIKE '$name'"; + } + + $state = CRM_Utils_Array::value('state_province_id', + $this->_formValues + ); + if ($state) { + $clauses[] = "indSP.id = $state"; + } + + if ($includeContactIDs) { + $contactIDs = array(); + foreach ($this->_formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $clauses[] = "contact.id IN ( $contactIDs )"; + } + } + + return implode(' AND ', $clauses); + } + + function having($includeContactIDs = FALSE) { + $clauses = array(); + return implode(' AND ', $clauses); + } + + /* + * Functions below generally don't need to be modified + */ + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + return $this->all($offset, $rowcount, $sort); + } + + function &columns() { + return $this->_columns; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function summary() { + return NULL; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/EventAggregate.php b/CRM/Contact/Form/Search/Custom/EventAggregate.php new file mode 100644 index 0000000000..e7435082b0 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/EventAggregate.php @@ -0,0 +1,308 @@ +_formValues = $formValues; + + /** + * Define the columns for search result rows + */ + $this->_columns = array( + ts('Event') => 'event_name', + ts('Type') => 'event_type', + ts('Number of
    Participant') => 'participant_count', + ts('Total Payment') => 'payment_amount', + ts('Fee') => 'fee', + ts('Net Payment') => 'net_payment', + ts('Participant') => 'participant', + ); + } + + function buildForm(&$form) { + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Find Totals for Events'); + + /** + * Define the search form fields here + */ + + $form->addElement('checkbox', 'paid_online', ts('Only show Credit Card Payments')); + + $form->addElement('checkbox', 'show_payees', ts('Show payees')); + + $event_type = CRM_Core_OptionGroup::values('event_type', FALSE); + foreach ($event_type as $eventId => $eventName) { + $form->addElement('checkbox', "event_type_id[$eventId]", 'Event Type', $eventName); + } + $events = CRM_Event_BAO_Event::getEvents(TRUE); + $form->add('select', 'event_id', ts('Event Name'), array('' => ts('- select -')) + $events); + + $form->addDate('start_date', ts('Payments Date From'), FALSE, array('formatType' => 'custom')); + $form->addDate('end_date', ts('...through'), FALSE, array('formatType' => 'custom')); + + /** + * If you are using the sample template, this array tells the template fields to render + * for the search form. + */ + $form->assign('elements', array('paid_online', 'start_date', 'end_date', 'show_payees', 'event_type_id', 'event_id')); + } + + /** + * Define the smarty template used to layout the search form and results listings. + */ + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/EventDetails.tpl'; + } + + /** + * Construct the search query + */ + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + // SELECT clause must include contact_id as an alias for civicrm_contact.id if you are going to use "tasks" like export etc. + $select = "civicrm_participant.event_id as event_id, + COUNT(civicrm_participant.id) as participant_count, + GROUP_CONCAT(DISTINCT(civicrm_event.title)) as event_name, + civicrm_event.event_type_id as event_type_id, + civicrm_option_value.label as event_type, + IF(civicrm_contribution.payment_instrument_id <>0 , 'Yes', 'No') as payment_instrument_id, + SUM(civicrm_contribution.total_amount) as payment_amount, + format(sum(if(civicrm_contribution.payment_instrument_id <>0,(civicrm_contribution.total_amount *.034) +.45,0)),2) as fee, + format(sum(civicrm_contribution.total_amount - (if(civicrm_contribution.payment_instrument_id <>0,(civicrm_contribution.total_amount *.034) +.45,0))),2) as net_payment"; + + $from = $this->from(); + + $onLine = CRM_Utils_Array::value('paid_online', + $this->_formValues + ); + if ($onLine) { + $from .= " + inner join civicrm_entity_financial_trxn + on (civicrm_entity_financial_trxn.entity_id = civicrm_participant_payment.contribution_id and civicrm_entity_financial_trxn.entity_table='civicrm_contribution')"; + } + + $showPayees = CRM_Utils_Array::value('show_payees', + $this->_formValues + ); + if ($showPayees) { + $select .= ", GROUP_CONCAT(DISTINCT(civicrm_contact.display_name)) as participant "; + $from .= " inner join civicrm_contact + on civicrm_contact.id = civicrm_participant.contact_id"; + } + else { + unset($this->_columns['Participant']); + } + + $where = $this->where(); + + $groupBy = "event_id"; + if (!empty($this->_formValues['event_type_id'])) { + $groupBy = "event_type_id"; + } + + $sql = " + SELECT $select + FROM $from + WHERE $where + GROUP BY $groupBy + "; + // Define ORDER BY for query in $sort, with default value + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= " ORDER BY " . trim($sort->orderBy()); + } + } + else { + $sql .= "ORDER BY event_name desc"; + } + + if ($rowcount > 0 && $offset >= 0) { + $sql .= " LIMIT $offset, $rowcount "; + } + + // Uncomment the next line to see the actual SQL generated: + //CRM_Core_Error::debug('sql',$sql); exit(); + return $sql; + } + + function from() { + return " + civicrm_participant_payment + left join civicrm_participant + on civicrm_participant_payment.participant_id=civicrm_participant.id + + left join civicrm_event on + civicrm_participant.event_id = civicrm_event.id + + left join civicrm_contribution + on civicrm_contribution.id = civicrm_participant_payment.contribution_id + + left join civicrm_option_value on + ( civicrm_option_value.value = civicrm_event.event_type_id AND civicrm_option_value.option_group_id = 14)"; + } + + /* + * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values + * + */ + function where($includeContactIDs = FALSE) { + $clauses = array(); + + $clauses[] = "civicrm_participant.status_id in ( 1 )"; + $clauses[] = "civicrm_contribution.is_test = 0"; + $onLine = CRM_Utils_Array::value('paid_online', + $this->_formValues + ); + if ($onLine) { + $clauses[] = "civicrm_contribution.payment_instrument_id <> 0"; + } + + $startDate = CRM_Utils_Date::processDate($this->_formValues['start_date']); + if ($startDate) { + $clauses[] = "civicrm_contribution.receive_date >= $startDate"; + } + + $endDate = CRM_Utils_Date::processDate($this->_formValues['end_date']); + if ($endDate) { + $clauses[] = "civicrm_contribution.receive_date <= {$endDate}235959"; + } + + if (!empty($this->_formValues['event_id'])) { + $clauses[] = "civicrm_event.id = {$this->_formValues['event_id']}"; + } + + if ($includeContactIDs) { + $contactIDs = array(); + foreach ($this->_formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $clauses[] = "contact.id IN ( $contactIDs )"; + } + } + + if (!empty($this->_formValues['event_type_id'])) { + $event_type_ids = implode(',', array_keys($this->_formValues['event_type_id'])); + $clauses[] = "civicrm_event.event_type_id IN ( $event_type_ids )"; + } + return implode(' AND ', $clauses); + } + + + /* This function does a query to get totals for some of the search result columns and returns a totals array. */ + function summary() { + $totalSelect = " + SUM(civicrm_contribution.total_amount) as payment_amount,COUNT(civicrm_participant.id) as participant_count, + format(sum(if(civicrm_contribution.payment_instrument_id <>0,(civicrm_contribution.total_amount *.034) +.45,0)),2) as fee, + format(sum(civicrm_contribution.total_amount - (if(civicrm_contribution.payment_instrument_id <>0,(civicrm_contribution.total_amount *.034) +.45,0))),2) as net_payment"; + + $from = $this->from(); + + $onLine = CRM_Utils_Array::value('paid_online', + $this->_formValues + ); + if ($onLine) { + $from .= " + inner join civicrm_entity_financial_trxn + on (civicrm_entity_financial_trxn.entity_id = civicrm_participant_payment.contribution_id and civicrm_entity_financial_trxn.entity_table='civicrm_contribution')"; + } + + + $where = $this->where(); + + $sql = " + SELECT $totalSelect + FROM $from + WHERE $where + "; + + //CRM_Core_Error::debug('sql',$sql); + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + $totals = array(); + while ($dao->fetch()) { + $totals['payment_amount'] = $dao->payment_amount; + $totals['fee'] = $dao->fee; + $totals['net_payment'] = $dao->net_payment; + $totals['participant_count'] = $dao->participant_count; + } + return $totals; + } + + /* + * Functions below generally don't need to be modified + */ + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + return $this->all($offset, $rowcount, $sort); + } + + function &columns() { + return $this->_columns; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/FullText.php b/CRM/Contact/Form/Search/Custom/FullText.php new file mode 100644 index 0000000000..a7f842cc78 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/FullText.php @@ -0,0 +1,1035 @@ +_formValues = &$formValues; + + $this->_text = CRM_Utils_Array::value('text', $formValues); + $this->_table = CRM_Utils_Array::value('table', $formValues); + + if (!$this->_text) { + $this->_text = CRM_Utils_Request::retrieve('text', 'String', CRM_Core_DAO::$_nullObject); + if ($this->_text) { + $this->_text = trim($this->_text); + $formValues['text'] = $this->_text; + } + } + + if (!$this->_table) { + $this->_table = CRM_Utils_Request::retrieve('table', 'String', CRM_Core_DAO::$_nullObject); + if ($this->_table) { + $formValues['table'] = $this->_table; + } + } + + // fix text to include wild card characters at begining and end + if ($this->_text) { + if (is_numeric($this->_text)) { + $this->_textID = $this->_text; + } + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + $this->_text = $strtolower(CRM_Core_DAO::escapeString($this->_text)); + if (strpos($this->_text, '%') === FALSE) { + $this->_text = "'%{$this->_text}%'"; + } + else { + $this->_text = "'{$this->_text}'"; + } + } + else { + $this->_text = "'%'"; + } + + if (!$this->_table) { + $this->_limitClause = " LIMIT {$this->_limitNumberPlus1}"; + $this->_limitRowClause = $this->_limitDetailClause = " LIMIT {$this->_limitNumber}"; + } + else { + // when there is table specified, we would like to use the pager. But since + // 1. this custom search has slightly different structure , + // 2. we are in constructor right now, + // we 'll use a small hack - + $rowCount = CRM_Utils_Pager::ROWCOUNT; + $pageId = CRM_Utils_Array::value('crmPID', $_REQUEST); + $pageId = $pageId ? $pageId : 1; + $offset = ($pageId - 1) * $rowCount; + $this->_limitClause = NULL; + $this->_limitRowClause = " LIMIT $rowCount"; + $this->_limitDetailClause = " LIMIT $offset, $rowCount"; + } + } + + function __destruct() { + } + + function initialize() { + static $initialized = FALSE; + + if (!$initialized) { + $initialized = TRUE; + + $this->buildTempTable(); + + $this->fillTable(); + } + } + + function buildTempTable() { + $randomNum = md5(uniqid()); + $this->_tableName = "civicrm_temp_custom_details_{$randomNum}"; + + $this->_tableFields = array( + 'id' => 'int unsigned NOT NULL AUTO_INCREMENT', + 'table_name' => 'varchar(16)', + 'contact_id' => 'int unsigned', + 'sort_name' => 'varchar(128)', + 'assignee_contact_id' => 'int unsigned', + 'assignee_sort_name' => 'varchar(128)', + 'target_contact_id' => 'int unsigned', + 'target_sort_name' => 'varchar(128)', + 'activity_id' => 'int unsigned', + 'activity_type_id' => 'int unsigned', + 'client_id' => 'int unsigned', + 'case_id' => 'int unsigned', + 'case_start_date' => 'datetime', + 'case_end_date' => 'datetime', + 'case_is_deleted' => 'tinyint', + 'subject' => 'varchar(255)', + 'details' => 'varchar(255)', + 'contribution_id' => 'int unsigned', + 'financial_type' => 'varchar(255)', + 'contribution_page' => 'varchar(255)', + 'contribution_receive_date' => 'datetime', + 'contribution_total_amount' => 'decimal(20,2)', + 'contribution_trxn_Id' => 'varchar(255)', + 'contribution_source' => 'varchar(255)', + 'contribution_status' => 'varchar(255)', + 'contribution_check_number' => 'varchar(255)', + 'participant_id' => 'int unsigned', + 'event_title' => 'varchar(255)', + 'participant_fee_level' => 'varchar(255)', + 'participant_fee_amount' => 'int unsigned', + 'participant_source' => 'varchar(255)', + 'participant_register_date' => 'datetime', + 'participant_status' => 'varchar(255)', + 'participant_role' => 'varchar(255)', + 'membership_id' => 'int unsigned', + 'membership_fee' => 'int unsigned', + 'membership_type' => 'varchar(255)', + 'membership_start_date' => 'datetime', + 'membership_end_date' => 'datetime', + 'membership_source' => 'varchar(255)', + 'membership_status' => 'varchar(255)', + ); + + $sql = " +CREATE TEMPORARY TABLE {$this->_tableName} ( +"; + + foreach ($this->_tableFields as $name => $desc) { + $sql .= "$name $desc,\n"; + } + + $sql .= " + PRIMARY KEY ( id ) +) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci +"; + CRM_Core_DAO::executeQuery($sql); + + $this->_entityIDTableName = "civicrm_temp_custom_entityID_{$randomNum}"; + $sql = " +CREATE TEMPORARY TABLE {$this->_entityIDTableName} ( + id int unsigned NOT NULL AUTO_INCREMENT, + entity_id int unsigned NOT NULL, + + UNIQUE INDEX unique_entity_id ( entity_id ), + PRIMARY KEY ( id ) +) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci +"; + CRM_Core_DAO::executeQuery($sql); + } + + function fillTable() { + $config = CRM_Core_Config::singleton(); + + if ((!$this->_table || $this->_table == 'Contact')) { + $this->fillContact(); + } + + if ((!$this->_table || $this->_table == 'Activity') && + CRM_Core_Permission::check('view all activities') + ) { + $this->fillActivity(); + } + + if ((!$this->_table || $this->_table == 'Case') && + in_array('CiviCase', $config->enableComponents) + ) { + $this->fillCase(); + } + + if ((!$this->_table || $this->_table == 'Contribution') && + in_array('CiviContribute', $config->enableComponents) && + CRM_Core_Permission::check('access CiviContribute') + ) { + $this->fillContribution(); + } + + if ((!$this->_table || $this->_table == 'Participant') && + (in_array('CiviEvent', $config->enableComponents) && + CRM_Core_Permission::check('view event participants') + ) + ) { + $this->fillParticipant(); + } + + if ((!$this->_table || $this->_table == 'Membership') && + in_array('CiviMember', $config->enableComponents) && + CRM_Core_Permission::check('access CiviMember') + ) { + $this->fillMembership(); + } + + $this->filterACLContacts(); + } + + function filterACLContacts() { + if (CRM_Core_Permission::check('view all contacts')) { + CRM_Core_DAO::executeQuery("DELETE FROM {$this->_tableName} WHERE contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)"); + return; + } + + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + if (!$contactID) { + $contactID = 0; + } + + CRM_Contact_BAO_Contact_Permission::cache($contactID); + + $params = array(1 => array($contactID, 'Integer')); + + $sql = " +DELETE t.* +FROM {$this->_tableName} t +WHERE NOT EXISTS ( SELECT c.id + FROM civicrm_acl_contact_cache c + WHERE c.user_id = %1 AND t.contact_id = c.contact_id ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + + $sql = " +DELETE t.* +FROM {$this->_tableName} t +WHERE t.table_name = 'Activity' AND + NOT EXISTS ( SELECT c.id + FROM civicrm_acl_contact_cache c + WHERE c.user_id = %1 AND ( t.target_contact_id = c.contact_id OR t.target_contact_id IS NULL ) ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + + $sql = " +DELETE t.* +FROM {$this->_tableName} t +WHERE t.table_name = 'Activity' AND + NOT EXISTS ( SELECT c.id + FROM civicrm_acl_contact_cache c + WHERE c.user_id = %1 AND ( t.assignee_contact_id = c.contact_id OR t.assignee_contact_id IS NULL ) ) +"; + CRM_Core_DAO::executeQuery($sql, $params); + } + + function fillCustomInfo(&$tables, + $extends + ) { + + $sql = " +SELECT cg.table_name, cf.column_name +FROM civicrm_custom_group cg +INNER JOIN civicrm_custom_field cf ON cf.custom_group_id = cg.id +WHERE cg.extends IN $extends +AND cg.is_active = 1 +AND cf.is_active = 1 +AND cf.is_searchable = 1 +AND cf.html_type IN ( 'Text', 'TextArea', 'RichTextEditor' ) +"; + + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + if (!array_key_exists($dao->table_name, $tables)) { + $tables[$dao->table_name] = array( + 'id' => 'entity_id', + 'fields' => array(), + ); + } + $tables[$dao->table_name]['fields'][$dao->column_name] = NULL; + } + } + + function runQueries(&$tables) { + $sql = "TRUNCATE {$this->_entityIDTableName}"; + CRM_Core_DAO::executeQuery($sql); + + $maxRowCount = 0; + foreach ($tables as $tableName => $tableValues) { + if ($tableName == 'final') { + continue; + } + else if ($tableName == 'sql') { + foreach ($tableValues as $sqlStatement) { + $sql = " +REPLACE INTO {$this->_entityIDTableName} ( entity_id ) +$sqlStatement +{$this->_limitClause} +"; + CRM_Core_DAO::executeQuery($sql); + } + } + else { + $clauses = array(); + + foreach ($tableValues['fields'] as $fieldName => $fieldType) { + if ($fieldType == 'Int') { + if ($this->_textID) { + $clauses[] = "$fieldName = {$this->_textID}"; + } + } + else { + $clauses[] = "$fieldName LIKE {$this->_text}"; + } + } + + if (empty($clauses)) { + continue; + } + + $whereClause = implode(' OR ', $clauses); + + //resolve conflict between entity tables. + if ($tableName == 'civicrm_note' && + $entityTable = CRM_Utils_Array::value('entity_table', $tableValues) + ) { + $whereClause .= " AND entity_table = '{$entityTable}'"; + } + + $sql = " +REPLACE INTO {$this->_entityIDTableName} ( entity_id ) +SELECT {$tableValues['id']} +FROM $tableName +WHERE ( $whereClause ) +AND {$tableValues['id']} IS NOT NULL +GROUP BY {$tableValues['id']} +{$this->_limitClause} +"; + CRM_Core_DAO::executeQuery($sql); + } + } + + if (isset($tables['final'])) { + foreach ($tables['final'] as $sqlStatement) { + CRM_Core_DAO::executeQuery($sqlStatement); + } + } + + $rowCount = "SELECT count(*) FROM {$this->_entityIDTableName}"; + $tableKey = array_keys($tables); + $this->_foundRows[ucfirst(str_replace('civicrm_', '', $tableKey[0]))] = + CRM_Core_DAO::singleValueQuery($rowCount); + } + + function fillContactIDs() { + $contactSQL = array(); + $contactSQL[] = " +SELECT et.entity_id +FROM civicrm_entity_tag et +INNER JOIN civicrm_tag t ON et.tag_id = t.id +WHERE et.entity_table = 'civicrm_contact' +AND et.tag_id = t.id +AND t.name LIKE {$this->_text} +GROUP BY et.entity_id +"; + + // lets delete all the deceased contacts from the entityID box + // this allows us to keep numbers in sync + // when we have acl contacts, the situation gets even more murky + $final = array(); + $final[] = "DELETE FROM {$this->_entityIDTableName} WHERE entity_id IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)"; + + $tables = array( + 'civicrm_contact' => array( + 'id' => 'id', + 'fields' => array( + 'sort_name' => NULL, + 'nick_name' => NULL, + 'display_name' => NULL, + ), + ), + 'civicrm_address' => array( + 'id' => 'contact_id', + 'fields' => array( + 'street_address' => NULL, + 'city' => NULL, + 'postal_code' => NULL, + ), + ), + 'civicrm_email' => array( + 'id' => 'contact_id', + 'fields' => array('email' => NULL), + ), + 'civicrm_phone' => array( + 'id' => 'contact_id', + 'fields' => array('phone' => NULL), + ), + 'civicrm_note' => array( + 'id' => 'entity_id', + 'entity_table' => 'civicrm_contact', + 'fields' => array( + 'subject' => NULL, + 'note' => NULL, + ), + ), + 'sql' => $contactSQL, + 'final' => $final, + ); + + // get the custom data info + $this->fillCustomInfo($tables, + "( 'Contact', 'Individual', 'Organization', 'Household' )" + ); + + $this->runQueries($tables); + } + + function fillContact() { + + $this->fillContactIDs(); + + //move data from entity table to detail table. + $this->moveEntityToDetail('Contact'); + } + + function fillActivityIDs() { + $contactSQL = array(); + + $contactSQL[] = " +SELECT distinct ca.id +FROM civicrm_activity ca +INNER JOIN civicrm_contact c ON ca.source_contact_id = c.id +LEFT JOIN civicrm_email e ON e.contact_id = c.id +LEFT JOIN civicrm_option_group og ON og.name = 'activity_type' +LEFT JOIN civicrm_option_value ov ON ( ov.option_group_id = og.id ) +WHERE ( (c.sort_name LIKE {$this->_text} OR c.display_name LIKE {$this->_text}) OR + (e.email LIKE {$this->_text} AND + ca.activity_type_id = ov.value AND + ov.name IN ('Inbound Email', 'Email') ) ) +AND (ca.is_deleted = 0 OR ca.is_deleted IS NULL) +AND (c.is_deleted = 0 OR c.is_deleted IS NULL) +"; + + $contactSQL[] = " +SELECT distinct ca.id +FROM civicrm_activity ca +INNER JOIN civicrm_activity_target cat ON cat.activity_id = ca.id +INNER JOIN civicrm_contact c ON cat.target_contact_id = c.id +LEFT JOIN civicrm_email e ON cat.target_contact_id = e.contact_id +LEFT JOIN civicrm_option_group og ON og.name = 'activity_type' +LEFT JOIN civicrm_option_value ov ON ( ov.option_group_id = og.id ) +WHERE ( (c.sort_name LIKE {$this->_text} OR c.display_name LIKE {$this->_text}) OR + ( e.email LIKE {$this->_text} AND + ca.activity_type_id = ov.value AND + ov.name IN ('Inbound Email', 'Email') ) ) +AND (ca.is_deleted = 0 OR ca.is_deleted IS NULL) +AND (c.is_deleted = 0 OR c.is_deleted IS NULL) +"; + + $contactSQL[] = " +SELECT distinct ca.id +FROM civicrm_activity ca +INNER JOIN civicrm_activity_assignment caa ON caa.activity_id = ca.id +INNER JOIN civicrm_contact c ON caa.assignee_contact_id = c.id +LEFT JOIN civicrm_email e ON caa.assignee_contact_id = e.contact_id +LEFT JOIN civicrm_option_group og ON og.name = 'activity_type' +LEFT JOIN civicrm_option_value ov ON ( ov.option_group_id = og.id ) +WHERE caa.activity_id = ca.id +AND caa.assignee_contact_id = c.id +AND ( (c.sort_name LIKE {$this->_text} OR c.display_name LIKE {$this->_text}) OR + (e.email LIKE {$this->_text} AND + ca.activity_type_id = ov.value AND + ov.name IN ('Inbound Email', 'Email')) ) +AND (ca.is_deleted = 0 OR ca.is_deleted IS NULL) +AND (c.is_deleted = 0 OR c.is_deleted IS NULL) +"; + + $contactSQL[] = " +SELECT et.entity_id +FROM civicrm_entity_tag et +INNER JOIN civicrm_tag t ON et.tag_id = t.id +INNER JOIN civicrm_activity ca ON et.entity_id = ca.id +WHERE et.entity_table = 'civicrm_activity' +AND et.tag_id = t.id +AND t.name LIKE {$this->_text} +AND (ca.is_deleted = 0 OR ca.is_deleted IS NULL) +GROUP BY et.entity_id +"; + + $contactSQL[] = " +SELECT distinct ca.id +FROM civicrm_activity ca +WHERE (ca.subject LIKE {$this->_text} OR ca.details LIKE {$this->_text}) +AND (ca.is_deleted = 0 OR ca.is_deleted IS NULL) +"; + + $final = array(); + $final[] = " +DELETE e.* FROM {$this->_entityIDTableName} e +INNER JOIN civicrm_activity a ON e.entity_id = a.id +INNER JOIN civicrm_contact c ON a.source_contact_id = c.id +WHERE c.id IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1) +"; + + $tables = array( + 'civicrm_activity' => array( 'fields' => array() ), + 'sql' => $contactSQL, + 'final' => $final, + ); + + $this->fillCustomInfo($tables, "( 'Activity' )"); + $this->runQueries($tables); + } + + function fillActivity() { + + $this->fillActivityIDs(); + + //move data from entity table to detail table + $this->moveEntityToDetail('Activity'); + } + + function fillCase() { + $this->fillCaseIDs( ); + + //move data from entity table to detail table + $this->moveEntityToDetail('Case'); + } + + function fillCaseIDs( ) { + $contactSQL = array(); + + $contactSQL[] = " +SELECT distinct cc.id +FROM civicrm_case cc +LEFT JOIN civicrm_case_contact ccc ON cc.id = ccc.case_id +LEFT JOIN civicrm_contact c ON ccc.contact_id = c.id +WHERE (c.sort_name LIKE {$this->_text} OR c.display_name LIKE {$this->_text}) + AND (cc.is_deleted = 0 OR cc.is_deleted IS NULL) +"; + + if ($this->_textID) { + $contactSQL[] = " +SELECT distinct cc.id +FROM civicrm_case cc +LEFT JOIN civicrm_case_contact ccc ON cc.id = ccc.case_id +LEFT JOIN civicrm_contact c ON ccc.contact_id = c.id +WHERE cc.id = {$this->_textID} + AND (cc.is_deleted = 0 OR cc.is_deleted IS NULL) +"; + } + + $contactSQL[] = " +SELECT et.entity_id +FROM civicrm_entity_tag et +INNER JOIN civicrm_tag t ON et.tag_id = t.id +WHERE et.entity_table = 'civicrm_case' +AND et.tag_id = t.id +AND t.name LIKE {$this->_text} +GROUP BY et.entity_id +"; + + $tables = array( + 'civicrm_case' => array( 'fields' => array( ) ), + 'sql' => $contactSQL, + ); + + $this->runQueries($tables); + } + + function fillContribution() { + //get contribution ids in entity table. + $this->fillContributionIDs(); + + //move data from entity table to detail table + $this->moveEntityToDetail('Contribution'); + } + + /** + * get contribution ids in entity tables. + */ + function fillContributionIDs() { + $contactSQL = array(); + $contactSQL[] = " +SELECT distinct cc.id +FROM civicrm_contribution cc +INNER JOIN civicrm_contact c ON cc.contact_id = c.id +WHERE (c.sort_name LIKE {$this->_text} OR + c.display_name LIKE {$this->_text}) +"; + $tables = array( + 'civicrm_contribution' => array('id' => 'id', + 'fields' => array( + 'source' => NULL, + 'amount_level' => NULL, + 'trxn_Id' => NULL, + 'invoice_id' => NULL, + 'check_number' => ($this->_textID) ? 'Int' : NULL, + 'total_amount' => ($this->_textID) ? 'Int' : NULL, + ), + ), + 'sql' => $contactSQL, + 'civicrm_note' => array( + 'id' => 'entity_id', + 'entity_table' => 'civicrm_contribution', + 'fields' => array( + 'subject' => NULL, + 'note' => NULL, + ), + ), + ); + + // get the custom data info + $this->fillCustomInfo($tables, "( 'Contribution' )"); + $this->runQueries($tables); + } + + function fillParticipant() { + //get participant ids in entity table. + $this->fillParticipantIDs(); + + //move data from entity table to detail table + $this->moveEntityToDetail('Participant'); + } + + /** + * get participant ids in entity tables. + */ + function fillParticipantIDs() { + $contactSQL = array(); + $contactSQL[] = " +SELECT distinct cp.id +FROM civicrm_participant cp +INNER JOIN civicrm_contact c ON cp.contact_id = c.id +WHERE (c.sort_name LIKE {$this->_text} OR c.display_name LIKE {$this->_text}) +"; + $tables = array( + 'civicrm_participant' => array('id' => 'id', + 'fields' => array( + 'source' => NULL, + 'fee_level' => NULL, + 'fee_amount' => ($this->_textID) ? 'Int' : NULL, + ), + ), + 'sql' => $contactSQL, + 'civicrm_note' => array( + 'id' => 'entity_id', + 'entity_table' => 'civicrm_participant', + 'fields' => array( + 'subject' => NULL, + 'note' => NULL, + ), + ), + ); + + // get the custom data info + $this->fillCustomInfo($tables, "( 'Participant' )"); + $this->runQueries($tables); + } + + function fillMembership() { + + //get membership ids in entity table. + $this->fillMembershipIDs(); + + //move data from entity table to detail table + $this->moveEntityToDetail('Membership'); + } + + /** + * get membership ids in entity tables. + */ + function fillMembershipIDs() { + $contactSQL = array(); + $contactSQL[] = " +SELECT distinct cm.id +FROM civicrm_membership cm +INNER JOIN civicrm_contact c ON cm.contact_id = c.id +WHERE (c.sort_name LIKE {$this->_text} OR c.display_name LIKE {$this->_text}) +"; + $tables = array( + 'civicrm_membership' => array('id' => 'id', + 'fields' => array('source' => NULL), + ), + 'sql' => $contactSQL, + ); + + // get the custom data info + $this->fillCustomInfo($tables, "( 'Membership' )"); + $this->runQueries($tables); + } + + function buildForm(&$form) { + $config = CRM_Core_Config::singleton(); + + $form->applyFilter('__ALL__', 'trim'); + $form->add('text', + 'text', + ts('Find'), + TRUE + ); + + // also add a select box to allow the search to be constrained + $tables = array('' => ts('All tables')); + if (CRM_Core_Permission::check('view all contacts')) { + $tables['Contact'] = ts('Contacts'); + } + if (CRM_Core_Permission::check('view all activities')) { + $tables['Activity'] = ts('Activities'); + } + if (in_array('CiviCase', $config->enableComponents)) { + $tables['Case'] = ts('Cases'); + } + if (in_array('CiviContribute', $config->enableComponents)) { + $tables['Contribution'] = ts('Contributions'); + } + if (in_array('CiviEvent', $config->enableComponents) && CRM_Core_Permission::check('view event participants')) { + $tables['Participant'] = ts('Participants'); + } + if (in_array('CiviMember', $config->enableComponents)) { + $tables['Membership'] = ts('Memberships'); + } + + $form->add('select', + 'table', + ts('Tables'), + $tables + ); + + $form->assign('csID', $form->get('csid')); + + // also add the limit constant + $form->assign('limit', self::LIMIT); + + /** + * You can define a custom title for the search form + */ + $this->setTitle(ts('Full-text Search')); + } + + function &columns() { + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Name') => 'sort_name', + ); + + return $this->_columns; + } + + function summary() { + $this->initialize(); + + $summary = array('Contact' => array(), + 'Activity' => array(), + 'Case' => array(), + 'Contribution' => array(), + 'Participant' => array(), + 'Membership' => array(), + ); + + + // now iterate through the table and add entries to the relevant section + $sql = "SELECT * FROM {$this->_tableName}"; + if ($this->_table) { + $sql .= " {$this->_limitRowClause} "; + } + $dao = CRM_Core_DAO::executeQuery($sql); + + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE); + $roleIds = CRM_Event_PseudoConstant::participantRole(); + while ($dao->fetch()) { + $row = array(); + foreach ($this->_tableFields as $name => $dontCare) { + if ($name != 'activity_type_id') { + $row[$name] = $dao->$name; + } + else { + $row['activity_type'] = CRM_Utils_Array::value($dao->$name, $activityTypes); + } + } + if (isset($row['participant_role'])) { + $participantRole = explode(CRM_Core_DAO::VALUE_SEPARATOR, $row['participant_role']); + $viewRoles = array(); + foreach ($participantRole as $k => $v) { + $viewRoles[] = $roleIds[$v]; + } + $row['participant_role'] = implode(', ', $viewRoles); + } + $summary[$dao->table_name][] = $row; + } + + $summary['Count'] = array(); + foreach (array_keys($summary) as $table) { + $summary['Count'][$table] = CRM_Utils_Array::value($table, $this->_foundRows); + if ($summary['Count'][$table] >= self::LIMIT) { + $summary['addShowAllLink'][$table] = TRUE; + } + else { + $summary['addShowAllLink'][$table] = FALSE; + } + } + + return $summary; + } + + function count() { + $this->initialize(); + + if ($this->_table) { + return $this->_foundRows[$this->_table]; + } + else { + return CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM {$this->_tableName}"); + } + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + $this->initialize(); + + return CRM_Core_DAO::singleValueQuery("SELECT contact_id FROM {$this->_tableName}"); + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + $this->initialize(); + + if ($justIDs) { + $select = "contact_a.contact_id as contact_id"; + } + else { + $select = " + contact_a.contact_id as contact_id , + contact_a.sort_name as sort_name +"; + } + + $sql = " +SELECT $select +FROM {$this->_tableName} contact_a + {$this->_limitRowClause} +"; + return $sql; + } + + function from() { + return NULL; + } + + function where($includeContactIDs = FALSE) { + return NULL; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/FullText.tpl'; + } + + function setDefaultValues() { + return array(); + } + + function alterRow(&$row) {} + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + } + + /** + * get entity id retrieve related data from db and move all data to detail table. + * + */ + function moveEntityToDetail($tableName) { + $sql = NULL; + switch ($tableName) { + case 'Contact': + $sql = " +INSERT INTO {$this->_tableName} +( contact_id, sort_name, table_name ) +SELECT c.id, c.sort_name, 'Contact' + FROM {$this->_entityIDTableName} ct +INNER JOIN civicrm_contact c ON ct.entity_id = c.id +{$this->_limitDetailClause} +"; + break; + + case 'Activity': + $sql = " +INSERT INTO {$this->_tableName} +( table_name, activity_id, subject, details, contact_id, sort_name, assignee_contact_id, assignee_sort_name, target_contact_id, + target_sort_name, activity_type_id, case_id, client_id ) +SELECT 'Activity', ca.id, substr(ca.subject, 1, 50), substr(ca.details, 1, 250), + c1.id, c1.sort_name, + c2.id, c2.sort_name, + c3.id, c3.sort_name, + ca.activity_type_id, + cca.case_id, + ccc.contact_id as client_id +FROM {$this->_entityIDTableName} eid +INNER JOIN civicrm_activity ca ON ca.id = eid.entity_id +LEFT JOIN civicrm_contact c1 ON ca.source_contact_id = c1.id +LEFT JOIN civicrm_activity_assignment caa ON caa.activity_id = ca.id +LEFT JOIN civicrm_contact c2 ON caa.assignee_contact_id = c2.id +LEFT JOIN civicrm_activity_target cat ON cat.activity_id = ca.id +LEFT JOIN civicrm_contact c3 ON cat.target_contact_id = c3.id +LEFT JOIN civicrm_case_activity cca ON cca.activity_id = ca.id +LEFT JOIN civicrm_case_contact ccc ON ccc.case_id = cca.case_id +WHERE (ca.is_deleted = 0 OR ca.is_deleted IS NULL) +GROUP BY ca.id +{$this->_limitDetailClause} +"; + break; + + case 'Contribution': + $sql = " +INSERT INTO {$this->_tableName} +( table_name, contact_id, sort_name, contribution_id, financial_type, contribution_page, contribution_receive_date, + contribution_total_amount, contribution_trxn_Id, contribution_source, contribution_status, contribution_check_number ) + SELECT 'Contribution', c.id, c.sort_name, cc.id, cct.name, ccp.title, cc.receive_date, + cc.total_amount, cc.trxn_id, cc.source, contribution_status.label, cc.check_number + FROM {$this->_entityIDTableName} ct +INNER JOIN civicrm_contribution cc ON cc.id = ct.entity_id +LEFT JOIN civicrm_contact c ON cc.contact_id = c.id +LEFT JOIN civicrm_financial_type cct ON cct.id = cc.financial_type_id +LEFT JOIN civicrm_contribution_page ccp ON ccp.id = cc.contribution_page_id +LEFT JOIN civicrm_option_group option_group_contributionStatus ON option_group_contributionStatus.name = 'contribution_status' +LEFT JOIN civicrm_option_value contribution_status ON +( contribution_status.option_group_id = option_group_contributionStatus.id AND contribution_status.value = cc.contribution_status_id ) +{$this->_limitDetailClause} +"; + break; + + case 'Participant': + $sql = " +INSERT INTO {$this->_tableName} +( table_name, contact_id, sort_name, participant_id, event_title, participant_fee_level, participant_fee_amount, +participant_register_date, participant_source, participant_status, participant_role ) + SELECT 'Participant', c.id, c.sort_name, cp.id, ce.title, cp.fee_level, cp.fee_amount, cp.register_date, cp.source, + participantStatus.label, cp.role_id + FROM {$this->_entityIDTableName} ct +INNER JOIN civicrm_participant cp ON cp.id = ct.entity_id +LEFT JOIN civicrm_contact c ON cp.contact_id = c.id +LEFT JOIN civicrm_event ce ON ce.id = cp.event_id +LEFT JOIN civicrm_participant_status_type participantStatus ON participantStatus.id = cp.status_id +{$this->_limitDetailClause} +"; + break; + + case 'Membership': + $sql = " +INSERT INTO {$this->_tableName} +( table_name, contact_id, sort_name, membership_id, membership_type, membership_fee, membership_start_date, +membership_end_date, membership_source, membership_status ) + SELECT 'Membership', c.id, c.sort_name, cm.id, cmt.name, cc.total_amount, cm.start_date, cm.end_date, cm.source, cms.name + FROM {$this->_entityIDTableName} ct +INNER JOIN civicrm_membership cm ON cm.id = ct.entity_id +LEFT JOIN civicrm_contact c ON cm.contact_id = c.id +LEFT JOIN civicrm_membership_type cmt ON cmt.id = cm.membership_type_id +LEFT JOIN civicrm_membership_payment cmp ON cmp.membership_id = cm.id +LEFT JOIN civicrm_contribution cc ON cc.id = cmp.contribution_id +LEFT JOIN civicrm_membership_status cms ON cms.id = cm.status_id +{$this->_limitDetailClause} +"; + break; + + case 'Case': + $sql = " +INSERT INTO {$this->_tableName} +( table_name, contact_id, sort_name, case_id, case_start_date, case_end_date, case_is_deleted ) +SELECT 'Case', c.id, c.sort_name, cc.id, DATE(cc.start_date), DATE(cc.end_date), cc.is_deleted +FROM {$this->_entityIDTableName} ct +INNER JOIN civicrm_case cc ON cc.id = ct.entity_id +LEFT JOIN civicrm_case_contact ccc ON cc.id = ccc.case_id +LEFT JOIN civicrm_contact c ON ccc.contact_id = c.id +{$this->_limitDetailClause} +"; + break; + + } + + if ($sql) { + CRM_Core_DAO::executeQuery($sql); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/Group.php b/CRM/Contact/Form/Search/Custom/Group.php new file mode 100644 index 0000000000..fa3d932bd5 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/Group.php @@ -0,0 +1,600 @@ +_formValues = $formValues; + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Contact Type') => 'contact_type', + ts('Name') => 'sort_name', + ts('Group Name') => 'gname', + ts('Tag Name') => 'tname', + ); + + $this->_includeGroups = CRM_Utils_Array::value('includeGroups', $this->_formValues, array()); + $this->_excludeGroups = CRM_Utils_Array::value('excludeGroups', $this->_formValues, array()); + $this->_includeTags = CRM_Utils_Array::value('includeTags', $this->_formValues, array()); + $this->_excludeTags = CRM_Utils_Array::value('excludeTags', $this->_formValues, array()); + + //define variables + $this->_allSearch = FALSE; + $this->_groups = FALSE; + $this->_tags = FALSE; + $this->_andOr = CRM_Utils_Array::value('andOr', $this->_formValues); + + + //make easy to check conditions for groups and tags are + //selected or it is empty search + if (empty($this->_includeGroups) && empty($this->_excludeGroups) && + empty($this->_includeTags) && empty($this->_excludeTags) + ) { + //empty search + $this->_allSearch = TRUE; + } + + $this->_groups = (!empty($this->_includeGroups) || !empty($this->_excludeGroups)); + + $this->_tags = (!empty($this->_includeTags) || !empty($this->_excludeTags)); + } + + function __destruct() { + // mysql drops the tables when connectiomn is terminated + // cannot drop tables here, since the search might be used + // in other parts after the object is destroyed + } + + function buildForm(&$form) { + + $this->setTitle(ts('Include / Exclude Search')); + + $groups = CRM_Core_PseudoConstant::group(); + + $tags = CRM_Core_PseudoConstant::tag(); + if (count($groups) == 0 || count($tags) == 0) { + CRM_Core_Session::setStatus(ts("At least one Group and Tag must be present for Custom Group / Tag search."), ts('Missing Group/Tag')); + $url = CRM_Utils_System::url('civicrm/contact/search/custom/list', 'reset=1'); + CRM_Utils_System::redirect($url); + } + + $inG = &$form->addElement('advmultiselect', 'includeGroups', + ts('Include Group(s)') . ' ', $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $outG = &$form->addElement('advmultiselect', 'excludeGroups', + ts('Exclude Group(s)') . ' ', $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $andOr = array( + '1' => ts('Show contacts that meet the Groups criteria AND the Tags criteria'), + '0' => ts('Show contacts that meet the Groups criteria OR the Tags criteria'), + ); + $form->addRadio('andOr', ts('AND/OR'), $andOr, TRUE, '
    ', TRUE); + + $int = &$form->addElement('advmultiselect', 'includeTags', + ts('Include Tag(s)') . ' ', $tags, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $outt = &$form->addElement('advmultiselect', 'excludeTags', + ts('Exclude Tag(s)') . ' ', $tags, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + //add/remove buttons for groups + $inG->setButtonAttributes('add', array('value' => ts('Add >>')));; + $outG->setButtonAttributes('add', array('value' => ts('Add >>')));; + $inG->setButtonAttributes('remove', array('value' => ts('<< Remove')));; + $outG->setButtonAttributes('remove', array('value' => ts('<< Remove')));; + + //add/remove buttons for tags + $int->setButtonAttributes('add', array('value' => ts('Add >>')));; + $outt->setButtonAttributes('add', array('value' => ts('Add >>')));; + $int->setButtonAttributes('remove', array('value' => ts('<< Remove')));; + $outt->setButtonAttributes('remove', array('value' => ts('<< Remove')));; + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('includeGroups', 'excludeGroups', 'andOr', 'includeTags', 'excludeTags')); + } + + /* + * Set search form field defaults here. + */ + function setDefaultValues() { + return + array( 'andOr' => '1' ); + } + + function all( + $offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = "contact_a.id as contact_id, + contact_a.contact_type as contact_type, + contact_a.sort_name as sort_name"; + + //distinguish column according to user selection + if (($this->_includeGroups && !$this->_includeTags)) { + unset($this->_columns['Tag Name']); + $selectClause .= ", GROUP_CONCAT(DISTINCT group_names ORDER BY group_names ASC ) as gname"; + } + elseif ($this->_includeTags && (!$this->_includeGroups)) { + unset($this->_columns['Group Name']); + $selectClause .= ", GROUP_CONCAT(DISTINCT tag_names ORDER BY tag_names ASC ) as tname"; + } + elseif (!empty($this->_includeTags) && !empty($this->_includeGroups)) { + $selectClause .= ", GROUP_CONCAT(DISTINCT group_names ORDER BY group_names ASC ) as gname , GROUP_CONCAT(DISTINCT tag_names ORDER BY tag_names ASC ) as tname"; + } + else { + unset($this->_columns['Tag Name']); + unset($this->_columns['Group Name']); + } + } + + $from = $this->from(); + + $where = $this->where($includeContactIDs); + + if (!$justIDs && !$this->_allSearch) { + $groupBy = " GROUP BY contact_a.id"; + } + else { + // CRM-10850 + // we do this since this if stmt is called by the smart group part of the code + // adding a groupBy clause and saving it as a smart group messes up the query and + // bad things happen + // andrew hunt seemed to have rewritten this piece when he worked on this search + $groupBy = null; + } + + $sql = "SELECT $selectClause $from WHERE $where $groupBy"; + + // Define ORDER BY for query in $sort, with default value + if (!$justIDs) { + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= " ORDER BY " . trim($sort->orderBy()); + } + } + else { + $sql .= " ORDER BY contact_id ASC"; + } + } + + if ($offset >= 0 && $rowcount > 0) { + $sql .= " LIMIT $offset, $rowcount "; + } + + return $sql; + } + + function from() { + + $iGroups = $xGroups = $iTags = $xTags = 0; + + //define table name + $randomNum = md5(uniqid()); + $this->_tableName = "civicrm_temp_custom_{$randomNum}"; + + //block for Group search + $smartGroup = array(); + if ($this->_groups || $this->_allSearch) { + $group = new CRM_Contact_DAO_Group(); + $group->is_active = 1; + $group->find(); + while ($group->fetch()) { + $allGroups[] = $group->id; + if ($group->saved_search_id) { + $smartGroup[$group->saved_search_id] = $group->id; + } + } + $includedGroups = implode(',', $allGroups); + + if (!empty($this->_includeGroups)) { + $iGroups = implode(',', $this->_includeGroups); + } + else { + //if no group selected search for all groups + $iGroups = NULL; + } + if (is_array($this->_excludeGroups)) { + $xGroups = implode(',', $this->_excludeGroups); + } + else { + $xGroups = 0; + } + + $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql); + + //used only when exclude group is selected + if ($xGroups != 0) { + $excludeGroup = "INSERT INTO Xg_{$this->_tableName} ( contact_id ) + SELECT DISTINCT civicrm_group_contact.contact_id + FROM civicrm_group_contact, civicrm_contact + WHERE + civicrm_contact.id = civicrm_group_contact.contact_id AND + civicrm_group_contact.status = 'Added' AND + civicrm_group_contact.group_id IN( {$xGroups})"; + + CRM_Core_DAO::executeQuery($excludeGroup); + + //search for smart group contacts + foreach ($this->_excludeGroups as $keys => $values) { + if (in_array($values, $smartGroup)) { + $ssId = CRM_Utils_Array::key($values, $smartGroup); + + $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId); + + $smartSql = $smartSql . " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')"; + + $smartGroupQuery = " INSERT IGNORE INTO Xg_{$this->_tableName}(contact_id) $smartSql"; + + CRM_Core_DAO::executeQuery($smartGroupQuery); + } + } + } + + $sql = "CREATE TEMPORARY TABLE Ig_{$this->_tableName} ( id int PRIMARY KEY AUTO_INCREMENT, + contact_id int, + group_names varchar(64)) ENGINE=HEAP"; + + CRM_Core_DAO::executeQuery($sql); + + if ($iGroups) { + $includeGroup = "INSERT INTO Ig_{$this->_tableName} (contact_id, group_names) + SELECT civicrm_contact.id as contact_id, civicrm_group.title as group_name + FROM civicrm_contact + INNER JOIN civicrm_group_contact + ON civicrm_group_contact.contact_id = civicrm_contact.id + LEFT JOIN civicrm_group + ON civicrm_group_contact.group_id = civicrm_group.id"; + } + else { + $includeGroup = "INSERT INTO Ig_{$this->_tableName} (contact_id, group_names) + SELECT civicrm_contact.id as contact_id, '' + FROM civicrm_contact"; + } + + + //used only when exclude group is selected + if ($xGroups != 0) { + $includeGroup .= " LEFT JOIN Xg_{$this->_tableName} + ON civicrm_contact.id = Xg_{$this->_tableName}.contact_id"; + } + + if ($iGroups) { + $includeGroup .= " WHERE + civicrm_group_contact.status = 'Added' AND + civicrm_group_contact.group_id IN($iGroups)"; + } + else { + $includeGroup .= " WHERE ( 1 ) "; + } + + //used only when exclude group is selected + if ($xGroups != 0) { + $includeGroup .= " AND Xg_{$this->_tableName}.contact_id IS null"; + } + + CRM_Core_DAO::executeQuery($includeGroup); + + //search for smart group contacts + + foreach ($this->_includeGroups as $keys => $values) { + if (in_array($values, $smartGroup)) { + + $ssId = CRM_Utils_Array::key($values, $smartGroup); + + $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId); + + $smartSql .= " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $smartSql .= " AND contact_a.id NOT IN (SELECT contact_id FROM Xg_{$this->_tableName})"; + } + + $smartGroupQuery = " INSERT IGNORE INTO Ig_{$this->_tableName}(contact_id) + $smartSql"; + + CRM_Core_DAO::executeQuery($smartGroupQuery); + $insertGroupNameQuery = "UPDATE IGNORE Ig_{$this->_tableName} + SET group_names = (SELECT title FROM civicrm_group + WHERE civicrm_group.id = $values) + WHERE Ig_{$this->_tableName}.contact_id IS NOT NULL + AND Ig_{$this->_tableName}.group_names IS NULL"; + CRM_Core_DAO::executeQuery($insertGroupNameQuery); + } + } + } + //group contact search end here; + + //block for Tags search + if ($this->_tags || $this->_allSearch) { + //find all tags + $tag = new CRM_Core_DAO_Tag(); + $tag->is_active = 1; + $tag->find(); + while ($tag->fetch()) { + $allTags[] = $tag->id; + } + $includedTags = implode(',', $allTags); + + if (!empty($this->_includeTags)) { + $iTags = implode(',', $this->_includeTags); + } + else { + //if no group selected search for all groups + $iTags = NULL; + } + if (is_array($this->_excludeTags)) { + $xTags = implode(',', $this->_excludeTags); + } + else { + $xTags = 0; + } + + $sql = "CREATE TEMPORARY TABLE Xt_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql); + + //used only when exclude tag is selected + if ($xTags != 0) { + $excludeTag = "INSERT INTO Xt_{$this->_tableName} ( contact_id ) + SELECT DISTINCT civicrm_entity_tag.entity_id + FROM civicrm_entity_tag, civicrm_contact + WHERE + civicrm_entity_tag.entity_table = 'civicrm_contact' AND + civicrm_contact.id = civicrm_entity_tag.entity_id AND + civicrm_entity_tag.tag_id IN( {$xTags})"; + + CRM_Core_DAO::executeQuery($excludeTag); + } + + $sql = "CREATE TEMPORARY TABLE It_{$this->_tableName} ( id int PRIMARY KEY AUTO_INCREMENT, + contact_id int, + tag_names varchar(64)) ENGINE=HEAP"; + + CRM_Core_DAO::executeQuery($sql); + + if ($iTags) { + $includeTag = "INSERT INTO It_{$this->_tableName} (contact_id, tag_names) + SELECT civicrm_contact.id as contact_id, civicrm_tag.name as tag_name + FROM civicrm_contact + INNER JOIN civicrm_entity_tag + ON ( civicrm_entity_tag.entity_table = 'civicrm_contact' AND + civicrm_entity_tag.entity_id = civicrm_contact.id ) + LEFT JOIN civicrm_tag + ON civicrm_entity_tag.tag_id = civicrm_tag.id"; + } + else { + $includeTag = "INSERT INTO It_{$this->_tableName} (contact_id, tag_names) + SELECT civicrm_contact.id as contact_id, '' + FROM civicrm_contact"; + } + + //used only when exclude tag is selected + if ($xTags != 0) { + $includeTag .= " LEFT JOIN Xt_{$this->_tableName} + ON civicrm_contact.id = Xt_{$this->_tableName}.contact_id"; + } + if ($iTags) { + $includeTag .= " WHERE civicrm_entity_tag.tag_id IN($iTags)"; + } + else { + $includeTag .= " WHERE ( 1 ) "; + } + + //used only when exclude tag is selected + if ($xTags != 0) { + $includeTag .= " AND Xt_{$this->_tableName}.contact_id IS null"; + } + + CRM_Core_DAO::executeQuery($includeTag); + } + + $from = " FROM civicrm_contact contact_a"; + + /* + * CRM-10850 / CRM-10848 + * If we use include / exclude groups as smart groups for ACL's having the below causes + * a cycle which messes things up. Hence commenting out for now + * $this->buildACLClause('contact_a'); + */ + + /* + * check the situation and set booleans + */ + + $Ig = ($iGroups != 0); + + $It = ($iTags != 0); + + $Xg = ($xGroups != 0); + + $Xt = ($xTags != 0); + + //PICK UP FROM HERE + if (!$this->_groups && !$this->_tags) { + $this->_andOr = 1; + } + + /* + * Set from statement depending on array sel + */ + $whereitems = array(); + foreach (array('Ig', 'It') as $inc) { + if ($this->_andOr == 1) { + if ($$inc) { + $from .= " INNER JOIN {$inc}_{$this->_tableName} temptable$inc ON (contact_a.id = temptable$inc.contact_id)"; + } + } + else { + if ($$inc) { + $from .= " LEFT JOIN {$inc}_{$this->_tableName} temptable$inc ON (contact_a.id = temptable$inc.contact_id)"; + } + } + if ($$inc) { + $whereitems[] = "temptable$inc.contact_id IS NOT NULL"; + } + } + $this->_where = $whereitems ? "(" . implode(' OR ', $whereitems) . ')' : '(1)'; + foreach (array('Xg', 'Xt') as $exc) { + if ($$exc) { + $from .= " LEFT JOIN {$exc}_{$this->_tableName} temptable$exc ON (contact_a.id = temptable$exc.contact_id)"; + $this->_where .= " AND temptable$exc.contact_id IS NULL"; + } + } + + $from .= " LEFT JOIN civicrm_email ON ( contact_a.id = civicrm_email.contact_id AND ( civicrm_email.is_primary = 1 OR civicrm_email.is_bulkmail = 1 ) ) {$this->_aclFrom}"; + + if ($this->_aclWhere) { + $this->_where .= " AND {$this->_aclWhere} "; + } + + // also exclude all contacts that are deleted + // CRM-11627 + $this->_where .= " AND (contact_a.is_deleted != 1) "; + + return $from; + } + + function where($includeContactIDs = FALSE) { + if ($includeContactIDs) { + $contactIDs = array(); + + foreach ($this->_formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $clauses[] = "contact_a.id IN ( $contactIDs )"; + } + $where = "{$this->_where} AND " . implode(' AND ', $clauses); + } + else { + $where = $this->_where; + } + + return $where; + } + + /* + * Functions below generally don't need to be modified + */ + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL, $returnSQL = FALSE) { + return $this->all($offset, $rowcount, $sort, FALSE, TRUE); + } + + function &columns() { + return $this->_columns; + } + + function summary() { + return NULL; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function buildACLClause($tableAlias = 'contact') { + list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause($tableAlias); + } +} + diff --git a/CRM/Contact/Form/Search/Custom/MultipleValues.php b/CRM/Contact/Form/Search/Custom/MultipleValues.php new file mode 100644 index 0000000000..a99764be9d --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/MultipleValues.php @@ -0,0 +1,301 @@ +_groupTree = CRM_Core_BAO_CustomGroup::getTree("'Contact', 'Individual', 'Organization', 'Household'", + CRM_Core_DAO::$_nullObject, + NULL, -1 + ); + + $this->_group = CRM_Utils_Array::value('group', $this->_formValues); + + $this->_tag = CRM_Utils_Array::value('tag', $this->_formValues); + + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Contact Type') => 'contact_type', + ts('Name') => 'sort_name', + ); + + $this->_customGroupIDs = CRM_Utils_Array::value('custom_group', $formValues); + + if (!empty($this->_customGroupIDs)) { + $this->addColumns(); + } + } + + function addColumns() { + // add all the fields for chosen groups + $this->_tables = $this->_options = array(); + foreach ($this->_groupTree as $groupID => $group) { + if (!CRM_Utils_Array::value($groupID, $this->_customGroupIDs)) { + continue; + } + + // now handle all the fields + foreach ($group['fields'] as $fieldID => $field) { + $this->_columns[$field['label']] = "custom_{$field['id']}"; + if (!array_key_exists($group['table_name'], $this->_tables)) { + $this->_tables[$group['table_name']] = array(); + } + $this->_tables[$group['table_name']][$field['id']] = $field['column_name']; + + // also build the option array + $this->_options[$field['id']] = array(); + CRM_Core_BAO_CustomField::buildOption($field, + $this->_options[$field['id']] + ); + } + } + } + + function buildForm(&$form) { + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Multiple Value Custom Group Search and Export'); + + $form->add('text', 'sort_name', ts('Contact Name'), TRUE); + + // add select for contact type + $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements(); + $form->add('select', 'contact_type', ts('Find...'), $contactTypes); + + // add select for groups + $group = array('' => ts('- any group -')) + CRM_Core_PseudoConstant::group(); + $form->addElement('select', 'group', ts('in'), $group); + + // add select for tags + $tag = array('' => ts('- any tag -')) + CRM_Core_PseudoConstant::tag(); + $form->addElement('select', 'tag', ts('Tagged'), $tag); + + if (empty($this->_groupTree)) { + CRM_Core_Error::statusBounce(ts("Atleast one Custom Group must be present, for Custom Group search."), + CRM_Utils_System::url('civicrm/contact/search/custom/list', + 'reset=1' + ) + ); + } + // add the checkbox for custom_groups + foreach ($this->_groupTree as $groupID => $group) { + if ($groupID == 'info') { + continue; + } + $form->addElement('checkbox', "custom_group[$groupID]", NULL, $group['title']); + } + } + + function summary() { + return NULL; + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE, + ) { + //redirect if custom group not select in search criteria + if (!CRM_Utils_Array::value('custom_group', $this->_formValues)) { + CRM_Core_Error::statusBounce(ts("You must select at least one Custom Group as a search criteria."), + CRM_Utils_System::url('civicrm/contact/search/custom', + "reset=1&csid={$this->_formValues['customSearchID']}", + FALSE, NULL, FALSE, TRUE + ) + ); + } + + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = " +contact_a.id as contact_id , +contact_a.contact_type as contact_type, +contact_a.sort_name as sort_name, +"; + } + + $customClauses = array(); + foreach ($this->_tables as $tableName => $fields) { + foreach ($fields as $fieldID => $fieldName) { + $customClauses[] = "{$tableName}.{$fieldName} as custom_{$fieldID}"; + } + } + $selectClause .= implode(',', $customClauses); + + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + $from = "FROM civicrm_contact contact_a"; + $customFrom = array(); + // lets do an INNER JOIN so we get only relevant values rather than all values + if (!empty($this->_tables)) { + foreach ($this->_tables as $tableName => $fields) { + $customFrom[] = " INNER JOIN $tableName ON {$tableName}.entity_id = contact_a.id "; + } + $from .= implode(' ', $customFrom); + } + + // This prevents duplicate rows when contacts have more than one tag any you select "any tag" + if ($this->_tag) { + $from .= " LEFT JOIN civicrm_entity_tag t ON (t.entity_table='civicrm_contact' + AND contact_a.id = t.entity_id)"; + } + + if ($this->_group) { + $from .= " LEFT JOIN civicrm_group_contact cgc ON ( cgc.contact_id = contact_a.id + AND cgc.status = 'Added')"; + } + + return $from; + } + + function where($includeContactIDs = FALSE) { + $count = 1; + $clause = array(); + $params = array(); + $name = CRM_Utils_Array::value('sort_name', + $this->_formValues + ); + if ($name != NULL) { + if (strpos($name, '%') === FALSE) { + $name = "%{$name}%"; + } + $params[$count] = array($name, 'String'); + $clause[] = "contact_a.sort_name LIKE %{$count}"; + $count++; + } + + $contact_type = CRM_Utils_Array::value('contact_type', + $this->_formValues + ); + if ($contact_type != NULL) { + $contactType = explode(CRM_Core_DAO::VALUE_SEPARATOR, $contact_type); + if (count($contactType) > 1) { + $clause[] = "contact_a.contact_type = '$contactType[0]' AND contact_a.contact_sub_type = '$contactType[1]'"; + } + else { + $clause[] = "contact_a.contact_type = '$contactType[0]'"; + } + } + + if ($this->_tag) { + $clause[] = "t.tag_id = {$this->_tag}"; + } + + if ($this->_group) { + $clause[] = "cgc.group_id = {$this->_group}"; + } + + $where = '( 1 )'; + if (!empty($clause)) { + $where .= ' AND ' . implode(' AND ', $clause); + } + + return $this->whereClause($where, $params); + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/MultipleValues.tpl'; + } + + function setDefaultValues() { + return array(); + } + + function alterRow(&$row) { + foreach ($this->_options as $fieldID => $values) { + $customVal = $valueSeparatedArray = array(); + if (in_array($values['attributes']['html_type'], + array('Radio', 'Select', 'Autocomplete-Select') + )) { + if ($values['attributes']['data_type'] == 'ContactReference' && $row["custom_{$fieldID}"]) { + $row["custom_{$fieldID}"] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', (int)$row["custom_{$fieldID}"], 'display_name'); + } + elseif ($row["custom_{$fieldID}"] && + array_key_exists($row["custom_{$fieldID}"], + $values + ) + ) { + $row["custom_{$fieldID}"] = $values[$row["custom_{$fieldID}"]]; + } + } + elseif (in_array($values['attributes']['html_type'], + array('CheckBox', 'Multi-Select', 'AdvMulti-Select') + )) { + $valueSeparatedArray = array_filter(explode(CRM_Core_DAO::VALUE_SEPARATOR, $row["custom_{$fieldID}"])); + foreach ($valueSeparatedArray as $val) { + $customVal[] = $values[$val]; + } + $row["custom_{$fieldID}"] = implode(', ', $customVal); + } + elseif (in_array($values['attributes']['html_type'], + array('Multi-Select State/Province', 'Select State/Province') + )) { + $valueSeparatedArray = array_filter(explode(CRM_Core_DAO::VALUE_SEPARATOR, $row["custom_{$fieldID}"])); + $stateName = CRM_Core_PseudoConstant::stateProvince(); + foreach ($valueSeparatedArray as $val) { + $customVal[] = $stateName[$val]; + } + $row["custom_{$fieldID}"] = implode(', ', $customVal); + } + elseif (in_array($values['attributes']['html_type'], + array('Multi-Select Country', 'Select Country') + )) { + $valueSeparatedArray = array_filter(explode(CRM_Core_DAO::VALUE_SEPARATOR, $row["custom_{$fieldID}"])); + CRM_Core_PseudoConstant::populate($countryNames, 'CRM_Core_DAO_Country', + TRUE, 'name', 'is_active' + ); + foreach ($valueSeparatedArray as $val) { + $customVal[] = $countryNames[$val]; + } + $row["custom_{$fieldID}"] = implode(', ', $customVal); + } + } + } + + function setTitle($title) { + CRM_Utils_System::setTitle($title); + } +} + diff --git a/CRM/Contact/Form/Search/Custom/PostalMailing.php b/CRM/Contact/Form/Search/Custom/PostalMailing.php new file mode 100644 index 0000000000..dc2784ceb8 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/PostalMailing.php @@ -0,0 +1,121 @@ +_columns = array( + ts('Contact Id') => 'contact_id', + ts('Address') => 'address', + ts('Contact Type') => 'contact_type', + ts('Name') => 'sort_name', + ts('State') => 'state_province', + ); + } + + function buildForm(&$form) { + $groups = array('' => ts('- select group -')) + CRM_Core_PseudoConstant::allGroup(); + $form->addElement('select', 'group_id', ts('Group'), $groups); + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('group_id')); + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = " +DISTINCT contact_a.id as contact_id , +contact_a.contact_type as contact_type, +contact_a.sort_name as sort_name, +address.street_address as address, +state_province.name as state_province +"; + } + + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + return " +FROM civicrm_group_contact as cgc, + civicrm_contact as contact_a +LEFT JOIN civicrm_address address ON (address.contact_id = contact_a.id AND + address.is_primary = 1 ) +LEFT JOIN civicrm_state_province state_province ON state_province.id = address.state_province_id +"; + } + + function where($includeContactIDs = FALSE) { + $params = array(); + + $count = 1; + $clause = array(); + $groupID = CRM_Utils_Array::value('group_id', + $this->_formValues + ); + if ($groupID) { + $params[$count] = array($groupID, 'Integer'); + $clause[] = "cgc.group_id = %{$count}"; + } + + $clause[] = "cgc.status = 'Added'"; + $clause[] = "contact_a.id = IF( EXISTS(select cr.id from civicrm_relationship cr where (cr.contact_id_a = cgc.contact_id AND (cr.relationship_type_id = 7 OR cr.relationship_type_id = 6))), + (select cr.contact_id_b from civicrm_relationship cr where (cr.contact_id_a = cgc.contact_id AND (cr.relationship_type_id = 7 OR cr.relationship_type_id = 6))), + cgc.contact_id )"; + $clause[] = "contact_a.contact_type IN ('Individual','Household')"; + + if (!empty($clause)) { + $where = implode(' AND ', $clause); + } + + return $this->whereClause($where, $params); + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/PriceSet.php b/CRM/Contact/Form/Search/Custom/PriceSet.php new file mode 100644 index 0000000000..dc3fe40148 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/PriceSet.php @@ -0,0 +1,307 @@ +_eventID = CRM_Utils_Array::value('event_id', + $this->_formValues + ); + + $this->setColumns(); + + if ($this->_eventID) { + $this->buildTempTable(); + + $this->fillTable(); + } + } + + function __destruct() { + /* + if ( $this->_eventID ) { + $sql = "DROP TEMPORARY TABLE {$this->_tableName}"; + CRM_Core_DAO::executeQuery( $sql ); + } + */ + } + + function buildTempTable() { + $randomNum = md5(uniqid()); + $this->_tableName = "civicrm_temp_custom_{$randomNum}"; + $sql = " +CREATE TEMPORARY TABLE {$this->_tableName} ( + id int unsigned NOT NULL AUTO_INCREMENT, + contact_id int unsigned NOT NULL, + participant_id int unsigned NOT NULL, +"; + + foreach ($this->_columns as $dontCare => $fieldName) { + if (in_array($fieldName, array( + 'contact_id', + 'participant_id', + 'display_name', + ))) { + continue; + } + $sql .= "{$fieldName} int default 0,\n"; + } + + $sql .= " +PRIMARY KEY ( id ), +UNIQUE INDEX unique_participant_id ( participant_id ) +) ENGINE=HEAP +"; + + CRM_Core_DAO::executeQuery($sql); + } + + function fillTable() { + $sql = " +REPLACE INTO {$this->_tableName} +( contact_id, participant_id ) +SELECT c.id, p.id +FROM civicrm_contact c, + civicrm_participant p +WHERE p.contact_id = c.id + AND p.is_test = 0 + AND p.event_id = {$this->_eventID} + AND p.status_id NOT IN (4,11,12) + AND ( c.is_deleted = 0 OR c.is_deleted IS NULL ) +"; + CRM_Core_DAO::executeQuery($sql); + + $sql = " +SELECT c.id as contact_id, + p.id as participant_id, + l.price_field_value_id as price_field_value_id, + l.qty +FROM civicrm_contact c, + civicrm_participant p, + civicrm_line_item l +WHERE c.id = p.contact_id +AND p.event_id = {$this->_eventID} +AND p.id = l.entity_id +AND l.entity_table ='civicrm_participant' +ORDER BY c.id, l.price_field_value_id; +"; + + $dao = CRM_Core_DAO::executeQuery($sql); + + // first store all the information by option value id + $rows = array(); + while ($dao->fetch()) { + $contactID = $dao->contact_id; + $participantID = $dao->participant_id; + if (!isset($rows[$participantID])) { + $rows[$participantID] = array(); + } + + $rows[$participantID][] = "price_field_{$dao->price_field_value_id} = {$dao->qty}"; + } + + foreach (array_keys($rows) as $participantID) { + $values = implode(',', $rows[$participantID]); + $sql = " +UPDATE {$this->_tableName} +SET $values +WHERE participant_id = $participantID; +"; + CRM_Core_DAO::executeQuery($sql); + } + } + + function priceSetDAO($eventID = NULL) { + + // get all the events that have a price set associated with it + $sql = " +SELECT e.id as id, + e.title as title, + p.price_set_id as price_set_id +FROM civicrm_event e, + civicrm_price_set_entity p + +WHERE p.entity_table = 'civicrm_event' +AND p.entity_id = e.id +"; + + $params = array(); + if ($eventID) { + $params[1] = array($eventID, 'Integer'); + $sql .= " AND e.id = $eventID"; + } + + $dao = CRM_Core_DAO::executeQuery($sql, + $params + ); + return $dao; + } + + function buildForm(&$form) { + $dao = $this->priceSetDAO(); + + $event = array(); + while ($dao->fetch()) { + $event[$dao->id] = $dao->title; + } + + if (empty($event)) { + CRM_Core_Error::fatal(ts('There are no events with Price Sets')); + } + + $form->add('select', + 'event_id', + ts('Event'), + $event, + TRUE + ); + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Price Set Export'); + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('event_id')); + } + + function setColumns() { + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Participant Id') => 'participant_id', + ts('Name') => 'display_name', + ); + + if (!$this->_eventID) { + return; + } + + // for the selected event, find the price set and all the columns associated with it. + // create a column for each field and option group within it + $dao = $this->priceSetDAO($this->_formValues['event_id']); + + if ($dao->fetch() && + !$dao->price_set_id + ) { + CRM_Core_Error::fatal(ts('There are no events with Price Sets')); + } + + // get all the fields and all the option values associated with it + $priceSet = CRM_Price_BAO_Set::getSetDetail($dao->price_set_id); + if (is_array($priceSet[$dao->price_set_id])) { + foreach ($priceSet[$dao->price_set_id]['fields'] as $key => $value) { + if (is_array($value['options'])) { + foreach ($value['options'] as $oKey => $oValue) { + $columnHeader = CRM_Utils_Array::value('label', $value); + if (CRM_Utils_Array::value('html_type', $value) != 'Text') { + $columnHeader .= ' - ' . $oValue['label']; + } + + $this->_columns[$columnHeader] = "price_field_{$oValue['id']}"; + } + } + } + } + } + + function summary() { + return NULL; + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = " +contact_a.id as contact_id , +contact_a.display_name as display_name"; + + foreach ($this->_columns as $dontCare => $fieldName) { + if (in_array($fieldName, array( + 'contact_id', + 'display_name', + ))) { + continue; + } + $selectClause .= ",\ntempTable.{$fieldName} as {$fieldName}"; + } + } + + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + return " +FROM civicrm_contact contact_a +INNER JOIN {$this->_tableName} tempTable ON ( tempTable.contact_id = contact_a.id ) +"; + } + + function where($includeContactIDs = FALSE) { + return ' ( 1 ) '; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + function setDefaultValues() { + return array(); + } + + function alterRow(&$row) {} + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Export Price Set Info for an Event')); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/Proximity.php b/CRM/Contact/Form/Search/Custom/Proximity.php new file mode 100644 index 0000000000..9d17cc8415 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/Proximity.php @@ -0,0 +1,278 @@ +_formValues['uf_group_id']); + unset($this->_formValues['component_mode']); + unset($this->_formValues['operator']); + + if (!empty($this->_formValues)) { + // add the country and state + if (CRM_Utils_Array::value('country_id', $this->_formValues)) { + $this->_formValues['country'] = CRM_Core_PseudoConstant::country($this->_formValues['country_id']); + } + + if (CRM_Utils_Array::value('state_province_id', $this->_formValues)) { + $this->_formValues['state_province'] = CRM_Core_PseudoConstant::stateProvince($this->_formValues['state_province_id']); + } + + // use the address to get the latitude and longitude + CRM_Utils_Geocode_Google::format($this->_formValues); + + if (!is_numeric(CRM_Utils_Array::value('geo_code_1', $this->_formValues)) || + !is_numeric(CRM_Utils_Array::value('geo_code_2', $this->_formValues)) || + !isset($this->_formValues['distance']) + ) { + CRM_Core_Error::fatal(ts('Could not geocode input')); + } + + $this->_latitude = $this->_formValues['geo_code_1']; + $this->_longitude = $this->_formValues['geo_code_2']; + + if ($this->_formValues['prox_distance_unit'] == "miles") { + $conversionFactor = 1609.344; + } + else { + $conversionFactor = 1000; + } + $this->_distance = $this->_formValues['distance'] * $conversionFactor; + } + $this->_group = CRM_Utils_Array::value('group', $this->_formValues); + + $this->_tag = CRM_Utils_Array::value('tag', $this->_formValues); + + $this->_columns = array( + ts('Name') => 'sort_name', + ts('Street Address') => 'street_address', + ts('City') => 'city', + ts('Postal Code') => 'postal_code', + ts('State') => 'state_province', + ts('Country') => 'country', + ); + } + + function buildForm(&$form) { + + $config = CRM_Core_Config::singleton(); + $countryDefault = $config->defaultContactCountry; + + $form->add('text', 'distance', ts('Distance'), NULL, TRUE); + + $proxUnits = array('km' => ts('km'), 'miles' => ts('miles')); + $form->add('select', 'prox_distance_unit', ts('Units'), $proxUnits, TRUE); + + $form->add('text', + 'street_address', + ts('Street Address') + ); + + $form->add('text', + 'city', + ts('City') + ); + + $form->add('text', + 'postal_code', + ts('Postal Code') + ); + $stateCountryMap = array(); + $stateCountryMap[] = array( + 'state_province' => 'state_province_id', + 'country' => 'country_id', + ); + $defaults = array(); + if ($countryDefault) { + $stateProvince = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($countryDefault); + $defaults['country_id'] = $countryDefault; + } + else { + $stateProvince = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvince(); + } + $form->addElement('select', 'state_province_id', ts('State/Province'), $stateProvince); + + $country = array('' => ts('- select -')) + CRM_Core_PseudoConstant::country(); + $form->add('select', 'country_id', ts('Country'), $country, TRUE); + + $group = array('' => ts('- any group -')) + CRM_Core_PseudoConstant::group(); + $form->addElement('select', 'group', ts('Group'), $group); + + $tag = array('' => ts('- any tag -')) + CRM_Core_PseudoConstant::tag(); + $form->addElement('select', 'tag', ts('Tag'), $tag); + + + // state country js, CRM-5233 + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + CRM_Core_BAO_Address::fixAllStateSelects($form, $defaults); + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Proximity Search'); + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array( + 'distance', + 'prox_distance_unit', + 'street_address', + 'city', + 'postal_code', + 'country_id', + 'state_province_id', + 'group', + 'tag', + )); + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = " +contact_a.id as contact_id , +contact_a.sort_name as sort_name , +address.street_address as street_address, +address.city as city , +address.postal_code as postal_code , +state_province.name as state_province, +country.name as country +"; + } + + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + $f = " +FROM civicrm_contact contact_a +LEFT JOIN civicrm_address address ON ( address.contact_id = contact_a.id AND + address.is_primary = 1 ) +LEFT JOIN civicrm_state_province state_province ON state_province.id = address.state_province_id +LEFT JOIN civicrm_country country ON country.id = address.country_id +"; + + // This prevents duplicate rows when contacts have more than one tag any you select "any tag" + if ($this->_tag) { + $f .= " +LEFT JOIN civicrm_entity_tag t ON (t.entity_table='civicrm_contact' AND contact_a.id = t.entity_id) +"; + } + if ($this->_group) { + $f .= " +LEFT JOIN civicrm_group_contact cgc ON ( cgc.contact_id = contact_a.id AND cgc.status = 'Added') +"; + } + + return $f; + } + + function where($includeContactIDs = FALSE) { + $params = array(); + $clause = array(); + + $where = CRM_Contact_BAO_ProximityQuery::where($this->_latitude, + $this->_longitude, + $this->_distance, + 'address' + ); + + if ($this->_tag) { + $where .= " +AND t.tag_id = {$this->_tag} +"; + } + if ($this->_group) { + $where .= " +AND cgc.group_id = {$this->_group} + "; + } + + $where .= " AND contact_a.is_deleted != 1 "; + + return $this->whereClause($where, $params); + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom/Proximity.tpl'; + } + + function setDefaultValues() { + $config = CRM_Core_Config::singleton(); + $countryDefault = $config->defaultContactCountry; + $stateprovinceDefault = $config->defaultContactStateProvince; + $defaults = array(); + + if ($countryDefault) { + if ($countryDefault == '1228' || $countryDefault == '1226') { + $defaults['prox_distance_unit'] = 'miles'; + } + else { + $defaults['prox_distance_unit'] = 'km'; + } + $defaults['country_id'] = $countryDefault; + if ($stateprovinceDefault) { + $defaults['state_province_id'] = $stateprovinceDefault; + } + return $defaults; + } + return NULL; + } + + function alterRow(&$row) {} + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/RandomSegment.php b/CRM/Contact/Form/Search/Custom/RandomSegment.php new file mode 100644 index 0000000000..8f2d015ef0 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/RandomSegment.php @@ -0,0 +1,343 @@ +_columns = array( + ts('Contact Id') => 'contact_id', + ts('Contact Type') => 'contact_type', + ts('Name') => 'sort_name', + ts('Email') => 'email', + ); + + $this->initialize(); + } + + function initialize() { + $this->_segmentSize = CRM_Utils_Array::value('segmentSize', $this->_formValues); + + $this->_includeGroups = CRM_Utils_Array::value('includeGroups', $this->_formValues); + + $this->_excludeGroups = CRM_Utils_Array::value('excludeGroups', $this->_formValues); + + $this->_allSearch = FALSE; + $this->_groups = FALSE; + + if (empty($this->_includeGroups) && empty($this->_excludeGroups)) { + //empty search + $this->_allSearch = TRUE; + } + + if (!empty($this->_includeGroups) || !empty($this->_excludeGroups)) { + //group(s) selected + $this->_groups = TRUE; + } + } + + function buildForm(&$form) { + $form->add('text', + 'segmentSize', + ts('Segment Size'), + TRUE + ); + + $groups = CRM_Core_PseudoConstant::group(); + $inG = &$form->addElement('advmultiselect', 'includeGroups', + ts('Include Group(s)') . ' ', $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $outG = &$form->addElement('advmultiselect', 'excludeGroups', + ts('Exclude Group(s)') . ' ', $groups, + array( + 'size' => 5, + 'style' => 'width:240px', + 'class' => 'advmultiselect', + ) + ); + + $inG->setButtonAttributes('add', array('value' => ts('Add >>'))); + $outG->setButtonAttributes('add', array('value' => ts('Add >>'))); + $inG->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + $outG->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + $this->setTitle('Create a random segment of contacts'); + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('segmentSize', 'includeGroups', 'excludeGroups')); + } + + function summary() { + return NULL; + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = "contact_a.id as contact_id, + contact_a.contact_type as contact_type, + contact_a.sort_name as sort_name, + civicrm_email.email as email"; + } + + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + //define table name + $randomNum = md5(uniqid()); + $this->_tableName = "civicrm_temp_custom_{$randomNum}"; + + //block for Group search + $smartGroup = array(); + $group = new CRM_Contact_DAO_Group(); + $group->is_active = 1; + $group->find(); + while ($group->fetch()) { + $allGroups[] = $group->id; + if ($group->saved_search_id) { + $smartGroup[$group->saved_search_id] = $group->id; + } + } + $includedGroups = implode(',', $allGroups); + + if (!empty($this->_includeGroups)) { + $iGroups = implode(',', $this->_includeGroups); + } + else { + //if no group selected search for all groups + $iGroups = $includedGroups; + } + if (is_array($this->_excludeGroups)) { + $xGroups = implode(',', $this->_excludeGroups); + } + else { + $xGroups = 0; + } + + $sql = "DROP TEMPORARY TABLE IF EXISTS Xg_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql); + $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql); + + //used only when exclude group is selected + if ($xGroups != 0) { + $excludeGroup = "INSERT INTO Xg_{$this->_tableName} ( contact_id ) + SELECT DISTINCT civicrm_group_contact.contact_id + FROM civicrm_group_contact + WHERE + civicrm_group_contact.status = 'Added' AND + civicrm_group_contact.group_id IN ( {$xGroups} )"; + + CRM_Core_DAO::executeQuery($excludeGroup); + + //search for smart group contacts + foreach ($this->_excludeGroups as $keys => $values) { + if (in_array($values, $smartGroup)) { + $ssId = CRM_Utils_Array::key($values, $smartGroup); + + $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId); + + $smartSql = $smartSql . " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')"; + + $smartGroupQuery = " INSERT IGNORE INTO Xg_{$this->_tableName}(contact_id) $smartSql"; + + CRM_Core_DAO::executeQuery($smartGroupQuery); + } + } + } + + $sql = "DROP TEMPORARY TABLE IF EXISTS Ig_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql); + $sql = "CREATE TEMPORARY TABLE Ig_{$this->_tableName} + ( id int PRIMARY KEY AUTO_INCREMENT, + contact_id int, + group_names varchar(64)) ENGINE=HEAP"; + + if ($this->_debug > 0) { + print "-- Include groups query:
    ";
    +      print "$sql;";
    +      print "
    "; + } + + CRM_Core_DAO::executeQuery($sql); + + $includeGroup = "INSERT INTO Ig_{$this->_tableName} (contact_id, group_names) + SELECT civicrm_group_contact.contact_id, civicrm_group.name as group_name + FROM civicrm_group_contact + LEFT JOIN civicrm_group + ON civicrm_group_contact.group_id = civicrm_group.id"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $includeGroup .= " LEFT JOIN Xg_{$this->_tableName} + ON civicrm_group_contact.contact_id = Xg_{$this->_tableName}.contact_id"; + } + $includeGroup .= " WHERE + civicrm_group_contact.status = 'Added' AND + civicrm_group_contact.group_id IN($iGroups)"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $includeGroup .= " AND Xg_{$this->_tableName}.contact_id IS null"; + } + + if ($this->_debug > 0) { + print "-- Include groups query:
    ";
    +      print "$includeGroup;";
    +      print "
    "; + } + + CRM_Core_DAO::executeQuery($includeGroup); + + //search for smart group contacts + foreach ($this->_includeGroups as $keys => $values) { + if (in_array($values, $smartGroup)) { + + $ssId = CRM_Utils_Array::key($values, $smartGroup); + + $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId); + + $smartSql .= " AND contact_a.id NOT IN ( + SELECT contact_id FROM civicrm_group_contact + WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')"; + + //used only when exclude group is selected + if ($xGroups != 0) { + $smartSql .= " AND contact_a.id NOT IN (SELECT contact_id FROM Xg_{$this->_tableName})"; + } + + $smartGroupQuery = " INSERT IGNORE INTO Ig_{$this->_tableName}(contact_id) + $smartSql"; + + CRM_Core_DAO::executeQuery($smartGroupQuery); + $insertGroupNameQuery = "UPDATE IGNORE Ig_{$this->_tableName} + SET group_names = (SELECT title FROM civicrm_group + WHERE civicrm_group.id = $values) + WHERE Ig_{$this->_tableName}.contact_id IS NOT NULL + AND Ig_{$this->_tableName}.group_names IS NULL"; + CRM_Core_DAO::executeQuery($insertGroupNameQuery); + } + } + + $from = "FROM civicrm_contact contact_a"; + + $fromTail = "LEFT JOIN civicrm_email ON ( contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1 )"; + + $fromTail .= " INNER JOIN Ig_{$this->_tableName} temptable1 ON (contact_a.id = temptable1.contact_id)"; + + // now create a temp table to store the randomized contacts + $sql = "DROP TEMPORARY TABLE IF EXISTS random_{$this->_tableName}"; + CRM_Core_DAO::executeQuery($sql); + $sql = "CREATE TEMPORARY TABLE random_{$this->_tableName} ( id int primary key ) ENGINE=HEAP"; + CRM_Core_DAO::executeQuery($sql); + + if (substr($this->_segmentSize, -1) == '%') { + $countSql = "SELECT DISTINCT contact_a.id $from $fromTail + WHERE " . $this->where(); + $dao = CRM_Core_DAO::executeQuery($countSql); + $totalSize = $dao->N; + $multiplier = substr($this->_segmentSize, 0, strlen($this->_segmentSize) - 1); + $multiplier /= 100; + //CRM_Core_Error::debug( "Total size: $totalSize
    Multiplier: $multiplier
    "); + $this->_segmentSize = round($totalSize * $multiplier); + } + + $sql = "INSERT INTO random_{$this->_tableName} ( id ) + SELECT DISTINCT contact_a.id $from $fromTail + WHERE " . $this->where() . " + ORDER BY RAND() + LIMIT {$this->_segmentSize}"; + CRM_Core_DAO::executeQuery($sql); + + $from = "FROM random_{$this->_tableName} random"; + + $from .= " INNER JOIN civicrm_contact contact_a ON random.id = contact_a.id"; + + $from .= " $fromTail"; + + return $from; + } + + function where($includeContactIDs = FALSE) { + return '(1)'; + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql); + return $dao->N; + } + + function __destruct() { + // the temporary tables are dropped automatically + // so we dont do it here + // but let mysql clean up + return; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/Sample.php b/CRM/Contact/Form/Search/Custom/Sample.php new file mode 100644 index 0000000000..9250ca9cbd --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/Sample.php @@ -0,0 +1,181 @@ +_stateID = CRM_Utils_Request::retrieve('stateID', 'Integer', + CRM_Core_DAO::$_nullObject + ); + if ($this->_stateID) { + $formValues['state_province_id'] = $this->_stateID; + } + } + + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Contact Type') => 'contact_type', + ts('Name') => 'sort_name', + ts('State') => 'state_province', + ); + } + + function buildForm(&$form) { + + $form->add('text', + 'household_name', + ts('Household Name'), + TRUE + ); + + $stateProvince = array('' => ts('- any state/province -')) + CRM_Core_PseudoConstant::stateProvince(); + $form->addElement('select', 'state_province_id', ts('State/Province'), $stateProvince); + + /** + * You can define a custom title for the search form + */ + $this->setTitle('My Search Title'); + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('household_name', 'state_province_id')); + } + + function summary() { + $summary = array( + 'summary' => 'This is a summary', + 'total' => 50.0, + ); + return $summary; + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = " +contact_a.id as contact_id , +contact_a.contact_type as contact_type, +contact_a.sort_name as sort_name, +state_province.name as state_province +"; + } + + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + return " +FROM civicrm_contact contact_a +LEFT JOIN civicrm_address address ON ( address.contact_id = contact_a.id AND + address.is_primary = 1 ) +LEFT JOIN civicrm_email ON ( civicrm_email.contact_id = contact_a.id AND + civicrm_email.is_primary = 1 ) +LEFT JOIN civicrm_state_province state_province ON state_province.id = address.state_province_id +"; + } + + function where($includeContactIDs = FALSE) { + $params = array(); + $where = "contact_a.contact_type = 'Household'"; + + $count = 1; + $clause = array(); + $name = CRM_Utils_Array::value('household_name', + $this->_formValues + ); + if ($name != NULL) { + if (strpos($name, '%') === FALSE) { + $name = "%{$name}%"; + } + $params[$count] = array($name, 'String'); + $clause[] = "contact_a.household_name LIKE %{$count}"; + $count++; + } + + $state = CRM_Utils_Array::value('state_province_id', + $this->_formValues + ); + if (!$state && + $this->_stateID + ) { + $state = $this->_stateID; + } + + if ($state) { + $params[$count] = array($state, 'Integer'); + $clause[] = "state_province.id = %{$count}"; + } + + if (!empty($clause)) { + $where .= ' AND ' . implode(' AND ', $clause); + } + + return $this->whereClause($where, $params); + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + function setDefaultValues() { + return array( + 'household_name' => '', + ); + } + + function alterRow(&$row) { + $row['sort_name'] .= ' ( altered )'; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } +} + diff --git a/CRM/Contact/Form/Search/Custom/TagContributions.php b/CRM/Contact/Form/Search/Custom/TagContributions.php new file mode 100644 index 0000000000..35aa7691fa --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/TagContributions.php @@ -0,0 +1,225 @@ +_formValues = $formValues; + + /** + * Define the columns for search result rows + */ + $this->_columns = array( + ts('Contact Id') => 'contact_id', + ts('Full Name') => 'sort_name', + ts('First Name') => 'first_name', + ts('Last Name') => 'last_name', + ts('Tag') => 'tag_name', + ts('Totals') => 'amount', + ); + } + + function buildForm(&$form) { + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Find Contribution Amounts by Tag'); + + /** + * Define the search form fields here + */ + + + $form->addDate('start_date', ts('Contribution Date From'), FALSE, array('formatType' => 'custom')); + $form->addDate('end_date', ts('...through'), FALSE, array('formatType' => 'custom')); + $tag = array('' => ts('- any tag -')) + CRM_Core_PseudoConstant::tag(); + $form->addElement('select', 'tag', ts('Tagged'), $tag); + + /** + * If you are using the sample template, this array tells the template fields to render + * for the search form. + */ + $form->assign('elements', array('start_date', 'end_date', 'tag')); + } + + /** + * Define the smarty template used to layout the search form and results listings. + */ + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + /** + * Construct the search query + */ + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $onlyIDs = FALSE + ) { + + // SELECT clause must include contact_id as an alias for civicrm_contact.id + if ($onlyIDs) { + $select = "contact_a.id as contact_id"; + } + else { + $select = " +DISTINCT +contact_a.id as contact_id, +contact_a.sort_name as sort_name, +contact_a.first_name as first_name, +contact_a.last_name as last_name, +GROUP_CONCAT(DISTINCT civicrm_tag.name ORDER BY civicrm_tag.name ASC ) as tag_name, +sum(civicrm_contribution.total_amount) as amount +"; + } + $from = $this->from(); + + $where = $this->where($includeContactIDs); + + $sql = " +SELECT $select +FROM $from +WHERE $where +"; + //for only contact ids ignore order and group by. + if (!$onlyIDs) { + $sql .= " GROUP BY contact_a.id"; + // Define ORDER BY for query in $sort, with default value + if (!empty($sort)) { + if (is_string($sort)) { + $sql .= " ORDER BY $sort "; + } + else { + $sql .= " ORDER BY " . trim($sort->orderBy()); + } + } + else { + $sql .= ""; + } + } + return $sql; + } + + function from() { + return " + civicrm_contribution, + civicrm_contact contact_a + LEFT JOIN civicrm_entity_tag ON ( civicrm_entity_tag.entity_table = 'civicrm_contact' AND + civicrm_entity_tag.entity_id = contact_a.id ) + LEFT JOIN civicrm_tag ON civicrm_tag.id = civicrm_entity_tag.tag_id +"; + } + + /* + * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values + * + */ + function where($includeContactIDs = FALSE) { + $clauses = array(); + + $clauses[] = "contact_a.contact_type = 'Individual'"; + $clauses[] = "civicrm_contribution.contact_id = contact_a.id"; + + $startDate = CRM_Utils_Date::processDate($this->_formValues['start_date']); + if ($startDate) { + $clauses[] = "civicrm_contribution.receive_date >= $startDate"; + } + + $endDate = CRM_Utils_Date::processDate($this->_formValues['end_date']); + if ($endDate) { + $clauses[] = "civicrm_contribution.receive_date <= $endDate"; + } + + $tag = CRM_Utils_Array::value('tag', $this->_formValues); + if ($tag) { + $clauses[] = "civicrm_entity_tag.tag_id = $tag"; + $clauses[] = "civicrm_tag.id = civicrm_entity_tag.tag_id"; + } + else { + $clauses[] = "civicrm_entity_tag.tag_id IS NOT NULL"; + } + + if ($includeContactIDs) { + $contactIDs = array(); + foreach ($this->_formValues as $id => $value) { + if ($value && + substr($id, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX + ) { + $contactIDs[] = substr($id, CRM_Core_Form::CB_PREFIX_LEN); + } + } + + if (!empty($contactIDs)) { + $contactIDs = implode(', ', $contactIDs); + $clauses[] = "contact_a.id IN ( $contactIDs )"; + } + } + return implode(' AND ', $clauses); + } + + + /* + * Functions below generally don't need to be modified + */ + function count() { + $sql = $this->all(); + + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + return $dao->N; + } + + function contactIDs($offset = 0, $rowcount = 0, $sort = NULL) { + return $this->all($offset, $rowcount, $sort, FALSE, TRUE); + } + + function &columns() { + return $this->_columns; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } + + function summary() { + return NULL; + } +} + diff --git a/CRM/Contact/Form/Search/Custom/ZipCodeRange.php b/CRM/Contact/Form/Search/Custom/ZipCodeRange.php new file mode 100644 index 0000000000..b07cece660 --- /dev/null +++ b/CRM/Contact/Form/Search/Custom/ZipCodeRange.php @@ -0,0 +1,150 @@ +_columns = array( + ts('Contact Id') => 'contact_id', + ts('Name') => 'sort_name', + ts('Email') => 'email', + ts('Zip') => 'postal_code', + ); + } + + function buildForm(&$form) { + $form->add('text', + 'postal_code_low', + ts('Postal Code Start'), + TRUE + ); + + $form->add('text', + 'postal_code_high', + ts('Postal Code End'), + TRUE + ); + + /** + * You can define a custom title for the search form + */ + $this->setTitle('Zip Code Range Search'); + + /** + * if you are using the standard template, this array tells the template what elements + * are part of the search criteria + */ + $form->assign('elements', array('postal_code_low', 'postal_code_high')); + } + + function summary() { + $summary = array(); + return $summary; + } + + function all($offset = 0, $rowcount = 0, $sort = NULL, + $includeContactIDs = FALSE, $justIDs = FALSE + ) { + if ($justIDs) { + $selectClause = "contact_a.id as contact_id"; + } + else { + $selectClause = " +contact_a.id as contact_id , +contact_a.sort_name as sort_name , +email.email as email , +address.postal_code as postal_code +"; + } + return $this->sql($selectClause, + $offset, $rowcount, $sort, + $includeContactIDs, NULL + ); + } + + function from() { + return " +FROM civicrm_contact contact_a +LEFT JOIN civicrm_address address ON ( address.contact_id = contact_a.id AND + address.is_primary = 1 ) +LEFT JOIN civicrm_email email ON ( email.contact_id = contact_a.id AND + email.is_primary = 1 ) +"; + } + + function where($includeContactIDs = FALSE) { + $params = array(); + + $low = CRM_Utils_Array::value('postal_code_low', + $this->_formValues + ); + $high = CRM_Utils_Array::value('postal_code_high', + $this->_formValues + ); + if ($low == NULL || $high == NULL) { + CRM_Core_Error::statusBounce(ts('Please provide start and end postal codes'), + CRM_Utils_System::url('civicrm/contact/search/custom', + "reset=1&csid={$this->_formValues['customSearchID']}", + FALSE, NULL, FALSE, TRUE + ) + ); + } + + $where = "ROUND(address.postal_code) >= %1 AND ROUND(address.postal_code) <= %2"; + $params = array(1 => array(trim($low), 'Integer'), + 2 => array(trim($high), 'Integer'), + ); + + return $this->whereClause($where, $params); + } + + function setDefaultValues() { + return array(); + } + + function templateFile() { + return 'CRM/Contact/Form/Search/Custom.tpl'; + } + + function setTitle($title) { + if ($title) { + CRM_Utils_System::setTitle($title); + } + else { + CRM_Utils_System::setTitle(ts('Search')); + } + } +} + diff --git a/CRM/Contact/Form/Search/Interface.php b/CRM/Contact/Form/Search/Interface.php new file mode 100644 index 0000000000..a0c8a4e06a --- /dev/null +++ b/CRM/Contact/Form/Search/Interface.php @@ -0,0 +1,109 @@ +assign('rows', $this->get('rows')); + + $this->_params = $this->controller->exportValues($this->_name); + } + + public function buildQuickForm() { + $config = CRM_Core_Config::singleton(); + + $this->add('select', + 'country_id', + ts('Country'), + array('' => ts('- select -')) + CRM_Core_PseudoConstant::country() + ); + + $countryID = isset($_POST['country_id']) ? $_POST['country_id'] : NULL; + if (!$countryID) { + $countryID = isset($this->_params['country_id']) ? $this->_params['country_id'] : NULL; + } + if ($countryID) { + $this->add('select', + 'state_province_id', + ts('State'), + array('' => ts('- select a state -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($countryID) + ); + } + else { + $this->add('select', + 'state_province_id', + ts('State'), + array('' => ts('- select a country first -')) + ); + } + + $stateCountryURL = CRM_Utils_System::url('civicrm/ajax/jqState'); + $this->assign('stateCountryURL', $stateCountryURL); + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + public function postProcess() { + $this->_params = $this->controller->exportValues($this->_name); + CRM_Core_Error::debug($this->_params); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Contact/Form/Task.php b/CRM/Contact/Form/Task.php new file mode 100644 index 0000000000..ce74d5d2c1 --- /dev/null +++ b/CRM/Contact/Form/Task.php @@ -0,0 +1,393 @@ +_contactIds = array(); + $form->_contactTypes = array(); + + // get the submitted values of the search form + // we'll need to get fv from either search or adv search in the future + $fragment = 'search'; + if ($form->_action == CRM_Core_Action::ADVANCED) { + self::$_searchFormValues = $form->controller->exportValues('Advanced'); + $fragment .= '/advanced'; + } + elseif ($form->_action == CRM_Core_Action::PROFILE) { + self::$_searchFormValues = $form->controller->exportValues('Builder'); + $fragment .= '/builder'; + } + elseif ($form->_action == CRM_Core_Action::COPY) { + self::$_searchFormValues = $form->controller->exportValues('Custom'); + $fragment .= '/custom'; + } + else { + self::$_searchFormValues = $form->controller->exportValues('Basic'); + } + + //set the user context for redirection of task actions + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + + $cacheKey = "civicrm search {$qfKey}"; + + $url = CRM_Utils_System::url('civicrm/contact/' . $fragment, $urlParams); + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext($url); + + $form->_task = CRM_Utils_Array::value('task', self::$_searchFormValues); + $crmContactTaskTasks = CRM_Contact_Task::taskTitles(); + $form->assign('taskName', CRM_Utils_Array::value($form->_task, $crmContactTaskTasks)); + + if ($useTable) { + $form->_componentTable = CRM_Core_DAO::createTempTableName('civicrm_task_action', TRUE, $qfKey); + $sql = " DROP TABLE IF EXISTS {$form->_componentTable}"; + CRM_Core_DAO::executeQuery($sql); + + $sql = "CREATE TABLE {$form->_componentTable} ( contact_id int primary key) ENGINE=MyISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci"; + CRM_Core_DAO::executeQuery($sql); + } + + // all contacts or action = save a search + if ((CRM_Utils_Array::value('radio_ts', self::$_searchFormValues) == 'ts_all') || + ($form->_task == CRM_Contact_Task::SAVE_SEARCH) + ) { + $sortByCharacter = $form->get('sortByCharacter'); + $cacheKey = ($sortByCharacter && $sortByCharacter != 'all') ? "{$cacheKey}_alphabet" : $cacheKey; + + if ($form->_action == CRM_Core_Action::COPY) { + $allCids[$cacheKey] = $form->getContactIds( ); + } + else { + $allCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey, "getall"); + } + + $form->_contactIds = array(); + if ($useTable) { + $count = 0; + $insertString = array(); + foreach ($allCids[$cacheKey] as $cid => $ignore) { + $count++; + $insertString[] = " ( {$cid} ) "; + if ($count % 200 == 0) { + $string = implode(',', $insertString); + $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string"; + CRM_Core_DAO::executeQuery($sql); + $insertString = array(); + } + } + if (!empty($insertString)) { + $string = implode(',', $insertString); + $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string"; + CRM_Core_DAO::executeQuery($sql); + } + } + else { + // filter duplicates here + // CRM-7058 + // might be better to do this in the query, but that logic is a bit complex + // and it decides when to use distinct based on input criteria, which needs + // to be fixed and optimized. + + foreach ($allCids[$cacheKey] as $cid => $ignore) { + $form->_contactIds[] = $cid; + } + } + } + elseif (CRM_Utils_Array::value('radio_ts', self::$_searchFormValues) == 'ts_sel') { + // selected contacts only + // need to perform action on only selected contacts + $insertString = array(); + + // refire sql in case of custom seach + if ($form->_action == CRM_Core_Action::COPY) { + // selected contacts only + // need to perform action on only selected contacts + foreach (self::$_searchFormValues as $name => $value) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $contactID = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + if ($useTable) { + $insertString[] = " ( {$contactID} ) "; + } + else { + $form->_contactIds[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + } + } + } + } + else { + // fetching selected contact ids of passed cache key + $selectedCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey); + foreach ($selectedCids[$cacheKey] as $selectedCid => $ignore) { + if ($useTable) { + $insertString[] = " ( {$selectedCid} ) "; + } + else { + $form->_contactIds[] = $selectedCid; + } + } + } + + if (!empty($insertString)) { + $string = implode(',', $insertString); + $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string"; + CRM_Core_DAO::executeQuery($sql); + } + } + + //contact type for pick up profiles as per selected contact types with subtypes + //CRM-5521 + if ($selectedTypes = CRM_Utils_Array::value('contact_type', self::$_searchFormValues)) { + if (!is_array($selectedTypes)) { + $selectedTypes = explode(' ', $selectedTypes); + } + foreach ($selectedTypes as $ct => $dontcare) { + if (strpos($ct, CRM_Core_DAO::VALUE_SEPARATOR) === FALSE) { + $form->_contactTypes[] = $ct; + } + else { + $separator = strpos($ct, CRM_Core_DAO::VALUE_SEPARATOR); + $form->_contactTypes[] = substr($ct, $separator + 1); + } + } + } + + + if (CRM_Utils_Array::value('radio_ts', self::$_searchFormValues) == 'ts_sel' + && ($form->_action != CRM_Core_Action::COPY) ) { + $params = array(); + $sel = CRM_Utils_Array::value('radio_ts', self::$_searchFormValues); + $form->assign('searchtype',$sel); + $result = CRM_Core_BAO_PrevNextCache::getSelectedContacts(); + $form->assign("value", $result); + } + + if (!empty($form->_contactIds)) { + $form->_componentClause = ' contact_a.id IN ( ' . implode(',', $form->_contactIds) . ' ) '; + $form->assign('totalSelectedContacts', count($form->_contactIds)); + + $form->_componentIds = $form->_contactIds; + } + } + + /** + * Function to get the contact id for custom search + * we are not using prev/next table incase of custom search + */ + public function getContactIds() { + // need to perform action on all contacts + // fire the query again and get the contact id's + display name + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $selectorName = $this->controller->selectorName(); + require_once (str_replace('_', DIRECTORY_SEPARATOR, $selectorName) . '.php'); + + $fv = $this->get('formValues'); + $customClass = $this->get('customSearchClass'); + require_once 'CRM/Core/BAO/Mapping.php'; + $returnProperties = CRM_Core_BAO_Mapping::returnProperties(self::$_searchFormValues); + + eval('$selector = new ' . + $selectorName . + '( $customClass, $fv, null, $returnProperties ); ' + ); + + $params = $this->get('queryParams'); + + // fix for CRM-5165 + $sortByCharacter = $this->get('sortByCharacter'); + if ($sortByCharacter && + $sortByCharacter != 1 + ) { + $params[] = array('sortByCharacter', '=', $sortByCharacter, 0, 0); + } + $queryOperator = $this->get('queryOperator'); + if (!$queryOperator) { + $queryOperator = 'AND'; + } + $dao = &$selector->contactIDQuery($params, $this->_action, $sortID, + CRM_Utils_Array::value('display_relationship_type', $fv ), + $queryOperator + ); + + $contactIds = array(); + while( $dao->fetch()) { + $contactIds[$dao->contact_id] = $dao->contact_id; + } + + return $contactIds; + } + + + /** + * This function sets the default values for the form. Relationship that in edit/view action + * the default values are retrieved from the database + * + * @access public + * + * @return void + */ + function setDefaultValues() { + $defaults = array(); + return $defaults; + } + + /** + * This function is used to add the rules for form. + * + * @return void + * @access public + */ + function addRules() {} + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $this->addDefaultButtons(ts('Confirm Action')); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() {} + //end of function + + /** + * simple shell that derived classes can call to add buttons to + * the form with a customized title for the main Submit + * + * @param string $title title of the main button + * @param string $type button type for the form after processing + * + * @return void + * @access public + */ + function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) { + $this->addButtons(array( + array( + 'type' => $nextType, + 'name' => $title, + 'isDefault' => TRUE, + ), + array( + 'type' => $backType, + 'name' => ts('Cancel'), + ), + ) + ); + } +} + diff --git a/CRM/Contact/Form/Task/AddToGroup.php b/CRM/Contact/Form/Task/AddToGroup.php new file mode 100644 index 0000000000..fa88457460 --- /dev/null +++ b/CRM/Contact/Form/Task/AddToGroup.php @@ -0,0 +1,250 @@ +_context = $this->get('context'); + $this->_id = $this->get('amtgID'); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + + //create radio buttons to select existing group or add a new group + $options = array(ts('Add Contact To Existing Group'), ts('Create New Group')); + + if (!$this->_id) { + $this->addRadio('group_option', ts('Group Options'), $options, array('onclick' => "return showElements();")); + + $this->add('text', 'title', ts('Group Name:') . ' ', + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Group', 'title') + ); + $this->addRule('title', ts('Name already exists in Database.'), + 'objectExists', array('CRM_Contact_DAO_Group', $this->_id, 'title') + ); + + $this->add('textarea', 'description', ts('Description:') . ' ', + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Group', 'description') + ); + + $groupTypes = CRM_Core_OptionGroup::values('group_type', TRUE); + if (!CRM_Core_Permission::access('CiviMail')) { + $isWorkFlowEnabled = CRM_Mailing_Info::workflowEnabled(); + if ($isWorkFlowEnabled && + !CRM_Core_Permission::check('create mailings') && + !CRM_Core_Permission::check('schedule mailings') && + !CRM_Core_Permission::check('approve mailings') + ) { + unset($groupTypes['Mailing List']); + } + } + + if (!empty($groupTypes)) { + $this->addCheckBox('group_type', + ts('Group Type'), + $groupTypes, + NULL, NULL, NULL, NULL, '   ' + ); + } + } + + // add select for groups + $group = array('' => ts('- select group -')) + CRM_Core_PseudoConstant::group(); + + $groupElement = $this->add('select', 'group_id', ts('Select Group'), $group); + + $this->_title = $group[$this->_id]; + + if ($this->_context === 'amtg') { + $groupElement->freeze(); + + // also set the group title + $groupValues = array('id' => $this->_id, 'title' => $this->_title); + $this->assign_by_ref('group', $groupValues); + } + + // Set dynamic page title for 'Add Members Group (confirm)' + if ($this->_id) { + CRM_Utils_System::setTitle(ts('Add Contacts: %1', array(1 => $this->_title))); + } + else { + CRM_Utils_System::setTitle(ts('Add Contacts to A Group')); + } + + $this->addDefaultButtons(ts('Add to Group')); + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + $defaults = array(); + + if ($this->_context === 'amtg') { + $defaults['group_id'] = $this->_id; + } + + $defaults['group_option'] = 0; + return $defaults; + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_task_AddToGroup', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($params) { + $errors = array(); + + if (!empty($params['group_option']) && empty($params['title'])) { + $errors['title'] = "Group Name is a required field"; + } + elseif (empty($params['group_option']) && empty($params['group_id'])) { + $errors['group_id'] = "Select Group is a required field."; + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->controller->exportValues(); + $groupOption = CRM_Utils_Array::value('group_option', $params, NULL); + if ($groupOption) { + $groupParams = array(); + $groupParams['title'] = $params['title']; + $groupParams['description'] = $params['description']; + $groupParams['visibility'] = "User and User Admin Only"; + if (array_key_exists('group_type', $params) && is_array($params['group_type'])) { + $groupParams['group_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($params['group_type']) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + } + else { + $groupParams['group_type'] = ''; + } + $groupParams['is_active'] = 1; + + $createdGroup = CRM_Contact_BAO_Group::create($groupParams); + $groupID = $createdGroup->id; + $groupName = $groupParams['title']; + } + else { + $groupID = $params['group_id']; + $group = CRM_Core_PseudoConstant::group(); + $groupName = $group[$groupID]; + } + + list($total, $added, $notAdded) = CRM_Contact_BAO_GroupContact::addContactsToGroup($this->_contactIds, $groupID); + + $status = array(ts('%count contact added to group', array('count' => $added, 'plural' => '%count contacts added to group'))); + if ($notAdded) { + $status[] = ts('%count contact was already in group', array('count' => $notAdded, 'plural' => '%count contacts were already in group')); + } + $status = '
    • ' . implode('
    • ', $status) . '
    '; + CRM_Core_Session::setStatus($status, ts('Added Contact to %1', array(1 => $groupName, 'count' => $added, 'plural' => 'Added Contacts to %1')), 'success', array('expires' => 0)); + } + //end of function +} + diff --git a/CRM/Contact/Form/Task/AddToHousehold.php b/CRM/Contact/Form/Task/AddToHousehold.php new file mode 100644 index 0000000000..30122c27c1 --- /dev/null +++ b/CRM/Contact/Form/Task/AddToHousehold.php @@ -0,0 +1,288 @@ +addElement('text', 'name', ts('Find Target Household')); + + $this->add('select', 'relationship_type_id', ts('Relationship Type'), + array( + '' => ts('- select -')) + + CRM_Contact_BAO_Relationship::getRelationType("Household"), TRUE + ); + + $searchRows = $this->get('searchRows'); + $searchCount = $this->get('searchCount'); + if ($searchRows) { + $checkBoxes = array(); + $chekFlag = 0; + foreach ($searchRows as $id => $row) { + if (!$chekFlag) { + $chekFlag = $id; + } + $checkBoxes[$id] = $this->createElement('radio', NULL, NULL, NULL, $id); + } + $this->addGroup($checkBoxes, 'contact_check'); + if ($chekFlag) { + $checkBoxes[$chekFlag]->setChecked(TRUE); + } + $this->assign('searchRows', $searchRows); + } + + $this->assign('searchCount', $searchCount); + $this->assign('searchDone', $this->get('searchDone')); + $this->assign('contact_type_display', ts('Household')); + $this->addElement('submit', $this->getButtonName('refresh'), ts('Search'), array('class' => 'form-submit')); + $this->addElement('submit', $this->getButtonName('cancel'), ts('Cancel'), array('class' => 'form-submit')); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Add to Household'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $this->set('searchDone', 0); + if (CRM_Utils_Array::value('_qf_AddToHousehold_refresh', $_POST)) { + $searchParams['contact_type'] = array('Household' => 'Household'); + $searchParams['rel_contact'] = $params['name']; + self::search($this, $searchParams); + $this->set('searchDone', 1); + return; + } + + $data = array(); + //$params['relationship_type_id']='4_a_b'; + $data['relationship_type_id'] = $params['relationship_type_id']; + $data['is_active'] = 1; + $invalid = $valid = $duplicate = 0; + if (is_array($this->_contactIds)) { + foreach ($this->_contactIds as $value) { + $ids = array(); + $ids['contact'] = $value; + //contact b --> household + // contact a -> individual + $errors = CRM_Contact_BAO_Relationship::checkValidRelationship($params, $ids, $params['contact_check']); + if ($errors) { + $invalid++; + continue; + } + + if (CRM_Contact_BAO_Relationship::checkDuplicateRelationship($params, + CRM_Utils_Array::value('contact', $ids), + // step 2 + $params['contact_check'] + )) { + $duplicate++; + continue; + } + CRM_Contact_BAO_Relationship::add($data, $ids, $params['contact_check']); + $valid++; + } + + $house = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['contact_check'], 'display_name'); + list($rtype, $a_b) = explode('_', $data['relationship_type_id'], 2); + $relationship = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', $rtype, "label_$a_b"); + + $status = array(ts('%count %2 %3 relationship created', array('count' => $valid, 'plural' => '%count %2 %3 relationships created', 2 => $relationship, 3 => $house))); + if ($duplicate) { + $status[] = ts('%count was skipped because the contact is already %2 %3', array('count' => $duplicate, 'plural' => '%count were skipped because the contacts are already %2 %3', 2 => $relationship, 3 => $house)); + } + if ($invalid) { + $status[] = ts('%count relationship was not created because the contact is not of the right type for this relationship', array('count' => $invalid, 'plural' => '%count relationships were not created because the contact is not of the right type for this relationship')); + } + $status = '
    • ' . implode('
    • ', $status) . '
    '; + CRM_Core_Session::setStatus($status, ts('Relationship Created', array('count' => $valid, 'plural' => 'Relationships Created')), 'success', array('expires' => 0)); + } + } + + /** + * This function is to get the result of the search for Add to * forms + * + * @param array $params This contains elements for search criteria + * + * @access public + * + * @return None + * + */ + function search(&$form, &$params) { + //max records that will be listed + $searchValues = array(); + if (CRM_Utils_Array::value('rel_contact', $params)) { + if (isset($params['rel_contact_id']) && + is_numeric($params['rel_contact_id']) + ) { + $searchValues[] = array('contact_id', '=', $params['rel_contact_id'], 0, 1); + } + else { + $searchValues[] = array('sort_name', 'LIKE', $params['rel_contact'], 0, 1); + } + } + $contactTypeAdded = FALSE; + + $excludedContactIds = array(); + if (isset($form->_contactId)) { + $excludedContactIds[] = $form->_contactId; + } + + if (CRM_Utils_Array::value('relationship_type_id', $params)) { + $relationshipType = new CRM_Contact_DAO_RelationshipType(); + list($rid, $direction) = explode('_', $params['relationship_type_id'], 2); + + $relationshipType->id = $rid; + if ($relationshipType->find(TRUE)) { + if ($direction == 'a_b') { + $type = $relationshipType->contact_type_b; + $subType = $relationshipType->contact_sub_type_b; + } + else { + $type = $relationshipType->contact_type_a; + $subType = $relationshipType->contact_sub_type_a; + } + + $form->set('contact_type', $type); + $form->set('contact_sub_type', $subType); + if ($type == 'Individual' || $type == 'Organization' || $type == 'Household') { + $searchValues[] = array('contact_type', '=', $type, 0, 0); + $contactTypeAdded = TRUE; + } + + if ($subType) { + $searchValues[] = array('contact_sub_type', '=', $subType, 0, 0); + } + } + } + + if (!$contactTypeAdded && CRM_Utils_Array::value('contact_type', $params)) { + $searchValues[] = array('contact_type', '=', $params['contact_type'], 0, 0); + } + + // get the count of contact + $contactBAO = new CRM_Contact_BAO_Contact(); + $query = new CRM_Contact_BAO_Query($searchValues); + $searchCount = $query->searchQuery(0, 0, NULL, TRUE); + $form->set('searchCount', $searchCount); + if ($searchCount <= 50) { + // get the result of the search + $result = $query->searchQuery(0, 50, NULL); + + $config = CRM_Core_Config::singleton(); + $searchRows = array(); + + //variable is set if only one record is foun and that record already has relationship with the contact + $duplicateRelationship = 0; + + while ($result->fetch()) { + $contactID = $result->contact_id; + if (in_array($contactID, $excludedContactIds)) { + $duplicateRelationship++; + continue; + } + + $duplicateRelationship = 0; + + $searchRows[$contactID]['id'] = $contactID; + $searchRows[$contactID]['name'] = $result->sort_name; + $searchRows[$contactID]['city'] = $result->city; + $searchRows[$contactID]['state'] = $result->state_province; + $searchRows[$contactID]['email'] = $result->email; + $searchRows[$contactID]['phone'] = $result->phone; + + $contact_type = 'get('searchRows'); + $searchCount = $this->get('searchCount'); + if ($searchRows) { + $checkBoxes = array(); + $chekFlag = 0; + foreach ($searchRows as $id => $row) { + if (!$chekFlag) { + $chekFlag = $id; + } + + $checkBoxes[$id] = $this->createElement('radio', NULL, NULL, NULL, $id); + } + + $this->addGroup($checkBoxes, 'contact_check'); + if ($chekFlag) { + $checkBoxes[$chekFlag]->setChecked(TRUE); + } + $this->assign('searchRows', $searchRows); + } + + + $this->assign('searchCount', $searchCount); + $this->assign('searchDone', $this->get('searchDone')); + $this->assign('contact_type_display', ts('Organization')); + $this->addElement('submit', $this->getButtonName('refresh'), ts('Search'), array('class' => 'form-submit')); + $this->addElement('submit', $this->getButtonName('cancel'), ts('Cancel'), array('class' => 'form-submit')); + + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Add to Organization'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $this->set('searchDone', 0); + if (CRM_Utils_Array::value('_qf_AddToOrganization_refresh', $_POST)) { + $searchParams['contact_type'] = array('Organization' => 'Organization'); + $searchParams['rel_contact'] = $params['name']; + CRM_Contact_Form_Task_AddToHousehold::search($this, $searchParams); + $this->set('searchDone', 1); + return; + } + + $data = array(); + $data['relationship_type_id'] = $params['relationship_type_id']; + $data['is_active'] = 1; + $invalid = 0; + $valid = 0; + $duplicate = 0; + if (is_array($this->_contactIds)) { + foreach ($this->_contactIds as $value) { + $ids = array(); + $ids['contact'] = $value; + $errors = CRM_Contact_BAO_Relationship::checkValidRelationship($params, $ids, $params['contact_check']); + if ($errors) { + $invalid++; + continue; + } + + if (CRM_Contact_BAO_Relationship::checkDuplicateRelationship($params, + CRM_Utils_Array::value('contact', $ids), + // step 2 + $params['contact_check'] + )) { + $duplicate++; + continue; + } + CRM_Contact_BAO_Relationship::add($data, $ids, $params['contact_check']); + $valid++; + } + $org = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['contact_check'], 'display_name'); + list($rtype, $a_b) = explode('_', $data['relationship_type_id'], 2); + $relationship = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', $rtype, "label_$a_b"); + + $status = array(ts('%count %2 %3 relationship created', array('count' => $valid, 'plural' => '%count %2 %3 relationships created', 2 => $relationship, 3 => $org))); + if ($duplicate) { + $status[] = ts('%count was skipped because the contact is already %2 %3', array('count' => $duplicate, 'plural' => '%count were skipped because the contacts are already %2 %3', 2 => $relationship, 3 => $org)); + } + if ($invalid) { + $status[] = ts('%count relationship was not created because the contact is not of the right type for this relationship', array('count' => $invalid, 'plural' => '%count relationships were not created because the contact is not of the right type for this relationship')); + } + $status = '
    • ' . implode('
    • ', $status) . '
    '; + CRM_Core_Session::setStatus($status, ts('Relationship Created', array('count' => $valid, 'plural' => 'Relationships Created')), 'success', array('expires' => 0)); + } + } + +} diff --git a/CRM/Contact/Form/Task/AddToTag.php b/CRM/Contact/Form/Task/AddToTag.php new file mode 100644 index 0000000000..33edb9b57f --- /dev/null +++ b/CRM/Contact/Form/Task/AddToTag.php @@ -0,0 +1,154 @@ +_tags = CRM_Core_BAO_Tag::getTags(); + + foreach ($this->_tags as $tagID => $tagName) { + $this->_tagElement = &$this->addElement('checkbox', "tag[$tagID]", NULL, $tagName); + } + + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_contact'); + CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_contact'); + + $this->addDefaultButtons(ts('Tag Contacts')); + } + + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Task_AddToTag', 'formRule')); + } + + static function formRule($form, $rule) { + $errors = array(); + if (empty($form['tag']) && empty($form['contact_taglist'])) { + $errors['_qf_default'] = ts("Please select at least one tag."); + } + return $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + //get the submitted values in an array + $params = $this->controller->exportValues($this->_name); + $contactTags = $tagList = array(); + + // check if contact tags exists + if (CRM_Utils_Array::value('tag', $params)) { + $contactTags = $params['tag']; + } + + // check if tags are selected from taglists + if (CRM_Utils_Array::value('contact_taglist', $params)) { + foreach ($params['contact_taglist'] as $val) { + if ($val) { + if (is_numeric($val)) { + $tagList[$val] = 1; + } + else { + $tagIDs = explode(',', $val); + if (!empty($tagIDs)) { + foreach ($tagIDs as $tagID) { + if (is_numeric($tagID)) { + $tagList[$tagID] = 1; + } + } + } + } + } + } + } + + $tagSets = CRM_Core_BAO_Tag::getTagsUsedFor('civicrm_contact', FALSE, TRUE); + + foreach ($tagSets as $key => $value) { + $this->_tags[$key] = $value['name']; + } + + // merge contact and taglist tags + $allTags = CRM_Utils_Array::crmArrayMerge($contactTags, $tagList); + + $this->_name = array(); + foreach ($allTags as $key => $dnc) { + $this->_name[] = $this->_tags[$key]; + + list($total, $added, $notAdded) = CRM_Core_BAO_EntityTag::addEntitiesToTag($this->_contactIds, $key); + + $status = array(ts('%count contact tagged', array('count' => $added, 'plural' => '%count contacts tagged'))); + if ($notAdded) { + $status[] = ts('%count contact already had this tag', array('count' => $notAdded, 'plural' => '%count contacts already had this tag')); + } + $status = '
    • ' . implode('
    • ', $status) . '
    '; + CRM_Core_Session::setStatus($status, ts("Added Tag %1", array(1 => $this->_tags[$key])), 'success', array('expires' => 0)); + } + + } + //end of function +} + diff --git a/CRM/Contact/Form/Task/AlterPreferences.php b/CRM/Contact/Form/Task/AlterPreferences.php new file mode 100644 index 0000000000..682314fd8f --- /dev/null +++ b/CRM/Contact/Form/Task/AlterPreferences.php @@ -0,0 +1,141 @@ + +addRadio('actionTypeOption', ts('actionTypeOption'), $options); + + $privacyOptions = CRM_Core_SelectValues::privacy(); + + foreach ($privacyOptions as $prefID => $prefName) { + $this->_prefElement = &$this->addElement('checkbox', "pref[$prefID]", NULL, $prefName); + } + + $this->addDefaultButtons(ts('Set Privacy Options')); + } + + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Task_AlterPreferences', 'formRule')); + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + $defaults = array(); + + $defaults['actionTypeOption'] = 0; + return $defaults; + } + + static function formRule($form, $rule) { + $errors = array(); + if (empty($form['pref']) && empty($form['contact_taglist'])) { + $errors['_qf_default'] = ts("Please select at least one privacy option."); + } + return $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + //get the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $actionTypeOption = CRM_Utils_Array::value('actionTypeOption', $params, NULL); + // If remove option has been selected set new privacy value to "false" + $privacyValueNew = empty($actionTypeOption); + + // check if any privay option has been checked + if (!empty($params['pref'])) { + $privacyValues = $params['pref']; + $count = 0; + foreach($this->_contactIds as $contact_id) { + $contact = new CRM_Contact_BAO_Contact(); + $contact->id = $contact_id; + + foreach($privacyValues as $privacy_key => $privacy_value) { + $contact->$privacy_key = $privacyValueNew; + } + $contact->save(); + $count++; + } + // Status message + $privacyOptions = CRM_Core_SelectValues::privacy(); + $status = array(); + foreach($privacyValues as $privacy_key => $privacy_value) { + $label = $privacyOptions[$privacy_key]; + $status[] = $privacyValueNew ? ts("Added '%1'", array(1 => $label)) : ts("Removed '%1'", array(1 => $label)); + } + + $status = '
    • ' . implode('
    • ', $status) . '
    '; + if ($count > 1) { + $title = ts('%1 Contacts Updated', array(1 => $count)); + } + else { + $name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contact_id, 'display_name'); + $title = ts('%1 Updated', array(1 => $name)); + } + + CRM_Core_Session::setStatus($status, $title, 'success'); + } + } +} diff --git a/CRM/Contact/Form/Task/Batch.php b/CRM/Contact/Form/Task/Batch.php new file mode 100644 index 0000000000..98deb93f52 --- /dev/null +++ b/CRM/Contact/Form/Task/Batch.php @@ -0,0 +1,329 @@ +get('ufGroupId'); + + if (!$ufGroupId) { + CRM_Core_Error::fatal('ufGroupId is missing'); + } + $this->_title = ts('Batch Update') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId); + CRM_Utils_System::setTitle($this->_title); + + $this->addDefaultButtons(ts('Save')); + $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW); + + // remove file type field and then limit fields + $suppressFields = FALSE; + $removehtmlTypes = array('File', 'Autocomplete-Select'); + foreach ($this->_fields as $name => $field) { + if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) && + in_array($this->_fields[$name]['html_type'], $removehtmlTypes) + ) { + $suppressFields = TRUE; + unset($this->_fields[$name]); + } + } + + //FIX ME: phone ext field is added at the end and it gets removed because of below code + //$this->_fields = array_slice($this->_fields, 0, $this->_maxFields); + + $this->addButtons(array( + array( + 'type' => 'submit', + 'name' => ts('Update Contact(s)'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + + $this->assign('profileTitle', $this->_title); + $this->assign('componentIds', $this->_contactIds); + + // if below fields are missing we should not reset sort name / display name + // CRM-6794 + $preserveDefaultsArray = array( + 'first_name', 'last_name', 'middle_name', + 'organization_name', + 'household_name', + ); + + foreach ($this->_contactIds as $contactId) { + $profileFields = $this->_fields; + CRM_Core_BAO_Address::checkContactSharedAddressFields($profileFields, $contactId); + foreach ($profileFields as $name => $field) { + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contactId); + + if (in_array($field['name'], $preserveDefaultsArray)) { + $this->_preserveDefault = FALSE; + } + } + } + + $this->assign('fields', $this->_fields); + + // don't set the status message when form is submitted. + $buttonName = $this->controller->getButtonName('submit'); + + if ($suppressFields && $buttonName != '_qf_BatchUpdateProfile_next') { + CRM_Core_Session::setStatus(ts("File or Autocomplete Select type field(s) in the selected profile are not supported for Batch Update and have been excluded."), ts('Some Fields Excluded'), 'info'); + } + + $this->addDefaultButtons(ts('Update Contacts')); + $this->addFormRule(array('CRM_Contact_Form_Task_Batch', 'formRule')); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if (empty($this->_fields)) { + return; + } + + $defaults = $sortName = array(); + foreach ($this->_contactIds as $contactId) { + $details[$contactId] = array(); + + //build sortname + $sortName[$contactId] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $contactId, + 'sort_name' + ); + + CRM_Core_BAO_UFGroup::setProfileDefaults($contactId, $this->_fields, $defaults, FALSE); + } + + $this->assign('sortName', $sortName); + + return $defaults; + } + + /** + * global form rule + * + * @param array $fields the input form values + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields) { + $errors = array(); + $externalIdentifiers = array(); + foreach ($fields['field'] as $componentId => $field) { + foreach ($field as $fieldName => $fieldValue) { + if ($fieldName == 'external_identifier') { + if (in_array($fieldValue, $externalIdentifiers)) { + $errors["field[$componentId][external_identifier]"] = ts('Duplicate value for External Identifier.'); + } + else { + $externalIdentifiers[$componentId] = $fieldValue; + } + } + } + } + + return $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->exportValues(); + + $ufGroupId = $this->get('ufGroupId'); + $notify = NULL; + $inValidSubtypeCnt = 0; + //send profile notification email if 'notify' field is set + $notify = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $ufGroupId, 'notify'); + foreach ($params['field'] as $key => $value) { + + //CRM-5521 + //validate subtype before updating + if (CRM_Utils_Array::value('contact_sub_type', $value) && !CRM_Contact_BAO_ContactType::isAllowEdit($key)) { + unset($value['contact_sub_type']); + $inValidSubtypeCnt++; + } + + $value['preserveDBName'] = $this->_preserveDefault; + + //parse street address, CRM-7768 + self::parseStreetAddress($value, $this); + + CRM_Contact_BAO_Contact::createProfileContact($value, $this->_fields, $key, NULL, $ufGroupId); + if ($notify) { + $values = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($ufGroupId, $key, NULL); + CRM_Core_BAO_UFGroup::commonSendMail($key, $values); + } + } + + CRM_Core_Session::setStatus('', ts("Updates Saved"), 'success'); + if ($inValidSubtypeCnt) { + CRM_Core_Session::setStatus(ts('Contact SubType field of 1 contact has not been updated.', array('plural' => 'Contact SubType field of %count contacts has not been updated.', 'count' => $inValidSubtypeCnt)), ts('Invalid Subtype')); + } + } + //end of function + + function parseStreetAddress(&$contactValues, &$form) { + if (!is_array($contactValues) || + !is_array($form->_fields) + ) { + return; + } + + static $parseAddress; + $addressFldKey = 'street_address'; + if (!isset($parseAddress)) { + $parseAddress = FALSE; + foreach ($form->_fields as $key => $fld) { + if (strpos($key, $addressFldKey) !== FALSE) { + $parseAddress = CRM_Utils_Array::value('street_address_parsing', + CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options' + ), + FALSE + ); + break; + } + } + } + + if (!$parseAddress) { + return; + } + + $allParseValues = array(); + foreach ($contactValues as $key => $value) { + if (strpos($key, $addressFldKey) !== FALSE) { + $locTypeId = substr($key, strlen($addressFldKey) + 1); + + // parse address field. + $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($value); + + //street address consider to be parsed properly, + //If we get street_name and street_number. + if (!CRM_Utils_Array::value('street_name', $parsedFields) || + !CRM_Utils_Array::value('street_number', $parsedFields) + ) { + $parsedFields = array_fill_keys(array_keys($parsedFields), ''); + } + + //merge parse values. + foreach ($parsedFields as $fldKey => $parseVal) { + if ($locTypeId) { + $fldKey .= "-{$locTypeId}"; + } + $allParseValues[$fldKey] = $parseVal; + } + } + } + + //finally merge all parse values + if (!empty($allParseValues)) { + $contactValues += $allParseValues; + } + } +} + diff --git a/CRM/Contact/Form/Task/Delete.php b/CRM/Contact/Form/Task/Delete.php new file mode 100644 index 0000000000..7e9451d7f3 --- /dev/null +++ b/CRM/Contact/Form/Task/Delete.php @@ -0,0 +1,270 @@ +_searchKey = CRM_Utils_Request::retrieve('key', 'String', $this); + + // sort out whether it’s a delete-to-trash, delete-into-oblivion or restore (and let the template know) + $values = $this->controller->exportValues(); + $this->_skipUndelete = (CRM_Core_Permission::check('access deleted contacts') and (CRM_Utils_Request::retrieve('skip_undelete', 'Boolean', $this) or CRM_Utils_Array::value('task', $values) == CRM_Contact_Task::DELETE_PERMANENTLY)); + $this->_restore = (CRM_Utils_Request::retrieve('restore', 'Boolean', $this) or CRM_Utils_Array::value('task', $values) == CRM_Contact_Task::RESTORE); + + if ($this->_restore && !CRM_Core_Permission::check('access deleted contacts')) { + CRM_Core_Error::fatal(ts('You do not have permission to access this contact.')); + } + elseif (!CRM_Core_Permission::check('delete contacts')) { + CRM_Core_Error::fatal(ts('You do not have permission to delete this contact.')); + } + + $this->assign('trash', CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_undelete', NULL) and !$this->_skipUndelete); + $this->assign('restore', $this->_restore); + + if ($this->_restore) { + CRM_Utils_System::setTitle(ts('Restore Contact')); + } + + if ($cid) { + if (!CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT)) { + CRM_Core_Error::fatal(ts('You do not have permission to delete this contact. Note: you can delete contacts if you can edit them.')); + } elseif (CRM_Contact_BAO_Contact::checkDomainContact($cid)) { + CRM_Core_Error::fatal(ts('This contact is a special one for the contact information associated with the CiviCRM installation for this domain. No one is allowed to delete it because the information is used for special system purposes.')); + } + + $this->_contactIds = array($cid); + $this->_single = TRUE; + $this->assign('totalSelectedContacts', 1); + } + else { + parent::preProcess(); + } + + $this->_sharedAddressMessage = $this->get('sharedAddressMessage'); + if (!$this->_restore && !$this->_sharedAddressMessage) { + // we check for each contact for shared contact address + $sharedContactList = array(); + $sharedAddressCount = 0; + foreach ($this->_contactIds as $contactId) { + // check if a contact that is being deleted has any shared addresses + $sharedAddressMessage = CRM_Core_BAO_Address::setSharedAddressDeleteStatus(NULL, $contactId, TRUE); + + if ($sharedAddressMessage['count'] > 0) { + $sharedAddressCount += $sharedAddressMessage['count']; + $sharedContactList = array_merge($sharedContactList, + $sharedAddressMessage['contactList'] + ); + } + } + + $this->_sharedAddressMessage = array( + 'count' => $sharedAddressCount, + 'contactList' => $sharedContactList, + ); + + if ($sharedAddressCount > 0) { + if (count($this->_contactIds) > 1) { + // more than one contact deleted + $message = ts('One of the selected contacts has an address record that is shared with 1 other contact.', array('plural' => 'One or more selected contacts have address records which are shared with %count other contacts.', 'count' => $sharedAddressCount)); + } + else { + // only one contact deleted + $message = ts('This contact has an address record which is shared with 1 other contact.', array('plural' => 'This contact has an address record which is shared with %count other contacts.', 'count' => $sharedAddressCount)); + } + CRM_Core_Session::setStatus($message . ' ' . ts('Shared addresses will not be removed or altered but will no longer be shared.'), ts('Shared Addesses Owner')); + } + + // set in form controller so that queries are not fired again + $this->set('sharedAddressMessage', $this->_sharedAddressMessage); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $label = $this->_restore ? ts('Restore Contact(s)') : ts('Delete Contact(s)'); + + if ($this->_single) { + // also fix the user context stack in case the user hits cancel + $context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'basic'); + if ($context == 'search' && CRM_Utils_Rule::qfKey($this->_searchKey)) { + $urlParams = "&context=$context&key=$this->_searchKey"; + } + else { + $urlParams = ''; + } + + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', + 'reset=1&cid=' . $this->_contactIds[0] . $urlParams + )); + $this->addDefaultButtons($label, 'done', 'cancel'); + } + else { + $this->addDefaultButtons($label, 'done'); + } + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $session = CRM_Core_Session::singleton(); + $currentUserId = $session->get('userID'); + + $context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'basic'); + $urlParams = 'force=1'; + $urlString = "civicrm/contact/search/$context"; + + if (CRM_Utils_Rule::qfKey($this->_searchKey)) { + $urlParams .= "&qfKey=$this->_searchKey"; + } + elseif ($context == 'search') { + $urlParams .= "&qfKey={$this->controller->_key}"; + $urlString = 'civicrm/contact/search'; + } + elseif ($context == 'smog') { + $urlParams .= "&qfKey={$this->controller->_key}&context=smog"; + $urlString = 'civicrm/group/search'; + } + else { + $urlParams = "reset=1"; + $urlString = 'civicrm/dashboard'; + } + + // Delete/Restore Contacts. Report errors. + $deleted = 0; + $not_deleted = array(); + foreach ($this->_contactIds as $cid) { + $name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'); + if (CRM_Contact_BAO_Contact::checkDomainContact($cid)) { + $session->setStatus(ts("'%1' cannot be deleted because the information is used for special system purposes.", array(1 => $name)), 'Cannot Delete Domain Contact', 'error'); + continue; + } + if ($currentUserId == $cid && !$this->_restore) { + $session->setStatus(ts("You are currently logged in as '%1'. You cannot delete yourself.", array(1 => $name)), 'Unable To Delete', 'error'); + continue; + } + if (CRM_Contact_BAO_Contact::deleteContact($cid, $this->_restore, $this->_skipUndelete)) { + $deleted++; + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$cid"); + $not_deleted[$cid] = "$name"; + } + } + if ($deleted) { + $title = ts('Deleted'); + if ($this->_restore) { + $title = ts('Restored'); + $status = ts('%1 has been restored from the trash.', array(1 => $name, 'plural' => '%count contacts restored from trash.', 'count' => $deleted)); + } + elseif ($this->_skipUndelete) { + $status = ts('%1 has been permanently deleted.', array(1 => $name, 'plural' => '%count contacts permanently deleted.', 'count' => $deleted)); + } + else { + $status = ts('%1 has been moved to the trash.', array(1 => $name, 'plural' => '%count contacts moved to trash.', 'count' => $deleted)); + } + $session->setStatus($status, $title, 'success'); + } + // Alert user of any failures + if ($not_deleted) { + $status = ts('The contact might be the Membership Organization of a Membership Type. You will need to edit the Membership Type and change the Membership Organization before you can delete this contact.'); + $title = ts('Unable to Delete'); + $session->setStatus('
    • ' . implode('
    • ', $not_deleted) . '
    ' . $status, $title, 'error'); + } + + if (isset($this->_sharedAddressMessage) && $this->_sharedAddressMessage['count'] > 0 && !$this->_restore) { + if (count($this->_sharedAddressMessage['contactList']) == 1) { + $message = ts('The following contact had been sharing an address with a contact you just deleted. Their address will no longer be shared, but has not been removed or altered.'); + } + else { + $message = ts('The following contacts had been sharing addresses with a contact you just deleted. Their addressses will no longer be shared, but have not been removed or altered.'); + } + $message .= '
    • ' . implode('
    • ', $this->_sharedAddressMessage['contactList']) . '
    '; + + $session->setStatus($message, ts('Shared Addesses Owner Deleted'), 'info', array('expires' => 0)); + + $this->set('sharedAddressMessage', NULL); + } + + if ($this->_single && empty($this->_skipUndelete)) { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactIds[0]}")); + } + else { + $session->replaceUserContext(CRM_Utils_System::url($urlString, $urlParams)); + } + } + //end of function +} + diff --git a/CRM/Contact/Form/Task/Email.php b/CRM/Contact/Form/Task/Email.php new file mode 100644 index 0000000000..464cd9a8ea --- /dev/null +++ b/CRM/Contact/Form/Task/Email.php @@ -0,0 +1,123 @@ +_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this, FALSE); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE); + if ($cid) { + CRM_Contact_Page_View::setTitle($cid); + } + + CRM_Contact_Form_Task_EmailCommon::preProcessFromAddress($this); + + if (!$cid && $this->_context != 'standalone') { + parent::preProcess(); + } + + //early prevent, CRM-6209 + if (count($this->_contactIds) > CRM_Contact_Form_Task_EmailCommon::MAX_EMAILS_KILL_SWITCH) { + CRM_Core_Error::statusBounce(ts('Please do not use this task to send a lot of emails (greater than %1). We recommend using CiviMail instead.', array(1 => CRM_Contact_Form_Task_EmailCommon::MAX_EMAILS_KILL_SWITCH))); + } + + $this->assign('single', $this->_single); + if (CRM_Core_Permission::check('administer CiviCRM')) { + $this->assign('isAdmin', 1); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('suppressForm', FALSE); + $this->assign('emailTask', TRUE); + + CRM_Contact_Form_Task_EmailCommon::buildQuickForm($this); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Contact_Form_Task_EmailCommon::postProcess($this); + } +} + diff --git a/CRM/Contact/Form/Task/EmailCommon.php b/CRM/Contact/Form/Task/EmailCommon.php new file mode 100644 index 0000000000..dcfcbc8492 --- /dev/null +++ b/CRM/Contact/Form/Task/EmailCommon.php @@ -0,0 +1,432 @@ +_single = FALSE; + $className = CRM_Utils_System::getClassName($form); + if (property_exists($form, '_context') && + $form->_context != 'search' && + $className == 'CRM_Contact_Form_Task_Email' + ) { + $form->_single = TRUE; + } + + $form->_emails = $emails = array(); + + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + + $form->_contactIds = array($contactID); + $contactEmails = CRM_Core_BAO_Email::allEmails($contactID); + + $form->_onHold = array(); + + $fromDisplayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $contactID, 'display_name' + ); + + foreach ($contactEmails as $emailId => $item) { + $email = $item['email']; + if (!$email && + (count($emails) <= 1) + ) { + $emails[$emailId] = '"' . $fromDisplayName . '"'; + $form->_noEmails = TRUE; + } + else { + if ($email) { + if (in_array($email, $emails)) { + // CRM-3624 + continue; + } + + $emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> '; + $form->_onHold[$emailId] = $item['on_hold']; + } + } + + $form->_emails[$emailId] = $emails[$emailId]; + + $emails[$emailId] .= $item['locationType']; + + if ($item['is_primary']) { + $emails[$emailId] .= ' ' . ts('(preferred)'); + } + $emails[$emailId] = htmlspecialchars($emails[$emailId]); + } + + $form->assign('noEmails', $form->_noEmails); + + if ($form->_noEmails) { + CRM_Core_Error::statusBounce(ts('Your user record does not have a valid email address')); + } + + // now add domain from addresses + $domainEmails = array(); + $domainFrom = CRM_Core_PseudoConstant::fromEmailAddress(); + foreach (array_keys($domainFrom) as $k) { + $domainEmail = $domainFrom[$k]; + $domainEmails[$domainEmail] = htmlspecialchars($domainEmail); + $form->_emails[$domainEmail] = $domainEmail; + } + + $form->_fromEmails = CRM_Utils_Array::crmArrayMerge($emails, $domainEmails); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + static function buildQuickForm(&$form) { + $toArray = $ccArray = $bccArray = array(); + $suppressedEmails = 0; + //here we are getting logged in user id as array but we need target contact id. CRM-5988 + $cid = $form->get('cid'); + if ($cid) { + $form->_contactIds = array($cid); + } + + $to = $form->add('text', 'to', ts('To'), '', TRUE); + $cc = $form->add('text', 'cc_id', ts('CC')); + $bcc = $form->add('text', 'bcc_id', ts('BCC')); + + $elements = array('cc', 'bcc'); + foreach ($elements as $element) { + if ($$element->getValue()) { + preg_match_all('!"(.*?)"\s+<\s*(.*?)\s*>!', $$element->getValue(), $matches); + $elementValues = array(); + for ($i = 0; $i < count($matches[0]); $i++) { + $name = '"' . $matches[1][$i] . '" <' . $matches[2][$i] . '>'; + $elementValues[] = array( + 'name' => $name, + 'id' => $matches[0][$i], + ); + } + + $var = "{$element}Contact"; + $form->assign($var, json_encode($elementValues)); + } + } + + $toSetDefault = TRUE; + if (property_exists($form, '_context') && $form->_context == 'standalone') { + $toSetDefault = FALSE; + } + // when form is submitted recompute contactIds + $allToEmails = array(); + if ($to->getValue()) { + $allToEmails = explode(',', $to->getValue()); + $form->_contactIds = array(); + foreach ($allToEmails as $value) { + list($contactId, $email) = explode('::', $value); + if ($contactId) { + $form->_contactIds[] = $contactId; + $form->_toContactEmails[] = $email; + } + } + $toSetDefault = TRUE; + } + + //get the group of contacts as per selected by user in case of Find Activities + if (!empty($form->_activityHolderIds)) { + $contact = $form->get('contacts'); + $form->_contactIds = $contact; + } + + if (is_array($form->_contactIds) && $toSetDefault) { + $returnProperties = array( + 'sort_name' => 1, + 'email' => 1, + 'do_not_email' => 1, + 'is_deceased' => 1, + 'on_hold' => 1, + 'display_name' => 1, + 'preferred_mail_format' => 1, + ); + + list($form->_contactDetails) = CRM_Utils_Token::getTokenDetails($form->_contactIds, + $returnProperties, + FALSE, + FALSE + ); + + // make a copy of all contact details + $form->_allContactDetails = $form->_contactDetails; + + foreach ($form->_contactIds as $key => $contactId) { + $value = $form->_contactDetails[$contactId]; + if ($value['do_not_email'] || empty($value['email']) || CRM_Utils_Array::value('is_deceased', $value) || $value['on_hold']) { + $suppressedEmails++; + + // unset contact details for contacts that we won't be sending email. This is prevent extra computation + // during token evaluation etc. + unset($form->_contactDetails[$contactId]); + } + else { + if (empty($form->_toContactEmails)) { + $email = $value['email']; + } + else { + $email = $form->_toContactEmails[$key]; + } + $toArray[] = array( + 'name' => '"' . $value['sort_name'] . '" <' . $email . '>', + 'id' => "$contactId::{$email}", + ); + } + } + + if (empty($toArray)) { + CRM_Core_Error::statusBounce(ts('Selected contact(s) do not have a valid email address, or communication preferences specify DO NOT EMAIL, or they are deceased or Primary email address is On Hold.')); + } + } + + $form->assign('toContact', json_encode($toArray)); + $form->assign('suppressedEmails', $suppressedEmails); + + $form->assign('totalSelectedContacts', count($form->_contactIds)); + + $form->add('text', 'subject', ts('Subject'), 'size=50 maxlength=254', TRUE); + + $form->add('select', 'fromEmailAddress', ts('From'), $form->_fromEmails, TRUE); + + CRM_Mailing_BAO_Mailing::commonCompose($form); + + // add attachments + CRM_Core_BAO_File::buildAttachment($form, NULL); + + if ($form->_single) { + // also fix the user context stack + if ($form->_caseId) { + $ccid = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseContact', $form->_caseId, + 'contact_id', 'case_id' + ); + $url = CRM_Utils_System::url('civicrm/contact/view/case', + "&reset=1&action=view&cid={$ccid}&id={$form->_caseId}" + ); + } + elseif ($form->_context) { + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view', + "&show=1&action=browse&cid={$form->_contactIds[0]}&selectedChild=activity" + ); + } + + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext($url); + $form->addDefaultButtons(ts('Send Email'), 'upload', 'cancel'); + } + else { + $form->addDefaultButtons(ts('Send Email'), 'upload'); + } + + $form->addFormRule(array('CRM_Contact_Form_Task_EmailCommon', 'formRule'), $form); + } + + /** + * form rule + * + * @param array $fields the input form values + * @param array $dontCare + * @param array $self additional values form 'this' + * + * @return true if no errors, else array of errors + * @access public + * + */ + static function formRule($fields, $dontCare, $self) { + $errors = array(); + $template = CRM_Core_Smarty::singleton(); + + if (isset($fields['html_message'])) { + $htmlMessage = str_replace(array("\n", "\r"), ' ', $fields['html_message']); + $htmlMessage = str_replace('"', '\"', $htmlMessage); + $template->assign('htmlContent', $htmlMessage); + } + + //Added for CRM-1393 + if (CRM_Utils_Array::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) { + $errors['saveTemplateName'] = ts("Enter name to save message template"); + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + static function postProcess(&$form) { + if (count($form->_contactIds) > self::MAX_EMAILS_KILL_SWITCH) { + CRM_Core_Error::fatal(ts('Please do not use this task to send a lot of emails (greater than %1). We recommend using CiviMail instead.', + array(1 => self::MAX_EMAILS_KILL_SWITCH) + )); + } + + // check and ensure that + $formValues = $form->controller->exportValues($form->getName()); + + $fromEmail = $formValues['fromEmailAddress']; + $from = CRM_Utils_Array::value($fromEmail, $form->_emails); + $cc = CRM_Utils_Array::value('cc_id', $formValues); + $bcc = CRM_Utils_Array::value('bcc_id', $formValues); + $subject = $formValues['subject']; + + // CRM-5916: prepend case id hash to CiviCase-originating emails’ subjects + if (isset($form->_caseId) && is_numeric($form->_caseId)) { + $hash = substr(sha1(CIVICRM_SITE_KEY . $form->_caseId), 0, 7); + $subject = "[case #$hash] $subject"; + } + + // process message template + if (CRM_Utils_Array::value('saveTemplate', $formValues) + || CRM_Utils_Array::value('updateTemplate', $formValues) + ) { + $messageTemplate = array( + 'msg_text' => $formValues['text_message'], + 'msg_html' => $formValues['html_message'], + 'msg_subject' => $formValues['subject'], + 'is_active' => TRUE, + ); + + if (CRM_Utils_Array::value('saveTemplate', $formValues)) { + $messageTemplate['msg_title'] = $formValues['saveTemplateName']; + CRM_Core_BAO_MessageTemplates::add($messageTemplate); + } + + if (CRM_Utils_Array::value('template', $formValues) && + CRM_Utils_Array::value('updateTemplate', $formValues) + ) { + $messageTemplate['id'] = $formValues['template']; + unset($messageTemplate['msg_title']); + CRM_Core_BAO_MessageTemplates::add($messageTemplate); + } + } + + $attachments = array(); + CRM_Core_BAO_File::formatAttachment($formValues, + $attachments, + NULL, NULL + ); + + // format contact details array to handle multiple emails from same contact + $formattedContactDetails = array(); + $tempEmails = array(); + + foreach ($form->_contactIds as $key => $contactId) { + // if we dont have details on this contactID, we should ignore + // potentially this is due to the contact not wanting to receive email + if (!isset($form->_contactDetails[$contactId])) { + continue; + } + $email = $form->_toContactEmails[$key]; + // prevent duplicate emails if same email address is selected CRM-4067 + // we should allow same emails for different contacts + $emailKey = "{$contactId}::{$email}"; + if (!in_array($emailKey, $tempEmails)) { + $tempEmails[] = $emailKey; + $details = $form->_contactDetails[$contactId]; + $details['email'] = $email; + unset($details['email_id']); + $formattedContactDetails[] = $details; + } + } + + // send the mail + list($sent, $activityId) = CRM_Activity_BAO_Activity::sendEmail( + $formattedContactDetails, + $subject, + $formValues['text_message'], + $formValues['html_message'], + NULL, + NULL, + $from, + $attachments, + $cc, + $bcc, + array_keys($form->_contactDetails) + ); + + if ($sent) { + $count_success = count($form->_contactDetails); + CRM_Core_Session::setStatus(ts('One message was sent successfully.', array('plural' => '%count messages were sent successfully.', 'count' => $count_success)), ts('Message Sent', array('plural' => 'Messages Sent', 'count' => $count_success)), 'success'); + } + + //Display the name and number of contacts for those email is not sent. + $emailsNotSent = array_diff_assoc($form->_allContactDetails, $form->_contactDetails); + + if ($emailsNotSent) { + $not_sent = array(); + foreach ($emailsNotSent as $contactId => $values) { + $displayName = $values['display_name']; + $email = $values['email']; + $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$contactId"); + $not_sent[] = "$displayName" . ($values['on_hold'] ? '(' . ts('on hold') . ')' : ''); + } + $status = '(' . ts('because no email address on file or communication preferences specify DO NOT EMAIL or Contact is deceased or Primary email address is On Hold') . ')
    • ' . implode('
    • ', $not_sent) . '
    '; + CRM_Core_Session::setStatus($status, ts('One Message Not Sent', array('count' => count($emailsNotSent), 'plural' => '%count Messages Not Sent')), 'info'); + } + + if (isset($form->_caseId) && is_numeric($form->_caseId)) { + // if case-id is found in the url, create case activity record + $caseParams = array( + 'activity_id' => $activityId, + 'case_id' => $form->_caseId, + ); + CRM_Case_BAO_Case::processCaseActivity($caseParams); + } + } + //end of function +} diff --git a/CRM/Contact/Form/Task/HookSample.php b/CRM/Contact/Form/Task/HookSample.php new file mode 100644 index 0000000000..c26447d239 --- /dev/null +++ b/CRM/Contact/Form/Task/HookSample.php @@ -0,0 +1,96 @@ +_contactIds);; + $query = " +SELECT c.id as contact_id, c.display_name as name, + c.contact_type as contact_type, e.email as email +FROM civicrm_contact c, civicrm_email e +WHERE e.contact_id = c.id +AND e.is_primary = 1 +AND c.id IN ( $contactIDs )"; + + + $rows = array(); + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $rows[] = array( + 'id' => $dao->contact_id, + 'name' => $dao->name, + 'contact_type' => $dao->contact_type, + 'email' => $dao->email, + ); + } + + $this->assign('rows', $rows); + } + + /** + * Build the form - it consists of + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $this->addDefaultButtons(ts('Back to Search'), 'done'); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() {} +} + diff --git a/CRM/Contact/Form/Task/Label.php b/CRM/Contact/Form/Task/Label.php new file mode 100644 index 0000000000..6af5e9379d --- /dev/null +++ b/CRM/Contact/Form/Task/Label.php @@ -0,0 +1,496 @@ +set('contactIds', $this->_contactIds); + parent::preProcess(); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + CRM_Utils_System::setTitle(ts('Make Mailing Labels')); + + //add select for label + $label = CRM_Core_BAO_LabelFormat::getList(TRUE); + + $this->add('select', 'label_name', ts('Select Label'), array('' => ts('- select label -')) + $label, TRUE); + + + // add select for Location Type + $this->addElement('select', 'location_type_id', ts('Select Location'), + array( + '' => ts('Primary')) + CRM_Core_PseudoConstant::locationType(), TRUE + ); + + // checkbox for SKIP contacts with Do Not Mail privacy option + $this->addElement('checkbox', 'do_not_mail', ts('Do not print labels for contacts with "Do Not Mail" privacy option checked')); + + $this->add('checkbox', 'merge_same_address', ts('Merge labels for contacts with the same address'), NULL); + $this->add('checkbox', 'merge_same_household', ts('Merge labels for contacts belonging to the same household'), NULL); + + $this->addDefaultButtons(ts('Make Mailing Labels')); + } + + /** + * This function sets the default values for the form. + * + * @param null + * + * @return array array of default values + * @access public + */ + function setDefaultValues() { + $defaults = array(); + $format = CRM_Core_BAO_LabelFormat::getDefaultValues(); + $defaults['label_name'] = CRM_Utils_Array::value('name', $format); + $defaults['do_not_mail'] = 1; + + return $defaults; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + $fv = $this->controller->exportValues($this->_name); + $config = CRM_Core_Config::singleton(); + $locName = NULL; + //get the address format sequence from the config file + $mailingFormat = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'mailing_format' + ); + + $sequence = CRM_Utils_Address::sequence($mailingFormat); + + foreach ($sequence as $v) { + $address[$v] = 1; + } + + if (array_key_exists('postal_code', $address)) { + $address['postal_code_suffix'] = 1; + } + + //build the returnproperties + $returnProperties = array('display_name' => 1, 'contact_type' => 1); + $mailingFormat = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'mailing_format' + ); + + $mailingFormatProperties = array(); + if ($mailingFormat) { + $mailingFormatProperties = self::getReturnProperties($mailingFormat); + $returnProperties = array_merge($returnProperties, $mailingFormatProperties); + } + //we should not consider addressee for data exists, CRM-6025 + if (array_key_exists('addressee', $mailingFormatProperties)) { + unset($mailingFormatProperties['addressee']); + } + + $customFormatProperties = array(); + if (stristr($mailingFormat, 'custom_')) { + foreach ($mailingFormatProperties as $token => $true) { + if (substr($token, 0, 7) == 'custom_') { + if (!CRM_Utils_Array::value($token, $customFormatProperties)) { + $customFormatProperties[$token] = $mailingFormatProperties[$token]; + } + } + } + } + + if (!empty($customFormatProperties)) { + $returnProperties = array_merge($returnProperties, $customFormatProperties); + } + + if (isset($fv['merge_same_address'])) { + // we need first name/last name for summarising to avoid spillage + $returnProperties['first_name'] = 1; + $returnProperties['last_name'] = 1; + } + + //get the contacts information + $params = array(); + if (CRM_Utils_Array::value('location_type_id', $fv)) { + $locType = CRM_Core_PseudoConstant::locationType(); + $locName = $locType[$fv['location_type_id']]; + $location = array('location' => array("{$locName}" => $address)); + $returnProperties = array_merge($returnProperties, $location); + $params[] = array('location_type', '=', array($fv['location_type_id'] => 1), 0, 0); + } + else { + $returnProperties = array_merge($returnProperties, $address); + } + + $rows = array(); + + foreach ($this->_contactIds as $key => $contactID) { + $params[] = array( + CRM_Core_Form::CB_PREFIX . $contactID, + '=', 1, 0, 0, + ); + } + + // fix for CRM-2651 + if (CRM_Utils_Array::value('do_not_mail', $fv)) { + $params[] = array('do_not_mail', '=', 0, 0, 0); + } + // fix for CRM-2613 + $params[] = array('is_deceased', '=', 0, 0, 0); + + $custom = array(); + foreach ($returnProperties as $name => $dontCare) { + $cfID = CRM_Core_BAO_CustomField::getKeyID($name); + if ($cfID) { + $custom[] = $cfID; + } + } + + //get the total number of contacts to fetch from database. + $numberofContacts = count($this->_contactIds); + $query = new CRM_Contact_BAO_Query($params, $returnProperties); + $details = $query->apiQuery($params, $returnProperties, NULL, NULL, 0, $numberofContacts); + + $messageToken = CRM_Utils_Token::getTokens($mailingFormat); + + // also get all token values + CRM_Utils_Hook::tokenValues($details[0], + $this->_contactIds, + NULL, + $messageToken, + 'CRM_Contact_Form_Task_Label' + ); + + $tokens = array(); + CRM_Utils_Hook::tokens($tokens); + $tokenFields = array(); + foreach ($tokens as $category => $catTokens) { + foreach ($catTokens as $token => $tokenName) { + $tokenFields[] = $token; + } + } + + foreach ($this->_contactIds as $value) { + foreach ($custom as $cfID) { + if (isset($details[0][$value]["custom_{$cfID}"])) { + $details[0][$value]["custom_{$cfID}"] = CRM_Core_BAO_CustomField::getDisplayValue($details[0][$value]["custom_{$cfID}"], $cfID, $details[1]); + } + } + $contact = CRM_Utils_Array::value($value, $details['0']); + + if (is_a($contact, 'CRM_Core_Error')) { + return NULL; + } + + // we need to remove all the "_id" + unset($contact['contact_id']); + + if ($locName && CRM_Utils_Array::value($locName, $contact)) { + // If location type is not primary, $contact contains + // one more array as "$contact[$locName] = array( values... )" + + $found = FALSE; + // we should replace all the tokens that are set in mailing label format + foreach ($mailingFormatProperties as $key => $dontCare) { + if (CRM_Utils_Array::value($key, $contact)) { + $found = TRUE; + break; + } + } + + if (!$found) { + continue; + } + + unset($contact[$locName]); + + if (CRM_Utils_Array::value('county_id', $contact)) { + unset($contact['county_id']); + } + + foreach ($contact as $field => $fieldValue) { + $rows[$value][$field] = $fieldValue; + } + + $valuesothers = array(); + $paramsothers = array('contact_id' => $value); + $valuesothers = CRM_Core_BAO_Location::getValues($paramsothers, $valuesothers); + if (CRM_Utils_Array::value('location_type_id', $fv)) { + foreach ($valuesothers as $vals) { + if ( CRM_Utils_Array::value('location_type_id', $vals) == + CRM_Utils_Array::value('location_type_id', $fv ) ) { + foreach ($vals as $k => $v) { + if (in_array($k, array( + 'email', 'phone', 'im', 'openid'))) { + if ($k == 'im') { + $rows[$value][$k] = $v['1']['name']; + } + else { + $rows[$value][$k] = $v['1'][$k]; + } + $rows[$value][$k . '_id'] = $v['1']['id']; + } + } + } + } + } + } + else { + $found = FALSE; + // we should replace all the tokens that are set in mailing label format + foreach ($mailingFormatProperties as $key => $dontCare) { + if (CRM_Utils_Array::value($key, $contact)) { + $found = TRUE; + break; + } + } + + if (!$found) { + continue; + } + + if (CRM_Utils_Array::value('addressee_display', $contact)) { + $contact['addressee_display'] = trim($contact['addressee_display']); + } + if (CRM_Utils_Array::value('addressee', $contact)) { + $contact['addressee'] = $contact['addressee_display']; + } + + // now create the rows for generating mailing labels + foreach ($contact as $field => $fieldValue) { + $rows[$value][$field] = $fieldValue; + } + } + } + + $individualFormat = FALSE; + if (isset($fv['merge_same_address'])) { + $this->mergeSameAddress($rows); + $individualFormat = TRUE; + } + if (isset($fv['merge_same_household'])) { + $rows = $this->mergeSameHousehold($rows); + $individualFormat = TRUE; + } + + // format the addresses according to CIVICRM_ADDRESS_FORMAT (CRM-1327) + foreach ($rows as $id => $row) { + if ($commMethods = CRM_Utils_Array::value('preferred_communication_method', $row)) { + $val = array_filter(explode(CRM_Core_DAO::VALUE_SEPARATOR, $commMethods)); + $comm = CRM_Core_PseudoConstant::pcm(); + $temp = array(); + foreach ($val as $vals) { + $temp[] = $comm[$vals]; + } + $row['preferred_communication_method'] = implode(', ', $temp); + } + $row['id'] = $id; + $formatted = CRM_Utils_Address::format($row, 'mailing_format', FALSE, TRUE, $individualFormat, $tokenFields); + + // CRM-2211: UFPDF doesn't have bidi support; use the PECL fribidi package to fix it. + // On Ubuntu (possibly Debian?) be aware of http://pecl.php.net/bugs/bug.php?id=12366 + // Due to FriBidi peculiarities, this can't be called on + // a multi-line string, hence the explode+implode approach. + if (function_exists('fribidi_log2vis')) { + $lines = explode("\n", $formatted); + foreach ($lines as $i => $line) { + $lines[$i] = fribidi_log2vis($line, FRIBIDI_AUTO, FRIBIDI_CHARSET_UTF8); + } + $formatted = implode("\n", $lines); + } + $rows[$id] = array($formatted); + } + + //call function to create labels + self::createLabel($rows, $fv['label_name']); + CRM_Utils_System::civiExit(1); + } + + /** + * function to create labels (pdf) + * + * @param array $contactRows assciated array of contact data + * @param string $format format in which labels needs to be printed + * @param string $fileName The name of the file to save the label in + * + * @return null + * @access public + */ + function createLabel(&$contactRows, &$format, $fileName = 'MailingLabels_CiviCRM.pdf') { + $pdf = new CRM_Utils_PDF_Label($format, 'mm'); + $pdf->Open(); + $pdf->AddPage(); + + //build contact string that needs to be printed + $val = NULL; + foreach ($contactRows as $row => $value) { + foreach ($value as $k => $v) { + $val .= "$v\n"; + } + + $pdf->AddPdfLabel($val); + $val = ''; + } + $pdf->Output($fileName, 'D'); + } + + /** + * function to create the array of returnProperties + * + * @param string $format format for which return properties build + * + * @return array of returnProperties + * @access public + */ + function getReturnProperties(&$format) { + $returnProperties = array(); + $matches = array(); + preg_match_all('/(? $data) { + // copy data back to $rows + $count = 0; + // one last name list per row + foreach ($data['names'] as $last_name => $first_names) { + // too many to list + if ($count > 2) { + break; + } + // collapse the tree to summarize + $family = trim(implode(" & ", $first_names) . " " . $last_name); + if ($count) { + $processedNames .= "\n" . $family; + } + else { + // build display_name string + $processedNames = $family; + } + $count++; + } + $rows[$data['ID']]['addressee'] = $rows[$data['ID']]['addressee_display'] = $rows[$data['ID']]['display_name'] = $processedNames; + } + } + + function mergeSameHousehold(&$rows) { + # group selected contacts by type + $individuals = array(); + $households = array(); + foreach ($rows as $contact_id => $row) { + if ($row['contact_type'] == 'Household') { + $households[$contact_id] = $row; + } + elseif ($row['contact_type'] == 'Individual') { + $individuals[$contact_id] = $row; + } + } + + # exclude individuals belonging to selected households + foreach ($households as $household_id => $row) { + $dao = new CRM_Contact_DAO_Relationship(); + $dao->contact_id_b = $household_id; + $dao->find(); + while ($dao->fetch()) { + $individual_id = $dao->contact_id_a; + if (array_key_exists($individual_id, $individuals)) { + unset($individuals[$individual_id]); + } + } + } + + # merge back individuals and households + $rows = array_merge($individuals, $households); + return $rows; + } +} + diff --git a/CRM/Contact/Form/Task/Map.php b/CRM/Contact/Form/Task/Map.php new file mode 100644 index 0000000000..d0b683f6e5 --- /dev/null +++ b/CRM/Contact/Form/Task/Map.php @@ -0,0 +1,245 @@ +assign('profileGID', $profileGID); + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + + $type = 'Contact'; + if ($cid) { + $ids = array($cid); + $this->_single = TRUE; + if ($profileGID) { + // this does a check and ensures that the user has permission on this profile + // CRM-11766 + $profileIDs = CRM_Profile_Page_Listings::getProfileContact($profileGID); + if (!in_array($cid, $profileIDs)) { + CRM_Core_Error::fatal(); + } + } + elseif ($context) { + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + $session = CRM_Core_Session::singleton(); + $urlString = "civicrm/contact/search/$context"; + if ($context == 'search') { + $urlString = 'civicrm/contact/search'; + } + $url = CRM_Utils_System::url($urlString, $urlParams); + $session->replaceUserContext($url); + } + } + elseif ($eid) { + $ids = $eid; + $type = 'Event'; + } + else { + if ($profileGID) { + $ids = CRM_Profile_Page_Listings::getProfileContact($profileGID); + } + else { + parent::preProcess(); + $ids = $this->_contactIds; + } + } + self::createMapXML($ids, $lid, $this, TRUE, $type); + $this->assign('single', $this->_single); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() {} + //end of function + + /** + * assign smarty variables to the template that will be used by google api to plot the contacts + * + * @param array $contactIds list of contact ids that we need to plot + * @param int $locationId location_id + * + * @return string the location of the file we have created + * @access protected + */ + static function createMapXML($ids, $locationId, &$page, $addBreadCrumb, $type = 'Contact') { + $config = CRM_Core_Config::singleton(); + + CRM_Utils_System::setTitle(ts('Map Location(s)')); + $page->assign('query', 'CiviCRM Search Query'); + $page->assign('mapProvider', $config->mapProvider); + $page->assign('mapKey', urlencode($config->mapAPIKey)); + if ($type == 'Contact') { + $imageUrlOnly = FALSE; + + // google needs image url, CRM-6564 + if ($config->mapProvider == 'Google' || $config->mapProvider == 'OpenStreetMaps') { + $imageUrlOnly = TRUE; + } + $locations = CRM_Contact_BAO_Contact_Location::getMapInfo($ids, $locationId, $imageUrlOnly); + } + else { + $locations = CRM_Event_BAO_Event::getMapInfo($ids); + } + + if (empty($locations)) { + CRM_Core_Error::statusBounce(ts('This address does not contain latitude/longitude information and cannot be mapped.')); + } + + if ($addBreadCrumb) { + $session = CRM_Core_Session::singleton(); + $redirect = $session->readUserContext(); + if ($type == 'Contact') { + $bcTitle = ts('Contact'); + } + else { + $bcTitle = ts('Event Info'); + $action = CRM_Utils_Request::retrieve('action', 'String', + $page, FALSE + ); + if ($action) { + $args = 'reset=1&action=preview&id='; + } + else { + $args = 'reset=1&id='; + } + $session->pushUserContext(CRM_Utils_System::url('civicrm/event/info', "{$args}{$ids}")); + } + CRM_Utils_System::appendBreadCrumb($bcTitle, $redirect); + } + + $page->assign_by_ref('locations', $locations); + + // only issue a javascript warning if we know we will not + // mess the poor user with too many warnings + if (count($locations) <= 3) { + $page->assign('geoCodeWarn', TRUE); + } + else { + $page->assign('geoCodeWarn', FALSE); + } + + $sumLat = $sumLng = 0; + $maxLat = $maxLng = -400; + $minLat = $minLng = + 400; + foreach ($locations as $location) { + $sumLat += $location['lat']; + $sumLng += $location['lng']; + + if ($location['lat'] > $maxLat) { + $maxLat = $location['lat']; + } + if ($location['lat'] < $minLat) { + $minLat = $location['lat']; + } + + if ($location['lng'] > $maxLng) { + $maxLng = $location['lng']; + } + if ($location['lng'] < $minLng) { + $minLng = $location['lng']; + } + } + + $center = array( + 'lat' => (float ) $sumLat / count($locations), + 'lng' => (float ) $sumLng / count($locations), + ); + $span = array( + 'lat' => (float )($maxLat - $minLat), + 'lng' => (float )($maxLng - $minLng), + ); + $page->assign_by_ref('center', $center); + $page->assign_by_ref('span', $span); + } +} + diff --git a/CRM/Contact/Form/Task/Map/Event.php b/CRM/Contact/Form/Task/Map/Event.php new file mode 100644 index 0000000000..63025f3dce --- /dev/null +++ b/CRM/Contact/Form/Task/Map/Event.php @@ -0,0 +1,66 @@ +assign('single', FALSE); + $this->assign('skipLocationType', TRUE); + } + + function getTemplateFileName() { + return 'CRM/Contact/Form/Task/Map.tpl'; + } +} + diff --git a/CRM/Contact/Form/Task/Merge.php b/CRM/Contact/Form/Task/Merge.php new file mode 100644 index 0000000000..6b79abf23d --- /dev/null +++ b/CRM/Contact/Form/Task/Merge.php @@ -0,0 +1,94 @@ +_contactIds)) { + $contactIds = array_unique($this->_contactIds); + } + if (count($contactIds) != 2) { + $statusMsg = ts('Merge operation requires selecting two contacts.'); + } + + // do check for same contact type. + $contactTypes = array(); + if (!$statusMsg) { + $sql = "SELECT contact_type FROM civicrm_contact WHERE id IN (" . implode(',', $contactIds) . ")"; + $contact = CRM_Core_DAO::executeQuery($sql); + while ($contact->fetch()) { + $contactTypes[$contact->contact_type] = TRUE; + if (count($contactTypes) > 1) + break; + } + if (count($contactTypes) > 1) { + $statusMsg = ts('Selected records must all be the same contact type (i.e. all Individuals).'); + } + } + if ($statusMsg) { + CRM_Core_Error::statusBounce($statusMsg); + } + + // redirect to merge form directly. + $cid = $contactIds[0]; + $oid = $contactIds[1]; + + //don't allow to delete logged in user. + $session = CRM_Core_Session::singleton(); + if ($oid == $session->get('userID')) { + $oid = $cid; + $cid = $session->get('userID'); + } + + $url = CRM_Utils_System::url('civicrm/contact/merge', "reset=1&cid={$cid}&oid={$oid}"); + + // redirect to merge page. + CRM_Utils_System::redirect($url); + } +} + diff --git a/CRM/Contact/Form/Task/PDF.php b/CRM/Contact/Form/Task/PDF.php new file mode 100644 index 0000000000..e72b19c4c0 --- /dev/null +++ b/CRM/Contact/Form/Task/PDF.php @@ -0,0 +1,125 @@ +skipOnHold = $this->skipDeceased = FALSE; + CRM_Contact_Form_Task_PDFLetterCommon::preProcess($this); + + // store case id if present + $this->_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this, FALSE); + + // retrieve contact ID if this is 'single' mode + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE); + + if ($cid) { + // this is true in non-search context / single mode + // in search context 'id' is the default profile id for search display + // CRM-11227 + $this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE); + } + + if ($cid) { + CRM_Contact_Form_Task_PDFLetterCommon::preProcessSingle($this, $cid); + $this->_single = TRUE; + $this->_cid = $cid; + } + else { + parent::preProcess(); + } + $this->assign('single', $this->_single); + } + + function setDefaultValues() { + $defaults = array(); + if (isset($this->_activityId)) { + $params = array('id' => $this->_activityId); + CRM_Activity_BAO_Activity::retrieve($params, $defaults); + $defaults['html_message'] = CRM_Utils_Array::value('details', $defaults); + } + $defaults = $defaults + CRM_Contact_Form_Task_PDFLetterCommon::setDefaultValues(); + return $defaults; + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('suppressForm', FALSE); + CRM_Contact_Form_Task_PDFLetterCommon::buildQuickForm($this); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Contact_Form_Task_PDFLetterCommon::postProcess($this); + } +} + diff --git a/CRM/Contact/Form/Task/PDFLetterCommon.php b/CRM/Contact/Form/Task/PDFLetterCommon.php new file mode 100644 index 0000000000..cfff10dc61 --- /dev/null +++ b/CRM/Contact/Form/Task/PDFLetterCommon.php @@ -0,0 +1,403 @@ +is_active = 1; + $dao->find(); + while ($dao->fetch()) { + $messageText[$dao->id] = $dao->msg_text; + $messageSubject[$dao->id] = $dao->msg_subject; + } + + $form->assign('message', $messageText); + $form->assign('messageSubject', $messageSubject); + } + + static function preProcessSingle(&$form, $cid) { + $form->_contactIds = array($cid); + // put contact display name in title for single contact mode + CRM_Contact_Page_View::setTitle($cid); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + static function buildQuickForm(&$form) { + $form->add('static', 'pdf_format_header', NULL, ts('Page Format')); + $form->add('select', 'format_id', ts('Select Format'), + array( + 0 => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE), FALSE, + array('onChange' => "selectFormat( this.value, false );") + ); + $form->add('select', 'paper_size', ts('Paper Size'), + array( + 0 => ts('- default -')) + CRM_Core_BAO_PaperSize::getList(TRUE), FALSE, + array('onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();") + ); + $form->add('static', 'paper_dimensions', NULL, ts('Width x Height')); + $form->add('select', 'orientation', ts('Orientation'), CRM_Core_BAO_PdfFormat::getPageOrientations(), FALSE, + array('onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();") + ); + $form->add('select', 'metric', ts('Unit of Measure'), CRM_Core_BAO_PdfFormat::getUnits(), FALSE, + array('onChange' => "selectMetric( this.value );") + ); + $form->add('text', 'margin_left', ts('Left Margin'), + array( + 'size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"), TRUE + ); + $form->add('text', 'margin_right', ts('Right Margin'), + array( + 'size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"), TRUE + ); + $form->add('text', 'margin_top', ts('Top Margin'), + array( + 'size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"), TRUE + ); + $form->add('text', 'margin_bottom', ts('Bottom Margin'), + array( + 'size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"), TRUE + ); + $form->add('checkbox', 'bind_format', ts('Always use this Page Format with the selected Template')); + $form->add('checkbox', 'update_format', ts('Update Page Format (this will affect all templates that use this format)')); + + $form->assign('useThisPageFormat', ts('Always use this Page Format with the new template?')); + $form->assign('useSelectedPageFormat', ts('Should the new template always use the selected Page Format?')); + $form->assign('totalSelectedContacts', count($form->_contactIds)); + + CRM_Mailing_BAO_Mailing::commonLetterCompose($form); + + if ($form->_single) { + $cancelURL = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&cid={$form->_cid}&selectedChild=activity", + FALSE, NULL, FALSE + ); + if ($form->get('action') == CRM_Core_Action::VIEW) { + $form->addButtons(array( + array( + 'type' => 'cancel', + 'name' => ts('Done'), + 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"), + ), + ) + ); + } + else { + $form->addButtons(array( + array( + 'type' => 'submit', + 'name' => ts('Make PDF Letter'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Done'), + 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"), + ), + ) + ); + } + } + else { + $form->addDefaultButtons(ts('Make PDF Letters')); + } + + $form->addFormRule(array('CRM_Contact_Form_Task_PDFLetterCommon', 'formRule'), $form); + } + + /** + * Set default values + */ + static function setDefaultValues() { + $defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues(); + $defaultFormat['format_id'] = $defaultFormat['id']; + return $defaultFormat; + } + + /** + * form rule + * + * @param array $fields the input form values + * @param array $dontCare + * @param array $self additional values form 'this' + * + * @return true if no errors, else array of errors + * @access public + * + */ + static function formRule($fields, $dontCare, $self) { + $errors = array(); + $template = CRM_Core_Smarty::singleton(); + + //Added for CRM-1393 + if (CRM_Utils_Array::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) { + $errors['saveTemplateName'] = ts("Enter name to save message template"); + } + if (!is_numeric($fields['margin_left'])) { + $errors['margin_left'] = 'Margin must be numeric'; + } + if (!is_numeric($fields['margin_right'])) { + $errors['margin_right'] = 'Margin must be numeric'; + } + if (!is_numeric($fields['margin_top'])) { + $errors['margin_top'] = 'Margin must be numeric'; + } + if (!is_numeric($fields['margin_bottom'])) { + $errors['margin_bottom'] = 'Margin must be numeric'; + } + return empty($errors) ? TRUE : $errors; + } + + /** + * part of the post process which prepare and extract information from the template + * + * @access protected + * + * @return array( $categories, $html_message, $messageToken, $returnProperties ) + */ + static protected function processMessageTemplate(&$form) { + $formValues = $form->controller->exportValues($form->getName()); + + // process message template + if (CRM_Utils_Array::value('saveTemplate', $formValues) || CRM_Utils_Array::value('updateTemplate', $formValues)) { + $messageTemplate = array( + 'msg_text' => NULL, + 'msg_html' => $formValues['html_message'], + 'msg_subject' => NULL, + 'is_active' => TRUE, + ); + + $messageTemplate['pdf_format_id'] = 'null'; + if (CRM_Utils_Array::value('bind_format', $formValues) && $formValues['format_id'] > 0) { + $messageTemplate['pdf_format_id'] = $formValues['format_id']; + } + if (CRM_Utils_Array::value('saveTemplate', $formValues) && $formValues['saveTemplate']) { + $messageTemplate['msg_title'] = $formValues['saveTemplateName']; + CRM_Core_BAO_MessageTemplates::add($messageTemplate); + } + + if (CRM_Utils_Array::value('updateTemplate', $formValues) && $formValues['template'] && $formValues['updateTemplate']) { + $messageTemplate['id'] = $formValues['template']; + + unset($messageTemplate['msg_title']); + CRM_Core_BAO_MessageTemplates::add($messageTemplate); + } + } + elseif (CRM_Utils_Array::value('template', $formValues) > 0) { + if (CRM_Utils_Array::value('bind_format', $formValues) && $formValues['format_id'] > 0) { + $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}"; + } + else { + $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}"; + } + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + if (CRM_Utils_Array::value('update_format', $formValues)) { + $bao = new CRM_Core_BAO_PdfFormat(); + $bao->savePdfFormat($formValues, $formValues['format_id']); + } + + $html = array(); + + $tokens = array(); + CRM_Utils_Hook::tokens($tokens); + $categories = array_keys($tokens); + + $html_message = $formValues['html_message']; + + //time being hack to strip ' ' + //from particular letter line, CRM-6798 + self::formatMessage($html_message); + + $messageToken = CRM_Utils_Token::getTokens($html_message); + + $returnProperties = array(); + if (isset($messageToken['contact'])) { + foreach ($messageToken['contact'] as $key => $value) { + $returnProperties[$value] = 1; + } + } + + return array($formValues, $categories, $html_message, $messageToken, $returnProperties); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + static function postProcess(&$form) { + list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form); + + $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE; + $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE; + + foreach ($form->_contactIds as $item => $contactId) { + $params = array('contact_id' => $contactId); + + list($contact) = CRM_Utils_Token::getTokenDetails($params, + $returnProperties, + $skipOnHold, + $skipDeceased, + NULL, + $messageToken, + 'CRM_Contact_Form_Task_PDFLetterCommon' + ); + if (civicrm_error($contact)) { + $notSent[] = $contactId; + continue; + } + + $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken); + $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE); + + if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) { + $smarty = CRM_Core_Smarty::singleton(); + // also add the contact tokens to the template + $smarty->assign_by_ref('contact', $contact); + $tokenHtml = $smarty->fetch("string:$tokenHtml"); + } + + $html[] = $tokenHtml; + } + + self::createActivities($form, $html_message, $form->_contactIds); + + CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues); + + $form->postProcessHook(); + + CRM_Utils_System::civiExit(1); + } + + function createActivities($form, $html_message, $contactIds) { + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', + 'Print PDF Letter', + 'name' + ); + $activityParams = array( + 'source_contact_id' => $userID, + 'activity_type_id' => $activityTypeID, + 'activity_date_time' => date('YmdHis'), + 'details' => $html_message, + ); + if (!empty($form->_activityId)) { + $activityParams += array('id' => $form->_activityId); + } + if ($form->_cid) { + $activity = CRM_Activity_BAO_Activity::create($activityParams); + } + else { + // create Print PDF activity for each selected contact. CRM-6886 + $activityIds = array(); + foreach ($contactIds as $contactId) { + $activityID = CRM_Activity_BAO_Activity::create($activityParams); + $activityIds[$contactId] = $activityID->id; + } + } + + foreach ($form->_contactIds as $contactId) { + $activityTargetParams = array( + 'activity_id' => empty($activity->id) ? $activityIds[$contactId] : $activity->id, + 'target_contact_id' => $contactId, + ); + CRM_Activity_BAO_Activity::createActivityTarget($activityTargetParams); + } + } + + function formatMessage(&$message) { + $newLineOperators = array( + 'p' => array( + 'oper' => '

    ', + 'pattern' => '/<(\s+)?p(\s+)?>/m', + ), + 'br' => array( + 'oper' => '
    ', + 'pattern' => '/<(\s+)?br(\s+)?\/>/m', + ), + ); + + $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message); + foreach ($htmlMsg as $k => & $m) { + $messages = preg_split($newLineOperators['br']['pattern'], $m); + foreach ($messages as $key => & $msg) { + $msg = trim($msg); + $matches = array(); + if (preg_match('/^( )+/', $msg, $matches)) { + $spaceLen = strlen($matches[0]) / 6; + $trimMsg = ltrim($msg, '  '); + $charLen = strlen($trimMsg); + $totalLen = $charLen + $spaceLen; + if ($totalLen > 100) { + $spacesCount = 10; + if ($spaceLen > 50) { + $spacesCount = 20; + } + if ($charLen > 100) { + $spacesCount = 1; + } + $msg = str_repeat(' ', $spacesCount) . $trimMsg; + } + } + } + $m = implode($newLineOperators['br']['oper'], $messages); + } + $message = implode($newLineOperators['p']['oper'], $htmlMsg); + } +} + diff --git a/CRM/Contact/Form/Task/PickProfile.php b/CRM/Contact/Form/Task/PickProfile.php new file mode 100644 index 0000000000..2b04bf264c --- /dev/null +++ b/CRM/Contact/Form/Task/PickProfile.php @@ -0,0 +1,177 @@ +_userContext = $session->readUserContext(); + + $validate = FALSE; + //validations + if (count($this->_contactIds) > $this->_maxContacts) { + CRM_Core_Session::setStatus(ts("The maximum number of contacts you can select for Batch Update is %1. You have selected %2. Please select fewer contacts from your search results and try again.", array(1 => $this->_maxContacts, 2 => count($this->_contactIds))), ts('Maximum Exceeded'), 'error'); + $validate = TRUE; + } + + if (CRM_Contact_BAO_Contact_Utils::checkContactType($this->_contactIds)) { + CRM_Core_Session::setStatus(ts("Batch update requires that all selected contacts be the same basic type (e.g. all Individuals OR all Organizations...). Please modify your selection and try again."), ts('Contact Type Mismatch'), 'error'); + $validate = TRUE; + } + + // than redirect + if ($validate) { + CRM_Utils_System::redirect($this->_userContext); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + CRM_Utils_System::setTitle(ts('Batch Profile Update for Contact')); + + foreach ($this->_contactIds as $id) { + $this->_contactTypes = CRM_Contact_BAO_Contact::getContactTypes($id); + } + + //add Contact type profiles + $this->_contactTypes[] = 'Contact'; + + $profiles = CRM_Core_BAO_UFGroup::getProfiles($this->_contactTypes); + + if (empty($profiles)) { + $types = implode(' ' . ts('or') . ' ', $this->_contactTypes); + CRM_Core_Session::setStatus(ts("The contact type selected for Batch Update does not have a corresponding profile. Please set up a profile for %1s and try again.", array(1 => $types)), ts('No Profile Available'), 'error'); + CRM_Utils_System::redirect($this->_userContext); + } + $ufGroupElement = $this->add('select', 'uf_group_id', ts('Select Profile'), array('' => ts('- select profile -')) + $profiles, TRUE); + + $this->addDefaultButtons(ts('Continue >>')); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Task_PickProfile', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + if (CRM_Core_BAO_UFField::checkProfileType($fields['uf_group_id'])) { + $errorMsg['uf_group_id'] = "You cannot select mix profile for batch update."; + } + + if (!empty($errorMsg)) { + return $errorMsg; + } + + return TRUE; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->exportValues(); + + $this->set('ufGroupId', $params['uf_group_id']); + + // also reset the batch page so it gets new values from the db + $this->controller->resetPage('Batch'); + } + //end of function +} + diff --git a/CRM/Contact/Form/Task/Print.php b/CRM/Contact/Form/Task/Print.php new file mode 100644 index 0000000000..cb3b7c89c8 --- /dev/null +++ b/CRM/Contact/Form/Task/Print.php @@ -0,0 +1,148 @@ +controller->setPrint(1); + $this->assign('id', $this->get('id')); + $this->assign('pageTitle', ts('CiviCRM Contact Listing')); + + $params = $this->get('queryParams'); + if (!empty($this->_contactIds)) { + //using _contactIds field for creating params for query so that multiple selections on multiple pages + //can be printed. + foreach ($this->_contactIds as $contactId) { + $params[] = array( + CRM_Core_Form::CB_PREFIX . $contactId, + '=', + 1, 0, 0); + } + } + + // create the selector, controller and run - store results in session + $fv = $this->get('formValues'); + $returnProperties = $this->get('returnProperties'); + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $includeContactIds = FALSE; + if ($fv['radio_ts'] == 'ts_sel') { + $includeContactIds = TRUE; + } + + $selectorName = $this->controller->selectorName(); + require_once (str_replace('_', DIRECTORY_SEPARATOR, $selectorName) . '.php'); + + $returnP = isset($returnPropeties) ? $returnPropeties : ""; + $customSearchClass = $this->get('customSearchClass'); + eval('$selector = new ' . + $selectorName . + '( $customSearchClass, + $fv, + $params, + $returnP, + $this->_action, + $includeContactIds );' + ); + $controller = new CRM_Core_Selector_Controller($selector, + NULL, + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::SCREEN + ); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + /** + * Build the form - it consists of + * - displaying the QILL (query in local language) + * - displaying elements for saving the search + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // + // just need to add a javacript to popup the window for printing + // + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Print Contact List'), + 'js' => array('onclick' => 'window.print()'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Done'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + // redirect to the main search page after printing is over + } +} + diff --git a/CRM/Contact/Form/Task/ProximityCommon.php b/CRM/Contact/Form/Task/ProximityCommon.php new file mode 100644 index 0000000000..eefe7496d1 --- /dev/null +++ b/CRM/Contact/Form/Task/ProximityCommon.php @@ -0,0 +1,177 @@ +assign('proximity_search', TRUE); + + $form->add('text', 'prox_street_address', ts('Street Address'), NULL, FALSE); + + $form->add('text', 'prox_city', ts('City'), NULL, FALSE); + + $form->add('text', 'prox_postal_code', ts('Postal Code'), NULL, FALSE); + + $defaults = self::setDefaultValues($form); + if (CRM_Utils_Array::value('prox_country_id', $defaults)) { + $stateProvince = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvinceForCountry($defaults['prox_country_id']); + } + else { + $stateProvince = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvince(); + } + $form->add('select', 'prox_state_province_id', ts('State/Province'), $stateProvince, $proxRequired); + + $country = array('' => ts('- select -')) + CRM_Core_PseudoConstant::country(); + $form->add('select', 'prox_country_id', ts('Country'), $country, $proxRequired); + + $form->add('text', 'prox_distance', ts('Distance'), NULL, $proxRequired); + + $proxUnits = array('km' => ts('km'), 'miles' => ts('miles')); + $form->add('select', 'prox_distance_unit', ts('Units'), $proxUnits, $proxRequired); + // prox_distance_unit + + // state country js, CRM-5233 + $stateCountryMap = array(); + $stateCountryMap[] = array( + 'state_province' => 'prox_state_province_id', + 'country' => 'prox_country_id', + ); + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + CRM_Core_BAO_Address::fixAllStateSelects($this, $defaults); + $form->addFormRule(array('CRM_Contact_Form_Task_ProximityCommon', 'formRule'), $form); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $form) { + $errors = array(); + // If Distance is present, make sure state, country and city or postal code are populated. + if (CRM_Utils_Array::value('prox_distance', $fields)) { + if (!CRM_Utils_Array::value('prox_state_province_id', $fields) || + !CRM_Utils_Array::value('prox_country_id', $fields) + ) { + $errors["prox_state_province_id"] = ts("Country AND State/Province are required to search by distance."); + } + if (!CRM_Utils_Array::value('prox_postal_code', $fields) AND + !CRM_Utils_Array::value('prox_city', $fields) + ) { + $errors["prox_distance"] = ts("City OR Postal Code are required to search by distance."); + } + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues($form) { + $defaults = array(); + $config = CRM_Core_Config::singleton(); + $countryDefault = $config->defaultContactCountry; + + if ($countryDefault) { + $defaults['prox_country_id'] = $countryDefault; + if ($countryDefault == '1228') { + $defaults['prox_distance_unit'] = 'miles'; + } + else { + $defaults['prox_distance_unit'] = 'km'; + } + } + $form->setDefaults($defaults); + return $defaults; + } +} + diff --git a/CRM/Contact/Form/Task/RemoveFromGroup.php b/CRM/Contact/Form/Task/RemoveFromGroup.php new file mode 100644 index 0000000000..f000e05744 --- /dev/null +++ b/CRM/Contact/Form/Task/RemoveFromGroup.php @@ -0,0 +1,97 @@ + ts('- select group -')) + CRM_Core_PseudoConstant::group(); + $groupElement = $this->add('select', 'group_id', ts('Select Group'), $group, TRUE); + + CRM_Utils_System::setTitle(ts('Remove Contacts from Group')); + $this->addDefaultButtons(ts('Remove from Group')); + } + + /** + * Set the default form values + * + * @access protected + * + * @return array the default array reference + */ + function setDefaultValues() { + $defaults = array(); + + if ($this->get('context') === 'smog') { + $defaults['group_id'] = $this->get('gid'); + } + return $defaults; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $groupId = $this->controller->exportValue('RemoveFromGroup', 'group_id'); + $group = CRM_Core_PseudoConstant::group(); + + list($total, $removed, $notRemoved) = CRM_Contact_BAO_GroupContact::removeContactsFromGroup($this->_contactIds, $groupId); + + $status = array(ts("%count contact removed from '%2'", array('count' => $removed, 'plural' => "%count contacts removed from '%2'", 2 => $group[$groupId]))); + if ($notRemoved) { + $status[] = ts('1 contact was already not in this group', array('count' => $notRemoved, 'plural' => '%count contacts were already not in this group')); + } + $status = '

    • ' . implode('
    • ', $status) . '
    '; + CRM_Core_Session::setStatus($status, ts("Removed Contact From Group", array('plural' => "Removed Contacts From Group", 'count' => $removed)), 'success', array('expires' => 0)); + } + //end of function +} + diff --git a/CRM/Contact/Form/Task/RemoveFromTag.php b/CRM/Contact/Form/Task/RemoveFromTag.php new file mode 100644 index 0000000000..054532b8ff --- /dev/null +++ b/CRM/Contact/Form/Task/RemoveFromTag.php @@ -0,0 +1,143 @@ +_tags = CRM_Core_BAO_Tag::getTags(); + foreach ($this->_tags as $tagID => $tagName) { + $this->_tagElement = &$this->addElement('checkbox', "tag[$tagID]", NULL, $tagName); + } + + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_contact'); + CRM_Core_Form_Tag::buildQuickForm($this, $parentNames, 'civicrm_contact', NULL, TRUE, FALSE, TRUE); + + $this->addDefaultButtons(ts('Remove Tags from Contacts')); + } + + function addRules() { + $this->addFormRule(array('CRM_Contact_Form_Task_RemoveFromTag', 'formRule')); + } + + static function formRule($form, $rule) { + $errors = array(); + if (empty($form['tag']) && empty($form['contact_taglist'])) { + $errors['_qf_default'] = "Please select atleast one tag."; + } + return $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + //get the submitted values in an array + $params = $this->controller->exportValues($this->_name); + + $contactTags = $tagList = array(); + + // check if contact tags exists + if (CRM_Utils_Array::value('tag', $params)) { + $contactTags = $params['tag']; + } + + // check if tags are selected from taglists + if (CRM_Utils_Array::value('contact_taglist', $params)) { + foreach ($params['contact_taglist'] as $val) { + if ($val) { + if (is_numeric($val)) { + $tagList[$val] = 1; + } + else { + list($label, $tagID) = explode(',', $val); + $tagList[$tagID] = 1; + } + } + } + } + $tagSets = CRM_Core_BAO_Tag::getTagsUsedFor('civicrm_contact', FALSE, TRUE); + + foreach ($tagSets as $key => $value) { + $this->_tags[$key] = $value['name']; + } + // merge contact and taglist tags + $allTags = CRM_Utils_Array::crmArrayMerge($contactTags, $tagList); + + $this->_name = array(); + foreach ($allTags as $key => $dnc) { + $this->_name[] = $this->_tags[$key]; + + list($total, $removed, $notRemoved) = CRM_Core_BAO_EntityTag::removeEntitiesFromTag($this->_contactIds, $key); + + $status = array(ts('%count contact un-tagged', array('count' => $removed, 'plural' => '%count contacts un-tagged'))); + if ($notRemoved) { + $status[] = ts('1 contact already did not have this tag', array('count' => $notRemoved, 'plural' => '%count contacts already did not have this tag')); + } + $status = '
    • ' . implode('
    • ', $status) . '
    '; + CRM_Core_Session::setStatus($status, ts("Removed Tag %1", array(1 => $this->_tags[$key])), 'success', array('expires' => 0)); + } + } + //end of function +} + diff --git a/CRM/Contact/Form/Task/Result.php b/CRM/Contact/Form/Task/Result.php new file mode 100644 index 0000000000..45f643b339 --- /dev/null +++ b/CRM/Contact/Form/Task/Result.php @@ -0,0 +1,116 @@ +set('searchRows', ''); + + $context = $this->get('context'); + if (in_array($context, array( + 'smog', 'amtg'))) { + $urlParams = 'reset=1&force=1&context=smog&gid='; + $urlParams .= ($context == 'smog') ? $this->get('gid') : $this->get('amtgID'); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/group/search', $urlParams)); + return; + } + + $ssID = $this->get('ssID'); + + if ($this->_action == CRM_Core_Action::BASIC) { + $fragment = 'search'; + } + elseif ($this->_action == CRM_Core_Action::PROFILE) { + $fragment = 'search/builder'; + } + elseif ($this->_action == CRM_Core_Action::ADVANCED) { + $fragment = 'search/advanced'; + } + else { + $fragment = 'search/custom'; + } + + $path = 'force=1'; + if (isset($ssID)) { + $path .= "&reset=1&ssID={$ssID}"; + } + if (!CRM_Contact_Form_Search::isSearchContext($context)) { + $context = 'search'; + } + $path .= "&context=$context"; + + //set the user context for redirection of task actions + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); + if (CRM_Utils_Rule::qfKey($qfKey)) { + $path .= "&qfKey=$qfKey"; + } + + $url = CRM_Utils_System::url('civicrm/contact/' . $fragment, $path); + $session->replaceUserContext($url); + return; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Contact/Form/Task/SMS.php b/CRM/Contact/Form/Task/SMS.php new file mode 100644 index 0000000000..8fc300c2df --- /dev/null +++ b/CRM/Contact/Form/Task/SMS.php @@ -0,0 +1,101 @@ +_context = CRM_Utils_Request::retrieve('context', 'String', $this); + + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE); + if ($cid) { + CRM_Contact_Page_View::setTitle($cid); + } + + CRM_Contact_Form_Task_SMSCommon::preProcessProvider($this); + + if (!$cid && $this->_context != 'standalone') { + parent::preProcess(); + } + + $this->assign('single', $this->_single); + if (CRM_Core_Permission::check('administer CiviCRM')) { + $this->assign('isAdmin', 1); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('suppressForm', FALSE); + $this->assign('SMSTask', TRUE); + CRM_Contact_Form_Task_SMSCommon::buildQuickForm($this); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Contact_Form_Task_SMSCommon::postProcess($this); + } +} + diff --git a/CRM/Contact/Form/Task/SMSCommon.php b/CRM/Contact/Form/Task/SMSCommon.php new file mode 100644 index 0000000000..d21c14495f --- /dev/null +++ b/CRM/Contact/Form/Task/SMSCommon.php @@ -0,0 +1,429 @@ +_single = FALSE; + $className = CRM_Utils_System::getClassName($form); + + if (property_exists($form, '_context') && + $form->_context != 'search' && + $className == 'CRM_Contact_Form_Task_SMS' + ) { + $form->_single = TRUE; + } + + $providersCount = CRM_SMS_BAO_Provider::activeProviderCount(); + + if (!$providersCount) { + CRM_Core_Error::statusBounce(ts('There are no SMS providers configured, or no SMS providers are set active')); + } + + if ($className == 'CRM_Activity_Form_Task_SMS') { + $activityCheck = 0; + foreach ($form->_activityHolderIds as $value) { + if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $value, 'subject', 'id') != self::RECIEVED_SMS_ACTIVITY_SUBJECT) { + $activityCheck++; + } + } + if ($activityCheck == count($form->_activityHolderIds)) { + CRM_Core_Error::statusBounce(ts("The Reply SMS Could only be sent for activities with '%1' subject.", + array(1 => self::RECIEVED_SMS_ACTIVITY_SUBJECT) + )); + } + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + static function buildQuickForm(&$form) { + + $toArray = array(); + + $form->assign('max_sms_length', CRM_SMS_Provider::MAX_SMS_CHAR); + + $providers = CRM_SMS_BAO_Provider::getProviders(NULL, NULL, TRUE, 'is_default desc'); + + $providerSelect = array(); + foreach ($providers as $provider) { + $providerSelect[$provider['id']] = $provider['title']; + } + $suppressedSms = 0; + //here we are getting logged in user id as array but we need target contact id. CRM-5988 + $cid = $form->get('cid'); + + if ($cid) { + $form->_contactIds = array($cid); + } + + $to = $form->add('text', 'to', ts('To'), '', TRUE); + $form->add('text', 'activity_subject', ts('Name The SMS'), '', TRUE); + + $toSetDefault = TRUE; + if (property_exists($form, '_context') && $form->_context == 'standalone') { + $toSetDefault = FALSE; + } + + // when form is submitted recompute contactIds + $allToSMS = array(); + if ($to->getValue()) { + $allToPhone = explode(',', $to->getValue()); + + $form->_contactIds = array(); + foreach ($allToPhone as $value) { + list($contactId, $phone) = explode('::', $value); + if ($contactId) { + $form->_contactIds[] = $contactId; + $form->_toContactPhone[] = $phone; + } + } + $toSetDefault = TRUE; + } + + //get the group of contacts as per selected by user in case of Find Activities + if (!empty($form->_activityHolderIds)) { + $extendTargetContacts = 0; + $invalidActivity = 0; + $validActivities = 0; + foreach ($form->_activityHolderIds as $key => $id) { + //valid activity check + if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $id, 'subject', 'id') != self::RECIEVED_SMS_ACTIVITY_SUBJECT) { + $invalidActivity++; + continue; + } + + //target contacts limit check + $ids = array_keys(CRM_Activity_BAO_ActivityTarget::getTargetNames($id)); + + if (count($ids) > 1) { + $extendTargetContacts++; + continue; + } + $validActivities++; + $form->_contactIds = empty($form->_contactIds) ? $ids : array_unique(array_merge($form->_contactIds, $ids)); + } + + if (!$validActivities) { + $errorMess = ""; + if ($extendTargetContacts) { + $errorMess = ts('One selected activity consists of more than one target contact.', array( + 'count' => $extendTargetContacts, + 'plural' => '%count selected activities consist of more than one target contact.')); + } + if ($invalidActivity) { + $errorMess = ($errorMess ? ' ' : ''); + $errorMess .= ts('The selected activity is invalid.', array( + 'count' => $invalidActivity, + 'plural' => '%count selected activities are invalid.')); + } + CRM_Core_Error::statusBounce(ts("%1: SMS Reply will not be sent.", array(1 => $errorMess))); + } + } + + if (is_array($form->_contactIds) && $toSetDefault) { + $returnProperties = array( + 'sort_name' => 1, + 'phone' => 1, + 'do_not_sms' => 1, + 'is_deceased' => 1, + 'display_name' => 1, + ); + + list($form->_contactDetails) = CRM_Utils_Token::getTokenDetails($form->_contactIds, + $returnProperties, + FALSE, + FALSE + ); + + // make a copy of all contact details + $form->_allContactDetails = $form->_contactDetails; + + foreach ($form->_contactIds as $key => $contactId) { + $value = $form->_contactDetails[$contactId]; + + //to check if the phone type is "Mobile" + $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name'); + + if (CRM_Utils_System::getClassName($form) == 'CRM_Activity_Form_Task_SMS') { + //to check for "if the contact id belongs to a specified activity type" + $actDetails = CRM_Activity_BAO_Activity::getContactActivity($contactId); + if (self::RECIEVED_SMS_ACTIVITY_SUBJECT != + CRM_Utils_Array::retrieveValueRecursive($actDetails, 'subject') + ) { + $suppressedSms++; + unset($form->_contactDetails[$contactId]); + continue; + } + } + + if ((isset($value['phone_type_id']) && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes)) || $value['do_not_sms'] || empty($value['phone']) || CRM_Utils_Array::value('is_deceased', $value)) { + + //if phone is not primary check if non-primary phone is "Mobile" + if (!empty($value['phone']) + && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes) + && !CRM_Utils_Array::value('is_deceased', $value) + ) { + $filter = array('do_not_sms' => 0); + $contactPhones = CRM_Core_BAO_Phone::allPhones($contactId, FALSE, 'Mobile', $filter); + if (count($contactPhones) > 0) { + $mobilePhone = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'phone'); + $form->_contactDetails[$contactId]['phone_id'] = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'id'); + $form->_contactDetails[$contactId]['phone'] = $mobilePhone; + $form->_contactDetails[$contactId]['phone_type_id'] = CRM_Utils_Array::value('Mobile', $phoneTypes); + } + else { + $suppressedSms++; + unset($form->_contactDetails[$contactId]); + continue; + } + } + else { + $suppressedSms++; + unset($form->_contactDetails[$contactId]); + continue; + } + } + + if (isset($mobilePhone)) { + $phone = $mobilePhone; + } + elseif (empty($form->_toContactPhone)) { + $phone = $value['phone']; + } + else { + $phone = CRM_Utils_Array::value($key, $form->_toContactPhone); + } + + if ($phone) { + $toArray[] = array( + 'name' => '"' . $value['sort_name'] . '" <' . $phone . '>', + 'id' => "$contactId::{$phone}", + ); + } + } + + if (empty($toArray)) { + CRM_Core_Error::statusBounce(ts('Selected contact(s) do not have a valid Phone, or communication preferences specify DO NOT SMS, or they are deceased')); + } + } + + //activity related variables + if (isset($invalidActivity)) { + $form->assign('invalidActivity', $invalidActivity); + } + if (isset($extendTargetContacts)) { + $form->assign('extendTargetContacts', $extendTargetContacts); + } + + + $form->assign('toContact', json_encode($toArray)); + $form->assign('suppressedSms', $suppressedSms); + $form->assign('totalSelectedContacts', count($form->_contactIds)); + + $form->add('select', 'sms_provider_id', ts('From'), $providerSelect, TRUE); + + CRM_Mailing_BAO_Mailing::commonCompose($form); + + if ($form->_single) { + // also fix the user context stack + if ($form->_context) { + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view', + "&show=1&action=browse&cid={$form->_contactIds[0]}&selectedChild=activity" + ); + } + + $session = CRM_Core_Session::singleton(); + $session->replaceUserContext($url); + $form->addDefaultButtons(ts('Send SMS'), 'upload', 'cancel'); + } + else { + $form->addDefaultButtons(ts('Send SMS'), 'upload'); + } + + $form->addFormRule(array('CRM_Contact_Form_Task_SMSCommon', 'formRule'), $form); + } + + /** + * form rule + * + * @param array $fields the input form values + * @param array $dontCare + * @param array $self additional values form 'this' + * + * @return true if no errors, else array of errors + * @access public + * + */ + static function formRule($fields, $dontCare, $self) { + $errors = array(); + + $template = CRM_Core_Smarty::singleton(); + + if (!CRM_Utils_Array::value('text_message', $fields)) { + $errors['text_message'] = ts('Please provide Text message.'); + } + else { + if (CRM_Utils_Array::value('text_message', $fields)) { + $messageCheck = CRM_Utils_Array::value('text_message', $fields); + $messageCheck = str_replace("\r\n", "\n", $messageCheck); + if ($messageCheck && (strlen($messageCheck) > CRM_SMS_Provider::MAX_SMS_CHAR)) { + $errors['text_message'] = ts("You can configure the SMS message body up to %1 characters", array(1 => CRM_SMS_Provider::MAX_SMS_CHAR)); + } + } + } + + //Added for CRM-1393 + if (CRM_Utils_Array::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) { + $errors['saveTemplateName'] = ts("Enter name to save message template"); + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + static function postProcess(&$form) { + + // check and ensure that + $thisValues = $form->controller->exportValues($form->getName()); + + $fromSmsProviderId = $thisValues['sms_provider_id']; + + // process message template + if (CRM_Utils_Array::value('saveTemplate', $thisValues) + || CRM_Utils_Array::value('updateTemplate', $thisValues) + ) { + $messageTemplate = array( + 'msg_text' => $thisValues['text_message'], + 'is_active' => TRUE, + ); + + if (CRM_Utils_Array::value('saveTemplate', $thisValues)) { + $messageTemplate['msg_title'] = $thisValues['saveTemplateName']; + CRM_Core_BAO_MessageTemplates::add($messageTemplate); + } + + if (CRM_Utils_Array::value('template', $thisValues) && + CRM_Utils_Array::value('updateTemplate', $thisValues) + ) { + $messageTemplate['id'] = $thisValues['template']; + unset($messageTemplate['msg_title']); + CRM_Core_BAO_MessageTemplates::add($messageTemplate); + } + } + + // format contact details array to handle multiple sms from same contact + $formattedContactDetails = array(); + $tempPhones = array(); + + foreach ($form->_contactIds as $key => $contactId) { + $phone = $form->_toContactPhone[$key]; + + if ($phone) { + $phoneKey = "{$contactId}::{$phone}"; + if (!in_array($phoneKey, $tempPhones)) { + $tempPhones[] = $phoneKey; + if (CRM_Utils_Array::value($contactId, $form->_contactDetails)) { + $formattedContactDetails[] = $form->_contactDetails[$contactId]; + } + } + } + } + + // $smsParams carries all the arguments provided on form (or via hooks), to the provider->send() method + // this gives flexibity to the users / implementors to add their own args via hooks specific to their sms providers + $smsParams = $thisValues; + unset($smsParams['text_message']); + $smsParams['provider_id'] = $fromSmsProviderId; + + list($sent, $activityId) = CRM_Activity_BAO_Activity::sendSMS($formattedContactDetails, + $thisValues, + $smsParams, + array_keys($form->_contactDetails) + ); + + if ($sent) { + $count_success = count($form->_contactDetails); + CRM_Core_Session::setStatus(ts('One message was sent successfully.', array('plural' => '%count messages were sent successfully.', 'count' => $count_success)), ts('Message Sent', array('plural' => 'Messages Sent', 'count' => $count_success)), 'success'); + } + + //Display the name and number of contacts for those sms is not sent. + $smsNotSent = array_diff_assoc($form->_allContactDetails, $form->_contactDetails); + + if (!empty($smsNotSent)) { + $not_sent = array(); + foreach ($smsNotSent as $contactId => $values) { + $displayName = $values['display_name']; + $phone = $values['phone']; + $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$contactId"); + $not_sent[] = "$displayName"; + } + $status = '(' . ts('because no phone number on file or communication preferences specify DO NOT SMS or Contact is deceased'); + if (CRM_Utils_System::getClassName($form) == 'CRM_Activity_Form_Task_SMS') { + $status .= ' ' . ts("or the contact is not part of the activity '%1'", array(1 => self::RECIEVED_SMS_ACTIVITY_SUBJECT)); + } + $status .= ')
    • ' . implode('
    • ', $not_sent) . '
    '; + CRM_Core_Session::setStatus($status, ts('One Message Not Sent', array('count' => count($smsNotSent), 'plural' => '%count Messages Not Sent')), 'info'); + } + + } +} + diff --git a/CRM/Contact/Form/Task/SaveSearch.php b/CRM/Contact/Form/Task/SaveSearch.php new file mode 100644 index 0000000000..7e2f270e33 --- /dev/null +++ b/CRM/Contact/Form/Task/SaveSearch.php @@ -0,0 +1,221 @@ +_id = NULL; + + // get the submitted values of the search form + // we'll need to get fv from either search or adv search in the future + if ($this->_action == CRM_Core_Action::ADVANCED) { + $values = $this->controller->exportValues('Advanced'); + } + elseif ($this->_action == CRM_Core_Action::PROFILE) { + $values = $this->controller->exportValues('Builder'); + } + elseif ($this->_action == CRM_Core_Action::COPY) { + $values = $this->controller->exportValues('Custom'); + } + else { + $values = $this->controller->exportValues('Basic'); + } + + $this->_task = CRM_Utils_Array::value('task', $values); + $crmContactTaskTasks = CRM_Contact_Task::taskTitles(); + $this->assign('taskName', CRM_Utils_Array::value($this->_task, $crmContactTaskTasks)); + } + + /** + * Build the form - it consists of + * - displaying the QILL (query in local language) + * - displaying elements for saving the search + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // get the qill + $query = new CRM_Contact_BAO_Query($this->get('queryParams')); + $qill = $query->qill(); + + // need to save qill for the smarty template + $this->assign('qill', $qill); + + // the name and description are actually stored with the group and not the saved search + $this->add('text', 'title', ts('Name'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Group', 'title'), TRUE + ); + + + $this->addElement('textarea', 'description', ts('Description'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Group', 'description') + ); + + $groupTypes = CRM_Core_OptionGroup::values('group_type', TRUE); + unset($groupTypes['Access Control']); + if (!CRM_Core_Permission::access('CiviMail')) { + $isWorkFlowEnabled = CRM_Mailing_Info::workflowEnabled(); + if ($isWorkFlowEnabled && + !CRM_Core_Permission::check('create mailings') && + !CRM_Core_Permission::check('schedule mailings') && + !CRM_Core_Permission::check('approve mailings') + ) { + unset($groupTypes['Mailing List']); + } + } + + if (!empty($groupTypes)) { + $this->addCheckBox('group_type', + ts('Group Type'), + $groupTypes, + NULL, NULL, NULL, NULL, '   ' + ); + } + + // get the group id for the saved search + $groupID = NULL; + if (isset($this->_id)) { + $groupID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', + $this->_id, + 'id', + 'saved_search_id' + ); + $this->addDefaultButtons(ts('Update Smart Group')); + } + else { + $this->addDefaultButtons(ts('Save Smart Group')); + } + $this->addRule('title', ts('Name already exists in Database.'), + 'objectExists', array('CRM_Contact_DAO_Group', $groupID, 'title') + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + // saved search form values + // get form values of all the forms in this controller + $formValues = $this->controller->exportValues(); + + $isAdvanced = $this->get('isAdvanced'); + $isSearchBuilder = $this->get('isSearchBuilder'); + + // add mapping record only for search builder saved search + $mappingId = NULL; + if ($isAdvanced == '2' && $isSearchBuilder == '1') { + //save the mapping for search builder + + if (!$this->_id) { + //save record in mapping table + $mappingParams = array('mapping_type' => 'Search Builder'); + $temp = array(); + $mapping = CRM_Core_BAO_Mapping::add($mappingParams, $temp); + $mappingId = $mapping->id; + } + else { + //get the mapping id from saved search + + $savedSearch = new CRM_Contact_BAO_SavedSearch(); + $savedSearch->id = $this->_id; + $savedSearch->find(TRUE); + $mappingId = $savedSearch->mapping_id; + } + + //save mapping fields + CRM_Core_BAO_Mapping::saveMappingFields($formValues, $mappingId); + } + + //save the search + $savedSearch = new CRM_Contact_BAO_SavedSearch(); + $savedSearch->id = $this->_id; + $savedSearch->form_values = serialize($this->get('formValues')); + $savedSearch->mapping_id = $mappingId; + $savedSearch->search_custom_id = $this->get('customSearchID'); + $savedSearch->save(); + $this->set('ssID', $savedSearch->id); + CRM_Core_Session::setStatus(ts("Your smart group has been saved as '%1'.", array(1 => $formValues['title'])), ts('Group Saved'), 'success'); + + // also create a group that is associated with this saved search only if new saved search + $params = array(); + $params['title'] = $formValues['title']; + $params['description'] = $formValues['description']; + if (isset($formValues['group_type']) && + is_array($formValues['group_type']) + ) { + $params['group_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($formValues['group_type']) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + } + else { + $params['group_type'] = ''; + } + $params['visibility'] = 'User and User Admin Only'; + $params['saved_search_id'] = $savedSearch->id; + $params['is_active'] = 1; + + if ($this->_id) { + $params['id'] = CRM_Contact_BAO_SavedSearch::getName($this->_id, 'id'); + } + + $group = CRM_Contact_BAO_Group::create($params); + + // CRM-9464 + $this->_id = $savedSearch->id; + } +} + diff --git a/CRM/Contact/Form/Task/SaveSearch/Update.php b/CRM/Contact/Form/Task/SaveSearch/Update.php new file mode 100644 index 0000000000..3972919eb5 --- /dev/null +++ b/CRM/Contact/Form/Task/SaveSearch/Update.php @@ -0,0 +1,80 @@ +_id = $this->get('ssID'); + if (!$this->_id) { + // fetch the value from the group id gid + $gid = $this->get('gid'); + if ($gid) { + $this->_id = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $gid, 'saved_search_id'); + } + } + } + + /** + * This function sets the default values for the form. + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + + $defaults = array(); + $params = array(); + + $params = array('saved_search_id' => $this->_id); + CRM_Contact_BAO_Group::retrieve($params, $defaults); + + return $defaults; + } +} + diff --git a/CRM/Contact/Form/Task/Unhold.php b/CRM/Contact/Form/Task/Unhold.php new file mode 100644 index 0000000000..d72a405bea --- /dev/null +++ b/CRM/Contact/Form/Task/Unhold.php @@ -0,0 +1,40 @@ +addDefaultButtons(ts('Unhold Email'), 'done'); + } + + public function postProcess() { + // Query to unhold emails of selected contacts + $num = count($this->_contactIds); + if ($num >= 1) { + $queryString = " +UPDATE civicrm_email SET on_hold = 0, hold_date = null +WHERE on_hold = 1 AND hold_date is not null AND contact_id in (" . implode(",", $this->_contactIds) . ")"; + CRM_Core_DAO::executeQuery($queryString); + $sql = "SELECT ROW_COUNT( )"; + $result = CRM_Core_DAO::singleValueQuery($sql); + if ($result) { + CRM_Core_Session::setStatus(ts('%count email was found on hold and updated.', array('count' => $result, 'plural' => '%count emails were found on hold and updated.')), ts('Emails Restored'), 'success'); + } + else { + CRM_Core_Session::setStatus(ts('The selected contact does not have an email on hold.', array('count' => $result, 'plural' => 'None of the selected contacts have an email on hold.')), ts('No Emails to Restore'), 'info'); + } + } + else { + CRM_Core_Session::setStatus(ts('Please select one or more contact for this action'), ts('No Contacts Selected'), 'error'); + } + } +} + diff --git a/CRM/Contact/Form/Task/Useradd.php b/CRM/Contact/Form/Task/Useradd.php new file mode 100755 index 0000000000..3b386d7c72 --- /dev/null +++ b/CRM/Contact/Form/Task/Useradd.php @@ -0,0 +1,156 @@ +_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $params['id'] = $params['contact_id'] = $this->_contactId; + $contact = CRM_Contact_BAO_Contact::retrieve($params, $defaults, $ids); + $this->_displayName = $contact->display_name; + $this->_email = $contact->email; + CRM_Utils_System::setTitle(ts('Create User Record for %1', array(1 => $this->_displayName))); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + $defaults['contactID'] = $this->_contactId; + $defaults['name'] = $this->_displayName; + if (!empty($this->_email)) { + $defaults['email'] = $this->_email[1]['email']; + } + + return $defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $element = $this->add('text', 'name', ts('Full Name'), array('class' => 'huge')); + $element->freeze(); + $this->add('text', 'cms_name', ts('Username'), array('class' => 'huge')); + $this->addRule('cms_name', 'Username is required', 'required'); + $this->addRule('cms_name', 'Enter a valid username', 'minlength', 2); + $this->add('password', 'cms_pass', ts('Password'), array('class' => 'huge')); + $this->add('password', 'cms_confirm_pass', ts('Confirm Password'), array('class' => 'huge')); + $this->addRule('cms_pass', 'Password is required', 'required'); + $this->addRule(array('cms_pass', 'cms_confirm_pass'), 'ERROR: Password mismatch', 'compare'); + $this->add('text', 'email', ts('Email:'), array('class' => 'huge'))->freeze(); + $this->add('hidden', 'contactID'); + + //add a rule to check username uniqueness + $this->addFormRule(array('CRM_Contact_Form_Task_Useradd', 'usernameRule')); + + $this->addButtons( + array( + array( + 'type' => 'next', + 'name' => ts('Add'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + $this->setDefaults($this->setDefaultValues()); + } + + /** + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->exportValues(); + + CRM_Core_BAO_CMSUser::create($params, 'email'); + CRM_Core_Session::setStatus('', ts('User Added'), 'success'); + } + + /** + * Validation Rule + * + * @static + */ + static function usernameRule($params) { + $config = CRM_Core_Config::singleton(); + $errors = array(); + $check_params = array( + 'name' => $params['cms_name'], + 'mail' => $params['email'], + ); + $config->userSystem->checkUserNameEmailExists($check_params, $errors); + + return empty($errors) ? TRUE : $errors; + } +} + diff --git a/CRM/Contact/Form/Test.php b/CRM/Contact/Form/Test.php new file mode 100644 index 0000000000..06ea9b037f --- /dev/null +++ b/CRM/Contact/Form/Test.php @@ -0,0 +1,85 @@ +addElement('text', "state", ts('State / Province'), 'onkeyup="getState(this,event, false);" onblur="getState(this,event, false);" autocomplete="off"'); + + $this->addElement('text', "state_id", ts('State / Province Id')); + //$this->addElement('text', "country", ts('Country')); + // $this->addElement('text', "country_id", ts('Country Id')); + $this->addElement('select', "country", ts('Country'), array('' => ts('- select -')), 'onblur="getState(this,event, true);"'); + } + + /** + * Form submission of new/edit contact is processed. + * + * @access public + * + * @return None + */ + public function postProcess() {} +} + diff --git a/CRM/Contact/Page/AJAX.php b/CRM/Contact/Page/AJAX.php new file mode 100644 index 0000000000..1ae994dbfe --- /dev/null +++ b/CRM/Contact/Page/AJAX.php @@ -0,0 +1,1217 @@ + 3, 'check_permissions' => TRUE); + + if ($context = CRM_Utils_Array::value('context', $_GET)) { + $params['context'] = CRM_Utils_Type::escape($_GET['context'], 'String'); + } + + if ($name = CRM_Utils_Array::value('s', $_GET)) { + $params['name'] = CRM_Utils_Type::escape($name, 'String'); + } + + //CRM-10687: Allow quicksearch by multiple fields + if (!empty($_GET['fieldName'])) { + $params['field_name'] = CRM_Utils_Type::escape($_GET['fieldName'], 'String'); + if ($params['field_name'] == 'phone_numeric') { + $params['name'] = preg_replace('/[^\d]/', '', $params['name']); + } + if (!$params['name']) { + CRM_Utils_System::civiExit(); + } + } + + if (!empty($_GET['tableName'])) { + $params['table_name'] = CRM_Utils_Type::escape($_GET['tableName'], 'String'); + } + + $params['limit'] = 10; + if (CRM_Utils_Array::value('limit', $_GET)) { + $params['limit'] = CRM_Utils_Type::escape($_GET['limit'], 'Positive'); + } + + $orgId = $employee_id = $cid = $id = $context = $rel = NULL; + $params['org'] = CRM_Utils_Array::value('org', $_GET); + if (CRM_Utils_Array::value('id', $_GET)) { + $params['orgId'] = CRM_Utils_Type::escape($_GET['id'], 'Positive'); + } + + if (CRM_Utils_Array::value('employee_id', $_GET)) { + $params['employee_id'] = CRM_Utils_Type::escape($_GET['employee_id'], 'Positive'); + } + + if (CRM_Utils_Array::value('cid', $_GET)) { + $params['cid'] = CRM_Utils_Type::escape($_GET['cid'], 'Positive'); + } + + if (CRM_Utils_Array::value('id', $_GET)) { + $params['id'] = CRM_Utils_Type::escape($_GET['id'], 'Positive'); + } + + if (isset($_GET['rel'])) { + $params['rel'] = $_GET['rel']; + } + + if (CRM_Utils_Array::value('cmsuser', $_GET)) { + $params['cmsuser'] = CRM_Utils_Type::escape($_GET['cmsuser'], 'Boolean'); + } + + $result = civicrm_api('Contact', 'getquick', $params); + if (empty($result['is_error']) && !empty($result['values'])) { + foreach ($result['values'] as $key => $val) { + echo "{$val['data']}|{$val['id']}\n"; + } + } + CRM_Utils_System::civiExit(); + } + + static function contactReference() { + $name = CRM_Utils_Array::value('s', $_GET); + $name = CRM_Utils_Type::escape($name, 'String'); + $cfID = CRM_Utils_Type::escape($_GET['id'], 'Positive'); + + // check that this is a valid, active custom field of Contact Reference type + $params = array('id' => $cfID); + $returnProperties = array('filter', 'data_type', 'is_active'); + $fldValues = array(); + CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomField', $params, $cf, $returnProperties); + if (!$cf['id'] || !$cf['is_active'] || $cf['data_type'] = !'ContactReference') { + echo "$name|error\n"; + CRM_Utils_System::civiExit(); + } + + if ($cf['filter']) { + $filterParams = array(); + parse_str($cf['filter'], $filterParams); + + $action = CRM_Utils_Array::value('action', $filterParams); + + if (!empty($action) && + !in_array($action, array('get', 'lookup')) + ) { + echo "$name|error\n"; + CRM_Utils_System::civiExit(); + } + } + + $list = array_keys(CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_reference_options' + ), '1'); + + $return = array_unique(array_merge(array('sort_name'), $list)); + + $config = CRM_Core_Config::singleton(); + + $limit = 10; + if (CRM_Utils_Array::value('limit', $_GET)) { + $limit = CRM_Utils_Type::escape($_GET['limit'], 'Positive'); + } + + $params = array('offset' => 0, 'rowCount' => $limit, 'version' => 3); + foreach ($return as $fld) { + $params["return.{$fld}"] = 1; + } + + if (!empty($action)) { + $excludeGet = array('reset', 'key', 'className', 'fnName', 'json', 'reset', 'context', 'timestamp', 'limit', 'id', 's', 'q', 'action'); + foreach ($_GET as $param => $val) { + if (empty($val) || + in_array($param, $excludeGet) || + strpos($param, 'return.') !== FALSE || + strpos($param, 'api.') !== FALSE + ) { + continue; + } + $params[$param] = $val; + } + } + + if ($name) { + $params['sort_name'] = $name; + } + + $params['sort'] = 'sort_name'; + + // tell api to skip permission chk. dgg + $params['check_permissions'] = 0; + + // add filter variable to params + if (!empty($filterParams)) { + $params = array_merge($params, $filterParams); + } + + $contact = civicrm_api('Contact', 'Get', $params); + + if (CRM_Utils_Array::value('is_error', $contact)) { + echo "$name|error\n"; + CRM_Utils_System::civiExit(); + } + + $contactList = ''; + foreach ($contact['values'] as $value) { + $view = array(); + foreach ($return as $fld) { + if (CRM_Utils_Array::value($fld, $value)) { + $view[] = $value[$fld]; + } + } + echo $contactList = implode(' :: ', $view) . "|" . $value['id'] . "\n"; + } + + if (!$contactList) { + echo "$name|$name\n"; + } + + CRM_Utils_System::civiExit(); + } + + /** + * Function to fetch PCP ID by PCP Supporter sort_name, also displays PCP title and associated Contribution Page title + */ + static function getPCPList() { + $name = CRM_Utils_Array::value('s', $_GET); + $name = CRM_Utils_Type::escape($name, 'String'); + $limit = '10'; + + $where = ' AND pcp.page_id = cp.id AND pcp.contact_id = cc.id'; + + $config = CRM_Core_Config::singleton(); + if ($config->includeWildCardInName) { + $strSearch = "%$name%"; + } + else { + $strSearch = "$name%"; + } + $includeEmailFrom = $includeNickName = ''; + if ($config->includeNickNameInName) { + $includeNickName = " OR nick_name LIKE '$strSearch'"; + } + if ($config->includeEmailInName) { + $includeEmailFrom = "LEFT JOIN civicrm_email eml ON ( cc.id = eml.contact_id AND eml.is_primary = 1 )"; + $whereClause = " WHERE ( email LIKE '$strSearch' OR sort_name LIKE '$strSearch' $includeNickName ) {$where} "; + } + else { + $whereClause = " WHERE ( sort_name LIKE '$strSearch' $includeNickName ) {$where} "; + } + + if (CRM_Utils_Array::value('limit', $_GET)) { + $limit = CRM_Utils_Type::escape($_GET['limit'], 'Positive'); + } + + $select = 'cc.sort_name, pcp.title, cp.title'; + $query = " + SELECT id, data + FROM ( + SELECT pcp.id as id, CONCAT_WS( ' :: ', {$select} ) as data, sort_name + FROM civicrm_pcp pcp, civicrm_contribution_page cp, civicrm_contact cc + {$includeEmailFrom} + {$whereClause} + LIMIT 0, {$limit} + ) t + ORDER BY sort_name + "; + + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + echo $pcpList = "$dao->data|$dao->id\n"; + } + + CRM_Utils_System::civiExit(); + } + + /** + * Function to fetch the values + */ + static function autocomplete() { + $fieldID = CRM_Utils_Type::escape($_GET['cfid'], 'Integer'); + $optionGroupID = CRM_Utils_Type::escape($_GET['ogid'], 'Integer'); + $label = CRM_Utils_Type::escape($_GET['s'], 'String'); + + $selectOption = CRM_Core_BAO_CustomOption::valuesByID($fieldID, $optionGroupID); + + $completeList = NULL; + foreach ($selectOption as $id => $value) { + if (strtolower($label) == strtolower(substr($value, 0, strlen($label)))) { + echo $completeList = "$value|$id\n"; + } + } + CRM_Utils_System::civiExit(); + } + + static function relationship() { + $relType = CRM_Utils_Array::value('rel_type', $_REQUEST); + $relContactID = CRM_Utils_Array::value('rel_contact', $_REQUEST); + $sourceContactID = CRM_Utils_Array::value('contact_id', $_REQUEST); + $relationshipID = CRM_Utils_Array::value('rel_id', $_REQUEST); + $caseID = CRM_Utils_Array::value('case_id', $_REQUEST); + + $relationParams = array( + 'relationship_type_id' => $relType . '_a_b', + 'contact_check' => array($relContactID => 1), + 'is_active' => 1, + 'case_id' => $caseID, + 'start_date' => date("Ymd"), + ); + + $relationIds = array('contact' => $sourceContactID); + if ($relationshipID && $relationshipID != 'null') { + $relationIds['relationship'] = $relationshipID; + $relationIds['contactTarget'] = $relContactID; + } + + $return = CRM_Contact_BAO_Relationship::create($relationParams, $relationIds); + $status = 'process-relationship-fail'; + if (CRM_Utils_Array::value(0, $return[4])) { + $relationshipID = $return[4][0]; + $status = 'process-relationship-success'; + } + + $caseRelationship = array(); + if ($relationshipID && $relationshipID != 'null') { + // we should return phone and email + $caseRelationship = CRM_Case_BAO_Case::getCaseRoles($sourceContactID, + $caseID, $relationshipID + ); + + //create an activity for case role assignment.CRM-4480 + CRM_Case_BAO_Case::createCaseRoleActivity($caseID, $relationshipID, $relContactID); + } + $relation = CRM_Utils_Array::value($relationshipID, $caseRelationship, array()); + + $relation['rel_id'] = $relationshipID; + $relation['status'] = $status; + echo json_encode($relation); + CRM_Utils_System::civiExit(); + } + + /** + * Function to fetch the custom field help + */ + static function customField() { + $fieldId = CRM_Utils_Type::escape($_REQUEST['id'], 'Integer'); + $params = array('id' => $fieldId); + $returnProperties = array('help_pre', 'help_post'); + $values = array(); + + CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomField', $params, $values, $returnProperties); + echo json_encode($values); + CRM_Utils_System::civiExit(); + } + + /** + * Function to obtain list of permissioned employer for the given contact-id. + */ + static function getPermissionedEmployer() { + $cid = CRM_Utils_Type::escape($_GET['cid'], 'Integer'); + $name = trim(CRM_Utils_Type::escape($_GET['s'], 'String')); + $name = str_replace('*', '%', $name); + + $elements = CRM_Contact_BAO_Relationship::getPermissionedEmployer($cid, $name); + + if (!empty($elements)) { + foreach ($elements as $cid => $name) { + echo $element = $name['name'] . "|$cid\n"; + } + } + CRM_Utils_System::civiExit(); + } + + + static function groupTree() { + $gids = CRM_Utils_Type::escape($_GET['gids'], 'String'); + echo CRM_Contact_BAO_GroupNestingCache::json($gids); + CRM_Utils_System::civiExit(); + } + + /** + * Function for building contact combo box + */ + static function search() { + $json = TRUE; + $name = CRM_Utils_Array::value('name', $_GET, ''); + if (!array_key_exists('name', $_GET)) { + $name = CRM_Utils_Array::value('s', $_GET) . '%'; + $json = FALSE; + } + $name = CRM_Utils_Type::escape($name, 'String'); + $whereIdClause = ''; + if (CRM_Utils_Array::value('id', $_GET)) { + $json = TRUE; + if (is_numeric($_GET['id'])) { + $id = CRM_Utils_Type::escape($_GET['id'], 'Integer'); + $whereIdClause = " AND civicrm_contact.id = {$id}"; + } + else { + $name = $_GET['id']; + } + } + + $elements = array(); + if ($name || isset($id)) { + $name = $name . '%'; + + //contact's based of relationhip type + $relType = NULL; + if (isset($_GET['rel'])) { + $relation = explode('_', $_GET['rel']); + $relType = CRM_Utils_Type::escape($relation[0], 'Integer'); + $rel = CRM_Utils_Type::escape($relation[2], 'String'); + } + + //shared household info + $shared = NULL; + if (isset($_GET['sh'])) { + $shared = CRM_Utils_Type::escape($_GET['sh'], 'Integer'); + if ($shared == 1) { + $contactType = 'Household'; + $cName = 'household_name'; + } + else { + $contactType = 'Organization'; + $cName = 'organization_name'; + } + } + + // contacts of type household + $hh = $addStreet = $addCity = NULL; + if (isset($_GET['hh'])) { + $hh = CRM_Utils_Type::escape($_GET['hh'], 'Integer'); + } + + //organization info + $organization = $street = $city = NULL; + if (isset($_GET['org'])) { + $organization = CRM_Utils_Type::escape($_GET['org'], 'Integer'); + } + + if (isset($_GET['org']) || isset($_GET['hh'])) { + $json = FALSE; + if ($splitName = explode(' :: ', $name)) { + $contactName = trim(CRM_Utils_Array::value('0', $splitName)); + $street = trim(CRM_Utils_Array::value('1', $splitName)); + $city = trim(CRM_Utils_Array::value('2', $splitName)); + } + else { + $contactName = $name; + } + + if ($street) { + $addStreet = "AND civicrm_address.street_address LIKE '$street%'"; + } + if ($city) { + $addCity = "AND civicrm_address.city LIKE '$city%'"; + } + } + + if ($organization) { + + $query = " +SELECT CONCAT_WS(' :: ',sort_name,LEFT(street_address,25),city) 'sort_name', +civicrm_contact.id 'id' +FROM civicrm_contact +LEFT JOIN civicrm_address ON ( civicrm_contact.id = civicrm_address.contact_id + AND civicrm_address.is_primary=1 + ) +WHERE civicrm_contact.contact_type='Organization' AND organization_name LIKE '%$contactName%' +{$addStreet} {$addCity} {$whereIdClause} +ORDER BY organization_name "; + } + elseif ($shared) { + $query = " +SELECT CONCAT_WS(':::' , sort_name, supplemental_address_1, sp.abbreviation, postal_code, cc.name )'sort_name' , civicrm_contact.id 'id' , civicrm_contact.display_name 'disp' FROM civicrm_contact LEFT JOIN civicrm_address ON (civicrm_contact.id =civicrm_address.contact_id AND civicrm_address.is_primary =1 )LEFT JOIN civicrm_state_province sp ON (civicrm_address.state_province_id =sp.id )LEFT JOIN civicrm_country cc ON (civicrm_address.country_id =cc.id )WHERE civicrm_contact.contact_type ='{$contactType}' AND {$cName} LIKE '%$name%' {$whereIdClause} ORDER BY {$cName} "; + } + elseif ($hh) { + $query = " +SELECT CONCAT_WS(' :: ' , sort_name, LEFT(street_address,25),city) 'sort_name' , location_type_id 'location_type_id', is_primary 'is_primary', is_billing 'is_billing', civicrm_contact.id 'id' +FROM civicrm_contact +LEFT JOIN civicrm_address ON (civicrm_contact.id =civicrm_address.contact_id AND civicrm_address.is_primary =1 ) +WHERE civicrm_contact.contact_type ='Household' +AND household_name LIKE '%$contactName%' {$addStreet} {$addCity} {$whereIdClause} ORDER BY household_name "; + } + elseif ($relType) { + if (CRM_Utils_Array::value('case', $_GET)) { + $query = " +SELECT distinct(c.id), c.sort_name +FROM civicrm_contact c +LEFT JOIN civicrm_relationship ON civicrm_relationship.contact_id_{$rel} = c.id +WHERE c.sort_name LIKE '%$name%' +AND civicrm_relationship.relationship_type_id = $relType +GROUP BY sort_name +"; + } + } + else { + + $query = " +SELECT sort_name, id +FROM civicrm_contact +WHERE sort_name LIKE '%$name' +{$whereIdClause} +ORDER BY sort_name "; + } + + $limit = 10; + if (isset($_GET['limit'])) { + $limit = CRM_Utils_Type::escape($_GET['limit'], 'Positive'); + } + + $query .= " LIMIT 0,{$limit}"; + + $dao = CRM_Core_DAO::executeQuery($query); + + if ($shared) { + while ($dao->fetch()) { + echo $dao->sort_name; + CRM_Utils_System::civiExit(); + } + } + else { + while ($dao->fetch()) { + if ($json) { + $elements[] = array('name' => addslashes($dao->sort_name), + 'id' => $dao->id, + ); + } + else { + echo $elements = "$dao->sort_name|$dao->id|$dao->location_type_id|$dao->is_primary|$dao->is_billing\n"; + } + } + //for adding new household address / organization + if (empty($elements) && !$json && ($hh || $organization)) { + echo CRM_Utils_Array::value('s', $_GET); + } + } + } + + if (isset($_GET['sh'])) { + echo ""; + CRM_Utils_System::civiExit(); + } + + if (empty($elements)) { + $name = str_replace('%', '', $name); + $elements[] = array( + 'name' => $name, + 'id' => $name, + ); + } + + if ($json) { + echo json_encode($elements); + } + CRM_Utils_System::civiExit(); + } + + /** + * + * Function to check how many contact exits in db for given criteria, + * if one then return contact id else null + */ + static function contact() { + $name = CRM_Utils_Type::escape($_GET['name'], 'String'); + + $query = " +SELECT id +FROM civicrm_contact +WHERE sort_name LIKE '%$name%'"; + + $dao = CRM_Core_DAO::executeQuery($query); + $dao->fetch(); + + if ($dao->N == 1) { + echo $dao->id; + } + CRM_Utils_System::civiExit(); + } + + /** + * Function to delete custom value + * + */ + static function deleteCustomValue() { + $customValueID = CRM_Utils_Type::escape($_REQUEST['valueID'], 'Positive'); + $customGroupID = CRM_Utils_Type::escape($_REQUEST['groupID'], 'Positive'); + + CRM_Core_BAO_CustomValue::deleteCustomValue($customValueID, $customGroupID); + if ($contactId = CRM_Utils_Array::value('contactId', $_REQUEST)) { + echo CRM_Contact_BAO_Contact::getCountComponent('custom_' . $_REQUEST['groupID'], $contactId); + } + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + CRM_Utils_System::civiExit(); + } + + /** + * Function to perform enable / disable actions on record. + * + */ + static function enableDisable() { + $op = CRM_Utils_Type::escape($_REQUEST['op'], 'String'); + $recordID = CRM_Utils_Type::escape($_REQUEST['recordID'], 'Positive'); + $recordBAO = CRM_Utils_Type::escape($_REQUEST['recordBAO'], 'String'); + + $isActive = NULL; + if ($op == 'disable-enable') { + $isActive = TRUE; + } + elseif ($op == 'enable-disable') { + $isActive = FALSE; + } + $status = array('status' => 'record-updated-fail'); + if (isset($isActive)) { + // first munge and clean the recordBAO and get rid of any non alpha numeric characters + $recordBAO = CRM_Utils_String::munge($recordBAO); + $recordClass = explode('_', $recordBAO); + + // make sure recordClass is namespaced (we cant check CRM since extensions can also use this) + // but it should be at least 3 levels deep + if (count($recordClass) >= 3) { + require_once (str_replace('_', DIRECTORY_SEPARATOR, $recordBAO) . ".php"); + $method = 'setIsActive'; + + if (method_exists($recordBAO, $method)) { + $updated = call_user_func_array(array($recordBAO, $method), + array($recordID, $isActive) + ); + if ($updated) { + $status = array('status' => 'record-updated-success'); + } + + // call hook enableDisable + CRM_Utils_Hook::enableDisable($recordBAO, $recordID, $isActive); + } + } + echo json_encode($status); + CRM_Utils_System::civiExit(); + } + } + + /** + *Function to check the CMS username + * + */ + static public function checkUserName() { + $config = CRM_Core_Config::singleton(); + $username = trim($_REQUEST['cms_name']); + + $params = array('name' => $username); + + $errors = array(); + $config->userSystem->checkUserNameEmailExists($params, $errors); + + if (isset($errors['cms_name']) || isset($errors['name'])) { + //user name is not availble + $user = array('name' => 'no'); + echo json_encode($user); + } + else { + //user name is available + $user = array('name' => 'yes'); + echo json_encode($user); + } + CRM_Utils_System::civiExit(); + } + + /** + * Function to get email address of a contact + */ + static function getContactEmail() { + if (CRM_Utils_Array::value('contact_id', $_REQUEST)) { + $contactID = CRM_Utils_Type::escape($_REQUEST['contact_id'], 'Positive'); + list($displayName, + $userEmail + ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID); + if ($userEmail) { + echo $userEmail; + } + } + else { + $noemail = CRM_Utils_Array::value('noemail', $_GET); + $queryString = NULL; + if ($name = CRM_Utils_Array::value('name', $_GET)) { + $name = CRM_Utils_Type::escape($name, 'String'); + if ($noemail) { + $queryString = " cc.sort_name LIKE '%$name%'"; + } + else { + $queryString = " ( cc.sort_name LIKE '%$name%' OR ce.email LIKE '%$name%' ) "; + } + } + elseif ($cid = CRM_Utils_Array::value('cid', $_GET)) { + //check cid for interger + $contIDS = explode(',', $cid); + foreach ($contIDS as $contID) { + CRM_Utils_Type::escape($contID, 'Integer'); + } + $queryString = " cc.id IN ( $cid )"; + } + + if ($queryString) { + $offset = CRM_Utils_Array::value('offset', $_GET, 0); + $rowCount = CRM_Utils_Array::value('rowcount', $_GET, 20); + + // add acl clause here + list($aclFrom, $aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause('cc'); + if ($aclWhere) { + $aclWhere = " AND $aclWhere"; + } + if ($noemail) { + $query = " +SELECT sort_name name, cc.id +FROM civicrm_contact cc + {$aclFrom} +WHERE cc.is_deceased = 0 AND {$queryString} + {$aclWhere} +LIMIT {$offset}, {$rowCount} +"; + + // send query to hook to be modified if needed + CRM_Utils_Hook::contactListQuery($query, + $name, + CRM_Utils_Array::value('context', $_GET), + CRM_Utils_Array::value('cid', $_GET) + ); + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $result[] = array( + 'name' => $dao->name, + 'id' => $dao->id, + ); + } + } + else { + $query = " +SELECT sort_name name, ce.email, cc.id +FROM civicrm_email ce INNER JOIN civicrm_contact cc ON cc.id = ce.contact_id + {$aclFrom} +WHERE ce.on_hold = 0 AND cc.is_deceased = 0 AND cc.do_not_email = 0 AND {$queryString} + {$aclWhere} +LIMIT {$offset}, {$rowCount} +"; + + // send query to hook to be modified if needed + CRM_Utils_Hook::contactListQuery($query, + $name, + CRM_Utils_Array::value('context', $_GET), + CRM_Utils_Array::value('cid', $_GET) + ); + + + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $result[] = array( + 'name' => '"' . $dao->name . '" <' . $dao->email . '>', + 'id' => (CRM_Utils_Array::value('id', $_GET)) ? "{$dao->id}::{$dao->email}" : '"' . $dao->name . '" <' . $dao->email . '>', + ); + } + } + + if ($result) { + echo json_encode($result); + } + } + } + CRM_Utils_System::civiExit(); + } + + static function getContactPhone() { + + $queryString = NULL; + //check for mobile type + $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name'); + $mobileType = CRM_Utils_Array::value('Mobile', $phoneTypes); + + if ($name = CRM_Utils_Array::value('name', $_GET)) { + $name = CRM_Utils_Type::escape($name, 'String'); + $queryString = " ( cc.sort_name LIKE '%$name%' OR cp.phone LIKE '%$name%' ) "; + } + elseif ($cid = CRM_Utils_Array::value('cid', $_GET)) { + //check cid for interger + $contIDS = explode(',', $cid); + foreach ($contIDS as $contID) { + CRM_Utils_Type::escape($contID, 'Integer'); + } + $queryString = " cc.id IN ( $cid )"; + } + + if ($queryString) { + $offset = CRM_Utils_Array::value('offset', $_GET, 0); + $rowCount = CRM_Utils_Array::value('rowcount', $_GET, 20); + + // add acl clause here + list($aclFrom, $aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause('cc'); + if ($aclWhere) { + $aclWhere = " AND $aclWhere"; + } + + $query = " +SELECT sort_name name, cp.phone, cc.id +FROM civicrm_phone cp INNER JOIN civicrm_contact cc ON cc.id = cp.contact_id + {$aclFrom} +WHERE cc.is_deceased = 0 AND cc.do_not_sms = 0 AND cp.phone_type_id = {$mobileType} AND {$queryString} + {$aclWhere} +LIMIT {$offset}, {$rowCount} +"; + + // send query to hook to be modified if needed + CRM_Utils_Hook::contactListQuery($query, + $name, + CRM_Utils_Array::value('context', $_GET), + CRM_Utils_Array::value('cid', $_GET) + ); + + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $result[] = array( + 'name' => '"' . $dao->name . '" <' . $dao->phone . '>', + 'id' => (CRM_Utils_Array::value('id', $_GET)) ? "{$dao->id}::{$dao->phone}" : '"' . $dao->name . '" <' . $dao->phone . '>', + ); + } + } + + if ($result) { + echo json_encode($result); + } + CRM_Utils_System::civiExit(); + } + + + static function buildSubTypes() { + $parent = CRM_Utils_Array::value('parentId', $_REQUEST); + + switch ($parent) { + case 1: + $contactType = 'Individual'; + break; + + case 2: + $contactType = 'Household'; + break; + + case 4: + $contactType = 'Organization'; + break; + } + + $subTypes = CRM_Contact_BAO_ContactType::subTypePairs($contactType, FALSE, NULL); + asort($subTypes); + echo json_encode($subTypes); + CRM_Utils_System::civiExit(); + } + + static function buildDedupeRules() { + $parent = CRM_Utils_Array::value('parentId', $_REQUEST); + + switch ($parent) { + case 1: + $contactType = 'Individual'; + break; + + case 2: + $contactType = 'Household'; + break; + + case 4: + $contactType = 'Organization'; + break; + } + + $dedupeRules = CRM_Dedupe_BAO_RuleGroup::getByType($contactType); + + echo json_encode($dedupeRules); + CRM_Utils_System::civiExit(); + } + + /** + * Function used for CiviCRM dashboard operations + */ + static function dashboard() { + $operation = CRM_Utils_Type::escape($_REQUEST['op'], 'String'); + + switch ($operation) { + case 'get_widgets_by_column': + // This would normally be coming from either the database (this user's settings) or a default/initial dashboard configuration. + // get contact id of logged in user + + $dashlets = CRM_Core_BAO_Dashboard::getContactDashlets(); + break; + + case 'get_widget': + $dashletID = CRM_Utils_Type::escape($_GET['id'], 'Positive'); + + $dashlets = CRM_Core_BAO_Dashboard::getDashletInfo($dashletID); + break; + + case 'save_columns': + CRM_Core_BAO_Dashboard::saveDashletChanges($_REQUEST['columns']); + CRM_Utils_System::civiExit(); + case 'delete_dashlet': + $dashletID = CRM_Utils_Type::escape($_REQUEST['dashlet_id'], 'Positive'); + CRM_Core_BAO_Dashboard::deleteDashlet($dashletID); + CRM_Utils_System::civiExit(); + } + + echo json_encode($dashlets); + CRM_Utils_System::civiExit(); + } + + /** + * Function to retrieve signature based on email id + */ + static function getSignature() { + $emailID = CRM_Utils_Type::escape($_REQUEST['emailID'], 'Positive'); + $query = "SELECT signature_text, signature_html FROM civicrm_email WHERE id = {$emailID}"; + $dao = CRM_Core_DAO::executeQuery($query); + + $signatures = array(); + while ($dao->fetch()) { + $signatures = array( + 'signature_text' => $dao->signature_text, + 'signature_html' => $dao->signature_html, + ); + } + + echo json_encode($signatures); + CRM_Utils_System::civiExit(); + } + + static function relationshipContacts() { + $searchValues = $searchRows = array(); + $addCount = 0; + + $relType = CRM_Utils_Type::escape($_REQUEST['relType'], 'String'); + $typeName = isset($_REQUEST['typeName']) ? CRM_Utils_Type::escape($_REQUEST['typeName'], 'String') : ''; + $relContact = CRM_Utils_Type::escape($_REQUEST['relContact'], 'String'); + $currentContactId = CRM_Utils_Type::escape($_REQUEST['cid'], 'Integer'); + + if (in_array($typeName, array( + 'Employee of', 'Employer of'))) { + $addCount = 1; + } + + $sortMapper = array( + 1 => 'sort_name', (2 + $addCount) => 'city', (3 + $addCount) => 'state_province', + (4 + $addCount) => 'email', (5 + $addCount) => 'phone', + ); + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? $sortMapper[CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer')] : 'sort_name'; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $searchValues[] = array('sort_name', 'LIKE', $relContact, 0, 1); + + list($rid, $direction) = explode('_', $relType, 2); + + $relationshipType = new CRM_Contact_DAO_RelationshipType(); + + $relationshipType->id = $rid; + if ($relationshipType->find(TRUE)) { + if ($direction == 'a_b') { + $type = $relationshipType->contact_type_b; + $subType = $relationshipType->contact_sub_type_b; + } + else { + $type = $relationshipType->contact_type_a; + $subType = $relationshipType->contact_sub_type_a; + } + + if ($type == 'Individual' || $type == 'Organization' || $type == 'Household') { + $searchValues[] = array('contact_type', '=', $type, 0, 0); + } + + if ($subType) { + $searchValues[] = array('contact_sub_type', '=', $subType, 0, 0); + } + } + + // exclude current contact + $searchValues[] = array('contact_id', '!=', $currentContactId, 0, 0); + + $query = new CRM_Contact_BAO_Query($searchValues); + $searchCount = $query->searchQuery(0, 0, NULL, TRUE); + $iTotal = $searchCount; + + if ($searchCount > 0) { + // get the result of the search + $result = $query->searchQuery($offset, $rowCount, $sort, FALSE, FALSE, + FALSE, FALSE, FALSE, NULL, $sortOrder + ); + + $config = CRM_Core_Config::singleton(); + + while ($result->fetch()) { + $contactID = $result->contact_id; + $typeImage = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type, + FALSE, $contactID + ); + + $searchRows[$contactID]['id'] = $contactID; + $searchRows[$contactID]['name'] = $typeImage . ' ' . $result->sort_name; + $searchRows[$contactID]['city'] = $result->city; + $searchRows[$contactID]['state'] = $result->state_province; + $searchRows[$contactID]['email'] = $result->email; + $searchRows[$contactID]['phone'] = $result->phone; + } + } + + foreach ($searchRows as $cid => $row) { + $searchRows[$cid]['check'] = ''; + + if ($typeName == 'Employee of') { + $searchRows[$cid]['employee_of'] = ''; + } + elseif ($typeName == 'Employer of') { + $searchRows[$cid]['employer_of'] = ''; + } + } + + $selectorElements = array('check', 'name'); + if ($typeName == 'Employee of') { + $selectorElements[] = 'employee_of'; + } + elseif ($typeName == 'Employer of') { + $selectorElements[] = 'employer_of'; + } + $selectorElements = array_merge($selectorElements, array('city', 'state', 'email', 'phone')); + + $iFilteredTotal = $iTotal; + echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + CRM_Utils_System::civiExit(); + } + + /** + * Function to process dupes. + * + */ + static function processDupes() { + $oper = CRM_Utils_Type::escape($_REQUEST['op'], 'String'); + $cid = CRM_Utils_Type::escape($_REQUEST['cid'], 'Positive'); + $oid = CRM_Utils_Type::escape($_REQUEST['oid'], 'Positive'); + + if (!$oper || !$cid || !$oid) { + return; + } + + $exception = new CRM_Dedupe_DAO_Exception(); + $exception->contact_id1 = $cid; + $exception->contact_id2 = $oid; + //make sure contact2 > contact1. + if ($cid > $oid) { + $exception->contact_id1 = $oid; + $exception->contact_id2 = $cid; + } + $exception->find(TRUE); + $status = NULL; + if ($oper == 'dupe-nondupe') { + $status = $exception->save(); + } + if ($oper == 'nondupe-dupe') { + $status = $exception->delete(); + } + + echo json_encode(array('status' => ($status) ? $oper : $status)); + CRM_Utils_System::civiExit(); + } + + static function getDedupes() { + + $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer'); + $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0; + $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25; + $sort = isset($_REQUEST['iSortCol_0']) ? $sortMapper[CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer')] : 'sort_name'; + $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc'; + + $gid = isset($_REQUEST['gid']) ? CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer') : 0; + $rgid = isset($_REQUEST['rgid']) ? CRM_Utils_Type::escape($_REQUEST['rgid'], 'Integer') : 0; + $contactType = ''; + if ($rgid) { + $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type'); + } + + $cacheKeyString = "merge {$contactType}_{$rgid}_{$gid}"; + $searchRows = array(); + $selectorElements = array('src', 'dst', 'weight', 'actions'); + + + $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND + pn.entity_id2 = de.contact_id2 )"; + $where = "de.id IS NULL"; + + $iFilteredTotal = $iTotal = CRM_Core_BAO_PrevNextCache::getCount($cacheKeyString, $join, $where); + $mainContacts = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where, $offset, $rowCount); + + foreach ($mainContacts as $mainId => $main) { + $searchRows[$mainId]['src'] = CRM_Utils_System::href($main['srcName'], 'civicrm/contact/view', "reset=1&cid={$main['srcID']}"); + $searchRows[$mainId]['dst'] = CRM_Utils_System::href($main['dstName'], 'civicrm/contact/view', "reset=1&cid={$main['dstID']}"); + $searchRows[$mainId]['weight'] = CRM_Utils_Array::value('weight', $main); + + if (CRM_Utils_Array::value('canMerge', $main)) { + $mergeParams = "reset=1&cid={$main['srcID']}&oid={$main['dstID']}&action=update&rgid={$rgid}"; + if ($gid) { + $mergeParams .= "&gid={$gid}"; + } + + $searchRows[$mainId]['actions'] = CRM_Utils_System::href(ts('merge'), 'civicrm/contact/merge', $mergeParams); + $searchRows[$mainId]['actions'] .= " |  " . ts('not a duplicate') . ""; + } + else { + $searchRows[$mainId]['actions'] = '' . ts('Insufficient access rights - cannot merge') . ''; + } + } + + echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements); + + CRM_Utils_System::civiExit(); + } + + /** + * Function to retrieve a PDF Page Format for the PDF Letter form + */ + function pdfFormat() { + $formatId = CRM_Utils_Type::escape($_REQUEST['formatId'], 'Integer'); + + $pdfFormat = CRM_Core_BAO_PdfFormat::getById($formatId); + + echo json_encode($pdfFormat); + CRM_Utils_System::civiExit(); + } + + /** + * Function to retrieve Paper Size dimensions + */ + function paperSize() { + $paperSizeName = CRM_Utils_Type::escape($_REQUEST['paperSizeName'], 'String'); + + $paperSize = CRM_Core_BAO_PaperSize::getByName($paperSizeName); + + echo json_encode($paperSize); + CRM_Utils_System::civiExit(); + } + + static function relationshipContactTypeList() { + $relType = CRM_Utils_Array::value('relType', $_REQUEST); + + $types = CRM_Contact_BAO_Relationship::getValidContactTypeList($relType); + + $elements = array(); + foreach ($types as $key => $label) { + $elements[] = array( + 'name' => $label, + 'value' => $key, + ); + } + + echo json_encode($elements); + CRM_Utils_System::civiExit(); + } + + static function selectUnselectContacts() { + $name = CRM_Utils_Array::value('name', $_REQUEST); + $cacheKey = CRM_Utils_Array::value('qfKey', $_REQUEST); + $state = CRM_Utils_Array::value('state', $_REQUEST, 'checked'); + $variableType = CRM_Utils_Array::value('variableType', $_REQUEST, 'single'); + + $actionToPerform = CRM_Utils_Array::value('action', $_REQUEST, 'select'); + + if ($variableType == 'multiple') { + // action post value only works with multiple type variable + if ($name) { + //multiple names like mark_x_1-mark_x_2 where 1,2 are cids + $elements = explode('-', $name); + foreach ($elements as $key => $element) { + $elements[$key] = self::_convertToId($element); + } + CRM_Core_BAO_PrevNextCache::markSelection($cacheKey, $actionToPerform, $elements); + } + else { + CRM_Core_BAO_PrevNextCache::markSelection($cacheKey, $actionToPerform); + } + } + elseif ($variableType == 'single') { + $cId = self::_convertToId($name); + $action = ($state == 'checked') ? 'select' : 'unselect'; + CRM_Core_BAO_PrevNextCache::markSelection($cacheKey, $action, $cId); + } + $contactIds = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey); + $countSelectionCids = count($contactIds[$cacheKey]); + + $arrRet = array('getCount' => $countSelectionCids); + echo json_encode($arrRet); + CRM_Utils_System::civiExit(); + } + + static function _convertToId($name) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $cId = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + } + return $cId; + } + + static function getAddressDisplay() { + $contactId = CRM_Utils_Array::value('contact_id', $_REQUEST); + if (!$contactId) { + $addressVal["error_message"] = "no contact id found"; + } + else { + $entityBlock = + array( + 'contact_id' => $contactId, + 'entity_id' => $contactId, + ); + $addressVal = CRM_Core_BAO_Address::getValues($entityBlock); + } + + echo json_encode($addressVal); + CRM_Utils_System::civiExit(); + } +} diff --git a/CRM/Contact/Page/CustomSearch.php b/CRM/Contact/Page/CustomSearch.php new file mode 100644 index 0000000000..e395b9102c --- /dev/null +++ b/CRM/Contact/Page/CustomSearch.php @@ -0,0 +1,103 @@ +fetch()) { + if (trim($dao->description)) { + $rows[$dao->value] = $dao->description; + } + else { + $rows[$dao->value] = $dao->label; + } + } + return $rows; + } + + /** + * Browse all custom searches. + * + * @return content of the parents run method + * + */ + function browse() { + $rows = self::info(); + $this->assign('rows', $rows); + return parent::run(); + } + + /** + * run this page (figure out the action needed and perform it). + * + * @return void + */ + function run() { + $action = CRM_Utils_Request::retrieve('action', + 'String', + $this, FALSE, 'browse' + ); + + $this->assign('action', $action); + return $this->browse(); + } +} + diff --git a/CRM/Contact/Page/DashBoard.php b/CRM/Contact/Page/DashBoard.php new file mode 100644 index 0000000000..6576551f29 --- /dev/null +++ b/CRM/Contact/Page/DashBoard.php @@ -0,0 +1,121 @@ +addScriptFile('civicrm', 'packages/jquery/plugins/jquery.dashboard.js', 0, 'html-header', FALSE) + ->addStyleFile('civicrm', 'packages/jquery/css/dashboard.css'); + + $resetCache = CRM_Utils_Request::retrieve('resetCache', 'Positive', CRM_Core_DAO::$_nullObject); + + CRM_Utils_System::setTitle(ts('CiviCRM Home')); + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + + if ($resetCache) { + CRM_Core_BAO_Dashboard::resetDashletCache($contactID); + } + + // call hook to get html from other modules + // ignored but needed to prevent warnings + $contentPlacement = CRM_Utils_Hook::DASHBOARD_BELOW; + $html = CRM_Utils_Hook::dashboard($contactID, $contentPlacement); + if (is_array($html)) { + $this->assign_by_ref('hookContent', $html); + $this->assign('hookContentPlacement', $contentPlacement); + } + + //check that default FROM email address, owner (domain) organization name and default mailbox are configured. + $fromEmailOK = TRUE; + $ownerOrgOK = TRUE; + $defaultMailboxOK = TRUE; + + // Don't put up notices if user doesn't have administer CiviCRM permission + if (CRM_Core_Permission::check('administer CiviCRM')) { + $destination = CRM_Utils_System::url( + 'civicrm/dashboard', + 'reset=1', + FALSE, NULL, FALSE + ); + + $destination = urlencode($destination); + + list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(TRUE); + + if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') { + $fixEmailUrl = CRM_Utils_System::url("civicrm/admin/domain", "action=update&reset=1&civicrmDestination={$destination}"); + $this->assign('fixEmailUrl', $fixEmailUrl); + $fromEmailOK = FALSE; + } + + $domain = CRM_Core_BAO_Domain::getDomain(); + $domainName = $domain->name; + if (!$domainName || $domainName == 'Default Domain Name') { + $fixOrgUrl = CRM_Utils_System::url("civicrm/admin/domain", "action=update&reset=1&civicrmDestination={$destination}"); + $this->assign('fixOrgUrl', $fixOrgUrl); + $ownerOrgOK = FALSE; + } + + $config = CRM_Core_Config::singleton(); + if (in_array('CiviMail', $config->enableComponents) && + CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG" + ) { + $fixDefaultMailbox = CRM_Utils_System::url('civicrm/admin/mailSettings', "reset=1&civicrmDestination={$destination}"); + $this->assign('fixDefaultMailbox', $fixDefaultMailbox); + $defaultMailboxOK = FALSE; + } + } + + $this->assign('fromEmailOK', $fromEmailOK); + $this->assign('ownerOrgOK', $ownerOrgOK); + $this->assign('defaultMailboxOK', $defaultMailboxOK); + + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/Dashlet.php b/CRM/Contact/Page/Dashlet.php new file mode 100644 index 0000000000..606c49ef62 --- /dev/null +++ b/CRM/Contact/Page/Dashlet.php @@ -0,0 +1,86 @@ +assign('admin', CRM_Core_Permission::check('administer CiviCRM')); + + // get all dashlets + $allDashlets = CRM_Core_BAO_Dashboard::getDashlets(FALSE); + + // get dashlets for logged in contact + $currentDashlets = CRM_Core_BAO_Dashboard::getContactDashlets(); + $contactDashlets = $availableDashlets = array(); + + foreach ($currentDashlets as $columnNo => $values) { + foreach ($values as $val => $isMinimized) { + list($weight, $dashletID) = explode('-', $val); + $key = "{$dashletID}-{$isMinimized}"; + $contactDashlets[$columnNo][$key] = array( + 'label' => $allDashlets[$dashletID]['label'], + 'is_reserved' => $allDashlets[$dashletID]['is_reserved'], + ); + unset($allDashlets[$dashletID]); + } + } + + foreach ($allDashlets as $dashletID => $values) { + $key = "{$dashletID}-0"; + $availableDashlets[$key] = array( + 'label' => $values['label'], + 'is_reserved' => $values['is_reserved'], + ); + } + + $this->assign('contactDashlets', $contactDashlets); + $this->assign('availableDashlets', $availableDashlets); + + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/DedupeException.php b/CRM/Contact/Page/DedupeException.php new file mode 100644 index 0000000000..201f9aa1e9 --- /dev/null +++ b/CRM/Contact/Page/DedupeException.php @@ -0,0 +1,93 @@ +find(); + $contactIds = array(); + while ($exception->fetch()) { + $key = "{$exception->contact_id1}_{$exception->contact_id2}"; + $contactIds[$exception->contact_id1] = $exception->contact_id1; + $contactIds[$exception->contact_id2] = $exception->contact_id2; + $dedupeExceptions[$key] = array('main' => array('id' => $exception->contact_id1), + 'other' => array('id' => $exception->contact_id2), + ); + } + //get the dupe contacts display names. + if (!empty($dedupeExceptions)) { + $sql = 'select id, display_name from civicrm_contact where id IN ( ' . implode(', ', $contactIds) . ' )'; + $contact = CRM_Core_DAO::executeQuery($sql); + $displayNames = array(); + while ($contact->fetch()) { + $displayNames[$contact->id] = $contact->display_name; + } + foreach ($dedupeExceptions as $key => & $values) { + $values['main']['name'] = CRM_Utils_Array::value($values['main']['id'], $displayNames); + $values['other']['name'] = CRM_Utils_Array::value($values['other']['id'], $displayNames); + } + } + $this->assign('dedupeExceptions', $dedupeExceptions); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/DedupeFind.php b/CRM/Contact/Page/DedupeFind.php new file mode 100644 index 0000000000..1d93c62ae4 --- /dev/null +++ b/CRM/Contact/Page/DedupeFind.php @@ -0,0 +1,359 @@ +get('selectedSearchContactIds'); + if ($context == 'search' || !empty($contactIds)) { + $context = 'search'; + $this->assign('backURL', $session->readUserContext()); + } + + if ($action & CRM_Core_Action::RENEW) { + // empty cache + $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); + + if ($rgid) { + $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type'); + $cacheKeyString = "merge $contactType"; + $cacheKeyString .= $rgid ? "_{$rgid}" : '_0'; + $cacheKeyString .= $gid ? "_{$gid}" : '_0'; + CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKeyString); + } + $urlQry = "reset=1&action=update&rgid={$rgid}"; + if ($gid) { + $urlQry .= "&gid={$gid}"; + } + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry)); + } + elseif ($action & CRM_Core_Action::MAP) { + // do a batch merge if requested + $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); + $result = CRM_Dedupe_Merger::batchMerge($rgid, $gid, 'safe', TRUE, TRUE); + + $skippedCount = CRM_Utils_Request::retrieve('skipped', 'Positive', $this, FALSE, 0); + $skippedCount = $skippedCount + count($result['skipped']); + $mergedCount = CRM_Utils_Request::retrieve('merged', 'Positive', $this, FALSE, 0); + $mergedCount = $mergedCount + count($result['merged']); + + if (empty($result['merged']) && empty($result['skipped'])) { + $message = ''; + if ($mergedCount >= 1) { + $message = ts("%1 pairs of duplicates were merged", array(1 => $mergedCount)); + } + if ($skippedCount >= 1) { + $message = $message ? "{$message} and " : ''; + $message .= ts("%1 pairs of duplicates were skipped due to conflict", + array(1 => $skippedCount) + ); + } + $message .= ts(" during the batch merge process with safe mode."); + CRM_Core_Session::setStatus($message, ts('Merge Complete'), 'success'); + + $urlQry = "reset=1&action=update&rgid={$rgid}"; + if ($gid) { + $urlQry .= "&gid={$gid}"; + } + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry)); + } + else { + $urlQry = "reset=1&action=map&rgid={$rgid}"; + if ($gid) { + $urlQry .= "&gid={$gid}"; + } + $urlQry .= "&skipped={$skippedCount}&merged={$mergedCount}"; + CRM_Utils_System::jsRedirect( + CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry), + ts('Batch Merge Task in progress'), + ts('The batch merge task is still in progress. This page will be refreshed automatically.') + ); + } + } + + if ($action & CRM_Core_Action::UPDATE || + $action & CRM_Core_Action::BROWSE + ) { + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE, 0); + $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); + $this->action = CRM_Core_Action::UPDATE; + + //calculate the $contactType + if ($rgid) { + $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', + $rgid, + 'contact_type' + ); + } + + $sourceParams = 'snippet=4'; + if ($gid) { + $sourceParams .= "&gid={$gid}"; + } + if ($rgid) { + $sourceParams .= "&rgid={$rgid}"; + } + + $this->assign('sourceUrl', CRM_Utils_System::url('civicrm/ajax/dedupefind', $sourceParams, FALSE, NULL, FALSE)); + + //reload from cache table + $cacheKeyString = "merge $contactType"; + $cacheKeyString .= $rgid ? "_{$rgid}" : '_0'; + $cacheKeyString .= $gid ? "_{$gid}" : '_0'; + + $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND + pn.entity_id2 = de.contact_id2 )"; + $where = "de.id IS NULL"; + $this->_mainContacts = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where); + if (empty($this->_mainContacts)) { + if ($gid) { + $foundDupes = $this->get("dedupe_dupes_$gid"); + if (!$foundDupes) { + $foundDupes = CRM_Dedupe_Finder::dupesInGroup($rgid, $gid); + } + $this->set("dedupe_dupes_$gid", $foundDupes); + } + elseif (!empty($contactIds)) { + $foundDupes = $this->get("search_dedupe_dupes_$gid"); + if (!$foundDupes) { + $foundDupes = CRM_Dedupe_Finder::dupes($rgid, $contactIds); + } + $this->get("search_dedupe_dupes_$gid", $foundDupes); + } + else { + $foundDupes = $this->get('dedupe_dupes'); + if (!$foundDupes) { + $foundDupes = CRM_Dedupe_Finder::dupes($rgid); + } + $this->set('dedupe_dupes', $foundDupes); + } + if (!$foundDupes) { + $ruleGroup = new CRM_Dedupe_BAO_RuleGroup(); + $ruleGroup->id = $rgid; + $ruleGroup->find(TRUE); + + $session = CRM_Core_Session::singleton(); + $session->setStatus(ts('No possible duplicates were found using %1 rule.', array(1 => $ruleGroup->name)), ts('None Found'), 'info'); + $url = CRM_Utils_System::url('civicrm/contact/deduperules', 'reset=1'); + if ($context == 'search') { + $url = $session->readUserContext(); + } + CRM_Utils_System::redirect($url); + } + else { + $cids = array(); + foreach ($foundDupes as $dupe) { + $cids[$dupe[0]] = 1; + $cids[$dupe[1]] = 1; + } + $cidString = implode(', ', array_keys($cids)); + $sql = "SELECT id, display_name FROM civicrm_contact WHERE id IN ($cidString) ORDER BY sort_name"; + $dao = new CRM_Core_DAO(); + $dao->query($sql); + $displayNames = array(); + while ($dao->fetch()) { + $displayNames[$dao->id] = $dao->display_name; + } + + // FIXME: sort the contacts; $displayName + // is already sort_name-sorted, so use that + // (also, consider sorting by dupe count first) + // lobo - change the sort to by threshold value + // so the more likely dupes are sorted first + $session = CRM_Core_Session::singleton(); + $userId = $session->get('userID'); + $mainContacts = $permission = array(); + + foreach ($foundDupes as $dupes) { + $srcID = $dupes[0]; + $dstID = $dupes[1]; + if ($dstID == $userId) { + $srcID = $dupes[1]; + $dstID = $dupes[0]; + } + + /*** + * Eliminate this since it introduces 3 queries PER merge row + * and hence is very expensive + * CRM-8822 + if ( !array_key_exists( $srcID, $permission ) ) { + $permission[$srcID] = CRM_Contact_BAO_Contact_Permission::allow( $srcID, CRM_Core_Permission::EDIT ); + } + if ( !array_key_exists( $dstID, $permission ) ) { + $permission[$dstID] = CRM_Contact_BAO_Contact_Permission::allow( $dstID, CRM_Core_Permission::EDIT ); + } + + $canMerge = ( $permission[$dstID] && $permission[$srcID] ); + * + */ + + // we'll do permission checking during the merge process + $canMerge = TRUE; + + $mainContacts[] = $row = array( + 'srcID' => $srcID, + 'srcName' => $displayNames[$srcID], + 'dstID' => $dstID, + 'dstName' => $displayNames[$dstID], + 'weight' => $dupes[2], + 'canMerge' => $canMerge, + ); + + $data = CRM_Core_DAO::escapeString(serialize($row)); + $values[] = " ( 'civicrm_contact', $srcID, $dstID, '$cacheKeyString', '$data' ) "; + } + if ($cid) { + $this->_cid = $cid; + } + if ($gid) { + $this->_gid = $gid; + } + $this->_rgid = $rgid; + $this->_mainContacts = $mainContacts; + + CRM_Core_BAO_PrevNextCache::setItem($values); + $session = CRM_Core_Session::singleton(); + if ($this->_cid) { + $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/deduperules', + "action=update&rgid={$this->_rgid}&gid={$this->_gid}&cid={$this->_cid}" + )); + } + else { + $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/dedupefind', + "reset=1&action=update&rgid={$this->_rgid}" + )); + } + } + } + else { + if ($cid) { + $this->_cid = $cid; + } + if ($gid) { + $this->_gid = $gid; + } + $this->_rgid = $rgid; + } + + $this->assign('action', $this->action); + $this->browse(); + } + else { + $this->action = CRM_Core_Action::UPDATE; + $this->edit($this->action); + $this->assign('action', $this->action); + } + $this->assign('context', $context); + + // parent run + return parent::run(); + } + + /** + * Browse all rule groups + * + * @return void + * @access public + */ + function browse() { + $this->assign('main_contacts', $this->_mainContacts); + + if ($this->_cid) { + $this->assign('cid', $this->_cid); + } + if (isset($this->_gid) || $this->_gid) { + $this->assign('gid', $this->_gid); + } + $this->assign('rgid', $this->_rgid); + } + + /** + * Get name of edit form + * + * @return string classname of edit form + */ + function editForm() { + return 'CRM_Contact_Form_DedupeFind'; + } + + /** + * Get edit form name + * + * @return string name of this page + */ + function editName() { + return 'DedupeFind'; + } + + /** + * Get user context + * + * @return string user context + */ + function userContext($mode = NULL) { + return 'civicrm/contact/dedupefind'; + } +} + diff --git a/CRM/Contact/Page/DedupeRules.php b/CRM/Contact/Page/DedupeRules.php new file mode 100644 index 0000000000..9348041174 --- /dev/null +++ b/CRM/Contact/Page/DedupeRules.php @@ -0,0 +1,211 @@ + ts('Use Rule'), + 'url' => 'civicrm/contact/dedupefind', + 'qs' => 'reset=1&rgid=%%id%%&action=preview', + 'title' => ts('Use DedupeRule'), + ); + } + if (CRM_Core_Permission::check('administer dedupe rules')) { + $links[CRM_Core_Action::UPDATE] = array( + 'name' => ts('Edit Rule'), + 'url' => 'civicrm/contact/deduperules', + 'qs' => 'action=update&id=%%id%%', + 'title' => ts('Edit DedupeRule'), + ); + $links[CRM_Core_Action::DELETE] = array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/deduperules', + 'qs' => 'action=delete&id=%%id%%', + 'extra' => 'onclick = "return confirm(\'' . $deleteExtra . '\');"', + 'title' => ts('Delete DedupeRule'), + ); + } + + self::$_links = $links; + } + return self::$_links; + } + + /** + * Run the page + * + * This method is called after the page is created. It checks for the type + * of action and executes that action. Finally it calls the parent's run + * method. + * + * @return void + * @access public + * + */ + function run() { + // get the requested action, default to 'browse' + $action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, 0); + + $context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE); + if ($context == 'nonDupe') { + CRM_Core_Session::setStatus(ts('Selected contacts have been marked as not duplicates'), ts('Changes Saved'), 'success'); + } + + // assign permissions vars to template + $this->assign('hasperm_administer_dedupe_rules', CRM_Core_Permission::check('administer dedupe rules')); + $this->assign('hasperm_merge_duplicate_contacts', CRM_Core_Permission::check('merge duplicate contacts')); + + // which action to take? + if ($action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD)) { + $this->edit($action, $id); + } + if ($action & CRM_Core_Action::DELETE) { + $this->delete($id); + } + + // browse the rules + $this->browse(); + + // parent run + return parent::run(); + } + + /** + * Browse all rule groups + * + * @return void + * @access public + */ + function browse() { + // get all rule groups + $ruleGroups = array(); + $dao = new CRM_Dedupe_DAO_RuleGroup(); + $dao->orderBy('contact_type,used ASC'); + $dao->find(); + + while ($dao->fetch()) { + $ruleGroups[$dao->contact_type][$dao->id] = array(); + CRM_Core_DAO::storeValues($dao, $ruleGroups[$dao->contact_type][$dao->id]); + + // form all action links + $action = array_sum(array_keys($this->links())); + $links = self::links(); + /* if ($dao->is_default) { + unset($links[CRM_Core_Action::MAP]); + unset($links[CRM_Core_Action::DELETE]); + }*/ + + if ($dao->is_reserved) { + unset($links[CRM_Core_Action::DELETE]); + } + + $ruleGroups[$dao->contact_type][$dao->id]['action'] = CRM_Core_Action::formLink($links, $action, array('id' => $dao->id)); + CRM_Dedupe_DAO_RuleGroup::addDisplayEnums($ruleGroups[$dao->contact_type][$dao->id]); + } + + $this->assign('brows', $ruleGroups); + } + + /** + * Get name of edit form + * + * @return string classname of edit form + */ + function editForm() { + return 'CRM_Contact_Form_DedupeRules'; + } + + /** + * Get edit form name + * + * @return string name of this page + */ + function editName() { + return 'DedupeRules'; + } + + /** + * Get user context + * + * @return string user context + */ + function userContext($mode = NULL) { + return 'civicrm/contact/deduperules'; + } + + function delete($id) { + $ruleDao = new CRM_Dedupe_DAO_Rule(); + $ruleDao->dedupe_rule_group_id = $id; + $ruleDao->delete(); + + $rgDao = new CRM_Dedupe_DAO_RuleGroup(); + $rgDao->id = $id; + $rgDao->delete(); + } +} + diff --git a/CRM/Contact/Page/Inline/Actions.php b/CRM/Contact/Page/Inline/Actions.php new file mode 100644 index 0000000000..e209ff219d --- /dev/null +++ b/CRM/Contact/Page/Inline/Actions.php @@ -0,0 +1,73 @@ +assign('contactId', $contactId); + $this->assign('actionsMenuList', CRM_Contact_BAO_Contact::contextMenu($contactId)); + CRM_Contact_Page_View::addUrls($this, $contactId); + + // also create the form element for the activity links box + $controller = new CRM_Core_Controller_Simple('CRM_Activity_Form_ActivityLinks', + ts('Activity Links'), + NULL + ); + $controller->setEmbedded(TRUE); + $controller->run(); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/Address.php b/CRM/Contact/Page/Inline/Address.php new file mode 100644 index 0000000000..5385408801 --- /dev/null +++ b/CRM/Contact/Page/Inline/Address.php @@ -0,0 +1,122 @@ + 0 ) { + $locationTypes = CRM_Core_PseudoConstant::locationDisplayName(); + + $entityBlock = array('id' => $addressId); + $address = CRM_Core_BAO_Address::getValues($entityBlock, FALSE, 'id'); + if (!empty($address)) { + foreach ($address as $key =>& $value) { + $value['location_type'] = $locationTypes[$value['location_type_id']]; + } + } + } + + // we just need current address block + $currentAddressBlock['address'][$locBlockNo] = array_pop( $address ); + + if ( !empty( $currentAddressBlock['address'][$locBlockNo] ) ) { + // get contact name of shared contact names + $sharedAddresses = array(); + $shareAddressContactNames = CRM_Contact_BAO_Contact_Utils::getAddressShareContactNames($currentAddressBlock['address']); + foreach ($currentAddressBlock['address'] as $key => $addressValue) { + if (CRM_Utils_Array::value('master_id', $addressValue) && + !$shareAddressContactNames[$addressValue['master_id']]['is_deleted'] + ) { + $sharedAddresses[$key]['shared_address_display'] = array( + 'address' => $addressValue['display'], + 'name' => $shareAddressContactNames[$addressValue['master_id']]['name'], + ); + } + } + + // add custom data of type address + $groupTree = CRM_Core_BAO_CustomGroup::getTree( 'Address', + $this, $currentAddressBlock['address'][$locBlockNo]['id'] + ); + + // we setting the prefix to dnc_ below so that we don't overwrite smarty's grouptree var. + $currentAddressBlock['address'][$locBlockNo]['custom'] = CRM_Core_BAO_CustomGroup::buildCustomDataView( $this, $groupTree, FALSE, NULL, "dnc_"); + $this->assign("dnc_viewCustomData", NULL); + + $this->assign('add', $currentAddressBlock['address'][$locBlockNo]); + $this->assign('sharedAddresses', $sharedAddresses); + } + $contact = new CRM_Contact_BAO_Contact( ); + $contact->id = $contactId; + $contact->find(true); + $privacy = array( ); + foreach ( CRM_Contact_BAO_Contact::$_commPrefs as $name ) { + if ( isset( $contact->$name ) ) { + $privacy[$name] = $contact->$name; + } + } + + $this->assign('contactId', $contactId); + $this->assign('locationIndex', $locBlockNo); + $this->assign('addressId', $addressId); + $this->assign('privacy', $privacy); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/CommunicationPreferences.php b/CRM/Contact/Page/Inline/CommunicationPreferences.php new file mode 100644 index 0000000000..cd22caf4de --- /dev/null +++ b/CRM/Contact/Page/Inline/CommunicationPreferences.php @@ -0,0 +1,71 @@ + $contactId); + + $defaults = array(); + CRM_Contact_BAO_Contact::getValues( $params, $defaults ); + $defaults['privacy_values'] = CRM_Core_SelectValues::privacy(); + + $this->assign('contactId', $contactId); + $this->assign($defaults); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/ContactInfo.php b/CRM/Contact/Page/Inline/ContactInfo.php new file mode 100644 index 0000000000..950a1edd93 --- /dev/null +++ b/CRM/Contact/Page/Inline/ContactInfo.php @@ -0,0 +1,79 @@ + $contactId); + + $defaults = array(); + CRM_Contact_BAO_Contact::getValues( $params, $defaults ); + + //get the current employer name + if (CRM_Utils_Array::value('contact_type', $defaults) == 'Individual') { + if (CRM_Utils_Array::value('employer_id', $defaults) && + CRM_Utils_Array::value('organization_name', $defaults)) { + $defaults['current_employer'] = $defaults['organization_name']; + $defaults['current_employer_id'] = $defaults['employer_id']; + } + } + + $this->assign('contactId', $contactId); + $this->assign($defaults); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/ContactName.php b/CRM/Contact/Page/Inline/ContactName.php new file mode 100644 index 0000000000..7e10b3a8f6 --- /dev/null +++ b/CRM/Contact/Page/Inline/ContactName.php @@ -0,0 +1,76 @@ +assign('contactId', $contactId); + + $title = CRM_Contact_Page_View::setTitle($contactId, $isDeleted); + $this->assign('title', $title); + + // Check if this is default domain contact CRM-10482 + if (CRM_Contact_BAO_Contact::checkDomainContact($contactId)) { + $this->assign('domainContact', TRUE); + } else { + $this->assign('domainContact', FALSE); + } + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/CustomData.php b/CRM/Contact/Page/Inline/CustomData.php new file mode 100644 index 0000000000..3eb0e48e60 --- /dev/null +++ b/CRM/Contact/Page/Inline/CustomData.php @@ -0,0 +1,77 @@ +assign('contactId', $contactId); + $this->assign('customGroupId', $cgId); + $this->assign_by_ref('cd_edit', $fields); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/Demographics.php b/CRM/Contact/Page/Inline/Demographics.php new file mode 100644 index 0000000000..057c393085 --- /dev/null +++ b/CRM/Contact/Page/Inline/Demographics.php @@ -0,0 +1,78 @@ + $contactId); + + $defaults = array(); + CRM_Contact_BAO_Contact::getValues( $params, $defaults ); + + if (CRM_Utils_Array::value('gender_id', $defaults)) { + $gender = CRM_Core_PseudoConstant::gender(); + $defaults['gender_display'] = $gender[CRM_Utils_Array::value('gender_id', $defaults)]; + } + + $this->assign('contactId', $contactId); + $this->assign($defaults); + + //for birthdate format with respect to birth format set + $this->assign('birthDateViewFormat', CRM_Utils_Array::value('qfMapping', CRM_Utils_Date::checkBirthDateFormat())); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/Email.php b/CRM/Contact/Page/Inline/Email.php new file mode 100644 index 0000000000..f679bf0ccd --- /dev/null +++ b/CRM/Contact/Page/Inline/Email.php @@ -0,0 +1,86 @@ + $contactId); + $emails = CRM_Core_BAO_Email::getValues($entityBlock); + if (!empty($emails)) { + foreach ($emails as $key => & $value) { + $value['location_type'] = $locationTypes[$value['location_type_id']]; + } + } + + $contact = new CRM_Contact_BAO_Contact( ); + $contact->id = $contactId; + $contact->find(true); + $privacy = array( ); + foreach ( CRM_Contact_BAO_Contact::$_commPrefs as $name ) { + if ( isset( $contact->$name ) ) { + $privacy[$name] = $contact->$name; + } + } + + $this->assign('contactId', $contactId); + $this->assign('email', $emails); + $this->assign('privacy', $privacy); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/IM.php b/CRM/Contact/Page/Inline/IM.php new file mode 100644 index 0000000000..39fc657c94 --- /dev/null +++ b/CRM/Contact/Page/Inline/IM.php @@ -0,0 +1,77 @@ + $contactId); + $ims = CRM_Core_BAO_IM::getValues($entityBlock); + if (!empty($ims)) { + foreach ($ims as $key => & $value) { + $value['location_type'] = $locationTypes[$value['location_type_id']]; + $value['provider'] = $IMProviders[$value['provider_id']]; + } + } + + $this->assign('contactId', $contactId); + $this->assign('im', $ims); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/OpenID.php b/CRM/Contact/Page/Inline/OpenID.php new file mode 100644 index 0000000000..fc04626b12 --- /dev/null +++ b/CRM/Contact/Page/Inline/OpenID.php @@ -0,0 +1,75 @@ + $contactId); + $openids = CRM_Core_BAO_OpenID::getValues($entityBlock); + if (!empty($openids)) { + foreach ($openids as $key => & $value) { + $value['location_type'] = $locationTypes[$value['location_type_id']]; + } + } + + $this->assign('contactId', $contactId); + $this->assign('openid', $openids); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/Phone.php b/CRM/Contact/Page/Inline/Phone.php new file mode 100644 index 0000000000..b93e6d043e --- /dev/null +++ b/CRM/Contact/Page/Inline/Phone.php @@ -0,0 +1,88 @@ + $contactId); + $phones = CRM_Core_BAO_Phone::getValues($entityBlock); + if (!empty($phones)) { + foreach ($phones as $key => & $value) { + $value['location_type'] = $locationTypes[$value['location_type_id']]; + $value['phone_type'] = $phoneTypes[$value['phone_type_id']]; + } + } + + $contact = new CRM_Contact_BAO_Contact( ); + $contact->id = $contactId; + $contact->find(true); + $privacy = array( ); + foreach ( CRM_Contact_BAO_Contact::$_commPrefs as $name ) { + if ( isset( $contact->$name ) ) { + $privacy[$name] = $contact->$name; + } + } + + $this->assign('contactId', $contactId); + $this->assign('phone', $phones); + $this->assign('privacy', $privacy); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/Inline/Website.php b/CRM/Contact/Page/Inline/Website.php new file mode 100644 index 0000000000..4a48c3b618 --- /dev/null +++ b/CRM/Contact/Page/Inline/Website.php @@ -0,0 +1,75 @@ + $contactId); + $websites = CRM_Core_BAO_Website::getValues($params, CRM_Core_DAO::$_nullArray); + if (!empty($websites)) { + foreach ($websites as $key => & $value) { + $value['website_type'] = $websiteTypes[$value['website_type_id']]; + } + } + + $this->assign('contactId', $contactId); + $this->assign('website', $websites); + + // check logged in user permission + CRM_Contact_Page_View::checkUserPermission($this, $contactId); + + // finally call parent + parent::run(); + } +} + diff --git a/CRM/Contact/Page/SavedSearch.php b/CRM/Contact/Page/SavedSearch.php new file mode 100644 index 0000000000..a6729febf5 --- /dev/null +++ b/CRM/Contact/Page/SavedSearch.php @@ -0,0 +1,169 @@ +saved_search_id = $id; + if ($group->find(TRUE)) { + CRM_Contact_BAO_Group::discard($group->id); + } + + $savedSearch = new CRM_Contact_DAO_SavedSearch(); + $savedSearch->id = $id; + $savedSearch->is_active = 0; + $savedSearch->save(); + return; + } + + /** + * Browse all saved searches. + * + * @return content of the parents run method + * + */ + function browse() { + $rows = array(); + + $savedSearch = new CRM_Contact_DAO_SavedSearch(); + $savedSearch->is_active = 1; + $savedSearch->selectAdd(); + $savedSearch->selectAdd('id, form_values'); + $savedSearch->find(); + $properties = array('id', 'name', 'description'); + while ($savedSearch->fetch()) { + // get name and description from group object + $group = new CRM_Contact_DAO_Group(); + $group->saved_search_id = $savedSearch->id; + if ($group->find(TRUE)) { + $permissions = CRM_Group_Page_Group::checkPermission($group->id, $group->title); + if (!CRM_Utils_System::isNull($permissions)) { + $row = array(); + + $row['name'] = $group->title; + $row['description'] = $group->description; + + $row['id'] = $savedSearch->id; + $formValues = unserialize($savedSearch->form_values); + $query = new CRM_Contact_BAO_Query($formValues); + $row['query_detail'] = $query->qill(); + + $action = array_sum(array_keys(self::links())); + $action = $action & CRM_Core_Action::mask($permissions); + $row['action'] = CRM_Core_Action::formLink(self::links(), $action, array('id' => $row['id'])); + + $rows[] = $row; + } + } + } + + $this->assign('rows', $rows); + return parent::run(); + } + + /** + * run this page (figure out the action needed and perform it). + * + * @return void + */ + function run() { + $action = CRM_Utils_Request::retrieve('action', 'String', + $this, FALSE, 'browse' + ); + + $this->assign('action', $action); + + if ($action & CRM_Core_Action::DELETE) { + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, TRUE + ); + $this->delete($id); + } + $this->browse(); + } + + /** + * Get action Links + * + * @return array (reference) of action links + * @static + */ + static function &links() { + + if (!(self::$_links)) { + + $deleteExtra = ts('Do you really want to remove this Smart Group?'); + + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('Search'), + 'url' => 'civicrm/contact/search/advanced', + 'qs' => 'reset=1&force=1&ssID=%%id%%', + 'title' => ts('Search'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/search/saved', + 'qs' => 'action=delete&id=%%id%%', + 'extra' => 'onclick="return confirm(\'' . $deleteExtra . '\');"', + ), + ); + } + return self::$_links; + } +} + diff --git a/CRM/Contact/Page/Task.php b/CRM/Contact/Page/Task.php new file mode 100644 index 0000000000..293cb47fa5 --- /dev/null +++ b/CRM/Contact/Page/Task.php @@ -0,0 +1,55 @@ +_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $this->assign('id', $this->_id); + + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + //validate the qfKey + if (!CRM_Utils_Rule::qfKey($qfKey)) { + $qfKey = NULL; + } + $this->assign('searchKey', $qfKey); + + // retrieve the group contact id, so that we can get contact id + $gcid = CRM_Utils_Request::retrieve('gcid', 'Positive', $this); + + if (!$gcid) { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + } + else { + $this->_contactId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_GroupContact', $gcid, 'contact_id'); + } + + if (!$this->_contactId) { + CRM_Core_Error::statusBounce( + ts('We could not find a contact id.'), + CRM_Utils_System::url('civicrm/dashboard', 'reset=1') + ); + } + + // ensure that the id does exist + if ( CRM_Core_DAO::getFieldValue( 'CRM_Contact_DAO_Contact', $this->_contactId, 'id' ) != $this->_contactId ) { + CRM_Core_Error::statusBounce( + ts('A Contact with that ID does not exist: %1', array(1 => $this->_contactId)), + CRM_Utils_System::url('civicrm/dashboard', 'reset=1') + ); + } + + $this->assign('contactId', $this->_contactId); + + // see if we can get prev/next positions from qfKey + $navContacts = array( + 'prevContactID' => NULL, + 'prevContactName' => NULL, + 'nextContactID' => NULL, + 'nextContactName' => NULL, + 'nextPrevError' => 0, + ); + if ($qfKey) { + $pos = CRM_Core_BAO_PrevNextCache::getPositions("civicrm search $qfKey", + $this->_contactId, + $this->_contactId + ); + $found = FALSE; + + if (isset($pos['prev'])) { + $navContacts['prevContactID'] = $pos['prev']['id1']; + $navContacts['prevContactName'] = $pos['prev']['data']; + $found = TRUE; + } + + if (isset($pos['next'])) { + $navContacts['nextContactID'] = $pos['next']['id1']; + $navContacts['nextContactName'] = $pos['next']['data']; + $found = TRUE; + } + + if (!$found) { + // seems like we did not find any contacts + // maybe due to bug CRM-9096 + // however we should account for 1 contact results (which dont have prev next) + if (!$pos['foundEntry']) { + $navContacts['nextPrevError'] = 1; + } + } + } + $this->assign($navContacts); + + $path = CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $this->_contactId); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('View Contact'), + 'url' => $path, + ))); + CRM_Utils_System::appendBreadCrumb(array(array('title' => ts('Search Results'), + 'url' => self::getSearchURL(), + ))); + + if ($image_URL = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactId, 'image_URL')) { + + //CRM-7265 --time being fix. + $config = CRM_Core_Config::singleton(); + $image_URL = str_replace('https://', 'http://', $image_URL); + if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'enableSSL')) { + $image_URL = str_replace('http://', 'https://', $image_URL); + } + + list($imageWidth, $imageHeight) = getimagesize($image_URL); + list($imageThumbWidth, $imageThumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($imageWidth, $imageHeight); + $this->assign("imageWidth", $imageWidth); + $this->assign("imageHeight", $imageHeight); + $this->assign("imageThumbWidth", $imageThumbWidth); + $this->assign("imageThumbHeight", $imageThumbHeight); + $this->assign("imageURL", $image_URL); + } + + // also store in session for future use + $session = CRM_Core_Session::singleton(); + $session->set('view.id', $this->_contactId); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + + // check logged in user permission + self::checkUserPermission($this); + + list($displayName, $contactImage, + $contactType, $contactSubtype, $contactImageUrl + ) = self::getContactDetails($this->_contactId); + $this->assign('displayName', $displayName); + + $this->set('contactType', $contactType); + $this->set('contactSubtype', $contactSubtype); + + // add to recently viewed block + $isDeleted = (bool) CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactId, 'is_deleted'); + + $recentOther = array( + 'imageUrl' => $contactImageUrl, + 'subtype' => $contactSubtype, + 'isDeleted' => $isDeleted, + ); + + if (($session->get('userID') == $this->_contactId) || + CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT) + ) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/contact/add', "reset=1&action=update&cid={$this->_contactId}"); + } + + if (($session->get('userID') != $this->_contactId) && CRM_Core_Permission::check('delete contacts') + && !$isDeleted + ) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/delete', "reset=1&delete=1&cid={$this->_contactId}"); + } + + CRM_Utils_Recent::add($displayName, + CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactId}"), + $this->_contactId, + $contactType, + $this->_contactId, + $displayName, + $recentOther + ); + $this->assign('isDeleted', $isDeleted); + + // set page title + $title = self::setTitle($this->_contactId, $isDeleted); + $this->assign('title', $title); + + // Check if this is default domain contact CRM-10482 + if (CRM_Contact_BAO_Contact::checkDomainContact($this->_contactId)) { + $this->assign('domainContact', TRUE); + } else { + $this->assign('domainContact', FALSE); + } + + // Add links for actions menu + self::addUrls($this, $this->_contactId); + + if ($contactType == 'Organization' && + CRM_Core_Permission::check('administer Multiple Organizations') && + CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'is_enabled' + ) + ) { + //check is any relationship between the organization and groups + $groupOrg = CRM_Contact_BAO_GroupOrganization::hasGroupAssociated($this->_contactId); + if ($groupOrg) { + $groupOrganizationUrl = CRM_Utils_System::url('civicrm/group', + "reset=1&oid={$this->_contactId}" + ); + $this->assign('groupOrganizationUrl', $groupOrganizationUrl); + } + } + } + + /** + * Get meta details of the contact. + * + * @return array contact fields in fixed order + * @access public + */ + static function getContactDetails($contactId) { + return list($displayName, + $contactImage, + $contactType, + $contactSubtype, + $contactImageUrl + ) = CRM_Contact_BAO_Contact::getDisplayAndImage($contactId, + TRUE, + TRUE + ); + } + + function getSearchURL() { + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + $context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'search'); + $this->assign('context', $context); + + //validate the qfKey + if (!CRM_Utils_Rule::qfKey($qfKey)) { + $qfKey = NULL; + } + + $urlString = NULL; + $urlParams = 'force=1'; + + switch ($context) { + case 'custom': + $urlString = 'civicrm/contact/search/custom'; + break; + + case 'fulltext': + $urlString = 'civicrm/contact/search/custom'; + if ( $qfKey ) { + $urlParams = '_qf_Custom_display=true'; + } + break; + + case 'advanced': + $urlString = 'civicrm/contact/search/advanced'; + break; + + case 'builder': + $urlString = 'civicrm/contact/search/builder'; + break; + + case 'basic': + $urlString = 'civicrm/contact/search/basic'; + break; + + case 'search': + $urlString = 'civicrm/contact/search'; + break; + + case 'smog': + case 'amtg': + $urlString = 'civicrm/group/search'; + break; + } + if ($qfKey) { + $urlParams .= "&qfKey=$qfKey"; + } + if (!$urlString) { + $urlString = 'civicrm/contact/search/basic'; + } + + return CRM_Utils_System::url($urlString, $urlParams); + } + + static function checkUserPermission($page, $contactID = NULL) { + // check for permissions + $page->_permission = NULL; + + if (!$contactID) { + $contactID = $page->_contactId; + } + + // automatically grant permissin for users on their own record. makes + // things easier in dashboard + $session = CRM_Core_Session::singleton(); + + if ($session->get('userID') == $contactID) { + $page->assign('permission', 'edit'); + $page->_permission = CRM_Core_Permission::EDIT; + // deleted contacts’ stuff should be (at best) only viewable + } + elseif (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'is_deleted') and CRM_Core_Permission::check('access deleted contacts')) { + $page->assign('permission', 'view'); + $page->_permission = CRM_Core_Permission::VIEW; + } + elseif (CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::EDIT)) { + $page->assign('permission', 'edit'); + $page->_permission = CRM_Core_Permission::EDIT; + } + elseif (CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::VIEW)) { + $page->assign('permission', 'view'); + $page->_permission = CRM_Core_Permission::VIEW; + } + else { + $session->pushUserContext(CRM_Utils_System::url('civicrm', 'reset=1')); + CRM_Core_Error::statusBounce(ts('You do not have the necessary permission to view this contact.')); + } + } + + static function setTitle($contactId, $isDeleted = FALSE) { + static $contactDetails; + $displayName = $contactImage = NULL; + if (!isset($contactDetails[$contactId])) { + list($displayName, $contactImage) = self::getContactDetails($contactId); + $contactDetails[$contactId] = array( + 'displayName' => $displayName, + 'contactImage' => $contactImage, + ); + } + else { + $displayName = $contactDetails[$contactId]['displayName']; + $contactImage = $contactDetails[$contactId]['contactImage']; + } + + // set page title + $title = "{$contactImage} {$displayName}"; + if ($isDeleted) { + $title = "{$title}"; + } + + // Inline-edit places its own title on the page + CRM_Utils_System::setTitle('CiviCRM', ''); + + return $title; + } + + /** + * Add urls for display in the actions menu + */ + static function addUrls(&$obj, $cid) { + $config = CRM_Core_Config::singleton(); + $session = CRM_Core_Session::singleton(); + $uid = CRM_Core_BAO_UFMatch::getUFId($cid); + if ($uid) { + // To do: we should also allow drupal users with CRM_Core_Permission::check( 'view user profiles' ) true to access $userRecordUrl + // but this is currently returning false regardless of permission set for the role. dgg + if ($config->userSystem->is_drupal == '1' && + ($session->get('userID') == $cid || CRM_Core_Permission::check('administer users')) + ) { + $userRecordUrl = CRM_Utils_System::url('user/' . $uid); + } + elseif ($config->userFramework == 'Joomla') { + $userRecordUrl = NULL; + // if logged in user is super user, then he can view other users joomla profile + if (JFactory::getUser()->authorise('core.admin')) { + $userRecordUrl = $config->userFrameworkBaseURL . "index.php?option=com_users&view=user&task=user.edit&id=" . $uid; + } + elseif ($session->get('userID') == $cid) { + $userRecordUrl = $config->userFrameworkBaseURL . "index.php?option=com_admin&view=profile&layout=edit&id=" . $uid; + } + } + else { + $userRecordUrl = NULL; + } + $obj->assign('userRecordUrl', $userRecordUrl); + $obj->assign('userRecordId', $uid); + } + elseif (($config->userSystem->is_drupal == '1' && CRM_Core_Permission::check('administer users')) || + ($config->userFramework == 'Joomla' && + JFactory::getUser()->authorise('core.create', 'com_users') + ) + ) { + $userAddUrl = CRM_Utils_System::url('civicrm/contact/view/useradd', + 'reset=1&action=add&cid=' . $cid + ); + $obj->assign('userAddUrl', $userAddUrl); + } + + if (CRM_Core_Permission::check('access Contact Dashboard')) { + $dashboardURL = CRM_Utils_System::url('civicrm/user', + "reset=1&id={$cid}" + ); + $obj->assign('dashboardURL', $dashboardURL); + } + + // See if other modules want to add links to the activtity bar + $hookLinks = CRM_Utils_Hook::links('view.contact.activity', + 'Contact', + $cid, + CRM_Core_DAO::$_nullObject, + CRM_Core_DAO::$_nullObject + ); + if (is_array($hookLinks)) { + $obj->assign('hookLinks', $hookLinks); + } + } +} + diff --git a/CRM/Contact/Page/View/CustomData.php b/CRM/Contact/Page/View/CustomData.php new file mode 100644 index 0000000000..62ba165aac --- /dev/null +++ b/CRM/Contact/Page/View/CustomData.php @@ -0,0 +1,142 @@ +_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + + $this->_groupId = CRM_Utils_Request::retrieve('gid', 'Positive', $this, TRUE); + $this->assign('groupId', $this->_groupId); + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * + * @access public + * + * @param object $page - the view page which created this one + * + * @return none + * @static + * + */ + function run() { + $this->preProcess(); + + //set the userContext stack + $doneURL = 'civicrm/contact/view'; + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url($doneURL, 'action=browse&selectedChild=custom_' . $this->_groupId), FALSE); + + // get permission detail view or edit + $permUser = CRM_Core_Permission::getPermission(); + + $editCustomData = (CRM_Core_Permission::VIEW == $permUser) ? 0 : 1; + $this->assign('editCustomData', $editCustomData); + + //allow to edit own customdata CRM-5518 + $editOwnCustomData = FALSE; + if ($session->get('userID') == $this->_contactId) { + $editOwnCustomData = TRUE; + } + $this->assign('editOwnCustomData', $editOwnCustomData); + + if ($this->_action == CRM_Core_Action::BROWSE) { + //Custom Groups Inline + $entityType = CRM_Contact_BAO_Contact::getContactType($this->_contactId); + $entitySubType = CRM_Contact_BAO_Contact::getContactSubType($this->_contactId); + $groupTree = &CRM_Core_BAO_CustomGroup::getTree($entityType, $this, $this->_contactId, + $this->_groupId, $entitySubType + ); + CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree); + } + else { + + $controller = new CRM_Core_Controller_Simple('CRM_Contact_Form_CustomData', + ts('Custom Data'), + $this->_action + ); + $controller->setEmbedded(TRUE); + + $controller->set('tableId', $this->_contactId); + $controller->set('groupId', $this->_groupId); + $controller->set('entityType', CRM_Contact_BAO_Contact::getContactType($this->_contactId)); + $controller->set('entitySubType', CRM_Contact_BAO_Contact::getContactSubType($this->_contactId, ',')); + $controller->process(); + $controller->run(); + } + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/Email.php b/CRM/Contact/Page/View/Email.php new file mode 100644 index 0000000000..3a2e8ab5c4 --- /dev/null +++ b/CRM/Contact/Page/View/Email.php @@ -0,0 +1,107 @@ +activity_id = $id; + $dao->activity_type = ts('Email Sent'); + if ($dao->find(TRUE)) { + $cid = $dao->entity_id; + } + + $dao = new CRM_Core_DAO_EmailHistory(); + $dao->id = $id; + + if ($dao->find(TRUE)) { + // get the display name and email for the contact + list($toContactName, $toContactEmail, $toDoNotEmail) = CRM_Contact_BAO_Contact::getContactDetails($cid); + + if (!trim($toContactName)) { + $toContactName = $toContactEmail; + } + + if (trim($toContactEmail)) { + $toContactName = "\"$toContactName\" <$toContactEmail>"; + } + + $this->assign('toName', $toContactName); + + // get the display name and email for the contact + list($fromContactName, $fromContactEmail, $toDoNotEmail) = CRM_Contact_BAO_Contact::getContactDetails($dao->contact_id); + + if (!trim($fromContactEmail)) { + CRM_Core_Error::statusBounce(ts('Your user record does not have a valid email address')); + } + + if (!trim($fromContactName)) { + $fromContactName = $fromContactEmail; + } + + $this->assign('fromName', "\"$fromContactName\" <$fromContactEmail>"); + + $this->assign('sentDate', $dao->sent_date); + $this->assign('subject', $dao->subject); + $this->assign('message', $dao->message); + + // get the display name and images for the contact + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($dao->contact_id); + + CRM_Utils_System::setTitle($contactImage . ' ' . $displayName); + // also add the cid params to the Menu array + CRM_Core_Menu::addParam('cid', $cid); + } + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/GroupContact.php b/CRM/Contact/Page/View/GroupContact.php new file mode 100644 index 0000000000..61696ef0a0 --- /dev/null +++ b/CRM/Contact/Page/View/GroupContact.php @@ -0,0 +1,223 @@ +_contactId, NULL, NULL, TRUE); + + $in = CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, 'Added'); + $pending = CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, 'Pending'); + $out = CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, 'Removed'); + + // keep track of all 'added' contact groups so we can remove them from the smart group + // section + $staticGroups = array(); + if (!empty($in)) { + foreach ($in as $group) { + $staticGroups[$group['group_id']] = 1; + } + } + + $this->assign('groupCount', $count); + $this->assign_by_ref('groupIn', $in); + $this->assign_by_ref('groupPending', $pending); + $this->assign_by_ref('groupOut', $out); + + $allGroup = CRM_Contact_BAO_GroupContactCache::contactGroup($this->_contactId); + $this->assign('groupSmart' , null); + $this->assign('groupParent', null); + + if (!empty($allGroup)) { + $smart = $parent = array( ); + foreach ($allGroup['group'] as $group) { + // delete all smart groups which are also in static groups + if (isset($staticGroups[$group['id']])) { + continue; + } + if (empty($group['children'])) { + $smart[] = $group; + } + else { + $parent[] = $group; + } + } + + if (!empty($smart)) { + $this->assign_by_ref('groupSmart', $smart); + } + if (!empty($parent)) { + $this->assign_by_ref('groupParent', $parent); + } + } + } + + /** + * This function is called when action is update + * + * @param int $groupID group id + * + * return null + * @access public + */ + function edit($groupId = NULL) { + $controller = new CRM_Core_Controller_Simple( + 'CRM_Contact_Form_GroupContact', + ts('Contact\'s Groups'), + $this->_action + ); + $controller->setEmbedded(TRUE); + + // set the userContext stack + $session = CRM_Core_Session::singleton(); + + $session->pushUserContext( + CRM_Utils_System::url( + 'civicrm/contact/view', + "action=browse&selectedChild=group&cid={$this->_contactId}" + ), + FALSE + ); + $controller->reset(); + + $controller->set('contactId', $this->_contactId); + $controller->set('groupId', $groupId); + + $controller->process(); + $controller->run(); + } + + function preProcess() { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + } + + /** + * This function is the main function that is called + * when the page loads, it decides the which action has + * to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + $this->assign('displayName', $displayName); + + if ($this->_action == CRM_Core_Action::DELETE) { + $groupContactId = CRM_Utils_Request::retrieve('gcid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE); + $status = CRM_Utils_Request::retrieve('st', 'String', CRM_Core_DAO::$_nullObject, TRUE); + if (is_numeric($groupContactId) && $status) { + $this->del($groupContactId, $status, $this->_contactId); + } + $session = CRM_Core_Session::singleton(); + CRM_Utils_System::redirect($session->popUserContext()); + } + + $this->edit(NULL, CRM_Core_Action::ADD); + $this->browse(); + return parent::run(); + } + + /** + * function to remove/ rejoin the group + * + * @param int $groupContactId id of crm_group_contact + * @param string $status this is the status that should be updated. + * + * $access public + */ + function del($groupContactId, $status, $contactID) { + $groupId = CRM_Contact_BAO_GroupContact::getGroupId($groupContactId); + + switch ($status) { + case 'i': + $groupStatus = 'Added'; + break; + + case 'p': + $groupStatus = 'Pending'; + break; + + case 'o': + $groupStatus = 'Removed'; + break; + + case 'd': + $groupStatus = 'Deleted'; + break; + } + + $groupNum = CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, 'Added', + NULL, TRUE, TRUE + ); + if ($groupNum == 1 && + $groupStatus == 'Removed' && + CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'is_enabled' + ) + ) { + CRM_Core_Session::setStatus(ts('Please ensure at least one contact group association is maintained.'), ts('Could Not Remove')); + return FALSE; + } + + $ids = array($contactID); + $method = 'Admin'; + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + + if ($userID == $contactID) { + $method = 'Web'; + } + + CRM_Contact_BAO_GroupContact::removeContactsFromGroup($ids, $groupId, $method, $groupStatus); + } +} + diff --git a/CRM/Contact/Page/View/Log.php b/CRM/Contact/Page/View/Log.php new file mode 100644 index 0000000000..24b4c02980 --- /dev/null +++ b/CRM/Contact/Page/View/Log.php @@ -0,0 +1,104 @@ +assign('useLogging', $loggingReport); + + if ($loggingReport) { + $this->assign('instanceUrl', + CRM_Utils_System::url("civicrm/report/instance/{$loggingReport}", + "reset=1&force=1&snippet=4§ion=2&altered_contact_id_op=eq&altered_contact_id_value={$this->_contactId}&cid={$this->_contactId}", FALSE, NULL, FALSE)); + return; + } + + $log = new CRM_Core_DAO_Log(); + + $log->entity_table = 'civicrm_contact'; + $log->entity_id = $this->_contactId; + $log->orderBy('modified_date desc'); + $log->find(); + + $logEntries = array(); + while ($log->fetch()) { + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($log->modified_id); + $logEntries[] = array( + 'id' => $log->modified_id, + 'name' => $displayName, + 'image' => $contactImage, + 'date' => $log->modified_date, + ); + } + + $this->assign('logCount', count($logEntries)); + $this->assign_by_ref('log', $logEntries); + } + + function preProcess() { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + $this->assign('displayName', $displayName); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + } + + /** + * This function is the main function that is called when the page loads, it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + $this->browse(); + + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/Note.php b/CRM/Contact/Page/View/Note.php new file mode 100644 index 0000000000..02ead389a5 --- /dev/null +++ b/CRM/Contact/Page/View/Note.php @@ -0,0 +1,315 @@ +id = $this->_id; + if ($note->find(TRUE)) { + $values = array(); + CRM_Core_DAO::storeValues($note, $values); + $values['privacy'] = CRM_Core_OptionGroup::optionLabel('note_privacy', $values['privacy']); + $this->assign('note', $values); + } + + $comments = CRM_Core_BAO_Note::getNoteTree($values['id'], 1); + if (!empty($comments)) { + $this->assign('comments', $comments); + } + + // add attachments part + $currentAttachmentInfo = CRM_Core_BAO_File::getEntityFile('civicrm_note', $this->_id); + $this->assign('currentAttachmentInfo', $currentAttachmentInfo); + + } + + /** + * This function is called when action is browse + * + * return null + * @access public + */ + function browse() { + $note = new CRM_Core_DAO_Note(); + $note->entity_table = 'civicrm_contact'; + $note->entity_id = $this->_contactId; + + $note->orderBy('modified_date desc'); + + //CRM-4418, handling edit and delete separately. + $permissions = array($this->_permission); + if ($this->_permission == CRM_Core_Permission::EDIT) { + //previously delete was subset of edit + //so for consistency lets grant delete also. + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + $values = array(); + $links = self::links(); + $action = array_sum(array_keys($links)) & $mask; + + $note->find(); + while ($note->fetch()) { + if (!CRM_Core_BAO_Note::getNotePrivacyHidden($note)) { + CRM_Core_DAO::storeValues($note, $values[$note->id]); + + $values[$note->id]['action'] = CRM_Core_Action::formLink($links, + $action, + array( + 'id' => $note->id, + 'cid' => $this->_contactId, + ) + ); + $contact = new CRM_Contact_DAO_Contact(); + $contact->id = $note->contact_id; + $contact->find(); + $contact->fetch(); + $values[$note->id]['createdBy'] = $contact->display_name; + $values[$note->id]['comment_count'] = CRM_Core_BAO_Note::getChildCount($note->id); + } + } + + $this->assign('notes', $values); + + $commentLinks = self::commentLinks(); + + $action = array_sum(array_keys($commentLinks)) & $mask; + + $commentAction = CRM_Core_Action::formLink($commentLinks, + $action, + array( + 'id' => $note->id, + 'pid' => $note->entity_id, + 'cid' => $note->entity_id, + ) + ); + $this->assign('commentAction', $commentAction); + } + + /** + * This function is called when action is update or new + * + * return null + * @access public + */ + function edit() { + $controller = new CRM_Core_Controller_Simple('CRM_Note_Form_Note', ts('Contact Notes'), $this->_action); + $controller->setEmbedded(TRUE); + + // set the userContext stack + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/contact/view', + 'action=browse&selectedChild=note&cid=' . $this->_contactId + ); + $session->pushUserContext($url); + + if (CRM_Utils_Request::retrieve('confirmed', 'Boolean', + CRM_Core_DAO::$_nullObject + )) { + CRM_Core_BAO_Note::del($this->_id); + CRM_Utils_System::redirect($url); + } + + $controller->reset(); + $controller->set('entityTable', 'civicrm_contact'); + $controller->set('entityId', $this->_contactId); + $controller->set('id', $this->_id); + + $controller->process(); + $controller->run(); + } + + function preProcess() { + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + + if ($this->_id && CRM_Core_BAO_Note::getNotePrivacyHidden($this->_id)) { + CRM_Core_Error::statusBounce(ts('You do not have access to this note.')); + } + + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + // set page title + CRM_Contact_Page_View::setTitle($this->_contactId); + + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + CRM_Utils_System::setTitle(ts('Notes for') . ' ' . $displayName); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->view(); + } + elseif ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD)) { + $this->edit(); + } + elseif ($this->_action & CRM_Core_Action::DELETE) { + // we use the edit screen the confirm the delete + $this->edit(); + } + + $this->browse(); + return parent::run(); + } + + /** + * delete the note object from the db + * + * @return void + * @access public + */ + function delete() { + CRM_Core_BAO_Note::del($this->_id); + } + + /** + * Get action links + * + * @return array (reference) of action links + * @static + */ + static function &links() { + if (!(self::$_links)) { + $deleteExtra = ts('Are you sure you want to delete this note?'); + + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=view&reset=1&cid=%%cid%%&id=%%id%%&selectedChild=note', + 'title' => ts('View Note'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=update&reset=1&cid=%%cid%%&id=%%id%%&selectedChild=note', + 'title' => ts('Edit Note'), + ), + CRM_Core_Action::ADD => array( + 'name' => ts('Comment'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=add&reset=1&cid=%%cid%%&parentId=%%id%%&selectedChild=note', + 'title' => ts('Add Comment'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=delete&reset=1&cid=%%cid%%&id=%%id%%&selectedChild=note', + 'extra' => 'onclick = "if (confirm(\'' . $deleteExtra . '\') ) this.href+=\'&confirmed=1\'; else return false;"', + 'title' => ts('Delete Note'), + ), + ); + } + return self::$_links; + } + + /** + * Get action links for comments + * + * @return array (reference) of action links + * @static + */ + static function &commentLinks() { + if (!(self::$_commentLinks)) { + $deleteExtra = ts('Are you sure you want to delete this comment?'); + self::$_commentLinks = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=view&reset=1&cid=%%cid%%&id={id}&selectedChild=note', + 'title' => ts('View Comment'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=update&reset=1&cid=%%cid%%&id={id}&parentId=%%pid%%&selectedChild=note', + 'title' => ts('Edit Comment'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/note', + 'qs' => 'action=delete&reset=1&cid=%%cid%%&id={id}&selectedChild=note', + 'extra' => 'onclick = "if (confirm(\'' . $deleteExtra . '\') ) this.href+=\'&confirmed=1\'; else return false;"', + 'title' => ts('Delete Comment'), + ), + ); + } + return self::$_commentLinks; + } +} + diff --git a/CRM/Contact/Page/View/Print.php b/CRM/Contact/Page/View/Print.php new file mode 100644 index 0000000000..c641c133de --- /dev/null +++ b/CRM/Contact/Page/View/Print.php @@ -0,0 +1,79 @@ +_print = CRM_Core_Smarty::PRINT_PAGE; + + $this->preProcess(); + + $this->view(); + + return parent::run(); + } + + /** + * View summary details of a contact + * + * @return void + * @access public + */ + function view() { + $params = array(); + $defaults = array(); + $ids = array(); + + $params['id'] = $params['contact_id'] = $this->_contactId; + $contact = CRM_Contact_BAO_Contact::retrieve($params, $defaults, $ids); + + $this->assign('pageTitle', $contact->sort_name); + + return parent::view(); + } +} + diff --git a/CRM/Contact/Page/View/Relationship.php b/CRM/Contact/Page/View/Relationship.php new file mode 100644 index 0000000000..45226008b7 --- /dev/null +++ b/CRM/Contact/Page/View/Relationship.php @@ -0,0 +1,363 @@ +_contactId, NULL, NULL, NULL, $this->_id); + //To check whether selected contact is a contact_id_a in + //relationship type 'a_b' in relationship table, if yes then + //revert the permissionship text in template + $relationship = new CRM_Contact_DAO_Relationship(); + $relationship->id = $viewRelationship[$this->_id]['id']; + + if ($relationship->find(TRUE)) { + if (($viewRelationship[$this->_id]['rtype'] == 'a_b') && ($this->_contactId == $relationship->contact_id_a)) { + $this->assign("is_contact_id_a", TRUE); + } + } + $relType = $viewRelationship[$this->_id]['civicrm_relationship_type_id']; + $this->assign('viewRelationship', $viewRelationship); + + $employerId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactId, 'employer_id'); + $this->assign('isCurrentEmployer', FALSE); + if ($viewRelationship[$this->_id]['employer_id'] == $this->_contactId) { + $this->assign('isCurrentEmployer', TRUE); + } + elseif ($relType == 4 && + ($viewRelationship[$this->_id]['cid'] == $employerId) + ) { + // make sure we are viewing employee of relationship + $this->assign('isCurrentEmployer', TRUE); + } + + $viewNote = CRM_Core_BAO_Note::getNote($this->_id); + $this->assign('viewNote', $viewNote); + + $groupTree = CRM_Core_BAO_CustomGroup::getTree('Relationship', $this, $this->_id, 0, $relType); + CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree); + + $rType = CRM_Utils_Array::value('rtype', $viewRelationship[$this->_id]); + // add viewed contribution to recent items list + $url = CRM_Utils_System::url('civicrm/contact/view/rel', + "action=view&reset=1&id={$viewRelationship[$this->_id]['id']}&cid={$this->_contactId}&context=home" + ); + + + $session = CRM_Core_Session::singleton(); + $recentOther = array(); + + if (($session->get('userID') == $this->_contactId) || + CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT) + ) { + $recentOther = array( + 'editUrl' => CRM_Utils_System::url('civicrm/contact/view/rel', + "action=update&reset=1&id={$viewRelationship[$this->_id]['id']}&cid={$this->_contactId}&rtype={$rType}&context=home" + ), + 'deleteUrl' => CRM_Utils_System::url('civicrm/contact/view/rel', + "action=delete&reset=1&id={$viewRelationship[$this->_id]['id']}&cid={$this->_contactId}&rtype={$rType}&context=home" + ), + ); + } + + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + $this->assign('displayName', $displayName); + CRM_Utils_System::setTitle(ts('View Relationship for') . ' ' . $displayName); + + $title = $displayName . ' (' . $viewRelationship[$this->_id]['relation'] . ' ' . CRM_Contact_BAO_Contact::displayName($viewRelationship[$this->_id]['cid']) . ')'; + + // add the recently viewed Relationship + CRM_Utils_Recent::add($title, + $url, + $viewRelationship[$this->_id]['id'], + 'Relationship', + $this->_contactId, + NULL, + $recentOther + ); + } + + /** + * This function is called when action is browse + * + * return null + * @access public + */ + function browse() { + $links = self::links(); + + //CRM-4418, handling edit and delete separately. + $permissions = array($this->_permission); + if ($this->_permission == CRM_Core_Permission::EDIT) { + //previously delete was subset of edit + //so for consistency lets grant delete also. + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + $currentRelationships = CRM_Contact_BAO_Relationship::getRelationship($this->_contactId, + CRM_Contact_BAO_Relationship::CURRENT, + 0, 0, 0, + $links, $mask + ); + + $inactiveRelationships = CRM_Contact_BAO_Relationship::getRelationship($this->_contactId, + CRM_Contact_BAO_Relationship::INACTIVE, + 0, 0, 0, + $links, $mask + ); + + $this->assign('currentRelationships', $currentRelationships); + // to show the 'Current Relationships' title and links only when viewed + // from relationship tab, not from dashboard + $this->assign('relationshipTabContext', TRUE); + $this->assign('inactiveRelationships', $inactiveRelationships); + } + + /** + * This function is called when action is update or new + * + * return null + * @access public + */ + function edit() { + $controller = new CRM_Core_Controller_Simple('CRM_Contact_Form_Relationship', ts('Contact Relationships'), $this->_action); + $controller->setEmbedded(TRUE); + + // set the userContext stack + $session = CRM_Core_Session::singleton(); + + // if this is called from case view, we need to redirect back to same page + if ($this->_caseId) { + $url = CRM_Utils_System::url('civicrm/contact/view/case', "action=view&reset=1&cid={$this->_contactId}&id={$this->_caseId}"); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view', "action=browse&selectedChild=rel&reset=1&cid={$this->_contactId}"); + } + + $session->pushUserContext($url); + + if (CRM_Utils_Request::retrieve('confirmed', 'Boolean', + CRM_Core_DAO::$_nullObject + )) { + if ($this->_caseId) { + //create an activity for case role removal.CRM-4480 + CRM_Case_BAO_Case::createCaseRoleActivity($this->_caseId, $this->_id); + CRM_Core_Session::setStatus(ts('Case Role has been deleted successfully.'), ts('Record Deleted'), 'success'); + } + + // delete relationship + CRM_Contact_BAO_Relationship::del($this->_id); + + CRM_Utils_System::redirect($url); + } + + $controller->set('contactId', $this->_contactId); + $controller->set('id', $this->_id); + $controller->process(); + $controller->run(); + } + + function preProcess() { + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + // set page title + CRM_Contact_Page_View::setTitle($this->_contactId); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + $this->setContext(); + + $this->_caseId = CRM_Utils_Request::retrieve('caseID', 'Integer', $this); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->view(); + } + elseif ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::DELETE)) { + $this->edit(); + } + elseif ($this->_action & CRM_Core_Action::DISABLE) { + CRM_Contact_BAO_Relationship::disableEnableRelationship($this->_id, CRM_Core_Action::DISABLE); + CRM_Contact_BAO_Relationship::setIsActive($this->_id, 0); + $session = CRM_Core_Session::singleton(); + CRM_Utils_System::redirect($session->popUserContext()); + } + elseif ($this->_action & CRM_Core_Action::ENABLE) { + CRM_Contact_BAO_Relationship::disableEnableRelationship($this->_id, CRM_Core_Action::ENABLE); + CRM_Contact_BAO_Relationship::setIsActive($this->_id, 1); + $session = CRM_Core_Session::singleton(); + CRM_Utils_System::redirect($session->popUserContext()); + } + + // if this is called from case view, suppress browse relationships form + if (!$this->_caseId) { + $this->browse(); + } + + return parent::run(); + } + + function setContext() { + $context = CRM_Utils_Request::retrieve('context', 'String', + $this, FALSE, 'search' + ); + + if ($context == 'dashboard') { + $cid = CRM_Utils_Request::retrieve('cid', 'Integer', + $this, FALSE + ); + $url = CRM_Utils_System::url('civicrm/user', + "reset=1&id={$cid}" + ); + } + else { + $url = CRM_Utils_System::url('civicrm/contact/view', 'action=browse&selectedChild=rel'); + } + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } + + /** + * This function is called to delete the relationship of a contact + * + * return null + * @access public + */ + function delete() { + // calls a function to delete relationship + CRM_Contact_BAO_Relationship::del($this->_id); + } + + /** + * Get action links + * + * @return array (reference) of action links + * @static + */ + static function &links() { + if (!(self::$_links)) { + $deleteExtra = ts('Are you sure you want to delete this relationship?'); + $disableExtra = ts('Are you sure you want to disable this relationship?'); + $enableExtra = ts('Are you sure you want to re-enable this relationship?'); + + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view/rel', + 'qs' => 'action=view&reset=1&cid=%%cid%%&id=%%id%%&rtype=%%rtype%%&selectedChild=rel', + 'title' => ts('View Relationship'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/view/rel', + 'qs' => 'action=update&reset=1&cid=%%cid%%&id=%%id%%&rtype=%%rtype%%', + 'title' => ts('Edit Relationship'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'url' => 'civicrm/contact/view/rel', + 'qs' => 'action=enable&reset=1&cid=%%cid%%&id=%%id%%&rtype=%%rtype%%&selectedChild=rel', + 'extra' => 'onclick = "return confirm(\'' . $enableExtra . '\');"', + 'title' => ts('Enable Relationship'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'url' => 'civicrm/contact/view/rel', + 'qs' => 'action=disable&reset=1&cid=%%cid%%&id=%%id%%&rtype=%%rtype%%&selectedChild=rel', + 'extra' => 'onclick = "return confirm(\'' . $disableExtra . '\');"', + 'title' => ts('Disable Relationship'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/rel', + 'qs' => 'action=delete&reset=1&cid=%%cid%%&id=%%id%%&rtype=%%rtype%%', + 'extra' => 'onclick = "if (confirm(\'' . $deleteExtra . '\') ) this.href+=\'&confirmed=1\'; else return false;"', + 'title' => ts('Delete Relationship'), + ), + // FIXME: Not sure what to put as the key. + // We want to use it differently later anyway (see CRM_Contact_BAO_Relationship::getRelationship). NONE should make it hidden by default. + CRM_Core_Action::NONE => array( + 'name' => ts('Manage Case'), + 'url' => 'civicrm/contact/view/case', + 'qs' => 'action=view&reset=1&cid=%%clientid%%&id=%%caseid%%', + 'title' => ts('Manage Case'), + ), + ); + } + return self::$_links; + } +} + diff --git a/CRM/Contact/Page/View/SMS.php b/CRM/Contact/Page/View/SMS.php new file mode 100644 index 0000000000..7eef83dbb1 --- /dev/null +++ b/CRM/Contact/Page/View/SMS.php @@ -0,0 +1,97 @@ +activity_id = $id; + $dao->activity_type = ts('SMS Sent'); + if ($dao->find(TRUE)) { + $cid = $dao->entity_id; + } + + $dao = new CRM_SMS_DAO_History(); + $dao->id = $id; + + if ($dao->find(TRUE)) { + $this->assign('fromName', + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $dao->contact_id, + 'display_name' + ) + ); + $this->assign('toName', + CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $cid, + 'display_name' + ) + ); + $this->assign('sentDate', $dao->sent_date); + $this->assign('message', $dao->message); + + // get the display name and images for the contact + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($dao->contact_id); + + CRM_Utils_System::setTitle($contactImage . ' ' . $displayName); + + // also add the cid params to the Menu array + CRM_Core_Menu::addParam('cid', $cid); + } + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/Summary.php b/CRM/Contact/Page/View/Summary.php new file mode 100644 index 0000000000..8ba24f8066 --- /dev/null +++ b/CRM/Contact/Page/View/Summary.php @@ -0,0 +1,387 @@ +_contactId); + + $this->assign('actionsMenuList', $menuItems); + + //retrieve inline custom data + $entityType = $this->get('contactType'); + if ($entitySubType = $this->get('contactSubtype')) { + $entitySubType = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($entitySubType, CRM_Core_DAO::VALUE_SEPARATOR) + ); + } + $groupTree = &CRM_Core_BAO_CustomGroup::getTree($entityType, + $this, + $this->_contactId, + NULL, + $entitySubType + ); + + CRM_Core_BAO_CustomGroup::buildCustomDataView($this, + $groupTree + ); + + // also create the form element for the activity links box + $controller = new CRM_Core_Controller_Simple( + 'CRM_Activity_Form_ActivityLinks', + ts('Activity Links'), + NULL, + FALSE, + FALSE, + TRUE + ); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + /** + * Heart of the viewing process. The runner gets all the meta data for + * the contact and calls the appropriate type of page to view. + * + * @return void + * @access public + * + */ + function run() { + $this->preProcess(); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $this->edit(); + } + else { + $this->view(); + } + + return parent::run(); + } + + /** + * Edit name and address of a contact + * + * @return void + * @access public + */ + function edit() { + // set the userContext stack + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $this->_contactId); + $session->pushUserContext($url); + + $controller = new CRM_Core_Controller_Simple('CRM_Contact_Form_Contact', ts('Contact Page'), CRM_Core_Action::UPDATE); + $controller->setEmbedded(TRUE); + $controller->process(); + return $controller->run(); + } + + /** + * View summary details of a contact + * + * @return void + * @access public + */ + function view() { + // Add js for in-place editing and jstree for tags + CRM_Core_Resources::singleton() + ->addScriptFile('civicrm', 'templates/CRM/Contact/Page/View/Summary.js') + ->addScriptFile('civicrm', 'packages/jquery/plugins/jstree/jquery.jstree.js', 0, 'html-header', FALSE) + ->addStyleFile('civicrm', 'packages/jquery/plugins/jstree/themes/default/style.css', 0, 'html-header'); + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $this->_contactId); + $session->pushUserContext($url); + + $params = array(); + $defaults = array(); + $ids = array(); + + $params['id'] = $params['contact_id'] = $this->_contactId; + $params['noRelationships'] = $params['noNotes'] = $params['noGroups'] = TRUE; + $contact = CRM_Contact_BAO_Contact::retrieve($params, $defaults, TRUE); + + $communicationType = array( + 'phone' => array( + 'type' => 'phoneType', + 'id' => 'phone_type', + ), + 'im' => array( + 'type' => 'IMProvider', + 'id' => 'provider', + ), + 'website' => array( + 'type' => 'websiteType', + 'id' => 'website_type', + ), + 'address' => array('skip' => TRUE, 'customData' => 1), + 'email' => array('skip' => TRUE), + 'openid' => array('skip' => TRUE), + ); + + foreach ($communicationType as $key => $value) { + if (CRM_Utils_Array::value($key, $defaults)) { + foreach ($defaults[$key] as & $val) { + CRM_Utils_Array::lookupValue($val, 'location_type', CRM_Core_PseudoConstant::locationDisplayName(), FALSE); + if (!CRM_Utils_Array::value('skip', $value)) { + eval('$pseudoConst = CRM_Core_PseudoConstant::' . $value['type'] . '();'); + CRM_Utils_Array::lookupValue($val, $value['id'], $pseudoConst, FALSE); + } + } + if (isset($value['customData'])) { + foreach ($defaults[$key] as $blockId => $blockVal) { + $idValue = $blockVal['id']; + if ( $key == 'address' ) { + if ( CRM_Utils_Array::value( 'master_id', $blockVal ) ) { + $idValue = $blockVal['master_id']; + } + } + $groupTree = CRM_Core_BAO_CustomGroup::getTree(ucfirst($key), + $this, + $idValue + ); + // we setting the prefix to dnc_ below so that we don't overwrite smarty's grouptree var. + $defaults[$key][$blockId]['custom'] = CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree, FALSE, NULL, "dnc_"); + } + // reset template variable since that won't be of any use, and could be misleading + $this->assign("dnc_viewCustomData", NULL); + } + } + } + + if (CRM_Utils_Array::value('gender_id', $defaults)) { + $gender = CRM_Core_PseudoConstant::gender(TRUE); + $defaults['gender_display'] = $gender[CRM_Utils_Array::value('gender_id', $defaults)]; + } + + // to make contact type label available in the template - + $contactType = array_key_exists('contact_sub_type', $defaults) ? $defaults['contact_sub_type'] : $defaults['contact_type']; + $defaults['contact_type_label'] = CRM_Contact_BAO_ContactType::contactTypePairs(TRUE, $contactType, ', '); + + // get contact tags + $contactTags = CRM_Core_BAO_EntityTag::getContactTags($this->_contactId); + + if (!empty($contactTags)) { + $defaults['contactTag'] = implode(', ', $contactTags); + } + + $defaults['privacy_values'] = CRM_Core_SelectValues::privacy(); + + //Show blocks only if they are visible in edit form + $this->_editOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_edit_options' + ); + + foreach ($this->_editOptions as $blockName => $value) { + $varName = '_show' . $blockName; + $this->$varName = $value; + $this->assign(substr($varName, 1), $this->$varName); + } + + // get contact name of shared contact names + $sharedAddresses = array(); + $shareAddressContactNames = CRM_Contact_BAO_Contact_Utils::getAddressShareContactNames($defaults['address']); + foreach ($defaults['address'] as $key => $addressValue) { + if (CRM_Utils_Array::value('master_id', $addressValue) && + !$shareAddressContactNames[$addressValue['master_id']]['is_deleted'] + ) { + $sharedAddresses[$key]['shared_address_display'] = array( + 'address' => $addressValue['display'], + 'name' => $shareAddressContactNames[$addressValue['master_id']]['name'], + ); + } + } + $this->assign('sharedAddresses', $sharedAddresses); + + //get the current employer name + if (CRM_Utils_Array::value('contact_type', $defaults) == 'Individual') { + if ($contact->employer_id && $contact->organization_name) { + $defaults['current_employer'] = $contact->organization_name; + $defaults['current_employer_id'] = $contact->employer_id; + } + + //for birthdate format with respect to birth format set + $this->assign('birthDateViewFormat', CRM_Utils_Array::value('qfMapping', CRM_Utils_Date::checkBirthDateFormat())); + } + + $this->assign($defaults); + + // FIXME: when we sort out TZ isssues with DATETIME/TIMESTAMP, we can skip next query + // also assign the last modifed details + $lastModified = CRM_Core_BAO_Log::lastModified($this->_contactId, 'civicrm_contact'); + $this->assign_by_ref('lastModified', $lastModified); + + $allTabs = array(); + $weight = 10; + + $this->_viewOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_view_options', TRUE + ); + $changeLog = $this->_viewOptions['log']; + $this->assign_by_ref('changeLog', $changeLog); + $components = CRM_Core_Component::getEnabledComponents(); + + foreach ($components as $name => $component) { + if (CRM_Utils_Array::value($name, $this->_viewOptions) && + CRM_Core_Permission::access($component->name) + ) { + $elem = $component->registerTab(); + + // FIXME: not very elegant, probably needs better approach + // allow explicit id, if not defined, use keyword instead + if (array_key_exists('id', $elem)) { + $i = $elem['id']; + } + else { + $i = $component->getKeyword(); + } + $u = $elem['url']; + + //appending isTest to url for test soft credit CRM-3891. + //FIXME: hack ajax url. + $q = "reset=1&snippet=1&force=1&cid={$this->_contactId}"; + if (CRM_Utils_Request::retrieve('isTest', 'Positive', $this)) { + $q = $q . "&isTest=1"; + } + $allTabs[] = array( + 'id' => $i, + 'url' => CRM_Utils_System::url("civicrm/contact/view/$u", $q), + 'title' => $elem['title'], + 'weight' => $elem['weight'], + 'count' => CRM_Contact_BAO_Contact::getCountComponent($u, $this->_contactId), + ); + // make sure to get maximum weight, rest of tabs go after + // FIXME: not very elegant again + if ($weight < $elem['weight']) { + $weight = $elem['weight']; + } + } + } + + $rest = array('activity' => ts('Activities'), + 'case' => ts('Cases'), + 'rel' => ts('Relationships'), + 'group' => ts('Groups'), + 'note' => ts('Notes'), + 'tag' => ts('Tags'), + 'log' => ts('Change Log'), + ); + + foreach ($rest as $k => $v) { + if (CRM_Utils_Array::value($k, $this->_viewOptions)) { + $allTabs[] = array( + 'id' => $k, + 'url' => CRM_Utils_System::url("civicrm/contact/view/$k", + "reset=1&snippet=1&cid={$this->_contactId}" + ), + 'title' => $v, + 'weight' => $weight, + 'count' => CRM_Contact_BAO_Contact::getCountComponent($k, $this->_contactId), + ); + $weight += 10; + } + } + + // now add all the custom tabs + $entityType = $this->get('contactType'); + $activeGroups = CRM_Core_BAO_CustomGroup::getActiveGroups($entityType, + 'civicrm/contact/view/cd', + $this->_contactId + ); + + foreach ($activeGroups as $group) { + $id = "custom_{$group['id']}"; + $allTabs[] = array( + 'id' => $id, + 'url' => CRM_Utils_System::url($group['path'], $group['query'] . "&snippet=1&selectedChild=$id"), + 'title' => $group['title'], + 'weight' => $weight, + 'count' => CRM_Contact_BAO_Contact::getCountComponent($id, $this->_contactId, $group['table_name']), + ); + $weight += 10; + } + + // see if any other modules want to add any tabs + CRM_Utils_Hook::tabs($allTabs, $this->_contactId); + + // now sort the tabs based on weight + usort($allTabs, array('CRM_Utils_Sort', 'cmpFunc')); + + $this->assign('allTabs', $allTabs); + + $selectedChild = CRM_Utils_Request::retrieve('selectedChild', 'String', $this, FALSE, 'summary'); + $this->assign('selectedChild', $selectedChild); + + // hook for contact summary + // ignored but needed to prevent warnings + $contentPlacement = CRM_Utils_Hook::SUMMARY_BELOW; + CRM_Utils_Hook::summary($this->_contactId, $content, $contentPlacement); + if ($content) { + $this->assign_by_ref('hookContent', $content); + $this->assign('hookContentPlacement', $contentPlacement); + } + } + + function getTemplateFileName() { + if ($this->_contactId) { + $csType = $this->get('contactSubtype'); + if ($csType) { + $templateFile = "CRM/Contact/Page/View/SubType/{$csType}.tpl"; + $template = CRM_Core_Page::getTemplate(); + if ($template->template_exists($templateFile)) { + return $templateFile; + } + } + } + return parent::getTemplateFileName(); + } +} + diff --git a/CRM/Contact/Page/View/Sunlight.php b/CRM/Contact/Page/View/Sunlight.php new file mode 100644 index 0000000000..d1cb256e40 --- /dev/null +++ b/CRM/Contact/Page/View/Sunlight.php @@ -0,0 +1,71 @@ +_contactId); + $locations = CRM_Contact_BAO_Contact_Location::getMapInfo($ids); + + $rows = &CRM_Utils_Sunlight::getInfo($locations[0]['city'], + $locations[0]['state'], + $locations[0]['postal_code'] + ); + $this->assign('rowCount', count($rows)); + $this->assign_by_ref('rows', $rows); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + $this->browse(); + + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/Tag.php b/CRM/Contact/Page/View/Tag.php new file mode 100644 index 0000000000..cdc9fd67ef --- /dev/null +++ b/CRM/Contact/Page/View/Tag.php @@ -0,0 +1,83 @@ +_action); + $controller->setEmbedded(TRUE); + + // set the userContext stack + $session = CRM_Core_Session::singleton(); + + $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/view', 'action=browse&selectedChild=tag'), FALSE); + $controller->reset(); + $controller->set('contactId', $this->_contactId); + $controller->process(); + $controller->run(); + } + + function preProcess() { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->assign('action', $this->_action); + } + + /** + * This function is the main function that is called when the page loads + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + $this->browse(); + + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/UserDashBoard.php b/CRM/Contact/Page/View/UserDashBoard.php new file mode 100644 index 0000000000..eaa3aaa26d --- /dev/null +++ b/CRM/Contact/Page/View/UserDashBoard.php @@ -0,0 +1,262 @@ +_contactId = CRM_Utils_Request::retrieve('id', 'Positive', $this); + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + + if (!$this->_contactId) { + $this->_contactId = $userID; + } + elseif ($this->_contactId != $userID) { + if (!CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::VIEW)) { + CRM_Core_Error::fatal(ts('You do not have permission to view this contact')); + } + if (!CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT)) { + $this->_edit = FALSE; + } + } + } + + /* + * Heart of the viewing process. The runner gets all the meta data for + * the contact and calls the appropriate type of page to view. + * + * @return void + * @access public + * + */ + function preProcess() { + if (!$this->_contactId) { + CRM_Core_Error::fatal(ts('You must be logged in to view this page.')); + } + + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($this->_contactId); + + $this->set('displayName', $displayName); + $this->set('contactImage', $contactImage); + + CRM_Utils_System::setTitle(ts('Dashboard - %1', array(1 => $displayName))); + + $this->assign('recentlyViewed', FALSE); + } + + /** + * Function to build user dashboard + * + * @return none + * @access public + */ + function buildUserDashBoard() { + //build component selectors + $dashboardElements = array(); + $config = CRM_Core_Config::singleton(); + + $this->_userOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'user_dashboard_options' + ); + + $components = CRM_Core_Component::getEnabledComponents(); + $this->assign('contactId', $this->_contactId); + foreach ($components as $name => $component) { + $elem = $component->getUserDashboardElement(); + if (!$elem) { + continue; + } + + if (CRM_Utils_Array::value($name, $this->_userOptions) && + (CRM_Core_Permission::access($component->name) || + CRM_Core_Permission::check($elem['perm'][0]) + ) + ) { + + $userDashboard = $component->getUserDashboardObject(); + $dashboardElements[] = array('templatePath' => $userDashboard->getTemplateFileName(), + 'sectionTitle' => $elem['title'], + 'weight' => $elem['weight'], + ); + $userDashboard->run(); + } + } + + if (CRM_Utils_Array::value('Permissioned Orgs', $this->_userOptions)) { + $dashboardElements[] = array( + 'templatePath' => 'CRM/Contact/Page/View/Relationship.tpl', + 'sectionTitle' => ts('Your Contacts / Organizations'), + 'weight' => 40, + ); + + $links = self::links(); + $currentRelationships = CRM_Contact_BAO_Relationship::getRelationship($this->_contactId, + CRM_Contact_BAO_Relationship::CURRENT, + 0, 0, 0, + $links, NULL, TRUE + ); + $this->assign('currentRelationships', $currentRelationships); + } + + if (CRM_Utils_Array::value('PCP', $this->_userOptions)) { + $dashboardElements[] = array( + 'templatePath' => 'CRM/Contribute/Page/PcpUserDashboard.tpl', + 'sectionTitle' => ts('Personal Campaign Pages'), + 'weight' => 40, + ); + list($pcpBlock, $pcpInfo) = CRM_PCP_BAO_PCP::getPcpDashboardInfo($this->_contactId); + $this->assign('pcpBlock', $pcpBlock); + $this->assign('pcpInfo', $pcpInfo); + } + + if (CRM_Utils_Array::value('Assigned Activities', $this->_userOptions)) { + // Assigned Activities section + $dashboardElements[] = array( + 'templatePath' => 'CRM/Activity/Page/UserDashboard.tpl', + 'sectionTitle' => ts('Your Assigned Activities'), + 'weight' => 5, + ); + $userDashboard = new CRM_Activity_Page_UserDashboard; + $userDashboard->run(); + } + + usort($dashboardElements, array('CRM_Utils_Sort', 'cmpFunc')); + $this->assign('dashboardElements', $dashboardElements); + + if (CRM_Utils_Array::value('Groups', $this->_userOptions)) { + $this->assign('showGroup', TRUE); + //build group selector + $gContact = new CRM_Contact_Page_View_UserDashBoard_GroupContact(); + $gContact->run(); + } + else { + $this->assign('showGroup', FALSE); + } + } + + /** + * perform actions and display for user dashboard + * + * @return none + * + * @access public + */ + function run() { + $this->preProcess(); + $this->buildUserDashBoard(); + return parent::run(); + } + + /** + * Get action links + * + * @return array (reference) of action links + * @static + */ + static + function &links() { + if (!(self::$_links)) { + $disableExtra = ts('Are you sure you want to disable this relationship?'); + + self::$_links = array( + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit Contact Information'), + 'url' => 'civicrm/contact/relatedcontact', + 'qs' => 'action=update&reset=1&cid=%%cbid%%&rcid=%%cid%%', + 'title' => ts('Edit Relationship'), + ), + CRM_Core_Action::VIEW => array( + 'name' => ts('Dashboard'), + 'url' => 'civicrm/user', + 'qs' => 'reset=1&id=%%cbid%%', + 'title' => ts('View Relationship'), + ), + ); + + + if (CRM_Core_Permission::check('access CiviCRM')) { + self::$_links = array_merge(self::$_links, array( + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'url' => 'civicrm/contact/view/rel', + 'qs' => 'action=disable&reset=1&cid=%%cid%%&id=%%id%%&rtype=%%rtype%%&selectedChild=rel%%&context=dashboard', + 'extra' => 'onclick = "return confirm(\'' . $disableExtra . '\');"', + 'title' => ts('Disable Relationship'), + ), + )); + } + } + + // call the hook so we can modify it + CRM_Utils_Hook::links('view.contact.userDashBoard', + 'Contact', + CRM_Core_DAO::$_nullObject, + self::$_links, + CRM_Core_DAO::$_nullObject + ); + return self::$_links; + } +} + diff --git a/CRM/Contact/Page/View/UserDashBoard/GroupContact.php b/CRM/Contact/Page/View/UserDashBoard/GroupContact.php new file mode 100644 index 0000000000..abd1d5ab9d --- /dev/null +++ b/CRM/Contact/Page/View/UserDashBoard/GroupContact.php @@ -0,0 +1,142 @@ +_contactId, + NULL, + NULL, TRUE, TRUE, + $this->_onlyPublicGroups + ); + + $in = &CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, + 'Added', + NULL, FALSE, TRUE, + $this->_onlyPublicGroups + ); + $pending = &CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, + 'Pending', + NULL, FALSE, TRUE, + $this->_onlyPublicGroups + ); + $out = &CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, + 'Removed', + NULL, FALSE, TRUE, + $this->_onlyPublicGroups + ); + + $this->assign('groupCount', $count); + $this->assign_by_ref('groupIn', $in); + $this->assign_by_ref('groupPending', $pending); + $this->assign_by_ref('groupOut', $out); + } + + /** + * This function is called when action is update + * + * @param int $groupID group id + * + * return null + * @access public + */ + function edit($groupId = NULL) { + $this->assign('edit', $this->_edit); + if (!$this->_edit) { + return; + } + + $action = CRM_Utils_Request::retrieve('action', 'String', + CRM_Core_DAO::$_nullObject, + FALSE, 'browse' + ); + + if ($action == CRM_Core_Action::DELETE) { + $groupContactId = CRM_Utils_Request::retrieve('gcid', 'Positive', + CRM_Core_DAO::$_nullObject, TRUE + ); + $status = CRM_Utils_Request::retrieve('st', 'String', + CRM_Core_DAO::$_nullObject, TRUE + ); + if (is_numeric($groupContactId) && $status) { + CRM_Contact_Page_View_GroupContact::del($groupContactId, $status, $this->_contactId); + } + + $url = CRM_Utils_System::url('civicrm/user', + "reset=1&id={$this->_contactId}" + ); + CRM_Utils_System::redirect($url); + } + + $controller = new CRM_Core_Controller_Simple('CRM_Contact_Form_GroupContact', + ts("Contact's Groups"), + CRM_Core_Action::ADD + ); + $controller->setEmbedded(TRUE); + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/user', + "reset=1&id={$this->_contactId}" + ), + FALSE + ); + + $controller->reset(); + $controller->set('contactId', $this->_contactId); + $controller->set('groupId', $groupId); + $controller->set('context', 'user'); + $controller->set('onlyPublicGroups', $this->_onlyPublicGroups); + $controller->process(); + $controller->run(); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->edit(); + $this->browse(); + } +} + diff --git a/CRM/Contact/Page/View/Useradd.php b/CRM/Contact/Page/View/Useradd.php new file mode 100755 index 0000000000..0b9876025f --- /dev/null +++ b/CRM/Contact/Page/View/Useradd.php @@ -0,0 +1,63 @@ +setEmbedded(TRUE); + + $controller->process(); + $controller->run(); + + return parent::run(); + } +} + diff --git a/CRM/Contact/Page/View/Vcard.php b/CRM/Contact/Page/View/Vcard.php new file mode 100644 index 0000000000..0566b494b4 --- /dev/null +++ b/CRM/Contact/Page/View/Vcard.php @@ -0,0 +1,168 @@ +preProcess(); + + $params = array(); + $defaults = array(); + $ids = array(); + + $params['id'] = $params['contact_id'] = $this->_contactId; + $contact = CRM_Contact_BAO_Contact::retrieve($params, $defaults, $ids); + + // now that we have the contact's data - let's build the vCard + // TODO: non-US-ASCII support (requires changes to the Contact_Vcard_Build class) + $vcardNames = CRM_Core_PseudoConstant::locationVcardName(); + $vcard = new Contact_Vcard_Build('2.1'); + + if ($defaults['contact_type'] == 'Individual') { + $vcard->setName(CRM_Utils_Array::value('last_name', $defaults), + CRM_Utils_Array::value('first_name', $defaults), + CRM_Utils_Array::value('middle_name', $defaults), + CRM_Utils_Array::value('prefix', $defaults), + CRM_Utils_Array::value('suffix', $defaults) + ); + } + elseif ($defaults['contact_type'] == 'Organization') { + $vcard->setName($defaults['organization_name'], '', '', '', ''); + } + elseif ($defaults['contact_type'] == 'Household') { + $vcard->setName($defaults['household_name'], '', '', '', ''); + } + $vcard->setFormattedName($defaults['display_name']); + $vcard->setSortString($defaults['sort_name']); + + if (CRM_Utils_Array::value('nick_name', $defaults)) { + $vcard->addNickname($defaults['nick_name']); + } + + if (CRM_Utils_Array::value('job_title', $defaults)) { + $vcard->setTitle($defaults['job_title']); + } + + if (CRM_Utils_Array::value('birth_date_display', $defaults)) { + $vcard->setBirthday(CRM_Utils_Array::value('birth_date_display', $defaults)); + } + + if (CRM_Utils_Array::value('home_URL', $defaults)) { + $vcard->setURL($defaults['home_URL']); + } + + // TODO: $vcard->setGeo($lat, $lon); + if (CRM_Utils_Array::value('address', $defaults)) { + $stateProvices = CRM_Core_PseudoConstant::stateProvince(); + $countries = CRM_Core_PseudoConstant::country(); + foreach ($defaults['address'] as $location) { + // we don't keep PO boxes in separate fields + $pob = ''; + $extend = CRM_Utils_Array::value('supplemental_address_1', $location); + if (CRM_Utils_Array::value('supplemental_address_2', $location)) { + $extend .= ', ' . $location['supplemental_address_2']; + } + $street = CRM_Utils_Array::value('street_address', $location); + $locality = CRM_Utils_Array::value('city', $location); + $region = NULL; + if (CRM_Utils_Array::value('state_province_id', $location)) { + $region = $stateProvices[CRM_Utils_Array::value('state_province_id', $location)]; + } + $country = NULL; + if (CRM_Utils_Array::value('country_id', $location)) { + $country = $countries[CRM_Utils_Array::value('country_id', $location)]; + } + + $postcode = CRM_Utils_Array::value('postal_code', $location); + if (CRM_Utils_Array::value('postal_code_suffix', $location)) { + $postcode .= '-' . $location['postal_code_suffix']; + } + + $vcard->addAddress($pob, $extend, $street, $locality, $region, $postcode, $country); + $vcardName = $vcardNames[$location['location_type_id']]; + if ($vcardName) { + $vcard->addParam('TYPE', $vcardName); + } + if (CRM_Utils_Array::value('is_primary', $location)) { + $vcard->addParam('TYPE', 'PREF'); + } + } + } + if (CRM_Utils_Array::value('phone', $defaults)) { + foreach ($defaults['phone'] as $phone) { + $vcard->addTelephone($phone['phone']); + $vcardName = $vcardNames[$phone['location_type_id']]; + if ($vcardName) { + $vcard->addParam('TYPE', $vcardName); + } + if ($phone['is_primary']) { + $vcard->addParam('TYPE', 'PREF'); + } + } + } + + if (CRM_Utils_Array::value('email', $defaults)) { + foreach ($defaults['email'] as $email) { + $vcard->addEmail($email['email']); + $vcardName = $vcardNames[$email['location_type_id']]; + if ($vcardName) { + $vcard->addParam('TYPE', $vcardName); + } + if ($email['is_primary']) { + $vcard->addParam('TYPE', 'PREF'); + } + } + } + + // all that's left is sending the vCard to the browser + $filename = CRM_Utils_String::munge($defaults['display_name']); + $vcard->send($filename . '.vcf', 'attachment', 'utf-8'); + CRM_Utils_System::civiExit(); + } +} + diff --git a/CRM/Contact/Selector.php b/CRM/Contact/Selector.php new file mode 100644 index 0000000000..02311baf6b --- /dev/null +++ b/CRM/Contact/Selector.php @@ -0,0 +1,1084 @@ +_formValues = &$formValues; + $this->_params = &$params; + $this->_returnProperties = &$returnProperties; + $this->_contextMenu = &$contextMenu; + $this->_context = $searchContext; + + // type of selector + $this->_action = $action; + + $this->_searchContext = $searchContext; + + $this->_ufGroupID = CRM_Utils_Array::value('uf_group_id', $this->_formValues); + + if ($this->_ufGroupID) { + $this->_fields = CRM_Core_BAO_UFGroup::getListingFields(CRM_Core_Action::VIEW, + CRM_Core_BAO_UFGroup::PUBLIC_VISIBILITY | + CRM_Core_BAO_UFGroup::LISTINGS_VISIBILITY, + FALSE, $this->_ufGroupID + ); + self::$_columnHeaders = NULL; + + $this->_customFields = CRM_Core_BAO_CustomField::getFieldsForImport('Individual'); + + $this->_returnProperties = CRM_Contact_BAO_Contact::makeHierReturnProperties($this->_fields); + $this->_returnProperties['contact_type'] = 1; + $this->_returnProperties['contact_sub_type'] = 1; + $this->_returnProperties['sort_name'] = 1; + } + + $displayRelationshipType = CRM_Utils_Array::value('display_relationship_type', $this->_formValues); + $operator = CRM_Utils_Array::value('operator', $this->_formValues, 'AND'); + + // rectify params to what proximity search expects if there is a value for prox_distance + // CRM-7021 + if (!empty($this->_params)) { + CRM_Contact_BAO_ProximityQuery::fixInputParams($this->_params); + } + + $this->_query = new CRM_Contact_BAO_Query( + $this->_params, + $this->_returnProperties, + NULL, + $includeContactIds, + FALSE, + CRM_Contact_BAO_Query::MODE_CONTACTS, + FALSE, + $searchDescendentGroups, + FALSE, + $displayRelationshipType, + $operator + ); + + $this->_options = &$this->_query->_options; + } + //end of constructor + + /** + * This method returns the links that are given for each search row. + * currently the links added for each row are + * + * - View + * - Edit + * + * @return array + * @access public + * + */ + static function &links() { + list($context, $contextMenu, $key) = func_get_args(); + $extraParams = ($key) ? "&key={$key}" : NULL; + $searchContext = ($context) ? "&context=$context" : NULL; + + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view', + 'qs' => "reset=1&cid=%%id%%{$searchContext}{$extraParams}", + 'title' => ts('View Contact Details'), + 'ref' => 'view-contact', + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/add', + 'qs' => "reset=1&action=update&cid=%%id%%{$searchContext}{$extraParams}", + 'title' => ts('Edit Contact Details'), + 'ref' => 'edit-contact', + ), + ); + + $config = CRM_Core_Config::singleton(); + if ($config->mapAPIKey && $config->mapProvider) { + self::$_links[CRM_Core_Action::MAP] = array( + 'name' => ts('Map'), + 'url' => 'civicrm/contact/map', + 'qs' => "reset=1&cid=%%id%%{$searchContext}{$extraParams}", + 'title' => ts('Map Contact'), + ); + } + + // Adding Context Menu Links in more action + if ($contextMenu) { + $counter = 7000; + foreach ($contextMenu as $key => $value) { + $contextVal = '&context=' . $value['key']; + if ($value['key'] == 'delete') { + $contextVal = $searchContext; + } + + $url = "civicrm/contact/view/{$value['key']}"; + $qs = "reset=1&action=add&cid=%%id%%{$contextVal}{$extraParams}"; + if ($value['key'] == 'activity') { + $qs = "action=browse&selectedChild=activity&reset=1&cid=%%id%%{$extraParams}"; + } + elseif ($value['key'] == 'email') { + $url = "civicrm/contact/view/activity"; + $qs = "atype=3&action=add&reset=1&cid=%%id%%{$extraParams}"; + } + + self::$_links[$counter++] = array( + 'name' => $value['title'], + 'url' => $url, + 'qs' => $qs, + 'title' => $value['title'], + 'ref' => $value['ref'], + ); + } + } + } + return self::$_links; + } + //end of function + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['status'] = ts('Contact %%StatusMessage%%'); + $params['csvString'] = NULL; + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + //end of function + function &getColHeads($action = NULL, $output = NULL) { + + $colHeads = self::_getColumnHeaders(); + + $colHeads[] = array('desc' => ts('Actions'), 'name' => ts('Action')); + return $colHeads; + } + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + function &getColumnHeaders($action = NULL, $output = NULL) { + $headers = NULL; + if ($output == CRM_Core_Selector_Controller::EXPORT) { + $csvHeaders = array(ts('Contact Id'), ts('Contact Type')); + foreach ($this->getColHeads($action, $output) as $column) { + if (array_key_exists('name', $column)) { + $csvHeaders[] = $column['name']; + } + } + $headers = $csvHeaders; + } + elseif ($output == CRM_Core_Selector_Controller::SCREEN) { + $csvHeaders = array(ts('Name')); + foreach ($this->getColHeads($action, $output) as $key => $column) { + if (array_key_exists('name', $column) && + $column['name'] && + $column['name'] != ts('Name') + ) { + $csvHeaders[$key] = $column['name']; + } + } + $headers = $csvHeaders; + } + elseif ($this->_ufGroupID) { + // we dont use the cached value of column headers + // since it potentially changed because of the profile selected + static $skipFields = array('group', 'tag'); + $direction = CRM_Utils_Sort::ASCENDING; + $empty = TRUE; + if (!self::$_columnHeaders) { + self::$_columnHeaders = array(array('name' => ''), + array( + 'name' => ts('Name'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::ASCENDING, + ), + ); + + $locationTypes = CRM_Core_PseudoConstant::locationType(); + + foreach ($this->_fields as $name => $field) { + if (CRM_Utils_Array::value('in_selector', $field) && + !in_array($name, $skipFields) + ) { + if (strpos($name, '-') !== FALSE) { + list($fieldName, $lType, $type) = CRM_Utils_System::explode('-', $name, 3); + + if ($lType == 'Primary') { + $locationTypeName = 1; + } + else { + $locationTypeName = $locationTypes[$lType]; + } + + if (in_array($fieldName, array( + 'phone', 'im', 'email'))) { + if ($type) { + $name = "`$locationTypeName-$fieldName-$type`"; + } + else { + $name = "`$locationTypeName-$fieldName`"; + } + } + else { + $name = "`$locationTypeName-$fieldName`"; + } + } + //to handle sort key for Internal contactId.CRM-2289 + if ($name == 'id') { + $name = 'contact_id'; + } + + self::$_columnHeaders[] = array( + 'name' => $field['title'], + 'sort' => $name, + 'direction' => $direction, + ); + $direction = CRM_Utils_Sort::DONTCARE; + $empty = FALSE; + } + } + + // if we dont have any valid columns, dont add the implicit ones + // this allows the template to check on emptiness of column headers + if ($empty) { + self::$_columnHeaders = array(); + } + else { + self::$_columnHeaders[] = array('desc' => ts('Actions'), 'name' => ts('Action')); + } + } + $headers = self::$_columnHeaders; + } + elseif (!empty($this->_returnProperties)) { + + self::$_columnHeaders = array(array('name' => ''), + array( + 'name' => ts('Name'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::ASCENDING, + ), + ); + $properties = self::makeProperties($this->_returnProperties); + + foreach ($properties as $prop) { + if ($prop == 'contact_type' || $prop == 'contact_sub_type' || $prop == 'sort_name') { + continue; + } + + if (strpos($prop, '-')) { + list($loc, $fld, $phoneType) = CRM_Utils_System::explode('-', $prop, 3); + $title = $this->_query->_fields[$fld]['title']; + if (trim($phoneType) && !is_numeric($phoneType) && strtolower($phoneType) != $fld) { + $title .= "-{$phoneType}"; + } + $title .= " ($loc)"; + } + elseif (isset($this->_query->_fields[$prop]) && isset($this->_query->_fields[$prop]['title'])) { + $title = $this->_query->_fields[$prop]['title']; + } else { + $title = ''; + } + + self::$_columnHeaders[] = array('name' => $title, 'sort' => $prop); + } + self::$_columnHeaders[] = array('name' => ts('Actions')); + $headers = self::$_columnHeaders; + } + else { + $headers = $this->getColHeads($action, $output); + } + + return $headers; + } + + /** + * Returns total number of rows for the query. + * + * @param + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action) { + return $this->_query->searchQuery(0, 0, NULL, TRUE); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return int the total number of rows for this action + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { + $config = CRM_Core_Config::singleton(); + + if (($output == CRM_Core_Selector_Controller::EXPORT || + $output == CRM_Core_Selector_Controller::SCREEN + ) && + $this->_formValues['radio_ts'] == 'ts_sel' + ) { + $includeContactIds = TRUE; + } + else { + $includeContactIds = FALSE; + } + + // note the formvalues were given by CRM_Contact_Form_Search to us + // and contain the search criteria (parameters) + // note that the default action is basic + $result = $this->_query->searchQuery($offset, $rowCount, $sort, FALSE, $includeContactIds); + + // process the result of the query + $rows = array(); + $permissions = array(CRM_Core_Permission::getPermission()); + if (CRM_Core_Permission::check('delete contacts')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + // mask value to hide map link if there are not lat/long + $mapMask = $mask & 4095; + + if ($this->_searchContext == 'smog') { + $gc = CRM_Core_SelectValues::groupContactStatus(); + } + + if ($this->_ufGroupID) { + $locationTypes = CRM_Core_PseudoConstant::locationType(); + + $names = array(); + static $skipFields = array('group', 'tag'); + foreach ($this->_fields as $key => $field) { + if (CRM_Utils_Array::value('in_selector', $field) && + !in_array($key, $skipFields) + ) { + if (strpos($key, '-') !== FALSE) { + list($fieldName, $id, $type) = CRM_Utils_System::explode('-', $key, 3); + + if ($id == 'Primary') { + $locationTypeName = 1; + } + else { + $locationTypeName = CRM_Utils_Array::value($id, $locationTypes); + if (!$locationTypeName) { + continue; + } + } + + $locationTypeName = str_replace(' ', '_', $locationTypeName); + if (in_array($fieldName, array( + 'phone', 'im', 'email'))) { + if ($type) { + $names[] = "{$locationTypeName}-{$fieldName}-{$type}"; + } + else { + $names[] = "{$locationTypeName}-{$fieldName}"; + } + } + else { + $names[] = "{$locationTypeName}-{$fieldName}"; + } + } + else { + $names[] = $field['name']; + } + } + } + + $names[] = "status"; + } + elseif (!empty($this->_returnProperties)) { + $names = self::makeProperties($this->_returnProperties); + } + else { + $names = self::$_properties; + } + + $multipleSelectFields = array('preferred_communication_method' => 1); + + $links = self::links($this->_context, $this->_contextMenu, $this->_key); + + //check explicitly added contact to a Smart Group. + $groupID = CRM_Utils_Array::key('1', $this->_formValues['group']); + + // for CRM-3157 purposes + if (in_array('country', $names)) { + $countries = CRM_Core_PseudoConstant::country(); + } + + if (in_array('state_province', $names)) { + $provinces = CRM_Core_PseudoConstant::stateProvince(); + } + + if (in_array('world_region', $names)) { + $regions = CRM_Core_PseudoConstant::worldRegion(); + } + + $seenIDs = array(); + while ($result->fetch()) { + $row = array(); + + // the columns we are interested in + foreach ($names as $property) { + if ($property == 'status') { + continue; + } + if ($cfID = CRM_Core_BAO_CustomField::getKeyID($property)) { + $row[$property] = CRM_Core_BAO_CustomField::getDisplayValue($result->$property, + $cfID, + $this->_options, + $result->contact_id + ); + } + elseif ($multipleSelectFields && + array_key_exists($property, $multipleSelectFields) + ) { + //fix to display student checkboxes + $key = $property; + $paramsNew = array($key => $result->$property); + + if ($key == 'test_tutoring') { + $name = array($key => array('newName' => $key, 'groupName' => 'test')); + // for readers group + } + elseif (substr($key, 0, 4) == 'cmr_') { + $name = array($key => array('newName' => $key, 'groupName' => substr($key, 0, -3))); + } + else { + $name = array($key => array('newName' => $key, 'groupName' => $key)); + } + CRM_Core_OptionGroup::lookupValues($paramsNew, $name, FALSE); + $row[$key] = $paramsNew[$key]; + } + elseif (strpos($property, '-im')) { + $row[$property] = $result->$property; + if (!empty($result->$property)) { + $imProviders = CRM_Core_PseudoConstant::IMProvider(); + $providerId = $property . "-provider_id"; + $providerName = $imProviders[$result->$providerId]; + $row[$property] = $result->$property . " ({$providerName})"; + } + } + elseif (in_array($property, array( + 'addressee', 'email_greeting', 'postal_greeting'))) { + $greeting = $property . '_display'; + $row[$property] = $result->$greeting; + } + elseif ($property == 'country') { + $row[$property] = CRM_Utils_Array::value($result->country_id, $countries); + } + elseif ($property == 'state_province') { + $row[$property] = CRM_Utils_Array::value($result->state_province_id, $provinces); + } + elseif ($property == 'world_region') { + $row[$property] = CRM_Utils_Array::value($result->worldregion_id, $regions); + } + elseif (strpos($property, '-url') !== FALSE) { + $websiteUrl = ''; + $websiteKey = 'website-1'; + $propertyArray = explode('-', $property); + $websiteFld = $websiteKey . '-' . array_pop($propertyArray); + if (!empty($result->$websiteFld)) { + $websiteTypes = CRM_Core_PseudoConstant::websiteType(); + $websiteType = $websiteTypes[$result->{"$websiteKey-website_type_id"}]; + $websiteValue = $result->$websiteFld; + $websiteUrl = "{$websiteValue} ({$websiteType})"; + } + $row[$property] = $websiteUrl; + } + else { + $row[$property] = isset($result->$property) ? $result->$property : NULL; + } + } + + if (!empty($result->postal_code_suffix)) { + $row['postal_code'] .= "-" . $result->postal_code_suffix; + } + + if ($output != CRM_Core_Selector_Controller::EXPORT && + $this->_searchContext == 'smog' + ) { + if (empty($result->status) && + $groupID + ) { + $contactID = $result->contact_id; + if ($contactID) { + $gcParams = array( + 'contact_id' => $contactID, + 'group_id' => $groupID, + ); + + $gcDefaults = array(); + CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_GroupContact', $gcParams, $gcDefaults); + + if (empty($gcDefaults)) { + $row['status'] = ts('Smart'); + } + else { + $row['status'] = $gc[$gcDefaults['status']]; + } + } + else { + $row['status'] = NULL; + } + } + else { + $row['status'] = $gc[$result->status]; + } + } + + if ($output != CRM_Core_Selector_Controller::EXPORT) { + $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->contact_id; + + if (CRM_Utils_Array::value('deleted_contacts', $this->_formValues) + && CRM_Core_Permission::check('access deleted contacts') + ) { + $links = array( + array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view', + 'qs' => 'reset=1&cid=%%id%%', + 'title' => ts('View Contact Details'), + ), + array( + 'name' => ts('Restore'), + 'url' => 'civicrm/contact/view/delete', + 'qs' => 'reset=1&cid=%%id%%&restore=1', + 'title' => ts('Restore Contact'), + ), + ); + if (CRM_Core_Permission::check('delete contacts')) { + $links[] = array( + 'name' => ts('Delete Permanently'), + 'url' => 'civicrm/contact/view/delete', + 'qs' => 'reset=1&cid=%%id%%&skip_undelete=1', + 'title' => ts('Permanently Delete Contact'), + ); + } + $row['action'] = CRM_Core_Action::formLink($links, NULL, array('id' => $result->contact_id)); + } + elseif ((is_numeric(CRM_Utils_Array::value('geo_code_1', $row))) || + ($config->mapGeoCoding && + CRM_Utils_Array::value('city', $row) && + CRM_Utils_Array::value('state_province', $row) + ) + ) { + $row['action'] = CRM_Core_Action::formLink($links, $mask, array('id' => $result->contact_id)); + } + else { + $row['action'] = CRM_Core_Action::formLink($links, $mapMask, array('id' => $result->contact_id)); + } + + // allow components to add more actions + CRM_Core_Component::searchAction($row, $result->contact_id); + + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type, + FALSE, + $result->contact_id + ); + + $row['contact_type_orig'] = $result->contact_type; + $row['contact_sub_type'] = $result->contact_sub_type ? + CRM_Contact_BAO_ContactType::contactTypePairs(FALSE, $result->contact_sub_type, ', ') : $result->contact_sub_type; + $row['contact_id'] = $result->contact_id; + $row['sort_name'] = $result->sort_name; + if (array_key_exists('id', $row)) { + $row['id'] = $result->contact_id; + } + } + + // Dedupe contacts + if (in_array($row['contact_id'], $seenIDs) === FALSE) { + $seenIDs[] = $row['contact_id']; + $rows[] = $row; + } + } + + $this->buildPrevNextCache($sort); + + return $rows; + } + + function buildPrevNextCache($sort) { + $cacheKey = CRM_Utils_Array::value('qfKey', $this->_formValues); + + //for prev/next pagination + $crmPID = CRM_Utils_Request::retrieve('crmPID', 'Integer', CRM_Core_DAO::$_nullObject); + + //for alphabetic pagination selection save + $sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String', CRM_Core_DAO::$_nullObject); + + //for text field pagination selection save + $countRow = CRM_Core_BAO_PrevNextCache::getCount("%civicrm search {$cacheKey}%", NULL, "entity_table = 'civicrm_contact'", "LIKE"); + + if (!$crmPID && $countRow == 0 && !$sortByCharacter) { + $this->fillupPrevNextCache($sort); + } + elseif ($sortByCharacter) { + $cacheKeyCharacter = "civicrm search {$cacheKey}_alphabet"; + if ($sortByCharacter == 'all') { + //delete the alphabet key corresponding records in prevnext_cache + CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKeyCharacter, 'civicrm_contact'); + } + else { + $this->fillupPrevNextCache($sort, $cacheKeyCharacter); + } + } + } + + function addActions(&$rows) { + $config = CRM_Core_Config::singleton(); + + $permissions = array(CRM_Core_Permission::getPermission()); + if (CRM_Core_Permission::check('delete contacts')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + // mask value to hide map link if there are not lat/long + $mapMask = $mask & 4095; + + // mask value to hide map link if there are not lat/long + $mapMask = $mask & 4095; + + $links = self::links($this->_context, $this->_contextMenu, $this->_key); + + + foreach ($rows as $id => & $row) { + if (CRM_Utils_Array::value('deleted_contacts', $this->_formValues) + && CRM_Core_Permission::check('access deleted contacts') + ) { + $links = array( + array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view', + 'qs' => 'reset=1&cid=%%id%%', + 'title' => ts('View Contact Details'), + ), + array( + 'name' => ts('Restore'), + 'url' => 'civicrm/contact/view/delete', + 'qs' => 'reset=1&cid=%%id%%&restore=1', + 'title' => ts('Restore Contact'), + ), + ); + if (CRM_Core_Permission::check('delete contacts')) { + $links[] = array( + 'name' => ts('Delete Permanently'), + 'url' => 'civicrm/contact/view/delete', + 'qs' => 'reset=1&cid=%%id%%&skip_undelete=1', + 'title' => ts('Permanently Delete Contact'), + ); + } + $row['action'] = CRM_Core_Action::formLink($links, NULL, array('id' => $row['contact_id'])); + } + elseif ((is_numeric(CRM_Utils_Array::value('geo_code_1', $row))) || + ($config->mapGeoCoding && + CRM_Utils_Array::value('city', $row) && + CRM_Utils_Array::value('state_province', $row) + ) + ) { + $row['action'] = CRM_Core_Action::formLink($links, $mask, array('id' => $row['contact_id'])); + } + else { + $row['action'] = CRM_Core_Action::formLink($links, $mapMask, array('id' => $row['contact_id'])); + } + + // allow components to add more actions + CRM_Core_Component::searchAction($row, $row['contact_id']); + + $contactType = null; + if ( CRM_Utils_Array::value('contact_sub_type', $row) ) { + $contactType = $row['contact_sub_type']; + } + elseif ( CRM_Utils_Array::value('contact_type_orig', $row) ) { + $contactType = $row['contact_type_orig']; + } + + if ( $contactType ) { + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($contactType, + FALSE, $row['contact_id']); + } + } + } + + function removeActions(&$rows) { + foreach ($rows as $rid => & $rValue) { + unset($rValue['contact_type']); + unset($rValue['action']); + } + } + + function fillupPrevNextCache($sort, $cacheKey = NULL) { + if (!$cacheKey) { + $cacheKey = "civicrm search {$this->_key}"; + } + + CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey, 'civicrm_contact'); + + // lets fill up the prev next cache here, so view can scroll thru + if (is_a($this, 'CRM_Contact_Selector_Custom')) { + $sql = $this->_search->contactIDs(0, 0, $sort, TRUE); + $replaceSQL = "SELECT contact_a.id as contact_id"; + } + else { + $sql = $this->_query->searchQuery( + 0, 0, $sort, + FALSE, FALSE, + FALSE, TRUE, TRUE, NULL + ); + $replaceSQL = "SELECT contact_a.id as id"; + } + + // CRM-9096 + // due to limitations in our search query writer, the above query does not work + // in cases where the query is being sorted on a non-contact table + // this results in a fatal error :( + // see below for the gross hack of trapping the error and not filling + // the prev next cache in this situation + // the other alternative of running the FULL query will just be incredibly inefficient + // and slow things down way too much on large data sets / complex queries + + $insertSQL = " +INSERT INTO civicrm_prevnext_cache ( entity_table, entity_id1, entity_id2, cacheKey, data ) +SELECT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.display_name +"; + + $sql = str_replace($replaceSQL, $insertSQL, $sql); + + + CRM_Core_Error::ignoreException(); + $result = CRM_Core_DAO::executeQuery($sql); + CRM_Core_Error::setCallback(); + + if (is_a($result, 'DB_Error')) { + // oops the above query failed, so lets just ignore it + // and return + // we print a sorry cant figure it out on view page + return; + } + + // also record an entry in the cache key table, so we can delete it periodically + CRM_Core_BAO_Cache::setItem($cacheKey, 'CiviCRM Search PrevNextCache', $cacheKey); + } + + /** + * Given the current formValues, gets the query in local + * language + * + * @param array( + reference) $formValues submitted formValues + * + * @return array $qill which contains an array of strings + * @access public + */ + + // the current internationalisation is bad, but should more or less work + // for most of "European" languages + public function getQILL() { + return $this->_query->qill(); + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('CiviCRM Contact Search'); + } + + /** + * get colunmn headers for search selector + * + * + * @return array $_columnHeaders + * @access private + */ + private static function &_getColumnHeaders() { + if (!isset(self::$_columnHeaders)) { + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options', TRUE, NULL, TRUE + ); + + self::$_columnHeaders = array('contact_type' => array('desc' => ts('Contact Type')), + 'sort_name' => array( + 'name' => ts('Name'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::ASCENDING, + ), + ); + + $defaultAddress = array('street_address' => array('name' => ts('Address')), + 'city' => array('name' => ts('City'), + 'sort' => 'city', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + 'state_province' => array('name' => ts('State'), + 'sort' => 'state_province', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + 'postal_code' => array('name' => ts('Postal'), + 'sort' => 'postal_code', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + 'country' => array('name' => ts('Country'), + 'sort' => 'country', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + ); + + foreach ($defaultAddress as $columnName => $column) { + if (CRM_Utils_Array::value($columnName, $addressOptions)) { + self::$_columnHeaders[$columnName] = $column; + } + } + + self::$_columnHeaders['email'] = array('name' => ts('Email'), + 'sort' => 'email', + 'direction' => CRM_Utils_Sort::DONTCARE, + ); + + self::$_columnHeaders['phone'] = array('name' => ts('Phone')); + } + return self::$_columnHeaders; + } + + function &getQuery() { + return $this->_query; + } + + function alphabetQuery() { + return $this->_query->searchQuery(NULL, NULL, NULL, FALSE, FALSE, TRUE); + } + + function contactIDQuery($params, $action, $sortID, $displayRelationshipType = NULL, $queryOperator = 'AND') { + $sortOrder = &$this->getSortOrder($this->_action); + $sort = new CRM_Utils_Sort($sortOrder, $sortID); + + // rectify params to what proximity search expects if there is a value for prox_distance + // CRM-7021 CRM-7905 + if (!empty($params)) { + CRM_Contact_BAO_ProximityQuery::fixInputParams($params); + } + + if (!$displayRelationshipType) { + $query = new CRM_Contact_BAO_Query($params, + $this->_returnProperties, + NULL, FALSE, FALSE, 1, + FALSE, TRUE, TRUE, NULL, + $queryOperator + ); + } + else { + $query = new CRM_Contact_BAO_Query($params, $this->_returnProperties, + NULL, FALSE, FALSE, 1, + FALSE, TRUE, TRUE, $displayRelationshipType, + $queryOperator + ); + } + $value = $query->searchQuery(0, 0, $sort, + FALSE, FALSE, FALSE, + FALSE, FALSE + ); + return $value; + } + + function &makeProperties(&$returnProperties) { + $properties = array(); + foreach ($returnProperties as $name => $value) { + if ($name != 'location') { + $properties[] = $name; + } + else { + // extract all the location stuff + foreach ($value as $n => $v) { + foreach ($v as $n1 => $v1) { + if (!strpos('_id', $n1) && $n1 != 'location_type') { + $properties[] = "{$n}-{$n1}"; + } + } + } + } + } + return $properties; + } +} +//end of class + diff --git a/CRM/Contact/Selector/Controller.php b/CRM/Contact/Selector/Controller.php new file mode 100644 index 0000000000..3dc97fc277 --- /dev/null +++ b/CRM/Contact/Selector/Controller.php @@ -0,0 +1,40 @@ +_object->getQILL(); + } +} + diff --git a/CRM/Contact/Selector/Custom.php b/CRM/Contact/Selector/Custom.php new file mode 100644 index 0000000000..eb63dfb030 --- /dev/null +++ b/CRM/Contact/Selector/Custom.php @@ -0,0 +1,407 @@ +_customSearchClass = $customSearchClass; + $this->_formValues = $formValues; + $this->_includeContactIds = $includeContactIds; + + $ext = CRM_Extension_System::singleton()->getMapper(); + + if (!$ext->isExtensionKey($customSearchClass)) { + if ($ext->isExtensionClass($customSearchClass)) { + $customSearchFile = $ext->classToPath($customSearchClass); + require_once ($customSearchFile); + } + else { + require_once (str_replace('_', DIRECTORY_SEPARATOR, $customSearchClass) . '.php'); + } + eval('$this->_search = new ' . $customSearchClass . '( $formValues );'); + } + else { + $customSearchFile = $ext->keyToPath($customSearchClass, 'search'); + require_once ($customSearchFile); + eval('$this->_search = new ' . $ext->keyToClass($customSearchClass, 'search') . '( $formValues );'); + } + } + //end of constructor + + /** + * This method returns the links that are given for each search row. + * currently the links added for each row are + * + * - View + * - Edit + * + * @return array + * @access public + * + */ + static function &links() { + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view', + 'qs' => 'reset=1&cid=%%id%%', + 'title' => ts('View Contact Details'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/add', + 'qs' => 'reset=1&action=update&cid=%%id%%', + 'title' => ts('Edit Contact Details'), + ), + ); + + $config = CRM_Core_Config::singleton(); + if ($config->mapAPIKey && $config->mapProvider) { + self::$_links[CRM_Core_Action::MAP] = array( + 'name' => ts('Map'), + 'url' => 'civicrm/contact/map', + 'qs' => 'reset=1&cid=%%id%%&searchType=custom', + 'title' => ts('Map Contact'), + ); + } + } + return self::$_links; + } + //end of function + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['status'] = ts('Contact %%StatusMessage%%'); + $params['csvString'] = NULL; + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + //end of function + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + function &getColumnHeaders($action = NULL, $output = NULL) { + $columns = $this->_search->columns(); + if ($output == CRM_Core_Selector_Controller::EXPORT) { + return array_keys($columns); + } + else { + $headers = array(); + foreach ($columns as $name => $key) { + if (!empty($name)) { + $headers[] = array( + 'name' => $name, + 'sort' => $key, + 'direction' => CRM_Utils_Sort::ASCENDING, + ); + } + else { + $headers[] = array(); + } + } + return $headers; + } + } + + /** + * Returns total number of rows for the query. + * + * @param + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action) { + return $this->_search->count(); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return int the total number of rows for this action + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { + + $includeContactIDs = FALSE; + if (($output == CRM_Core_Selector_Controller::EXPORT || + $output == CRM_Core_Selector_Controller::SCREEN + ) && + $this->_formValues['radio_ts'] == 'ts_sel' + ) { + $includeContactIDs = TRUE; + } + + $sql = $this->_search->all($offset, $rowCount, $sort, $includeContactIDs); + + $dao = CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + + $columns = $this->_search->columns(); + $columnNames = array_values($columns); + $links = self::links(); + + $permissions = array(CRM_Core_Permission::getPermission()); + if (CRM_Core_Permission::check('delete contacts')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + $alterRow = FALSE; + if (method_exists($this->_customSearchClass, + 'alterRow' + )) { + $alterRow = TRUE; + } + $image = FALSE; + if (is_a($this->_search, 'CRM_Contact_Form_Search_Custom_Basic')) { + $image = TRUE; + } + // process the result of the query + $rows = array(); + while ($dao->fetch()) { + $row = array(); + $empty = TRUE; + + // the columns we are interested in + foreach ($columnNames as $property) { + $row[$property] = $dao->$property; + if (!empty($dao->$property)) { + $empty = FALSE; + } + } + if (!$empty) { + $contactID = isset($dao->contact_id) ? $dao->contact_id : NULL; + + $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $contactID; + $row['action'] = CRM_Core_Action::formLink($links, + $mask, + array('id' => $contactID) + ); + $row['contact_id'] = $contactID; + + if ($alterRow) { + $this->_search->alterRow($row); + } + + if ($image) { + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($dao->contact_sub_type ? + $dao->contact_sub_type : $dao->contact_type, FALSE, $contactID + ); + } + $rows[] = $row; + } + } + + $this->buildPrevNextCache($sort); + + return $rows; + } + + /** + * Given the current formValues, gets the query in local + * language + * + * @param array( + reference) $formValues submitted formValues + * + * @return array $qill which contains an array of strings + * @access public + */ + public function getQILL() { + return NULL; + } + + public function getSummary() { + return $this->_search->summary(); + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('CiviCRM Custom Search'); + } + + function alphabetQuery() { + return NULL; + } + + function &contactIDQuery($params, $action, $sortID, $displayRelationshipType = NULL, $queryOperator = 'AND') { + $params = array(); + $sql = $this->_search->contactIDs($params); + + return CRM_Core_DAO::executeQuery($sql, $params); + } + + function addActions(&$rows) { + $links = self::links(); + + $permissions = array(CRM_Core_Permission::getPermission()); + if (CRM_Core_Permission::check('delete contacts')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + foreach ($rows as $id => & $row) { + $row['action'] = CRM_Core_Action::formLink($links, + $mask, + array('id' => $row['contact_id']) + ); + } + } + + function removeActions(&$rows) { + foreach ($rows as $rid => & $rValue) { + unset($rValue['action']); + } + } +} + diff --git a/CRM/Contact/StateMachine/Search.php b/CRM/Contact/StateMachine/Search.php new file mode 100644 index 0000000000..f04eed1ac7 --- /dev/null +++ b/CRM/Contact/StateMachine/Search.php @@ -0,0 +1,144 @@ +_pages = array(); + if ($action == CRM_Core_Action::ADVANCED) { + $this->_pages['CRM_Contact_Form_Search_Advanced'] = NULL; + list($task, $result) = $this->taskName($controller, 'Advanced'); + } + elseif ($action == CRM_Core_Action::PROFILE) { + $this->_pages['CRM_Contact_Form_Search_Builder'] = NULL; + list($task, $result) = $this->taskName($controller, 'Builder'); + } + elseif ($action == CRM_Core_Action::COPY) { + $this->_pages['CRM_Contact_Form_Search_Custom'] = NULL; + list($task, $result) = $this->taskName($controller, 'Custom'); + } + else { + $this->_pages['CRM_Contact_Form_Search_Basic'] = NULL; + list($task, $result) = $this->taskName($controller, 'Basic'); + } + $this->_task = $task; + if (is_array($task)) { + foreach ($task as $t) { + $this->_pages[$t] = NULL; + } + } + else { + $this->_pages[$task] = NULL; + } + + if ($result) { + $this->_pages['CRM_Contact_Form_Task_Result'] = NULL; + } + + $this->addSequentialPages($this->_pages, $action); + } + + /** + * Determine the form name based on the action. This allows us + * to avoid using conditional state machine, much more efficient + * and simpler + * + * @param CRM_Core_Controller $controller the controller object + * + * @return string the name of the form that will handle the task + * @access protected + */ + function taskName($controller, $formName = 'Search') { + // total hack, check POST vars and then session to determine stuff + // fix value if print button is pressed + if (CRM_Utils_Array::value('_qf_' . $formName . '_next_print', $_POST)) { + $value = CRM_Contact_Task::PRINT_CONTACTS; + } + else { + $value = CRM_Utils_Array::value('task', $_POST); + } + if (!isset($value)) { + $value = $this->_controller->get('task'); + } + $this->_controller->set('task', $value); + + if ($value) { + $componentMode = $this->_controller->get('component_mode'); + $modeValue = CRM_Contact_Form_Search::getModeValue($componentMode); + require_once (str_replace('_', DIRECTORY_SEPARATOR, $modeValue['taskClassName']) . '.php'); + return eval("return {$modeValue['taskClassName']}::getTask( $value );"); + } + else { + return CRM_Contact_Task::getTask($value); + } + } + + /** + * return the form name of the task + * + * @return string + * @access public + */ + function getTaskFormName() { + if (is_array($this->_task)) { + // return first page + return CRM_Utils_String::getClassName($this->_task[0]); + } + else { + return CRM_Utils_String::getClassName($this->_task); + } + } + + /** + * Since this is a state machine for search and we want to come back to the same state + * we dont want to issue a reset of the state session when we are done processing a task + * + */ + function shouldReset() { + return FALSE; + } +} + diff --git a/CRM/Contact/Task.php b/CRM/Contact/Task.php new file mode 100644 index 0000000000..d0262dd650 --- /dev/null +++ b/CRM/Contact/Task.php @@ -0,0 +1,346 @@ + array('title' => ts('Add Contacts to Group'), + 'class' => 'CRM_Contact_Form_Task_AddToGroup', + ), + 2 => array('title' => ts('Remove Contacts from Group'), + 'class' => 'CRM_Contact_Form_Task_RemoveFromGroup', + ), + 3 => array('title' => ts('Tag Contacts (assign tags)'), + 'class' => 'CRM_Contact_Form_Task_AddToTag', + ), + 4 => array('title' => ts('Untag Contacts (remove tags)'), + 'class' => 'CRM_Contact_Form_Task_RemoveFromTag', + ), + 5 => array('title' => ts('Export Contacts'), + 'class' => array( + 'CRM_Export_Form_Select', + 'CRM_Export_Form_Map', + ), + 'result' => FALSE, + ), + 6 => array('title' => ts('Send Email to Contacts'), + 'class' => 'CRM_Contact_Form_Task_Email', + 'result' => TRUE, + ), + 7 => array('title' => ts('Send SMS to Contacts'), + 'class' => 'CRM_Contact_Form_Task_SMS', + 'result' => TRUE, + ), + 8 => array('title' => ts('Delete Contacts'), + 'class' => 'CRM_Contact_Form_Task_Delete', + 'result' => FALSE, + ), + 11 => array('title' => ts('Record Activity for Contacts'), + 'class' => 'CRM_Activity_Form_Activity', + ), + 13 => array('title' => ts('New Smart Group'), + 'class' => 'CRM_Contact_Form_Task_SaveSearch', + 'result' => TRUE, + ), + 14 => array('title' => ts('Update Smart Group'), + 'class' => 'CRM_Contact_Form_Task_SaveSearch_Update', + 'result' => TRUE, + ), + 15 => array('title' => ts('Print Contacts'), + 'class' => 'CRM_Contact_Form_Task_Print', + 'result' => FALSE, + ), + 16 => array('title' => ts('Mailing Labels'), + 'class' => 'CRM_Contact_Form_Task_Label', + 'result' => TRUE, + ), + 17 => array('title' => ts('Batch Update via Profile'), + 'class' => array( + 'CRM_Contact_Form_Task_PickProfile', + 'CRM_Contact_Form_Task_Batch', + ), + 'result' => TRUE, + ), + 19 => array('title' => ts('Print PDF Letter for Contacts'), + 'class' => 'CRM_Contact_Form_Task_PDF', + 'result' => TRUE, + ), + 22 => array('title' => ts('Unhold Emails'), + 'class' => 'CRM_Contact_Form_Task_Unhold', + ), + 25 => array('title' => ts('Alter Contact Communication Preferences'), + 'class' => 'CRM_Contact_Form_Task_AlterPreferences', + ), + self::RESTORE => array( + 'title' => ts('Restore Contacts'), + 'class' => 'CRM_Contact_Form_Task_Delete', + 'result' => FALSE, + ), + self::DELETE_PERMANENTLY => array( + 'title' => ts('Delete Permanently'), + 'class' => 'CRM_Contact_Form_Task_Delete', + 'result' => FALSE, + ), + ); + + if (CRM_Contact_BAO_ContactType::isActive('Household')) { + $label = CRM_Contact_BAO_ContactType::getLabel('Household'); + self::$_tasks[9] = array( + 'title' => ts('Add Contacts to %1', + array(1 => $label) + ), + 'class' => 'CRM_Contact_Form_Task_AddToHousehold', + ); + } + + if (CRM_Contact_BAO_ContactType::isActive('Organization')) { + $label = CRM_Contact_BAO_ContactType::getLabel('Organization'); + self::$_tasks[10] = array( + 'title' => ts('Add Contacts to %1', + array(1 => $label) + ), + 'class' => 'CRM_Contact_Form_Task_AddToOrganization', + ); + } + + if (CRM_Core_Permission::check('merge duplicate contacts')) { + self::$_tasks[21] = array('title' => ts('Merge Contacts'), + 'class' => 'CRM_Contact_Form_Task_Merge', + 'result' => TRUE, + ); + } + + //CRM-4418, check for delete + if (!CRM_Core_Permission::check('delete contacts')) { + unset(self::$_tasks[8]); + } + + //show map action only if map provider and geoprovider are set (Google doesn't need geoprovider) + // should fix this to be more flexible as providers are added ?? + $config = CRM_Core_Config::singleton(); + + if ($config->mapProvider && + ($config->mapProvider == 'Google' || + ($config->mapProvider == 'OpenStreetMaps' || + $config->geoProvider == 'Google' + ) + ) + ) { + self::$_tasks[12] = array('title' => ts('Map Contacts'), + 'class' => 'CRM_Contact_Form_Task_Map', + 'result' => FALSE, + ); + } + + if (CRM_Core_Permission::access('CiviEvent')) { + self::$_tasks[18] = array('title' => ts('Add Contacts to Event'), + 'class' => 'CRM_Event_Form_Participant', + ); + } + + if (CRM_Core_Permission::access('CiviMail')) { + self::$_tasks[20] = array('title' => ts('Schedule/Send a Mass Mailing'), + 'class' => array( + 'CRM_Mailing_Form_Group', + 'CRM_Mailing_Form_Settings', + 'CRM_Mailing_Form_Upload', + 'CRM_Mailing_Form_Test', + 'CRM_Mailing_Form_Schedule', + ), + 'result' => FALSE, + ); + } + elseif (CRM_Mailing_Info::workflowEnabled() && + CRM_Core_Permission::check('create mailings') + ) { + self::$_tasks[20] = array('title' => ts('Create a Mass Mailing'), + 'class' => array( + 'CRM_Mailing_Form_Group', + 'CRM_Mailing_Form_Settings', + 'CRM_Mailing_Form_Upload', + 'CRM_Mailing_Form_Test', + ), + 'result' => FALSE, + ); + } + + self::$_tasks += CRM_Core_Component::taskList(); + + CRM_Utils_Hook::searchTasks('contact', self::$_tasks); + + asort(self::$_tasks); + } + } + + /** + * These tasks are the core set of tasks that the user can perform + * on a contact / group of contacts + * + * @return array the set of tasks for a group of contacts + * @static + * @access public + */ + static function &taskTitles() { + self::initTasks(); + + $titles = array(); + foreach (self::$_tasks as $id => $value) { + $titles[$id] = $value['title']; + } + + // hack unset update saved search and print contacts + unset($titles[14]); + unset($titles[15]); + + $config = CRM_Core_Config::singleton(); + + if (!CRM_Utils_Mail::validOutBoundMail()) { + unset($titles[6]); + unset($titles[20]); + } + + // if ( ! in_array( 'CiviSMS', $config->enableComponents ) ) { + // unset( $titles[7] ); + // } + + // CRM-6806 + if (!CRM_Core_Permission::check('access deleted contacts') || + !CRM_Core_Permission::check('delete contacts') + ) { + unset($titles[self::DELETE_PERMANENTLY]); + } + asort($titles); + return $titles; + } + + /** + * show tasks selectively based on the permission level + * of the user + * + * @param int $permission + * @param bool $deletedContacts are these tasks for operating on deleted contacts? + * + * @return array set of tasks that are valid for the user + * @access public + */ + static function &permissionedTaskTitles($permission, $deletedContacts = false) { + self::initTasks(); + $tasks = array(); + if ($deletedContacts) { + if (CRM_Core_Permission::check('access deleted contacts')) { + $tasks[self::RESTORE] = self::$_tasks[self::RESTORE]['title']; + if (CRM_Core_Permission::check('delete contacts')) { + $tasks[self::DELETE_PERMANENTLY] = self::$_tasks[self::DELETE_PERMANENTLY]['title']; + } + } + } + elseif ($permission == CRM_Core_Permission::EDIT) { + $tasks = self::taskTitles(); + } + else { + $tasks = array( + 5 => self::$_tasks[5]['title'], + 6 => self::$_tasks[6]['title'], + 16 => self::$_tasks[16]['title'], + ); + + if (isset(self::$_tasks[12]) && + !empty(self::$_tasks[12]['title']) + ) { + $tasks[12] = self::$_tasks[12]['title']; + } + + if (isset(self::$_tasks[20]) && + !empty(self::$_tasks[20]['title']) + ) { + $tasks[20] = self::$_tasks[20]['title']; + } + } + return $tasks; + } + + /** + * These tasks get added based on the context the user is in + * + * @return array the set of optional tasks for a group of contacts + * @static + * @access public + */ + static function &optionalTaskTitle() { + $tasks = array( + 14 => self::$_tasks[14]['title'], + ); + return $tasks; + } + + static function getTask($value) { + self::initTasks(); + + if (!CRM_Utils_Array::value($value, self::$_tasks)) { + // make it the print task by default + $value = 15; + } + return array(CRM_Utils_Array::value('class', self::$_tasks[$value]), + CRM_Utils_Array::value('result', self::$_tasks[$value]), + ); + } +} + diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php new file mode 100644 index 0000000000..7435436307 --- /dev/null +++ b/CRM/Contribute/BAO/Contribution.php @@ -0,0 +1,2966 @@ +push(CRM_Core_Error::DUPLICATE_CONTRIBUTION, + 'Fatal', + array($d), + "Duplicate error - existing contribution record(s) have a matching Transaction ID or Invoice ID. Contribution record ID(s) are: $d" + ); + return $error; + } + + // first clean up all the money fields + $moneyFields = array( + 'total_amount', + 'net_amount', + 'fee_amount', + 'non_deductible_amount', + ); + //if priceset is used, no need to cleanup money + if (CRM_Utils_Array::value('skipCleanMoney', $params)) { + unset($moneyFields[0]); + } + + foreach ($moneyFields as $field) { + if (isset($params[$field])) { + $params[$field] = CRM_Utils_Rule::cleanMoney($params[$field]); + } + } + + if (CRM_Utils_Array::value('payment_instrument_id', $params)) { + $paymentInstruments = CRM_Contribute_PseudoConstant::paymentInstrument('name'); + if ($params['payment_instrument_id'] != array_search('Check', $paymentInstruments)) { + $params['check_number'] = 'null'; + } + } + + // contribution status is missing, choose Completed as default status + if (!CRM_Utils_Array::value('contribution_status_id', $params)) { + $params['contribution_status_id'] = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name'); + } + + if (CRM_Utils_Array::value('contribution', $ids)) { + CRM_Utils_Hook::pre('edit', 'Contribution', $ids['contribution'], $params); + } + else { + CRM_Utils_Hook::pre('create', 'Contribution', NULL, $params); + } + + $contribution = new CRM_Contribute_BAO_Contribution(); + $contribution->copyValues($params); + + $contribution->id = CRM_Utils_Array::value('contribution', $ids); + + if (!CRM_Utils_Rule::currencyCode($contribution->currency)) { + $config = CRM_Core_Config::singleton(); + $contribution->currency = $config->defaultCurrency; + } + + if (CRM_Utils_Array::value('contribution', $ids)) { + $contributionId['id'] = $ids['contribution']; + $params['prevContribution'] = self::getValues($contributionId, CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray); + if (CRM_Utils_Array::value('soft_credit_to', $params)) { + foreach (array('financial_type_id', 'total_amount') as $field) { + if (!isset($contribution->$field)) { + $contribution->$field = $params['prevContribution']->$field; + } + } + } + } + + $result = $contribution->save(); + + // Add financial_trxn details as part of fix for CRM-4724 + $contribution->trxn_result_code = CRM_Utils_Array::value('trxn_result_code', $params); + $contribution->payment_processor = CRM_Utils_Array::value('payment_processor', $params); + + //add Account details + $params['contribution'] = $contribution; + self::recordFinancialAccounts($params, $ids); + + // Add soft_contribution details as part of fix for CRM-8908 + $contribution->soft_credit_to = CRM_Utils_Array::value('soft_credit_to', $params); + + // reset the group contact cache for this group + CRM_Contact_BAO_GroupContactCache::remove(); + + if (CRM_Utils_Array::value('contribution', $ids)) { + CRM_Utils_Hook::post('edit', 'Contribution', $contribution->id, $contribution); + } + else { + CRM_Utils_Hook::post('create', 'Contribution', $contribution->id, $contribution); + } + + return $result; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $params input parameters to find object + * @param array $values output values of the object + * @param array $ids the array that holds all the db ids + * + * @return CRM_Contribute_BAO_Contribution|null the found object or null + * @access public + * @static + */ + static function &getValues(&$params, &$values, &$ids) { + if (empty($params)) { + return NULL; + } + $contribution = new CRM_Contribute_BAO_Contribution(); + + $contribution->copyValues($params); + + if ($contribution->find(TRUE)) { + $ids['contribution'] = $contribution->id; + + CRM_Core_DAO::storeValues($contribution, $values); + + return $contribution; + } + return NULL; + } + + /** + * takes an associative array and creates a contribution object + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $ids the array that holds all the db ids + * + * @return object CRM_Contribute_BAO_Contribution object + * @access public + * @static + */ + static function &create(&$params, &$ids) { + $dateFields = array('receive_date', 'cancel_date', 'receipt_date', 'thankyou_date'); + foreach ($dateFields as $df) { + if (isset($params[$df])) { + $params[$df] = CRM_Utils_Date::isoToMysql($params[$df]); + } + } + + if (CRM_Utils_Array::value('contribution', $ids) && + !CRM_Utils_Array::value('softID', $params) + ) { + if ($softID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionSoft', $ids['contribution'], 'id', 'contribution_id')) { + $params['softID'] = $softID; + } + } + + $transaction = new CRM_Core_Transaction(); + + // delete the soft credit record if no soft credit contact ID AND no PCP is set in the form + if (CRM_Utils_Array::value('contribution', $ids) && + (!CRM_Utils_Array::value('soft_credit_to', $params) && + !CRM_Utils_Array::value('pcp_made_through_id', $params) + ) && + CRM_Utils_Array::value('softID', $params) + ) { + $softCredit = new CRM_Contribute_DAO_ContributionSoft(); + $softCredit->id = $params['softID']; + $softCredit->delete(); + } + + $contribution = self::add($params, $ids); + + if (is_a($contribution, 'CRM_Core_Error')) { + $transaction->rollback(); + return $contribution; + } + + $params['contribution_id'] = $contribution->id; + + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_contribution', $contribution->id); + } + + $session = CRM_Core_Session::singleton(); + + if (CRM_Utils_Array::value('note', $params)) { + + $noteParams = array( + 'entity_table' => 'civicrm_contribution', + 'note' => $params['note'], + 'entity_id' => $contribution->id, + 'contact_id' => $session->get('userID'), + 'modified_date' => date('Ymd'), + ); + if (!$noteParams['contact_id']) { + $noteParams['contact_id'] = $params['contact_id']; + } + CRM_Core_BAO_Note::add($noteParams, + CRM_Utils_Array::value('note', $ids) + ); + } + + // make entry in batch entity batch table + if (CRM_Utils_Array::value('batch_id', $params)) { + // in some update cases we need to get extra fields - ie an update that doesn't pass in all these params + $titleFields = array( + 'contact_id', + 'total_amount', + 'currency', + 'financial_type_id', + ); + $retrieverequired = 0; + foreach ($titleFields as $titleField) { + if(!isset($contribution->$titleField)){ + $retrieverequired = 1; + break; + } + } + if ($retrieverequired == 1) { + $contribution->find(true); + } + } + + // check if activity record exist for this contribution, if + // not add activity + $activity = new CRM_Activity_DAO_Activity(); + $activity->source_record_id = $contribution->id; + $activity->activity_type_id = CRM_Core_OptionGroup::getValue('activity_type', + 'Contribution', + 'name' + ); + if (!$activity->find()) { + CRM_Activity_BAO_Activity::addActivity($contribution, 'Offline'); + } + // Handle soft credit and / or link to personal campaign page + if (CRM_Utils_Array::value('soft_credit_to', $params) || + CRM_Utils_Array::value('pcp_made_through_id', $params) + ) { + $csParams = array(); + if ($id = CRM_Utils_Array::value('softID', $params)) { + $csParams['id'] = $params['softID']; + } + + $csParams['contribution_id'] = $contribution->id; + // If pcp_made_through_id set, we define soft_credit_to contact based on selected PCP, + // else use passed soft_credit_to + if (CRM_Utils_Array::value('pcp_made_through_id', $params)) { + $csParams['pcp_display_in_roll'] = $params['pcp_display_in_roll'] ? 1 : 0; + foreach (array( + 'pcp_roll_nickname', 'pcp_personal_note') as $val) { + $csParams[$val] = $params[$val]; + } + + $csParams['pcp_id'] = CRM_Utils_Array::value('pcp_made_through_id', $params); + $csParams['contact_id'] = CRM_Core_DAO::getFieldValue('CRM_PCP_DAO_PCP', + $csParams['pcp_id'], 'contact_id' + ); + } + else { + $csParams['contact_id'] = $params['soft_credit_to']; + $csParams['pcp_id'] = ''; + } + + // first stage: we register whole amount as credited to given person + $csParams['amount'] = $contribution->total_amount; + + self::addSoftContribution($csParams); + } + + $transaction->commit(); + + // do not add to recent items for import, CRM-4399 + if (!CRM_Utils_Array::value('skipRecentView', $params)) { + $url = CRM_Utils_System::url('civicrm/contact/view/contribution', + "action=view&reset=1&id={$contribution->id}&cid={$contribution->contact_id}&context=home" + ); + // in some update cases we need to get extra fields - ie an update that doesn't pass in all these params + $titleFields = array( + 'contact_id', + 'total_amount', + 'currency', + 'financial_type_id', + ); + $retrieverequired = 0; + foreach ($titleFields as $titleField) { + if(!isset($contribution->$titleField)){ + $retrieverequired = 1; + break; + } + } + if($retrieverequired == 1){ + $contribution->find(true); + } + $contributionTypes = CRM_Contribute_PseudoConstant::financialType(); + $title = CRM_Contact_BAO_Contact::displayName($contribution->contact_id) . ' - (' . CRM_Utils_Money::format($contribution->total_amount, $contribution->currency) . ' ' . ' - ' . $contributionTypes[$contribution->financial_type_id] . ')'; + + $recentOther = array(); + if (CRM_Core_Permission::checkActionPermission('CiviContribute', CRM_Core_Action::UPDATE)) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/contact/view/contribution', + "action=update&reset=1&id={$contribution->id}&cid={$contribution->contact_id}&context=home" + ); + } + + if (CRM_Core_Permission::checkActionPermission('CiviContribute', CRM_Core_Action::DELETE)) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/contribution', + "action=delete&reset=1&id={$contribution->id}&cid={$contribution->contact_id}&context=home" + ); + } + + // add the recently created Contribution + CRM_Utils_Recent::add($title, + $url, + $contribution->id, + 'Contribution', + $contribution->contact_id, + NULL, + $recentOther + ); + } + + return $contribution; + } + + /** + * Get the values for pseudoconstants for name->value and reverse. + * + * @param array $defaults (reference) the default values, some of which need to be resolved. + * @param boolean $reverse true if we want to resolve the values in the reverse direction (value -> name) + * + * @return void + * @access public + * @static + */ + static function resolveDefaults(&$defaults, $reverse = FALSE) { + self::lookupValue($defaults, 'financial_type', CRM_Contribute_PseudoConstant::financialType(), $reverse); + self::lookupValue($defaults, 'payment_instrument', CRM_Contribute_PseudoConstant::paymentInstrument(), $reverse); + self::lookupValue($defaults, 'contribution_status', CRM_Contribute_PseudoConstant::contributionStatus(), $reverse); + self::lookupValue($defaults, 'pcp', CRM_Contribute_PseudoConstant::pcPage(), $reverse); + } + + /** + * This function is used to convert associative array names to values + * and vice-versa. + * + * This function is used by both the web form layer and the api. Note that + * the api needs the name => value conversion, also the view layer typically + * requires value => name conversion + */ + static function lookupValue(&$defaults, $property, &$lookup, $reverse) { + $id = $property . '_id'; + + $src = $reverse ? $property : $id; + $dst = $reverse ? $id : $property; + + if (!array_key_exists($src, $defaults)) { + return FALSE; + } + + $look = $reverse ? array_flip($lookup) : $lookup; + + if (is_array($look)) { + if (!array_key_exists($defaults[$src], $look)) { + return FALSE; + } + } + $defaults[$dst] = $look[$defaults[$src]]; + return TRUE; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. We'll tweak this function to be more + * full featured over a period of time. This is the inverse function of + * create. It also stores all the retrieved values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the name / value pairs + * in a hierarchical manner + * @param array $ids (reference) the array that holds all the db ids + * + * @return object CRM_Contribute_BAO_Contribution object + * @access public + * @static + */ + static function retrieve(&$params, &$defaults, &$ids) { + $contribution = CRM_Contribute_BAO_Contribution::getValues($params, $defaults, $ids); + return $contribution; + } + + /** + * combine all the importable fields from the lower levels object + * + * The ordering is important, since currently we do not have a weight + * scheme. Adding weight is super important and should be done in the + * next week or so, before this can be called complete. + * + * @return array array of importable Fields + * @access public + * @static + */ + static function &importableFields($contacType = 'Individual', $status = TRUE) { + if (!self::$_importableFields) { + if (!self::$_importableFields) { + self::$_importableFields = array(); + } + + if (!$status) { + $fields = array('' => array('title' => ts('- do not import -'))); + } + else { + $fields = array('' => array('title' => ts('- Contribution Fields -'))); + } + + $note = CRM_Core_DAO_Note::import(); + $tmpFields = CRM_Contribute_DAO_Contribution::import(); + unset($tmpFields['option_value']); + $optionFields = CRM_Core_OptionValue::getFields($mode = 'contribute'); + $contactFields = CRM_Contact_BAO_Contact::importableFields($contacType, NULL); + + // Using new Dedupe rule. + $ruleParams = array( + 'contact_type' => $contacType, + 'used' => 'Unsupervised', + ); + $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); + $tmpConatctField = array(); + if (is_array($fieldsArray)) { + foreach ($fieldsArray as $value) { + //skip if there is no dupe rule + if ($value == 'none') { + continue; + } + $customFieldId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', + $value, + 'id', + 'column_name' + ); + $value = $customFieldId ? 'custom_' . $customFieldId : $value; + $tmpConatctField[trim($value)] = $contactFields[trim($value)]; + if (!$status) { + $title = $tmpConatctField[trim($value)]['title'] . ' ' . ts('(match to contact)'); + } + else { + $title = $tmpConatctField[trim($value)]['title']; + } + $tmpConatctField[trim($value)]['title'] = $title; + } + } + + $tmpConatctField['external_identifier'] = $contactFields['external_identifier']; + $tmpConatctField['external_identifier']['title'] = $contactFields['external_identifier']['title'] . ' ' . ts('(match to contact)'); + $tmpFields['contribution_contact_id']['title'] = $tmpFields['contribution_contact_id']['title'] . ' ' . ts('(match to contact)'); + $fields = array_merge($fields, $tmpConatctField); + $fields = array_merge($fields, $tmpFields); + $fields = array_merge($fields, $note); + $fields = array_merge($fields, $optionFields); + $fields = array_merge($fields, CRM_Financial_DAO_FinancialType::export()); + $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Contribution')); + self::$_importableFields = $fields; + } + return self::$_importableFields; + } + + static function &exportableFields() { + if (!self::$_exportableFields) { + if (!self::$_exportableFields) { + self::$_exportableFields = array(); + } + + $impFields = CRM_Contribute_DAO_Contribution::export(); + $expFieldProduct = CRM_Contribute_DAO_Product::export(); + $expFieldsContrib = CRM_Contribute_DAO_ContributionProduct::export(); + $typeField = CRM_Financial_DAO_FinancialType::export(); + $financialAccount = CRM_Financial_DAO_FinancialAccount::export(); + $optionField = CRM_Core_OptionValue::getFields($mode = 'contribute'); + $contributionStatus = array( + 'contribution_status' => array( + 'title' => ts('Contribution Status'), + 'name' => 'contribution_status', + 'data_type' => CRM_Utils_Type::T_STRING + )); + + $contributionNote = array( + 'contribution_note' => + array( + 'title' => ts('Contribution Note'), + 'name' => 'contribution_note', + 'data_type' => CRM_Utils_Type::T_TEXT + ) + ); + + $contributionRecurId = array( + 'contribution_recur_id' => + array( + 'title' => ts('Recurring Contributions ID'), + 'name' => 'contribution_recur_id', + 'where' => 'civicrm_contribution.contribution_recur_id', + 'data_type' => CRM_Utils_Type::T_INT + )); + + $extraFields = array( + 'contribution_campaign' => + array( + 'title' => ts('Campaign Title') + ), + 'contribution_batch' => + array( + 'title' => ts('Batch Name') + ) + ); + + $fields = array_merge($impFields, $typeField, $contributionStatus, $optionField, $expFieldProduct, + $expFieldsContrib, $contributionNote, $contributionRecurId, $extraFields, $financialAccount, + CRM_Core_BAO_CustomField::getFieldsForImport('Contribution') + ); + + self::$_exportableFields = $fields; + } + + return self::$_exportableFields; + } + + static function getTotalAmountAndCount($status = NULL, $startDate = NULL, $endDate = NULL) { + $where = array(); + switch ($status) { + case 'Valid': + $where[] = 'contribution_status_id = 1'; + break; + + case 'Cancelled': + $where[] = 'contribution_status_id = 3'; + break; + } + + if ($startDate) { + $where[] = "receive_date >= '" . CRM_Utils_Type::escape($startDate, 'Timestamp') . "'"; + } + if ($endDate) { + $where[] = "receive_date <= '" . CRM_Utils_Type::escape($endDate, 'Timestamp') . "'"; + } + + $whereCond = implode(' AND ', $where); + + $query = " + SELECT sum( total_amount ) as total_amount, + count( civicrm_contribution.id ) as total_count, + currency + FROM civicrm_contribution +INNER JOIN civicrm_contact contact ON ( contact.id = civicrm_contribution.contact_id ) + WHERE $whereCond + AND ( is_test = 0 OR is_test IS NULL ) + AND contact.is_deleted = 0 + GROUP BY currency +"; + + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + $amount = array(); + $count = 0; + while ($dao->fetch()) { + $count += $dao->total_count; + $amount[] = CRM_Utils_Money::format($dao->total_amount, $dao->currency); + } + if ($count) { + return array('amount' => implode(', ', $amount), + 'count' => $count, + ); + } + return NULL; + } + + /** + * Delete the indirect records associated with this contribution first + * + * @return $results no of deleted Contribution on success, false otherwise + * @access public + * @static + */ + static function deleteContribution($id) { + CRM_Utils_Hook::pre('delete', 'Contribution', $id, CRM_Core_DAO::$_nullArray); + + $transaction = new CRM_Core_Transaction(); + + $results = NULL; + //delete activity record + $params = array( + 'source_record_id' => $id, + // activity type id for contribution + 'activity_type_id' => 6, + ); + + CRM_Activity_BAO_Activity::deleteActivity($params); + + //delete billing address if exists for this contribution. + self::deleteAddress($id); + + //update pledge and pledge payment, CRM-3961 + CRM_Pledge_BAO_PledgePayment::resetPledgePayment($id); + + // remove entry from civicrm_price_set_entity, CRM-5095 + if (CRM_Price_BAO_Set::getFor('civicrm_contribution', $id)) { + CRM_Price_BAO_Set::removeFrom('civicrm_contribution', $id); + } + // cleanup line items. + $participantId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $id, 'participant_id', 'contribution_id'); + + // delete any related entity_financial_trxn and financial_trxn records. + CRM_Core_BAO_FinancialTrxn::deleteFinancialTrxn($id, 'civicrm_contribution'); + + if ($participantId) { + CRM_Price_BAO_LineItem::deleteLineItems($participantId, 'civicrm_participant'); + } + else { + CRM_Price_BAO_LineItem::deleteLineItems($id, 'civicrm_contribution'); + } + + //delete note. + $note = CRM_Core_BAO_Note::getNote($id, 'civicrm_contribution'); + $noteId = key($note); + if ($noteId) { + CRM_Core_BAO_Note::del($noteId, FALSE); + } + + $dao = new CRM_Contribute_DAO_Contribution(); + $dao->id = $id; + + $results = $dao->delete(); + + $transaction->commit(); + + CRM_Utils_Hook::post('delete', 'Contribution', $dao->id, $dao); + + // delete the recently created Contribution + $contributionRecent = array( + 'id' => $id, + 'type' => 'Contribution', + ); + CRM_Utils_Recent::del($contributionRecent); + + return $results; + } + + /** + * Check if there is a contribution with the same trxn_id or invoice_id + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $duplicates (reference ) store ids of duplicate contribs + * + * @return boolean true if duplicate, false otherwise + * @access public + * static + */ + static function checkDuplicate($input, &$duplicates, $id = NULL) { + if (!$id) { + $id = CRM_Utils_Array::value('id', $input); + } + $trxn_id = CRM_Utils_Array::value('trxn_id', $input); + $invoice_id = CRM_Utils_Array::value('invoice_id', $input); + + $clause = array(); + $input = array(); + + if ($trxn_id) { + $clause[] = "trxn_id = %1"; + $input[1] = array($trxn_id, 'String'); + } + + if ($invoice_id) { + $clause[] = "invoice_id = %2"; + $input[2] = array($invoice_id, 'String'); + } + + if (empty($clause)) { + return FALSE; + } + + $clause = implode(' OR ', $clause); + if ($id) { + $clause = "( $clause ) AND id != %3"; + $input[3] = array($id, 'Integer'); + } + + $query = "SELECT id FROM civicrm_contribution WHERE $clause"; + $dao = CRM_Core_DAO::executeQuery($query, $input); + $result = FALSE; + while ($dao->fetch()) { + $duplicates[] = $dao->id; + $result = TRUE; + } + return $result; + } + + /** + * takes an associative array and creates a contribution_product object + * + * the function extract all the params it needs to initialize the create a + * contribution_product object. the params array could contain additional unused name/value + * pairs + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return object CRM_Contribute_BAO_ContributionProduct object + * @access public + * @static + */ + static function addPremium(&$params) { + $contributionProduct = new CRM_Contribute_DAO_ContributionProduct(); + $contributionProduct->copyValues($params); + return $contributionProduct->save(); + } + + /** + * Function to get list of contribution fields for profile + * For now we only allow custom contribution fields to be in + * profile + * + * @param boolean $addExtraFields true if special fields needs to be added + * + * @return return the list of contribution fields + * @static + * @access public + */ + static function getContributionFields($addExtraFields = TRUE) { + $contributionFields = CRM_Contribute_DAO_Contribution::export(); + $contributionFields = array_merge($contributionFields, CRM_Core_OptionValue::getFields($mode = 'contribute')); + + if ($addExtraFields) { + $contributionFields = array_merge($contributionFields, self::getSpecialContributionFields()); + } + + $contributionFields = array_merge($contributionFields, CRM_Financial_DAO_FinancialType::export()); + + foreach ($contributionFields as $key => $var) { + if ($key == 'contribution_contact_id') { + continue; + } + elseif ($key == 'contribution_campaign_id') { + $var['title'] = ts('Campaign'); + } + $fields[$key] = $var; + } + + $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Contribution')); + return $fields; + } + + /** + * Function to add extra fields specific to contribtion + * + * @static + */ + static function getSpecialContributionFields() { + $extraFields = array( + 'honor_contact_name' => array( + 'name' => 'honor_contact_name', + 'title' => 'Honor Contact Name', + 'headerPattern' => '/^honor_contact_name$/i', + 'where' => 'civicrm_contact_c.display_name', + ), + 'honor_contact_email' => array( + 'name' => 'honor_contact_email', + 'title' => 'Honor Contact Email', + 'headerPattern' => '/^honor_contact_email$/i', + 'where' => 'honor_email.email', + ), + 'honor_contact_id' => array( + 'name' => 'honor_contact_id', + 'title' => 'Honor Contact ID', + 'headerPattern' => '/^honor_contact_id$/i', + 'where' => 'civicrm_contribution.honor_contact_id', + ), + 'honor_type_label' => array( + 'name' => 'honor_type_label', + 'title' => 'Honor Type Label', + 'headerPattern' => '/^honor_type_label$/i', + 'where' => 'honor_type.label', + ), + 'soft_credit_name' => array( + 'name' => 'soft_credit_name', + 'title' => 'Soft Credit Name', + 'headerPattern' => '/^soft_credit_name$/i', + 'where' => 'civicrm_contact_d.display_name', + ), + 'soft_credit_email' => array( + 'name' => 'soft_credit_email', + 'title' => 'Soft Credit Email', + 'headerPattern' => '/^soft_credit_email$/i', + 'where' => 'soft_email.email', + ), + 'soft_credit_phone' => array( + 'name' => 'soft_credit_phone', + 'title' => 'Soft Credit Phone', + 'headerPattern' => '/^soft_credit_phone$/i', + 'where' => 'soft_phone.phone', + ), + 'soft_credit_contact_id' => array( + 'name' => 'soft_credit_contact_id', + 'title' => 'Soft Credit Contact ID', + 'headerPattern' => '/^soft_credit_contact_id$/i', + 'where' => 'civicrm_contribution_soft.contact_id', + ), + ); + + return $extraFields; + } + + static function getCurrentandGoalAmount($pageID) { + $query = " +SELECT p.goal_amount as goal, sum( c.total_amount ) as total + FROM civicrm_contribution_page p, + civicrm_contribution c + WHERE p.id = c.contribution_page_id + AND p.id = %1 + AND c.cancel_date is null +GROUP BY p.id +"; + + $config = CRM_Core_Config::singleton(); + $params = array(1 => array($pageID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + if ($dao->fetch()) { + return array($dao->goal, $dao->total); + } + else { + return array(NULL, NULL); + } + } + + /** + * Function to create is honor of + * + * @param array $params associated array of fields (by reference) + * @param int $honorId honor Id + * @param array $honorParams any params that should be send to the create function + * + * @return contact id + */ + static function createHonorContact(&$params, $honorId = NULL, $honorParams = array()) { + $honorParams = array_merge( + array( + 'first_name' => $params['honor_first_name'], + 'last_name' => $params['honor_last_name'], + 'prefix_id' => $params['honor_prefix_id'], + 'email-Primary' => $params['honor_email'], + ), + $honorParams + ); + if (!$honorId) { + $honorParams['email'] = $params['honor_email']; + + $dedupeParams = CRM_Dedupe_Finder::formatParams($honorParams, 'Individual'); + $dedupeParams['check_permission'] = FALSE; + $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual'); + + // if we find more than one contact, use the first one + $honorId = CRM_Utils_Array::value(0, $ids); + } + + $contactID = CRM_Contact_BAO_Contact::createProfileContact( + $honorParams, + CRM_Core_DAO::$_nullArray, + $honorId + ); + return $contactID; + } + + /** + * Function to get list of contribution In Honor of contact Ids + * + * @param int $honorId In Honor of Contact ID + * + * @return return the list of contribution fields + * + * @access public + * @static + */ + static function getHonorContacts($honorId) { + $params = array(); + $honorDAO = new CRM_Contribute_DAO_Contribution(); + $honorDAO->honor_contact_id = $honorId; + $honorDAO->find(); + + $status = CRM_Contribute_PseudoConstant::contributionStatus($honorDAO->contribution_status_id); + $type = CRM_Contribute_PseudoConstant::financialType(); + + while ($honorDAO->fetch()) { + $params[$honorDAO->id]['honorId'] = $honorDAO->contact_id; + $params[$honorDAO->id]['display_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $honorDAO->contact_id, 'display_name'); + $params[$honorDAO->id]['type'] = $type[$honorDAO->financial_type_id]; + $params[$honorDAO->id]['type_id'] = $honorDAO->financial_type_id; + $params[$honorDAO->id]['amount'] = CRM_Utils_Money::format($honorDAO->total_amount, $honorDAO->currency); + $params[$honorDAO->id]['source'] = $honorDAO->source; + $params[$honorDAO->id]['receive_date'] = $honorDAO->receive_date; + $params[$honorDAO->id]['contribution_status'] = CRM_Utils_Array::value($honorDAO->contribution_status_id, $status); + } + + return $params; + } + + /** + * function to get the sort name of a contact for a particular contribution + * + * @param int $id id of the contribution + * + * @return null|string sort name of the contact if found + * @static + * @access public + */ + static function sortName($id) { + $id = CRM_Utils_Type::escape($id, 'Integer'); + + $query = " +SELECT civicrm_contact.sort_name +FROM civicrm_contribution, civicrm_contact +WHERE civicrm_contribution.contact_id = civicrm_contact.id + AND civicrm_contribution.id = {$id} +"; + return CRM_Core_DAO::singleValueQuery($query, CRM_Core_DAO::$_nullArray); + } + + static function annual($contactID) { + if (is_array($contactID)) { + $contactIDs = implode(',', $contactID); + } + else { + $contactIDs = $contactID; + } + + $config = CRM_Core_Config::singleton(); + $startDate = $endDate = NULL; + + $currentMonth = date('m'); + $currentDay = date('d'); + if ((int ) $config->fiscalYearStart['M'] > $currentMonth || + ((int ) $config->fiscalYearStart['M'] == $currentMonth && + (int ) $config->fiscalYearStart['d'] > $currentDay + ) + ) { + $year = date('Y') - 1; + } + else { + $year = date('Y'); + } + $nextYear = $year + 1; + + if ($config->fiscalYearStart) { + if ($config->fiscalYearStart['M'] < 10) { + $config->fiscalYearStart['M'] = '0' . $config->fiscalYearStart['M']; + } + if ($config->fiscalYearStart['d'] < 10) { + $config->fiscalYearStart['d'] = '0' . $config->fiscalYearStart['d']; + } + $monthDay = $config->fiscalYearStart['M'] . $config->fiscalYearStart['d']; + } + else { + $monthDay = '0101'; + } + $startDate = "$year$monthDay"; + $endDate = "$nextYear$monthDay"; + + $query = " + SELECT count(*) as count, + sum(total_amount) as amount, + avg(total_amount) as average, + currency + FROM civicrm_contribution b + WHERE b.contact_id IN ( $contactIDs ) + AND b.contribution_status_id = 1 + AND b.is_test = 0 + AND b.receive_date >= $startDate + AND b.receive_date < $endDate + GROUP BY currency + "; + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + $count = 0; + $amount = $average = array(); + while ($dao->fetch()) { + if ($dao->count > 0 && $dao->amount > 0) { + $count += $dao->count; + $amount[] = CRM_Utils_Money::format($dao->amount, $dao->currency); + $average[] = CRM_Utils_Money::format($dao->average, $dao->currency); + } + } + if ($count > 0) { + return array( + $count, + implode(', ', $amount), + implode(', ', $average), + ); + } + return array(0, 0, 0); + } + + /** + * Check if there is a contribution with the params passed in. + * Used for trxn_id,invoice_id and contribution_id + * + * @param array $params an assoc array of name/value pairs + * + * @return array contribution id if success else NULL + * @access public + * static + */ + static function checkDuplicateIds($params) { + $dao = new CRM_Contribute_DAO_Contribution(); + + $clause = array(); + $input = array(); + foreach ($params as $k => $v) { + if ($v) { + $clause[] = "$k = '$v'"; + } + } + $clause = implode(' AND ', $clause); + $query = "SELECT id FROM civicrm_contribution WHERE $clause"; + $dao = CRM_Core_DAO::executeQuery($query, $input); + + while ($dao->fetch()) { + $result = $dao->id; + return $result; + } + return NULL; + } + + /** + * Function to get the contribution details for component export + * + * @param int $exportMode export mode + * @param string $componentIds component ids + * + * @return array associated array + * + * @static + * @access public + */ + static function getContributionDetails($exportMode, $componentIds) { + $paymentDetails = array(); + $componentClause = ' IN ( ' . implode(',', $componentIds) . ' ) '; + + if ($exportMode == CRM_Export_Form_Select::EVENT_EXPORT) { + $componentSelect = " civicrm_participant_payment.participant_id id"; + $additionalClause = " +INNER JOIN civicrm_participant_payment ON (civicrm_contribution.id = civicrm_participant_payment.contribution_id +AND civicrm_participant_payment.participant_id {$componentClause} ) +"; + } + elseif ($exportMode == CRM_Export_Form_Select::MEMBER_EXPORT) { + $componentSelect = " civicrm_membership_payment.membership_id id"; + $additionalClause = " +INNER JOIN civicrm_membership_payment ON (civicrm_contribution.id = civicrm_membership_payment.contribution_id +AND civicrm_membership_payment.membership_id {$componentClause} ) +"; + } + elseif ($exportMode == CRM_Export_Form_Select::PLEDGE_EXPORT) { + $componentSelect = " civicrm_pledge_payment.id id"; + $additionalClause = " +INNER JOIN civicrm_pledge_payment ON (civicrm_contribution.id = civicrm_pledge_payment.contribution_id +AND civicrm_pledge_payment.pledge_id {$componentClause} ) +"; + } + + $query = " SELECT total_amount, contribution_status.name as status_id, contribution_status.label as status, payment_instrument.name as payment_instrument, receive_date, + trxn_id, {$componentSelect} +FROM civicrm_contribution +LEFT JOIN civicrm_option_group option_group_payment_instrument ON ( option_group_payment_instrument.name = 'payment_instrument') +LEFT JOIN civicrm_option_value payment_instrument ON (civicrm_contribution.payment_instrument_id = payment_instrument.value + AND option_group_payment_instrument.id = payment_instrument.option_group_id ) +LEFT JOIN civicrm_option_group option_group_contribution_status ON (option_group_contribution_status.name = 'contribution_status') +LEFT JOIN civicrm_option_value contribution_status ON (civicrm_contribution.contribution_status_id = contribution_status.value + AND option_group_contribution_status.id = contribution_status.option_group_id ) +{$additionalClause} +"; + + $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + + while ($dao->fetch()) { + $paymentDetails[$dao->id] = array( + 'total_amount' => $dao->total_amount, + 'contribution_status' => $dao->status, + 'receive_date' => $dao->receive_date, + 'pay_instru' => $dao->payment_instrument, + 'trxn_id' => $dao->trxn_id, + ); + } + + return $paymentDetails; + } + + /** + * Function to create address associated with contribution record. + * @param array $params an associated array + * @param int $billingID $billingLocationTypeID + * + * @return address id + * @static + */ + static function createAddress(&$params, $billingLocationTypeID) { + $billingFields = array( + 'street_address', + 'city', + 'state_province_id', + 'postal_code', + 'country_id', + ); + + //build address array + $addressParams = array(); + $addressParams['location_type_id'] = $billingLocationTypeID; + $addressParams['is_billing'] = 1; + $addressParams['address_name'] = "{$params['billing_first_name']}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$params['billing_middle_name']}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$params['billing_last_name']}"; + + foreach ($billingFields as $value) { + $addressParams[$value] = $params["billing_{$value}-{$billingLocationTypeID}"]; + } + + $address = CRM_Core_BAO_Address::add($addressParams, FALSE); + + return $address->id; + } + + /** + * Function to create soft contributon with contribution record. + * @param array $params an associated array + * + * @return soft contribution id + * @static + */ + static function addSoftContribution($params) { + $softContribution = new CRM_Contribute_DAO_ContributionSoft(); + $softContribution->copyValues($params); + + // set currency for CRM-1496 + if (!isset($softContribution->currency)) { + $config = CRM_Core_Config::singleton(); + $softContribution->currency = $config->defaultCurrency; + } + + return $softContribution->save(); + } + + /** + * Function to retrieve soft contributon for contribution record. + * @param array $params an associated array + * + * @return soft contribution id + * @static + */ + static function getSoftContribution($params, $all = FALSE) { + $cs = new CRM_Contribute_DAO_ContributionSoft(); + $cs->copyValues($params); + $softContribution = array(); + if ($cs->find(TRUE)) { + if ($all) { + foreach (array( + 'pcp_id', 'pcp_display_in_roll', 'pcp_roll_nickname', 'pcp_personal_note') as $key => $val) { + $softContribution[$val] = $cs->$val; + } + } + $softContribution['soft_credit_to'] = $cs->contact_id; + $softContribution['soft_credit_id'] = $cs->id; + + } + return $softContribution; + } + + /** + * Function to retrieve the list of soft contributons for given contact. + * @param int $contact_id contact id + * + * @return array + * @static + */ + static function getSoftContributionList($contact_id, $isTest = 0) { + $query = " + SELECT ccs.id, ccs.amount as amount, + ccs.contribution_id, + ccs.pcp_id, + ccs.pcp_display_in_roll, + ccs.pcp_roll_nickname, + ccs.pcp_personal_note, + cc.receive_date, + cc.contact_id as contributor_id, + cc.contribution_status_id as contribution_status_id, + cp.title as pcp_title, + cc.currency, + contact.display_name, + cct.name as contributionType + FROM civicrm_contribution_soft ccs + LEFT JOIN civicrm_contribution cc + ON ccs.contribution_id = cc.id + LEFT JOIN civicrm_pcp cp + ON ccs.pcp_id = cp.id + LEFT JOIN civicrm_contact contact + ON ccs.contribution_id = cc.id AND + cc.contact_id = contact.id + LEFT JOIN civicrm_financial_type cct + ON cc.financial_type_id = cct.id + WHERE cc.is_test = %2 AND ccs.contact_id = %1 + ORDER BY cc.receive_date DESC"; + + $params = array(1 => array($contact_id, 'Integer'), + 2 => array($isTest, 'Integer')); + $cs = CRM_Core_DAO::executeQuery($query, $params); + $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(); + $result = array(); + while ($cs->fetch()) { + $result[$cs->id]['amount'] = $cs->amount; + $result[$cs->id]['currency'] = $cs->currency; + $result[$cs->id]['contributor_id'] = $cs->contributor_id; + $result[$cs->id]['contribution_id'] = $cs->contribution_id; + $result[$cs->id]['contributor_name'] = $cs->display_name; + $result[$cs->id]['financial_type'] = $cs->contributionType; + $result[$cs->id]['receive_date'] = $cs->receive_date; + $result[$cs->id]['pcp_id'] = $cs->pcp_id; + $result[$cs->id]['pcp_title'] = $cs->pcp_title; + $result[$cs->id]['pcp_display_in_roll'] = $cs->pcp_display_in_roll; + $result[$cs->id]['pcp_roll_nickname'] = $cs->pcp_roll_nickname; + $result[$cs->id]['pcp_personal_note'] = $cs->pcp_personal_note; + $result[$cs->id]['contribution_status'] = CRM_Utils_Array::value($cs->contribution_status_id, $contributionStatus); + + if ($isTest) { + $result[$cs->id]['contribution_status'] = $result[$cs->id]['contribution_status'] . '
    (test)'; + } + } + return $result; + } + + static function getSoftContributionTotals($contact_id, $isTest = 0) { + $query = " + SELECT SUM(amount) as amount, + AVG(total_amount) as average, + cc.currency + FROM civicrm_contribution_soft ccs + LEFT JOIN civicrm_contribution cc + ON ccs.contribution_id = cc.id + WHERE cc.is_test = %2 AND + ccs.contact_id = %1 + GROUP BY currency "; + + $params = array(1 => array($contact_id, 'Integer'), + 2 => array($isTest, 'Integer')); + + $cs = CRM_Core_DAO::executeQuery($query, $params); + + $count = 0; + $amount = $average = array(); + + while ($cs->fetch()) { + if ($cs->amount > 0) { + $count++; + $amount[] = $cs->amount; + $average[] = $cs->average; + $currency[] = $cs->currency; + } + } + + if ($count > 0) { + return array(implode(', ', $amount), + implode(', ', $average), + implode(', ', $currency), + ); + } + return array(0, 0); + } + + /** + * Delete billing address record related contribution + * + * @param int $contact_id contact id + * @param int $contribution_id contributionId + * @access public + * @static + */ + static function deleteAddress($contributionId = NULL, $contactId = NULL) { + $clauses = array(); + $contactJoin = NULL; + + if ($contributionId) { + $clauses[] = "cc.id = {$contributionId}"; + } + + if ($contactId) { + $clauses[] = "cco.id = {$contactId}"; + $contactJoin = "INNER JOIN civicrm_contact cco ON cc.contact_id = cco.id"; + } + + if (empty($clauses)) { + CRM_Core_Error::fatal(); + } + + $condition = implode(' OR ', $clauses); + + $query = " +SELECT ca.id +FROM civicrm_address ca +INNER JOIN civicrm_contribution cc ON cc.address_id = ca.id + $contactJoin +WHERE $condition +"; + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $params = array('id' => $dao->id); + CRM_Core_BAO_Block::blockDelete('Address', $params); + } + } + + /** + * This function check online pending contribution associated w/ + * Online Event Registration or Online Membership signup. + * + * @param int $componentId participant/membership id. + * @param string $componentName Event/Membership. + * + * @return $contributionId pending contribution id. + * @static + */ + static function checkOnlinePendingContribution($componentId, $componentName) { + $contributionId = NULL; + if (!$componentId || + !in_array($componentName, array('Event', 'Membership')) + ) { + return $contributionId; + } + + if ($componentName == 'Event') { + $idName = 'participant_id'; + $componentTable = 'civicrm_participant'; + $paymentTable = 'civicrm_participant_payment'; + $source = ts('Online Event Registration'); + } + + if ($componentName == 'Membership') { + $idName = 'membership_id'; + $componentTable = 'civicrm_membership'; + $paymentTable = 'civicrm_membership_payment'; + $source = ts('Online Contribution'); + } + + $pendingStatusId = array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name')); + + $query = " + SELECT component.id as {$idName}, + componentPayment.contribution_id as contribution_id, + contribution.source source, + contribution.contribution_status_id as contribution_status_id, + contribution.is_pay_later as is_pay_later + FROM $componentTable component +LEFT JOIN $paymentTable componentPayment ON ( componentPayment.{$idName} = component.id ) +LEFT JOIN civicrm_contribution contribution ON ( componentPayment.contribution_id = contribution.id ) + WHERE component.id = {$componentId}"; + + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + if ($dao->contribution_id && + $dao->is_pay_later && + $dao->contribution_status_id == $pendingStatusId && + strpos($dao->source, $source) !== FALSE + ) { + $contributionId = $dao->contribution_id; + $dao->free(); + } + } + + return $contributionId; + } + + /** + * This function update contribution as well as related objects. + */ + function transitionComponents($params, $processContributionObject = FALSE) { + // get minimum required values. + $contactId = CRM_Utils_Array::value('contact_id', $params); + $componentId = CRM_Utils_Array::value('component_id', $params); + $componentName = CRM_Utils_Array::value('componentName', $params); + $contributionId = CRM_Utils_Array::value('contribution_id', $params); + $contributionStatusId = CRM_Utils_Array::value('contribution_status_id', $params); + + // if we already processed contribution object pass previous status id. + $previousContriStatusId = CRM_Utils_Array::value('previous_contribution_status_id', $params); + + $updateResult = array(); + + $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + + // we process only ( Completed, Cancelled, or Failed ) contributions. + if (!$contributionId || + !in_array($contributionStatusId, array(array_search('Completed', $contributionStatuses), + array_search('Cancelled', $contributionStatuses), + array_search('Failed', $contributionStatuses), + )) + ) { + return $updateResult; + } + + if (!$componentName || !$componentId) { + // get the related component details. + $componentDetails = self::getComponentDetails($contributionId); + } + else { + $componentDetails['contact_id'] = $contactId; + $componentDetails['component'] = $componentName; + + if ($componentName == 'event') { + $componentDetails['participant'] = $componentId; + } + else { + $componentDetails['membership'] = $componentId; + } + } + + if (CRM_Utils_Array::value('contact_id', $componentDetails)) { + $componentDetails['contact_id'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', + $contributionId, + 'contact_id' + ); + } + + // do check for required ids. + if (!CRM_Utils_Array::value('membership', $componentDetails) && + !CRM_Utils_Array::value('participant', $componentDetails) && + !CRM_Utils_Array::value('pledge_payment', $componentDetails) || + !CRM_Utils_Array::value('contact_id', $componentDetails) + ) { + return $updateResult; + } + + //now we are ready w/ required ids, start processing. + + $baseIPN = new CRM_Core_Payment_BaseIPN(); + + $input = $ids = $objects = array(); + + $input['component'] = CRM_Utils_Array::value('component', $componentDetails); + $ids['contribution'] = $contributionId; + $ids['contact'] = CRM_Utils_Array::value('contact_id', $componentDetails); + $ids['membership'] = CRM_Utils_Array::value('membership', $componentDetails); + $ids['participant'] = CRM_Utils_Array::value('participant', $componentDetails); + $ids['event'] = CRM_Utils_Array::value('event', $componentDetails); + $ids['pledge_payment'] = CRM_Utils_Array::value('pledge_payment', $componentDetails); + $ids['contributionRecur'] = NULL; + $ids['contributionPage'] = NULL; + + if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) { + CRM_Core_Error::fatal(); + } + + $memberships = &$objects['membership']; + $participant = &$objects['participant']; + $pledgePayment = &$objects['pledge_payment']; + $contribution = &$objects['contribution']; + + if ($pledgePayment) { + $pledgePaymentIDs = array(); + foreach ($pledgePayment as $key => $object) { + $pledgePaymentIDs[] = $object->id; + } + $pledgeID = $pledgePayment[0]->pledge_id; + } + + + $membershipStatuses = CRM_Member_PseudoConstant::membershipStatus(); + + if ($participant) { + $participantStatuses = CRM_Event_PseudoConstant::participantStatus(); + $oldStatus = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', + $participant->id, + 'status_id' + ); + } + // we might want to process contribution object. + $processContribution = FALSE; + if ($contributionStatusId == array_search('Cancelled', $contributionStatuses)) { + if (is_array($memberships)) { + foreach ($memberships as $membership) { + if ($membership) { + $membership->status_id = array_search('Cancelled', $membershipStatuses); + $membership->save(); + + $updateResult['updatedComponents']['CiviMember'] = $membership->status_id; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + } + } + + if ($participant) { + $updatedStatusId = array_search('Cancelled', $participantStatuses); + CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE); + + $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + + if ($pledgePayment) { + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId); + + $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + } + elseif ($contributionStatusId == array_search('Failed', $contributionStatuses)) { + if (is_array($memberships)) { + foreach ($memberships as $membership) { + if ($membership) { + $membership->status_id = array_search('Expired', $membershipStatuses); + $membership->save(); + + $updateResult['updatedComponents']['CiviMember'] = $membership->status_id; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + } + } + if ($participant) { + $updatedStatusId = array_search('Cancelled', $participantStatuses); + CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE); + + $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + + if ($pledgePayment) { + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId); + + $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + } + elseif ($contributionStatusId == array_search('Completed', $contributionStatuses)) { + + // only pending contribution related object processed. + if ($previousContriStatusId && + ($previousContriStatusId != array_search('Pending', $contributionStatuses)) + ) { + // this is case when we already processed contribution object. + return $updateResult; + } + elseif (!$previousContriStatusId && + $contribution->contribution_status_id != array_search('Pending', $contributionStatuses) + ) { + // this is case when we are going to process contribution object later. + return $updateResult; + } + + if (is_array($memberships)) { + foreach ($memberships as $membership) { + if ($membership) { + $format = '%Y%m%d'; + + //CRM-4523 + $currentMembership = CRM_Member_BAO_Membership::getContactMembership($membership->contact_id, + $membership->membership_type_id, + $membership->is_test, $membership->id + ); + + // CRM-8141 update the membership type with the value recorded in log when membership created/renewed + // this picks up membership type changes during renewals + $sql = " + SELECT membership_type_id + FROM civicrm_membership_log + WHERE membership_id=$membership->id + ORDER BY id DESC + LIMIT 1;"; + $dao = new CRM_Core_DAO; + $dao->query($sql); + if ($dao->fetch()) { + if (!empty($dao->membership_type_id)) { + $membership->membership_type_id = $dao->membership_type_id; + $membership->save(); + } + } + // else fall back to using current membership type + $dao->free(); + + if ($currentMembership) { + CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, + $changeToday = NULL + ); + $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id, + $changeToday = NULL + ); + $dates['join_date'] = CRM_Utils_Date::customFormat($currentMembership['join_date'], $format); + } + else { + $dates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membership->membership_type_id); + } + + //get the status for membership. + $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'], + $dates['end_date'], + $dates['join_date'], + 'today', + TRUE + ); + + $formatedParams = array( + 'status_id' => CRM_Utils_Array::value('id', $calcStatus, + array_search('Current', $membershipStatuses) + ), + 'join_date' => CRM_Utils_Date::customFormat($dates['join_date'], $format), + 'start_date' => CRM_Utils_Date::customFormat($dates['start_date'], $format), + 'end_date' => CRM_Utils_Date::customFormat($dates['end_date'], $format), + ); + + CRM_Utils_Hook::pre('edit', 'Membership', $membership->id, $formatedParams); + + $membership->copyValues($formatedParams); + $membership->save(); + + //updating the membership log + $membershipLog = array(); + $membershipLog = $formatedParams; + $logStartDate = CRM_Utils_Date::customFormat($dates['log_start_date'], $format); + $logStartDate = ($logStartDate) ? CRM_Utils_Date::isoToMysql($logStartDate) : $formatedParams['start_date']; + + $membershipLog['start_date'] = $logStartDate; + $membershipLog['membership_id'] = $membership->id; + $membershipLog['modified_id'] = $membership->contact_id; + $membershipLog['modified_date'] = date('Ymd'); + $membershipLog['membership_type_id'] = $membership->membership_type_id; + + CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray); + + //update related Memberships. + CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $formatedParams); + + $updateResult['membership_end_date'] = CRM_Utils_Date::customFormat($dates['end_date'], + '%B %E%f, %Y' + ); + $updateResult['updatedComponents']['CiviMember'] = $membership->status_id; + if ($processContributionObject) { + $processContribution = TRUE; + } + + CRM_Utils_Hook::post('edit', 'Membership', $membership->id, $membership); + } + } + } + + if ($participant) { + $updatedStatusId = array_search('Registered', $participantStatuses); + CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE); + + $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + + if ($pledgePayment) { + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId); + + $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId; + if ($processContributionObject) { + $processContribution = TRUE; + } + } + } + + // process contribution object. + if ($processContribution) { + $contributionParams = array(); + $fields = array( + 'contact_id', 'total_amount', 'receive_date', 'is_test', 'campaign_id', + 'payment_instrument_id', 'trxn_id', 'invoice_id', 'financial_type_id', + 'contribution_status_id', 'non_deductible_amount', 'receipt_date', 'check_number', + ); + foreach ($fields as $field) { + if (!CRM_Utils_Array::value($field, $params)) { + continue; + } + $contributionParams[$field] = $params[$field]; + } + + $ids = array('contribution' => $contributionId); + $contribution = CRM_Contribute_BAO_Contribution::create($contributionParams, $ids); + } + + return $updateResult; + } + + /** + * This function returns all contribution related object ids. + */ + function getComponentDetails($contributionId) { + $componentDetails = $pledgePayment = array(); + if (!$contributionId) { + return $componentDetails; + } + + $query = " + SELECT c.id as contribution_id, + c.contact_id as contact_id, + mp.membership_id as membership_id, + m.membership_type_id as membership_type_id, + pp.participant_id as participant_id, + p.event_id as event_id, + pgp.id as pledge_payment_id + FROM civicrm_contribution c + LEFT JOIN civicrm_membership_payment mp ON mp.contribution_id = c.id + LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id + LEFT JOIN civicrm_participant p ON pp.participant_id = p.id + LEFT JOIN civicrm_membership m ON m.id = mp.membership_id + LEFT JOIN civicrm_pledge_payment pgp ON pgp.contribution_id = c.id + WHERE c.id = $contributionId"; + + $dao = CRM_Core_DAO::executeQuery($query); + $componentDetails = array(); + + while ($dao->fetch()) { + $componentDetails['component'] = $dao->participant_id ? 'event' : 'contribute'; + $componentDetails['contact_id'] = $dao->contact_id; + if ($dao->event_id) { + $componentDetails['event'] = $dao->event_id; + } + if ($dao->participant_id) { + $componentDetails['participant'] = $dao->participant_id; + } + if ($dao->membership_id) { + if (!isset($componentDetails['membership'])) { + $componentDetails['membership'] = $componentDetails['membership_type'] = array(); + } + $componentDetails['membership'][] = $dao->membership_id; + $componentDetails['membership_type'][] = $dao->membership_type_id; + } + if ($dao->pledge_payment_id) { + $pledgePayment[] = $dao->pledge_payment_id; + } + } + + if ($pledgePayment) { + $componentDetails['pledge_payment'] = $pledgePayment; + } + + return $componentDetails; + } + + static function contributionCount($contactId, $includeSoftCredit = TRUE, $includeHonoree = TRUE) { + if (!$contactId) { + return 0; + } + + $fromClause = "civicrm_contribution contribution"; + $whereConditions = array("contribution.contact_id = {$contactId}"); + if ($includeSoftCredit) { + $fromClause .= " LEFT JOIN civicrm_contribution_soft softContribution + ON ( contribution.id = softContribution.contribution_id )"; + $whereConditions[] = " softContribution.contact_id = {$contactId}"; + } + if ($includeHonoree) { + $whereConditions[] = " contribution.honor_contact_id = {$contactId}"; + } + $whereClause = " contribution.is_test = 0 AND ( " . implode(' OR ', $whereConditions) . " )"; + + $query = " + SELECT count( contribution.id ) count + FROM {$fromClause} + WHERE {$whereClause}"; + + return CRM_Core_DAO::singleValueQuery($query); + } + + /** + * Function to get individual id for onbehalf contribution + * + * @param int $contributionId contribution id + * @param int $contributorId contributer id + * + * @return array $ids containing organization id and individual id + * @access public + */ + function getOnbehalfIds($contributionId, $contributorId = NULL) { + + $ids = array(); + + if (!$contributionId) { + return $ids; + } + + // fetch contributor id if null + if (!$contributorId) { + $contributorId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', + $contributionId, 'contact_id' + ); + } + + $activityTypeIds = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name'); + $activityTypeId = array_search('Contribution', $activityTypeIds); + + if ($activityTypeId && $contributorId) { + $activityQuery = " +SELECT source_contact_id + FROM civicrm_activity + WHERE activity_type_id = %1 + AND source_record_id = %2"; + + $params = array(1 => array($activityTypeId, 'Integer'), + 2 => array($contributionId, 'Integer'), + ); + + $sourceContactId = CRM_Core_DAO::singleValueQuery($activityQuery, $params); + + // for on behalf contribution source is individual and contributor is organization + if ($sourceContactId && $sourceContactId != $contributorId) { + $relationshipTypeIds = CRM_Core_PseudoConstant::relationshipType('name'); + // get rel type id for employee of relation + foreach ($relationshipTypeIds as $id => $typeVals) { + if ($typeVals['name_a_b'] == 'Employee of') { + $relationshipTypeId = $id; + break; + } + } + + $rel = new CRM_Contact_DAO_Relationship(); + $rel->relationship_type_id = $relationshipTypeId; + $rel->contact_id_a = $sourceContactId; + $rel->contact_id_b = $contributorId; + if ($rel->find(TRUE)) { + $ids['individual_id'] = $rel->contact_id_a; + $ids['organization_id'] = $rel->contact_id_b; + } + } + } + + return $ids; + } + + /** + * @return array + * @static + */ + static function getContributionDates() { + $config = CRM_Core_Config::singleton(); + $currentMonth = date('m'); + $currentDay = date('d'); + if ((int ) $config->fiscalYearStart['M'] > $currentMonth || + ((int ) $config->fiscalYearStart['M'] == $currentMonth && + (int ) $config->fiscalYearStart['d'] > $currentDay + ) + ) { + $year = date('Y') - 1; + } + else { + $year = date('Y'); + } + $year = array('Y' => $year); + $yearDate = $config->fiscalYearStart; + $yearDate = array_merge($year, $yearDate); + $yearDate = CRM_Utils_Date::format($yearDate); + + $monthDate = date('Ym') . '01'; + + $now = date('Ymd'); + + return array( + 'now' => $now, + 'yearDate' => $yearDate, + 'monthDate' => $monthDate, + ); + } + + /* + * Load objects relations to contribution object + * Objects are stored in the $_relatedObjects property + * In the first instance we are just moving functionality from BASEIpn - + * see http://issues.civicrm.org/jira/browse/CRM-9996 + * + * @param array $input Input as delivered from Payment Processor + * @param array $ids Ids as Loaded by Payment Processor + * @param boolean $required Is Payment processor / contribution page required + * @param boolean $loadAll - load all related objects - even where id not passed in? (allows API to call this) + * Note that the unit test for the BaseIPN class tests this function + */ + function loadRelatedObjects(&$input, &$ids, $required = FALSE, $loadAll = false) { + if($loadAll){ + $ids = array_merge($this->getComponentDetails($this->id),$ids); + if(empty($ids['contact']) && isset($this->contact_id)){ + $ids['contact'] = $this->contact_id; + } + } + if (empty($this->_component)) { + if (! empty($ids['event'])) { + $this->_component = 'event'; + } + else { + $this->_component = strtolower(CRM_Utils_Array::value('component', $input, 'contribute')); + } + } + $paymentProcessorID = CRM_Utils_Array::value('paymentProcessor', $ids); + $contributionType = new CRM_Financial_BAO_FinancialType(); + $contributionType->id = $this->financial_type_id; + if (!$contributionType->find(TRUE)) { + throw new Exception("Could not find financial type record: " . $this->financial_type_id); + } + if (!empty($ids['contact'])) { + $this->_relatedObjects['contact'] = new CRM_Contact_BAO_Contact(); + $this->_relatedObjects['contact']->id = $ids['contact']; + $this->_relatedObjects['contact']->find(TRUE); + } + $this->_relatedObjects['contributionType'] = $contributionType; + + if ($this->_component == 'contribute') { + // retrieve the other optional objects first so + // stuff down the line can use this info and do things + // CRM-6056 + //in any case get the memberships associated with the contribution + //because we now support multiple memberships w/ price set + // see if there are any other memberships to be considered for same contribution. + $query = " + SELECT membership_id + FROM civicrm_membership_payment +WHERE contribution_id = %1 "; + $params = array(1 => array($this->id, 'Integer')); + + $dao = CRM_Core_DAO::executeQuery($query, $params ); + while ($dao->fetch()) { + if ($dao->membership_id) { + if (!is_array($ids['membership'])) { + $ids['membership'] = array(); + } + $ids['membership'][] = $dao->membership_id; + } + } + + if (array_key_exists('membership', $ids) && is_array($ids['membership'])) { + foreach ($ids['membership'] as $id) { + if (!empty($id)) { + $membership = new CRM_Member_BAO_Membership(); + $membership->id = $id; + if (!$membership->find(TRUE)) { + throw new Exception("Could not find membership record: $id"); + } + $membership->join_date = CRM_Utils_Date::isoToMysql($membership->join_date); + $membership->start_date = CRM_Utils_Date::isoToMysql($membership->start_date); + $membership->end_date = CRM_Utils_Date::isoToMysql($membership->end_date); + $this->_relatedObjects['membership'][$membership->membership_type_id] = $membership; + $membership->free(); + } + } + } + + if (!empty($ids['pledge_payment'])) { + + foreach ($ids['pledge_payment'] as $key => $paymentID) { + if (empty($paymentID)) { + continue; + } + $payment = new CRM_Pledge_BAO_PledgePayment(); + $payment->id = $paymentID; + if (!$payment->find(TRUE)) { + throw new Exception("Could not find pledge payment record: " . $paymentID); + } + $this->_relatedObjects['pledge_payment'][] = $payment; + } + } + + if (!empty($ids['contributionRecur'])) { + $recur = new CRM_Contribute_BAO_ContributionRecur(); + $recur->id = $ids['contributionRecur']; + if (!$recur->find(TRUE)) { + throw new Exception("Could not find recur record: " . $ids['contributionRecur']); + } + $this->_relatedObjects['contributionRecur'] = &$recur; + //get payment processor id from recur object. + $paymentProcessorID = $recur->payment_processor_id; + } + //for normal contribution get the payment processor id. + if (!$paymentProcessorID) { + if ($this->contribution_page_id) { + // get the payment processor id from contribution page + $paymentProcessorID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', + $this->contribution_page_id, + 'payment_processor' + ); + } + //fail to load payment processor id. + elseif (!CRM_Utils_Array::value('pledge_payment', $ids)) { + $loadObjectSuccess = TRUE; + if ($required) { + throw new Exception("Could not find contribution page for contribution record: " . $this->id); + } + return $loadObjectSuccess; + } + } + } + else { + // we are in event mode + // make sure event exists and is valid + $event = new CRM_Event_BAO_Event(); + $event->id = $ids['event']; + if ($ids['event'] && + !$event->find(TRUE) + ) { + throw new Exception("Could not find event: " . $ids['event']); + } + + $this->_relatedObjects['event'] = &$event; + + $participant = new CRM_Event_BAO_Participant(); + $participant->id = $ids['participant']; + if ($ids['participant'] && + !$participant->find(TRUE) + ) { + throw new Exception("Could not find participant: " . $ids['participant']); + } + $participant->register_date = CRM_Utils_Date::isoToMysql($participant->register_date); + + $this->_relatedObjects['participant'] = &$participant; + + if (!$paymentProcessorID) { + $paymentProcessorID = $this->_relatedObjects['event']->payment_processor; + } + } + + $loadObjectSuccess = TRUE; + if ($paymentProcessorID) { + $paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($paymentProcessorID, + $this->is_test ? 'test' : 'live' + ); + $ids['paymentProcessor'] = $paymentProcessorID; + $this->_relatedObjects['paymentProcessor'] = &$paymentProcessor; + } + elseif ($required) { + $loadObjectSuccess = FALSE; + throw new Exception("Could not find payment processor for contribution record: " . $this->id); + } + + return $loadObjectSuccess; + } + + /* + * Create array of message information - ie. return html version, txt version, to field + * + * @param array $input incoming information + * - is_recur - should this be treated as recurring (not sure why you wouldn't + * just check presence of recur object but maintaining legacy approach + * to be careful) + * @param array $ids IDs of related objects + * @param array $values any values that may have already been compiled by calling process + * This is augmented by values 'gathered' by gatherMessageValues + * @param bool $returnMessageText distinguishes between whether to send message or return + * message text. We are working towards this function ALWAYS returning message text & calling + * function doing emails / pdfs with it + * @return array $messageArray - messages + */ + function composeMessageArray(&$input, &$ids, &$values, $recur = FALSE, $returnMessageText = TRUE) { + if (empty($this->_relatedObjects)) { + $this->loadRelatedObjects($input, $ids); + } + if (empty($this->_component)) { + $this->_component = CRM_Utils_Array::value('component', $input); + } + + //not really sure what params might be passed in but lets merge em into values + $values = array_merge($this->_gatherMessageValues($input, $values, $ids), $values); + $template = CRM_Core_Smarty::singleton(); + $this->_assignMessageVariablesToTemplate($values, $input, $template, $recur, $returnMessageText); + //what does recur 'mean here - to do with payment processor return functionality but + // what is the importance + if ($recur && !empty($this->_relatedObjects['paymentProcessor'])) { + $paymentObject = &CRM_Core_Payment::singleton( + $this->is_test ? 'test' : 'live', + $this->_relatedObjects['paymentProcessor'] + ); + + $entityID = $entity = NULL; + if (isset($ids['contribution'])) { + $entity = 'contribution'; + $entityID = $ids['contribution']; + } + if (isset($ids['membership']) && $ids['membership']) { + $entity = 'membership'; + $entityID = $ids['membership']; + } + + $url = $paymentObject->subscriptionURL($entityID, $entity); + $template->assign('cancelSubscriptionUrl', $url); + + $url = $paymentObject->subscriptionURL($entityID, $entity, 'billing'); + $template->assign('updateSubscriptionBillingUrl', $url); + + $url = $paymentObject->subscriptionURL($entityID, $entity, 'update'); + $template->assign('updateSubscriptionUrl', $url); + + if ($this->_relatedObjects['paymentProcessor']['billing_mode'] & CRM_Core_Payment::BILLING_MODE_FORM) { + //direct mode showing billing block, so use directIPN for temporary + $template->assign('contributeMode', 'directIPN'); + } + } + // todo remove strtolower - check consistency + if (strtolower($this->_component) == 'event') { + return CRM_Event_BAO_Event::sendMail($ids['contact'], $values, + $this->_relatedObjects['participant']->id, $this->is_test, $returnMessageText + ); + } + else { + $values['contribution_id'] = $this->id; + if (CRM_Utils_Array::value('related_contact', $ids)) { + $values['related_contact'] = $ids['related_contact']; + if (isset($ids['onbehalf_dupe_alert'])) { + $values['onbehalf_dupe_alert'] = $ids['onbehalf_dupe_alert']; + } + $entityBlock = array( + 'contact_id' => $ids['contact'], + 'location_type_id' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_LocationType', + 'Home', 'id', 'name' + ), + ); + $address = CRM_Core_BAO_Address::getValues($entityBlock); + $template->assign('onBehalfAddress', $address[$entityBlock['location_type_id']]['display']); + } + $isTest = FALSE; + if ($this->is_test) { + $isTest = TRUE; + } + if (!empty($this->_relatedObjects['membership'])) { + foreach ($this->_relatedObjects['membership'] as $membership) { + if ($membership->id) { + $values['membership_id'] = $membership->id; + + // need to set the membership values here + $template->assign('membership_assign', 1); + $template->assign('membership_name', + CRM_Member_PseudoConstant::membershipType($membership->membership_type_id) + ); + $template->assign('mem_start_date', $membership->start_date); + $template->assign('mem_join_date', $membership->join_date); + $template->assign('mem_end_date', $membership->end_date); + $membership_status = CRM_Member_PseudoConstant::membershipStatus($membership->status_id, NULL, 'label'); + $template->assign('mem_status', $membership_status); + if ($membership_status == 'Pending' && $membership->is_pay_later == 1) { + $template->assign('is_pay_later', 1); + } + + // if separate payment there are two contributions recorded and the + // admin will need to send a receipt for each of them separately. + // we dont link the two in the db (but can potentially infer it if needed) + $template->assign('is_separate_payment', 0); + + if ($recur && $paymentObject) { + $url = $paymentObject->subscriptionURL($membership->id, 'membership'); + $template->assign('cancelSubscriptionUrl', $url); + $url = $paymentObject->subscriptionURL($membership->id, 'membership', 'billing'); + $template->assign('updateSubscriptionBillingUrl', $url); + $url = $paymentObject->subscriptionURL($entityID, $entity, 'update'); + $template->assign('updateSubscriptionUrl', $url); + } + + $result = CRM_Contribute_BAO_ContributionPage::sendMail($ids['contact'], $values, $isTest, $returnMessageText); + + return $result; + // otherwise if its about sending emails, continue sending without return, as we + // don't want to exit the loop. + } + } + } + else { + return CRM_Contribute_BAO_ContributionPage::sendMail($ids['contact'], $values, $isTest, $returnMessageText); + } + } + } + + /* + * Gather values for contribution mail - this function has been created + * as part of CRM-9996 refactoring as a step towards simplifying the composeMessage function + * Values related to the contribution in question are gathered + * + * @param array $input input into function (probably from payment processor) + * @param array $ids the set of ids related to the inpurt + * + * @return array $values + * + * NB don't add direct calls to the function as we intend to change the signature + */ + function _gatherMessageValues($input, &$values, $ids = array()) { + // set display address of contributor + if ($this->address_id) { + $addressParams = array('id' => $this->address_id); + $addressDetails = CRM_Core_BAO_Address::getValues($addressParams, FALSE, 'id'); + $addressDetails = array_values($addressDetails); + $values['address'] = $addressDetails[0]['display']; + } + if ($this->_component == 'contribute') { + if (isset($this->contribution_page_id)) { + CRM_Contribute_BAO_ContributionPage::setValues( + $this->contribution_page_id, + $values + ); + if ($this->contribution_page_id) { + // CRM-8254 - override default currency if applicable + $config = CRM_Core_Config::singleton(); + $config->defaultCurrency = CRM_Utils_Array::value( + 'currency', + $values, + $config->defaultCurrency + ); + } + } + // no contribution page -probably back office + else { + // Handle re-print receipt for offline contributions (call from PDF.php - no contribution_page_id) + $values['is_email_receipt'] = 1; + $values['title'] = 'Contribution'; + } + // set lineItem for contribution + if ($this->id) { + $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->id, 'contribution', 1); + if (!empty($lineItem)) { + $itemId = key($lineItem); + foreach ($lineItem as &$eachItem) { + if (array_key_exists($eachItem['membership_type_id'], $this->_relatedObjects['membership']) ) { + $eachItem['join_date'] = CRM_Utils_Date::customFormat($this->_relatedObjects['membership'][$eachItem['membership_type_id']]->join_date); + $eachItem['start_date'] = CRM_Utils_Date::customFormat($this->_relatedObjects['membership'][$eachItem['membership_type_id']]->start_date); + $eachItem['end_date'] = CRM_Utils_Date::customFormat($this->_relatedObjects['membership'][$eachItem['membership_type_id']]->end_date); + } + } + $values['lineItem'][0] = $lineItem; + $values['priceSetID'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Field', $lineItem[$itemId]['price_field_id'], 'price_set_id'); + } + } + + $relatedContact = CRM_Contribute_BAO_Contribution::getOnbehalfIds( + $this->id, + $this->contact_id + ); + // if this is onbehalf of contribution then set related contact + if (CRM_Utils_Array::value('individual_id', $relatedContact)) { + $values['related_contact'] = $ids['related_contact'] = $relatedContact['individual_id']; + } + } + else { + // event + $eventParams = array( + 'id' => $this->_relatedObjects['event']->id, + ); + $values['event'] = array(); + + CRM_Event_BAO_Event::retrieve($eventParams, $values['event']); + + //get location details + $locationParams = array( + 'entity_id' => $this->_relatedObjects['event']->id, + 'entity_table' => 'civicrm_event', + ); + $values['location'] = CRM_Core_BAO_Location::getValues($locationParams); + + $ufJoinParams = array( + 'entity_table' => 'civicrm_event', + 'entity_id' => $ids['event'], + 'module' => 'CiviEvent', + ); + + list($custom_pre_id, + $custom_post_ids + ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + + $values['custom_pre_id'] = $custom_pre_id; + $values['custom_post_id'] = $custom_post_ids; + + // set lineItem for event contribution + if ($this->id) { + $participantIds = CRM_Event_BAO_Participant::getParticipantIds($this->id); + if (!empty($participantIds)) { + foreach ($participantIds as $pIDs) { + $lineItem = CRM_Price_BAO_LineItem::getLineItems($pIDs); + if (!CRM_Utils_System::isNull($lineItem)) { + $values['lineItem'][] = $lineItem; + } + } + } + } + } + + return $values; + } + + /** + * Apply variables for message to smarty template - this function is part of analysing what is in the huge + * function & breaking it down into manageable chunks. Eventually it will be refactored into something else + * Note we send directly from this function in some cases because it is only partly refactored + * Don't call this function directly as the signature will change + */ + function _assignMessageVariablesToTemplate(&$values, $input, &$template, $recur = FALSE, $returnMessageText = True) { + $template->assign('first_name', $this->_relatedObjects['contact']->first_name); + $template->assign('last_name', $this->_relatedObjects['contact']->last_name); + $template->assign('displayName', $this->_relatedObjects['contact']->display_name); + if (!empty($values['lineItem']) && !empty($this->_relatedObjects['membership'])) { + $template->assign('useForMember', true); + } + //assign honor infomation to receiptmessage + $honorID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', + $this->id, + 'honor_contact_id' + ); + if (!empty($honorID)) { + + $honorDefault = $honorIds = array(); + $honorIds['contribution'] = $this->id; + $idParams = array('id' => $honorID, 'contact_id' => $honorID); + CRM_Contact_BAO_Contact::retrieve($idParams, $honorDefault, $honorIds); + $honorType = CRM_Core_PseudoConstant::honor(); + + $template->assign('honor_block_is_active', 1); + if (CRM_Utils_Array::value('prefix_id', $honorDefault)) { + $prefix = CRM_Core_PseudoConstant::individualPrefix(); + $template->assign('honor_prefix', $prefix[$honorDefault['prefix_id']]); + } + $template->assign('honor_first_name', CRM_Utils_Array::value('first_name', $honorDefault)); + $template->assign('honor_last_name', CRM_Utils_Array::value('last_name', $honorDefault)); + $template->assign('honor_email', CRM_Utils_Array::value('email', $honorDefault['email'][1])); + $template->assign('honor_type', $honorType[$this->honor_type_id]); + } + + $dao = new CRM_Contribute_DAO_ContributionProduct(); + $dao->contribution_id = $this->id; + if ($dao->find(TRUE)) { + $premiumId = $dao->product_id; + $template->assign('option', $dao->product_option); + + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $premiumId; + $productDAO->find(TRUE); + $template->assign('selectPremium', TRUE); + $template->assign('product_name', $productDAO->name); + $template->assign('price', $productDAO->price); + $template->assign('sku', $productDAO->sku); + } + $template->assign('title', CRM_Utils_Array::value('title',$values)); + $amount = CRM_Utils_Array::value('total_amount', $input,(CRM_Utils_Array::value('amount', $input)),null); + if(empty($amount) && isset($this->total_amount)){ + $amount = $this->total_amount; + } + $template->assign('amount', $amount); + // add the new contribution values + if (strtolower($this->_component) == 'contribute') { + //PCP Info + $softDAO = new CRM_Contribute_DAO_ContributionSoft(); + $softDAO->contribution_id = $this->id; + if ($softDAO->find(TRUE)) { + $template->assign('pcpBlock', TRUE); + $template->assign('pcp_display_in_roll', $softDAO->pcp_display_in_roll); + $template->assign('pcp_roll_nickname', $softDAO->pcp_roll_nickname); + $template->assign('pcp_personal_note', $softDAO->pcp_personal_note); + + //assign the pcp page title for email subject + $pcpDAO = new CRM_PCP_DAO_PCP(); + $pcpDAO->id = $softDAO->pcp_id; + if ($pcpDAO->find(TRUE)) { + $template->assign('title', $pcpDAO->title); + } + } + } + + if ($this->financial_type_id) { + $values['financial_type_id'] = $this->financial_type_id; + } + + + $template->assign('trxn_id', $this->trxn_id); + $template->assign('receive_date', + CRM_Utils_Date::mysqlToIso($this->receive_date) + ); + $template->assign('contributeMode', 'notify'); + $template->assign('action', $this->is_test ? 1024 : 1); + $template->assign('receipt_text', + CRM_Utils_Array::value('receipt_text', + $values + ) + ); + $template->assign('is_monetary', 1); + $template->assign('is_recur', (bool) $recur); + $template->assign('currency', $this->currency); + $template->assign('address', CRM_Utils_Address::format($input)); + if ($this->_component == 'event') { + $template->assign('title', $values['event']['title']); + $participantRoles = CRM_Event_PseudoConstant::participantRole(); + $viewRoles = array(); + foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, $this->_relatedObjects['participant']->role_id) as $k => $v) { + $viewRoles[] = $participantRoles[$v]; + } + $values['event']['participant_role'] = implode(', ', $viewRoles); + $template->assign('event', $values['event']); + $template->assign('location', $values['location']); + $template->assign('customPre', $values['custom_pre_id']); + $template->assign('customPost', $values['custom_post_id']); + + $isTest = FALSE; + if ($this->_relatedObjects['participant']->is_test) { + $isTest = TRUE; + } + + $values['params'] = array(); + //to get email of primary participant. + $primaryEmail = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Email', $this->_relatedObjects['participant']->contact_id, 'email', 'contact_id'); + $primaryAmount[] = array('label' => $this->_relatedObjects['participant']->fee_level . ' - ' . $primaryEmail, 'amount' => $this->_relatedObjects['participant']->fee_amount); + //build an array of cId/pId of participants + $additionalIDs = CRM_Event_BAO_Event::buildCustomProfile($this->_relatedObjects['participant']->id, NULL, $this->_relatedObjects['contact']->id, $isTest, TRUE); + unset($additionalIDs[$this->_relatedObjects['participant']->id]); + //send receipt to additional participant if exists + if (count($additionalIDs)) { + $template->assign('isPrimary', 0); + $template->assign('customProfile', NULL); + //set additionalParticipant true + $values['params']['additionalParticipant'] = TRUE; + foreach ($additionalIDs as $pId => $cId) { + $amount = array(); + //to change the status pending to completed + $additional = new CRM_Event_DAO_Participant(); + $additional->id = $pId; + $additional->contact_id = $cId; + $additional->find(TRUE); + $additional->register_date = $this->_relatedObjects['participant']->register_date; + $additional->status_id = 1; + $additionalParticipantInfo = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Email', $additional->contact_id, 'email', 'contact_id'); + //if additional participant dont have email + //use display name. + if (!$additionalParticipantInfo) { + $additionalParticipantInfo = CRM_Contact_BAO_Contact::displayName($additional->contact_id); + } + $amount[0] = array('label' => $additional->fee_level, 'amount' => $additional->fee_amount); + $primaryAmount[] = array('label' => $additional->fee_level . ' - ' . $additionalParticipantInfo, 'amount' => $additional->fee_amount); + $additional->save(); + $additional->free(); + $template->assign('amount', $amount); + CRM_Event_BAO_Event::sendMail($cId, $values, $pId, $isTest, $returnMessageText); + } + } + + //build an array of custom profile and assigning it to template + $customProfile = CRM_Event_BAO_Event::buildCustomProfile($this->_relatedObjects['participant']->id, $values, NULL, $isTest); + + if (count($customProfile)) { + $template->assign('customProfile', $customProfile); + } + + // for primary contact + $values['params']['additionalParticipant'] = FALSE; + $template->assign('isPrimary', 1); + $template->assign('amount', $primaryAmount); + $template->assign('register_date', CRM_Utils_Date::isoToMysql($this->_relatedObjects['participant']->register_date)); + if ($this->payment_instrument_id) { + $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument(); + $template->assign('paidBy', $paymentInstrument[$this->payment_instrument_id]); + } + // carry paylater, since we did not created billing, + // so need to pull email from primary location, CRM-4395 + $values['params']['is_pay_later'] = $this->_relatedObjects['participant']->is_pay_later; + } + return $template; + } + + /** + * Function to check whether payment processor supports + * cancellation of contribution subscription + * + * @param int $contributionId contribution id + * + * @return boolean + * @access public + * @static + */ + static function isCancelSubscriptionSupported($contributionId, $isNotCancelled = TRUE) { + $cacheKeyString = "$contributionId"; + $cacheKeyString .= $isNotCancelled ? '_1' : '_0'; + + static $supportsCancel = array(); + + if (!array_key_exists($cacheKeyString, $supportsCancel)) { + $supportsCancel[$cacheKeyString] = FALSE; + $isCancelled = FALSE; + + if ($isNotCancelled) { + $isCancelled = self::isSubscriptionCancelled($contributionId); + } + + $paymentObject = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($contributionId, 'contribute', 'obj'); + if (!empty($paymentObject)) { + $supportsCancel[$cacheKeyString] = $paymentObject->isSupported('cancelSubscription') && !$isCancelled; + } + } + return $supportsCancel[$cacheKeyString]; + } + + /** + * Function to check whether subscription is already cancelled + * + * @param int $contributionId contribution id + * + * @return string $status contribution status + * @access public + * @static + */ + static function isSubscriptionCancelled($contributionId) { + $sql = " + SELECT cr.contribution_status_id + FROM civicrm_contribution_recur cr + LEFT JOIN civicrm_contribution con ON ( cr.id = con.contribution_recur_id ) + WHERE con.id = %1 LIMIT 1"; + $params = array(1 => array($contributionId, 'Integer')); + $statusId = CRM_Core_DAO::singleValueQuery($sql, $params); + $status = CRM_Contribute_PseudoConstant::contributionStatus($statusId); + if ($status == 'Cancelled') { + return TRUE; + } + return FALSE; + } + + /** + * Function to create all financial accounts entry + * + * @param array $params contribution object, line item array and params for trxn + * + * @param array $ids of contribution id + * + * @access public + * @static + */ + static function recordFinancialAccounts(&$params, $ids) { + $skipRecords = $update = FALSE; + $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + + if (CRM_Utils_Array::value('contribution_mode', $params) == 'participant') { + $entityId = $params['participant_id']; + $entityTable = 'civicrm_participant'; + } + else { + $entityId = $params['contribution']->id; + $entityTable = 'civicrm_contribution'; + } + $entityID = $entityId; + if (!CRM_Utils_Array::value('prevContribution', $params)) { + $entityID = NULL; + } + // build line item array if its not set in $params + if (!CRM_Utils_Array::value('line_item', $params)) { + CRM_Price_BAO_LineItem::getLineItemArray($params, $entityID, str_replace('civicrm_', '', $entityTable)); + } + + if (CRM_Utils_Array::value('contribution_status_id', $params) != array_search('Failed', $contributionStatuses) && + !(CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', $contributionStatuses) && !$params['contribution']->is_pay_later)) { + $skipRecords = TRUE; + if (CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', $contributionStatuses)) { + $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); + $params['to_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $relationTypeId); + } + elseif (CRM_Utils_Array::value('payment_processor', $params)) { + $params['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($params['payment_processor'], 'civicrm_payment_processor', 'financial_account_id'); + } + elseif (CRM_Utils_Array::value('payment_instrument_id', $params)) { + $params['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($params['payment_instrument_id']); + } + else { + $params['to_financial_account_id'] = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1"); + } + + $totalAmount = CRM_Utils_Array::value('total_amount', $params); + if (!isset($totalAmount) && CRM_Utils_Array::value('prevContribution', $params)) { + $totalAmount = $params['total_amount'] = $params['prevContribution']->total_amount; + } + //build financial transaction params + $trxnParams = array( + 'contribution_id' => $params['contribution']->id, + 'to_financial_account_id' => $params['to_financial_account_id'], + 'trxn_date' => date('YmdHis'), + 'total_amount' => $totalAmount, + 'fee_amount' => CRM_Utils_Array::value('fee_amount', $params), + 'net_amount' => CRM_Utils_Array::value('net_amount', $params), + 'currency' => $params['contribution']->currency, + 'trxn_id' => $params['contribution']->trxn_id, + 'status_id' => $params['contribution']->contribution_status_id, + 'payment_instrument_id' => CRM_Utils_Array::value('payment_instrument_id', $params), + 'check_number' => CRM_Utils_Array::value('check_number', $params), + ); + + if (CRM_Utils_Array::value('payment_processor', $params)) { + $trxnParams['payment_processor_id'] = $params['payment_processor']; + } + $params['trxnParams'] = $trxnParams; + + if (CRM_Utils_Array::value('prevContribution', $params)) { + + //if Change contribution amount + if (array_key_exists('total_amount', $params) && isset($params['total_amount']) && + $params['total_amount'] != $params['prevContribution']->total_amount) { + //Update Financial Records + self::updateFinancialAccounts($params, 'changedAmount'); + } + + //Update contribution status + if (CRM_Utils_Array::value('contribution_status_id', $params) && + $params['prevContribution']->contribution_status_id != $params['contribution']->contribution_status_id) { + //Update Financial Records + self::updateFinancialAccounts($params, 'changedStatus'); + } + + // change Payment Instrument for a Completed contribution + // first handle special case when contribution is changed from Pending to Completed status when initial payment + // instrument is null and now new payment instrument is added along with the payment + if (array_key_exists('payment_instrument_id', $params)) { + if (CRM_Utils_System::isNull($params['prevContribution']->payment_instrument_id) && + !CRM_Utils_System::isNull($params['contribution']->payment_instrument_id)) { + //check if status is changed from Pending to Completed + // do not update payment instrument changes for Pending to Completed + if (!($params['contribution']->contribution_status_id == array_search('Completed', $contributionStatuses) && + $params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatuses))) { + // for all other statuses create new financial records + self::updateFinancialAccounts($params, 'changePaymentInstrument'); + } + } + else if ((!CRM_Utils_System::isNull($params['contribution']->payment_instrument_id) || + !CRM_Utils_System::isNull($params['prevContribution']->payment_instrument_id)) && + $params['contribution']->payment_instrument_id != $params['prevContribution']->payment_instrument_id) { + // for any other payment instrument changes create new financial records + self::updateFinancialAccounts($params, 'changePaymentInstrument'); + } + else if (!CRM_Utils_System::isNull($params['contribution']->check_number) && + $params['contribution']->check_number != $params['prevContribution']->check_number) { + // another special case when check number is changed, create new financial records + // create financial trxn with negative amount + $params['trxnParams']['total_amount'] = - $trxnParams['total_amount']; + $params['trxnParams']['check_number'] = $params['prevContribution']->check_number; + self::updateFinancialAccounts($params, 'changePaymentInstrument'); + // create financial trxn with positive amount + $params['trxnParams']['check_number'] = $params['contribution']->check_number; + $params['total_amount'] = $params['trxnParams']['total_amount'] = $trxnParams['total_amount']; + self::updateFinancialAccounts($params, 'changePaymentInstrument'); + } + } + + //if financial type is changed + if (CRM_Utils_Array::value('financial_type_id', $params) && + $params['contribution']->financial_type_id != $params['prevContribution']->financial_type_id) { + $incomeTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Income Account is' ")); + $oldFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($params['prevContribution']->financial_type_id, $incomeTypeId); + $newFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $incomeTypeId); + if ($oldFinancialAccount != $newFinancialAccount) { + $params['total_amount'] = 0; + if ($params['contribution']->contribution_status_id == array_search('Pending', $contributionStatuses)) { + $params['trxnParams']['to_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType( + $params['prevContribution']->financial_type_id, $relationTypeId); + } + self::updateFinancialAccounts($params, 'changeFinancialType'); + $params['trxnParams']['to_financial_account_id'] = $trxnParams['to_financial_account_id']; + $params['financial_account_id'] = $newFinancialAccount; + $params['total_amount'] = $params['trxnParams']['total_amount'] = $trxnParams['total_amount']; + self::updateFinancialAccounts($params); + } + } + $update = TRUE; + } + + if (!$update) { + //records finanical trxn and entity financial trxn + $financialTxn = CRM_Core_BAO_FinancialTrxn::create($trxnParams); + $params['entity_id'] = $financialTxn->id; + } + } + // record line items and finacial items + + if (!CRM_Utils_Array::value('skipLineItem', $params)) { + CRM_Price_BAO_LineItem::processPriceSet($entityId, CRM_Utils_Array::value('line_item', $params), $params['contribution'], $entityTable, $update); + } + + // create batch entry if batch_id is passed + if (CRM_Utils_Array::value('batch_id', $params)) { + $entityParams = array( + 'batch_id' => $params['batch_id'], + 'entity_table' => 'civicrm_financial_trxn', + 'entity_id' => $financialTxn->id, + ); + CRM_Batch_BAO_Batch::addBatchEntity($entityParams); + } + + // when a fee is charged + if (CRM_Utils_Array::value('fee_amount', $params) && (!CRM_Utils_Array::value('prevContribution', $params) + || $params['contribution']->fee_amount != $params['prevContribution']->fee_amount) && $skipRecords) { + CRM_Core_BAO_FinancialTrxn::recordFees($params); + } + + if (CRM_Utils_Array::value('prevContribution', $params) && $entityTable == 'civicrm_participant' + && $params['prevContribution']->contribution_status_id != $params['contribution']->contribution_status_id) { + $eventID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $entityId, 'event_id'); + $feeLevel[] = str_replace('', '', $params['prevContribution']->amount_level); + CRM_Event_BAO_Participant::createDiscountTrxn($eventID, $params, $feeLevel); + } + unset($params['line_item']); + } + + /** + * Function to update all financial accounts entry + * + * @param array $params contribution object, line item array and params for trxn + * + * @param string $context update scenarios + * + * @access public + * @static + */ + static function updateFinancialAccounts(&$params, $context = NULL, $skipTrxn = NULL) { + $itemAmount = $trxnID = NULL; + //get all the statuses + $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + if ($params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatus) && + $params['contribution']->contribution_status_id == array_search('Completed', $contributionStatus) + && $context == 'changePaymentInstrument') { + return; + } + if ($context == 'changedAmount' || $context == 'changeFinancialType') { + $itemAmount = $params['trxnParams']['total_amount'] = $params['total_amount'] - $params['prevContribution']->total_amount; + } + if ($context == 'changedStatus') { + //get all the statuses + $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + + if ($params['prevContribution']->contribution_status_id == array_search('Completed', $contributionStatus) + && ($params['contribution']->contribution_status_id == array_search('Refunded', $contributionStatus) + || $params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus))) { + + $params['trxnParams']['total_amount'] = - $params['total_amount']; + } + elseif ($params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatus)) { + $financialTypeID = CRM_Utils_Array::value('financial_type_id', $params) ? $params['financial_type_id'] : $params['prevContribution']->financial_type_id; + if ($params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus)) { + $params['trxnParams']['to_financial_account_id'] = NULL; + $params['trxnParams']['total_amount'] = - $params['total_amount']; + } + $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, + " AND v.name LIKE 'Accounts Receivable Account is' ")); + $params['trxnParams']['from_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType( + $financialTypeID, $relationTypeId); + } + $itemAmount = $params['trxnParams']['total_amount']; + } + elseif ($context == 'changePaymentInstrument') { + if ($params['prevContribution']->payment_instrument_id != null + && $params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatus) + && $params['contribution']->contribution_status_id == array_search('Pending', $contributionStatus)) { + $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' ")); + $params['trxnParams']['from_financial_account_id'] = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $relationTypeId); + } + elseif ($params['prevContribution']->payment_instrument_id != null) { + $params['trxnParams']['from_financial_account_id'] = + CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount( + $params['prevContribution']->payment_instrument_id); + } + else { + $params['trxnParams']['from_financial_account_id'] = CRM_Core_DAO::singleValueQuery( + "SELECT id FROM civicrm_financial_account WHERE is_default = 1"); + } + } + + $trxn = CRM_Core_BAO_FinancialTrxn::create($params['trxnParams']); + $params['entity_id'] = $trxn->id; + + if ($context == 'changedStatus') { + if (($params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatus)) && + ($params['contribution']->contribution_status_id == array_search('Completed', $contributionStatus))) { + $query = "UPDATE civicrm_financial_item SET status_id = %1 WHERE entity_id = %2"; + foreach ($params['line_item'] as $fieldId => $fields) { + foreach ($fields as $fieldValueId => $fieldValues) { + $fparams = array( + 1 => array(CRM_Core_OptionGroup::getValue('financial_item_status', 'Paid', 'name'), 'Integer'), + 2 => array($fieldValues['id'], 'Integer'), + ); + $entityParams = array( + 'entity_table' => 'civicrm_financial_item', + 'financial_trxn_id' => $trxn->id, + ); + CRM_Core_DAO::executeQuery($query, $fparams); + // FIXME:need to change + $entityParams['amount'] = $fieldValues['line_total']; + $entityParams['entity_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialItem', $fieldValues['id'], 'id', 'entity_id'); + CRM_Financial_BAO_FinancialItem::createEntityTrxn($entityParams); + } + } + return; + } + } + if ($context != 'changePaymentInstrument') { + $itemParams['entity_table'] = 'civicrm_line_item'; + $trxnIds['id'] = $params['entity_id']; + foreach ($params['line_item'] as $fieldId => $fields) { + foreach ($fields as $fieldValueId => $fieldValues) { + $prevParams['entity_id'] = $fieldValues['id']; + $prevfinancialItem = CRM_Financial_BAO_FinancialItem::retrieve($prevParams, CRM_Core_DAO::$_nullArray); + + $receiveDate = CRM_Utils_Date::isoToMysql($params['prevContribution']->receive_date); + if ($params['contribution']->receive_date) { + $receiveDate = CRM_Utils_Date::isoToMysql($params['contribution']->receive_date); + } + + $financialAccount = $prevfinancialItem->financial_account_id; + if (CRM_Utils_Array::value('financial_account_id', $params)) { + $financialAccount = $params['financial_account_id']; + } + + $currency = $params['prevContribution']->currency; + if ($params['contribution']->currency) { + $currency = $params['contribution']->currency; + } + if (CRM_Utils_Array::value('is_quick_config', $params)) { + $amount = $itemAmount; + if (!$amount) { + $amount = $params['total_amount']; + } + } + else { + $diff = 1; + if ($context == 'changeFinancialType' || $params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus)) { + $diff = -1; + } + $amount = $diff * $fieldValues['line_total']; + } + + $itemParams = array( + 'transaction_date' => $receiveDate, + 'contact_id' => $params['prevContribution']->contact_id, + 'currency' => $currency, + 'amount' => $amount, + 'description' => $prevfinancialItem->description, + 'status_id' => $prevfinancialItem->status_id, + 'financial_account_id' => $financialAccount, + 'entity_table' => 'civicrm_line_item', + 'entity_id' => $fieldValues['id'] + ); + CRM_Financial_BAO_FinancialItem::create($itemParams, NULL, $trxnIds); + } + } + } + } + + /** + * Function to check status validation on update of a contribution + * + * @param array $values previous form values before submit + * + * @param array $fields the input form values + * + * @param array $errors list of errors + * + * @access public + * @static + */ + static function checkStatusValidation($values, &$fields, &$errors) { + $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + $checkStatus = array( + 'Cancelled' => array('Completed', 'Refunded'), + 'Completed' => array('Cancelled', 'Refunded'), + 'Pending' => array('Cancelled', 'Completed', 'Failed'), + 'Refunded' => array('Cancelled', 'Completed') + ); + + if (!in_array($contributionStatuses[$fields['contribution_status_id']], $checkStatus[$contributionStatuses[$values['contribution_status_id']]])) { + $errors['contribution_status_id'] = ts("Cannot change contribution status from %1 to %2.", array(1 => $contributionStatuses[$values['contribution_status_id']], 2 => $contributionStatuses[$fields['contribution_status_id']])); + } + } +} diff --git a/CRM/Contribute/BAO/Contribution/Utils.php b/CRM/Contribute/BAO/Contribution/Utils.php new file mode 100644 index 0000000000..fedd339a41 --- /dev/null +++ b/CRM/Contribute/BAO/Contribution/Utils.php @@ -0,0 +1,805 @@ +_bltID, $form->_params, $paymentParams, TRUE); + + $contributionType = new CRM_Financial_DAO_FinancialType(); + if (isset($paymentParams['financial_type'])) { + $contributionType->id = $paymentParams['financial_type']; + } + elseif (CRM_Utils_Array::value('pledge_id', $form->_values)) { + $contributionType->id = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_Pledge', + $form->_values['pledge_id'], + 'financial_type_id' + ); + } + else { + $contributionType->id = $contributionTypeId; + } + if (!$contributionType->find(TRUE)) { + CRM_Core_Error::fatal('Could not find a system table'); + } + + // add some financial type details to the params list + // if folks need to use it + $paymentParams['contributionType_name'] = $form->_params['contributionType_name'] = $contributionType->name; + //CRM-11456 + $paymentParams['contributionType_accounting_code'] = $form->_params['contributionType_accounting_code'] = CRM_Financial_BAO_FinancialAccount::getAccountingCode($contributionType->id); + $paymentParams['contributionPageID'] = $form->_params['contributionPageID'] = $form->_values['id']; + + + $payment = NULL; + $paymentObjError = ts('The system did not record payment details for this payment and so could not process the transaction. Please report this error to the site administrator.'); + if ($form->_values['is_monetary'] && $form->_amount > 0.0 && is_array($form->_paymentProcessor)) { + $payment = CRM_Core_Payment::singleton($form->_mode, $form->_paymentProcessor, $form); + } + + //fix for CRM-2062 + $now = date('YmdHis'); + + $result = NULL; + if ($form->_contributeMode == 'notify' || + $form->_params['is_pay_later'] + ) { + // this is not going to come back, i.e. we fill in the other details + // when we get a callback from the payment processor + // also add the contact ID and contribution ID to the params list + $paymentParams['contactID'] = $form->_params['contactID'] = $contactID; + $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution( + $form, + $paymentParams, + NULL, + $contactID, + $contributionType, + TRUE, TRUE, TRUE + ); + + if ($contribution) { + $form->_params['contributionID'] = $contribution->id; + } + + $form->_params['contributionTypeID'] = $contributionType->id; + $form->_params['item_name'] = $form->_params['description']; + $form->_params['receive_date'] = $now; + + if ($contribution && $form->_values['is_recur'] && + $contribution->contribution_recur_id + ) { + $form->_params['contributionRecurID'] = $contribution->contribution_recur_id; + } + + $form->set('params', $form->_params); + $form->postProcessPremium($premiumParams, $contribution); + + if ($form->_values['is_monetary'] && $form->_amount > 0.0) { + // add qfKey so we can send to paypal + $form->_params['qfKey'] = $form->controller->_key; + if ($component == 'membership') { + $membershipResult = array(1 => $contribution); + return $membershipResult; + } + else { + if (!$form->_params['is_pay_later']) { + if (is_object($payment)) { + // call postprocess hook before leaving + $form->postProcessHook(); + // this does not return + $result = &$payment->doTransferCheckout($form->_params, 'contribute'); + } + else{ + CRM_Core_Error::fatal($paymentObjError); + } + } + else { + // follow similar flow as IPN + // send the receipt mail + $form->set('params', $form->_params); + if ($contributionType->is_deductible) { + $form->assign('is_deductible', TRUE); + $form->set('is_deductible', TRUE); + } + if (isset($paymentParams['contribution_source'])) { + $form->_params['source'] = $paymentParams['contribution_source']; + } + + // get the price set values for receipt. + if ($form->_priceSetId && $form->_lineItem) { + $form->_values['lineItem'] = $form->_lineItem; + $form->_values['priceSetID'] = $form->_priceSetId; + } + + $form->_values['contribution_id'] = $contribution->id; + $form->_values['contribution_page_id'] = $contribution->contribution_page_id; + + CRM_Contribute_BAO_ContributionPage::sendMail($contactID, + $form->_values, + $contribution->is_test + ); + return; + } + } + } + } + elseif ($form->_contributeMode == 'express') { + if ($form->_values['is_monetary'] && $form->_amount > 0.0) { + // determine if express + recurring and direct accordingly + if ($paymentParams['is_recur'] == 1) { + if (is_object($payment)) { + $result = &$payment->createRecurringPayments($paymentParams); + } + else { + CRM_Core_Error::fatal($paymentObjError); + } + } + else { + if (is_object($payment)) { + $result = &$payment->doExpressCheckout($paymentParams); + } + else { + CRM_Core_Error::fatal($paymentObjError); + } + } + } + } + elseif ($form->_values['is_monetary'] && $form->_amount > 0.0) { + if (CRM_Utils_Array::value('is_recur', $paymentParams) && + $form->_contributeMode == 'direct' + ) { + + // For recurring contribution, create Contribution Record first. + // Contribution ID, Recurring ID and Contact ID needed + // When we get a callback from the payment processor + + $paymentParams['contactID'] = $contactID; + $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution( + $form, + $paymentParams, + NULL, + $contactID, + $contributionType, + TRUE, TRUE, TRUE + ); + + $paymentParams['contributionID'] = $contribution->id; + $paymentParams['contributionTypeID'] = $contribution->financial_type_id; + $paymentParams['contributionPageID'] = $contribution->contribution_page_id; + + if ($form->_values['is_recur'] && $contribution->contribution_recur_id) { + $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id; + } + } + if (is_object($payment)) { + $result = &$payment->doDirectPayment($paymentParams); + } + else { + CRM_Core_Error::fatal($paymentObjError); + } + } + + if ($component == 'membership') { + $membershipResult = array(); + } + + if (is_a($result, 'CRM_Core_Error')) { + //make sure to cleanup db for recurring case. + if (CRM_Utils_Array::value('contributionID', $paymentParams)) { + CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']); + } + if (CRM_Utils_Array::value('contributionRecurID', $paymentParams)) { + CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']); + } + + if ($component !== 'membership') { + CRM_Core_Error::displaySessionError($result); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/transact', + "_qf_Main_display=true&qfKey={$form->_params['qfKey']}" + )); + } + $membershipResult[1] = $result; + } + elseif ($result) { + if ($result) { + $form->_params = array_merge($form->_params, $result); + } + $form->_params['receive_date'] = $now; + $form->set('params', $form->_params); + $form->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result)); + $form->assign('receive_date', + CRM_Utils_Date::mysqlToIso($form->_params['receive_date']) + ); + + // result has all the stuff we need + // lets archive it to a financial transaction + if ($contributionType->is_deductible) { + $form->assign('is_deductible', TRUE); + $form->set('is_deductible', TRUE); + } + + if (isset($paymentParams['contribution_source'])) { + $form->_params['source'] = $paymentParams['contribution_source']; + } + + // check if pending was set to true by payment processor + $pending = FALSE; + if (CRM_Utils_Array::value('contribution_status_pending', + $form->_params + )) { + $pending = TRUE; + } + if (!(!empty($paymentParams['is_recur']) && $form->_contributeMode == 'direct')) { + $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($form, + $form->_params, $result, + $contactID, $contributionType, + TRUE, $pending, TRUE + ); + } + $form->postProcessPremium($premiumParams, $contribution); + + $membershipResult[1] = $contribution; + } + + if ($component == 'membership') { + return $membershipResult; + } + + //Do not send an email if Recurring contribution is done via Direct Mode + //We will send email once the IPN is received. + if (!empty($paymentParams['is_recur']) && $form->_contributeMode == 'direct') { + return TRUE; + } + + // get the price set values for receipt. + if ($form->_priceSetId && $form->_lineItem) { + $form->_values['lineItem'] = $form->_lineItem; + $form->_values['priceSetID'] = $form->_priceSetId; + } + + // finally send an email receipt + if ($contribution) { + $form->_values['contribution_id'] = $contribution->id; + CRM_Contribute_BAO_ContributionPage::sendMail($contactID, + $form->_values, $contribution->is_test, + FALSE, $fieldTypes + ); + } + } + + /** + * Function to get the contribution details by month + * of the year + * + * @param int $param year + * + * @return array associated array + * + * @static + * @access public + */ + static function contributionChartMonthly($param) { + if ($param) { + $param = array(1 => array($param, 'Integer')); + } + else { + $param = date("Y"); + $param = array(1 => array($param, 'Integer')); + } + + $query = " + SELECT sum(contrib.total_amount) AS ctAmt, + MONTH( contrib.receive_date) AS contribMonth + FROM civicrm_contribution AS contrib +INNER JOIN civicrm_contact AS contact ON ( contact.id = contrib.contact_id ) + WHERE contrib.contact_id = contact.id + AND ( contrib.is_test = 0 OR contrib.is_test IS NULL ) + AND contrib.contribution_status_id = 1 + AND date_format(contrib.receive_date,'%Y') = %1 + AND contact.is_deleted = 0 + GROUP BY contribMonth + ORDER BY month(contrib.receive_date)"; + + $dao = CRM_Core_DAO::executeQuery($query, $param); + + $params = NULL; + while ($dao->fetch()) { + if ($dao->contribMonth) { + $params['By Month'][$dao->contribMonth] = $dao->ctAmt; + } + } + return $params; + } + + /** + * Function to get the contribution details by year + * + * @return array associated array + * + * @static + * @access public + */ + static function contributionChartYearly() { + $config = CRM_Core_Config::singleton(); + $yearClause = "year(contrib.receive_date) as contribYear"; + if (!empty($config->fiscalYearStart) && ($config->fiscalYearStart['M'] != 1 || $config->fiscalYearStart['d'] != 1)) { + $yearClause = "CASE WHEN DAYOFYEAR(contrib.receive_date)>= " . + date('z',mktime(0, 0, 0, $config->fiscalYearStart['M'], $config->fiscalYearStart['d']+1, 2000)) . + " THEN + concat(YEAR(contrib.receive_date), '-',YEAR(contrib.receive_date)+1) + ELSE concat(YEAR(contrib.receive_date)-1,'-', YEAR(contrib.receive_date)) END AS contribYear"; + } + + $query = " + SELECT sum(contrib.total_amount) AS ctAmt, + {$yearClause} + FROM civicrm_contribution AS contrib +INNER JOIN civicrm_contact contact ON ( contact.id = contrib.contact_id ) + WHERE ( contrib.is_test = 0 OR contrib.is_test IS NULL ) + AND contrib.contribution_status_id = 1 + AND contact.is_deleted = 0 + GROUP BY contribYear + ORDER BY contribYear"; + $dao = CRM_Core_DAO::executeQuery($query); + + $params = NULL; + while ($dao->fetch()) { + if (!empty($dao->contribYear)) { + $params['By Year'][$dao->contribYear] = $dao->ctAmt; + } + } + return $params; + } + + static function createCMSUser(&$params, $contactID, $mail) { + // lets ensure we only create one CMS user + static $created = FALSE; + + if ($created) { + return; + } + $created = TRUE; + + if (CRM_Utils_Array::value('cms_create_account', $params)) { + $params['contactID'] = $contactID; + if (!CRM_Core_BAO_CMSUser::create($params, $mail)) { + CRM_Core_Error::statusBounce(ts('Your profile is not saved and Account is not created.')); + } + } + } + + static function _fillCommonParams(&$params, $type = 'paypal') { + if (array_key_exists('transaction', $params)) { + $transaction = &$params['transaction']; + } + else { + $transaction = &$params; + } + + $params['contact_type'] = 'Individual'; + + $billingLocTypeId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_LocationType', 'Billing', 'id', 'name'); + if (!$billingLocTypeId) { + $billingLocTypeId = 1; + } + if (!CRM_Utils_System::isNull($params['address'])) { + $params['address'][1]['is_primary'] = 1; + $params['address'][1]['location_type_id'] = $billingLocTypeId; + } + if (!CRM_Utils_System::isNull($params['email'])) { + $params['email'] = array( + 1 => array('email' => $params['email'], + 'location_type_id' => $billingLocTypeId, + )); + } + + if (isset($transaction['trxn_id'])) { + // set error message if transaction has already been processed. + $contribution = new CRM_Contribute_DAO_Contribution(); + $contribution->trxn_id = $transaction['trxn_id']; + if ($contribution->find(TRUE)) { + $params['error'][] = ts('transaction already processed.'); + } + } + else { + // generate a new transaction id, if not already exist + $transaction['trxn_id'] = md5(uniqid(rand(), TRUE)); + } + + if (!isset( $transaction['financial_type_id'])) { + $contributionTypes = array_keys(CRM_Contribute_PseudoConstant::financialType()); + $transaction['financial_type_id'] = $contributionTypes[0]; + } + + if (($type == 'paypal') && (!isset($transaction['net_amount']))) { + $transaction['net_amount'] = $transaction['total_amount'] - CRM_Utils_Array::value('fee_amount', $transaction, 0); + } + + if (!isset($transaction['invoice_id'])) { + $transaction['invoice_id'] = $transaction['trxn_id']; + } + + $source = ts('ContributionProcessor: %1 API', + array(1 => ucfirst($type)) + ); + if (isset($transaction['source'])) { + $transaction['source'] = $source . ':: ' . $transaction['source']; + } + else { + $transaction['source'] = $source; + } + + return TRUE; + } + + static function formatAPIParams($apiParams, $mapper, $type = 'paypal', $category = TRUE) { + $type = strtolower($type); + + if (!in_array($type, array( + 'paypal', 'google', 'csv'))) { + // return the params as is + return $apiParams; + } + $params = $transaction = array(); + + if ($type == 'paypal') { + foreach ($apiParams as $detail => $val) { + if (isset($mapper['contact'][$detail])) { + $params[$mapper['contact'][$detail]] = $val; + } + elseif (isset($mapper['location'][$detail])) { + $params['address'][1][$mapper['location'][$detail]] = $val; + } + elseif (isset($mapper['transaction'][$detail])) { + switch ($detail) { + case 'l_period2': + // Sadly, PayPal seems to send two distinct data elements in a single field, + // so we break them out here. This is somewhat ugly and tragic. + $freqUnits = array( + 'D' => 'day', + 'W' => 'week', + 'M' => 'month', + 'Y' => 'year', + ); + list($frequency_interval, $frequency_unit) = explode(' ', $val); + $transaction['frequency_interval'] = $frequency_interval; + $transaction['frequency_unit'] = $freqUnits[$frequency_unit]; + break; + + case 'subscriptiondate': + case 'timestamp': + // PayPal dates are in ISO-8601 format. We need a format that + // MySQL likes + $unix_timestamp = strtotime($val); + $transaction[$mapper['transaction'][$detail]] = date('YmdHis', $unix_timestamp); + break; + + case 'note': + case 'custom': + case 'l_number0': + if ($val) { + $val = "[PayPal_field:{$detail}] {$val}"; + $transaction[$mapper['transaction'][$detail]] = !empty($transaction[$mapper['transaction'][$detail]]) ? $transaction[$mapper['transaction'][$detail]] . "
    " . $val : $val; + } + break; + + default: + $transaction[$mapper['transaction'][$detail]] = $val; + } + } + } + + if (!empty($transaction) && $category) { + $params['transaction'] = $transaction; + } + else { + $params += $transaction; + } + + self::_fillCommonParams($params, $type); + + return $params; + } + + if ($type == 'csv') { + $header = $apiParams['header']; + unset($apiParams['header']); + foreach ($apiParams as $key => $val) { + if (isset($mapper['contact'][$header[$key]])) { + $params[$mapper['contact'][$header[$key]]] = $val; + } + elseif (isset($mapper['location'][$header[$key]])) { + $params['address'][1][$mapper['location'][$header[$key]]] = $val; + } + elseif (isset($mapper['transaction'][$header[$key]])) { + $transaction[$mapper['transaction'][$header[$key]]] = $val; + } + else { + $params[$header[$key]] = $val; + } + } + + if (!empty($transaction) && $category) { + $params['transaction'] = $transaction; + } + else { + $params += $transaction; + } + + self::_fillCommonParams($params, $type); + + return $params; + } + + if ($type == 'google') { + // return if response smell invalid + if (!array_key_exists('risk-information-notification', $apiParams[1][$apiParams[0]]['notifications'])) { + return FALSE; + } + $riskInfo = &$apiParams[1][$apiParams[0]]['notifications']['risk-information-notification']; + + if (array_key_exists('new-order-notification', $apiParams[1][$apiParams[0]]['notifications'])) { + $newOrder = &$apiParams[1][$apiParams[0]]['notifications']['new-order-notification']; + } + + if ($riskInfo['google-order-number']['VALUE'] == $apiParams[2]['google-order-number']['VALUE']) { + foreach ($riskInfo['risk-information']['billing-address'] as $field => $info) { + if (CRM_Utils_Array::value($field, $mapper['location'])) { + $params['address'][1][$mapper['location'][$field]] = $info['VALUE']; + } + elseif (CRM_Utils_Array::value($field, $mapper['contact'])) { + if ($newOrder && CRM_Utils_Array::value('structured-name', $newOrder['buyer-billing-address'])) { + foreach ($newOrder['buyer-billing-address']['structured-name'] as $namePart => $nameValue) { + $params[$mapper['contact'][$namePart]] = $nameValue['VALUE']; + } + } + else { + $params[$mapper['contact'][$field]] = $info['VALUE']; + } + } + elseif (CRM_Utils_Array::value($field, $mapper['transaction'])) { + $transaction[$mapper['transaction'][$field]] = $info['VALUE']; + } + } + + // Response is an huge array. Lets pickup only those which we ineterested in + // using a local mapper, rather than traversing the entire array. + $localMapper = array( + 'google-order-number' => $riskInfo['google-order-number']['VALUE'], + 'total-charge-amount' => $apiParams[2]['total-charge-amount']['VALUE'], + 'currency' => $apiParams[2]['total-charge-amount']['currency'], + 'item-name' => $newOrder['shopping-cart']['items']['item']['item-name']['VALUE'], + 'timestamp' => $apiParams[2]['timestamp']['VALUE'], + ); + if (array_key_exists('latest-charge-fee', $apiParams[2])) { + $localMapper['latest-charge-fee'] = $apiParams[2]['latest-charge-fee']['total']['VALUE']; + $localMapper['net-amount'] = $localMapper['total-charge-amount'] - $localMapper['latest-charge-fee']; + } + + // This is a subscription (recurring) donation. + if (array_key_exists('subscription', $newOrder['shopping-cart']['items']['item'])) { + $subscription = $newOrder['shopping-cart']['items']['item']['subscription']; + $localMapper['amount'] = $newOrder['order-total']['VALUE']; + $localMapper['times'] = $subscription['payments']['subscription-payment']['times']; + // Convert Google's period to one compatible with the CiviCRM db field. + $freqUnits = array( + 'DAILY' => 'day', + 'WEEKLY' => 'week', + 'MONHTLY' => 'month', + 'YEARLY' => 'year', + ); + $localMapper['period'] = $freqUnits[$subscription['period']]; + // Unlike PayPal, Google has no concept of freq. interval, it is always 1. + $localMapper['frequency_interval'] = '1'; + // Google Checkout dates are in ISO-8601 format. We need a format that + // MySQL likes + $unix_timestamp = strtotime($localMapper['timestamp']); + $mysql_date = date('YmdHis', $unix_timestamp); + $localMapper['modified_date'] = $mysql_date; + $localMapper['start_date'] = $mysql_date; + // This is PayPal's nomenclature, but just use it for Google as well since + // we act on the value of trxn_type in processAPIContribution(). + $localMapper['trxn_type'] = 'subscrpayment'; + } + + foreach ($localMapper as $localKey => $localVal) { + if (CRM_Utils_Array::value($localKey, $mapper['transaction'])) { + $transaction[$mapper['transaction'][$localKey]] = $localVal; + } + } + + if (empty($params) && empty($transaction)) { + continue; + } + + if (!empty($transaction) && $category) { + $params['transaction'] = $transaction; + } + else { + $params += $transaction; + } + + self::_fillCommonParams($params, $type); + } + return $params; + } + } + + static function processAPIContribution($params) { + if (empty($params) || array_key_exists('error', $params)) { + return FALSE; + } + + // add contact using dedupe rule + $dedupeParams = CRM_Dedupe_Finder::formatParams($params, 'Individual'); + $dedupeParams['check_permission'] = FALSE; + $dupeIds = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual'); + // if we find more than one contact, use the first one + if (CRM_Utils_Array::value(0, $dupeIds)) { + $params['contact_id'] = $dupeIds[0]; + } + $contact = CRM_Contact_BAO_Contact::create($params); + if (!$contact->id) { + return FALSE; + } + + // only pass transaction params to contribution::create, if available + if (array_key_exists('transaction', $params)) { + $params = $params['transaction']; + $params['contact_id'] = $contact->id; + } + + // handle contribution custom data + $customFields = CRM_Core_BAO_CustomField::getFields('Contribution', + FALSE, + FALSE, + CRM_Utils_Array::value('financial_type_id', + $params + ) + ); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + CRM_Utils_Array::value('id', $params, NULL), + 'Contribution' + ); + // create contribution + + // if this is a recurring contribution then process it first + if ($params['trxn_type'] == 'subscrpayment') { + // see if a recurring record already exists + $recurring = new CRM_Contribute_BAO_ContributionRecur; + $recurring->processor_id = $params['processor_id']; + if (!$recurring->find(TRUE)) { + $recurring = new CRM_Contribute_BAO_ContributionRecur; + $recurring->invoice_id = $params['invoice_id']; + $recurring->find(TRUE); + } + + // This is the same thing the CiviCRM IPN handler does to handle + // subsequent recurring payments to avoid duplicate contribution + // errors due to invoice ID. See: + // ./CRM/Core/Payment/PayPalIPN.php:200 + if ($recurring->id) { + $params['invoice_id'] = md5(uniqid(rand(), TRUE)); + } + + $recurring->copyValues($params); + $recurring->save(); + if (is_a($recurring, 'CRM_Core_Error')) { + return FALSE; + } + else { + $params['contribution_recur_id'] = $recurring->id; + } + } + + $contribution = &CRM_Contribute_BAO_Contribution::create($params, + CRM_Core_DAO::$_nullArray + ); + if (!$contribution->id) { + return FALSE; + } + + return TRUE; + } + + static function getFirstLastDetails($contactID) { + static $_cache; + + if (!$_cache) { + $_cache = array(); + } + + if (!isset($_cache[$contactID])) { + $sql = " +SELECT total_amount, receive_date +FROM civicrm_contribution c +WHERE contact_id = %1 +ORDER BY receive_date ASC +LIMIT 1 +"; + $params = array(1 => array($contactID, 'Integer')); + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + $details = array( + 'first' => NULL, + 'last' => NULL, + ); + if ($dao->fetch()) { + $details['first'] = array( + 'total_amount' => $dao->total_amount, + 'receive_date' => $dao->receive_date, + ); + } + + // flip asc and desc to get the last query + $sql = str_replace('ASC', 'DESC', $sql); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + $details['last'] = array( + 'total_amount' => $dao->total_amount, + 'receive_date' => $dao->receive_date, + ); + } + + $_cache[$contactID] = $details; + } + return $_cache[$contactID]; + } +} + diff --git a/CRM/Contribute/BAO/ContributionPage.php b/CRM/Contribute/BAO/ContributionPage.php new file mode 100644 index 0000000000..2475655358 --- /dev/null +++ b/CRM/Contribute/BAO/ContributionPage.php @@ -0,0 +1,757 @@ +copyValues($params); + $dao->save(); + return $dao; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_ContributionPage', $id, 'is_active', $is_active); + } + + static function setValues($id, &$values) { + $params = array( + 'id' => $id, + ); + + CRM_Core_DAO::commonRetrieve('CRM_Contribute_DAO_ContributionPage', $params, $values); + + // get the profile ids + $ufJoinParams = array( + 'module' => 'CiviContribute', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $id, + ); + list($values['custom_pre_id'], $customPostIds) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + + if (!empty($customPostIds)) { + $values['custom_post_id'] = $customPostIds[0]; + } + else { + $values['custom_post_id'] = ''; + } + // // add an accounting code also + // if ($values ['financial_type_id']) { + // $values ['accountingCode'] = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_FinancialType', $values ['financial_type_id'], 'accounting_code' ); + // } + } + + /** + * Function to send the emails + * + * @param int $contactID contact id + * @param array $values associated array of fields + * @param boolean $isTest if in test mode + * @param boolean $returnMessageText return the message text instead of sending the mail + * + * @return void + * @access public + * @static + */ + static function sendMail($contactID, &$values, $isTest = FALSE, $returnMessageText = FALSE, $fieldTypes = NULL) { + $gIds = $params = array(); + $email = NULL; + if (isset($values['custom_pre_id'])) { + $preProfileType = CRM_Core_BAO_UFField::getProfileType($values['custom_pre_id']); + if ($preProfileType == 'Membership' && CRM_Utils_Array::value('membership_id', $values)) { + $params['custom_pre_id'] = array( + array( + 'member_id', + '=', + $values['membership_id'], + 0, + 0, + ), + ); + } + elseif ($preProfileType == 'Contribution' && CRM_Utils_Array::value('contribution_id', $values)) { + $params['custom_pre_id'] = array( + array( + 'contribution_id', + '=', + $values['contribution_id'], + 0, + 0, + ), + ); + } + + $gIds['custom_pre_id'] = $values['custom_pre_id']; + } + + if (isset($values['custom_post_id'])) { + $postProfileType = CRM_Core_BAO_UFField::getProfileType($values['custom_post_id']); + if ($postProfileType == 'Membership' && CRM_Utils_Array::value('membership_id', $values)) { + $params['custom_post_id'] = array( + array( + 'member_id', + '=', + $values['membership_id'], + 0, + 0, + ), + ); + } + elseif ($postProfileType == 'Contribution' && CRM_Utils_Array::value('contribution_id', $values)) { + $params['custom_post_id'] = array( + array( + 'contribution_id', + '=', + $values['contribution_id'], + 0, + 0, + ), + ); + } + + $gIds['custom_post_id'] = $values['custom_post_id']; + } + + if (CRM_Utils_Array::value('is_for_organization', $values)) { + if (CRM_Utils_Array::value('membership_id', $values)) { + $params['onbehalf_profile'] = array( + array( + 'member_id', + '=', + $values['membership_id'], + 0, + 0, + ), + ); + } + elseif (CRM_Utils_Array::value('contribution_id', $values)) { + $params['onbehalf_profile'] = array( + array( + 'contribution_id', + '=', + $values['contribution_id'], + 0, + 0, + ), + ); + } + } + + //check whether it is a test drive + if ($isTest && !empty($params['custom_pre_id'])) { + $params['custom_pre_id'][] = array( + 'contribution_test', + '=', + 1, + 0, + 0, + ); + } + + if ($isTest && !empty($params['custom_post_id'])) { + $params['custom_post_id'][] = array( + 'contribution_test', + '=', + 1, + 0, + 0, + ); + } + + if (!$returnMessageText && !empty($gIds)) { + //send notification email if field values are set (CRM-1941) + foreach ($gIds as $key => $gId) { + if ($gId) { + $email = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gId, 'notify'); + if ($email) { + $val = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($gId, $contactID, CRM_Utils_Array::value($key, $params), true ); + CRM_Core_BAO_UFGroup::commonSendMail($contactID, $val); + } + } + } + } + + if ( CRM_Utils_Array::value('is_email_receipt', $values) || + CRM_Utils_Array::value('onbehalf_dupe_alert', $values) || + $returnMessageText + ) { + $template = CRM_Core_Smarty::singleton(); + + // get the billing location type + if (!array_key_exists('related_contact', $values)) { + $locationTypes = CRM_Core_PseudoConstant::locationType(); + $billingLocationTypeId = array_search('Billing', $locationTypes); + } + else { + // presence of related contact implies onbehalf of org case, + // where location type is set to default. + $locType = CRM_Core_BAO_LocationType::getDefault(); + $billingLocationTypeId = $locType->id; + } + + if (!array_key_exists('related_contact', $values)) { + list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID, FALSE, $billingLocationTypeId); + } + // get primary location email if no email exist( for billing location). + if (!$email) { + list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID); + } + if (empty($displayName)) { + list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID); + } + + //for display profile need to get individual contact id, + //hence get it from related_contact if on behalf of org true CRM-3767 + //CRM-5001 Contribution/Membership:: On Behalf of Organization, + //If profile GROUP contain the Individual type then consider the + //profile is of Individual ( including the custom data of membership/contribution ) + //IF Individual type not present in profile then it is consider as Organization data. + $userID = $contactID; + if ($preID = CRM_Utils_Array::value('custom_pre_id', $values)) { + if (CRM_Utils_Array::value('related_contact', $values)) { + $preProfileTypes = CRM_Core_BAO_UFGroup::profileGroups($preID); + if (in_array('Individual', $preProfileTypes) || in_array('Contact', $postProfileTypes)) { + //Take Individual contact ID + $userID = CRM_Utils_Array::value('related_contact', $values); + } + } + self::buildCustomDisplay($preID, 'customPre', $userID, $template, $params['custom_pre_id']); + } + $userID = $contactID; + if ($postID = CRM_Utils_Array::value('custom_post_id', $values)) { + if (CRM_Utils_Array::value('related_contact', $values)) { + $postProfileTypes = CRM_Core_BAO_UFGroup::profileGroups($postID); + if (in_array('Individual', $postProfileTypes) || in_array('Contact', $postProfileTypes)) { + //Take Individual contact ID + $userID = CRM_Utils_Array::value('related_contact', $values); + } + } + self::buildCustomDisplay($postID, 'customPost', $userID, $template, $params['custom_post_id']); + } + + $title = isset($values['title']) ? $values['title'] : CRM_Contribute_PseudoConstant::contributionPage($values['contribution_page_id']); + + // set email in the template here + $tplParams = array( + 'email' => $email, + 'receiptFromEmail' => CRM_Utils_Array::value('receipt_from_email', $values), + 'contactID' => $contactID, + 'displayName' => $displayName, + 'contributionID' => CRM_Utils_Array::value('contribution_id', $values), + 'contributionOtherID' => CRM_Utils_Array::value('contribution_other_id', $values), + 'membershipID' => CRM_Utils_Array::value('membership_id', $values), + // CRM-5095 + 'lineItem' => CRM_Utils_Array::value('lineItem', $values), + // CRM-5095 + 'priceSetID' => CRM_Utils_Array::value('priceSetID', $values), + 'title' => $title, + 'isShare' => CRM_Utils_Array::value('is_share', $values), + ); + + if ( $contributionTypeId = CRM_Utils_Array::value('financial_type_id', $values ) ) { + $tplParams['contributionTypeId'] = $contributionTypeId; + $tplParams['contributionTypeName'] = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_FinancialType', + $contributionTypeId ); + } + + if ($contributionPageId = CRM_Utils_Array::value('id', $values)) { + $tplParams['contributionPageId'] = $contributionPageId; + } + + // address required during receipt processing (pdf and email receipt) + if ($displayAddress = CRM_Utils_Array::value('address', $values)) { + $tplParams['address'] = $displayAddress; + } + + // CRM-6976 + $originalCCReceipt = CRM_Utils_Array::value('cc_receipt', $values); + + // cc to related contacts of contributor OR the one who + // signs up. Is used for cases like - on behalf of + // contribution / signup ..etc + if (array_key_exists('related_contact', $values)) { + list($ccDisplayName, $ccEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($values['related_contact']); + $ccMailId = "{$ccDisplayName} <{$ccEmail}>"; + + $values['cc_receipt'] = CRM_Utils_Array::value('cc_receipt', $values) ? ($values['cc_receipt'] . ',' . $ccMailId) : $ccMailId; + + // reset primary-email in the template + $tplParams['email'] = $ccEmail; + + $tplParams['onBehalfName'] = $displayName; + $tplParams['onBehalfEmail'] = $email; + + $ufJoinParams = array( + 'module' => 'onBehalf', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $values['id'], + ); + $OnBehalfProfile = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + $profileId = $OnBehalfProfile[0]; + $userID = $contactID; + self::buildCustomDisplay($profileId, 'onBehalfProfile', $userID, $template, $params['onbehalf_profile'], $fieldTypes); + } + + // use either the contribution or membership receipt, based on whether it’s a membership-related contrib or not + $sendTemplateParams = array( + 'groupName' => $tplParams['membershipID'] ? 'msg_tpl_workflow_membership' : 'msg_tpl_workflow_contribution', + 'valueName' => $tplParams['membershipID'] ? 'membership_online_receipt' : 'contribution_online_receipt', + 'contactId' => $contactID, + 'tplParams' => $tplParams, + 'isTest' => $isTest, + 'PDFFilename' => 'receipt.pdf', + ); + + if ($returnMessageText) { + list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + return array( + 'subject' => $subject, + 'body' => $message, + 'to' => $displayName, + 'html' => $html, + ); + } + + if ($values['is_email_receipt']) { + $sendTemplateParams['from'] = CRM_Utils_Array::value('receipt_from_name', $values) . ' <' . $values['receipt_from_email'] . '>'; + $sendTemplateParams['toName'] = $displayName; + $sendTemplateParams['toEmail'] = $email; + $sendTemplateParams['cc'] = CRM_Utils_Array::value('cc_receipt', $values); + $sendTemplateParams['bcc'] = CRM_Utils_Array::value('bcc_receipt', $values); + list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + } + + // send duplicate alert, if dupe match found during on-behalf-of processing. + if (CRM_Utils_Array::value('onbehalf_dupe_alert', $values)) { + $sendTemplateParams['groupName'] = 'msg_tpl_workflow_contribution'; + $sendTemplateParams['valueName'] = 'contribution_dupalert'; + $sendTemplateParams['from'] = ts('Automatically Generated') . " <{$values['receipt_from_email']}>"; + $sendTemplateParams['toName'] = CRM_Utils_Array::value('receipt_from_name', $values); + $sendTemplateParams['toEmail'] = CRM_Utils_Array::value('receipt_from_email', $values); + $sendTemplateParams['tplParams']['onBehalfID'] = $contactID; + $sendTemplateParams['tplParams']['receiptMessage'] = $message; + + // fix cc and reset back to original, CRM-6976 + $sendTemplateParams['cc'] = $originalCCReceipt; + + CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + } + } + } + + /* + * Construct the message to be sent by the send function + * + */ + function composeMessage($tplParams, $contactID, $isTest) { + $sendTemplateParams = array( + 'groupName' => $tplParams['membershipID'] ? 'msg_tpl_workflow_membership' : 'msg_tpl_workflow_contribution', + 'valueName' => $tplParams['membershipID'] ? 'membership_online_receipt' : 'contribution_online_receipt', + 'contactId' => $contactID, + 'tplParams' => $tplParams, + 'isTest' => $isTest, + 'PDFFilename' => 'receipt.pdf', + ); + if ($returnMessageText) { + list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + return array( + 'subject' => $subject, + 'body' => $message, + 'to' => $displayName, + 'html' => $html, + ); + } + } + + /** + * Function to send the emails for Recurring Contribution Notication + * + * @param string $type txnType + * @param int $contactID contact id for contributor + * @param int $pageID contribution page id + * @param object $recur object of recurring contribution table + * @param object $autoRenewMembership is it a auto renew membership. + * + * @return void + * @access public + * @static + */ + static function recurringNotify($type, $contactID, $pageID, $recur, $autoRenewMembership = FALSE) { + $value = array(); + if ($pageID) { + CRM_Core_DAO::commonRetrieveAll('CRM_Contribute_DAO_ContributionPage', 'id', $pageID, $value, array( + 'title', + 'is_email_receipt', + 'receipt_from_name', + 'receipt_from_email', + 'cc_receipt', + 'bcc_receipt', + )); + } + + $isEmailReceipt = CRM_Utils_Array::value('is_email_receipt', $value[$pageID]); + $isOfflineRecur = FALSE; + if (!$pageID && $recur->id) { + $isOfflineRecur = TRUE; + } + if ($isEmailReceipt || $isOfflineRecur) { + if ($pageID) { + $receiptFrom = '"' . CRM_Utils_Array::value('receipt_from_name', $value[$pageID]) . '" <' . $value[$pageID]['receipt_from_email'] . '>'; + + $receiptFromName = $value[$pageID]['receipt_from_name']; + $receiptFromEmail = $value[$pageID]['receipt_from_email']; + } + else { + $domainValues = CRM_Core_BAO_Domain::getNameAndEmail(); + $receiptFrom = "$domainValues[0] <$domainValues[1]>"; + $receiptFromName = $domainValues[0]; + $receiptFromEmail = $domainValues[1]; + } + + list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID, FALSE); + $templatesParams = array( + 'groupName' => 'msg_tpl_workflow_contribution', + 'valueName' => 'contribution_recurring_notify', + 'contactId' => $contactID, + 'tplParams' => array( + 'recur_frequency_interval' => $recur->frequency_interval, + 'recur_frequency_unit' => $recur->frequency_unit, + 'recur_installments' => $recur->installments, + 'recur_start_date' => $recur->start_date, + 'recur_end_date' => $recur->end_date, + 'recur_amount' => $recur->amount, + 'recur_txnType' => $type, + 'displayName' => $displayName, + 'receipt_from_name' => $receiptFromName, + 'receipt_from_email' => $receiptFromEmail, + 'auto_renew_membership' => $autoRenewMembership, + ), + 'from' => $receiptFrom, + 'toName' => $displayName, + 'toEmail' => $email, + ); + + if ($recur->id) { + // in some cases its just recurringNotify() thats called for the first time and these urls don't get set. + // like in PaypalPro, & therefore we set it here additionally. + $template = CRM_Core_Smarty::singleton(); + $paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($recur->id, 'recur', 'obj'); + $url = $paymentProcessor->subscriptionURL($recur->id, 'recur'); + $template->assign('cancelSubscriptionUrl', $url); + + $url = $paymentProcessor->subscriptionURL($recur->id, 'recur', 'billing'); + $template->assign('updateSubscriptionBillingUrl', $url); + + $url = $paymentProcessor->subscriptionURL($recur->id, 'recur', 'update'); + $template->assign('updateSubscriptionUrl', $url); + } + + list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate($templatesParams); + + if ($sent) { + CRM_Core_Error::debug_log_message('Success: mail sent for recurring notification.'); + } + else { + CRM_Core_Error::debug_log_message('Failure: mail not sent for recurring notification.'); + } + } + } + + /** + * Function to add the custom fields for contribution page (ie profile) + * + * @param int $gid uf group id + * @param string $name + * @param int $cid contact id + * @param array $params params to build component whereclause + * + * @return void + * @access public + * @static + */ + function buildCustomDisplay($gid, $name, $cid, &$template, &$params, $fieldTypes = NULL) { + if ($gid) { + if (CRM_Core_BAO_UFGroup::filterUFGroups($gid, $cid)) { + $values = array(); + $groupTitle = NULL; + $fields = CRM_Core_BAO_UFGroup::getFields($gid, FALSE, CRM_Core_Action::VIEW, NULL, NULL, FALSE, NULL, FALSE, NULL, CRM_Core_Permission::CREATE, NULL); + foreach ($fields as $k => $v) { + if (!$groupTitle) { + $groupTitle = $v["groupTitle"]; + } + // suppress all file fields from display and formatting fields + if ( + CRM_Utils_Array::value('data_type', $v, '') == 'File' || + CRM_Utils_Array::value('name', $v, '') == 'image_URL' || + CRM_Utils_Array::value('field_type', $v) == 'Formatting' + ) { + unset($fields[$k]); + } + + if (!empty($fieldTypes) && (!in_array($v['field_type'], $fieldTypes))) { + unset($fields[$k]); + } + } + + if ($groupTitle) { + $template->assign($name . "_grouptitle", $groupTitle); + } + + CRM_Core_BAO_UFGroup::getValues($cid, $fields, $values, FALSE, $params); + + if (count($values)) { + $template->assign($name, $values); + } + } + } + } + + /** + * This function is to make a copy of a contribution page, including + * all the blocks in the page + * + * @param int $id the contribution page id to copy + * + * @return the copy object + * @access public + * @static + */ + static function copy($id) { + $fieldsFix = array( + 'prefix' => array( + 'title' => ts('Copy of') . ' ', + ), + ); + $copy = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_ContributionPage', array( + 'id' => $id, + ), NULL, $fieldsFix); + + //copying all the blocks pertaining to the contribution page + $copyPledgeBlock = &CRM_Core_DAO::copyGeneric('CRM_Pledge_DAO_PledgeBlock', array( + 'entity_id' => $id, + 'entity_table' => 'civicrm_contribution_page', + ), array( + 'entity_id' => $copy->id, + )); + + $copyMembershipBlock = &CRM_Core_DAO::copyGeneric('CRM_Member_DAO_MembershipBlock', array( + 'entity_id' => $id, + 'entity_table' => 'civicrm_contribution_page', + ), array( + 'entity_id' => $copy->id, + )); + + $copyUFJoin = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin', array( + 'entity_id' => $id, + 'entity_table' => 'civicrm_contribution_page', + ), array( + 'entity_id' => $copy->id, + )); + + $copyWidget = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Widget', array( + 'contribution_page_id' => $id, + ), array( + 'contribution_page_id' => $copy->id, + )); + + //copy option group and values + $copy->default_amount_id = CRM_Core_BAO_OptionGroup::copyValue('contribution', $id, $copy->id, CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $id, 'default_amount_id')); + $copyTellFriend = &CRM_Core_DAO::copyGeneric('CRM_Friend_DAO_Friend', array( + 'entity_id' => $id, + 'entity_table' => 'civicrm_contribution_page', + ), array( + 'entity_id' => $copy->id, + )); + + $copyPersonalCampaignPages = &CRM_Core_DAO::copyGeneric('CRM_PCP_DAO_PCPBlock', array( + 'entity_id' => $id, + 'entity_table' => 'civicrm_contribution_page', + ), array( + 'entity_id' => $copy->id, + )); + + $copyPremium = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Premium', array( + 'entity_id' => $id, + 'entity_table' => 'civicrm_contribution_page', + ), array( + 'entity_id' => $copy->id, + )); + $premiumQuery = " +SELECT id +FROM civicrm_premiums +WHERE entity_table = 'civicrm_contribution_page' + AND entity_id ={$id}"; + + $premiumDao = CRM_Core_DAO::executeQuery($premiumQuery, CRM_Core_DAO::$_nullArray); + while ($premiumDao->fetch()) { + if ($premiumDao->id) { + $copyPremiumProduct = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_PremiumsProduct', array( + 'premiums_id' => $premiumDao->id, + ), array( + 'premiums_id' => $copyPremium->id, + )); + } + } + + $copy->save(); + + CRM_Utils_Hook::copy('ContributionPage', $copy); + + return $copy; + } + + /** + * Function to check if contribution page contains payment + * processor that supports recurring payment + * + * @param int $contributionPageId Contribution Page Id + * + * @return boolean true if payment processor supports recurring + * else false + * + * @access public + * @static + */ + static function checkRecurPaymentProcessor($contributionPageId) { + //FIXME + $sql = " + SELECT pp.is_recur + FROM civicrm_contribution_page cp, + civicrm_payment_processor pp + WHERE cp.payment_processor = pp.id + AND cp.id = {$contributionPageId} +"; + + if ($recurring = &CRM_Core_DAO::singleValueQuery($sql, CRM_Core_DAO::$_nullArray)) { + return TRUE; + } + return FALSE; + } + + /** + * Function to get info for all sections enable/disable. + * + * @return array $info info regarding all sections. + * @access public + * @static + */ + static function getSectionInfo($contribPageIds = array( + )) { + $info = array(); + $whereClause = NULL; + if (is_array($contribPageIds) && !empty($contribPageIds)) { + $whereClause = 'WHERE civicrm_contribution_page.id IN ( ' . implode(', ', $contribPageIds) . ' )'; + } + + $sections = array( + 'settings', + 'amount', + 'membership', + 'custom', + 'thankyou', + 'friend', + 'pcp', + 'widget', + 'premium', + ); + $query = " + SELECT civicrm_contribution_page.id as id, + civicrm_contribution_page.financial_type_id as settings, + amount_block_is_active as amount, + civicrm_membership_block.id as membership, + civicrm_uf_join.id as custom, + civicrm_contribution_page.thankyou_title as thankyou, + civicrm_tell_friend.id as friend, + civicrm_pcp_block.id as pcp, + civicrm_contribution_widget.id as widget, + civicrm_premiums.id as premium + FROM civicrm_contribution_page +LEFT JOIN civicrm_membership_block ON ( civicrm_membership_block.entity_id = civicrm_contribution_page.id + AND civicrm_membership_block.entity_table = 'civicrm_contribution_page' + AND civicrm_membership_block.is_active = 1 ) +LEFT JOIN civicrm_uf_join ON ( civicrm_uf_join.entity_id = civicrm_contribution_page.id + AND civicrm_uf_join.entity_table = 'civicrm_contribution_page' + AND module = 'CiviContribute' + AND civicrm_uf_join.is_active = 1 ) +LEFT JOIN civicrm_tell_friend ON ( civicrm_tell_friend.entity_id = civicrm_contribution_page.id + AND civicrm_tell_friend.entity_table = 'civicrm_contribution_page' + AND civicrm_tell_friend.is_active = 1) +LEFT JOIN civicrm_pcp_block ON ( civicrm_pcp_block.entity_id = civicrm_contribution_page.id + AND civicrm_pcp_block.entity_table = 'civicrm_contribution_page' + AND civicrm_pcp_block.is_active = 1 ) +LEFT JOIN civicrm_contribution_widget ON ( civicrm_contribution_widget.contribution_page_id = civicrm_contribution_page.id + AND civicrm_contribution_widget.is_active = 1 ) +LEFT JOIN civicrm_premiums ON ( civicrm_premiums.entity_id = civicrm_contribution_page.id + AND civicrm_premiums.entity_table = 'civicrm_contribution_page' + AND civicrm_premiums.premiums_active = 1 ) + $whereClause"; + + $contributionPage = CRM_Core_DAO::executeQuery($query); + while ($contributionPage->fetch()) { + if (!isset($info[$contributionPage->id]) || !is_array($info[$contributionPage->id])) { + $info[$contributionPage->id] = array_fill_keys(array_values($sections), FALSE); + } + foreach ($sections as $section) { + if ($contributionPage->$section) { + $info[$contributionPage->id][$section] = TRUE; + } + } + } + + return $info; + } +} + diff --git a/CRM/Contribute/BAO/ContributionRecur.php b/CRM/Contribute/BAO/ContributionRecur.php new file mode 100644 index 0000000000..f918ca1670 --- /dev/null +++ b/CRM/Contribute/BAO/ContributionRecur.php @@ -0,0 +1,461 @@ +push(CRM_Core_Error::DUPLICATE_CONTRIBUTION, + 'Fatal', + array($d), + "Found matching recurring contribution(s): $d" + ); + return $error; + } + + $recurring = new CRM_Contribute_BAO_ContributionRecur(); + $recurring->copyValues($params); + $recurring->id = CRM_Utils_Array::value('id', $params); + + // set currency for CRM-1496 + if (!isset($recurring->currency)) { + $config = CRM_Core_Config::singleton(); + $recurring->currency = $config->defaultCurrency; + } + $result = $recurring->save(); + + if (CRM_Utils_Array::value('id', $params)) { + CRM_Utils_Hook::post('edit', 'ContributionRecur', $recurring->id, $recurring); + } + else { + CRM_Utils_Hook::post('create', 'ContributionRecur', $recurring->id, $recurring); + } + + return $result; + } + + /** + * Check if there is a recurring contribution with the same trxn_id or invoice_id + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $duplicates (reference ) store ids of duplicate contribs + * + * @return boolean true if duplicate, false otherwise + * @access public + * static + */ + static function checkDuplicate($params, &$duplicates) { + $id = CRM_Utils_Array::value('id', $params); + $trxn_id = CRM_Utils_Array::value('trxn_id', $params); + $invoice_id = CRM_Utils_Array::value('invoice_id', $params); + + $clause = array(); + $params = array(); + + if ($trxn_id) { + $clause[] = "trxn_id = %1"; + $params[1] = array($trxn_id, 'String'); + } + + if ($invoice_id) { + $clause[] = "invoice_id = %2"; + $params[2] = array($invoice_id, 'String'); + } + + if (empty($clause)) { + return FALSE; + } + + $clause = implode(' OR ', $clause); + if ($id) { + $clause = "( $clause ) AND id != %3"; + $params[3] = array($id, 'Integer'); + } + + $query = "SELECT id FROM civicrm_contribution_recur WHERE $clause"; + $dao = CRM_Core_DAO::executeQuery($query, $params); + $result = FALSE; + while ($dao->fetch()) { + $duplicates[] = $dao->id; + $result = TRUE; + } + return $result; + } + + static function getPaymentProcessor($id, $mode) { + //FIX ME: + $sql = " +SELECT r.payment_processor_id + FROM civicrm_contribution_recur r + WHERE r.id = %1"; + $params = array(1 => array($id, 'Integer')); + $paymentProcessorID = &CRM_Core_DAO::singleValueQuery($sql, + $params + ); + if (!$paymentProcessorID) { + return NULL; + } + + return CRM_Financial_BAO_PaymentProcessor::getPayment($paymentProcessorID, $mode); + } + + /** + * Function to get the number of installment done/completed for each recurring contribution + * + * @param array $ids (reference ) an array of recurring contribution ids + * + * @return array $totalCount an array of recurring ids count + * @access public + * static + */ + static function getCount(&$ids) { + $recurID = implode(',', $ids); + $totalCount = array(); + + $query = " + SELECT contribution_recur_id, count( contribution_recur_id ) as commpleted + FROM civicrm_contribution + WHERE contribution_recur_id IN ( {$recurID}) AND is_test = 0 + GROUP BY contribution_recur_id"; + + $res = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + + while ($res->fetch()) { + $totalCount[$res->contribution_recur_id] = $res->commpleted; + } + return $totalCount; + } + + /** + * Delete Recurring contribution. + * + * @return true / false. + * @access public + * @static + */ + static function deleteRecurContribution($recurId) { + $result = FALSE; + if (!$recurId) { + return $result; + } + + $recur = new CRM_Contribute_DAO_ContributionRecur(); + $recur->id = $recurId; + $result = $recur->delete(); + + return $result; + } + + /** + * Cancel Recurring contribution. + * + * @param integer $recurId recur contribution id. + * @param array $objects an array of objects that is to be cancelled like + * contribution, membership, event. At least contribution object is a must. + * + * @return true / false. + * @access public + * @static + */ + static function cancelRecurContribution($recurId, $objects, $activityParams = array()) { + if (!$recurId) { + return FALSE; + } + + $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + $canceledId = array_search('Cancelled', $contributionStatus); + $recur = new CRM_Contribute_DAO_ContributionRecur(); + $recur->id = $recurId; + $recur->whereAdd("contribution_status_id != $canceledId"); + + if ($recur->find(TRUE)) { + $transaction = new CRM_Core_Transaction(); + $recur->contribution_status_id = $canceledId; + $recur->start_date = CRM_Utils_Date::isoToMysql($recur->start_date); + $recur->create_date = CRM_Utils_Date::isoToMysql($recur->create_date); + $recur->modified_date = CRM_Utils_Date::isoToMysql($recur->modified_date); + $recur->cancel_date = date('YmdHis'); + $recur->save(); + + $dao = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recurId); + if ($dao->recur_id) { + $details = CRM_Utils_Array::value('details', $activityParams); + if ($dao->auto_renew && $dao->membership_id) { + // its auto-renewal membership mode + $membershipTypes = CRM_Member_PseudoConstant::membershipType(); + $membershipType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $dao->membership_id, 'membership_type_id'); + $membershipType = CRM_Utils_Array::value($membershipType, $membershipTypes); + $details .= ' +
    ' . ts('Automatic renewal of %1 membership cancelled.', array(1 => $membershipType)); + } + else { + $details .= ' +
    ' . ts('The recurring contribution of %1, every %2 %3 has been cancelled.', array( + 1 => $dao->amount, + 2 => $dao->frequency_interval, + 3 => $dao->frequency_unit + )); + } + $activityParams = array( + 'source_contact_id' => $dao->contact_id, + 'source_record_id' => CRM_Utils_Array::value('source_record_id', $activityParams), + 'activity_type_id' => CRM_Core_OptionGroup::getValue('activity_type', + 'Cancel Recurring Contribution', + 'name' + ), + 'subject' => CRM_Utils_Array::value('subject', $activityParams, ts('Recurring contribution cancelled')), + 'details' => $details, + 'activity_date_time' => date('YmdHis'), + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + 'Completed', + 'name' + ), + ); + $session = CRM_Core_Session::singleton(); + $cid = $session->get('userID'); + if ($cid) { + $activityParams['target_contact_id'][] = $activityParams['source_contact_id']; + $activityParams['source_contact_id'] = $cid; + } + CRM_Activity_BAO_Activity::create($activityParams); + } + + // if there are associated objects, cancel them as well + if ($objects == CRM_Core_DAO::$_nullObject) { + $transaction->commit(); + return TRUE; + } + else { + $baseIPN = new CRM_Core_Payment_BaseIPN(); + return $baseIPN->cancelled($objects, $transaction); + } + } + else { + // if already cancelled, return true + $recur->whereAdd(); + $recur->whereAdd("contribution_status_id = $canceledId"); + if ($recur->find(TRUE)) { + return TRUE; + } + } + + return FALSE; + } + + /** + * Function to get list of recurring contribution of contact Ids + * + * @param int $contactId Contact ID + * + * @return return the list of recurring contribution fields + * + * @access public + * @static + */ + static function getRecurContributions($contactId) { + $params = array(); + $recurDAO = new CRM_Contribute_DAO_ContributionRecur(); + $recurDAO->contact_id = $contactId; + $recurDAO->find(); + $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(); + + while ($recurDAO->fetch()) { + $params[$recurDAO->id]['id'] = $recurDAO->id; + $params[$recurDAO->id]['contactId'] = $recurDAO->contact_id; + $params[$recurDAO->id]['start_date'] = $recurDAO->start_date; + $params[$recurDAO->id]['end_date'] = $recurDAO->end_date; + $params[$recurDAO->id]['next_sched_contribution'] = $recurDAO->next_sched_contribution; + $params[$recurDAO->id]['amount'] = $recurDAO->amount; + $params[$recurDAO->id]['currency'] = $recurDAO->currency; + $params[$recurDAO->id]['frequency_unit'] = $recurDAO->frequency_unit; + $params[$recurDAO->id]['frequency_interval'] = $recurDAO->frequency_interval; + $params[$recurDAO->id]['installments'] = $recurDAO->installments; + $params[$recurDAO->id]['contribution_status_id'] = $recurDAO->contribution_status_id; + $params[$recurDAO->id]['contribution_status'] = CRM_Utils_Array::value($recurDAO->contribution_status_id, $contributionStatus); + $params[$recurDAO->id]['is_test'] = $recurDAO->is_test; + $params[$recurDAO->id]['payment_processor_id'] = $recurDAO->payment_processor_id; + } + + return $params; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + if (!$is_active) { + return self::cancelRecurContribution($id, CRM_Core_DAO::$_nullObject); + } + return FALSE; + } + + static function getSubscriptionDetails($entityID, $entity = 'recur') { + $sql = " +SELECT rec.id as recur_id, + rec.processor_id as subscription_id, + rec.frequency_interval, + rec.installments, + rec.frequency_unit, + rec.amount, + rec.is_test, + rec.auto_renew, + rec.currency, + con.id as contribution_id, + con.contribution_page_id, + con.contact_id, + mp.membership_id"; + + if ($entity == 'recur') { + $sql .= " + FROM civicrm_contribution_recur rec +INNER JOIN civicrm_contribution con ON ( con.contribution_recur_id = rec.id ) +LEFT JOIN civicrm_membership_payment mp ON ( mp.contribution_id = con.id ) + WHERE rec.id = %1 + GROUP BY rec.id"; + } + elseif ($entity == 'contribution') { + $sql .= " + FROM civicrm_contribution con +INNER JOIN civicrm_contribution_recur rec +LEFT JOIN civicrm_membership_payment mp ON ( mp.contribution_id = con.id ) + WHERE con.id = %1"; + } + elseif ($entity == 'membership') { + $sql .= " + FROM civicrm_membership_payment mp +INNER JOIN civicrm_membership mem ON ( mp.membership_id = mem.id ) +INNER JOIN civicrm_contribution_recur rec ON ( mem.contribution_recur_id = rec.id ) +INNER JOIN civicrm_contribution con ON ( con.id = mp.contribution_id ) + WHERE mp.membership_id = %1"; + } + + $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($entityID, 'Integer'))); + if ($dao->fetch()) { + return $dao; + } + else return CRM_Core_DAO::$_nullObject; + } + + static function setSubscriptionContext() { + // handle context redirection for subscription url + $session = CRM_Core_Session::singleton(); + if ($session->get('userID')) { + $url = FALSE; + $cid = CRM_Utils_Request::retrieve('cid', 'Integer', $this, FALSE); + $mid = CRM_Utils_Request::retrieve('mid', 'Integer', $this, FALSE); + $qfkey = CRM_Utils_Request::retrieve('key', 'String', $this, FALSE); + $context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE); + if ($cid) { + switch ($context) { + case 'contribution': + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&selectedChild=contribute&cid={$cid}" + ); + break; + + case 'membership': + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&selectedChild=member&cid={$cid}" + ); + break; + + case 'dashboard': + $url = CRM_Utils_System::url('civicrm/user', "reset=1&id={$cid}"); + break; + } + } + if ($mid) { + switch ($context) { + case 'dashboard': + $url = CRM_Utils_System::url('civicrm/member', "force=1&context={$context}&key={$qfkey}"); + break; + + case 'search': + $url = CRM_Utils_System::url('civicrm/member/search', "force=1&context={$context}&key={$qfkey}"); + break; + } + } + if ($url) { + $session->pushUserContext($url); + } + } + } +} + diff --git a/CRM/Contribute/BAO/ManagePremiums.php b/CRM/Contribute/BAO/ManagePremiums.php new file mode 100644 index 0000000000..9e3ad2c142 --- /dev/null +++ b/CRM/Contribute/BAO/ManagePremiums.php @@ -0,0 +1,148 @@ +copyValues($params); + if ($premium->find(TRUE)) { + $premium->product_name = $premium->name; + CRM_Core_DAO::storeValues($premium, $defaults); + return $premium; + } + return NULL; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + if (!$is_active) { + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->product_id = $id; + $dao->delete(); + } + return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Product', $id, 'is_active', $is_active); + } + + /** + * function to add the financial types + * + * @param array $params reference array contains the values submitted by the form + * @param array $ids reference array contains the id + * + * @access public + * @static + * + * @return object + */ + static function add(&$params, &$ids) { + + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['is_deductible'] = CRM_Utils_Array::value('is_deductible', $params, FALSE); + + // action is taken depending upon the mode + $premium = new CRM_Contribute_DAO_Product(); + $premium->copyValues($params); + + $premium->id = CRM_Utils_Array::value('premium', $ids); + + // set currency for CRM-1496 + if (!isset($premium->currency)) { + $config = CRM_Core_Config::singleton(); + $premium->currency = $config->defaultCurrency; + } + + $premium->save(); + return $premium; + } + + /** + * Function to delete premium Types + * + * @param int $productID + * @static + */ + + static function del($productID) { + //check dependencies + $premiumsProduct = new CRM_Contribute_DAO_PremiumsProduct(); + $premiumsProduct->product_id = $productID; + if ($premiumsProduct->find(TRUE)) { + $session = CRM_Core_Session::singleton(); + $message .= ts('This Premium is being linked to Online Contribution page. Please remove it in order to delete this Premium.', array(1 => CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1')), ts('Deletion Error'), 'error'); + CRM_Core_Session::setStatus($message); + return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/contribute/managePremiums', 'reset=1&action=browse')); + } + + //delete from financial Type table + $premium = new CRM_Contribute_DAO_Product(); + $premium->id = $productID; + $premium->delete(); + } +} + diff --git a/CRM/Contribute/BAO/Premium.php b/CRM/Contribute/BAO/Premium.php new file mode 100644 index 0000000000..522fe93fbf --- /dev/null +++ b/CRM/Contribute/BAO/Premium.php @@ -0,0 +1,269 @@ +copyValues($params); + if ($premium->find(TRUE)) { + CRM_Core_DAO::storeValues($premium, $defaults); + return $premium; + } + return NULL; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Premium', $id, 'premiums_active ', $is_active); + } + + /** + * Function to delete financial Types + * + * @param int $contributionTypeId + * @static + */ + static function del($premiumID) { + //check dependencies + + //delete from financial Type table + $premium = new CRM_Contribute_DAO_Premium(); + $premium->id = $premiumID; + $premium->delete(); + } + + /** + * Function to build Premium Block im Contribution Pages + * + * @param int $pageId + * @static + */ + static function buildPremiumBlock(&$form, $pageID, $formItems = FALSE, $selectedProductID = NULL, $selectedOption = NULL) { + $form->add('hidden', "selectProduct", $selectedProductID, array('id' => 'selectProduct')); + + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $pageID; + $dao->premiums_active = 1; + + if ($dao->find(TRUE)) { + $premiumID = $dao->id; + $premiumBlock = array(); + CRM_Core_DAO::storeValues($dao, $premiumBlock); + + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->premiums_id = $premiumID; + $dao->orderBy('weight'); + $dao->find(); + + $products = array(); + $radio = array(); + while ($dao->fetch()) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $dao->product_id; + $productDAO->is_active = 1; + if ($productDAO->find(TRUE)) { + if ($selectedProductID != NULL) { + if ($selectedProductID == $productDAO->id) { + if ($selectedOption) { + $productDAO->options = ts('Selected Option') . ': ' . $selectedOption; + } + else { + $productDAO->options = NULL; + } + CRM_Core_DAO::storeValues($productDAO, $products[$productDAO->id]); + } + } + else { + CRM_Core_DAO::storeValues($productDAO, $products[$productDAO->id]); + } + } + $options = $temp = array(); + $temp = explode(',', $productDAO->options); + foreach ($temp as $value) { + $options[trim($value)] = trim($value); + } + if ($temp[0] != '') { + $form->addElement('select', 'options_' . $productDAO->id, NULL, $options); + } + } + if (count($products)) { + $form->assign('showPremium', $formItems); + $form->assign('showSelectOptions', $formItems); + $form->assign('products', $products); + $form->assign('premiumBlock', $premiumBlock); + } + } + } + + /** + * Function to build Premium B im Contribution Pages + * + * @param int $pageId + * @static + */ + function buildPremiumPreviewBlock($form, $productID, $premiumProductID = NULL) { + if ($premiumProductID) { + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->id = $premiumProductID; + $dao->find(TRUE); + $productID = $dao->product_id; + } + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $productID; + $productDAO->is_active = 1; + if ($productDAO->find(TRUE)) { + CRM_Core_DAO::storeValues($productDAO, $products[$productDAO->id]); + } + + $radio[$productDAO->id] = $form->createElement('radio', NULL, NULL, NULL, $productDAO->id, NULL); + $options = $temp = array(); + $temp = explode(',', $productDAO->options); + foreach ($temp as $value) { + $options[$value] = $value; + } + if ($temp[0] != '') { + $form->add('select', 'options_' . $productDAO->id, NULL, $options); + } + + $form->addGroup($radio, 'selectProduct', NULL); + + $form->assign('showRadio', TRUE); + $form->assign('showSelectOptions', TRUE); + $form->assign('products', $products); + $form->assign('preview', TRUE); + } + + /** + * Function to delete premium associated w/ contribution page. + * + * @param int $contribution page id + * @static + */ + static function deletePremium($contributionPageID) { + if (!$contributionPageID) { + return; + } + + //need to delete entries from civicrm_premiums + //as well as from civicrm_premiums_product, CRM-4586 + + $params = array( + 'entity_id' => $contributionPageID, + 'entity_table' => 'civicrm_contribution_page', + ); + + $premium = new CRM_Contribute_DAO_Premium(); + $premium->copyValues($params); + $premium->find(); + while ($premium->fetch()) { + //lets delete from civicrm_premiums_product + $premiumsProduct = new CRM_Contribute_DAO_PremiumsProduct(); + $premiumsProduct->premiums_id = $premium->id; + $premiumsProduct->delete(); + + //now delete premium + $premium->delete(); + } + } + + /** + * Funtion to retrieve premium product and their options + * + * @return array product and option arrays + * @static + * @access public + */ + static function getPremiumProductInfo() { + if (!self::$productInfo) { + $products = $options = array(); + + $dao = new CRM_Contribute_DAO_Product(); + $dao->is_active = 1; + $dao->find(); + + while ($dao->fetch()) { + $products[$dao->id] = $dao->name . " ( " . $dao->sku . " )"; + $opts = explode(',', $dao->options); + foreach ($opts as $k => $v) { + $ops[$k] = trim($v); + } + if ($ops[0] != '') { + $options[$dao->id] = $opts; + } + } + + self::$productInfo = array($products, $options); + } + return self::$productInfo; + } +} + diff --git a/CRM/Contribute/BAO/Query.php b/CRM/Contribute/BAO/Query.php new file mode 100644 index 0000000000..2dab01d658 --- /dev/null +++ b/CRM/Contribute/BAO/Query.php @@ -0,0 +1,872 @@ +_mode & CRM_Contact_BAO_Query::MODE_CONTRIBUTE) { + $query->_select['contribution_id'] = "civicrm_contribution.id as contribution_id"; + $query->_element['contribution_id'] = 1; + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + } + + // get financial_type + if ( CRM_Utils_Array::value( 'financial_type', $query->_returnProperties ) ) { + $query->_select['financial_type'] = "civicrm_financial_type.name as financial_type"; + $query->_element['financial_type'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['civicrm_financial_type'] = 1; + } + + // get accounting code + if (CRM_Utils_Array::value( 'accounting_code', $query->_returnProperties)) { + $query->_select['accounting_code'] = "civicrm_financial_account.accounting_code as accounting_code"; + $query->_element['accounting_code'] = 1; + $query->_tables['civicrm_accounting_code'] = 1; + $query->_tables['civicrm_financial_account'] = 1; + } + + if (CRM_Utils_Array::value('contribution_note', $query->_returnProperties)) { + $query->_select['contribution_note'] = "civicrm_note.note as contribution_note"; + $query->_element['contribution_note'] = 1; + $query->_tables['contribution_note'] = 1; + } + + if (CRM_Utils_Array::value('contribution_batch', $query->_returnProperties)) { + $query->_select['contribution_batch'] = "civicrm_batch.title as contribution_batch"; + $query->_element['contribution_batch'] = 1; + $query->_tables['contribution_batch'] = 1; + } + + // get contribution_status + if (CRM_Utils_Array::value('contribution_status_id', $query->_returnProperties)) { + $query->_select['contribution_status_id'] = "contribution_status.value as contribution_status_id"; + $query->_element['contribution_status_id'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['contribution_status'] = 1; + } + + // get contribution_status label + if (CRM_Utils_Array::value('contribution_status', $query->_returnProperties)) { + $query->_select['contribution_status'] = "contribution_status.label as contribution_status"; + $query->_element['contribution_status'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['contribution_status'] = 1; + } + + // get payment instruments + if (CRM_Utils_Array::value('payment_instrument', $query->_returnProperties)) { + $query->_select['contribution_payment_instrument'] = "payment_instrument.name as contribution_payment_instrument"; + $query->_element['contribution_payment_instrument'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['contribution_payment_instrument'] = 1; + } + + // get honor contact name + if (CRM_Utils_Array::value('honor_contact_name', $query->_returnProperties)) { + $query->_select['contribution_honor_contact_name'] = "civicrm_contact_c.display_name as contribution_honor_contact_name"; + $query->_element['contribution_honor_contact_name'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['contribution_honor_contact_name'] = 1; + } + + // get honor type label + if (CRM_Utils_Array::value('honor_type_label', $query->_returnProperties)) { + $query->_select['contribution_honor_type_label'] = "honor_type.label as contribution_honor_type_label"; + $query->_element['contribution_honor_type_label'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['contribution_honor_type_label'] = 1; + } + + // get honor contact email + if (CRM_Utils_Array::value('honor_contact_email', $query->_returnProperties)) { + $query->_select['contribution_honor_contact_email'] = "honor_email.email as contribution_honor_contact_email"; + $query->_element['contribution_honor_contact_email'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['contribution_honor_contact_email'] = 1; + } + + // get honor contact id + if (CRM_Utils_Array::value('honor_contact_id', $query->_returnProperties)) { + $query->_select['contribution_honor_contact_id'] = "civicrm_contribution.honor_contact_id as contribution_honor_contact_id"; + $query->_element['contribution_honor_contact_id'] = 1; + $query->_tables['civicrm_contribution'] = 1; + } + + + if (CRM_Utils_Array::value('check_number', $query->_returnProperties)) { + $query->_select['contribution_check_number'] = "civicrm_contribution.check_number as contribution_check_number"; + $query->_element['contribution_check_number'] = 1; + $query->_tables['civicrm_contribution'] = 1; + } + + if (CRM_Utils_Array::value('contribution_campaign_id', $query->_returnProperties)) { + $query->_select['contribution_campaign_id'] = 'civicrm_contribution.campaign_id as contribution_campaign_id'; + $query->_element['contribution_campaign_id'] = 1; + $query->_tables['civicrm_contribution'] = 1; + } + + // LCD 716 + if (CRM_Utils_Array::value('soft_credit_name', $query->_returnProperties)) { + $query->_select['contribution_soft_credit_name'] = "civicrm_contact_d.display_name as contribution_soft_credit_name"; + $query->_element['contribution_soft_credit_name'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['civicrm_contribution_soft'] = 1; + $query->_tables['civicrm_contribution_soft_contact'] = 1; + } + + if (CRM_Utils_Array::value('soft_credit_email', $query->_returnProperties)) { + $query->_select['contribution_soft_credit_email'] = "soft_email.email as contribution_soft_credit_email"; + $query->_element['contribution_soft_credit_email'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['civicrm_contribution_soft'] = 1; + $query->_tables['civicrm_contribution_soft_contact'] = 1; + $query->_tables['civicrm_contribution_soft_email'] = 1; + } + + if (CRM_Utils_Array::value('soft_credit_phone', $query->_returnProperties)) { + $query->_select['contribution_soft_credit_email'] = "soft_phone.phone as contribution_soft_credit_phone"; + $query->_element['contribution_soft_credit_phone'] = 1; + $query->_tables['civicrm_contribution'] = 1; + $query->_tables['civicrm_contribution_soft'] = 1; + $query->_tables['civicrm_contribution_soft_contact'] = 1; + $query->_tables['civicrm_contribution_soft_phone'] = 1; + } + // LCD 716 END + } + + static function where(&$query) { + $testCondition = $grouping = NULL; + foreach (array_keys($query->_params) as $id) { + if (!CRM_Utils_Array::value(0, $query->_params[$id])) { + continue; + } + if (substr($query->_params[$id][0], 0, 13) == 'contribution_' || substr($query->_params[$id][0], 0, 10) == 'financial_') { + if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) { + $query->_useDistinct = TRUE; + } + if ($query->_params[$id][0] == 'contribution_test') { + $testCondition = $id; + continue; + } + $grouping = $query->_params[$id][3]; + self::whereClauseSingle($query->_params[$id], $query); + } + } + // Only add test condition if other fields are selected + if ($grouping !== NULL && $testCondition && + // we dont want to include all tests for sql OR CRM-7827 + $query->getOperator() != 'OR' + ) { + self::whereClauseSingle($query->_params[$testCondition], $query); + } + } + + static function whereClauseSingle(&$values, &$query) { + list($name, $op, $value, $grouping, $wildcard) = $values; + + $fields = array(); + $fields = self::getFields(); + if (!empty($value)) { + $quoteValue = "\"$value\""; + } + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + + switch ($name) { + case 'contribution_date': + case 'contribution_date_low': + case 'contribution_date_low_time': + case 'contribution_date_high': + case 'contribution_date_high_time': + // process to / from date + $query->dateQueryBuilder($values, + 'civicrm_contribution', 'contribution_date', 'receive_date', 'Contribution Date' + ); + return; + + case 'contribution_amount': + case 'contribution_amount_low': + case 'contribution_amount_high': + // process min/max amount + $query->numberRangeBuilder($values, + 'civicrm_contribution', 'contribution_amount', + 'total_amount', 'Contribution Amount', + NULL + ); + return; + + case 'contribution_total_amount': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.total_amount", + $op, $value, "Money" + ); + $query->_qill[$grouping][] = ts('Contribution Total Amount %1 %2', array(1 => $op, 2 => $value)); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_thankyou_date_is_not_null': + if ($value) { + $op = "IS NOT NULL"; + $query->_qill[$grouping][] = ts('Contribution Thank-you Sent'); + } + else { + $op = "IS NULL"; + $query->_qill[$grouping][] = ts('Contribution Thank-you Not Sent'); + } + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.thankyou_date", $op); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_receipt_date_is_not_null': + if ($value) { + $op = "IS NOT NULL"; + $query->_qill[$grouping][] = ts('Contribution Receipt Sent'); + } + else { + $op = "IS NULL"; + $query->_qill[$grouping][] = ts('Contribution Receipt Not Sent'); + } + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.receipt_date", $op); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'financial_type_id': + case 'financial_type': + $cType = $value; + $types = CRM_Contribute_PseudoConstant::financialType( ); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause( "civicrm_contribution.financial_type_id", + $op, $value, "Integer" + ); + $query->_qill[$grouping ][] = ts( 'Financial Type - %1', array( 1 => $types[$cType] ) ); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_page_id': + $cPage = $value; + $pages = CRM_Contribute_PseudoConstant::contributionPage(); + $query->_where[$grouping][] = "civicrm_contribution.contribution_page_id = $cPage"; + $query->_qill[$grouping][] = ts('Contribution Page - %1', array(1 => $pages[$cPage])); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_pcp_made_through_id': + $pcPage = $value; + $pcpages = CRM_Contribute_PseudoConstant::pcPage(); + $query->_where[$grouping][] = "civicrm_contribution_soft.pcp_id = $pcPage"; + $query->_qill[$grouping][] = ts('Personal Campaign Page - %1', array(1 => $pcpages[$pcPage])); + $query->_tables['civicrm_contribution_soft'] = $query->_whereTables['civicrm_contribution_soft'] = 1; + return; + + case 'contribution_payment_instrument_id': + case 'contribution_payment_instrument': + $pi = $value; + $pis = CRM_Contribute_PseudoConstant::paymentInstrument(); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.payment_instrument_id", + $op, $value, "Integer" + ); + + $query->_qill[$grouping][] = ts('Paid By - %1', array(1 => $pis[$pi])); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_in_honor_of': + $name = trim($value); + $newName = str_replace(',', " ", $name); + $pieces = explode(' ', $newName); + foreach ($pieces as $piece) { + $value = $strtolower(CRM_Core_DAO::escapeString(trim($piece))); + $value = "'%$value%'"; + $sub[] = " ( contact_b.sort_name LIKE $value )"; + } + + $query->_where[$grouping][] = ' ( ' . implode(' OR ', $sub) . ' ) '; + $query->_qill[$grouping][] = ts('Honor name like - \'%1\'', array(1 => $name)); + $query->_tables['civicrm_contact_b'] = $query->_whereTables['civicrm_contact_b'] = 1; + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_status': + case 'contribution_status_id': + if (is_array($value)) { + foreach ($value as $k => $v) { + if ($v) { + $val[$k] = $k; + } + } + + $status = implode(',', $val); + + if (count($val) > 1) { + $op = 'IN'; + $status = "({$status})"; + } + } + else { + $op = '='; + $status = $value; + } + + $statusValues = CRM_Core_OptionGroup::values("contribution_status"); + + $names = array(); + if (isset($val) && + is_array($val) + ) { + foreach ($val as $id => $dontCare) { + $names[] = $statusValues[$id]; + } + } + else { + $names[] = $statusValues[$value]; + } + + $query->_qill[$grouping][] = ts('Contribution Status %1', array(1 => $op)) . ' ' . implode(' ' . ts('or') . ' ', $names); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.contribution_status_id", + $op, + $status, + "Integer" + ); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_source': + $value = $strtolower(CRM_Core_DAO::escapeString($value)); + if ($wildcard) { + $value = "%$value%"; + $op = 'LIKE'; + } + $wc = ($op != 'LIKE') ? "LOWER(civicrm_contribution.source)" : "civicrm_contribution.source"; + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($wc, $op, $value, "String"); + $query->_qill[$grouping][] = ts('Contribution Source %1 %2', array(1 => $op, 2 => $quoteValue)); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_trxn_id': + case 'contribution_transaction_id': + $wc = ($op != 'LIKE') ? "LOWER(civicrm_contribution.trxn_id)" : "civicrm_contribution.trxn_id"; + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($wc, $op, $value, "String"); + $query->_qill[$grouping][] = ts('Transaction ID %1 %2', array(1 => $op, 2 => $quoteValue)); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_check_number': + $wc = ($op != 'LIKE') ? "LOWER(civicrm_contribution.check_number)" : "civicrm_contribution.check_number"; + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($wc, $op, $value, "String"); + $query->_qill[$grouping][] = ts('Check Number %1 %2', array(1 => $op, 2 => $quoteValue)); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_is_test': + case 'contribution_test': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.is_test", $op, $value, "Boolean"); + if ($value) { + $query->_qill[$grouping][] = ts("Only Display Test Contributions"); + } + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_is_pay_later': + case 'contribution_pay_later': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.is_pay_later", $op, $value, "Boolean"); + if ($value) { + $query->_qill[$grouping][] = ts("Find Pay Later Contributions"); + } + else { + $query->_qill[$grouping][] = ts("Exclude Pay Later Contributions"); + } + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_recurring': + if ($value) { + $query->_where[$grouping][] = "civicrm_contribution.contribution_recur_id IS NOT NULL"; + $query->_qill[$grouping][] = ts("Find Recurring Contributions"); + $query->_tables['civicrm_contribution_recur'] = $query->_whereTables['civicrm_contribution_recur'] = 1; + } + else { + $query->_where[$grouping][] = "civicrm_contribution.contribution_recur_id IS NULL"; + $query->_qill[$grouping][] = ts("Exclude Recurring Contributions"); + } + return; + + case 'contribution_recur_id': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.contribution_recur_id", + $op, $value, "Integer" + ); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_id': + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.id", $op, $value, "Integer"); + $query->_qill[$grouping][] = ts('Contribution ID %1 %2', array(1 => $op, 2 => $quoteValue)); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_note': + $value = $strtolower(CRM_Core_DAO::escapeString($value)); + if ($wildcard) { + $value = "%$value%"; + $op = 'LIKE'; + } + $wc = ($op != 'LIKE') ? "LOWER(civicrm_note.note)" : "civicrm_note.note"; + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($wc, $op, $value, "String"); + $query->_qill[$grouping][] = ts('Contribution Note %1 %2', array(1 => $op, 2 => $quoteValue)); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = $query->_whereTables['contribution_note'] = 1; + return; + + case 'contribution_membership_id': + $query->_where[$grouping][] = " civicrm_membership.id $op $value"; + $query->_tables['contribution_membership'] = $query->_whereTables['contribution_membership'] = 1; + + return; + + case 'contribution_participant_id': + $query->_where[$grouping][] = " civicrm_participant.id $op $value"; + $query->_tables['contribution_participant'] = $query->_whereTables['contribution_participant'] = 1; + return; + + case 'contribution_pcp_display_in_roll': + $query->_where[$grouping][] = " civicrm_contribution_soft.pcp_display_in_roll $op '$value'"; + if ($value) { + $query->_qill[$grouping][] = ts("Personal Campaign Page Honor Roll"); + } + else { + $query->_qill[$grouping][] = ts("NOT Personal Campaign Page Honor Roll"); + } + $query->_tables['civicrm_contribution_soft'] = $query->_whereTables['civicrm_contribution_soft'] = 1; + return; + + // Supporting search for currency type -- CRM-4711 + + case 'contribution_currency_type': + $currencySymbol = CRM_Core_PseudoConstant::currencySymbols('name'); + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution.currency", + $op, $currencySymbol[$value], "String" + ); + $query->_qill[$grouping][] = ts('Currency Type - %1', array(1 => $currencySymbol[$value])); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + return; + + case 'contribution_campaign_id': + $campParams = array( + 'op' => $op, + 'campaign' => $value, + 'grouping' => $grouping, + 'tableName' => 'civicrm_contribution', + ); + CRM_Campaign_BAO_Query::componentSearchClause($campParams, $query); + return; + + case 'contribution_batch_id': + $batches = CRM_Batch_BAO_Batch::getBatches(); + $query->_where[$grouping][] = " civicrm_entity_batch.batch_id $op $value"; + $query->_qill[$grouping][] = ts('Batch Name %1 %2', array(1 => $op, 2 => $batches[$value])); + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + $query->_tables['contribution_batch'] = $query->_whereTables['contribution_batch'] = 1; + return; + + default: + //all other elements are handle in this case + $fldName = substr($name, 13); + $whereTable = $fields[$fldName]; + $value = trim($value); + + //contribution fields (decimal fields) which don't require a quote in where clause. + $moneyFields = array('non_deductible_amount', 'fee_amount', 'net_amount'); + //date fields + $dateFields = array('receive_date', 'cancel_date', 'receipt_date', 'thankyou_date', 'fulfilled_date'); + + if (in_array($fldName, $dateFields)) { + $dataType = "Date"; + } + elseif (in_array($fldName, $moneyFields)) { + $dataType = "Money"; + } + else { + $dataType = "String"; + } + + $wc = ($op != 'LIKE' && $dataType != 'Date') ? "LOWER($whereTable[where])" : "$whereTable[where]"; + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($wc, $op, $value, $dataType); + $query->_qill[$grouping][] = "$whereTable[title] $op $quoteValue"; + list($tableName, $fieldName) = explode('.', $whereTable['where'], 2); + $query->_tables[$tableName] = $query->_whereTables[$tableName] = 1; + if ($tableName == 'civicrm_contribution_product') { + $query->_tables['civicrm_product'] = $query->_whereTables['civicrm_product'] = 1; + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + } + else { + $query->_tables['civicrm_contribution'] = $query->_whereTables['civicrm_contribution'] = 1; + } + } + } + + static function from($name, $mode, $side) { + $from = NULL; + switch ($name) { + case 'civicrm_contribution': + $from = " $side JOIN civicrm_contribution ON civicrm_contribution.contact_id = contact_a.id "; + break; + + case 'civicrm_contribution_recur': + $from = " $side JOIN civicrm_contribution_recur ON civicrm_contribution.contribution_recur_id = civicrm_contribution_recur.id "; + break; + + case 'civicrm_financial_type': + if ($mode & CRM_Contact_BAO_Query::MODE_CONTRIBUTE) { + $from = " INNER JOIN civicrm_financial_type ON civicrm_contribution.financial_type_id = civicrm_financial_type.id "; + } + else { + $from = " $side JOIN civicrm_financial_type ON civicrm_contribution.financial_type_id = civicrm_financial_type.id "; + } + break; + + case 'civicrm_accounting_code': + $from = " $side JOIN civicrm_entity_financial_account ON civicrm_entity_financial_account.entity_id = civicrm_contribution.financial_type_id AND civicrm_entity_financial_account.entity_table = 'civicrm_financial_type' "; + $from .= " INNER JOIN civicrm_financial_account ON civicrm_financial_account.id = civicrm_entity_financial_account.financial_account_id "; + $from .= " INNER JOIN civicrm_option_value cov ON cov.value = civicrm_entity_financial_account.account_relationship AND cov.name = 'Income Account is' "; + $from .= " INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id AND cog.name = 'account_relationship' "; + break; + + case 'civicrm_contribution_page': + $from = " $side JOIN civicrm_contribution_page ON civicrm_contribution.contribution_page ON civicrm_contribution.contribution_page.id"; + break; + + case 'civicrm_product': + $from = " $side JOIN civicrm_contribution_product ON civicrm_contribution_product.contribution_id = civicrm_contribution.id"; + $from .= " $side JOIN civicrm_product ON civicrm_contribution_product.product_id =civicrm_product.id "; + break; + + case 'contribution_payment_instrument': + $from = " $side JOIN civicrm_option_group option_group_payment_instrument ON ( option_group_payment_instrument.name = 'payment_instrument')"; + $from .= " $side JOIN civicrm_option_value payment_instrument ON (civicrm_contribution.payment_instrument_id = payment_instrument.value + AND option_group_payment_instrument.id = payment_instrument.option_group_id ) "; + break; + + case 'civicrm_contact_b': + $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_contribution.honor_contact_id = contact_b.id )"; + break; + + case 'contribution_status': + $from = " $side JOIN civicrm_option_group option_group_contribution_status ON (option_group_contribution_status.name = 'contribution_status')"; + $from .= " $side JOIN civicrm_option_value contribution_status ON (civicrm_contribution.contribution_status_id = contribution_status.value + AND option_group_contribution_status.id = contribution_status.option_group_id ) "; + break; + + case 'contribution_note': + $from .= " $side JOIN civicrm_note ON ( civicrm_note.entity_table = 'civicrm_contribution' AND + civicrm_contribution.id = civicrm_note.entity_id )"; + break; + + case 'contribution_honor_contact_name': + $from .= " $side JOIN civicrm_contact civicrm_contact_c ON (civicrm_contribution.honor_contact_id = civicrm_contact_c.id )"; + break; + + case 'contribution_honor_contact_email': + $from .= " $side JOIN civicrm_email as honor_email ON (civicrm_contribution.honor_contact_id = honor_email.contact_id AND honor_email.is_primary = 1 )"; + break; + + case 'contribution_honor_type_label': + $from = " $side JOIN civicrm_option_group option_group_honor_type ON ( option_group_honor_type.name = 'honor_type')"; + $from .= " $side JOIN civicrm_option_value honor_type ON (civicrm_contribution.honor_type_id = honor_type.value + AND option_group_honor_type.id = honor_type.option_group_id ) "; + break; + + case 'contribution_membership': + $from = " $side JOIN civicrm_membership_payment ON civicrm_membership_payment.contribution_id = civicrm_contribution.id"; + $from .= " $side JOIN civicrm_membership ON civicrm_membership_payment.membership_id = civicrm_membership.id "; + break; + + case 'contribution_participant': + $from = " $side JOIN civicrm_participant_payment ON civicrm_participant_payment.contribution_id = civicrm_contribution.id"; + $from .= " $side JOIN civicrm_participant ON civicrm_participant_payment.participant_id = civicrm_participant.id "; + break; + + case 'civicrm_contribution_soft': + $from = " $side JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id = civicrm_contribution.id"; + break; + + case 'civicrm_contribution_soft_contact': + $from .= " $side JOIN civicrm_contact civicrm_contact_d ON (civicrm_contribution_soft.contact_id = civicrm_contact_d.id )"; + break; + + case 'civicrm_contribution_soft_email': + $from .= " $side JOIN civicrm_email as soft_email ON (civicrm_contact_d.id = soft_email.contact_id )"; + break; + + case 'civicrm_contribution_soft_phone': + $from .= " $side JOIN civicrm_phone as soft_phone ON (civicrm_contact_d.id = soft_phone.contact_id )"; + break; + + case 'contribution_batch': + $from .= " $side JOIN civicrm_entity_batch ON ( civicrm_entity_batch.entity_table = 'civicrm_contribution' AND + civicrm_contribution.id = civicrm_entity_batch.entity_id )"; + $from .= " $side JOIN civicrm_batch ON civicrm_entity_batch.batch_id = civicrm_batch.id"; + break; + } + return $from; + } + + static function defaultReturnProperties($mode, $includeCustomFields = TRUE) { + $properties = NULL; + if ($mode & CRM_Contact_BAO_Query::MODE_CONTRIBUTE) { + $properties = array( + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'sort_name' => 1, + 'display_name' => 1, + 'financial_type' => 1, + 'contribution_source' => 1, + 'receive_date' => 1, + 'thankyou_date' => 1, + 'cancel_date' => 1, + 'total_amount' => 1, + 'accounting_code' => 1, + 'payment_instrument' => 1, + 'check_number' => 1, + 'non_deductible_amount' => 1, + 'fee_amount' => 1, + 'net_amount' => 1, + 'trxn_id' => 1, + 'invoice_id' => 1, + 'currency' => 1, + 'cancel_reason' => 1, + 'receipt_date' => 1, + 'product_name' => 1, + 'sku' => 1, + 'product_option' => 1, + 'fulfilled_date' => 1, + 'contribution_start_date' => 1, + 'contribution_end_date' => 1, + 'is_test' => 1, + 'is_pay_later' => 1, + 'contribution_status' => 1, + 'contribution_status_id' => 1, + 'contribution_recur_id' => 1, + 'amount_level' => 1, + 'contribution_note' => 1, + 'contribution_batch' => 1, + 'contribution_campaign_id' => 1 + ); + + if ($includeCustomFields) { + // also get all the custom contribution properties + $fields = CRM_Core_BAO_CustomField::getFieldsForImport('Contribution'); + if (!empty($fields)) { + foreach ($fields as $name => $dontCare) { + $properties[$name] = 1; + } + } + } + } + return $properties; + } + + /** + * add all the elements shared between contribute search and advnaced search + * + * @access public + * + * @return void + * @static + */ + static function buildSearchForm(&$form) { + + // Added contribution source + $form->addElement('text', 'contribution_source', ts('Contribution Source'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution', 'source')); + + CRM_Core_Form_Date::buildDateRange($form, 'contribution_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE); + + $form->add('text', 'contribution_amount_low', ts('From'), array('size' => 8, 'maxlength' => 8)); + $form->addRule('contribution_amount_low', ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('9.99', ' '))), 'money'); + + $form->add('text', 'contribution_amount_high', ts('To'), array('size' => 8, 'maxlength' => 8)); + $form->addRule('contribution_amount_high', ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('99.99', ' '))), 'money'); + + // Adding select option for curreny type -- CRM-4711 + $form->add('select', 'contribution_currency_type', + ts('Currency Type'), + array( + '' => ts('- any -')) + + CRM_Core_PseudoConstant::currencySymbols('name') + ); + + $form->add('select', 'financial_type_id', + ts('Financial Type'), + array( + '' => ts('- any -')) + + CRM_Contribute_PseudoConstant::financialType( ) + ); + + $form->add('select', 'contribution_page_id', + ts('Contribution Page'), + array( + '' => ts('- any -')) + + CRM_Contribute_PseudoConstant::contributionPage() + ); + + + $form->add('select', 'contribution_payment_instrument_id', + ts('Payment Instrument'), + array( + '' => ts('- any -')) + + CRM_Contribute_PseudoConstant::paymentInstrument() + ); + + $form->add('select', 'contribution_pcp_made_through_id', + ts('Personal Campaign Page'), + array( + '' => ts('- any -')) + + CRM_Contribute_PseudoConstant::pcPage() + ); + + $status = array(); + + $statusValues = CRM_Core_OptionGroup::values("contribution_status"); + // Remove status values that are only used for recurring contributions or pledges (In Progress, Overdue). + unset($statusValues['5'], $statusValues['6']); + + foreach ($statusValues as $key => $val) { + $status[] = $form->createElement('advcheckbox', $key, NULL, $val); + } + + $form->addGroup($status, 'contribution_status_id', ts('Contribution Status')); + + // Add fields for thank you and receipt + $form->addYesNo('contribution_thankyou_date_is_not_null', ts('Thank-you sent?')); + $form->addYesNo('contribution_receipt_date_is_not_null', ts('Receipt sent?')); + + // Add fields for honor search + $form->addElement('text', 'contribution_in_honor_of', ts("In Honor Of")); + + $form->addYesNo('contribution_pay_later', ts('Contribution is Pay Later?')); + $form->addYesNo('contribution_recurring', ts('Contribution is Recurring?')); + $form->addYesNo('contribution_test', ts('Contribution is a Test?')); + + // Add field for transaction ID search + $form->addElement('text', 'contribution_transaction_id', ts("Transaction ID")); + + $form->addElement('text', 'contribution_check_number', ts('Check Number')); + + // Add field for pcp display in roll search + $form->addYesNo('contribution_pcp_display_in_roll', ts('Personal Campaign Page Honor Roll?')); + + // Add all the custom searchable fields + $contribution = array('Contribution'); + $groupDetails = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, TRUE, $contribution); + if ($groupDetails) { + $form->assign('contributeGroupTree', $groupDetails); + foreach ($groupDetails as $group) { + foreach ($group['fields'] as $field) { + $fieldId = $field['id']; + $elementName = 'custom_' . $fieldId; + CRM_Core_BAO_CustomField::addQuickFormElement($form, + $elementName, + $fieldId, + FALSE, FALSE, TRUE + ); + } + } + } + + CRM_Campaign_BAO_Campaign::addCampaignInComponentSearch($form, 'contribution_campaign_id'); + + // Add batch select + $batches = CRM_Batch_BAO_Batch::getBatches(); + + if ( !empty( $batches ) ) { + $form->add('select', 'contribution_batch_id', + ts('Batch Name'), + array( '' => ts('- any -')) + $batches ); + } + + $form->assign('validCiviContribute', TRUE); + $form->setDefaults(array('contribution_test' => 0)); + } + + static function addShowHide(&$showHide) { + $showHide->addHide('contributeForm'); + $showHide->addShow('contributeForm_show'); + } + + static function searchAction(&$row, $id) { + } + + static function tableNames(&$tables) { + // Add contribution table + if (CRM_Utils_Array::value('civicrm_product', $tables)) { + $tables = array_merge(array('civicrm_contribution' => 1), $tables); + } + + if (CRM_Utils_Array::value('civicrm_contribution_product', $tables) && + !CRM_Utils_Array::value('civicrm_product', $tables)) { + $tables['civicrm_product'] = 1; + } + } +} + diff --git a/CRM/Contribute/BAO/Widget.php b/CRM/Contribute/BAO/Widget.php new file mode 100644 index 0000000000..ac313dfdb9 --- /dev/null +++ b/CRM/Contribute/BAO/Widget.php @@ -0,0 +1,199 @@ +defaultCurrencySymbol; + + if (empty($contributionPageID) || + CRM_Utils_Type::validate($contributionPageID, 'Integer') == NULL + ) { + $data['is_error'] = TRUE; + CRM_Core_Error::debug_log_message("$contributionPageID is not set"); + return $data; + } + + $widget = new CRM_Contribute_DAO_Widget(); + $widget->contribution_page_id = $contributionPageID; + if (!$widget->find(TRUE)) { + $data['is_error'] = TRUE; + CRM_Core_Error::debug_log_message("$contributionPageID is not found"); + return $data; + } + + $data['is_error'] = FALSE; + if (!$widget->is_active) { + $data['is_active'] = FALSE; + } + + $data['is_active'] = TRUE; + $data['title'] = $widget->title; + $data['logo'] = $widget->url_logo; + $data['button_title'] = $widget->button_title; + $data['about'] = $widget->about; + + $query = " + SELECT count( id ) as count, + sum( total_amount) as amount + FROM civicrm_contribution + WHERE is_test = 0 + AND contribution_status_id = 1 + AND contribution_page_id = %1"; + $params = array(1 => array($contributionPageID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + if ($dao->fetch()) { + $data['num_donors'] = (int)$dao->count; + $data['money_raised'] = (int)$dao->amount; + } + else { + $data['num_donors'] = $data['money_raised'] = $data->money_raised = 0; + } + + $query = " + SELECT goal_amount, start_date, end_date, is_active + FROM civicrm_contribution_page + WHERE id = %1"; + $params = array(1 => array($contributionPageID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + $data['campaign_start'] = ''; + $startDate = NULL; + if ($dao->fetch()) { + $data['money_target'] = (int)$dao->goal_amount; + + // conditions that needs to be handled + // 1. Campaign is not active - no text + // 2. Campaign start date greater than today - show start date + // 3. Campaign end date is set and greater than today - show end date + // 4. If no start and end date or no end date and start date greater than today, then it's ongoing + if ($dao->is_active) { + $data['campaign_start'] = ts('Campaign is ongoing'); + + // check for time being between start and end date + $now = time(); + if ($dao->start_date) { + $startDate = CRM_Utils_Date::unixTime($dao->start_date); + if ($startDate && + $startDate >= $now + ) { + $data['is_active'] = FALSE; + $data['campaign_start'] = ts('Campaign starts on %1', array( + 1 => CRM_Utils_Date::customFormat($dao->start_date, + $config->dateformatFull + ))); + } + } + + if ($dao->end_date) { + $endDate = CRM_Utils_Date::unixTime($dao->end_date); + if ($endDate && + $endDate < $now + ) { + $data['is_active'] = FALSE; + $data['campaign_start'] = ts('Campaign ended on %1', array( + 1 => CRM_Utils_Date::customFormat($dao->end_date, + $config->dateformatFull + ))); + } + elseif ($startDate >= $now) { + $data['campaign_start'] = ts('Campaign starts on %1', array( + 1 => CRM_Utils_Date::customFormat($dao->start_date, + $config->dateformatFull + ))); + } + else { + $data['campaign_start'] = ts('Campaign ends on %1', array( + 1 => CRM_Utils_Date::customFormat($dao->end_date, + $config->dateformatFull + ))); + } + } + } + else { + $data['is_active'] = FALSE; + } + } + else { + $data['is_active'] = FALSE; + } + + $data['money_raised_percentage'] = 0; + if ($data['money_target'] > 0) { + $percent = $data['money_raised'] / $data['money_target']; + $data['money_raised_percentage'] = (round($percent, 2)) * 100 . "%"; + $data['money_target_display'] = CRM_Utils_Money::format($data['money_target']); + $data['money_raised'] = ts('Raised %1 of %2', array(1 => CRM_Utils_Money::format($data['money_raised']), 2 => $data['money_target_display'])); + } + else { + $data['money_raised'] = ts('Raised %1', array(1 => CRM_Utils_Money::format($data['money_raised']))); + } + + $data['money_low'] = 0; + $data['num_donors'] = $data['num_donors'] . " " . ts('Donors'); + $data['home_url'] = "" . ts('Learn more.') . ""; + + // if is_active is false, show this link and hide the contribute button + $data['homepage_link'] = $widget->url_homepage; + + $data['colors'] = array(); + + $data['colors']["title"] = $widget->color_title; + $data['colors']["button"] = $widget->color_button; + $data['colors']["bar"] = $widget->color_bar; + $data['colors']["main_text"] = $widget->color_main_text; + $data['colors']["main"] = $widget->color_main; + $data['colors']["main_bg"] = $widget->color_main_bg; + $data['colors']["bg"] = $widget->color_bg; + $data['colors']["about_link"] = $widget->color_about_link; + + return $data; + } +} + diff --git a/CRM/Contribute/Config.php b/CRM/Contribute/Config.php new file mode 100644 index 0000000000..fce72b08f6 --- /dev/null +++ b/CRM/Contribute/Config.php @@ -0,0 +1,40 @@ +_stateMachine = new CRM_Contribute_StateMachine_Contribution($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $uploadNames = $this->get('uploadNames'); + if (!empty($uploadNames)) { + $config = CRM_Core_Config::singleton(); + $this->addActions($config->customFileUploadDir, $uploadNames); + } + else { + $this->addActions(); + } + } +} + diff --git a/CRM/Contribute/Controller/ContributionPage.php b/CRM/Contribute/Controller/ContributionPage.php new file mode 100644 index 0000000000..11e0ac2edf --- /dev/null +++ b/CRM/Contribute/Controller/ContributionPage.php @@ -0,0 +1,66 @@ +_stateMachine = new CRM_Contribute_StateMachine_ContributionPage($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $this->addActions(); + } +} + diff --git a/CRM/Contribute/Controller/Search.php b/CRM/Contribute/Controller/Search.php new file mode 100644 index 0000000000..ee6dce0925 --- /dev/null +++ b/CRM/Contribute/Controller/Search.php @@ -0,0 +1,66 @@ +_stateMachine = new CRM_Contribute_StateMachine_Search($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $config = CRM_Core_Config::singleton(); + $this->addActions(); + } +} + diff --git a/CRM/Contribute/Form.php b/CRM/Contribute/Form.php new file mode 100644 index 0000000000..3e359c836d --- /dev/null +++ b/CRM/Contribute/Form.php @@ -0,0 +1,138 @@ +_id = $this->get('id'); + $this->_BAOName = $this->get('BAOName'); + } + + /** + * This function sets the default values for the form. MobileProvider that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + $defaults = array(); + $params = array(); + + if (isset($this->_id)) { + $params = array('id' => $this->_id); + if (!empty( $this->_BAOName)) { + require_once (str_replace('_', DIRECTORY_SEPARATOR, $this->_BAOName) . ".php"); + eval($this->_BAOName . '::retrieve( $params, $defaults );'); + } + } + if ($this->_action == CRM_Core_Action::DELETE && CRM_Utils_Array::value('name', $defaults)) { + $this->assign('delName', $defaults['name']); + } + elseif ($this->_action == CRM_Core_Action::ADD) { + $condition = " AND is_default = 1"; + $values = CRM_Core_OptionGroup::values('financial_account_type', false, false, false, $condition); + $defaults['financial_account_type_id'] = array_keys($values); + $defaults['is_active'] = 1; + + } + elseif ($this->_action & CRM_Core_Action::UPDATE) { + if (CRM_Utils_Array::value('contact_id', $defaults) || CRM_Utils_Array::value('created_id', $defaults)) { + $contactID = CRM_Utils_Array::value('created_id', $defaults) ? $defaults['created_id'] : $defaults['contact_id']; + $this->assign('created_id', $contactID); + $this->assign('organisationId', $contactID); + } + + if ($parentId = CRM_Utils_Array::value('parent_id', $defaults)) { + $this->assign('parentId', $parentId); + } + } + return $defaults; + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + if ($this->_action & CRM_Core_Action::DELETE) { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + } +} + diff --git a/CRM/Contribute/Form/AbstractEditPayment.php b/CRM/Contribute/Form/AbstractEditPayment.php new file mode 100644 index 0000000000..6c0cbf7597 --- /dev/null +++ b/CRM/Contribute/Form/AbstractEditPayment.php @@ -0,0 +1,547 @@ + $id); + CRM_Contribute_BAO_Contribution::getValues($params, $values, $ids); + + //Check if this is an online transaction (financial_trxn.payment_processor_id NOT NULL) + $this->_online = FALSE; + $fids = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($id); + if (CRM_Utils_Array::value('financialTrxnId', $fids)) { + $this->_online = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $fids['financialTrxnId'], 'payment_processor_id'); + } + + // Also don't allow user to update some fields for recurring contributions. + if (!$this->_online) { + $this->_online = CRM_Utils_Array::value('contribution_recur_id', $values); + } + + $this->assign('isOnline', $this->_online ? TRUE : FALSE); + + //unset the honor type id:when delete the honor_contact_id + //and edit the contribution, honoree infomation pane open + //since honor_type_id is present + if (!CRM_Utils_Array::value('honor_contact_id', $values)) { + unset($values['honor_type_id']); + } + //to get note id + $daoNote = new CRM_Core_BAO_Note(); + $daoNote->entity_table = 'civicrm_contribution'; + $daoNote->entity_id = $id; + if ($daoNote->find(TRUE)) { + $this->_noteID = $daoNote->id; + $values['note'] = $daoNote->note; + } + $this->_contributionType = $values['financial_type_id']; + + $csParams = array('contribution_id' => $id); + $softCredit = CRM_Contribute_BAO_Contribution::getSoftContribution($csParams, TRUE); + + if (CRM_Utils_Array::value('soft_credit_to', $softCredit)) { + $softCredit['sort_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $softCredit['soft_credit_to'], 'sort_name' + ); + } + $values['soft_credit_to'] = CRM_Utils_Array::value('sort_name', $softCredit); + $values['softID'] = CRM_Utils_Array::value('soft_credit_id', $softCredit); + $values['soft_contact_id'] = CRM_Utils_Array::value('soft_credit_to', $softCredit); + + if (CRM_Utils_Array::value('pcp_id', $softCredit)) { + $pcpId = CRM_Utils_Array::value('pcp_id', $softCredit); + $pcpTitle = CRM_Core_DAO::getFieldValue('CRM_PCP_DAO_PCP', $pcpId, 'title'); + $contributionPageTitle = CRM_PCP_BAO_PCP::getPcpPageTitle($pcpId, 'contribute'); + $values['pcp_made_through'] = CRM_Utils_Array::value('sort_name', $softCredit) . " :: " . $pcpTitle . " :: " . $contributionPageTitle; + $values['pcp_made_through_id'] = CRM_Utils_Array::value('pcp_id', $softCredit); + $values['pcp_display_in_roll'] = CRM_Utils_Array::value('pcp_display_in_roll', $softCredit); + $values['pcp_roll_nickname'] = CRM_Utils_Array::value('pcp_roll_nickname', $softCredit); + $values['pcp_personal_note'] = CRM_Utils_Array::value('pcp_personal_note', $softCredit); + } + } + + /** + * @param string $type eg 'Contribution' + * @param string $subType + * @param int $entityId + */ + public function applyCustomData($type, $subType, $entityId) { + $this->set('type', $type); + $this->set('subType', $subType); + $this->set('entityId', $entityId); + + CRM_Custom_Form_CustomData::preProcess($this, NULL, $subType, 1, $type, $entityId); + CRM_Custom_Form_CustomData::buildQuickForm($this); + CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + public function assignPremiumProduct($id) { //to get Premium id + $sql = " +SELECT * +FROM civicrm_contribution_product +WHERE contribution_id = {$id} +"; + $dao = CRM_Core_DAO::executeQuery($sql, + CRM_Core_DAO::$_nullArray + ); + if ($dao->fetch()) { + $this->_premiumID = $dao->id; + $this->_productDAO = $dao; + } + $dao->free(); + } + + /** + * This function process contribution related objects. + */ + protected function updateRelatedComponent($contributionId, $statusId, $previousStatusId = NULL) { + $statusMsg = NULL; + if (!$contributionId || !$statusId) { + return $statusMsg; + } + + $params = array( + 'contribution_id' => $contributionId, + 'contribution_status_id' => $statusId, + 'previous_contribution_status_id' => $previousStatusId, + ); + + $updateResult = CRM_Contribute_BAO_Contribution::transitionComponents($params); + + if (!is_array($updateResult) || + !($updatedComponents = CRM_Utils_Array::value('updatedComponents', $updateResult)) || + !is_array($updatedComponents) || + empty($updatedComponents) + ) { + return $statusMsg; + } + + // get the user display name. + $sql = " + SELECT display_name as displayName + FROM civicrm_contact +LEFT JOIN civicrm_contribution on (civicrm_contribution.contact_id = civicrm_contact.id ) + WHERE civicrm_contribution.id = {$contributionId}"; + $userDisplayName = CRM_Core_DAO::singleValueQuery($sql); + + // get the status message for user. + foreach ($updatedComponents as $componentName => $updatedStatusId) { + + if ($componentName == 'CiviMember') { + $updatedStatusName = CRM_Utils_Array::value($updatedStatusId, + CRM_Member_PseudoConstant::membershipStatus() + ); + if ($updatedStatusName == 'Cancelled') { + $statusMsg .= "
    " . ts("Membership for %1 has been Cancelled.", array(1 => $userDisplayName)); + } + elseif ($updatedStatusName == 'Expired') { + $statusMsg .= "
    " . ts("Membership for %1 has been Expired.", array(1 => $userDisplayName)); + } + elseif ($endDate = CRM_Utils_Array::value('membership_end_date', $updateResult)) { + $statusMsg .= "
    " . ts("Membership for %1 has been updated. The membership End Date is %2.", + array( + 1 => $userDisplayName, + 2 => $endDate + ) + ); + } + } + + if ($componentName == 'CiviEvent') { + $updatedStatusName = CRM_Utils_Array::value($updatedStatusId, + CRM_Event_PseudoConstant::participantStatus() + ); + if ($updatedStatusName == 'Cancelled') { + $statusMsg .= "
    " . ts("Event Registration for %1 has been Cancelled.", array(1 => $userDisplayName)); + } + elseif ($updatedStatusName == 'Registered') { + $statusMsg .= "
    " . ts("Event Registration for %1 has been updated.", array(1 => $userDisplayName)); + } + } + + if ($componentName == 'CiviPledge') { + $updatedStatusName = CRM_Utils_Array::value($updatedStatusId, + CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name') + ); + if ($updatedStatusName == 'Cancelled') { + $statusMsg .= "
    " . ts("Pledge Payment for %1 has been Cancelled.", array(1 => $userDisplayName)); + } + elseif ($updatedStatusName == 'Failed') { + $statusMsg .= "
    " . ts("Pledge Payment for %1 has been Failed.", array(1 => $userDisplayName)); + } + elseif ($updatedStatusName == 'Completed') { + $statusMsg .= "
    " . ts("Pledge Payment for %1 has been updated.", array(1 => $userDisplayName)); + } + } + } + + return $statusMsg; + } + + /** + * @return array (0 => array(int $ppId => string $label), 1 => array(...payproc details...)) + */ + public function getValidProcessorsAndAssignFutureStartDate() { + $validProcessors = array(); + $processors = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE, "billing_mode IN ( 1, 3 )"); + + foreach ($processors as $ppID => $label) { + $paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($ppID, $this->_mode); + // at this stage only Authorize.net has been tested to support future start dates so if it's enabled let the template know + // to show receive date + $processorsSupportingFutureStartDate = array('AuthNet'); + if (in_array($paymentProcessor['payment_processor_type'], $processorsSupportingFutureStartDate)) { + $this->assign('processorSupportsFutureStartDate', TRUE); + } + if ($paymentProcessor['payment_processor_type'] == 'PayPal' && !$paymentProcessor['user_name']) { + continue; + } + elseif ($paymentProcessor['payment_processor_type'] == 'Dummy' && $this->_mode == 'live') { + continue; + } + else { + $paymentObject = CRM_Core_Payment::singleton($this->_mode, $paymentProcessor, $this); + $error = $paymentObject->checkConfig(); + if (empty($error)) { + $validProcessors[$ppID] = $label; + } + $paymentObject = NULL; + } + } + if (empty($validProcessors)) { + CRM_Core_Error::fatal(ts('You will need to configure the %1 settings for your Payment Processor before you can submit credit card transactions.', array(1 => $this->_mode))); + } + else { + return array($validProcessors, $paymentProcessor); + } + } + + /** + * Assign billing type id to bltID + * + * @return void + */ + public function assignBillingType() { + $locationTypes = CRM_Core_PseudoConstant::locationType(); + $this->_bltID = array_search('Billing', $locationTypes); + if (!$this->_bltID) { + CRM_Core_Error::fatal(ts('Please set a location type of %1', array(1 => 'Billing'))); + } + $this->set('bltID', $this->_bltID); + $this->assign('bltID', $this->_bltID); + } + + /** + * Assign $this->processors, $this->recurPaymentProcessors, and related Smarty variables + */ + public function assignProcessors() { + //ensure that processor has a valid config + //only valid processors get display to user + if ($this->_mode) { + list($this->_processors, $paymentProcessor) = $this->getValidProcessorsAndAssignFutureStartDate(); + + //get the valid recurring processors. + $recurring = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE, 'is_recur = 1'); + $this->_recurPaymentProcessors = array_intersect_assoc($this->_processors, $recurring); + } + $this->assign('recurringPaymentProcessorIds', + empty($this->_recurPaymentProcessors) ? '' : implode(',', array_keys($this->_recurPaymentProcessors)) + ); + + // this required to show billing block + $this->assign_by_ref('paymentProcessor', $paymentProcessor); + $this->assign('hidePayPalExpress', TRUE); + } + + public function getCurrency($submittedValues) { // get current currency from DB or use default currency + $config = CRM_Core_Config::singleton(); + + $currentCurrency = CRM_Utils_Array::value('currency', + $this->_values, + $config->defaultCurrency + ); + + // use submitted currency if present else use current currency + $result = CRM_Utils_Array::value('currency', + $submittedValues, + $currentCurrency + ); + return $result; + } + + public function getFinancialAccounts($financialTypeId) { + $financialAccounts = array(); + CRM_Core_PseudoConstant::populate($financialAccounts, + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = TRUE, + $retrieve = 'financial_account_id', + $filter = NULL, + " entity_id = {$financialTypeId} ", NULL, 'account_relationship'); + return $financialAccounts; + } + + public function getFinancialAccount($financialTypeId, $relationTypeId) { + $financialAccounts = $this->getFinancialAccounts($financialTypeId); + return CRM_Utils_Array::value($relationTypeId, $financialAccounts); + } + + public function preProcessPledge() { + //get the payment values associated with given pledge payment id OR check for payments due. + $this->_pledgeValues = array(); + if ($this->_ppID) { + $payParams = array('id' => $this->_ppID); + + CRM_Pledge_BAO_PledgePayment::retrieve($payParams, $this->_pledgeValues['pledgePayment']); + $this->_pledgeID = CRM_Utils_Array::value('pledge_id', $this->_pledgeValues['pledgePayment']); + $paymentStatusID = CRM_Utils_Array::value('status_id', $this->_pledgeValues['pledgePayment']); + $this->_id = CRM_Utils_Array::value('contribution_id', $this->_pledgeValues['pledgePayment']); + + //get all status + $allStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + if (!($paymentStatusID == array_search('Pending', $allStatus) || $paymentStatusID == array_search('Overdue', $allStatus))) { + CRM_Core_Error::fatal(ts("Pledge payment status should be 'Pending' or 'Overdue'.")); + } + + //get the pledge values associated with given pledge payment. + + $ids = array(); + $pledgeParams = array('id' => $this->_pledgeID); + CRM_Pledge_BAO_Pledge::getValues($pledgeParams, $this->_pledgeValues, $ids); + $this->assign('ppID', $this->_ppID); + } + else { + // Not making a pledge payment, so if adding a new contribution we should check if pledge payment(s) are due for this contact so we can alert the user. CRM-5206 + if (isset($this->_contactID)) { + $contactPledges = CRM_Pledge_BAO_Pledge::getContactPledges($this->_contactID); + + if (!empty($contactPledges)) { + $payments = $paymentsDue = NULL; + $multipleDue = FALSE; + foreach ($contactPledges as $key => $pledgeId) { + $payments = CRM_Pledge_BAO_PledgePayment::getOldestPledgePayment($pledgeId); + if ($payments) { + if ($paymentsDue) { + $multipleDue = TRUE; + break; + } + else { + $paymentsDue = $payments; + } + } + } + if ($multipleDue) { + // Show link to pledge tab since more than one pledge has a payment due + $pledgeTab = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&force=1&cid={$this->_contactID}&selectedChild=pledge" + ); + CRM_Core_Session::setStatus(ts('This contact has pending or overdue pledge payments. Click here to view their Pledges tab and verify whether this contribution should be applied as a pledge payment.', array(1 => $pledgeTab)), ts('Notice'), 'alert'); + } + elseif ($paymentsDue) { + // Show user link to oldest Pending or Overdue pledge payment + $ppAmountDue = CRM_Utils_Money::format($payments['amount'], $payments['currency']); + $ppSchedDate = CRM_Utils_Date::customFormat(CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment', $payments['id'], 'scheduled_date')); + if ($this->_mode) { + $ppUrl = CRM_Utils_System::url('civicrm/contact/view/contribution', + "reset=1&action=add&cid={$this->_contactID}&ppid={$payments['id']}&context=pledge&mode=live" + ); + } + else { + $ppUrl = CRM_Utils_System::url('civicrm/contact/view/contribution', + "reset=1&action=add&cid={$this->_contactID}&ppid={$payments['id']}&context=pledge" + ); + } + CRM_Core_Session::setStatus(ts('This contact has a pending or overdue pledge payment of %2 which is scheduled for %3. Click here to enter a pledge payment.', array( + 1 => $ppUrl, + 2 => $ppAmountDue, + 3 => $ppSchedDate + )), ts('Notice'), 'alert'); + } + } + } + } + } + + public function unsetCreditCardFields($submittedValues) { + //Offline Contribution. + $unsetParams = array( + 'payment_processor_id', + "email-{$this->_bltID}", + 'hidden_buildCreditCard', + 'hidden_buildDirectDebit', + 'billing_first_name', + 'billing_middle_name', + 'billing_last_name', + 'street_address-5', + "city-{$this->_bltID}", + "state_province_id-{$this->_bltID}", + "postal_code-{$this->_bltID}", + "country_id-{$this->_bltID}", + 'credit_card_number', + 'cvv2', + 'credit_card_exp_date', + 'credit_card_type', + ); + foreach ($unsetParams as $key) { + if (isset($submittedValues[$key])) { + unset($submittedValues[$key]); + } + } + return $submittedValues; + } + +} diff --git a/CRM/Contribute/Form/AdditionalInfo.php b/CRM/Contribute/Form/AdditionalInfo.php new file mode 100644 index 0000000000..eeb5110276 --- /dev/null +++ b/CRM/Contribute/Form/AdditionalInfo.php @@ -0,0 +1,517 @@ +add('hidden', 'hidden_Premium', 1); + $sel1 = $sel2 = array(); + + $dao = new CRM_Contribute_DAO_Product(); + $dao->is_active = 1; + $dao->find(); + $min_amount = array(); + $sel1[0] = '-select product-'; + while ($dao->fetch()) { + $sel1[$dao->id] = $dao->name . " ( " . $dao->sku . " )"; + $min_amount[$dao->id] = $dao->min_contribution; + $options = explode(',', $dao->options); + foreach ($options as $k => $v) { + $options[$k] = trim($v); + } + if ($options[0] != '') { + $sel2[$dao->id] = $options; + } + $form->assign('premiums', TRUE); + } + $form->_options = $sel2; + $form->assign('mincontribution', $min_amount); + $sel = & $form->addElement('hierselect', "product_name", ts('Premium'), 'onclick="showMinContrib();"'); + $js = "\n"; + $form->assign('initHideBoxes', $js); + + $form->addDate('fulfilled_date', ts('Fulfilled'), FALSE, array('formatType' => 'activityDate')); + $form->addElement('text', 'min_amount', ts('Minimum Contribution Amount')); + } + + /** + * Function to build the form for Additional Details. + * + * @access public + * + * @return void + */ + static function buildAdditionalDetail(&$form) { + //Additional information section + $form->add('hidden', 'hidden_AdditionalDetail', 1); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution'); + + $form->addDateTime('thankyou_date', ts('Thank-you Sent'), FALSE, array('formatType' => 'activityDateTime')); + + // add various amounts + $nonDeductAmount = & $form->add('text', 'non_deductible_amount', ts('Non-deductible Amount'), + $attributes['non_deductible_amount'] + ); + $form->addRule('non_deductible_amount', ts('Please enter a valid monetary value for Non-deductible Amount.'), 'money'); + + if ($form->_online) { + $nonDeductAmount->freeze(); + } + $feeAmount = & $form->add('text', 'fee_amount', ts('Fee Amount'), + $attributes['fee_amount'] + ); + $form->addRule('fee_amount', ts('Please enter a valid monetary value for Fee Amount.'), 'money'); + if ($form->_online) { + $feeAmount->freeze(); + } + + $netAmount = & $form->add('text', 'net_amount', ts('Net Amount'), + $attributes['net_amount'] + ); + $form->addRule('net_amount', ts('Please enter a valid monetary value for Net Amount.'), 'money'); + if ($form->_online) { + $netAmount->freeze(); + } + $element = & $form->add('text', 'invoice_id', ts('Invoice ID'), + $attributes['invoice_id'] + ); + if ($form->_online) { + $element->freeze(); + } + else { + $form->addRule('invoice_id', + ts('This Invoice ID already exists in the database.'), + 'objectExists', + array('CRM_Contribute_DAO_Contribution', $form->_id, 'invoice_id') + ); + } + + $form->add('select', 'contribution_page_id', + ts('Online Contribution Page'), + array( + '' => ts('- select -') + ) + + CRM_Contribute_PseudoConstant::contributionPage() + ); + + $form->add('textarea', 'note', ts('Notes'), array("rows" => 4, "cols" => 60)); + + $statusName = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + if ($form->_id && $form->_values['contribution_status_id'] == array_search('Cancelled', $statusName)) { + $netAmount->freeze(); + $feeAmount->freeze(); + } + + } + + /** + * Function to build the form for Honoree Information. + * + * @access public + * + * @return None + */ + static function buildHonoree(&$form) { + //Honoree section + $form->add('hidden', 'hidden_Honoree', 1); + $honor = CRM_Core_PseudoConstant::honor(); + $extraOption = array('onclick' => "return enableHonorType();"); + foreach ($honor as $key => $var) { + $honorTypes[$key] = $form->createElement('radio', NULL, NULL, $var, $key, $extraOption); + } + $form->addGroup($honorTypes, 'honor_type_id', NULL); + $form->add('select', 'honor_prefix_id', ts('Prefix'), array('' => ts('- prefix -')) + CRM_Core_PseudoConstant::individualPrefix()); + $form->add('text', 'honor_first_name', ts('First Name')); + $form->add('text', 'honor_last_name', ts('Last Name')); + $form->add('text', 'honor_email', ts('Email')); + $form->addRule("honor_email", ts('Email is not valid.'), 'email'); + } + + /** + * This function is used by CRM/Pledge/Form/Pledge.php + * + * Function to build the form for PaymentReminders Information. + * + * @access public + * + * @return void + * + */ + function buildPaymentReminders(&$form) { + //PaymentReminders section + $form->add('hidden', 'hidden_PaymentReminders', 1); + $form->add('text', 'initial_reminder_day', ts('Send Initial Reminder'), array('size' => 3)); + $this->addRule('initial_reminder_day', ts('Please enter a valid reminder day.'), 'positiveInteger'); + $form->add('text', 'max_reminders', ts('Send up to'), array('size' => 3)); + $this->addRule('max_reminders', ts('Please enter a valid No. of reminders.'), 'positiveInteger'); + $form->add('text', 'additional_reminder_day', ts('Send additional reminders'), array('size' => 3)); + $this->addRule('additional_reminder_day', ts('Please enter a valid additional reminder day.'), 'positiveInteger'); + } + + /** + * Function to process the Premium Information + * + * @access public + * + * @return None + */ + static function processPremium(&$params, $contributionID, $premiumID = NULL, &$options = NULL) { + $dao = new CRM_Contribute_DAO_ContributionProduct(); + $dao->contribution_id = $contributionID; + $dao->product_id = $params['product_name'][0]; + $dao->fulfilled_date = CRM_Utils_Date::processDate($params['fulfilled_date'], NULL, TRUE); + $isDeleted = False; + //CRM-11106 + $premiumParams = array( + 'id' => $params['product_name'][0], + ); + $productDetails = array(); + CRM_Contribute_BAO_ManagePremiums::retrieve($premiumParams, $productDetails); + $dao->financial_type_id = CRM_Utils_Array::value('financial_type_id', $productDetails); + if (CRM_Utils_Array::value($params['product_name'][0], $options)) { + $dao->product_option = $options[$params['product_name'][0]][$params['product_name'][1]]; + } + if ($premiumID) { + $premoumDAO = new CRM_Contribute_DAO_ContributionProduct(); + $premoumDAO->id = $premiumID; + $premoumDAO->find(TRUE); + if ($premoumDAO->product_id == $params['product_name'][0]) { + $dao->id = $premiumID; + $premium = $dao->save(); + } + else { + $premoumDAO->delete(); + $isDeleted = TRUE; + $premium = $dao->save(); + } + } + else { + $premium = $dao->save(); + } + //CRM-11106 + if ($premiumID == NULL || $isDeleted) { + $params = array( + 'cost' => CRM_Utils_Array::value('cost', $productDetails), + 'currency' => CRM_Utils_Array::value('currency', $productDetails), + 'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $productDetails), + 'contributionId' => $contributionID + ); + if ($isDeleted) { + $params['oldPremium']['product_id'] = $premoumDAO->product_id; + $params['oldPremium']['contribution_id'] = $premoumDAO->contribution_id; + } + CRM_Core_BAO_FinancialTrxn::createPremiumTrxn($params); + } + } + + /** + * Function to process the Note + * + * @access public + * + * @return None + */ + static function processNote(&$params, $contactID, $contributionID, $contributionNoteID = NULL) { + //process note + $noteParams = array( + 'entity_table' => 'civicrm_contribution', + 'note' => $params['note'], + 'entity_id' => $contributionID, + 'contact_id' => $contactID, + ); + $noteID = array(); + if ($contributionNoteID) { + $noteID = array("id" => $contributionNoteID); + $noteParams['note'] = $noteParams['note'] ? $noteParams['note'] : "null"; + } + CRM_Core_BAO_Note::add($noteParams, $noteID); + } + + /** + * Function to process the Common data + * + * @access public + * + * @return None + */ + static function postProcessCommon(&$params, &$formatted, &$form) { + $fields = array( + 'non_deductible_amount', + 'total_amount', + 'fee_amount', + 'net_amount', + 'trxn_id', + 'invoice_id', + 'campaign_id', + 'honor_type_id', + 'contribution_page_id', + ); + foreach ($fields as $f) { + $formatted[$f] = CRM_Utils_Array::value($f, $params); + } + + if (CRM_Utils_Array::value('thankyou_date', $params) && !CRM_Utils_System::isNull($params['thankyou_date'])) { + $formatted['thankyou_date'] = CRM_Utils_Date::processDate($params['thankyou_date'], $params['thankyou_date_time']); + } + else { + $formatted['thankyou_date'] = 'null'; + } + + if (CRM_Utils_Array::value('is_email_receipt', $params)) { + $params['receipt_date'] = $formatted['receipt_date'] = date('YmdHis'); + } + + if (CRM_Utils_Array::value('honor_type_id', $params)) { + if ($form->_honorID) { + $honorId = CRM_Contribute_BAO_Contribution::createHonorContact($params, $form->_honorID); + } + else { + $honorId = CRM_Contribute_BAO_Contribution::createHonorContact($params); + } + $formatted["honor_contact_id"] = $honorId; + } + else { + $formatted["honor_contact_id"] = 'null'; + } + + //special case to handle if all checkboxes are unchecked + $customFields = CRM_Core_BAO_CustomField::getFields('Contribution', + FALSE, + FALSE, + CRM_Utils_Array::value('financial_type_id', + $params + ) + ); + $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + CRM_Utils_Array::value('id', $params, NULL), + 'Contribution' + ); + } + + /** + * Function to send email receipt. + * + * @form object of Contribution form. + * + * @param array $params (reference ) an assoc array of name/value pairs. + * @$ccContribution boolen, is it credit card contribution. + * @access public. + * + * @return None. + */ + function emailReceipt(&$form, &$params, $ccContribution = FALSE) { + $this->assign('receiptType', 'contribution'); + // Retrieve Financial Type Name from financial_type_id + $params['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', + $params['financial_type_id']); + if (CRM_Utils_Array::value('payment_instrument_id', $params)) { + $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument(); + $params['paidBy'] = $paymentInstrument[$params['payment_instrument_id']]; + } + + // retrieve individual prefix value for honoree + if (CRM_Utils_Array::value('hidden_Honoree', $params)) { + $individualPrefix = CRM_Core_PseudoConstant::individualPrefix(); + $honor = CRM_Core_PseudoConstant::honor(); + $params['honor_prefix'] = CRM_Utils_Array::value(CRM_Utils_Array::value('honor_prefix_id', + $params + ), + $individualPrefix + ); + $params["honor_type"] = CRM_Utils_Array::value(CRM_Utils_Array::value('honor_type_id', + $params + ), + $honor + ); + } + + // retrieve premium product name and assigned fulfilled + // date to template + if (CRM_Utils_Array::value('hidden_Premium', $params)) { + if (isset($params['product_name']) && + is_array($params['product_name']) && + !empty($params['product_name']) + ) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $params['product_name'][0]; + $productDAO->find(TRUE); + $params['product_name'] = $productDAO->name; + $params['product_sku'] = $productDAO->sku; + + if (!CRM_Utils_Array::value('product_option', $params) && + CRM_Utils_Array::value($params['product_name'][0], + $form->_options + ) + ) { + $params['product_option'] = $form->_options[$params['product_name'][0]][$params['product_name'][1]]; + } + } + + if (CRM_Utils_Array::value('fulfilled_date', $params)) { + $this->assign('fulfilled_date', CRM_Utils_Date::processDate($params['fulfilled_date'])); + } + } + + $this->assign('ccContribution', $ccContribution); + if ($ccContribution) { + //build the name. + $name = CRM_Utils_Array::value('billing_first_name', $params); + if (CRM_Utils_Array::value('billing_middle_name', $params)) { + $name .= " {$params['billing_middle_name']}"; + } + $name .= ' ' . CRM_Utils_Array::value('billing_last_name', $params); + $name = trim($name); + $this->assign('billingName', $name); + + //assign the address formatted up for display + $addressParts = array( + "street_address" => "billing_street_address-{$form->_bltID}", + "city" => "billing_city-{$form->_bltID}", + "postal_code" => "billing_postal_code-{$form->_bltID}", + "state_province" => "state_province-{$form->_bltID}", + "country" => "country-{$form->_bltID}", + ); + + $addressFields = array(); + foreach ($addressParts as $name => $field) { + $addressFields[$name] = CRM_Utils_Array::value($field, $params); + } + $this->assign('address', CRM_Utils_Address::format($addressFields)); + + $date = CRM_Utils_Date::format($params['credit_card_exp_date']); + $date = CRM_Utils_Date::mysqlToIso($date); + $this->assign('credit_card_type', CRM_Utils_Array::value('credit_card_type', $params)); + $this->assign('credit_card_exp_date', $date); + $this->assign('credit_card_number', + CRM_Utils_System::mungeCreditCard($params['credit_card_number']) + ); + } + else { + //offline contribution + // assigned various dates to the templates + $form->assign('receipt_date', CRM_Utils_Date::processDate($params['receipt_date'])); + + if (CRM_Utils_Array::value('cancel_date', $params)) { + $form->assign('cancel_date', CRM_Utils_Date::processDate($params['cancel_date'])); + } + if (CRM_Utils_Array::value('thankyou_date', $params)) { + $form->assign('thankyou_date', CRM_Utils_Date::processDate($params['thankyou_date'])); + } + if ($form->_action & CRM_Core_Action::UPDATE) { + $form->assign('lineItem', empty($form->_lineItems) ? FALSE : $form->_lineItems); + } + } + + //handle custom data + if (CRM_Utils_Array::value('hidden_custom', $params)) { + $contribParams = array(array('contribution_id', '=', $params['contribution_id'], 0, 0)); + if ($form->_mode == 'test') { + $contribParams[] = array('contribution_test', '=', 1, 0, 0); + } + + //retrieve custom data + $customGroup = array(); + + foreach ($form->_groupTree as $groupID => $group) { + $customFields = $customValues = array(); + if ($groupID == 'info') { + continue; + } + foreach ($group['fields'] as $k => $field) { + $field['title'] = $field['label']; + $customFields["custom_{$k}"] = $field; + } + + //build the array of customgroup contain customfields. + CRM_Core_BAO_UFGroup::getValues($params['contact_id'], $customFields, $customValues, FALSE, $contribParams); + $customGroup[$group['title']] = $customValues; + } + //assign all custom group and corresponding fields to template. + $form->assign('customGroup', $customGroup); + } + + $form->assign_by_ref('formValues', $params); + list($contributorDisplayName, + $contributorEmail + ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($params['contact_id']); + $this->assign('contactID', $params['contact_id']); + $this->assign('contributionID', $params['contribution_id']); + + if (CRM_Utils_Array::value('currency', $params)) { + $this->assign('currency', $params['currency']); + } + + if (CRM_Utils_Array::value('receive_date', $params)) { + $this->assign('receive_date', CRM_Utils_Date::processDate($params['receive_date'])); + } + + list($sendReceipt, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate( + array( + 'groupName' => 'msg_tpl_workflow_contribution', + 'valueName' => 'contribution_offline_receipt', + 'contactId' => $params['contact_id'], + 'contributionId' => $params['contribution_id'], + 'from' => $params['from_email_address'], + 'toName' => $contributorDisplayName, + 'toEmail' => $contributorEmail, + 'isTest' => $form->_mode == 'test', + ) + ); + + return $sendReceipt; + } + +} + + diff --git a/CRM/Contribute/Form/CancelSubscription.php b/CRM/Contribute/Form/CancelSubscription.php new file mode 100644 index 0000000000..1c741023ad --- /dev/null +++ b/CRM/Contribute/Form/CancelSubscription.php @@ -0,0 +1,321 @@ +_mid = CRM_Utils_Request::retrieve('mid', 'Integer', $this, FALSE); + + $this->_crid = CRM_Utils_Request::retrieve('crid', 'Integer', $this, FALSE); + if ($this->_crid) { + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_crid, 'recur', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_crid); + $this->assign('frequency_unit', $this->_subscriptionDetails->frequency_unit); + $this->assign('frequency_interval', $this->_subscriptionDetails->frequency_interval); + $this->assign('amount', $this->_subscriptionDetails->amount); + $this->assign('installments', $this->_subscriptionDetails->installments); + + // Are we cancelling a recurring contribution that is linked to an auto-renew membership? + if ($this->_subscriptionDetails->membership_id) { + $this->_mid = $this->_subscriptionDetails->membership_id; + } + } + + if ($this->_mid) { + if (CRM_Member_BAO_Membership::isSubscriptionCancelled($this->_mid)) { + CRM_Core_Error::fatal(ts('The auto renewal option for this membership looks to have been cancelled already.')); + } + $this->_mode = 'auto_renew'; + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_mid, 'membership', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_mid, 'membership'); + + $membershipTypes = CRM_Member_PseudoConstant::membershipType(); + $membershipTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_mid, 'membership_type_id'); + $this->assign('membershipType', CRM_Utils_Array::value($membershipTypeId, $membershipTypes)); + } + + $this->_coid = CRM_Utils_Request::retrieve('coid', 'Integer', $this, FALSE); + if ($this->_coid) { + if (CRM_Contribute_BAO_Contribution::isSubscriptionCancelled($this->_coid)) { + CRM_Core_Error::fatal(ts('The recurring contribution looks to have been cancelled already.')); + } + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_coid, 'contribution'); + + $this->assign('frequency_unit', $this->_subscriptionDetails->frequency_unit); + $this->assign('frequency_interval', $this->_subscriptionDetails->frequency_interval); + $this->assign('amount', $this->_subscriptionDetails->amount); + $this->assign('installments', $this->_subscriptionDetails->installments); + } + + if ((!$this->_crid && !$this->_coid && !$this->_mid) || + ($this->_subscriptionDetails == CRM_Core_DAO::$_nullObject) + ) { + CRM_Core_Error::fatal('Required information missing.'); + } + + if (!CRM_Core_Permission::check('edit contributions')) { + $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE); + if (!CRM_Contact_BAO_Contact_Utils::validChecksum($this->_subscriptionDetails->contact_id, $userChecksum)) { + CRM_Core_Error::fatal(ts('You do not have permission to cancel this recurring contribution.')); + } + $this->_selfService = TRUE; + } + $this->assign('self_service', $this->_selfService); + + // handle context redirection + CRM_Contribute_BAO_ContributionRecur::setSubscriptionContext(); + + CRM_Utils_System::setTitle($this->_mid ? ts('Cancel Auto-renewal') : ts('Cancel Recurring Contribution')); + $this->assign('mode', $this->_mode); + + if ($this->_subscriptionDetails->contact_id) { + list($this->_donorDisplayName, $this->_donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($this->_subscriptionDetails->contact_id); + } + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + // Determine if we can cancel recurring contribution via API with this processor + $cancelSupported = $this->_paymentProcessorObj->isSupported('cancelSubscription'); + if ($cancelSupported) { + $searchRange = array(); + $searchRange[] = $this->createElement('radio', NULL, NULL, ts('Yes'), '1'); + $searchRange[] = $this->createElement('radio', NULL, NULL, ts('No'), '0'); + + $this->addGroup($searchRange, 'send_cancel_request', ts('Send cancellation request to %1 ?', array(1 => $this->_paymentProcessorObj->_processorName))); + } + $this->assign('cancelSupported', $cancelSupported); + + if ($this->_donorEmail) { + $this->add('checkbox', 'is_notify', ts('Notify Contributor?')); + } + if ($this->_mid) { + $cancelButton = ts('Cancel Automatic Membership Renewal'); + } + else { + $cancelButton = ts('Cancel Recurring Contribution'); + } + + $type = 'next'; + if ( $this->_selfService ) { + $type = 'submit'; + } + + $this->addButtons(array( + array( + 'type' => $type, + 'name' => $cancelButton, + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Not Now'), + ), + ) + ); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @param null + * + * @return array array of default values + * @access public + */ + function setDefaultValues() { + $defaults = array(); + $defaults['is_notify'] = 1; + return $defaults; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $status = $message = NULL; + $cancelSubscription = TRUE; + $params = $this->controller->exportValues($this->_name); + + if ($this->_selfService) { + // for self service force sending-request & notify + if ($this->_paymentProcessorObj->isSupported('cancelSubscription')) + $params['send_cancel_request'] = 1; + if ($this->_donorEmail) + $params['is_notify'] = 1; + } + + if (CRM_Utils_Array::value('send_cancel_request', $params) == 1) { + $cancelParams = array('subscriptionId' => $this->_subscriptionDetails->subscription_id); + $cancelSubscription = $this->_paymentProcessorObj->cancelSubscription($message, $cancelParams); + } + + if (is_a($cancelSubscription, 'CRM_Core_Error')) { + CRM_Core_Error::displaySessionError($cancelSubscription); + } + elseif ($cancelSubscription) { + $activityParams = array('subject' => $this->_mid ? ts('Auto-renewal membership cancelled') : ts('Recurring contribution cancelled'), + 'details' => $message, + ); + $cancelStatus = CRM_Contribute_BAO_ContributionRecur::cancelRecurContribution($this->_subscriptionDetails->recur_id, + CRM_Core_DAO::$_nullObject, $activityParams + ); + if ($cancelStatus) { + $tplParams = array(); + if ($this->_mid) { + $inputParams = array('id' => $this->_mid); + CRM_Member_BAO_Membership::getValues($inputParams, $tplParams); + $tplParams = $tplParams[$this->_mid]; + $tplParams['membership_status'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', $tplParams['status_id']); + $tplParams['membershipType'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $tplParams['membership_type_id']); + $status = ts('The automatic renewal of your %1 membership has been cancelled as requested. This does not affect the status of your membership - you will receive a separate notification when your membership is up for renewal.', array(1 => $tplParams['membershipType'])); + $msgTitle = 'Membership Renewal Cancelled'; + $msgType = 'info'; + } + else { + $tplParams['recur_frequency_interval'] = $this->_subscriptionDetails->frequency_interval; + $tplParams['recur_frequency_unit'] = $this->_subscriptionDetails->frequency_unit; + $tplParams['amount'] = $this->_subscriptionDetails->amount; + $tplParams['contact'] = array('display_name' => $this->_donorDisplayName); + $status = ts('The recurring contribution of %1, every %2 %3 has been cancelled.', + array( + 1 => $this->_subscriptionDetails->amount, + 2 => $this->_subscriptionDetails->frequency_interval, + 3 => $this->_subscriptionDetails->frequency_unit + ) + ); + $msgTitle = 'Contribution Cancelled'; + $msgType = 'success'; + } + + if (CRM_Utils_Array::value('is_notify', $params) == 1) { + if ($this->_subscriptionDetails->contribution_page_id) { + CRM_Core_DAO::commonRetrieveAll('CRM_Contribute_DAO_ContributionPage', 'id', + $this->_subscriptionDetails->contribution_page_id, + $value, array('title', + 'receipt_from_name', + 'receipt_from_email', + ) + ); + $receiptFrom = '"' . CRM_Utils_Array::value('receipt_from_name', $value[$this->_subscriptionDetails->contribution_page_id]) . '" <' . $value[$this->_subscriptionDetails->contribution_page_id]['receipt_from_email'] . '>'; + } + else { + $domainValues = CRM_Core_BAO_Domain::getNameAndEmail(); + $receiptFrom = "$domainValues[0] <$domainValues[1]>"; + } + + // send notification + $sendTemplateParams = + array( + 'groupName' => $this->_mode == 'auto_renew' ? 'msg_tpl_workflow_membership' : 'msg_tpl_workflow_contribution', + 'valueName' => $this->_mode == 'auto_renew' ? 'membership_autorenew_cancelled' : 'contribution_recurring_cancelled', + 'contactId' => $this->_subscriptionDetails->contact_id, + 'tplParams' => $tplParams, + //'isTest' => $isTest, set this from _objects + 'PDFFilename' => 'receipt.pdf', + 'from' => $receiptFrom, + 'toName' => $this->_donorDisplayName, + 'toEmail' => $this->_donorEmail, + ); + list($sent) = CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + } + } + else { + $msgType = 'error'; + $msgTitle = ts('Error'); + if ($params['send_cancel_request'] == 1) { + $status = ts('Recurring contribution was cancelled successfully by the processor, but could not be marked as cancelled in the database.'); + } + else { + $status = ts('Recurring contribution could not be cancelled in the database.'); + } + } + } + else { + $status = ts('The recurring contribution could not be cancelled.'); + $msgTitle = 'Error Cancelling Contribution'; + $msgType = 'error'; + } + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + if ( $userID && $status) { + $session->setStatus($status, $msgTitle, $msgType); + } + elseif (!$userID) { + if ($status) + CRM_Utils_System::setUFMessage($status); + // keep result as 1, since we not displaying anything on the redirected page anyway + return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/subscriptionstatus', + "reset=1&task=cancel&result=1")); + } + } +} + diff --git a/CRM/Contribute/Form/Contribution.php b/CRM/Contribute/Form/Contribution.php new file mode 100644 index 0000000000..ebee68fff2 --- /dev/null +++ b/CRM/Contribute/Form/Contribution.php @@ -0,0 +1,1657 @@ +_action)) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + + $this->_cdType = CRM_Utils_Array::value('type', $_GET); + + $this->assign('cdType', FALSE); + if ($this->_cdType) { + $this->assign('cdType', TRUE); + CRM_Custom_Form_CustomData::preProcess($this); + return; + } + + $this->_formType = CRM_Utils_Array::value('formType', $_GET); + + // get price set id. + $this->_priceSetId = CRM_Utils_Array::value('priceSetId', $_GET); + $this->set('priceSetId', $this->_priceSetId); + $this->assign('priceSetId', $this->_priceSetId); + + //get the pledge payment id + $this->_ppID = CRM_Utils_Request::retrieve('ppid', 'Positive', $this); + + //get the contact id + $this->_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + //get the action. + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add'); + $this->assign('action', $this->_action); + + //get the contribution id if update + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + if (!empty($this->_id)) { + $this->assign('contribID', $this->_id); + } + + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this); + $this->assign('context', $this->_context); + + $this->_compId = CRM_Utils_Request::retrieve('compId', 'Positive', $this); + + $this->_compContext = CRM_Utils_Request::retrieve('compContext', 'String', $this); + + //set the contribution mode. + $this->_mode = CRM_Utils_Request::retrieve('mode', 'String', $this); + + $this->assign('contributionMode', $this->_mode); + + $this->_paymentProcessor = array('billing_mode' => 1); + + $this->assign('showCheckNumber', TRUE); + + $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail(); + $this->assignProcessors(); + + if ($this->_contactID) { + list($this->userDisplayName, $this->userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID); + $this->assign('displayName', $this->userDisplayName); + } + + // also check for billing information + // get the billing location type + $this->assignBillingType(); + + $this->_fields = array(); + + CRM_Core_Payment_Form::setPaymentFieldsByType(CRM_Utils_Array::value('payment_type', $this->_processors), $this); + + if ($this->_action & CRM_Core_Action::DELETE) { + return; + } + + $config = CRM_Core_Config::singleton(); + if (in_array('CiviPledge', $config->enableComponents) && !$this->_formType) { + $this->preProcessPledge(); + } + + $this->_values = array(); + + // current contribution id + if ($this->_id) { + $this->assignPremiumProduct($this->_id); + $this->buildValuesAndAssignOnline_Note_Type($this->_id, $this->_values); + } + + // when custom data is included in this page + if (CRM_Utils_Array::value('hidden_custom', $_POST)) { + $this->applyCustomData('Contribution', CRM_Utils_Array::value('financial_type_id', $_POST), $this->_id); + } + + $this->_lineItems = array(); + if ($this->_id) { + if (!empty($this->_compId) && $this->_compContext == 'participant') { + $this->assign('compId', $this->_compId); + $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_compId); + } + else { + $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution',1); + } + empty($lineItem) ? NULL : $this->_lineItems[] = $lineItem; + } + + $this->assign('lineItem', empty($this->_lineItems) ? FALSE : $this->_lineItems); + + // Set title + if ($this->_contactID) { + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactID); + + // Check if this is default domain contact CRM-10482 + if (CRM_Contact_BAO_Contact::checkDomainContact($this->_contactID)) { + $displayName .= ' (' . ts('default organization') . ')'; + } + + // omitting contactImage from title for now since the summary overlay css doesn't work outside of our crm-container + CRM_Utils_System::setTitle(ts('Contribution from') . ' ' . $displayName); + } + + } + + function setDefaultValues() { + if ($this->_cdType) { + return CRM_Custom_Form_CustomData::setDefaultValues($this); + } + + $defaults = $this->_values; + + //set defaults for pledge payment. + if ($this->_ppID) { + $defaults['total_amount'] = CRM_Utils_Array::value('scheduled_amount', $this->_pledgeValues['pledgePayment']); + $defaults['honor_type_id'] = CRM_Utils_Array::value('honor_type_id', $this->_pledgeValues); + $defaults['honor_contact_id'] = CRM_Utils_Array::value('honor_contact_id', $this->_pledgeValues); + $defaults['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $this->_pledgeValues); + $defaults['currency'] = CRM_Utils_Array::value('currency', $this->_pledgeValues); + $defaults['option_type'] = 1; + } + + $fields = array(); + if ($this->_action & CRM_Core_Action::DELETE) { + return $defaults; + } + + if ($this->_mode) { + $config = CRM_Core_Config::singleton(); + // set default country from config if no country set + if (!CRM_Utils_Array::value("billing_country_id-{$this->_bltID}", $defaults)) { + $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry; + } + + if (!CRM_Utils_Array::value("billing_state_province_id-{$this->_bltID}", $defaults)) { + $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince; + } + + $names = array( + 'first_name', 'middle_name', 'last_name', "street_address-{$this->_bltID}", "city-{$this->_bltID}", + "postal_code-{$this->_bltID}", "country_id-{$this->_bltID}", "state_province_id-{$this->_bltID}", + "state_province-{$this->_bltID}", "country-{$this->_bltID}" + ); + + foreach ($names as $name) { + $fields[$name] = 1; + } + + if ($this->_contactID) { + CRM_Core_BAO_UFGroup::setProfileDefaults($this->_contactID, $fields, $defaults); + } + + foreach ($names as $name) { + if (!empty($defaults[$name])) { + $defaults['billing_' . $name] = $defaults[$name]; + } + } + + // now fix all state country selectors + CRM_Core_BAO_Address::fixAllStateSelects($this, $defaults); + } + + if ($this->_id) { + $this->_contactID = $defaults['contact_id']; + } + + // Set $newCredit variable in template to control whether link to credit card mode is included + CRM_Core_Payment::allowBackofficeCreditCard($this); + + // fix the display of the monetary value, CRM-4038 + if (isset($defaults['total_amount'])) { + $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'], NULL, '%a'); + } + + if (isset($defaults['non_deductible_amount'])) { + $defaults['non_deductible_amount'] = CRM_Utils_Money::format($defaults['non_deductible_amount'], NULL, '%a'); + } + + if (isset($defaults['fee_amount'])) { + $defaults['fee_amount'] = CRM_Utils_Money::format($defaults['fee_amount'], NULL, '%a'); + } + + if (isset($defaults['net_amount'])) { + $defaults['net_amount'] = CRM_Utils_Money::format($defaults['net_amount'], NULL, '%a'); + } + + if ($this->_contributionType) { + $defaults['financial_type_id'] = $this->_contributionType; + } + + if (CRM_Utils_Array::value('is_test', $defaults)) { + $this->assign('is_test', TRUE); + } + + if (isset($defaults['honor_contact_id'])) { + $honorDefault = $ids = array(); + $this->_honorID = $defaults['honor_contact_id']; + $honorType = CRM_Core_PseudoConstant::honor(); + $idParams = array( + 'id' => $defaults['honor_contact_id'], + 'contact_id' => $defaults['honor_contact_id'], + ); + CRM_Contact_BAO_Contact::retrieve($idParams, $honorDefault, $ids); + + $defaults['honor_prefix_id'] = CRM_Utils_Array::value('prefix_id', $honorDefault); + $defaults['honor_first_name'] = CRM_Utils_Array::value('first_name', $honorDefault); + $defaults['honor_last_name'] = CRM_Utils_Array::value('last_name', $honorDefault); + $defaults['honor_email'] = CRM_Utils_Array::value('email', $honorDefault['email'][1]); + $defaults['honor_type'] = $honorType[$defaults['honor_type_id']]; + } + + $this->assign('showOption', TRUE); + // for Premium section + if ($this->_premiumID) { + $this->assign('showOption', FALSE); + $options = isset($this->_options[$this->_productDAO->product_id]) ? $this->_options[$this->_productDAO->product_id] : ""; + if (!$options) { + $this->assign('showOption', TRUE); + } + $options_key = CRM_Utils_Array::key($this->_productDAO->product_option, $options); + if ($options_key) { + $defaults['product_name'] = array($this->_productDAO->product_id, trim($options_key)); + } + else { + $defaults['product_name'] = array($this->_productDAO->product_id); + } + if ($this->_productDAO->fulfilled_date) { + list($defaults['fulfilled_date']) = CRM_Utils_Date::setDateDefaults($this->_productDAO->fulfilled_date); + } + } + + if (isset($this->userEmail)) { + $this->assign('email', $this->userEmail); + } + + if (CRM_Utils_Array::value('is_pay_later', $defaults)) { + $this->assign('is_pay_later', TRUE); + } + $this->assign('contribution_status_id', CRM_Utils_Array::value('contribution_status_id', $defaults)); + + $dates = array('receive_date', 'receipt_date', 'cancel_date', 'thankyou_date'); + foreach ($dates as $key) { + if (CRM_Utils_Array::value($key, $defaults)) { + list($defaults[$key], + $defaults[$key . '_time'] + ) = CRM_Utils_Date::setDateDefaults(CRM_Utils_Array::value($key, $defaults), + 'activityDateTime' + ); + } + } + + if (!$this->_id && !CRM_Utils_Array::value('receive_date', $defaults)) { + list($defaults['receive_date'], + $defaults['receive_date_time'] + ) = CRM_Utils_Date::setDateDefaults(NULL, 'activityDateTime'); + } + + $this->assign('receive_date', CRM_Utils_Date::processDate(CRM_Utils_Array::value('receive_date', $defaults), + CRM_Utils_Array::value('receive_date_time', $defaults) + )); + $currency = CRM_Utils_Array::value('currency', $defaults); + $this->assign('currency', $currency); + // Hack to get currency info to the js layer. CRM-11440 + CRM_Utils_Money::format(1); + $this->assign('currencySymbol', CRM_Utils_Array::value($currency, CRM_Utils_Money::$_currencySymbols)); + $this->assign('totalAmount', CRM_Utils_Array::value('total_amount', $defaults)); + + //inherit campaign from pledge. + if ($this->_ppID && CRM_Utils_Array::value('campaign_id', $this->_pledgeValues)) { + $defaults['campaign_id'] = $this->_pledgeValues['campaign_id']; + } + + $this->_defaults = $defaults; + return $defaults; + } + + /** + * Function to build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + if ($this->_cdType) { + CRM_Custom_Form_CustomData::buildQuickForm($this); + return; + } + + // build price set form. + $buildPriceSet = FALSE; + if (empty($this->_lineItems) && + ($this->_priceSetId || CRM_Utils_Array::value('price_set_id', $_POST)) + ) { + $buildPriceSet = TRUE; + $getOnlyPriceSetElements = TRUE; + if (!$this->_priceSetId) { + $this->_priceSetId = $_POST['price_set_id']; + $getOnlyPriceSetElements = FALSE; + } + + $this->set('priceSetId', $this->_priceSetId); + CRM_Price_BAO_Set::buildPriceSet($this); + + // get only price set form elements. + if ($getOnlyPriceSetElements) { + return; + } + } + // use to build form during form rule. + $this->assign('buildPriceSet', $buildPriceSet); + + $showAdditionalInfo = FALSE; + + + $defaults = $this->_values; + $additionalDetailFields = array( + 'note', + 'thankyou_date', + 'invoice_id', + 'non_deductible_amount', + 'fee_amount', + 'net_amount' + ); + foreach ($additionalDetailFields as $key) { + if (!empty($defaults[$key])) { + $defaults['hidden_AdditionalDetail'] = 1; + break; + } + } + + $honorFields = array( + 'honor_type_id', + 'honor_prefix_id', + 'honor_first_name', + 'honor_lastname', + 'honor_email', + ); + foreach ($honorFields as $key) { + if (!empty($defaults[$key])) { + $defaults['hidden_Honoree'] = 1; + break; + } + } + + //check for honoree pane. + if ($this->_ppID && CRM_Utils_Array::value('honor_contact_id', $this->_pledgeValues)) { + $defaults['hidden_Honoree'] = 1; + } + + if ($this->_productDAO) { + if ($this->_productDAO->product_id) { + $defaults['hidden_Premium'] = 1; + } + } + + if ($this->_noteID && + isset($this->_values['note']) + ) { + $defaults['hidden_AdditionalDetail'] = 1; + } + + $paneNames = array( + ts('Additional Details') => 'AdditionalDetail', + ts('Honoree Information') => 'Honoree' + ); + + //Add Premium pane only if Premium is exists. + $dao = new CRM_Contribute_DAO_Product(); + $dao->is_active = 1; + + if ($dao->find(TRUE)) { + $paneNames[ts('Premium Information')] = 'Premium'; + } + + $ccPane = NULL; + if ($this->_mode) { + if (CRM_Utils_Array::value('payment_type', $this->_processors) & CRM_Core_Payment::PAYMENT_TYPE_DIRECT_DEBIT + ) { + $ccPane = array(ts('Direct Debit Information') => 'DirectDebit'); + } + else { + $ccPane = array(ts('Credit Card Information') => 'CreditCard'); + } + } + if (is_array($ccPane)) { + $paneNames = array_merge($ccPane, $paneNames); + } + + $buildRecurBlock = FALSE; + foreach ($paneNames as $name => $type) { + $urlParams = "snippet=4&formType={$type}"; + if ($this->_mode) { + $urlParams .= "&mode={$this->_mode}"; + } + + $open = 'false'; + if ($type == 'CreditCard' || + $type == 'DirectDebit' + ) { + $open = 'true'; + } + + $allPanes[$name] = array( + 'url' => CRM_Utils_System::url('civicrm/contact/view/contribution', $urlParams), + 'open' => $open, + 'id' => $type + ); + + // see if we need to include this paneName in the current form + if ($this->_formType == $type || + CRM_Utils_Array::value("hidden_{$type}", $_POST) || + CRM_Utils_Array::value("hidden_{$type}", $defaults) + ) { + $showAdditionalInfo = TRUE; + $allPanes[$name]['open'] = 'true'; + } + + if ($type == 'CreditCard') { + $buildRecurBlock = TRUE; + $this->add('hidden', 'hidden_CreditCard', 1); + CRM_Core_Payment_Form::buildCreditCard($this, TRUE); + } + elseif ($type == 'DirectDebit') { + $buildRecurBlock = TRUE; + $this->add('hidden', 'hidden_DirectDebit', 1); + CRM_Core_Payment_Form::buildDirectDebit($this, TRUE); + } + else { + eval('CRM_Contribute_Form_AdditionalInfo::build' . $type . '( $this );'); + } + } + if (empty($this->_recurPaymentProcessors)) { + $buildRecurBlock = FALSE; + } + if ($buildRecurBlock) { + CRM_Contribute_Form_Contribution_Main::buildRecur($this); + $this->setDefaults(array('is_recur' => 0)); + } + $this->assign('buildRecurBlock', $buildRecurBlock); + $qfKey = $this->controller->_key; + $this->assign('qfKey', $qfKey); + $this->assign('allPanes', $allPanes); + $this->assign('showAdditionalInfo', $showAdditionalInfo); + + if ($this->_formType) { + $this->assign('formType', $this->_formType); + return; + } + + $this->applyFilter('__ALL__', 'trim'); + + if ($this->_action & CRM_Core_Action::DELETE) { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel') + ) + ) + ); + return; + } + + //need to assign custom data type and subtype to the template + $this->assign('customDataType', 'Contribution'); + $this->assign('customDataSubType', $this->_contributionType); + $this->assign('entityID', $this->_id); + + if ($this->_context == 'standalone') { + CRM_Contact_Form_NewContact::buildQuickForm($this); + } + + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution'); + + $financialType = $this->add('select', 'financial_type_id', + ts('Financial Type'), + array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::financialType(), + TRUE + ); + + if (!$this->_mode) { + $paymentInstrument = $this->add('select', 'payment_instrument_id', + ts('Paid By'), + array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument(), + FALSE, array('onChange' => "return showHideByValue('payment_instrument_id','4','checkNumber','table-row','select',false);") + ); + } + + $trxnId = $this->add('text', 'trxn_id', ts('Transaction ID'), $attributes['trxn_id']); + + //add receipt for offline contribution + $this->addElement('checkbox', 'is_email_receipt', ts('Send Receipt?')); + + $this->add('select', 'from_email_address', ts('Receipt From'), $this->_fromEmails); + + $status = CRM_Contribute_PseudoConstant::contributionStatus(); + + // suppressing contribution statuses that are NOT relevant to pledges (CRM-5169) + $statusName = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + if ($this->_ppID) { + foreach (array( + 'Cancelled', + 'Failed', + 'In Progress' + ) as $suppress) { + unset($status[CRM_Utils_Array::key($suppress, $statusName)]); + } + } + elseif ((!$this->_ppID && $this->_id) || !$this->_id) { + foreach(array( + 'Overdue', + 'In Progress' + ) as $suppress) { + unset($status[CRM_Utils_Array::key($suppress, $statusName)]); + } + } + if ($this->_id) { + $contributionStatus = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->_id, 'contribution_status_id'); + $name = CRM_Utils_Array::value($contributionStatus, $statusName); + switch($name) { + case 'Completed': + case 'Cancelled': + case 'Refunded': + unset($status[CRM_Utils_Array::key('Pending', $statusName)]); + unset($status[CRM_Utils_Array::key('Failed', $statusName)]); + break; + case 'Pending': + unset($status[CRM_Utils_Array::key('Refunded', $statusName)]); + break; + case 'Failed': + foreach(array( + 'Pending', + 'Refunded', + 'Completed', + 'Cancelled' + ) as $suppress) { + unset($status[CRM_Utils_Array::key($suppress, $statusName)]); + } + break; + } + } else { + unset($status[CRM_Utils_Array::key('Refunded', $statusName)]); + } + + $this->add('select', 'contribution_status_id', + ts('Contribution Status'), + $status, + FALSE + ); + + // add various dates + $this->addDateTime('receive_date', ts('Received'), FALSE, array('formatType' => 'activityDateTime')); + + if ($this->_online) { + $this->assign('hideCalender', TRUE); + } + $checkNumber = $this->add('text', 'check_number', ts('Check Number'), $attributes['check_number']); + + $this->addDateTime('receipt_date', ts('Receipt Date'), FALSE, array('formatType' => 'activityDateTime')); + $this->addDateTime('cancel_date', ts('Cancelled / Refunded Date'), FALSE, array('formatType' => 'activityDateTime')); + + $this->add('textarea', 'cancel_reason', ts('Cancellation / Refund Reason'), $attributes['cancel_reason']); + + $recurJs = NULL; + if ($buildRecurBlock) { + $recurJs = array('onChange' => "buildRecurBlock( this.value ); return false;"); + } + $element = $this->add('select', + 'payment_processor_id', + ts('Payment Processor'), + $this->_processors, + NULL, + $recurJs + ); + + if ($this->_online) { + $element->freeze(); + } + $totalAmount = NULL; + if (empty($this->_lineItems)) { + $buildPriceSet = FALSE; + $priceSets = CRM_Price_BAO_Set::getAssoc(FALSE, 'CiviContribute'); + if (!empty($priceSets) && !$this->_ppID) { + $buildPriceSet = TRUE; + } + + // don't allow price set for contribution if it is related to participant, or if it is a pledge payment + // and if we already have line items for that participant. CRM-5095 + if ($buildPriceSet && $this->_id) { + $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id); + $pledgePaymentId = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment', + $this->_id, + 'id', + 'contribution_id' + ); + if ($pledgePaymentId) { + $buildPriceSet = FALSE; + } + if ($participantID = CRM_Utils_Array::value('participant', $componentDetails)) { + $participantLI = CRM_Price_BAO_LineItem::getLineItems($participantID); + if (!CRM_Utils_System::isNull($participantLI)) { + $buildPriceSet = FALSE; + } + } + } + + $hasPriceSets = FALSE; + if ($buildPriceSet) { + $hasPriceSets = TRUE; + $element = $this->add('select', 'price_set_id', ts('Choose price set'), + array( + '' => ts('Choose price set') + ) + $priceSets, + NULL, array('onchange' => "buildAmount( this.value );") + ); + if ($this->_online && !($this->_action & CRM_Core_Action::UPDATE)) { + $element->freeze(); + } + } + $this->assign('hasPriceSets', $hasPriceSets); + $currencyFreeze = FALSE; + if (!($this->_action & CRM_Core_Action::UPDATE)) { + if ($this->_online || $this->_ppID) { + $attributes['total_amount'] = array_merge($attributes['total_amount'], array( + 'READONLY' => TRUE, + 'style' => "background-color:#EBECE4" + )); + $optionTypes = array( + '1' => ts('Adjust Pledge Payment Schedule?'), + '2' => ts('Adjust Total Pledge Amount?'), + ); + $this->addRadio('option_type', + NULL, + $optionTypes, + array(), '
    ' + ); + + $currencyFreeze = TRUE; + } + } + + $totalAmount = $this->addMoney('total_amount', + ts('Total Amount'), + ($hasPriceSets) ? FALSE : TRUE, + $attributes['total_amount'], + TRUE, 'currency', NULL, $currencyFreeze + ); + } + + $this->add('text', 'source', ts('Source'), CRM_Utils_Array::value('source', $attributes)); + + //CRM-7362 --add campaigns. + CRM_Campaign_BAO_Campaign::addCampaign($this, CRM_Utils_Array::value('campaign_id', $this->_values)); + + // CRM-7368 allow user to set or edit PCP link for contributions + $siteHasPCPs = CRM_Contribute_PseudoConstant::pcPage(); + if (!CRM_Utils_Array::crmIsEmptyArray($siteHasPCPs)) { + $this->assign('siteHasPCPs', 1); + $pcpDataUrl = CRM_Utils_System::url('civicrm/ajax/rest', + 'className=CRM_Contact_Page_AJAX&fnName=getPCPList&json=1&context=contact&reset=1', + FALSE, NULL, FALSE + ); + $this->assign('pcpDataUrl', $pcpDataUrl); + $this->addElement('text', 'pcp_made_through', ts('Credit to a Personal Campaign Page')); + $this->addElement('hidden', 'pcp_made_through_id', '', array('id' => 'pcp_made_through_id')); + $this->addElement('checkbox', 'pcp_display_in_roll', ts('Display in Honor Roll?'), NULL); + $this->addElement('text', 'pcp_roll_nickname', ts('Name (for Honor Roll)')); + $this->addElement('textarea', 'pcp_personal_note', ts('Personal Note (for Honor Roll)')); + } + + // If we have a contact for this contribution, pass cid= to the dataUrl to exclude current contact from autocomplete results + if ($this->_contactID) { + $dataUrl = CRM_Utils_System::url('civicrm/ajax/rest', + "className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&reset=1&context=softcredit&cid={$this->_contactID}", + FALSE, NULL, FALSE + ); + } else { + $dataUrl = CRM_Utils_System::url('civicrm/ajax/rest', + 'className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&reset=1&context=softcredit', + FALSE, NULL, FALSE + ); + } + $this->assign('dataUrl', $dataUrl); + $this->addElement('text', 'soft_credit_to', ts('Soft Credit To')); + // Tell tpl to hide Soft Credit field if contribution is linked directly to a PCP Page + if (CRM_Utils_Array::value('pcp_made_through_id', $this->_values)) { + $this->assign('pcpLinked', 1); + } + $this->addElement('hidden', 'soft_contact_id', '', array('id' => 'soft_contact_id')); + + $js = NULL; + if (!$this->_mode) { + $js = array('onclick' => "return verify( );"); + } + + $mailingInfo = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, + 'mailing_backend' + ); + $this->assign('outBound_option', $mailingInfo['outBound_option']); + + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'js' => $js, + 'isDefault' => TRUE + ), + array( + 'type' => 'upload', + 'name' => ts('Save and New'), + 'js' => $js, + 'subName' => 'new' + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel') + ), + ) + ); + + // if status is Cancelled freeze Amount, Payment Instrument, Check #, Financial Type, + // Net and Fee Amounts are frozen in AdditionalInfo::buildAdditionalDetail + if ($this->_id && $this->_values['contribution_status_id'] == array_search('Cancelled', $statusName)) { + if ($totalAmount) { + $totalAmount->freeze(); + } + $checkNumber->freeze(); + $paymentInstrument->freeze(); + $trxnId->freeze(); + $financialType->freeze(); + } + + $this->addFormRule(array('CRM_Contribute_Form_Contribution', 'formRule'), $this); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->freeze(); + } + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + $errors = array(); + + //check if contact is selected in standalone mode + if (isset($fields['contact_select_id'][1]) && !$fields['contact_select_id'][1]) { + $errors['contact[1]'] = ts('Please select a contact or create new contact'); + } + + if (isset($fields['honor_type_id'])) { + if (!((CRM_Utils_Array::value('honor_first_name', $fields) && + CRM_Utils_Array::value('honor_last_name', $fields) + ) || + CRM_Utils_Array::value('honor_email', $fields) + ) + ) { + $errors['honor_first_name'] = ts('Honor First Name and Last Name OR an email should be set.'); + } + } + + //check for Credit Card Contribution. + if ($self->_mode) { + if (empty($fields['payment_processor_id'])) { + $errors['payment_processor_id'] = ts('Payment Processor is a required field.'); + } + } + + // do the amount validations. + if (!CRM_Utils_Array::value('total_amount', $fields) && empty($self->_lineItems)) { + if ($priceSetId = CRM_Utils_Array::value('price_set_id', $fields)) { + CRM_Price_BAO_Field::priceSetValidation($priceSetId, $fields, $errors); + } + } + + // if honor roll fields are populated but no PCP is selected + if (!CRM_Utils_Array::value('pcp_made_through_id', $fields)) { + if (CRM_Utils_Array::value('pcp_display_in_roll', $fields) || + CRM_Utils_Array::value('pcp_roll_nickname', $fields) || + CRM_Utils_Array::value('pcp_personal_note', $fields) + ) { + $errors['pcp_made_through'] = ts('Please select a Personal Campaign Page, OR uncheck Display in Honor Roll and clear both the Honor Roll Name and the Personal Note field.'); + } + } + + if (CRM_Utils_Array::value('total_amount', $fields) && (CRM_Utils_Array::value('net_amount', $fields) || CRM_Utils_Array::value('fee_amount', $fields))){ + $sum = CRM_Utils_Rule::cleanMoney($fields['net_amount']) + CRM_Utils_Rule::cleanMoney($fields['fee_amount']); + if (CRM_Utils_Rule::cleanMoney($fields['total_amount']) != $sum) { + $errors['total_amount'] = ts('The sum of fee amount and net amount must be equal to total amount'); + } + } + //form rule for status http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+4.3+Data+Flow + if ($self->_id && $self->_values['contribution_status_id'] != $fields['contribution_status_id']) { + CRM_Contribute_BAO_Contribution::checkStatusValidation($self->_values, $fields, $errors); + } + + //FIXME FOR NEW DATA FLOW http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+4.3+Data+Flow + if (CRM_Utils_Array::value('fee_amount', $fields)) { + $financialAccount = array(); + CRM_Core_PseudoConstant::populate($financialAccount, + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = TRUE, + $retrieve = 'financial_account_id', + $filter = NULL, + " account_relationship = 5 AND entity_id = {$fields['financial_type_id']} "); + if (!current($financialAccount)) { + $errors['financial_type_id'] = ts("Financial Account of account relationship of 'Expense Account is' is not configured for this Financial Type"); + } + } + return $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return void + */ + public function postProcess() { + $session = CRM_Core_Session::singleton(); + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Contribute_BAO_Contribution::deleteContribution($this->_id); + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', + "reset=1&cid={$this->_contactID}&selectedChild=contribute" + )); + return; + } + + // get the submitted form values. + $submittedValues = $this->controller->exportValues($this->_name); + if (CRM_Utils_Array::value('price_set_id', $submittedValues) && $this->_action & CRM_Core_Action::UPDATE ) { + $line = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution'); + $lineID = key($line); + $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Field', CRM_Utils_Array::value('price_field_id', $line[$lineID]), 'price_set_id'); + $quickConfig = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $priceSetId, 'is_quick_config'); + if ($quickConfig) { + CRM_Price_BAO_LineItem::deleteLineItems($this->_id, 'civicrm_contribution'); + } + } + + // process price set and get total amount and line items. + $lineItem = array(); + $priceSetId = $pId = NULL; + $priceSetId = CRM_Utils_Array::value('price_set_id', $submittedValues); + if (empty($priceSetId) && !$this->_id) { + $this->_priceSetId = $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', 'default_contribution_amount', 'id', 'name'); + $this->_priceSet = current(CRM_Price_BAO_Set::getSetDetail($priceSetId)); + $fieldID = key($this->_priceSet['fields']); + $fieldValueId = key($this->_priceSet['fields'][$fieldID]['options']); + $this->_priceSet['fields'][$fieldID]['options'][$fieldValueId]['amount'] = $submittedValues['total_amount']; + $submittedValues['price_' . $fieldID] = 1; + } + + if ($priceSetId) { + CRM_Price_BAO_Set::processAmount($this->_priceSet['fields'], + $submittedValues, $lineItem[$priceSetId]); + + $submittedValues['total_amount'] = CRM_Utils_Array::value('amount', $submittedValues); + } + if ($this->_id) { + //CRM-10964 + $pId = ($this->_compId && $this->_context == 'participant') ? $this->_compId : CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $this->_id, 'participant_id', 'contribution_id'); + } + if (!$priceSetId && CRM_Utils_Array::value('total_amount', $submittedValues) && $this->_id) { + // 10117 update th line items for participants + if ($pId) { + $entityTable = 'participant'; + $entityID = $pId; + $participantParams = array( + 'fee_amount' => $submittedValues['total_amount'], + 'id' => $entityID + ); + CRM_Event_BAO_Participant::add($participantParams); + if (empty($this->_lineItems)) { + $this->_lineItems = CRM_Price_BAO_LineItem::getLineItems($entityID, 'participant',1); + } + } else { + $entityTable = 'contribution'; + $entityID = $this->_id; + } + + $lineItems = CRM_Price_BAO_LineItem::getLineItems($entityID, $entityTable); + $itemId = key($lineItems); + $fieldType = NULL; + if ($itemId && CRM_Utils_Array::value('price_field_id', $lineItems[$itemId])) { + $fieldType = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Field', $lineItems[$itemId]['price_field_id'], 'html_type'); + } + $lineItems[$itemId]['unit_price'] = $lineItems[$itemId]['line_total'] = CRM_Utils_Rule::cleanMoney(CRM_Utils_Array::value('total_amount', $submittedValues)); + $lineItems[$itemId]['id'] = $itemId; + // 10117 update th line items for participants + $this->_priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Field', $lineItems[$itemId]['price_field_id'], 'price_set_id'); + $lineItem[$this->_priceSetId] = $lineItems; + } + $isQuickConfig = 0; + if ($this->_priceSetId && CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_priceSetId, 'is_quick_config')) { + $isQuickConfig = 1; + } + //CRM-11529 for quick config backoffice transactions + //when financial_type_id is passed in form, update the + //lineitems with the financial type selected in form + if ($isQuickConfig && CRM_Utils_Array::value('financial_type_id', $submittedValues) + && CRM_Utils_Array::value($this->_priceSetId, $lineItem)) { + foreach ($lineItem[$this->_priceSetId] as &$values) { + $values['financial_type_id'] = $submittedValues['financial_type_id']; + } + } + + if (!CRM_Utils_Array::value('total_amount', $submittedValues)) { + $submittedValues['total_amount'] = CRM_Utils_Array::value('total_amount', $this->_values); + } + $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE); + + if (CRM_Utils_Array::value('soft_credit_to', $submittedValues)) { + $submittedValues['soft_credit_to'] = $submittedValues['soft_contact_id']; + } + + // set the contact, when contact is selected + if (CRM_Utils_Array::value('contact_select_id', $submittedValues)) { + $this->_contactID = $submittedValues['contact_select_id'][1]; + } + + $config = CRM_Core_Config::singleton(); + + //Credit Card Contribution. + if ($this->_mode) { + $this->processCreditCard($submittedValues, $config, $session, $pId, $lineItem); + } + else { + //Offline Contribution. + $submittedValues = $this->unsetCreditCardFields($submittedValues); + + // get the required field value only. + $formValues = $submittedValues; + $params = $ids = array(); + + $params['contact_id'] = $this->_contactID; + + $params['currency'] = $this->getCurrency($submittedValues); + + $fields = array( + 'financial_type_id', + 'contribution_status_id', + 'payment_instrument_id', + 'cancel_reason', + 'source', + 'check_number', + 'soft_credit_to', + 'pcp_made_through_id', + 'pcp_display_in_roll', + 'pcp_roll_nickname', + 'pcp_personal_note', + ); + foreach ($fields as $f) { + $params[$f] = CRM_Utils_Array::value($f, $formValues); + } + + if ($softID = CRM_Utils_Array::value('softID', $this->_values)) { + $params['softID'] = $softID; + } + //if priceset is used, no need to cleanup money + //CRM-5740 + if ($priceSetId) { + $params['skipCleanMoney'] = 1; + } + + $dates = array( + 'receive_date', + 'receipt_date', + 'cancel_date', + ); + + foreach ($dates as $d) { + $params[$d] = CRM_Utils_Date::processDate($formValues[$d], $formValues[$d . '_time'], TRUE); + } + + if (CRM_Utils_Array::value('is_email_receipt', $formValues)) { + $params['receipt_date'] = date("Y-m-d"); + } + + if ($params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Cancelled', 'name') + || $params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Refunded', 'name')) { + if (CRM_Utils_System::isNull(CRM_Utils_Array::value('cancel_date', $params))) { + $params['cancel_date'] = date("Y-m-d"); + } + } + else { + $params['cancel_date'] = $params['cancel_reason'] = 'null'; + } + + // Set is_pay_later flag for back-office offline Pending status contributions CRM-8996 + if ($params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name')) { + $params['is_pay_later'] = 1; + } + + $ids['contribution'] = $params['id'] = $this->_id; + + //Add Additional common information to formatted params + CRM_Contribute_Form_AdditionalInfo::postProcessCommon($formValues, $params, $this); + if ($pId) { + $params['contribution_mode'] = 'participant'; + $params['participant_id'] = $pId; + } + $params['line_item'] = $lineItem; + $params['payment_processor_id'] = $params['payment_processor'] = CRM_Utils_Array::value('id', $this->_paymentProcessor); + //create contribution. + if ($isQuickConfig) { + $params['is_quick_config'] = 1; + } + + // CRM-11956 + // if non_deductible_amount exists i.e. Additional Details fieldset was opened [and staff typed something] -> keep it. + if (isset($params['non_deductible_amount']) && (!empty($params['non_deductible_amount']))) { + $params['non_deductible_amount'] = $params['non_deductible_amount']; + } + // if non_deductible_amount does NOT exist - then calculate it depending on: + // $ContributionType->is_deductible and whether there is a product (premium). + else { + $contributionType = new CRM_Financial_DAO_FinancialType(); + $contributionType->id = $params['financial_type_id']; + if (!$contributionType->find(TRUE)) { + CRM_Core_Error::fatal('Could not find a system table'); + } + if ($contributionType->is_deductible) { + + if (isset($formValues['product_name'][0])) { + $selectProduct = $formValues['product_name'][0]; + } + // if there is a product - compare the value to the contribution amount + if (isset($selectProduct)) + { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $selectProduct; + $productDAO->find(TRUE); + // product value exceeds contribution amount + if ($params['total_amount'] < $productDAO->price) { + $params['non_deductible_amount'] = $params['total_amount']; + } + // product value does NOT exceed contribution amount + else { + $params['non_deductible_amount'] = $productDAO->price; + } + } + // contribution is deductible - but there is no product + else { + $params['non_deductible_amount'] = '0.00'; + } + } + // contribution is NOT deductible + else { + $params['non_deductible_amount'] = $params['total_amount']; + } + } + + $contribution = CRM_Contribute_BAO_Contribution::create($params, $ids); + + // process associated membership / participant, CRM-4395 + $relatedComponentStatusMsg = NULL; + if ($contribution->id && $this->_action & CRM_Core_Action::UPDATE) { + $relatedComponentStatusMsg = $this->updateRelatedComponent($contribution->id, + $contribution->contribution_status_id, + CRM_Utils_Array::value('contribution_status_id', + $this->_values + ) + ); + } + + //process note + if ($contribution->id && isset($formValues['note'])) { + CRM_Contribute_Form_AdditionalInfo::processNote($formValues, $this->_contactID, $contribution->id, $this->_noteID); + } + + //process premium + if ($contribution->id && isset($formValues['product_name'][0])) { + CRM_Contribute_Form_AdditionalInfo::processPremium($formValues, $contribution->id, + $this->_premiumID, $this->_options + ); + } + + //send receipt mail. + if ($contribution->id && CRM_Utils_Array::value('is_email_receipt', $formValues)) { + $formValues['contact_id'] = $this->_contactID; + $formValues['contribution_id'] = $contribution->id; + + // to get 'from email id' for send receipt + $this->fromEmailId = $formValues['from_email_address']; + $sendReceipt = CRM_Contribute_Form_AdditionalInfo::emailReceipt($this, $formValues); + } + + $pledgePaymentId = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment', + $contribution->id, + 'id', + 'contribution_id' + ); + + //update pledge payment status. + if ((($this->_ppID && $contribution->id) && $this->_action & CRM_Core_Action::ADD) || + (($pledgePaymentId) && $this->_action & CRM_Core_Action::UPDATE) + ) { + + if ($this->_ppID) { + //store contribution id in payment record. + CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_PledgePayment', $this->_ppID, 'contribution_id', $contribution->id); + } + else { + $this->_ppID = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment', + $contribution->id, + 'id', + 'contribution_id' + ); + $this->_pledgeID = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment', + $contribution->id, + 'pledge_id', + 'contribution_id' + ); + } + + $adjustTotalAmount = FALSE; + if (CRM_Utils_Array::value('option_type', $formValues) == 2) { + $adjustTotalAmount = TRUE; + } + + $updatePledgePaymentStatus = FALSE; + //do only if either the status or the amount has changed + if ($this->_action & CRM_Core_Action::ADD) { + $updatePledgePaymentStatus = TRUE; + } + elseif ($this->_action & CRM_Core_Action::UPDATE && (($this->_defaults['contribution_status_id'] != $formValues['contribution_status_id']) || + ($this->_defaults['total_amount'] != $formValues['total_amount'])) + ) { + $updatePledgePaymentStatus = TRUE; + } + + if ($updatePledgePaymentStatus) { + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($this->_pledgeID, + array($this->_ppID), + $contribution->contribution_status_id, + NULL, + $contribution->total_amount, + $adjustTotalAmount + ); + } + } + + $statusMsg = ts('The contribution record has been saved.'); + if (CRM_Utils_Array::value('is_email_receipt', $formValues) && $sendReceipt) { + $statusMsg .= ' ' . ts('A receipt has been emailed to the contributor.'); + } + + if ($relatedComponentStatusMsg) { + $statusMsg .= ' ' . $relatedComponentStatusMsg; + } + + CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success'); + //Offline Contribution ends. + } + $buttonName = $this->controller->getButtonName(); + if ($this->_context == 'standalone') { + if ($buttonName == $this->getButtonName('upload', 'new')) { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/add', + 'reset=1&action=add&context=standalone' + )); + } + else { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', + "reset=1&cid={$this->_contactID}&selectedChild=contribute" + )); + } + } + elseif ($this->_context == 'contribution' && $this->_mode && $buttonName == $this->getButtonName('upload', 'new')) { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution', + "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}&mode={$this->_mode}" + )); + } + elseif ($buttonName == $this->getButtonName('upload', 'new')) { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution', + "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}" + )); + } + } + + public function processCreditCard($submittedValues, $config, $session, $pId, $lineItem) { + $unsetParams = array( + 'trxn_id', + 'payment_instrument_id', + 'contribution_status_id', + 'cancel_date', + 'cancel_reason', + ); + foreach ($unsetParams as $key) { + if (isset($submittedValues[$key])) { + unset($submittedValues[$key]); + } + } + + //Get the rquire fields value only. + $params = $this->_params = $submittedValues; + + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($this->_params['payment_processor_id'], + $this->_mode + ); + + //get the payment processor id as per mode. + $params['payment_processor_id'] = $this->_params['payment_processor_id'] = $submittedValues['payment_processor_id'] = $this->_paymentProcessor['id']; + + $now = date('YmdHis'); + $fields = array(); + + // we need to retrieve email address + if ($this->_context == 'standalone' && CRM_Utils_Array::value('is_email_receipt', $submittedValues)) { + list($this->userDisplayName, + $this->userEmail + ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID); + $this->assign('displayName', $this->userDisplayName); + } + + //set email for primary location. + $fields['email-Primary'] = 1; + $params['email-Primary'] = $this->userEmail; + + // now set the values for the billing location. + foreach ($this->_fields as $name => $dontCare) { + $fields[$name] = 1; + } + + // also add location name to the array + $params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $params) . ' ' . CRM_Utils_Array::value('billing_last_name', $params); + $params["address_name-{$this->_bltID}"] = trim($params["address_name-{$this->_bltID}"]); + $fields["address_name-{$this->_bltID}"] = 1; + + $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $this->_contactID, + 'contact_type' + ); + + $nameFields = array('first_name', 'middle_name', 'last_name'); + foreach ($nameFields as $name) { + $fields[$name] = 1; + if (array_key_exists("billing_$name", $params)) { + $params[$name] = $params["billing_{$name}"]; + $params['preserveDBName'] = TRUE; + } + } + + if (CRM_Utils_Array::value('source', $params)) { + unset($params['source']); + } + $contactID = CRM_Contact_BAO_Contact::createProfileContact($params, $fields, + $this->_contactID, + NULL, NULL, + $ctype + ); + + // add all the additioanl payment params we need + $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]); + $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]); + + if ($this->_paymentProcessor['payment_type'] & CRM_Core_Payment::PAYMENT_TYPE_CREDIT_CARD) { + $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params); + $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params); + } + $this->_params['ip_address'] = CRM_Utils_System::ipAddress(); + $this->_params['amount'] = $this->_params['total_amount']; + $this->_params['amount_level'] = 0; + $this->_params['currencyID'] = CRM_Utils_Array::value('currency', + $this->_params, + $config->defaultCurrency + ); + $this->_params['payment_action'] = 'Sale'; + if (CRM_Utils_Array::value('receive_date', $this->_params)) { + $this->_params['receive_date'] = CRM_Utils_Date::processDate($this->_params['receive_date'], $this->_params['receive_date_time']); + } + + if (CRM_Utils_Array::value('soft_credit_to', $params)) { + $this->_params['soft_credit_to'] = $params['soft_credit_to']; + $this->_params['pcp_made_through_id'] = $params['pcp_made_through_id']; + } + + $this->_params['pcp_display_in_roll'] = CRM_Utils_Array::value('pcp_display_in_roll', $params); + $this->_params['pcp_roll_nickname'] = CRM_Utils_Array::value('pcp_roll_nickname', $params); + $this->_params['pcp_personal_note'] = CRM_Utils_Array::value('pcp_personal_note', $params); + + //Add common data to formatted params + CRM_Contribute_Form_AdditionalInfo::postProcessCommon($params, $this->_params, $this); + + if (empty($this->_params['invoice_id'])) { + $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE)); + } + else { + $this->_params['invoiceID'] = $this->_params['invoice_id']; + } + + // at this point we've created a contact and stored its address etc + // all the payment processors expect the name and address to be in the + // so we copy stuff over to first_name etc. + $paymentParams = $this->_params; + $paymentParams['contactID'] = $this->_contactID; + CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, TRUE); + + $contributionType = new CRM_Financial_DAO_FinancialType(); + $contributionType->id = $params['financial_type_id']; + if (!$contributionType->find(TRUE)) { + CRM_Core_Error::fatal('Could not find a system table'); + } + + // add some financial type details to the params list + // if folks need to use it + $paymentParams['contributionType_name'] = $this->_params['contributionType_name'] = $contributionType->name; + $paymentParams['contributionPageID'] = NULL; + if (CRM_Utils_Array::value('is_email_receipt', $this->_params)) { + $paymentParams['email'] = $this->userEmail; + $paymentParams['is_email_receipt'] = 1; + } + else { + $paymentParams['is_email_receipt'] = 0; + $this->_params['is_email_receipt'] = 0; + } + if (CRM_Utils_Array::value('receive_date', $this->_params)) { + $paymentParams['receive_date'] = $this->_params['receive_date']; + } + if (CRM_Utils_Array::value('receive_date', $this->_params)) { + $paymentParams['receive_date'] = $this->_params['receive_date']; + } + + $result = NULL; + + // For recurring contribution, create Contribution Record first. + // Contribution ID, Recurring ID and Contact ID needed + // When we get a callback from the payment processor, CRM-7115 + if (CRM_Utils_Array::value('is_recur', $paymentParams)) { + $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($this, + $this->_params, + $result, + $this->_contactID, + $contributionType, + FALSE, + TRUE, + FALSE + ); + $paymentParams['contributionID'] = $contribution->id; + $paymentParams['contributionTypeID'] = $contribution->financial_type_id; + $paymentParams['contributionPageID'] = $contribution->contribution_page_id; + $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id; + } + + if ($paymentParams['amount'] > 0.0) { + // force a reget of the payment processor in case the form changed it, CRM-7179 + $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this, TRUE); + $result = $payment->doDirectPayment($paymentParams); + } + + if (is_a($result, 'CRM_Core_Error')) { + //make sure to cleanup db for recurring case. + if (CRM_Utils_Array::value('contributionID', $paymentParams)) { + CRM_Core_Error::debug_log_message(CRM_Core_Error::getMessages($result) . "contact id={$this->_contactID} (deleting contribution {$paymentParams['contributionID']}"); + CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']); + } + if (CRM_Utils_Array::value('contributionRecurID', $paymentParams)) { + CRM_Core_Error::debug_log_message(CRM_Core_Error::getMessages($result) . "contact id={$this->_contactID} (deleting recurring contribution {$paymentParams['contributionRecurID']}"); + CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']); + } + + //set the contribution mode. + $urlParams = "action=add&cid={$this->_contactID}"; + if ($this->_mode) { + $urlParams .= "&mode={$this->_mode}"; + } + if (!empty($this->_ppID)) { + $urlParams .= "&context=pledge&ppid={$this->_ppID}"; + } + CRM_Core_Error::displaySessionError($result); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/contribution', $urlParams)); + } + + if ($result) { + $this->_params = array_merge($this->_params, $result); + } + + $this->_params['receive_date'] = $now; + + if (CRM_Utils_Array::value('is_email_receipt', $this->_params)) { + $this->_params['receipt_date'] = $now; + } + else { + $this->_params['receipt_date'] = CRM_Utils_Date::processDate($this->_params['receipt_date'], + $params['receipt_date_time'], TRUE + ); + } + + $this->set('params', $this->_params); + $this->assign('trxn_id', $result['trxn_id']); + $this->assign('receive_date', $this->_params['receive_date']); + + // result has all the stuff we need + // lets archive it to a financial transaction + if ($contributionType->is_deductible) { + $this->assign('is_deductible', TRUE); + $this->set('is_deductible', TRUE); + } + + // set source if not set + if (empty($this->_params['source'])) { + $userID = $session->get('userID'); + $userSortName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $userID, + 'sort_name' + ); + $this->_params['source'] = ts('Submit Credit Card Payment by: %1', array(1 => $userSortName)); + } + + // build custom data getFields array + $customFieldsContributionType = CRM_Core_BAO_CustomField::getFields('Contribution', FALSE, FALSE, + CRM_Utils_Array::value('financial_type_id', $params) + ); + $customFields = CRM_Utils_Array::crmArrayMerge($customFieldsContributionType, + CRM_Core_BAO_CustomField::getFields('Contribution', FALSE, FALSE, NULL, NULL, TRUE) + ); + $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $this->_id, + 'Contribution' + ); + + + if (!CRM_Utils_Array::value('is_recur', $paymentParams)) { + $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($this, + $this->_params, + $result, + $this->_contactID, + $contributionType, + FALSE, FALSE, FALSE + ); + } + + //send receipt mail. + if ($contribution->id && + CRM_Utils_Array::value('is_email_receipt', $this->_params) + ) { + $this->_params['trxn_id'] = CRM_Utils_Array::value('trxn_id', $result); + $this->_params['contact_id'] = $this->_contactID; + $this->_params['contribution_id'] = $contribution->id; + $sendReceipt = CRM_Contribute_Form_AdditionalInfo::emailReceipt($this, $this->_params, TRUE); + } + + //process the note + if ($contribution->id && isset($params['note'])) { + CRM_Contribute_Form_AdditionalInfo::processNote($params, $contactID, $contribution->id, NULL); + } + //process premium + if ($contribution->id && isset($params['product_name'][0])) { + CRM_Contribute_Form_AdditionalInfo::processPremium($params, $contribution->id, NULL, $this->_options); + } + + //update pledge payment status. + if ($this->_ppID && $contribution->id) { + //store contribution id in payment record. + CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_PledgePayment', $this->_ppID, 'contribution_id', $contribution->id); + + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($this->_pledgeID, + array($this->_ppID), + $contribution->contribution_status_id, + NULL, + $contribution->total_amount + ); + } + + if ($contribution->id) { + $statusMsg = ts('The contribution record has been processed.'); + if (CRM_Utils_Array::value('is_email_receipt', $this->_params) && $sendReceipt) { + $statusMsg .= ' ' . ts('A receipt has been emailed to the contributor.'); + } + CRM_Core_Session::setStatus($statusMsg, ts('Complete'), 'success'); + } + } +} + diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php new file mode 100644 index 0000000000..271d89bcf6 --- /dev/null +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -0,0 +1,1714 @@ +_lineItem = $this->get('lineItem'); + $this->_paymentProcessor = $this->get('paymentProcessor'); + + if ($this->_contributeMode == 'express') { + // rfp == redirect from paypal + $rfp = CRM_Utils_Request::retrieve('rfp', 'Boolean', + CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET' + ); + if ($rfp) { + $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this); + $expressParams = $payment->getExpressCheckoutDetails($this->get('token')); + + $this->_params['payer'] = $expressParams['payer']; + $this->_params['payer_id'] = $expressParams['payer_id']; + $this->_params['payer_status'] = $expressParams['payer_status']; + + CRM_Core_Payment_Form::mapParams($this->_bltID, $expressParams, $this->_params, FALSE); + + // fix state and country id if present + if (!empty($this->_params["billing_state_province_id-{$this->_bltID}"]) && $this->_params["billing_state_province_id-{$this->_bltID}"]) { + $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]); + } + if (!empty($this->_params["billing_country_id-{$this->_bltID}"]) && $this->_params["billing_country_id-{$this->_bltID}"]) { + $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]); + } + + // set a few other parameters for PayPal + $this->_params['token'] = $this->get('token'); + + $this->_params['amount'] = $this->get('amount'); + + if (!empty($this->_membershipBlock)){ + $this->_params['selectMembership'] = $this->get('selectMembership'); + } + // we use this here to incorporate any changes made by folks in hooks + $this->_params['currencyID'] = $config->defaultCurrency; + + $this->_params['payment_action'] = 'Sale'; + + // also merge all the other values from the profile fields + $values = $this->controller->exportValues('Main'); + $skipFields = array( + 'amount', 'amount_other', + "billing_street_address-{$this->_bltID}", + "billing_city-{$this->_bltID}", + "billing_state_province_id-{$this->_bltID}", + "billing_postal_code-{$this->_bltID}", + "billing_country_id-{$this->_bltID}", + ); + foreach ($values as $name => $value) { + // skip amount field + if (!in_array($name, $skipFields)) { + $this->_params[$name] = $value; + } + } + $this->set('getExpressCheckoutDetails', $this->_params); + } + else { + $this->_params = $this->get('getExpressCheckoutDetails'); + } + } + else { + $this->_params = $this->controller->exportValues('Main'); + + if (!empty($this->_params["billing_state_province_id-{$this->_bltID}"])) { + $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]); + } + if (!empty($this->_params["billing_country_id-{$this->_bltID}"])) { + $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]); + } + + if (isset($this->_params['credit_card_exp_date'])) { + $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params); + $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params); + } + $this->_params['ip_address'] = $_SERVER['REMOTE_ADDR']; + // hack for safari + if ($this->_params['ip_address'] == '::1') { + $this->_params['ip_address'] = '127.0.0.1'; + } + $this->_params['amount'] = $this->get('amount'); + + $this->_useForMember = $this->get('useForMember'); + + if (isset($this->_params['amount'])) { + $priceField = new CRM_Price_DAO_Field(); + $priceField->price_set_id = $this->_params['priceSetId']; + $priceField->orderBy('weight'); + $priceField->find(); + $contriPriceId = NULL; + $isQuickConfig = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_params['priceSetId'], 'is_quick_config'); + while ($priceField->fetch()) { + if ($priceField->name == "contribution_amount") { + $contriPriceId = $priceField->id; + } + if ($isQuickConfig && !empty($this->_params["price_{$priceField->id}"])) { + if ($this->_values['fee'][$priceField->id]['html_type'] != 'Text') { + $this->_params['amount_level'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_FieldValue', + $this->_params["price_{$priceField->id}"], 'label'); + } + if ($priceField->name == "membership_amount") { + $this->_params['selectMembership'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_FieldValue', + $this->_params["price_{$priceField->id}"], 'membership_type_id'); + } + } // if seperate payment we set contribution amount to be null, so that it will not show contribution amount same as membership amount. + elseif ((CRM_Utils_Array::value('is_separate_payment', $this->_membershipBlock)) + && ($this->_values['fee'][$priceField->id]['name'] == "other_amount") + && CRM_Utils_Array::value("price_{$contriPriceId}", $this->_params) < 1 + && !CRM_Utils_Array::value("price_{$priceField->id}", $this->_params)) { + $this->_params['amount'] = null; + } + } + } + $this->_params['currencyID'] = $config->defaultCurrency; + $this->_params['payment_action'] = 'Sale'; + } + + $this->_params['is_pay_later'] = $this->get('is_pay_later'); + $this->assign('is_pay_later', $this->_params['is_pay_later']); + if ($this->_params['is_pay_later']) { + $this->assign('pay_later_receipt', $this->_values['pay_later_receipt']); + } + // if onbehalf-of-organization + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $this->_params)) { + if (CRM_Utils_Array::value('org_option', $this->_params) && + CRM_Utils_Array::value('organization_id', $this->_params) + ) { + if (CRM_Utils_Array::value('onbehalfof_id', $this->_params)) { + $this->_params['organization_id'] = $this->_params['onbehalfof_id']; + } + } + + $this->_params['organization_name'] = $this->_params['onbehalf']['organization_name']; + $addressBlocks = array( + 'street_address', 'city', 'state_province', + 'postal_code', 'country', 'supplemental_address_1', + 'supplemental_address_2', 'supplemental_address_3', + 'postal_code_suffix', 'geo_code_1', 'geo_code_2', 'address_name', + ); + + $blocks = array('email', 'phone', 'im', 'url', 'openid'); + foreach ($this->_params['onbehalf'] as $loc => $value) { + $field = $typeId = NULL; + if (strstr($loc, '-')) { + list($field, $locType) = explode('-', $loc); + } + + if (in_array($field, $addressBlocks)) { + if ($locType == 'Primary') { + $defaultLocationType = CRM_Core_BAO_LocationType::getDefault(); + $locType = $defaultLocationType->id; + } + + if ($field == 'country') { + $value = CRM_Core_PseudoConstant::countryIsoCode($value); + } + elseif ($field == 'state_province') { + $value = CRM_Core_PseudoConstant::stateProvinceAbbreviation($value); + } + + $isPrimary = 1; + if (isset($this->_params['onbehalf_location']['address']) + && count($this->_params['onbehalf_location']['address']) > 0) { + $isPrimary = 0; + } + + $this->_params['onbehalf_location']['address'][$locType][$field] = $value; + if (!CRM_Utils_Array::value('is_primary', $this->_params['onbehalf_location']['address'][$locType])) { + $this->_params['onbehalf_location']['address'][$locType]['is_primary'] = $isPrimary; + } + $this->_params['onbehalf_location']['address'][$locType]['location_type_id'] = $locType; + } + elseif (in_array($field, $blocks)) { + if (!$typeId || is_numeric($typeId)) { + $blockName = $fieldName = $field; + $locationType = 'location_type_id'; + if ( $locType == 'Primary' ) { + $defaultLocationType = CRM_Core_BAO_LocationType::getDefault(); + $locationValue = $defaultLocationType->id; + } + else { + $locationValue = $locType; + } + $locTypeId = ''; + $phoneExtField = array(); + + if ($field == 'url') { + $blockName = 'website'; + $locationType = 'website_type_id'; + $locationValue = CRM_Utils_Array::value("{$loc}-website_type_id", $this->_params['onbehalf']); + } + elseif ($field == 'im') { + $fieldName = 'name'; + $locTypeId = 'provider_id'; + $typeId = $this->_params['onbehalf']["{$loc}-provider_id"]; + } + elseif ($field == 'phone') { + list($field, $locType, $typeId) = explode('-', $loc); + $locTypeId = 'phone_type_id'; + + //check if extension field exists + $extField = str_replace('phone','phone_ext', $loc); + if (isset($this->_params['onbehalf'][$extField])) { + $phoneExtField = array('phone_ext' => $this->_params['onbehalf'][$extField]); + } + } + + $isPrimary = 1; + if ( isset ($this->_params['onbehalf_location'][$blockName] ) + && count( $this->_params['onbehalf_location'][$blockName] ) > 0 ) { + $isPrimary = 0; + } + if ($locationValue) { + $blockValues = array( + $fieldName => $value, + $locationType => $locationValue, + 'is_primary' => $isPrimary, + ); + + if ($locTypeId) { + $blockValues = array_merge($blockValues, array($locTypeId => $typeId)); + } + if (!empty($phoneExtField)) { + $blockValues = array_merge($blockValues, $phoneExtField); + } + + $this->_params['onbehalf_location'][$blockName][] = $blockValues; + } + } + } + elseif (strstr($loc, 'custom')) { + if ($value && isset($this->_params['onbehalf']["{$loc}_id"])) { + $value = $this->_params['onbehalf']["{$loc}_id"]; + } + $this->_params['onbehalf_location']["{$loc}"] = $value; + } + else { + if ($loc == 'contact_sub_type') { + $this->_params['onbehalf_location'][$loc] = $value; + } + else { + $this->_params['onbehalf_location'][$field] = $value; + } + } + } + } + elseif (CRM_Utils_Array::value('is_for_organization', $this->_values)) { + // no on behalf of an organization, CRM-5519 + // so reset loc blocks from main params. + foreach (array( + 'phone', 'email', 'address') as $blk) { + if (isset($this->_params[$blk])) { + unset($this->_params[$blk]); + } + } + } + + // if auto renew checkbox is set, initiate a open-ended recurring membership + if ((CRM_Utils_Array::value('selectMembership', $this->_params) || + CRM_Utils_Array::value('priceSetId', $this->_params) + ) && + CRM_Utils_Array::value('is_recur', $this->_paymentProcessor) && + CRM_Utils_Array::value('auto_renew', $this->_params) && + !CRM_Utils_Array::value('is_recur', $this->_params) && + !CRM_Utils_Array::value('frequency_interval', $this->_params) + ) { + + $this->_params['is_recur'] = $this->_values['is_recur'] = 1; + // check if price set is not quick config + if (CRM_Utils_Array::value('priceSetId', $this->_params) && !$isQuickConfig) { + list($this->_params['frequency_interval'], $this->_params['frequency_unit']) = CRM_Price_BAO_Set::getRecurDetails($this->_params['priceSetId']); + } + else { + // FIXME: set interval and unit based on selected membership type + $this->_params['frequency_interval'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', + $this->_params['selectMembership'], 'duration_interval' + ); + $this->_params['frequency_unit'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', + $this->_params['selectMembership'], 'duration_unit' + ); + } + } + + if ($this->_pcpId) { + $params = $this->processPcp($this, $this->_params); + $this->_params = $params; + } + $this->_params['invoiceID'] = $this->get('invoiceID'); + + //carry campaign from profile. + if (array_key_exists('contribution_campaign_id', $this->_params)) { + $this->_params['campaign_id'] = $this->_params['contribution_campaign_id']; + } + + $this->set('params', $this->_params); + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $this->assignToTemplate(); + + $params = $this->_params; + $honor_block_is_active = $this->get('honor_block_is_active'); + // make sure we have values for it + if ($honor_block_is_active && + ((!empty($params['honor_first_name']) && !empty($params['honor_last_name'])) || + (!empty($params['honor_email'])) + ) + ) { + $this->assign('honor_block_is_active', $honor_block_is_active); + $this->assign('honor_block_title', CRM_Utils_Array::value('honor_block_title', $this->_values)); + + $prefix = CRM_Core_PseudoConstant::individualPrefix(); + $honor = CRM_Core_PseudoConstant::honor(); + $this->assign('honor_type', CRM_Utils_Array::value($params['honor_type_id'], $honor)); + $this->assign('honor_prefix', CRM_Utils_Array::value($params['honor_prefix_id'], $prefix)); + $this->assign('honor_first_name', $params['honor_first_name']); + $this->assign('honor_last_name', $params['honor_last_name']); + $this->assign('honor_email', $params['honor_email']); + } + $this->assign('receiptFromEmail', CRM_Utils_Array::value('receipt_from_email', $this->_values)); + $amount_block_is_active = $this->get('amount_block_is_active'); + $this->assign('amount_block_is_active', $amount_block_is_active); + + if (CRM_Utils_Array::value('selectProduct', $params) && $params['selectProduct'] != 'no_thanks') { + $option = CRM_Utils_Array::value('options_' . $params['selectProduct'], $params); + $productID = $params['selectProduct']; + CRM_Contribute_BAO_Premium::buildPremiumBlock($this, $this->_id, FALSE, + $productID, $option + ); + $this->set('productID', $productID); + $this->set('option', $option); + } + $config = CRM_Core_Config::singleton(); + if (in_array('CiviMember', $config->enableComponents)) { + if (isset($params['selectMembership']) && + $params['selectMembership'] != 'no_thanks' + ) { + CRM_Member_BAO_Membership::buildMembershipBlock($this, + $this->_id, + FALSE, + $params['selectMembership'], + FALSE, NULL, + $this->_membershipContactID + ); + } + else { + $this->assign('membershipBlock', FALSE); + } + } + $this->buildCustom($this->_values['custom_pre_id'], 'customPre', TRUE); + $this->buildCustom($this->_values['custom_post_id'], 'customPost', TRUE); + + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $params)) { + $ufJoinParams = array( + 'module' => 'onBehalf', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $this->_id, + ); + $OnBehalfProfile = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + $profileId = $OnBehalfProfile[0]; + + $fieldTypes = array('Contact', 'Organization'); + $contactSubType = CRM_Contact_BAO_ContactType::subTypes('Organization'); + $fieldTypes = array_merge($fieldTypes, $contactSubType); + if (is_array($this->_membershipBlock) && !empty($this->_membershipBlock)) { + $fieldTypes = array_merge($fieldTypes, array('Membership')); + } + else { + $fieldTypes = array_merge($fieldTypes, array('Contribution')); + } + + $this->buildCustom($profileId, 'onbehalfProfile', TRUE, TRUE, $fieldTypes); + } + + $this->_separateMembershipPayment = $this->get('separateMembershipPayment'); + $this->assign('is_separate_payment', $this->_separateMembershipPayment); + if ($this->_priceSetId && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_priceSetId, 'is_quick_config')) { + $this->assign('lineItem', $this->_lineItem); + } else { + $this->assign('is_quick_config', 1); + $this->_params['is_quick_config'] = 1; + } + $this->assign('priceSetID', $this->_priceSetId); + $paymentProcessorType = CRM_Core_PseudoConstant::paymentProcessorType(false, null, 'name'); + if ($this->_paymentProcessor['payment_processor_type_id'] == CRM_Utils_Array::key('Google_Checkout', $paymentProcessorType) + && !$this->_params['is_pay_later'] && !($this->_amount == 0) + ) { + $this->_checkoutButtonName = $this->getButtonName('next', 'checkout'); + $this->add('image', + $this->_checkoutButtonName, + $this->_paymentProcessor['url_button'], + array('class' => 'form-submit') + ); + + $this->addButtons(array( + array( + 'type' => 'back', + 'name' => ts('<< Go Back'), + ), + ) + ); + } + else { + if ($this->_contributeMode == 'notify' || !$this->_values['is_monetary'] || + $this->_amount <= 0.0 || $this->_params['is_pay_later'] || + ($this->_separateMembershipPayment && $this->_amount <= 0.0) + ) { + $contribButton = ts('Continue >>'); + $this->assign('button', ts('Continue')); + } + else { + $contribButton = ts('Make Contribution'); + $this->assign('button', ts('Make Contribution')); + } + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => $contribButton, + 'spacing' => '         ', + 'isDefault' => TRUE, + 'js' => array('onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"), + ), + array( + 'type' => 'back', + 'name' => ts('Go Back'), + ), + ) + ); + } + + $defaults = array(); + $fields = array(); + foreach ($this->_fields as $name => $dontCare) { + if ($name == 'onbehalf') { + foreach ($dontCare as $key => $value) { + $fields['onbehalf'][$key] = 1; + } + } + else { + $fields[$name] = 1; + } + } + $fields["billing_state_province-{$this->_bltID}"] = $fields["billing_country-{$this->_bltID}"] = $fields["email-{$this->_bltID}"] = 1; + + $contact = $this->_params; + foreach ($fields as $name => $dontCare) { + if ($name == 'onbehalf') { + foreach ($dontCare as $key => $value) { + if (isset($contact['onbehalf'][$key])) { + $defaults[$key] = $contact['onbehalf'][$key]; + } + if (isset($contact['onbehalf']["{$key}_id"])) { + $defaults["{$key}_id"] = $contact['onbehalf']["{$key}_id"]; + } + } + } + elseif (isset($contact[$name])) { + $defaults[$name] = $contact[$name]; + if (substr($name, 0, 7) == 'custom_') { + $timeField = "{$name}_time"; + if (isset($contact[$timeField])) { + $defaults[$timeField] = $contact[$timeField]; + } + if (isset($contact["{$name}_id"])) { + $defaults["{$name}_id"] = $contact["{$name}_id"]; + } + } + elseif (in_array($name, array('addressee', 'email_greeting', 'postal_greeting')) + && CRM_Utils_Array::value($name . '_custom', $contact) + ) { + $defaults[$name . '_custom'] = $contact[$name . '_custom']; + } + } + } + + $this->assign('useForMember', $this->get('useForMember')); + + // now fix all state country selectors + CRM_Core_BAO_Address::fixAllStateSelects($this, $defaults); + + $this->setDefaults($defaults); + + $this->freeze(); + } + + /** + * overwrite action, since we are only showing elements in frozen mode + * no help display needed + * + * @return int + * @access public + */ + function getAction() { + if ($this->_action & CRM_Core_Action::PREVIEW) { + return CRM_Core_Action::VIEW | CRM_Core_Action::PREVIEW; + } + else { + return CRM_Core_Action::VIEW; + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return void + */ + function setDefaultValues() {} + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + $config = CRM_Core_Config::singleton(); + $contactID = $this->_userID; + + // add a description field at the very beginning + $this->_params['description'] = ts('Online Contribution') . ': ' . (($this->_pcpInfo['title']) ? $this->_pcpInfo['title'] : $this->_values['title']); + + // also add accounting code + $this->_params['accountingCode'] = CRM_Utils_Array::value('accountingCode', + $this->_values + ); + + // fix currency ID + $this->_params['currencyID'] = $config->defaultCurrency; + + $premiumParams = $membershipParams = $tempParams = $params = $this->_params; + + //carry payment processor id. + if ($paymentProcessorId = CRM_Utils_Array::value('id', $this->_paymentProcessor)) { + $this->_params['payment_processor_id'] = $paymentProcessorId; + foreach (array( + 'premiumParams', 'membershipParams', 'tempParams', 'params') as $p) { + ${$p}['payment_processor_id'] = $paymentProcessorId; + } + } + + $fields = array(); + + if (CRM_Utils_Array::value('image_URL', $params)) { + CRM_Contact_BAO_Contact::processImageParams($params); + } + + // set email for primary location. + $fields['email-Primary'] = 1; + + // get the add to groups + $addToGroups = array(); + + // now set the values for the billing location. + foreach ($this->_fields as $name => $value) { + $fields[$name] = 1; + + // get the add to groups for uf fields + if (CRM_Utils_Array::value('add_to_group_id', $value)) { + $addToGroups[$value['add_to_group_id']] = $value['add_to_group_id']; + } + } + + if (!array_key_exists('first_name', $fields)) { + $nameFields = array('first_name', 'middle_name', 'last_name'); + foreach ($nameFields as $name) { + $fields[$name] = 1; + if (array_key_exists("billing_$name", $params)) { + $params[$name] = $params["billing_{$name}"]; + $params['preserveDBName'] = TRUE; + } + } + } + + // billing email address + $fields["email-{$this->_bltID}"] = 1; + + //unset the billing parameters if it is pay later mode + //to avoid creation of billing location + if ($params['is_pay_later']) { + $billingFields = array( + 'billing_first_name', + 'billing_middle_name', + 'billing_last_name', + "billing_street_address-{$this->_bltID}", + "billing_city-{$this->_bltID}", + "billing_state_province-{$this->_bltID}", + "billing_state_province_id-{$this->_bltID}", + "billing_postal_code-{$this->_bltID}", + "billing_country-{$this->_bltID}", + "billing_country_id-{$this->_bltID}", + ); + + foreach ($billingFields as $value) { + unset($params[$value]); + unset($fields[$value]); + } + } + + // if onbehalf-of-organization contribution, take out + // organization params in a separate variable, to make sure + // normal behavior is continued. And use that variable to + // process on-behalf-of functionality. + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $this->_params)) { + $behalfOrganization = array(); + $orgFields = array('organization_name', 'organization_id', 'org_option'); + foreach ($orgFields as $fld) { + if (array_key_exists($fld, $params)) { + $behalfOrganization[$fld] = $params[$fld]; + unset($params[$fld]); + } + } + + if (is_array($params['onbehalf']) && !empty($params['onbehalf'])) { + foreach ($params['onbehalf'] as $fld => $values) { + if (strstr($fld, 'custom_')) { + $behalfOrganization[$fld] = $values; + } + elseif (!(strstr($fld, '-'))) { + if (in_array($fld, array( + 'contribution_campaign_id', 'member_campaign_id'))) { + $fld = 'campaign_id'; + } + else { + $behalfOrganization[$fld] = $values; + } + $this->_params[$fld] = $values; + } + } + } + + if (array_key_exists('onbehalf_location', $params) && is_array($params['onbehalf_location'])) { + foreach ($params['onbehalf_location'] as $block => $vals) { + //fix for custom data (of type checkbox, multi-select) + if ( substr($block, 0, 7) == 'custom_' ) { + continue; + } + // fix the index of block elements + if (is_array($vals) ) { + foreach ( $vals as $key => $val ) { + //dont adjust the index of address block as + //it's index is WRT to location type + $newKey = ($block == 'address') ? $key : ++$key; + $behalfOrganization[$block][$newKey] = $val; + } + } + } + unset($params['onbehalf_location']); + } + if (CRM_Utils_Array::value('onbehalf[image_URL]', $params)) { + $behalfOrganization['image_URL'] = $params['onbehalf[image_URL]']; + } + } + + // check for profile double opt-in and get groups to be subscribed + $subscribeGroupIds = CRM_Core_BAO_UFGroup::getDoubleOptInGroupIds($params, $contactID); + + // since we are directly adding contact to group lets unset it from mailing + if (!empty($addToGroups)) { + foreach ($addToGroups as $groupId) { + if (isset($subscribeGroupIds[$groupId])) { + unset($subscribeGroupIds[$groupId]); + } + } + } + + foreach ($addToGroups as $k) { + if (array_key_exists($k, $subscribeGroupIds)) { + unset($addToGroups[$k]); + } + } + + if (!isset($contactID)) { + $dupeParams = $params; + if (CRM_Utils_Array::value('onbehalf', $dupeParams)) { + unset($dupeParams['onbehalf']); + } + + $dedupeParams = CRM_Dedupe_Finder::formatParams($dupeParams, 'Individual'); + $dedupeParams['check_permission'] = FALSE; + $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual'); + + // if we find more than one contact, use the first one + $contact_id = CRM_Utils_Array::value(0, $ids); + + // Fetch default greeting id's if creating a contact + if (!$contact_id) { + foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) { + if (!isset($params[$greeting])) { + $params[$greeting] = CRM_Contact_BAO_Contact_Utils::defaultGreeting('Individual', $greeting); + } + } + } + + $contactID = &CRM_Contact_BAO_Contact::createProfileContact($params, + $fields, + $contact_id, + $addToGroups, + NULL, + NULL, + TRUE + ); + } + else { + $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'contact_type'); + $contactID = &CRM_Contact_BAO_Contact::createProfileContact($params, + $fields, + $contactID, + $addToGroups, + NULL, + $ctype, + TRUE + ); + } + + // Make the contact ID associated with the contribution available at the Class level. + // Also make available to the session. + $this->set('contactID', $contactID); + $this->_contactID = $contactID; + + //get email primary first if exist + $subscribtionEmail = array('email' => CRM_Utils_Array::value('email-Primary', $params)); + if (!$subscribtionEmail['email']) { + $subscribtionEmail['email'] = CRM_Utils_Array::value("email-{$this->_bltID}", $params); + } + // subscribing contact to groups + if (!empty($subscribeGroupIds) && $subscribtionEmail['email']) { + CRM_Mailing_Event_BAO_Subscribe::commonSubscribe($subscribeGroupIds, $subscribtionEmail, $contactID); + } + + // If onbehalf-of-organization contribution / signup, add organization + // and it's location. + if (isset($params['hidden_onbehalf_profile']) && isset($behalfOrganization['organization_name'])) { + $ufFields = array(); + foreach ($this->_fields['onbehalf'] as $name => $value) { + $ufFields[$name] = 1; + } + self::processOnBehalfOrganization($behalfOrganization, $contactID, $this->_values, + $this->_params, $ufFields + ); + } + + // lets store the contactID in the session + // for things like tell a friend + $session = CRM_Core_Session::singleton(); + if (!$session->get('userID')) { + $session->set('transaction.userID', $contactID); + } + else { + $session->set('transaction.userID', NULL); + } + + $this->_useForMember = $this->get('useForMember'); + + // store the fact that this is a membership and membership type is selected + $processMembership = FALSE; + if ((CRM_Utils_Array::value('selectMembership', $membershipParams) && + $membershipParams['selectMembership'] != 'no_thanks' + ) || + $this->_useForMember + ) { + $processMembership = TRUE; + + if (!$this->_useForMember) { + $this->assign('membership_assign', TRUE); + $this->set('membershipTypeID', $this->_params['selectMembership']); + } + + if ($this->_action & CRM_Core_Action::PREVIEW) { + $membershipParams['is_test'] = 1; + } + if ($this->_params['is_pay_later']) { + $membershipParams['is_pay_later'] = 1; + } + } + + if ($processMembership) { + CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $membershipParams, TRUE); + + // added new parameter for cms user contact id, needed to distinguish behaviour for on behalf of sign-ups + if (isset($this->_params['related_contact'])) { + $membershipParams['cms_contactID'] = $this->_params['related_contact']; + } + else { + $membershipParams['cms_contactID'] = $contactID; + } + + //inherit campaign from contirb page. + if (!array_key_exists('campaign_id', $membershipParams)) { + $membershipParams['campaign_id'] = CRM_Utils_Array::value('campaign_id', $this->_values); + } + + if (!empty($membershipParams['onbehalf']) && + is_array($membershipParams['onbehalf']) && + CRM_Utils_Array::value('member_campaign_id', $membershipParams['onbehalf'])) { + $this->_params['campaign_id'] = $membershipParams['onbehalf']['member_campaign_id']; + } + + $customFieldsFormatted = $fieldTypes = array(); + if (!empty($membershipParams['onbehalf']) && + is_array($membershipParams['onbehalf'])) { + foreach ($membershipParams['onbehalf'] as $key => $value) { + if (strstr($key, 'custom_')) { + $customFieldId = explode('_', $key); + CRM_Core_BAO_CustomField::formatCustomField( + $customFieldId[1], + $customFieldsFormatted, + $value, + 'Membership', + NULL, + $contactID + ); + } + } + $fieldTypes = array('Contact', 'Organization', 'Membership'); + } + + $priceFieldIds = $this->get('memberPriceFieldIDS'); + + if (!empty($priceFieldIds)) { + $contributionTypeID = CRM_Core_DAO::getFieldValue( 'CRM_Price_DAO_Set', $priceFieldIds['id'], 'financial_type_id' ); + unset($priceFieldIds['id']); + $membershipTypeIds = array(); + $membershipTypeTerms = array(); + foreach ($priceFieldIds as $priceFieldId) { + if ($id = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_FieldValue', $priceFieldId, 'membership_type_id')) { + $membershipTypeIds[] = $id; + $term = 1; + if ($term = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_FieldValue', $priceFieldId, 'membership_num_terms')) { + $membershipTypeTerms[$id] = ($term > 1) ? $term : 1; + } + else { + $membershipTypeTerms[$id] = 1; + } + } + } + $membershipParams['selectMembership'] = $membershipTypeIds; + $membershipParams['financial_type_id'] = $contributionTypeID; + $membershipParams['types_terms'] = $membershipTypeTerms; + } + if (CRM_Utils_Array::value('selectMembership', $membershipParams)) { + CRM_Member_BAO_Membership::postProcessMembership($membershipParams, $contactID, + $this, $premiumParams, $customFieldsFormatted, + $fieldTypes + ); + } + } + else { + // at this point we've created a contact and stored its address etc + // all the payment processors expect the name and address to be in the + // so we copy stuff over to first_name etc. + $paymentParams = $this->_params; + $contributionTypeId = $this->_values['financial_type_id']; + + $fieldTypes = array(); + if (!empty($paymentParams['onbehalf']) && + is_array($paymentParams['onbehalf']) + ) { + foreach ($paymentParams['onbehalf'] as $key => $value) { + if (strstr($key, 'custom_')) { + $this->_params[$key] = $value; + } + } + $fieldTypes = array('Contact', 'Organization', 'Contribution'); + } + + CRM_Contribute_BAO_Contribution_Utils::processConfirm($this, $paymentParams, + $premiumParams, $contactID, + $contributionTypeId, + 'contribution', + $fieldTypes + ); + } + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcessPremium($premiumParams, $contribution) { + // assigning Premium information to receipt tpl + $selectProduct = CRM_Utils_Array::value('selectProduct', $premiumParams); + if ($selectProduct && + $selectProduct != 'no_thanks' + ) { + $startDate = $endDate = ""; + $this->assign('selectPremium', TRUE); + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $selectProduct; + $productDAO->find(TRUE); + $this->assign('product_name', $productDAO->name); + $this->assign('price', $productDAO->price); + $this->assign('sku', $productDAO->sku); + $this->assign('option', CRM_Utils_Array::value('options_' . $premiumParams['selectProduct'], $premiumParams)); + + $periodType = $productDAO->period_type; + + if ($periodType) { + $fixed_period_start_day = $productDAO->fixed_period_start_day; + $duration_unit = $productDAO->duration_unit; + $duration_interval = $productDAO->duration_interval; + if ($periodType == 'rolling') { + $startDate = date('Y-m-d'); + } + elseif ($periodType == 'fixed') { + if ($fixed_period_start_day) { + $date = explode('-', date('Y-m-d')); + $month = substr($fixed_period_start_day, 0, strlen($fixed_period_start_day) - 2); + $day = substr($fixed_period_start_day, -2) . "
    "; + $year = $date[0]; + $startDate = $year . '-' . $month . '-' . $day; + } + else { + $startDate = date('Y-m-d'); + } + } + + $date = explode('-', $startDate); + $year = $date[0]; + $month = $date[1]; + $day = $date[2]; + + switch ($duration_unit) { + case 'year': + $year = $year + $duration_interval; + break; + + case 'month': + $month = $month + $duration_interval; + break; + + case 'day': + $day = $day + $duration_interval; + break; + + case 'week': + $day = $day + ($duration_interval * 7); + } + $endDate = date('Y-m-d H:i:s', mktime($hour, $minute, $second, $month, $day, $year)); + $this->assign('start_date', $startDate); + $this->assign('end_date', $endDate); + } + + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $this->_id; + $dao->find(TRUE); + $this->assign('contact_phone', $dao->premiums_contact_phone); + $this->assign('contact_email', $dao->premiums_contact_email); + + //create Premium record + $params = array( + 'product_id' => $premiumParams['selectProduct'], + 'contribution_id' => $contribution->id, + 'product_option' => CRM_Utils_Array::value('options_' . $premiumParams['selectProduct'], $premiumParams), + 'quantity' => 1, + 'start_date' => CRM_Utils_Date::customFormat($startDate, '%Y%m%d'), + 'end_date' => CRM_Utils_Date::customFormat($endDate, '%Y%m%d'), + ); + if( CRM_Utils_Array::value( 'selectProduct', $premiumParams ) ){ + $daoPremiumsProduct = new CRM_Contribute_DAO_PremiumsProduct(); + $daoPremiumsProduct->product_id = $premiumParams['selectProduct']; + $daoPremiumsProduct->premiums_id = $dao->id; + $daoPremiumsProduct->find(true); + $params['financial_type_id'] = $daoPremiumsProduct->financial_type_id; + } + //Fixed For CRM-3901 + $daoContrProd = new CRM_Contribute_DAO_ContributionProduct(); + $daoContrProd->contribution_id = $contribution->id; + if ($daoContrProd->find(TRUE)) { + $params['id'] = $daoContrProd->id; + } + + CRM_Contribute_BAO_Contribution::addPremium($params); + if ($productDAO->cost && CRM_Utils_Array::value('financial_type_id', $params)) { + $trxnParams = array( + 'cost' => $productDAO->cost, + 'currency' => $productDAO->currency, + 'financial_type_id' => $params['financial_type_id'], + 'contributionId' => $contribution->id + ); + CRM_Core_BAO_FinancialTrxn::createPremiumTrxn($trxnParams); + } + } + elseif ($selectProduct == 'no_thanks') { + //Fixed For CRM-3901 + $daoContrProd = new CRM_Contribute_DAO_ContributionProduct(); + $daoContrProd->contribution_id = $contribution->id; + if ($daoContrProd->find(TRUE)) { + $daoContrProd->delete(); + } + } + } + + /** + * Process the contribution + * + * @return CRM_Contribute_DAO_Contribution + * @access public + */ + static function processContribution(&$form, + $params, + $result, + $contactID, + $contributionType, + $deductibleMode = TRUE, + $pending = FALSE, + $online = TRUE + ) { + $transaction = new CRM_Core_Transaction(); + $className = get_class($form); + $honorCId = $recurringContributionID = NULL; + + if ($online && $form->get('honor_block_is_active')) { + $honorCId = $form->createHonorContact(); + } + + // add these values for the recurringContrib function ,CRM-10188 + $params['financial_type_id'] = $contributionType->id; + $params['is_email_receipt'] = CRM_Utils_Array::value( 'is_email_receipt', $form->_values ); + + $recurringContributionID = self::processRecurringContribution($form, $params, $contactID, $contributionType, $online); + + if (!$online && isset($params['honor_contact_id'])) { + $honorCId = $params['honor_contact_id']; + } + + $config = CRM_Core_Config::singleton(); + // CRM-11885 + // if non_deductible_amount exists i.e. Additional Details fieldset was opened [and staff typed something] -> keep it. + if (isset($params['non_deductible_amount']) && (!empty($params['non_deductible_amount']))) { + $nonDeductibleAmount = $params['non_deductible_amount']; + } + // if non_deductible_amount does NOT exist - then calculate it depending on: + // $contributionType->is_deductible and whether there is a product (premium). + else { + //if ($contributionType->is_deductible && $deductibleMode) { + if ($contributionType->is_deductible) { + if ($online && isset($params['selectProduct'])) { + $selectProduct = CRM_Utils_Array::value('selectProduct', $params); + } + if (!$online && isset($params['product_name'][0])) { + $selectProduct = $params['product_name'][0]; + } + // if there is a product - compare the value to the contribution amount + if (isset($selectProduct) && + $selectProduct != 'no_thanks' + ) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $selectProduct; + $productDAO->find(TRUE); + // product value exceeds contribution amount + if ($params['amount'] < $productDAO->price) { + $nonDeductibleAmount = $params['amount']; + } + // product value does NOT exceed contribution amount + else { + $nonDeductibleAmount = $productDAO->price; + } + } + // contribution is deductible - but there is no product + else { + $nonDeductibleAmount = '0.00'; + } + } + // contribution is NOT deductible + else { + $nonDeductibleAmount = $params['amount']; + } + } + + $now = date('YmdHis'); + $receiptDate = CRM_Utils_Array::value('receipt_date', $params); + if (CRM_Utils_Array::value('is_email_receipt', $form->_values)) { + $receiptDate = $now; + } + + //get the contrib page id. + $campaignId = $contributionPageId = NULL; + if ($online) { + $contributionPageId = $form->_id; + $campaignId = CRM_Utils_Array::value('campaign_id', $params); + if (!array_key_exists('campaign_id', $params)) { + $campaignId = CRM_Utils_Array::value('campaign_id', $form->_values); + } + } + else { + //also for offline we do support - CRM-7290 + $contributionPageId = CRM_Utils_Array::value('contribution_page_id', $params); + $campaignId = CRM_Utils_Array::value('campaign_id', $params); + } + + // first create the contribution record + $contribParams = array( + 'contact_id' => $contactID, + 'financial_type_id' => $contributionType->id, + 'contribution_page_id' => $contributionPageId, + 'receive_date' => (CRM_Utils_Array::value('receive_date', $params)) ? CRM_Utils_Date::processDate($params['receive_date']) : date('YmdHis'), + 'non_deductible_amount' => $nonDeductibleAmount, + 'total_amount' => $params['amount'], + 'amount_level' => CRM_Utils_Array::value('amount_level', $params), + 'invoice_id' => $params['invoiceID'], + 'currency' => $params['currencyID'], + 'source' => + (!$online || CRM_Utils_Array::value('source', $params)) ? + CRM_Utils_Array::value('source', $params) : + CRM_Utils_Array::value('description', $params), + 'is_pay_later' => CRM_Utils_Array::value('is_pay_later', $params, 0), + //configure cancel reason, cancel date and thankyou date + //from 'contribution' type profile if included + 'cancel_reason' => CRM_Utils_Array::value('cancel_reason', $params, 0), + 'cancel_date' => + isset($params['cancel_date']) ? + CRM_Utils_Date::format($params['cancel_date']) : + NULL, + 'thankyou_date' => + isset($params['thankyou_date']) ? + CRM_Utils_Date::format($params['thankyou_date']) : + NULL, + 'campaign_id' => $campaignId, + ); + + if (!$online && isset($params['thankyou_date'])) { + $contribParams['thankyou_date'] = $params['thankyou_date']; + } + + if (!$online || $form->_values['is_monetary']) { + if (!CRM_Utils_Array::value('is_pay_later', $params)) { + $contribParams['payment_instrument_id'] = 1; + } + } + + if (!$pending && $result) { + $contribParams += array( + 'fee_amount' => CRM_Utils_Array::value('fee_amount', $result), + 'net_amount' => CRM_Utils_Array::value('net_amount', $result, $params['amount']), + 'trxn_id' => $result['trxn_id'], + 'receipt_date' => $receiptDate, + // also add financial_trxn details as part of fix for CRM-4724 + 'trxn_result_code' => CRM_Utils_Array::value('trxn_result_code', $result), + 'payment_processor' => CRM_Utils_Array::value('payment_processor', $result), + ); + } + + if (isset($honorCId)) { + $contribParams['honor_contact_id'] = $honorCId; + $contribParams['honor_type_id'] = $params['honor_type_id']; + } + + if ($recurringContributionID) { + $contribParams['contribution_recur_id'] = $recurringContributionID; + } + + $contribParams['contribution_status_id'] = $pending ? 2 : 1; + + $contribParams['is_test'] = 0; + if ($form->_mode == 'test') { + $contribParams['is_test'] = 1; + } + + $ids = array(); + if (isset($contribParams['invoice_id'])) { + $contribID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', + $contribParams['invoice_id'], + 'id', + 'invoice_id' + ); + if (isset($contribID)) { + $ids['contribution'] = $contribID; + $contribParams['id'] = $contribID; + } + } + + + //create an contribution address + if ($form->_contributeMode != 'notify' + && !CRM_Utils_Array::value('is_pay_later', $params) + && CRM_Utils_Array::value('is_monetary', $form->_values) + ) { + $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $form->_bltID); + } + + // CRM-4038: for non-en_US locales, CRM_Contribute_BAO_Contribution::add() expects localised amounts + $contribParams['non_deductible_amount'] = trim(CRM_Utils_Money::format($contribParams['non_deductible_amount'], ' ')); + $contribParams['total_amount'] = trim(CRM_Utils_Money::format($contribParams['total_amount'], ' ')); + + // Prepare soft contribution due to pcp or Submit Credit / Debit Card Contribution by admin. + if ( + CRM_Utils_Array::value('pcp_made_through_id', $params) || + CRM_Utils_Array::value('soft_credit_to', $params) + ) { + // if its due to pcp + if (CRM_Utils_Array::value('pcp_made_through_id', $params)) { + $contribSoftContactId = CRM_Core_DAO::getFieldValue( + 'CRM_PCP_DAO_PCP', + $params['pcp_made_through_id'], + 'contact_id' + ); + } + else { + $contribSoftContactId = CRM_Utils_Array::value('soft_credit_to', $params); + } + + // Pass these details onto with the contribution to make them + // available at hook_post_process, CRM-8908 + $contribParams['soft_credit_to'] = $params['soft_credit_to'] = $contribSoftContactId; + } + + if ($params['amount']) { + $contribParams['line_item'] = $form->_lineItem; + //add contribution record + $contribution = &CRM_Contribute_BAO_Contribution::add($contribParams, $ids); + } + + // process soft credit / pcp pages + CRM_Contribute_Form_Contribution_Confirm::processPcpSoft($params, $contribution); + + //handle pledge stuff. + if ( + !CRM_Utils_Array::value('separate_membership_payment', $form->_params) && + CRM_Utils_Array::value('pledge_block_id', $form->_values) && + (CRM_Utils_Array::value('is_pledge', $form->_params) || + CRM_Utils_Array::value('pledge_id', $form->_values) + ) + ) { + + if (CRM_Utils_Array::value('pledge_id', $form->_values)) { + + //when user doing pledge payments. + //update the schedule when payment(s) are made + foreach ($form->_params['pledge_amount'] as $paymentId => $dontCare) { + $scheduledAmount = CRM_Core_DAO::getFieldValue( + 'CRM_Pledge_DAO_PledgePayment', + $paymentId, + 'scheduled_amount', + 'id' + ); + + $pledgePaymentParams = array( + 'id' => $paymentId, + 'contribution_id' => $contribution->id, + 'status_id' => $contribution->contribution_status_id, + 'actual_amount' => $scheduledAmount, + ); + + + CRM_Pledge_BAO_PledgePayment::add($pledgePaymentParams); + } + + //update pledge status according to the new payment statuses + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($form->_values['pledge_id']); + } + else { + //when user creating pledge record. + $pledgeParams = array(); + $pledgeParams['contact_id'] = $contribution->contact_id; + $pledgeParams['installment_amount'] = $pledgeParams['actual_amount'] = $contribution->total_amount; + $pledgeParams['contribution_id'] = $contribution->id; + $pledgeParams['contribution_page_id'] = $contribution->contribution_page_id; + $pledgeParams['financial_type_id'] = $contribution->financial_type_id; + $pledgeParams['frequency_interval'] = $params['pledge_frequency_interval']; + $pledgeParams['installments'] = $params['pledge_installments']; + $pledgeParams['frequency_unit'] = $params['pledge_frequency_unit']; + if ($pledgeParams['frequency_unit'] == 'month') { + $pledgeParams['frequency_day'] = intval(date("d")); + } + else { + $pledgeParams['frequency_day'] = 1; + } + $pledgeParams['create_date'] = $pledgeParams['start_date'] = $pledgeParams['scheduled_date'] = date("Ymd"); + $pledgeParams['status_id'] = $contribution->contribution_status_id; + $pledgeParams['max_reminders'] = $form->_values['max_reminders']; + $pledgeParams['initial_reminder_day'] = $form->_values['initial_reminder_day']; + $pledgeParams['additional_reminder_day'] = $form->_values['additional_reminder_day']; + $pledgeParams['is_test'] = $contribution->is_test; + $pledgeParams['acknowledge_date'] = date('Ymd'); + $pledgeParams['original_installment_amount'] = $pledgeParams['installment_amount']; + + //inherit campaign from contirb page. + $pledgeParams['campaign_id'] = $campaignId; + + $pledge = CRM_Pledge_BAO_Pledge::create($pledgeParams); + + $form->_params['pledge_id'] = $pledge->id; + + //send acknowledgment email. only when pledge is created + if ($pledge->id) { + //build params to send acknowledgment. + $pledgeParams['id'] = $pledge->id; + $pledgeParams['receipt_from_name'] = $form->_values['receipt_from_name']; + $pledgeParams['receipt_from_email'] = $form->_values['receipt_from_email']; + + //scheduled amount will be same as installment_amount. + $pledgeParams['scheduled_amount'] = $pledgeParams['installment_amount']; + + //get total pledge amount. + $pledgeParams['total_pledge_amount'] = $pledge->amount; + + CRM_Pledge_BAO_Pledge::sendAcknowledgment($form, $pledgeParams); + } + } + } + + if ($online && $contribution) { + CRM_Core_BAO_CustomValueTable::postProcess($form->_params, + CRM_Core_DAO::$_nullArray, + 'civicrm_contribution', + $contribution->id, + 'Contribution' + ); + } + elseif ($contribution) { + //handle custom data. + $params['contribution_id'] = $contribution->id; + if (CRM_Utils_Array::value('custom', $params) && + is_array($params['custom']) && + !is_a($contribution, 'CRM_Core_Error') + ) { + CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_contribution', $contribution->id); + } + } + // Save note + if ($contribution && !empty($params['contribution_note'])) { + $noteParams = array( + 'entity_table' => 'civicrm_contribution', + 'note' => $params['contribution_note'], + 'entity_id' => $contribution->id, + 'contact_id' => $contribution->contact_id, + 'modified_date' => date('Ymd'), + ); + + CRM_Core_BAO_Note::add($noteParams, array()); + } + + + if (isset($params['related_contact'])) { + $contactID = $params['related_contact']; + } + elseif (isset($params['cms_contactID'])) { + $contactID = $params['cms_contactID']; + } + CRM_Contribute_BAO_Contribution_Utils::createCMSUser($params, + $contactID, + 'email-' . $form->_bltID + ); + + //create contribution activity w/ individual and target + //activity w/ organisation contact id when onbelf, CRM-4027 + $targetContactID = NULL; + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $params)) { + $targetContactID = $contribution->contact_id; + $contribution->contact_id = $contactID; + } + + // create an activity record + if ($contribution) { + CRM_Activity_BAO_Activity::addActivity($contribution, NULL, $targetContactID); + } + + $transaction->commit(); + return $contribution; + } + + /** + * Create the recurring contribution record + * + */ + function processRecurringContribution(&$form, &$params, $contactID, $contributionType, $online = TRUE) { + // return if this page is not set for recurring + // or the user has not chosen the recurring option + + //this is online case validation. + if ((!CRM_Utils_Array::value('is_recur', $form->_values) && $online) || + !CRM_Utils_Array::value('is_recur', $params) + ) { + return NULL; + } + + $recurParams = array(); + $config = CRM_Core_Config::singleton(); + $recurParams['contact_id'] = $contactID; + $recurParams['amount'] = CRM_Utils_Array::value('amount', $params); + $recurParams['auto_renew'] = CRM_Utils_Array::value('auto_renew', $params); + $recurParams['frequency_unit'] = CRM_Utils_Array::value('frequency_unit', $params); + $recurParams['frequency_interval'] = CRM_Utils_Array::value('frequency_interval', $params); + $recurParams['installments'] = CRM_Utils_Array::value('installments', $params); + $recurParams['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $params); + + $recurParams['is_test'] = 0; + if (($form->_action & CRM_Core_Action::PREVIEW) || + (isset($form->_mode) && ($form->_mode == 'test')) + ) { + $recurParams['is_test'] = 1; + } + + $recurParams['start_date'] = $recurParams['create_date'] = $recurParams['modified_date'] = date('YmdHis'); + if (CRM_Utils_Array::value('receive_date', $params)) { + $recurParams['start_date'] = $params['receive_date']; + } + $recurParams['invoice_id'] = CRM_Utils_Array::value('invoiceID', $params); + $recurParams['contribution_status_id'] = 2; + $recurParams['payment_processor_id'] = CRM_Utils_Array::value('payment_processor_id', $params); + $recurParams['is_email_receipt'] = CRM_Utils_Array::value('is_email_receipt', $params); + // we need to add a unique trxn_id to avoid a unique key error + // in paypal IPN we reset this when paypal sends us the real trxn id, CRM-2991 + $recurParams['trxn_id'] = CRM_Utils_Array::value('trxn_id', $params, $params['invoiceID']); + $recurParams['financial_type_id'] = $contributionType->id; + + if (!$online || $form->_values['is_monetary']) { + $recurParams['payment_instrument_id'] = 1; + } + + $campaignId = CRM_Utils_Array::value('campaign_id', $params); + if ($online) { + if (!array_key_exists('campaign_id', $params)) { + $campaignId = CRM_Utils_Array::value('campaign_id', $form->_values); + } + } + $recurParams['campaign_id'] = $campaignId; + + $recurring = CRM_Contribute_BAO_ContributionRecur::add($recurParams); + if (is_a($recurring, 'CRM_Core_Error')) { + CRM_Core_Error::displaySessionError($result); + $urlString = 'civicrm/contribute/transact'; + $urlParams = '_qf_Main_display=true'; + if ($className == 'CRM_Contribute_Form_Contribution') { + $urlString = 'civicrm/contact/view/contribution'; + $urlParams = "action=add&cid={$form->_contactID}"; + if ($form->_mode) { + $urlParams .= "&mode={$form->_mode}"; + } + } + CRM_Utils_System::redirect(CRM_Utils_System::url($urlString, $urlParams)); + } + + return $recurring->id; + } + + /** + * Create the Honor contact + * + * @return void + * @access public + */ + function createHonorContact() { + $params = $this->controller->exportValues('Main'); + + // email is enough to create a contact + if (! CRM_Utils_Array::value('honor_email', $params) && + // or we need first name AND last name + (! CRM_Utils_Array::value('honor_first_name', $params) + || ! CRM_Utils_Array::value('honor_last_name', $params))) { + //don't create contact - possibly the form was left blank + return null; + } + + //assign to template for email receipt + $honor_block_is_active = $this->get('honor_block_is_active'); + + $this->assign('honor_block_is_active', $honor_block_is_active); + $this->assign('honor_block_title', CRM_Utils_Array::value('honor_block_title', $this->_values)); + + $prefix = CRM_Core_PseudoConstant::individualPrefix(); + $honorType = CRM_Core_PseudoConstant::honor(); + $this->assign('honor_type', CRM_Utils_Array::value(CRM_Utils_Array::value('honor_type_id', $params), $honorType)); + $this->assign('honor_prefix', CRM_Utils_Array::value(CRM_Utils_Array::value('honor_prefix_id', $params), $prefix)); + $this->assign('honor_first_name', CRM_Utils_Array::value('honor_first_name', $params)); + $this->assign('honor_last_name', CRM_Utils_Array::value('honor_last_name', $params)); + $this->assign('honor_email', CRM_Utils_Array::value('honor_email', $params)); + + //create honoree contact + return CRM_Contribute_BAO_Contribution::createHonorContact($params); + } + + /** + * Function to add on behalf of organization and it's location + * + * @param $behalfOrganization array array of organization info + * @param $values array form values array + * @param $contactID int individual contact id. One + * who is doing the process of signup / contribution. + * + * @return void + * @access public + */ + static function processOnBehalfOrganization(&$behalfOrganization, &$contactID, &$values, &$params, $fields = NULL) { + $isCurrentEmployer = FALSE; + $orgID = NULL; + if (CRM_Utils_Array::value('organization_id', $behalfOrganization) && + CRM_Utils_Array::value('org_option', $behalfOrganization) + ) { + $orgID = $behalfOrganization['organization_id']; + unset($behalfOrganization['organization_id']); + $isCurrentEmployer = TRUE; + } + + // formalities for creating / editing organization. + $behalfOrganization['contact_type'] = 'Organization'; + + // get the relationship type id + $relType = new CRM_Contact_DAO_RelationshipType(); + $relType->name_a_b = 'Employee of'; + $relType->find(TRUE); + $relTypeId = $relType->id; + + // keep relationship params ready + $relParams['relationship_type_id'] = $relTypeId . '_a_b'; + $relParams['is_permission_a_b'] = 1; + $relParams['is_active'] = 1; + + if (!$orgID) { + // check if matching organization contact exists + $dedupeParams = CRM_Dedupe_Finder::formatParams($behalfOrganization, 'Organization'); + $dedupeParams['check_permission'] = FALSE; + $dupeIDs = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Organization', 'Unsupervised'); + + // CRM-6243 says to pick the first org even if more than one match + if (count($dupeIDs) >= 1) { + $behalfOrganization['contact_id'] = $dupeIDs[0]; + // don't allow name edit + unset($behalfOrganization['organization_name']); + } + } + else { + // if found permissioned related organization, allow location edit + $behalfOrganization['contact_id'] = $orgID; + // don't allow name edit + unset($behalfOrganization['organization_name']); + } + + // handling for image url + if (CRM_Utils_Array::value('image_URL', $behalfOrganization)) { + CRM_Contact_BAO_Contact::processImageParams($behalfOrganization); + } + + // create organization, add location + $orgID = CRM_Contact_BAO_Contact::createProfileContact($behalfOrganization, $fields, $orgID, + NULL, NULL, 'Organization' + ); + // create relationship + $relParams['contact_check'][$orgID] = 1; + $cid = array('contact' => $contactID); + CRM_Contact_BAO_Relationship::create($relParams, $cid); + + // if multiple match - send a duplicate alert + if ($dupeIDs && (count($dupeIDs) > 1)) { + $values['onbehalf_dupe_alert'] = 1; + // required for IPN + $params['onbehalf_dupe_alert'] = 1; + } + + // make sure organization-contact-id is considered for recording + // contribution/membership etc.. + if ($contactID != $orgID) { + // take a note of contact-id, so we can send the + // receipt to individual contact as well. + + // required for mailing/template display ..etc + $values['related_contact'] = $contactID; + // required for IPN + $params['related_contact'] = $contactID; + + //make this employee of relationship as current + //employer / employee relationship, CRM-3532 + if ($isCurrentEmployer && + ($orgID != CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'employer_id')) + ) { + $isCurrentEmployer = FALSE; + } + + if (!$isCurrentEmployer && $orgID) { + //build current employer params + $currentEmpParams[$contactID] = $orgID; + CRM_Contact_BAO_Contact_Utils::setCurrentEmployer($currentEmpParams); + } + + // contribution / signup will be done using this + // organization id. + $contactID = $orgID; + } + } + + /** + * Function used to save pcp / soft credit entry + * This is used by contribution and also event pcps + * + * @param array $params associated array + * @param object $contribution contribution object + * + * @static + * @access public + */ + static function processPcpSoft(&$params, &$contribution) { + //add soft contribution due to pcp or Submit Credit / Debit Card Contribution by admin. + if (CRM_Utils_Array::value('soft_credit_to', $params)) { + $contribSoftParams = array(); + foreach (array( + 'pcp_display_in_roll', 'pcp_roll_nickname', 'pcp_personal_note', 'amount') as $val) { + if (CRM_Utils_Array::value($val, $params)) { + $contribSoftParams[$val] = $params[$val]; + } + } + + $contribSoftParams['contact_id'] = $params['soft_credit_to']; + // add contribution id + $contribSoftParams['contribution_id'] = $contribution->id; + // add pcp id + $contribSoftParams['pcp_id'] = $params['pcp_made_through_id']; + + $softContribution = CRM_Contribute_BAO_Contribution::addSoftContribution($contribSoftParams); + } + } + + /** + * Function used to se pcp related defaults / params + * This is used by contribution and also event pcps + * + * @param object $page form object + * @param array $params associated array + * + * @static + * @access public + */ + static function processPcp(&$page, $params) { + $params['pcp_made_through_id'] = $page->_pcpInfo['pcp_id']; + $page->assign('pcpBlock', TRUE); + if (CRM_Utils_Array::value('pcp_display_in_roll', $params) && + !CRM_Utils_Array::value('pcp_roll_nickname', $params) + ) { + $params['pcp_roll_nickname'] = ts('Anonymous'); + $params['pcp_is_anonymous'] = 1; + } + else { + $params['pcp_is_anonymous'] = 0; + } + foreach (array( + 'pcp_display_in_roll', 'pcp_is_anonymous', 'pcp_roll_nickname', 'pcp_personal_note') as $val) { + if (CRM_Utils_Array::value($val, $params)) { + $page->assign($val, $params[$val]); + } + } + + return $params; + } +} diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php new file mode 100644 index 0000000000..b876ce26e0 --- /dev/null +++ b/CRM/Contribute/Form/Contribution/Main.php @@ -0,0 +1,1443 @@ +_ppType = CRM_Utils_Array::value('type', $_GET); + $this->assign('ppType', FALSE); + if ($this->_ppType) { + $this->assign('ppType', TRUE); + return CRM_Core_Payment_ProcessorForm::preProcess($this); + } + + //get payPal express id and make it available to template + $paymentProcessors = $this->get('paymentProcessors'); + if (!empty($paymentProcessors)) { + foreach ($paymentProcessors as $ppId => $values) { + $payPalExpressId = ($values['payment_processor_type'] == 'PayPal_Express') ? $values['id'] : 0; + $this->assign('payPalExpressId', $payPalExpressId); + if ($payPalExpressId) { + break; + } + } + } + + // Make the contributionPageID avilable to the template + $this->assign('contributionPageID', $this->_id); + $this->assign('isShare', CRM_Utils_Array::value('is_share', $this->_values)); + $this->assign('isConfirmEnabled', CRM_Utils_Array::value('is_confirm_enabled', $this->_values)); + + // make sure we have right permission to edit this user + $csContactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE, $this->_userID); + $reset = CRM_Utils_Request::retrieve('reset', 'Boolean', CRM_Core_DAO::$_nullObject); + $mainDisplay = CRM_Utils_Request::retrieve('_qf_Main_display', 'Boolean', CRM_Core_DAO::$_nullObject); + + if ($csContactID != $this->_userID) { + if (CRM_Contact_BAO_Contact_Permission::validateChecksumContact($csContactID, $this)) { + $session = CRM_Core_Session::singleton(); + $session->set('userID', $csContactID); + $this->_userID = $csContactID; + } + } + + if ($reset) { + $this->assign('reset', $reset); + } + + if ($mainDisplay) { + $this->assign('mainDisplay', $mainDisplay); + } + + $this->_onbehalf = FALSE; + if (CRM_Utils_Array::value('is_for_organization', $this->_values)) { + $urlParams = "&id={$this->_id}&qfKey={$this->controller->_key}"; + $this->assign('urlParams', $urlParams); + $this->_onbehalf = CRM_Utils_Array::value('onbehalf', $_GET); + + CRM_Contribute_Form_Contribution_OnBehalfOf::preProcess($this); + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $_POST) && + (CRM_Utils_Array::value('is_for_organization', $_POST) || + CRM_Utils_Array::value('is_for_organization', $this->_values) == 2 + ) + ) { + CRM_Contribute_Form_Contribution_OnBehalfOf::buildQuickForm($this); + } + } + + if (CRM_Utils_Array::value('id', $this->_pcpInfo) && + CRM_Utils_Array::value('intro_text', $this->_pcpInfo) + ) { + $this->assign('intro_text', $this->_pcpInfo['intro_text']); + } + elseif (CRM_Utils_Array::value('intro_text', $this->_values)) { + $this->assign('intro_text', $this->_values['intro_text']); + } + + $qParams = "reset=1&id={$this->_id}"; + if ( $pcpId = CRM_Utils_Array::value( 'pcp_id', $this->_pcpInfo ) ) { + $qParams .= "&pcpId={$pcpId}"; + } + $this->assign( 'qParams' , $qParams ); + + if (CRM_Utils_Array::value('footer_text', $this->_values)) { + $this->assign('footer_text', $this->_values['footer_text']); + } + + //CRM-5001 + if (CRM_Utils_Array::value('is_for_organization', $this->_values)) { + $msg = ts('Mixed profile not allowed for on behalf of registration/sign up.'); + if ($preID = CRM_Utils_Array::value('custom_pre_id', $this->_values)) { + $preProfile = CRM_Core_BAO_UFGroup::profileGroups($preID); + foreach (array( + 'Individual', 'Organization', 'Household') as $contactType) { + if (in_array($contactType, $preProfile) && + (in_array('Membership', $preProfile) || + in_array('Contribution', $preProfile) + ) + ) { + CRM_Core_Error::fatal($msg); + } + } + } + + if ($postID = CRM_Utils_Array::value('custom_post_id', $this->_values)) { + $postProfile = CRM_Core_BAO_UFGroup::profileGroups($postID); + foreach (array( + 'Individual', 'Organization', 'Household') as $contactType) { + if (in_array($contactType, $postProfile) && + (in_array('Membership', $postProfile) || + in_array('Contribution', $postProfile) + ) + ) { + CRM_Core_Error::fatal($msg); + } + } + } + } + + if (CRM_Utils_Array::value('hidden_processor', $_POST)) { + $this->set('type', CRM_Utils_Array::value('payment_processor', $_POST)); + $this->set('mode', $this->_mode); + $this->set('paymentProcessor', $this->_paymentProcessor); + + CRM_Core_Payment_ProcessorForm::preProcess($this); + CRM_Core_Payment_ProcessorForm::buildQuickForm($this); + } + } + + function setDefaultValues() { + if ($this->_onbehalf) { + return; + } + + // check if the user is registered and we have a contact ID + $contactID = $this->_userID; + + if ($contactID) { + $fields = array(); + $removeCustomFieldTypes = array('Contribution', 'Membership'); + $contribFields = CRM_Contribute_BAO_Contribution::getContributionFields(); + + // remove component related fields + foreach ($this->_fields as $name => $dontCare) { + //don't set custom data Used for Contribution (CRM-1344) + if (substr($name, 0, 7) == 'custom_') { + $id = substr($name, 7); + if (!CRM_Core_BAO_CustomGroup::checkCustomField($id, $removeCustomFieldTypes)) { + continue; + } + // ignore component fields + } + elseif (array_key_exists($name, $contribFields) || (substr($name, 0, 11) == 'membership_') || (substr($name, 0, 13) == 'contribution_')) { + continue; + } + $fields[$name] = 1; + } + + $names = array( + 'first_name', 'middle_name', 'last_name', "street_address-{$this->_bltID}", "city-{$this->_bltID}", + "postal_code-{$this->_bltID}", "country_id-{$this->_bltID}", "state_province_id-{$this->_bltID}", + ); + foreach ($names as $name) { + $fields[$name] = 1; + } + $fields["state_province-{$this->_bltID}"] = 1; + $fields["country-{$this->_bltID}"] = 1; + $fields["email-{$this->_bltID}"] = 1; + $fields['email-Primary'] = 1; + + CRM_Core_BAO_UFGroup::setProfileDefaults($contactID, $fields, $this->_defaults); + + // use primary email address if billing email address is empty + if (empty($this->_defaults["email-{$this->_bltID}"]) && + !empty($this->_defaults['email-Primary']) + ) { + $this->_defaults["email-{$this->_bltID}"] = $this->_defaults['email-Primary']; + } + + foreach ($names as $name) { + if (!empty($this->_defaults[$name])) { + $this->_defaults['billing_' . $name] = $this->_defaults[$name]; + } + } + } + + //set custom field defaults set by admin if value is not set + if (!empty($this->_fields)) { + //load default campaign from page. + if (array_key_exists('contribution_campaign_id', $this->_fields)) { + $this->_defaults['contribution_campaign_id'] = CRM_Utils_Array::value('campaign_id', $this->_values); + } + + //set custom field defaults + foreach ($this->_fields as $name => $field) { + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) { + if (!isset($this->_defaults[$name])) { + CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, $name, $this->_defaults, + NULL, CRM_Profile_Form::MODE_REGISTER + ); + } + } + } + } + + //set default membership for membershipship block + if ($this->_membershipBlock) { + $this->_defaults['selectMembership'] = $defaultMemType = $this->_defaultMemTypeId ? $this->_defaultMemTypeId : CRM_Utils_Array::value('membership_type_default', $this->_membershipBlock); + } + + // // hack to simplify credit card entry for testing + // $this->_defaults['credit_card_type'] = 'Visa'; + // $this->_defaults['amount'] = 168; + // $this->_defaults['credit_card_number'] = '4111111111111111'; + // $this->_defaults['cvv2'] = '000'; + // $this->_defaults['credit_card_exp_date'] = array('Y' => '2014', 'M' => '05'); + + // // hack to simplify direct debit entry for testing + // $this->_defaults['account_holder'] = 'Max Müller'; + // $this->_defaults['bank_account_number'] = '12345678'; + // $this->_defaults['bank_identification_number'] = '12030000'; + // $this->_defaults['bank_name'] = 'Bankname'; + + //build set default for pledge overdue payment. + if (CRM_Utils_Array::value('pledge_id', $this->_values)) { + //get all payment statuses. + $statuses = array(); + $returnProperties = array('status_id'); + CRM_Core_DAO::commonRetrieveAll('CRM_Pledge_DAO_PledgePayment', 'pledge_id', $this->_values['pledge_id'], + $statuses, $returnProperties + ); + + $paymentStatusTypes = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + $duePayment = FALSE; + foreach ($statuses as $payId => $value) { + if ($paymentStatusTypes[$value['status_id']] == 'Overdue') { + $this->_defaults['pledge_amount'][$payId] = 1; + } + elseif (!$duePayment && $paymentStatusTypes[$value['status_id']] == 'Pending') { + $this->_defaults['pledge_amount'][$payId] = 1; + $duePayment = TRUE; + } + } + } + elseif (CRM_Utils_Array::value('pledge_block_id', $this->_values)) { + //set default to one time contribution. + $this->_defaults['is_pledge'] = 0; + } + + // to process Custom data that are appended to URL + $getDefaults = CRM_Core_BAO_CustomGroup::extractGetParams($this, "'Contact', 'Individual', 'Contribution'"); + if (!empty($getDefaults)) { + $this->_defaults = array_merge($this->_defaults, $getDefaults); + } + + $config = CRM_Core_Config::singleton(); + // set default country from config if no country set + if (!CRM_Utils_Array::value("billing_country_id-{$this->_bltID}", $this->_defaults)) { + $this->_defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry; + } + + // set default state/province from config if no state/province set + if (!CRM_Utils_Array::value("billing_state_province_id-{$this->_bltID}", $this->_defaults)) { + $this->_defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince; + } + + // now fix all state country selectors + CRM_Core_BAO_Address::fixAllStateSelects($this, $this->_defaults); + + if ($this->_priceSetId) { + if ($this->_useForMember && !empty($this->_currentMemberships)) { + $selectedCurrentMemTypes = array(); + foreach ($this->_priceSet['fields'] as $key => $val) { + foreach ($val['options'] as $keys => $values) { + $opMemTypeId = CRM_Utils_Array::value('membership_type_id', $values); + if ($opMemTypeId && + in_array($opMemTypeId, $this->_currentMemberships) && + !in_array($opMemTypeId, $selectedCurrentMemTypes) + ) { + if ($val['html_type'] == 'CheckBox') { + $this->_defaults["price_{$key}"][$keys] = 1; + } + else { + $this->_defaults["price_{$key}"] = $keys; + } + $selectedCurrentMemTypes[] = $values['membership_type_id']; + } + elseif (CRM_Utils_Array::value('is_default', $values) && + !$opMemTypeId && + (!isset($this->_defaults["price_{$key}"]) || + ($val['html_type'] == 'CheckBox' && !isset($this->_defaults["price_{$key}"][$keys])) + ) + ) { + if ($val['html_type'] == 'CheckBox') { + $this->_defaults["price_{$key}"][$keys] = 1; + } + else { + $this->_defaults["price_{$key}"] = $keys; + } + } + } + } + } + else { + CRM_Price_BAO_Set::setDefaultPriceSet($this, $this->_defaults); + } + } + + if (!empty($this->_paymentProcessors)) { + foreach ($this->_paymentProcessors as $pid => $value) { + if (CRM_Utils_Array::value('is_default', $value)) { + $this->_defaults['payment_processor'] = $pid; + } + } + } + + return $this->_defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + if ($this->_ppType) { + return CRM_Core_Payment_ProcessorForm::buildQuickForm($this); + } + + $config = CRM_Core_Config::singleton(); + if (CRM_Utils_Array::value('is_for_organization', $this->_values) == 2) { + $this->assign('onBehalfRequired', TRUE); + $this->_onBehalfRequired = 1; + } + if ($this->_onbehalf) { + $this->assign('onbehalf', TRUE); + return CRM_Contribute_Form_Contribution_OnBehalfOf::buildQuickForm($this); + } + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', "email-{$this->_bltID}", + ts('Email Address'), + array('size' => 30, 'maxlength' => 60, 'class' => 'email'), + TRUE + ); + $this->addRule("email-{$this->_bltID}", ts('Email is not valid.'), 'email'); + $this->_paymentProcessors = $this->get('paymentProcessors'); + $pps = array(); + if (!empty($this->_paymentProcessors)) { + $pps = $this->_paymentProcessors; + foreach ($pps as $key => & $name) { + $pps[$key] = $name['name']; + } + } + if (CRM_Utils_Array::value('is_pay_later', $this->_values)) { + $pps[0] = $this->_values['pay_later_text']; + } + + if (count($pps) > 1) { + $this->addRadio('payment_processor', ts('Payment Method'), $pps, + NULL, " ", TRUE + ); + } + elseif (!empty($pps)) { + $key = array_keys($pps); + $key = array_pop($key); + $this->addElement('hidden', 'payment_processor', $key); + if ($key === 0) { + $this->assign('is_pay_later', $this->_values['is_pay_later']); + $this->assign('pay_later_text', $this->_values['pay_later_text']); + } + } + //build pledge block. + $this->_useForMember = 0; + //don't build membership block when pledge_id is passed + if (!CRM_Utils_Array::value('pledge_id', $this->_values)) { + $this->_separateMembershipPayment = FALSE; + if (in_array('CiviMember', $config->enableComponents)) { + $isTest = 0; + if ($this->_action & CRM_Core_Action::PREVIEW) { + $isTest = 1; + } + + if ($this->_priceSetId && + (CRM_Core_Component::getComponentID('CiviMember') == CRM_Utils_Array::value('extends', $this->_priceSet)) + ) { + $this->_useForMember = 1; + $this->set('useForMember', $this->_useForMember); + } + + $this->_separateMembershipPayment = CRM_Member_BAO_Membership::buildMembershipBlock($this, + $this->_id, + TRUE, NULL, FALSE, + $isTest, $this->_membershipContactID + ); + } + $this->set('separateMembershipPayment', $this->_separateMembershipPayment); + } + $this->assign('useForMember', $this->_useForMember); + // If we configured price set for contribution page + // we are not allow membership signup as well as any + // other contribution amount field, CRM-5095 + if (isset($this->_priceSetId) && $this->_priceSetId) { + $this->add('hidden', 'priceSetId', $this->_priceSetId); + // build price set form. + $this->set('priceSetId', $this->_priceSetId); + CRM_Price_BAO_Set::buildPriceSet($this); + if ($this->_values['is_monetary'] && + $this->_values['is_recur'] && !CRM_Utils_Array::value('pledge_id', $this->_values) + ) { + self::buildRecur($this); + } + } + elseif (CRM_Utils_Array::value('amount_block_is_active', $this->_values) + && !CRM_Utils_Array::value('pledge_id', $this->_values) + ) { + $this->buildAmount($this->_separateMembershipPayment); + } + + if ($this->_priceSetId) { + $is_quick_config = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_priceSetId, 'is_quick_config'); + if ($is_quick_config) { + $this->_useForMember = 0; + $this->set('useForMember', $this->_useForMember); + } + } + + if ($this->_values['is_for_organization']) { + $this->buildOnBehalfOrganization(); + } + + //we allow premium for pledge during pledge creation only. + if (!CRM_Utils_Array::value('pledge_id', $this->_values)) { + CRM_Contribute_BAO_Premium::buildPremiumBlock($this, $this->_id, TRUE); + } + + if ($this->_values['honor_block_is_active']) { + $this->buildHonorBlock(); + } + + + //don't build pledge block when mid is passed + if (!$this->_mid) { + $config = CRM_Core_Config::singleton(); + if (in_array('CiviPledge', $config->enableComponents) + && CRM_Utils_Array::value('pledge_block_id', $this->_values) + ) { + CRM_Pledge_BAO_PledgeBlock::buildPledgeBlock($this); + } + } + + $this->buildCustom($this->_values['custom_pre_id'], 'customPre'); + $this->buildCustom($this->_values['custom_post_id'], 'customPost'); + + if ( !empty( $this->_fields ) ) { + $profileAddressFields = array(); + foreach( $this->_fields as $key => $value ) { + CRM_Core_BAO_UFField::assignAddressField($key, $profileAddressFields); + } + $this->set('profileAddressFields', $profileAddressFields); + } + + //to create an cms user + if (!$this->_userID) { + $createCMSUser = FALSE; + + if ($this->_values['custom_pre_id']) { + $profileID = $this->_values['custom_pre_id']; + $createCMSUser = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'is_cms_user'); + } + + if (!$createCMSUser && + $this->_values['custom_post_id'] + ) { + if (!is_array($this->_values['custom_post_id'])) { + $profileIDs = array($this->_values['custom_post_id']); + } + else { + $profileIDs = $this->_values['custom_post_id']; + } + foreach ($profileIDs as $pid) { + if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $pid, 'is_cms_user')) { + $profileID = $pid; + $createCMSUser = TRUE; + break; + } + } + } + + if ($createCMSUser) { + CRM_Core_BAO_CMSUser::buildForm($this, $profileID, TRUE); + } + } + if ($this->_pcpId) { + if ($pcpSupporter = CRM_PCP_BAO_PCP::displayName($this->_pcpId)) { + $this->assign('pcpSupporterText', ts('This contribution is being made thanks to effort of %1, who supports our campaign. You can support it as well - once you complete the donation, you will be able to create your own Personal Campaign Page!', array(1 => $pcpSupporter))); + } + $this->assign('pcp', TRUE); + $this->add('checkbox', 'pcp_display_in_roll', ts('Show my contribution in the public honor roll'), NULL, NULL, + array('onclick' => "showHideByValue('pcp_display_in_roll','','nameID|nickID|personalNoteID','block','radio',false); pcpAnonymous( );") + ); + $extraOption = array('onclick' => "return pcpAnonymous( );"); + $elements = array(); + $elements[] = &$this->createElement('radio', NULL, '', ts('Include my name and message'), 0, $extraOption); + $elements[] = &$this->createElement('radio', NULL, '', ts('List my contribution anonymously'), 1, $extraOption); + $this->addGroup($elements, 'pcp_is_anonymous', NULL, '   '); + $this->_defaults['pcp_is_anonymous'] = 0; + + $this->add('text', 'pcp_roll_nickname', ts('Name'), array('maxlength' => 30)); + $this->add('textarea', 'pcp_personal_note', ts('Personal Note'), array('style' => 'height: 3em; width: 40em;')); + } + + //we have to load confirm contribution button in template + //when multiple payment processor as the user + //can toggle with payment processor selection + $billingModePaymentProcessors = 0; + if ( !empty( $this->_paymentProcessors ) ) { + foreach ($this->_paymentProcessors as $key => $values) { + if ($values['billing_mode'] == CRM_Core_Payment::BILLING_MODE_BUTTON) { + $billingModePaymentProcessors++; + } + } + } + + if ($billingModePaymentProcessors && count($this->_paymentProcessors) == $billingModePaymentProcessors) { + $allAreBillingModeProcessors = TRUE; + } else { + $allAreBillingModeProcessors = FALSE; + } + + if (!($allAreBillingModeProcessors && !$this->_values['is_pay_later'])) { + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Contribute'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + ) + ); + } + + $this->addFormRule(array('CRM_Contribute_Form_Contribution_Main', 'formRule'), $this); + + } + + /** + * build the radio/text form elements for the amount field + * + * @return void + * @access private + */ + function buildAmount($separateMembershipPayment = FALSE) { + $elements = array(); + if (!empty($this->_values['amount'])) { + // first build the radio boxes + CRM_Utils_Hook::buildAmount('contribution', $this, $this->_values['amount']); + + foreach ($this->_values['amount'] as $amount) { + $elements[] = &$this->createElement('radio', NULL, '', + CRM_Utils_Money::format($amount['value']) . ' ' . $amount['label'], + $amount['amount_id'], + array('onclick' => 'clearAmountOther();') + ); + } + } + + if ($separateMembershipPayment) { + $elements[''] = $this->createElement('radio', NULL, NULL, ts('No thank you'), 'no_thanks', array('onclick' => 'clearAmountOther();')); + $this->assign('is_separate_payment', TRUE); + } + + if (isset($this->_values['default_amount_id'])) { + $this->_defaults['amount'] = $this->_values['default_amount_id']; + } + $title = ts('Contribution Amount'); + if ($this->_values['is_allow_other_amount']) { + if (!empty($this->_values['amount'])) { + $elements[] = &$this->createElement('radio', NULL, '', + ts('Other Amount'), 'amount_other_radio' + ); + + $this->addGroup($elements, 'amount', $title, '
    '); + + if (!$separateMembershipPayment) { + $this->addRule('amount', ts('%1 is a required field.', array(1 => ts('Amount'))), 'required'); + } + $this->add('text', 'amount_other', ts('Other Amount'), array('size' => 10, 'maxlength' => 10, 'onfocus' => 'useAmountOther();')); + } + else { + if ($separateMembershipPayment) { + $title = ts('Additional Contribution'); + } + $this->add('text', 'amount_other', $title, array('size' => 10, 'maxlength' => 10, 'onfocus' => 'useAmountOther();')); + if (!$separateMembershipPayment) { + $this->addRule('amount_other', ts('%1 is a required field.', array(1 => $title)), 'required'); + } + } + + $this->assign('is_allow_other_amount', TRUE); + + $this->addRule('amount_other', ts('Please enter a valid amount (numbers and decimal point only).'), 'money'); + } + else { + if (!empty($this->_values['amount'])) { + if ($separateMembershipPayment) { + $title = ts('Additional Contribution'); + } + $this->addGroup($elements, 'amount', $title, '
    '); + + if (!$separateMembershipPayment) { + $this->addRule('amount', ts('%1 is a required field.', array(1 => ts('Amount'))), 'required'); + } + } + $this->assign('is_allow_other_amount', FALSE); + } + } + + /** + * Function to add the honor block + * + * @return None + * @access public + */ + function buildHonorBlock() { + $this->assign('honor_block_is_active', TRUE); + $this->set('honor_block_is_active', TRUE); + + $this->assign('honor_block_title', CRM_Utils_Array::value('honor_block_title', $this->_values)); + $this->assign('honor_block_text', CRM_Utils_Array::value('honor_block_text', $this->_values)); + + $attributes = CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact'); + $extraOption = array('onclick' => "enableHonorType();"); + // radio button for Honor Type + $honorOptions = array(); + $honor = CRM_Core_PseudoConstant::honor(); + foreach ($honor as $key => $var) { + $honorTypes[$key] = $this->createElement('radio', NULL, NULL, $var, $key, $extraOption); + } + $this->addGroup($honorTypes, 'honor_type_id', NULL); + + // prefix + $this->addElement('select', 'honor_prefix_id', ts('Prefix'), array('' => ts('- prefix -')) + CRM_Core_PseudoConstant::individualPrefix()); + // first_name + $this->addElement('text', 'honor_first_name', ts('First Name'), $attributes['first_name']); + + //last_name + $this->addElement('text', 'honor_last_name', ts('Last Name'), $attributes['last_name']); + + //email + $this->addElement('text', 'honor_email', ts('Email Address'), array('class' => 'email')); + $this->addRule('honor_email', ts('Honoree Email is not valid.'), 'email'); + } + + /** + * build elements to enable pay on behalf of an organization. + * + * @access public + */ + function buildOnBehalfOrganization() { + if ($this->_membershipContactID) { + $entityBlock = array('contact_id' => $this->_membershipContactID); + CRM_Core_BAO_Location::getValues($entityBlock, $this->_defaults); + } + + if ($this->_values['is_for_organization'] != 2) { + $this->addElement('checkbox', 'is_for_organization', + $this->_values['for_organization'], + NULL, array('onclick' => "showOnBehalf( );") + ); + } + else { + $this->assign('onBehalfRequired', TRUE); + $this->_onBehalfRequired = 1; + } + + $this->assign('is_for_organization', TRUE); + $this->assign('urlPath', 'civicrm/contribute/transact'); + } + + /** + * build elements to collect information for recurring contributions + * + * @access public + */ + function buildRecur($form) { + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionRecur'); + $className = get_class($form); + + $this->assign('is_recur_interval', CRM_Utils_Array::value('is_recur_interval', $this->_values)); + $this->assign('is_recur_installments', CRM_Utils_Array::value('is_recur_installments', $this->_values)); + + $form->add('checkbox', 'is_recur', ts('I want to contribute this amount'), NULL); + + if (CRM_Utils_Array::value('is_recur_interval', $form->_values) || $className == 'CRM_Contribute_Form_Contribution') { + $form->add('text', 'frequency_interval', ts('Every'), $attributes['frequency_interval']); + $form->addRule('frequency_interval', ts('Frequency must be a whole number (EXAMPLE: Every 3 months).'), 'integer'); + } + else { + // make sure frequency_interval is submitted as 1 if given no choice to user. + $form->add('hidden', 'frequency_interval', 1); + } + + $frUnits = CRM_Utils_Array::value('recur_frequency_unit', $form->_values); + if (empty($frUnits) && + $className == 'CRM_Contribute_Form_Contribution' + ) { + $frUnits = implode(CRM_Core_DAO::VALUE_SEPARATOR, + CRM_Core_OptionGroup::values('recur_frequency_units') + ); + } + + $unitVals = explode(CRM_Core_DAO::VALUE_SEPARATOR, $frUnits); + + // CRM 10860, display text instead of a dropdown if there's only 1 frequency unit + if(sizeof($unitVals) == 1) { + $this->assign('one_frequency_unit', true); + $unit = $unitVals[0]; + $form->add('hidden', 'frequency_unit', $unit); + if (CRM_Utils_Array::value('is_recur_interval', $form->_values) || $className == 'CRM_Contribute_Form_Contribution') { + $unit .= "(s)"; + } + $this->assign('frequency_unit', $unit); + } else { + $this->assign('one_frequency_unit', false); + $units = array(); + $frequencyUnits = CRM_Core_OptionGroup::values('recur_frequency_units'); + foreach ($unitVals as $key => $val) { + if (array_key_exists($val, $frequencyUnits)) { + $units[$val] = $frequencyUnits[$val]; + if (CRM_Utils_Array::value('is_recur_interval', $form->_values) || $className == 'CRM_Contribute_Form_Contribution') { + $units[$val] = "{$frequencyUnits[$val]}(s)"; + } + } + } + $frequencyUnit = &$form->add('select', 'frequency_unit', NULL, $units); + } + + + // FIXME: Ideally we should freeze select box if there is only + // one option but looks there is some problem /w QF freeze. + //if ( count( $units ) == 1 ) { + //$frequencyUnit->freeze( ); + //} + + $form->add('text', 'installments', ts('installments'), + $attributes['installments'] + ); + $form->addRule('installments', ts('Number of installments must be a whole number.'), 'integer'); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + $errors = array(); + $amount = self::computeAmount($fields, $self); + + if ((CRM_Utils_Array::value('selectMembership', $fields) && + $fields['selectMembership'] != 'no_thanks' + ) || + (CRM_Utils_Array::value('priceSetId', $fields) && + $self->_useForMember + ) + ) { + $lifeMember = CRM_Member_BAO_Membership::getAllContactMembership($self->_userID, FALSE, TRUE); + + $membershipOrgDetails = CRM_Member_BAO_MembershipType::getMembershipTypeOrganization(); + + $unallowedOrgs = array(); + foreach (array_keys($lifeMember) as $memTypeId) { + $unallowedOrgs[] = $membershipOrgDetails[$memTypeId]; + } + } + + //check for atleast one pricefields should be selected + if (CRM_Utils_Array::value('priceSetId', $fields)) { + $priceField = new CRM_Price_DAO_Field(); + $priceField->price_set_id = $fields['priceSetId']; + $priceField->orderBy('weight'); + $priceField->find(); + + $check = array(); + $membershipIsActive = TRUE; + $previousId = $otherAmount = FALSE; + while ($priceField->fetch()) { + + if ($self->_quickConfig && ($priceField->name == 'contribution_amount' || $priceField->name == 'membership_amount')) { + $previousId = $priceField->id; + if ($priceField->name == 'membership_amount' && !$priceField->is_active ) { + $membershipIsActive = FALSE; + } + } + if ($priceField->name == 'other_amount') { + if ($self->_quickConfig && !CRM_Utils_Array::value("price_{$priceField->id}", $fields) && + array_key_exists("price_{$previousId}", $fields) && isset($fields["price_{$previousId}"]) && $self->_values['fee'][$previousId]['name'] == 'contribution_amount' && empty($fields["price_{$previousId}"])) { + $otherAmount = $priceField->id; + } + elseif (!empty($fields["price_{$priceField->id}"])) { + $otherAmountVal = $fields["price_{$priceField->id}"]; + $min = CRM_Utils_Array::value('min_amount', $self->_values); + $max = CRM_Utils_Array::value('max_amount', $self->_values); + if ($min && $otherAmountVal < $min) { + $errors["price_{$priceField->id}"] = ts('Contribution amount must be at least %1', + array(1 => $min) + ); + } + if ($max && $otherAmountVal > $max) { + $errors["price_{$priceField->id}"] = ts('Contribution amount cannot be more than %1.', + array(1 => $max) + ); + } + } + } + if (!empty($fields["price_{$priceField->id}"]) || ($previousId == $priceField->id && isset($fields["price_{$previousId}"]) + && empty($fields["price_{$previousId}"]))) { + $check[] = $priceField->id; + } + } + + if (empty($check)) { + if ($self->_useForMember == 1 && $membershipIsActive) { + $errors['_qf_default'] = ts('Select at least one option from Membership Type(s).'); + } + else { + $errors['_qf_default'] = ts('Select at least one option from Contribution(s).'); + } + } + if($otherAmount && !empty($check)) { + $errors["price_{$otherAmount}"] = ts('Amount is required field.'); + } + + if ($self->_useForMember == 1 && !empty($check) && $membershipIsActive) { + $priceFieldIDS = array(); + $priceFieldMemTypes = array(); + + foreach ($self->_priceSet['fields'] as $priceId => $value) { + if (!empty($fields['price_' . $priceId]) || ($self->_quickConfig && $value['name'] == 'membership_amount' && !CRM_Utils_Array::value('is_required', $self->_membershipBlock))) { + if (CRM_Utils_Array::value('price_' . $priceId, $fields) && is_array($fields['price_' . $priceId])) { + foreach ($fields['price_' . $priceId] as $priceFldVal => $isSet) { + if ($isSet) { + $priceFieldIDS[] = $priceFldVal; + } + } + } + elseif (!$value['is_enter_qty'] && CRM_Utils_Array::value('price_' . $priceId, $fields)) { + // The check for {!$value['is_enter_qty']} is done since, quantity fields allow entering + // quantity. And the quantity can't be conisdered as civicrm_price_field_value.id, CRM-9577 + $priceFieldIDS[] = $fields['price_' . $priceId]; + } + + if (CRM_Utils_Array::value('options', $value)) { + foreach ($value['options'] as $val) { + if (CRM_Utils_Array::value('membership_type_id', $val)) { + $priceFieldMemTypes[] = $val['membership_type_id']; + } + } + } + } + } + + if (!empty($lifeMember)) { + foreach ($priceFieldIDS as $priceFieldId) { + if (($id = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_FieldValue', $priceFieldId, 'membership_type_id')) && + in_array($membershipOrgDetails[$id], $unallowedOrgs) + ) { + $errors['_qf_default'] = ts('You already have a lifetime membership and cannot select a membership with a shorter term.'); + break; + } + } + } + + if (!empty($priceFieldIDS)) { + $ids = implode(',', $priceFieldIDS); + + $priceFieldIDS['id'] = $fields['priceSetId']; + $self->set('memberPriceFieldIDS', $priceFieldIDS); + $count = CRM_Price_BAO_Set::getMembershipCount($ids); + foreach ($count as $id => $occurance) { + if ($occurance > 1) { + $errors['_qf_default'] = ts('You have selected multiple memberships for the same organization or entity. Please review your selections and choose only one membership per entity. Contact the site administrator if you need assistance.'); + } + } + } + + if (empty($priceFieldMemTypes)) { + $errors['_qf_default'] = ts('Please select at least one membership option.'); + } + } + + $fieldId = $memPresent = $membershipLabel = $fieldOption = $proceFieldAmount = NULL; + if ($self->_separateMembershipPayment == 0 && $self->_quickConfig) { + foreach ($self->_priceSet['fields'] as $fieldKey => $fieldVal) { + if ($fieldVal['name'] == 'membership_amount') { + $fieldId = $fieldVal['id']; + $fieldOption = $fields['price_' . $fieldId]; + $memPresent = TRUE; + } + else { + if (CRM_Utils_Array::value('price_' . $fieldKey, $fields) && $memPresent && ($fieldVal['name'] == 'other_amount' || $fieldVal['name'] == 'contribution_amount')) { + $fieldId = $fieldVal['id']; + if ($fieldVal['name'] == 'other_amount') { + $proceFieldAmount = $self->_submitValues['price_' . $fieldId]; + } + else $proceFieldAmount = $fieldVal['options'][$self->_submitValues['price_' . $fieldId]]['amount']; + unset($fields['price_' . $fieldId]); + break; + } + } + } + } + + CRM_Price_BAO_Set::processAmount($self->_values['fee'], + $fields, $lineItem + ); + if ($proceFieldAmount) { + if ($proceFieldAmount < $lineItem[$fieldOption]['line_total']) { + $errors["price_$fieldId"] = ts('The Membership you have selected requires a minimum contribution of %1', + array(1 => CRM_Utils_Money::format($lineItem[$fieldOption]['line_total'])) + ); + } + $fields['amount'] = $proceFieldAmount; + } + if ($fields['amount'] < 0) { + $errors['_qf_default'] = ts('Contribution can not be less than zero. Please select the options accordingly'); + } + $amount = $fields['amount']; + } + + if (isset($fields['selectProduct']) && + $fields['selectProduct'] != 'no_thanks' && + $self->_values['amount_block_is_active'] + ) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $fields['selectProduct']; + $productDAO->find(TRUE); + $min_amount = $productDAO->min_contribution; + + if ($amount < $min_amount) { + $errors['selectProduct'] = ts('The premium you have selected requires a minimum contribution of %1', array(1 => CRM_Utils_Money::format($min_amount))); + CRM_Core_Session::setStatus($errors['selectProduct']); + } + } + + if ($self->_values['honor_block_is_active'] && CRM_Utils_Array::value('honor_type_id', $fields)) { + // make sure there is a first name and last name if email is not there + if (!CRM_Utils_Array::value('honor_email', $fields)) { + if (!CRM_Utils_Array::value('honor_first_name', $fields) || + !CRM_Utils_Array::value('honor_last_name', $fields) + ) { + $errors['honor_last_name'] = ts('In Honor Of - First Name and Last Name, OR an Email Address is required.'); + } + } + } + + if ( CRM_Utils_Array::value( 'is_recur', $fields ) ) { + if ($fields['frequency_interval'] <= 0) { + $errors['frequency_interval'] = ts('Please enter a number for how often you want to make this recurring contribution (EXAMPLE: Every 3 months).'); + } + if ($fields['frequency_unit'] == '0') { + $errors['frequency_unit'] = ts('Please select a period (e.g. months, years ...) for how often you want to make this recurring contribution (EXAMPLE: Every 3 MONTHS).'); + } + } + + if (CRM_Utils_Array::value('is_recur', $fields) && + CRM_Utils_Array::value('payment_processor', $fields) == 0) { + $errors['_qf_default'] = ts('You cannot set up a recurring contribution if you are not paying online by credit card.'); + } + + if (CRM_Utils_Array::value('is_for_organization', $fields) && + !property_exists($self, 'organizationName') + ) { + + if (!CRM_Utils_Array::value('organization_name', $fields['onbehalf'])) { + if (CRM_Utils_Array::value('org_option', $fields) && !$fields['onbehalfof_id']) { + $errors['organization_id'] = ts('Please select an organization or enter a new one.'); + } + elseif (!CRM_Utils_Array::value('org_option', $fields)) { + $errors['onbehalf']['organization_name'] = ts('Please enter the organization name.'); + } + } + + foreach ($fields['onbehalf'] as $key => $value) { + if (strstr($key, 'email')) { + $emailLocType = explode('-', $key); + } + } + if (!CRM_Utils_Array::value("email-{$emailLocType[1]}", $fields['onbehalf'])) { + $errors['onbehalf']["email-{$emailLocType[1]}"] = ts('Organization email is required.'); + } + } + + // validate PCP fields - if not anonymous, we need a nick name value + if ($self->_pcpId && CRM_Utils_Array::value('pcp_display_in_roll', $fields) && + (CRM_Utils_Array::value('pcp_is_anonymous', $fields) == 0) && + CRM_Utils_Array::value('pcp_roll_nickname', $fields) == '' + ) { + $errors['pcp_roll_nickname'] = ts('Please enter a name to include in the Honor Roll, or select \'contribute anonymously\'.'); + } + + // return if this is express mode + $config = CRM_Core_Config::singleton(); + if ($self->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON) { + if (CRM_Utils_Array::value($self->_expressButtonName . '_x', $fields) || + CRM_Utils_Array::value($self->_expressButtonName . '_y', $fields) || + CRM_Utils_Array::value($self->_expressButtonName, $fields) + ) { + return $errors; + } + } + + //validate the pledge fields. + if (CRM_Utils_Array::value('pledge_block_id', $self->_values)) { + //validation for pledge payment. + if (CRM_Utils_Array::value('pledge_id', $self->_values)) { + if (empty($fields['pledge_amount'])) { + $errors['pledge_amount'] = ts('At least one payment option needs to be checked.'); + } + } + elseif (CRM_Utils_Array::value('is_pledge', $fields)) { + if (CRM_Utils_Rule::positiveInteger(CRM_Utils_Array::value('pledge_installments', $fields)) == FALSE) { + $errors['pledge_installments'] = ts('Please enter a valid pledge installment.'); + } + else { + if (CRM_Utils_Array::value('pledge_installments', $fields) == NULL) { + $errors['pledge_installments'] = ts('Pledge Installments is required field.'); + } + elseif (CRM_Utils_array::value('pledge_installments', $fields) == 1) { + $errors['pledge_installments'] = ts('Pledges consist of multiple scheduled payments. Select one-time contribution if you want to make your gift in a single payment.'); + } + elseif (CRM_Utils_array::value('pledge_installments', $fields) == 0) { + $errors['pledge_installments'] = ts('Pledge Installments field must be > 1.'); + } + } + + //validation for Pledge Frequency Interval. + if (CRM_Utils_Rule::positiveInteger(CRM_Utils_Array::value('pledge_frequency_interval', $fields)) == FALSE) { + $errors['pledge_frequency_interval'] = ts('Please enter a valid Pledge Frequency Interval.'); + } + else { + if (CRM_Utils_Array::value('pledge_frequency_interval', $fields) == NULL) { + $errors['pledge_frequency_interval'] = ts('Pledge Frequency Interval. is required field.'); + } + elseif (CRM_Utils_array::value('pledge_frequency_interval', $fields) == 0) { + $errors['pledge_frequency_interval'] = ts('Pledge frequency interval field must be > 0'); + } + } + } + } + + // also return if paylater mode + if (CRM_Utils_Array::value('payment_processor', $fields) == 0) { + return empty($errors) ? TRUE : $errors; + } + + // if the user has chosen a free membership or the amount is less than zero + // i.e. we skip calling the payment processor and hence dont need credit card + // info + if ((float ) $amount <= 0.0) { + return $errors; + } + + if(isset($self->_paymentFields)) { + foreach ($self->_paymentFields as $name => $fld) { + if ($fld['is_required'] && + CRM_Utils_System::isNull(CRM_Utils_Array::value($name, $fields)) + ) { + $errors[$name] = ts('%1 is a required field.', array(1 => $fld['title'])); + } + } + } + + // make sure that credit card number and cvv are valid + if (CRM_Utils_Array::value('credit_card_type', $fields)) { + if (CRM_Utils_Array::value('credit_card_number', $fields) && + !CRM_Utils_Rule::creditCardNumber($fields['credit_card_number'], $fields['credit_card_type']) + ) { + $errors['credit_card_number'] = ts('Please enter a valid Credit Card Number'); + } + + if (CRM_Utils_Array::value('cvv2', $fields) && + !CRM_Utils_Rule::cvv($fields['cvv2'], $fields['credit_card_type']) + ) { + $errors['cvv2'] = ts('Please enter a valid Credit Card Verification Number'); + } + } + foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) { + if ($greetingType = CRM_Utils_Array::value($greeting, $fields)) { + $customizedValue = CRM_Core_OptionGroup::getValue($greeting, 'Customized', 'name'); + if ($customizedValue == $greetingType && empty($fielse[$greeting . '_custom'])) { + $errors[$greeting . '_custom'] = ts('Custom %1 is a required field if %1 is of type Customized.', + array(1 => ucwords(str_replace('_', " ", $greeting))) + ); + } + } + } + + return empty($errors) ? TRUE : $errors; + } + + public function computeAmount(&$params, &$form) { + $amount = NULL; + + // first clean up the other amount field if present + if (isset($params['amount_other'])) { + $params['amount_other'] = CRM_Utils_Rule::cleanMoney($params['amount_other']); + } + + if (CRM_Utils_Array::value('amount', $params) == 'amount_other_radio' || + CRM_Utils_Array::value('amount_other', $params) + ) { + $amount = $params['amount_other']; + } + elseif (!empty($params['pledge_amount'])) { + $amount = 0; + foreach ($params['pledge_amount'] as $paymentId => $dontCare) { + $amount += CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment', $paymentId, 'scheduled_amount'); + } + } + else { + if (CRM_Utils_Array::value('amount', $form->_values)) { + $amountID = CRM_Utils_Array::value('amount', $params); + + if ($amountID) { + $params['amount_level'] = CRM_Utils_Array::value('label', $form->_values[$amountID]); + $amount = CRM_Utils_Array::value('value', $form->_values[$amountID]); + } + } + } + return $amount; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + $config = CRM_Core_Config::singleton(); + + // we first reset the confirm page so it accepts new values + $this->controller->resetPage('Confirm'); + + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + if (CRM_Utils_Array::value('priceSetId', $params)) { + $is_quick_config = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_priceSetId, 'is_quick_config'); + $formValue = array(); + if ($is_quick_config) { + $priceField = new CRM_Price_DAO_Field(); + $priceField->price_set_id = $params['priceSetId']; + $priceField->orderBy('weight'); + $priceField->find(); + + $check = array(); + $otherAmount = FALSE; + while ($priceField->fetch()) { + CRM_Price_BAO_FieldValue::getValues($priceField->id, $values); + if ($priceField->name == 'membership_amount') { + if ($priceFiledID = CRM_Utils_Array::value("price_{$priceField->id}", $params)) { + $this->_params['selectMembership'] = $params['selectMembership'] = CRM_Utils_Array::value('membership_type_id', $values[$priceFiledID]); + $this->set('selectMembership',CRM_Utils_Array::value('selectMembership', $params)); + if (CRM_Utils_Array::value('is_separate_payment', $this->_membershipBlock) == 0) { + $this->_values['amount'] = CRM_Utils_Array::value('amount', $values[$priceFiledID]); + } + } + } + if ($priceField->name == 'contribution_amount') { + $priceFiledID = CRM_Utils_Array::value("price_{$priceField->id}", $params); + if ($priceFiledID > 0 && !empty($priceFiledID)) { + $params['amount'] = $priceFiledID; + $this->_values['amount'] = CRM_Utils_Array::value('amount', $values[$priceFiledID]); + $this->_values[$priceFiledID]['value'] = CRM_Utils_Array::value('amount', $values[$priceFiledID]); + $this->_values[$priceFiledID]['label'] = CRM_Utils_Array::value('label', $values[$priceFiledID]); + $this->_values[$priceFiledID]['amount_id'] = CRM_Utils_Array::value('id', $values[$priceFiledID]); + $this->_values[$priceFiledID]['weight'] = CRM_Utils_Array::value('weight', $values[$priceFiledID]); + } + } + if ($priceField->name == 'other_amount' && $priceFiledID = CRM_Utils_Array::value("price_{$priceField->id}", $params)) { + $params['amount_other'] = $priceFiledID; + } + } + } + } + + if (($this->_values['is_pay_later'] && + empty($this->_paymentProcessor) && + !array_key_exists('hidden_processor', $params)) || + CRM_Utils_Array::value('payment_processor', $params) == 0) { + $params['is_pay_later'] = 1; + } + else { + $params['is_pay_later'] = 0; + } + + $this->set('is_pay_later', $params['is_pay_later']); + // assign pay later stuff + $this->_params['is_pay_later'] = CRM_Utils_Array::value('is_pay_later', $params, FALSE); + $this->assign('is_pay_later', $params['is_pay_later']); + if ($params['is_pay_later']) { + $this->assign('pay_later_text', $this->_values['pay_later_text']); + $this->assign('pay_later_receipt', $this->_values['pay_later_receipt']); + } + + //carry campaign from profile. + if (array_key_exists('contribution_campaign_id', $params)) { + $params['campaign_id'] = $params['contribution_campaign_id']; + } + + if (CRM_Utils_Array::value('onbehalfof_id', $params)) { + $params['organization_id'] = $params['onbehalfof_id']; + } + + $params['currencyID'] = $config->defaultCurrency; + $params['amount'] = self::computeAmount($params, $this); + $params['separate_amount'] = $params['amount']; + $memFee = NULL; + if (CRM_Utils_Array::value('selectMembership', $params)) { + if (!empty($this->_membershipTypeValues)) { + $membershipTypeValues = $this->_membershipTypeValues[$params['selectMembership']]; + } + else { + $membershipTypeValues = CRM_Member_BAO_Membership::buildMembershipTypeValues($this, + $params['selectMembership'] + ); + } + $memFee = $membershipTypeValues['minimum_fee']; + if (!$params['amount'] && !$this->_separateMembershipPayment) { + $params['amount'] = $memFee ? $memFee : 0; + } + } + + //If the membership & contribution is used in contribution page & not seperate payment + $fieldId = $memPresent = $membershipLabel = $fieldOption = $proceFieldAmount = $is_quick_config = NULL; + if ($this->_separateMembershipPayment == 0) { + $is_quick_config = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_priceSetId, 'is_quick_config'); + if ($is_quick_config) { + foreach ($this->_priceSet['fields'] as $fieldKey => $fieldVal) { + if ($fieldVal['name'] == 'membership_amount') { + $fieldId = $fieldVal['id']; + $fieldOption = $params['price_' . $fieldId]; + $memPresent = TRUE; + } + else { + if (CRM_Utils_Array::value('price_' . $fieldKey, $params) && $memPresent && ($fieldVal['name'] == 'other_amount' || $fieldVal['name'] == 'contribution_amount')) { + $fieldId = $fieldVal['id']; + if ($fieldVal['name'] == 'other_amount') { + $proceFieldAmount = $this->_submitValues['price_' . $fieldId]; + } + else $proceFieldAmount = $fieldVal['options'][$this->_submitValues['price_' . $fieldId]]['amount']; + unset($params['price_' . $fieldId]); + break; + } + } + } + } + } + + if (!isset($params['amount_other'])) { + $this->set('amount_level', CRM_Utils_Array::value('amount_level', $params)); + } + + if ($priceSetId = CRM_Utils_Array::value('priceSetId', $params)) { + $lineItem = array(); + $is_quick_config = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $priceSetId, 'is_quick_config' ); + if ( $is_quick_config ) { + foreach ( $this->_values['fee'] as $key => & $val ) { + if ( $val['name'] == 'other_amount' && $val['html_type'] == 'Text' && array_key_exists( 'price_'.$key, $params ) && $params['price_'.$key] != 0 ) { + foreach ( $val['options'] as $optionKey => & $options ) { + $options['amount'] = CRM_Utils_Array::value( 'price_'.$key, $params ); + break; + } + $params['price_'.$key] = 1; + break; + } + } + } + + $component = ''; + if ($this->_membershipBlock) { + $component = 'membership'; + } + CRM_Price_BAO_Set::processAmount($this->_values['fee'], $params, $lineItem[$priceSetId], $component); + + if ($proceFieldAmount) { + $lineItem[$params['priceSetId']][$fieldOption]['line_total'] = $proceFieldAmount; + $lineItem[$params['priceSetId']][$fieldOption]['unit_price'] = $proceFieldAmount; + if (!$this->_membershipBlock['is_separate_payment']) { + $params['amount'] = $proceFieldAmount; //require when separate membership not used + } + } + $this->set('lineItem', $lineItem); + } + + if ($this->_membershipBlock['is_separate_payment'] && CRM_Utils_Array::value('separate_amount', $params)) { + $this->set('amount', $params['separate_amount']); + } else { + $this->set('amount', $params['amount']); + } + + // generate and set an invoiceID for this transaction + $invoiceID = md5(uniqid(rand(), TRUE)); + $this->set('invoiceID', $invoiceID); + + // required only if is_monetary and valid postive amount + if ($this->_values['is_monetary'] && + is_array($this->_paymentProcessor) && + ((float ) $params['amount'] > 0.0 || $memFee > 0.0) + ) { + + // default mode is direct + $this->set('contributeMode', 'direct'); + + if ($this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON) { + //get the button name + $buttonName = $this->controller->getButtonName(); + if (in_array($buttonName, + array($this->_expressButtonName, $this->_expressButtonName . '_x', $this->_expressButtonName . '_y') + ) && + !CRM_Utils_Array::value('is_pay_later', $params) + ) { + $this->set('contributeMode', 'express'); + + $donateURL = CRM_Utils_System::url('civicrm/contribute', '_qf_Contribute_display=1'); + $params['cancelURL'] = CRM_Utils_System::url('civicrm/contribute/transact', "_qf_Main_display=1&qfKey={$params['qfKey']}", TRUE, NULL, FALSE); + $params['returnURL'] = CRM_Utils_System::url('civicrm/contribute/transact', "_qf_Confirm_display=1&rfp=1&qfKey={$params['qfKey']}", TRUE, NULL, FALSE); + $params['invoiceID'] = $invoiceID; + + //default action is Sale + $params['payment_action'] = 'Sale'; + + $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this); + $token = $payment->setExpressCheckout($params); + if (is_a($token, 'CRM_Core_Error')) { + CRM_Core_Error::displaySessionError($token); + CRM_Utils_System::redirect($params['cancelURL']); + } + + $this->set('token', $token); + + $paymentURL = $this->_paymentProcessor['url_site'] . "/cgi-bin/webscr?cmd=_express-checkout&token=$token"; + CRM_Utils_System::redirect($paymentURL); + } + } + elseif ($this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY) { + $this->set('contributeMode', 'notify'); + } + } + + // should we skip the confirm page? + if (!CRM_Utils_Array::value('is_confirm_enabled', $this->_values)) { + // build the confirm page + $confirmForm = &$this->controller->_pages['Confirm']; + $confirmForm->preProcess(); + $confirmForm->buildQuickForm(); + + // the confirmation page is valid + $data = &$this->controller->container(); + $data['valid']['Confirm'] = 1; + + // confirm the contribution + $confirmForm->postProcess(); + $qfKey = $this->controller->_key; + + // redirect to thank you page + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/transact', "_qf_ThankYou_display=1&qfKey=$qfKey", TRUE, NULL, FALSE)); + } + } +} + diff --git a/CRM/Contribute/Form/Contribution/OnBehalfOf.php b/CRM/Contribute/Form/Contribution/OnBehalfOf.php new file mode 100644 index 0000000000..19cae8d928 --- /dev/null +++ b/CRM/Contribute/Form/Contribution/OnBehalfOf.php @@ -0,0 +1,178 @@ +get('userID'); + + $ufJoinParams = array( + 'module' => 'onBehalf', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $form->_id, + ); + $profileId = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + $form->_profileId = $profileId[0]; + + if (!$form->_profileId || + !CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $form->_profileId, 'is_active') + ) { + CRM_Core_Error::fatal(ts('This contribution page has been configured for contribution on behalf of an organization and the selected onbehalf profile is either disabled or not found.')); + } + + $requiredProfileFields = array('organization_name', 'email'); + $validProfile = CRM_Core_BAO_UFGroup::checkValidProfile($form->_profileId, $requiredProfileFields); + if (!$validProfile) { + CRM_Core_Error::fatal(ts('This contribution page has been configured for contribution on behalf of an organization and the required fields of the selected onbehalf profile are disabled.')); + } + + $form->assign('profileId', $form->_profileId); + $form->assign('mode', $form->_mode); + + if ($contactID) { + $form->_employers = CRM_Contact_BAO_Relationship::getPermissionedEmployer($contactID); + if (!empty($form->_employers)) { + $form->_relatedOrganizationFound = TRUE; + + $locDataURL = CRM_Utils_System::url('civicrm/ajax/permlocation', 'cid=', FALSE, NULL, FALSE); + $form->assign('locDataURL', $locDataURL); + + $dataURL = CRM_Utils_System::url('civicrm/ajax/employer', 'cid=' . $contactID, FALSE, NULL, FALSE); + $form->assign('employerDataURL', $dataURL); + } + + if ($form->_values['is_for_organization'] != 2) { + $form->assign('relatedOrganizationFound', $form->_relatedOrganizationFound); + } + else { + $form->assign('onBehalfRequired', $form->_onBehalfRequired); + } + + if (count($form->_employers) == 1) { + foreach ($form->_employers as $id => $value) { + $form->_organizationName = $value['name']; + $orgId = $id; + } + $form->assign('orgId', $orgId); + $form->assign('organizationName', $form->_organizationName); + } + } + } + + /** + * Function to build form for related contacts / on behalf of organization. + * + * @param $form object invoking Object + * @param $contactType string contact type + * @param $title string fieldset title + * + * @static + */ + static function buildQuickForm(&$form) { + $form->assign('fieldSetTitle', ts('Organization Details')); + $form->assign('buildOnBehalfForm', TRUE); + + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + + if ($contactID && count($form->_employers) >= 1) { + $form->add('text', 'organization_id', ts('Select an existing related Organization OR enter a new one')); + $form->add('hidden', 'onbehalfof_id', '', array('id' => 'onbehalfof_id')); + + $orgOptions = array(0 => ts('Select an existing organization'), + 1 => ts('Enter a new organization'), + ); + + $form->addRadio('org_option', ts('options'), $orgOptions); + $form->setDefaults(array('org_option' => 0)); + $form->add('checkbox', 'mode', ''); + } + + $profileFields = CRM_Core_BAO_UFGroup::getFields($form->_profileId, FALSE, CRM_Core_Action::VIEW, NULL, + NULL, FALSE, NULL, FALSE, NULL, + CRM_Core_Permission::CREATE, NULL + ); + $fieldTypes = array('Contact', 'Organization'); + $contactSubType = CRM_Contact_BAO_ContactType::subTypes('Organization'); + $fieldTypes = array_merge($fieldTypes, $contactSubType); + + if (is_array($form->_membershipBlock) && !empty($form->_membershipBlock)) { + $fieldTypes = array_merge($fieldTypes, array('Membership')); + } + else { + $fieldTypes = array_merge($fieldTypes, array('Contribution')); + } + + $stateCountryMap = array(); + foreach ($profileFields as $name => $field) { + if (in_array($field['field_type'], $fieldTypes)) { + list($prefixName, $index) = CRM_Utils_System::explode('-', $name, 2); + if (in_array($prefixName, array( + 'state_province', 'country', 'county'))) { + if (!array_key_exists($index, $stateCountryMap)) { + $stateCountryMap[$index] = array(); + } + + $stateCountryMap[$index][$prefixName] = 'onbehalf[' . $name . ']'; + } + elseif (in_array($prefixName, array( + 'organization_name', 'email')) && + !CRM_Utils_Array::value('is_required', $field) + ) { + $field['is_required'] = 1; + } + + CRM_Core_BAO_UFGroup::buildProfile($form, $field, NULL, NULL, FALSE, TRUE); + } + } + + if (!empty($stateCountryMap)) { + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + + // now fix all state country selectors + CRM_Core_BAO_Address::fixAllStateSelects($form, CRM_Core_DAO::$_nullArray); + } + + $form->assign('onBehalfOfFields', $profileFields); + $form->addElement('hidden', 'hidden_onbehalf_profile', 1); + } +} + diff --git a/CRM/Contribute/Form/Contribution/ThankYou.php b/CRM/Contribute/Form/Contribution/ThankYou.php new file mode 100644 index 0000000000..525b929d8d --- /dev/null +++ b/CRM/Contribute/Form/Contribution/ThankYou.php @@ -0,0 +1,298 @@ +_params = $this->get('params'); + $this->_lineItem = $this->get('lineItem'); + $is_deductible = $this->get('is_deductible'); + $this->assign('is_deductible', $is_deductible); + $this->assign('thankyou_title', CRM_Utils_Array::value('thankyou_title', $this->_values)); + $this->assign('thankyou_text', CRM_Utils_Array::value('thankyou_text', $this->_values)); + $this->assign('thankyou_footer', CRM_Utils_Array::value('thankyou_footer', $this->_values)); + $this->assign('max_reminders', CRM_Utils_Array::value('max_reminders', $this->_values)); + $this->assign('initial_reminder_day', CRM_Utils_Array::value('initial_reminder_day', $this->_values)); + CRM_Utils_System::setTitle(CRM_Utils_Array::value('thankyou_title', $this->_values)); + // Make the contributionPageID avilable to the template + $this->assign('contributionPageID', $this->_id); + $this->assign('isShare', $this->_values['is_share']); + + $this->_params['is_pay_later'] = $this->get('is_pay_later'); + $this->assign('is_pay_later', $this->_params['is_pay_later']); + if ($this->_params['is_pay_later']) { + $this->assign('pay_later_receipt', $this->_values['pay_later_receipt']); + } + } + + /** + * overwrite action, since we are only showing elements in frozen mode + * no help display needed + * + * @return int + * @access public + */ + function getAction() { + if ($this->_action & CRM_Core_Action::PREVIEW) { + return CRM_Core_Action::VIEW | CRM_Core_Action::PREVIEW; + } + else { + return CRM_Core_Action::VIEW; + } + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $this->assignToTemplate(); + $productID = $this->get('productID'); + $option = $this->get('option'); + $membershipTypeID = $this->get('membershipTypeID'); + $this->assign('receiptFromEmail', CRM_Utils_Array::value('receipt_from_email', $this->_values)); + + if ($productID) { + CRM_Contribute_BAO_Premium::buildPremiumBlock($this, $this->_id, FALSE, $productID, $option); + } + if ($this->_priceSetId && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $this->_priceSetId, 'is_quick_config')) { + $this->assign('lineItem', $this->_lineItem); + } else { + if (is_array($membershipTypeID)) { + $membershipTypeID = current($membershipTypeID); + } + $this->assign('is_quick_config', 1); + $this->_params['is_quick_config'] = 1; + } + $this->assign('priceSetID', $this->_priceSetId); + $this->assign('useForMember', $this->get('useForMember')); + + $params = $this->_params; + $honor_block_is_active = $this->get('honor_block_is_active'); + if ($honor_block_is_active && + ((!empty($params["honor_first_name"]) && !empty($params["honor_last_name"])) || + (!empty($params["honor_email"])) + ) + ) { + $this->assign('honor_block_is_active', $honor_block_is_active); + $this->assign('honor_block_title', CRM_Utils_Array::value('honor_block_title', $this->_values)); + + $prefix = CRM_Core_PseudoConstant::individualPrefix(); + $honor = CRM_Core_PseudoConstant::honor(); + $this->assign('honor_type', $honor[$params["honor_type_id"]]); + $this->assign('honor_prefix', ($params["honor_prefix_id"]) ? $prefix[$params["honor_prefix_id"]] : ' '); + $this->assign('honor_first_name', $params["honor_first_name"]); + $this->assign('honor_last_name', $params["honor_last_name"]); + $this->assign('honor_email', $params["honor_email"]); + } + + $qParams = "reset=1&id={$this->_id}"; + //pcp elements + if ($this->_pcpId) { + $qParams .= "&pcpId={$this->_pcpId}"; + $this->assign('pcpBlock', TRUE); + foreach (array( + 'pcp_display_in_roll', 'pcp_is_anonymous', 'pcp_roll_nickname', 'pcp_personal_note') as $val) { + if (CRM_Utils_Array::value($val, $this->_params)) { + $this->assign($val, $this->_params[$val]); + } + } + } + + $this->assign( 'qParams' , $qParams ); + + if ($membershipTypeID) { + $transactionID = $this->get('membership_trx_id'); + $membershipAmount = $this->get('membership_amount'); + $renewalMode = $this->get('renewal_mode'); + $this->assign('membership_trx_id', $transactionID); + $this->assign('membership_amount', $membershipAmount); + $this->assign('renewal_mode', $renewalMode); + + CRM_Member_BAO_Membership::buildMembershipBlock($this, + $this->_id, + FALSE, + $membershipTypeID, + TRUE, NULL, + $this->_membershipContactID + ); + } + + $this->_separateMembershipPayment = $this->get('separateMembershipPayment'); + $this->assign("is_separate_payment", $this->_separateMembershipPayment); + + $this->buildCustom($this->_values['custom_pre_id'], 'customPre', TRUE); + $this->buildCustom($this->_values['custom_post_id'], 'customPost', TRUE); + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $params)) { + $ufJoinParams = array( + 'module' => 'onBehalf', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $this->_id, + ); + $OnBehalfProfile = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + $profileId = $OnBehalfProfile[0]; + + $fieldTypes = array('Contact', 'Organization'); + $contactSubType = CRM_Contact_BAO_ContactType::subTypes('Organization'); + $fieldTypes = array_merge($fieldTypes, $contactSubType); + if (is_array($this->_membershipBlock) && !empty($this->_membershipBlock)) { + $fieldTypes = array_merge($fieldTypes, array('Membership')); + } + else { + $fieldTypes = array_merge($fieldTypes, array('Contribution')); + } + + $this->buildCustom($profileId, 'onbehalfProfile', TRUE, TRUE, $fieldTypes); + } + + $this->assign('trxn_id', + CRM_Utils_Array::value('trxn_id', + $this->_params + ) + ); + $this->assign('receive_date', + CRM_Utils_Date::mysqlToIso(CRM_Utils_Array::value('receive_date', $this->_params)) + ); + + $defaults = array(); + $fields = array(); + foreach ($this->_fields as $name => $dontCare) { + if ($name == 'onbehalf') { + foreach ($dontCare as $key => $value) { + $fields['onbehalf'][$key] = 1; + } + } + else { + $fields[$name] = 1; + } + } + $fields['state_province'] = $fields['country'] = $fields['email'] = 1; + $contact = $this->_params = $this->controller->exportValues('Main'); + + foreach ($fields as $name => $dontCare) { + if ($name == 'onbehalf') { + foreach ($dontCare as $key => $value) { + //$defaults[$key] = $contact['onbehalf'][$key]; + if (isset($contact['onbehalf'][$key])) { + $defaults[$key] = $contact['onbehalf'][$key]; + } + if (isset($contact['onbehalf']["{$key}_id"])) { + $defaults["{$key}_id"] = $contact['onbehalf']["{$key}_id"]; + } + + } + } + elseif (isset($contact[$name])) { + $defaults[$name] = $contact[$name]; + if (substr($name, 0, 7) == 'custom_') { + $timeField = "{$name}_time"; + if (isset($contact[$timeField])) { + $defaults[$timeField] = $contact[$timeField]; + } + } + elseif (in_array($name, array('addressee', 'email_greeting', 'postal_greeting')) + && CRM_Utils_Array::value($name . '_custom', $contact) + ) { + $defaults[$name . '_custom'] = $contact[$name . '_custom']; + } + } + } + + // now fix all state country selectors + CRM_Core_BAO_Address::fixAllStateSelects($this, $defaults); + + $this->_submitValues = array_merge($this->_submitValues, $defaults); + $this->setDefaults($defaults); + + $values['entity_id'] = $this->_id; + $values['entity_table'] = 'civicrm_contribution_page'; + + CRM_Friend_BAO_Friend::retrieve($values, $data); + $tellAFriend = FALSE; + if ($this->_pcpId) { + if ($this->_pcpBlock['is_tellfriend_enabled']) { + $this->assign('friendText', ts('Tell a Friend')); + $subUrl = "eid={$this->_pcpId}&blockId={$this->_pcpBlock['id']}&pcomponent=pcp"; + $tellAFriend = TRUE; + } + } + elseif (CRM_Utils_Array::value('is_active', $data)) { + $friendText = $data['title']; + $this->assign('friendText', $friendText); + $subUrl = "eid={$this->_id}&pcomponent=contribute"; + $tellAFriend = TRUE; + } + + if ($tellAFriend) { + if ($this->_action & CRM_Core_Action::PREVIEW) { + $url = CRM_Utils_System::url("civicrm/friend", + "reset=1&action=preview&{$subUrl}" + ); + } + else { + $url = CRM_Utils_System::url("civicrm/friend", + "reset=1&{$subUrl}" + ); + } + $this->assign('friendURL', $url); + } + + $this->freeze(); + + // can we blow away the session now to prevent hackery + // CRM-9491 + $this->controller->reset(); + } +} + diff --git a/CRM/Contribute/Form/ContributionBase.php b/CRM/Contribute/Form/ContributionBase.php new file mode 100644 index 0000000000..c316601bb7 --- /dev/null +++ b/CRM/Contribute/Form/ContributionBase.php @@ -0,0 +1,827 @@ +_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + if (!$this->_id) { + $pastContributionID = $session->get('pastContributionID'); + if (!$pastContributionID) { + CRM_Core_Error::fatal(ts('We can\'t load the requested web page due to an incomplete link. This can be caused by using your browser\'s Back button or by using an incomplete or invalid link.')); + } + else { + CRM_Core_Error::fatal(ts('An error occurred during form submission. This page requires form data to be submitted for processing and no form data was submitted or processed. We are sorry for any inconvience. Please click here to visit the contribution page and re-start the contribution process.', array(1 => CRM_Utils_System::url('civicrm/contribute/transact', 'reset=1&id=' . $pastContributionID)))); + } + } + else { + $session->set('pastContributionID', $this->_id); + } + + $this->_userID = $session->get('userID'); + $this->_mid = NULL; + if ($this->_userID) { + $this->_mid = CRM_Utils_Request::retrieve('mid', 'Positive', $this); + if ($this->_mid) { + $membership = new CRM_Member_DAO_Membership(); + $membership->id = $this->_mid; + + if ($membership->find(TRUE)) { + $this->_defaultMemTypeId = $membership->membership_type_id; + if ($membership->contact_id != $this->_userID) { + $employers = CRM_Contact_BAO_Relationship::getPermissionedEmployer($this->_userID); + if (array_key_exists($membership->contact_id, $employers)) { + $this->_membershipContactID = $membership->contact_id; + $this->assign('membershipContactID', $this->_membershipContactID); + $this->assign('membershipContactName', $employers[$this->_membershipContactID]['name']); + } + else { + CRM_Core_Session::setStatus(ts("Oops. The membership you're trying to renew appears to be invalid. Contact your site administrator if you need assistance. If you continue, you will be issued a new membership."), ts('Membership Invalid'), 'alert'); + } + } + } + else { + CRM_Core_Session::setStatus(ts("Oops. The membership you're trying to renew appears to be invalid. Contact your site administrator if you need assistance. If you continue, you will be issued a new membership."), ts('Membership Invalid'), 'alert'); + } + unset($membership); + } + } + + // we do not want to display recently viewed items, so turn off + $this->assign('displayRecent', FALSE); + // Contribution page values are cleared from session, so can't use normal Printer Friendly view. + // Use Browser Print instead. + $this->assign('browserPrint', TRUE); + + // action + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add'); + $this->assign('action', $this->_action); + + // current mode + $this->_mode = ($this->_action == 1024) ? 'test' : 'live'; + + $this->_values = $this->get('values'); + $this->_fields = $this->get('fields'); + $this->_bltID = $this->get('bltID'); + $this->_paymentProcessor = $this->get('paymentProcessor'); + $this->_priceSetId = $this->get('priceSetId'); + $this->_priceSet = $this->get('priceSet'); + + if (!$this->_values) { + // get all the values from the dao object + $this->_values = array(); + $this->_fields = array(); + + CRM_Contribute_BAO_ContributionPage::setValues($this->_id, $this->_values); + + // check if form is active + if (!CRM_Utils_Array::value('is_active', $this->_values)) { + // form is inactive, die a fatal death + CRM_Core_Error::fatal(ts('The page you requested is currently unavailable.')); + } + + // also check for billing informatin + // get the billing location type + $locationTypes = CRM_Core_PseudoConstant::locationType(); + // CRM-8108 remove ts around Billing location type + //$this->_bltID = array_search( ts('Billing'), $locationTypes ); + $this->_bltID = array_search('Billing', $locationTypes); + if (!$this->_bltID) { + CRM_Core_Error::fatal(ts('Please set a location type of %1', array(1 => 'Billing'))); + } + $this->set('bltID', $this->_bltID); + + // check for is_monetary status + $isMonetary = CRM_Utils_Array::value('is_monetary', $this->_values); + $isPayLater = CRM_Utils_Array::value('is_pay_later', $this->_values); + + //FIXME: to support multiple payment processors + if ($isMonetary && + (!$isPayLater || CRM_Utils_Array::value('payment_processor', $this->_values)) + ) { + $ppID = CRM_Utils_Array::value('payment_processor', $this->_values); + if (!$ppID) { + CRM_Core_Error::fatal(ts('A payment processor must be selected for this contribution page (contact the site administrator for assistance).')); + } + + $ppIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $ppID); + $this->_paymentProcessors = CRM_Financial_BAO_PaymentProcessor::getPayments($ppIds, $this->_mode); + + $this->set('paymentProcessors', $this->_paymentProcessors); + + //set default payment processor + if (!empty($this->_paymentProcessors) && empty($this->_paymentProcessor)) { + foreach ($this->_paymentProcessors as $ppId => $values) { + if ($values['is_default'] == 1 || (count($this->_paymentProcessors) == 1)) { + $defaultProcessorId = $ppId; + break; + } + } + } + + if (isset($defaultProcessorId)) { + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($defaultProcessorId, $this->_mode); + $this->assign_by_ref('paymentProcessor', $this->_paymentProcessor); + } + + if (!CRM_Utils_System::isNull($this->_paymentProcessors)) { + foreach ($this->_paymentProcessors as $eachPaymentProcessor) { + // check selected payment processor is active + if (empty($eachPaymentProcessor)) { + CRM_Core_Error::fatal(ts('A payment processor configured for this page might be disabled (contact the site administrator for assistance).')); + } + + // ensure that processor has a valid config + $this->_paymentObject = &CRM_Core_Payment::singleton($this->_mode, $eachPaymentProcessor, $this); + $error = $this->_paymentObject->checkConfig(); + if (!empty($error)) { + CRM_Core_Error::fatal($error); + } + } + } + } + + // get price info + // CRM-5095 + CRM_Price_BAO_Set::initSet($this, $this->_id, 'civicrm_contribution_page'); + + // this avoids getting E_NOTICE errors in php + $setNullFields = array( + 'amount_block_is_active', + 'honor_block_is_active', + 'is_allow_other_amount', + 'footer_text', + ); + foreach ($setNullFields as $f) { + if (!isset($this->_values[$f])) { + $this->_values[$f] = NULL; + } + } + + //check if Membership Block is enabled, if Membership Fields are included in profile + //get membership section for this contribution page + $this->_membershipBlock = CRM_Member_BAO_Membership::getMembershipBlock($this->_id); + $this->set('membershipBlock', $this->_membershipBlock); + + if ($this->_values['custom_pre_id']) { + $preProfileType = CRM_Core_BAO_UFField::getProfileType($this->_values['custom_pre_id']); + } + + if ($this->_values['custom_post_id']) { + $postProfileType = CRM_Core_BAO_UFField::getProfileType($this->_values['custom_post_id']); + } + + if (((isset($postProfileType) && $postProfileType == 'Membership') || + (isset($preProfileType) && $preProfileType == 'Membership') + ) && + !$this->_membershipBlock['is_active'] + ) { + CRM_Core_Error::fatal(ts('This page includes a Profile with Membership fields - but the Membership Block is NOT enabled. Please notify the site administrator.')); + } + + $pledgeBlock = CRM_Pledge_BAO_PledgeBlock::getPledgeBlock($this->_id); + + if ($pledgeBlock) { + $this->_values['pledge_block_id'] = CRM_Utils_Array::value('id', $pledgeBlock); + $this->_values['max_reminders'] = CRM_Utils_Array::value('max_reminders', $pledgeBlock); + $this->_values['initial_reminder_day'] = CRM_Utils_Array::value('initial_reminder_day', $pledgeBlock); + $this->_values['additional_reminder_day'] = CRM_Utils_Array::value('additional_reminder_day', $pledgeBlock); + + //set pledge id in values + $pledgeId = CRM_Utils_Request::retrieve('pledgeId', 'Positive', $this); + + //authenticate pledge user for pledge payment. + if ($pledgeId) { + $this->_values['pledge_id'] = $pledgeId; + + //lets override w/ pledge campaign. + $this->_values['campaign_id'] = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_Pledge', + $pledgeId, + 'campaign_id' + ); + self::authenticatePledgeUser(); + } + } + $this->set('values', $this->_values); + $this->set('fields', $this->_fields); + } + + // Handle PCP + $pcpId = CRM_Utils_Request::retrieve('pcpId', 'Positive', $this); + if ($pcpId) { + $pcp = CRM_PCP_BAO_PCP::handlePcp($pcpId, 'contribute', $this->_values); + $this->_pcpId = $pcp['pcpId']; + $this->_pcpBlock = $pcp['pcpBlock']; + $this->_pcpInfo = $pcp['pcpInfo']; + } + + // Link (button) for users to create their own Personal Campaign page + if ($linkText = CRM_PCP_BAO_PCP::getPcpBlockStatus($this->_id, 'contribute')) { + $linkTextUrl = CRM_Utils_System::url('civicrm/contribute/campaign', + "action=add&reset=1&pageId={$this->_id}&component=contribute", + FALSE, NULL, TRUE + ); + $this->assign('linkTextUrl', $linkTextUrl); + $this->assign('linkText', $linkText); + } + + //set pledge block if block id is set + if (CRM_Utils_Array::value('pledge_block_id', $this->_values)) { + $this->assign('pledgeBlock', TRUE); + } + + // check if one of the (amount , membership) bloks is active or not + $this->_membershipBlock = $this->get('membershipBlock'); + + if (!$this->_values['amount_block_is_active'] && + !$this->_membershipBlock['is_active'] && + !$this->_priceSetId + ) { + CRM_Core_Error::fatal(ts('The requested online contribution page is missing a required Contribution Amount section or Membership section or Price Set. Please check with the site administrator for assistance.')); + } + + if ($this->_values['amount_block_is_active']) { + $this->set('amount_block_is_active', $this->_values['amount_block_is_active']); + } + + $this->_contributeMode = $this->get('contributeMode'); + $this->assign('contributeMode', $this->_contributeMode); + + //assigning is_monetary and is_email_receipt to template + $this->assign('is_monetary', $this->_values['is_monetary']); + $this->assign('is_email_receipt', $this->_values['is_email_receipt']); + $this->assign('bltID', $this->_bltID); + + //assign cancelSubscription URL to templates + $this->assign('cancelSubscriptionUrl', + CRM_Utils_Array::value('cancelSubscriptionUrl', $this->_values) + ); + + // assigning title to template in case someone wants to use it, also setting CMS page title + if ($this->_pcpId) { + $this->assign('title', $this->_pcpInfo['title']); + CRM_Utils_System::setTitle($this->_pcpInfo['title']); + } + else { + $this->assign('title', $this->_values['title']); + CRM_Utils_System::setTitle($this->_values['title']); + } + $this->_defaults = array(); + + $this->_amount = $this->get('amount'); + + //CRM-6907 + $config = CRM_Core_Config::singleton(); + $config->defaultCurrency = CRM_Utils_Array::value('currency', + $this->_values, + $config->defaultCurrency + ); + + //lets allow user to override campaign. + $campID = CRM_Utils_Request::retrieve('campID', 'Positive', $this); + if ($campID && CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Campaign', $campID)) { + $this->_values['campaign_id'] = $campID; + } + + //do check for cancel recurring and clean db, CRM-7696 + if (CRM_Utils_Request::retrieve('cancel', 'Boolean', CRM_Core_DAO::$_nullObject)) { + self::cancelRecurring(); + } + } + + /** + * set the default values + * + * @return void + * @access public + */ + function setDefaultValues() { + return $this->_defaults; + } + + /** + * assign the minimal set of variables to the template + * + * @return void + * @access public + */ + function assignToTemplate() { + $name = CRM_Utils_Array::value('billing_first_name', $this->_params); + if (CRM_Utils_Array::value('billing_middle_name', $this->_params)) { + $name .= " {$this->_params['billing_middle_name']}"; + } + $name .= ' ' . CRM_Utils_Array::value('billing_last_name', $this->_params); + $name = trim($name); + $this->assign('billingName', $name); + $this->set('name', $name); + + $this->assign('paymentProcessor', $this->_paymentProcessor); + $vars = array( + 'amount', 'currencyID', + 'credit_card_type', 'trxn_id', 'amount_level', + ); + + $config = CRM_Core_Config::singleton(); + if (isset($this->_values['is_recur']) && + $this->_paymentProcessor['is_recur'] + ) { + $this->assign('is_recur_enabled', 1); + $vars = array_merge($vars, array( + 'is_recur', 'frequency_interval', 'frequency_unit', + 'installments', + )); + } + + if (in_array('CiviPledge', $config->enableComponents) && + CRM_Utils_Array::value('is_pledge', $this->_params) == 1 + ) { + $this->assign('pledge_enabled', 1); + + $vars = array_merge($vars, array( + 'is_pledge', + 'pledge_frequency_interval', + 'pledge_frequency_unit', + 'pledge_installments', + )); + } + + if (isset($this->_params['amount_other']) || isset($this->_params['selectMembership'])) { + $this->_params['amount_level'] = ''; + } + + foreach ($vars as $v) { + if (CRM_Utils_Array::value($v, $this->_params)) { + if ($v == 'frequency_unit' || $v == 'pledge_frequency_unit') { + $frequencyUnits = CRM_Core_OptionGroup::values('recur_frequency_units'); + if (array_key_exists($this->_params[$v], $frequencyUnits)) { + $this->_params[$v] = $frequencyUnits[$this->_params[$v]]; + } + } + $this->assign($v, $this->_params[$v]); + } + } + + // assign the address formatted up for display + $addressParts = array( + "street_address-{$this->_bltID}", + "city-{$this->_bltID}", + "postal_code-{$this->_bltID}", + "state_province-{$this->_bltID}", + "country-{$this->_bltID}", + ); + + $addressFields = array(); + foreach ($addressParts as $part) { + list($n, $id) = explode('-', $part); + $addressFields[$n] = CRM_Utils_Array::value('billing_' . $part, $this->_params); + } + + $this->assign('address', CRM_Utils_Address::format($addressFields)); + + if (CRM_Utils_Array::value('hidden_onbehalf_profile', $this->_params)) { + $this->assign('onBehalfName', $this->_params['organization_name']); + $locTypeId = array_keys($this->_params['onbehalf_location']['email']); + $this->assign('onBehalfEmail', $this->_params['onbehalf_location']['email'][$locTypeId[0]]['email']); + } + + //fix for CRM-3767 + $assignCCInfo = FALSE; + if ($this->_amount > 0.0) { + $assignCCInfo = TRUE; + } + elseif (CRM_Utils_array::value('selectMembership', $this->_params)) { + $memFee = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $this->_params['selectMembership'], 'minimum_fee'); + if ($memFee > 0.0) { + $assignCCInfo = TRUE; + } + } + + if ($this->_contributeMode == 'direct' && $assignCCInfo) { + if ($this->_paymentProcessor['payment_type'] & CRM_Core_Payment::PAYMENT_TYPE_DIRECT_DEBIT) { + $this->assign('payment_type', $this->_paymentProcessor['payment_type']); + $this->assign('account_holder', $this->_params['account_holder']); + $this->assign('bank_identification_number', $this->_params['bank_identification_number']); + $this->assign('bank_name', $this->_params['bank_name']); + $this->assign('bank_account_number', $this->_params['bank_account_number']); + } + else { + $date = CRM_Utils_Date::format(CRM_Utils_array::value('credit_card_exp_date', $this->_params)); + $date = CRM_Utils_Date::mysqlToIso($date); + $this->assign('credit_card_exp_date', $date); + $this->assign('credit_card_number', + CRM_Utils_System::mungeCreditCard(CRM_Utils_array::value('credit_card_number', $this->_params)) + ); + } + } + + $this->assign('email', + $this->controller->exportValue('Main', "email-{$this->_bltID}") + ); + + // also assign the receipt_text + if (isset($this->_values['receipt_text'])) { + $this->assign('receipt_text', $this->_values['receipt_text']); + } + } + + /** + * Function to add the custom fields + * + * @return None + * @access public + */ + function buildCustom($id, $name, $viewOnly = FALSE, $onBehalf = FALSE, $fieldTypes = NULL) { + $stateCountryMap = array(); + + if ($id) { + $contactID = $this->_userID; + + // we don't allow conflicting fields to be + // configured via profile - CRM 2100 + $fieldsToIgnore = array( + 'receive_date' => 1, + 'trxn_id' => 1, + 'invoice_id' => 1, + 'net_amount' => 1, + 'fee_amount' => 1, + 'non_deductible_amount' => 1, + 'total_amount' => 1, + 'amount_level' => 1, + 'contribution_status_id' => 1, + 'payment_instrument' => 1, + 'check_number' => 1, + 'financial_type' => 1, + ); + + $fields = NULL; + if ($contactID && CRM_Core_BAO_UFGroup::filterUFGroups($id, $contactID)) { + $fields = CRM_Core_BAO_UFGroup::getFields($id, FALSE, CRM_Core_Action::ADD, NULL, NULL, FALSE, + NULL, FALSE, NULL, CRM_Core_Permission::CREATE, NULL + ); + } + else { + $fields = CRM_Core_BAO_UFGroup::getFields($id, FALSE, CRM_Core_Action::ADD, NULL, NULL, FALSE, + NULL, FALSE, NULL, CRM_Core_Permission::CREATE, NULL + ); + } + + if ($fields) { + // unset any email-* fields since we already collect it, CRM-2888 + foreach (array_keys($fields) as $fieldName) { + if (substr($fieldName, 0, 6) == 'email-') { + unset($fields[$fieldName]); + } + } + + if (array_intersect_key($fields, $fieldsToIgnore)) { + $fields = array_diff_key($fields, $fieldsToIgnore); + CRM_Core_Session::setStatus(ts('Some of the profile fields cannot be configured for this page.'), ts('Warning'), 'alert'); + } + + $fields = array_diff_assoc($fields, $this->_fields); + + CRM_Core_BAO_Address::checkContactSharedAddressFields($fields, $contactID); + $addCaptcha = FALSE; + foreach ($fields as $key => $field) { + if ($viewOnly && + isset($field['data_type']) && + $field['data_type'] == 'File' || ($viewOnly && $field['name'] == 'image_URL') + ) { + // ignore file upload fields + continue; + } + + list($prefixName, $index) = CRM_Utils_System::explode('-', $key, 2); + if ($prefixName == 'state_province' || $prefixName == 'country' || $prefixName == 'county') { + if (!array_key_exists($index, $stateCountryMap)) { + $stateCountryMap[$index] = array(); + } + $stateCountryMap[$index][$prefixName] = $key; + } + + if ($onBehalf) { + if (!empty($fieldTypes) && in_array($field['field_type'], $fieldTypes)) { + CRM_Core_BAO_UFGroup::buildProfile( + $this, + $field, + CRM_Profile_Form::MODE_CREATE, + $contactID, + TRUE + ); + $this->_fields['onbehalf'][$key] = $field; + } + else { + unset($fields[$key]); + } + } + else { + CRM_Core_BAO_UFGroup::buildProfile( + $this, + $field, + CRM_Profile_Form::MODE_CREATE, + $contactID, + TRUE + ); + $this->_fields[$key] = $field; + } + if ($field['add_captcha']) { + $addCaptcha = TRUE; + } + } + + $this->assign($name, $fields); + + CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap); + + if ($addCaptcha && !$viewOnly) { + $captcha = CRM_Utils_ReCAPTCHA::singleton(); + $captcha->add($this); + $this->assign('isCaptcha', TRUE); + } + } + } + } + + function checkTemplateFileExists($suffix = NULL) { + if ($this->_id) { + $templateFile = "CRM/Contribute/Form/Contribution/{$this->_id}/{$this->_name}.{$suffix}tpl"; + $template = CRM_Core_Form::getTemplate(); + if ($template->template_exists($templateFile)) { + return $templateFile; + } + } + return NULL; + } + + function getTemplateFileName() { + $fileName = $this->checkTemplateFileExists(); + return $fileName ? $fileName : parent::getTemplateFileName(); + } + + function overrideExtraTemplateFileName() { + $fileName = $this->checkTemplateFileExists('extra.'); + return $fileName ? $fileName : parent::overrideExtraTemplateFileName(); + } + + /** + * Function to authenticate pledge user during online payment. + * + * @access public + * + * @return None + */ + public function authenticatePledgeUser() { + //get the userChecksum and contact id + $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this); + $contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + //get pledge status and contact id + $pledgeValues = array(); + $pledgeParams = array('id' => $this->_values['pledge_id']); + $returnProperties = array('contact_id', 'status_id'); + CRM_Core_DAO::commonRetrieve('CRM_Pledge_DAO_Pledge', $pledgeParams, $pledgeValues, $returnProperties); + + //get all status + $allStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + $validStatus = array(array_search('Pending', $allStatus), + array_search('In Progress', $allStatus), + array_search('Overdue', $allStatus), + ); + + $validUser = FALSE; + if ($this->_userID && + $this->_userID == $pledgeValues['contact_id'] + ) { + //check for authenticated user. + $validUser = TRUE; + } + elseif ($userChecksum && $pledgeValues['contact_id']) { + //check for anonymous user. + $validUser = CRM_Contact_BAO_Contact_Utils::validChecksum($pledgeValues['contact_id'], $userChecksum); + + //make sure cid is same as pledge contact id + if ($validUser && ($pledgeValues['contact_id'] != $contactID)) { + $validUser = FALSE; + } + } + + if (!$validUser) { + CRM_Core_Error::fatal(ts("Oops. It looks like you have an incorrect or incomplete link (URL). Please make sure you've copied the entire link, and try again. Contact the site administrator if this error persists.")); + } + + //check for valid pledge status. + if (!in_array($pledgeValues['status_id'], $validStatus)) { + CRM_Core_Error::fatal(ts('Oops. You cannot make a payment for this pledge - pledge status is %1.', array(1 => CRM_Utils_Array::value($pledgeValues['status_id'], $allStatus)))); + } + } + + /** + * In case user cancel recurring contribution, + * When we get the control back from payment gate way + * lets delete the recurring and related contribution. + * + **/ + public function cancelRecurring() { + $isCancel = CRM_Utils_Request::retrieve('cancel', 'Boolean', CRM_Core_DAO::$_nullObject); + if ($isCancel) { + $isRecur = CRM_Utils_Request::retrieve('isRecur', 'Boolean', CRM_Core_DAO::$_nullObject); + $recurId = CRM_Utils_Request::retrieve('recurId', 'Positive', CRM_Core_DAO::$_nullObject); + //clean db for recurring contribution. + if ($isRecur && $recurId) { + CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($recurId); + } + $contribId = CRM_Utils_Request::retrieve('contribId', 'Positive', CRM_Core_DAO::$_nullObject); + if ($contribId) { + CRM_Contribute_BAO_Contribution::deleteContribution($contribId); + } + } + } +} + diff --git a/CRM/Contribute/Form/ContributionCharts.php b/CRM/Contribute/Form/ContributionCharts.php new file mode 100644 index 0000000000..2ad052ad55 --- /dev/null +++ b/CRM/Contribute/Form/ContributionCharts.php @@ -0,0 +1,241 @@ +_year = CRM_Utils_Request::retrieve('year', 'Int', $this); + $this->_chartType = CRM_Utils_Request::retrieve('type', 'String', $this); + + $buildChart = FALSE; + + if ($this->_year || $this->_chartType) { + $buildChart = TRUE; + } + $this->assign('buildChart', $buildChart); + $this->postProcess(); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //p3 = Three dimensional pie chart. + //bvg = Vertical bar chart + $this->addElement('select', 'chart_type', ts('Chart Style'), array('bvg' => ts('Bar'), + 'p3' => ts('Pie'), + ), + array('onchange' => "getChart();") + ); + $defaultValues['chart_type'] = $this->_chartType; + $this->setDefaults($defaultValues); + + //take available years from database to show in drop down + $currentYear = date('Y'); + $years = array(); + if (!empty($this->_years)) { + if (!array_key_exists($currentYear, $this->_years)) { + $this->_years[$currentYear] = $currentYear; + krsort($this->_years); + } + foreach ($this->_years as $k => $v) { + $years[substr($k,0,4)] = substr($k,0,4); + } + } + + $this->addElement('select', 'select_year', ts('Select Year (for monthly breakdown)'), + $years, array('onchange' => "getChart();") + ); + $this->setDefaults(array( + 'select_year' => ($this->_year) ? $this->_year : $currentYear, + )); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $config = CRM_Core_Config::singleton(); + $chartType = 'bvg'; + if ($this->_chartType) { + $chartType = $this->_chartType; + } + $selectedYear = date('Y'); + if ($this->_year) { + $selectedYear = $this->_year; + } + + //take contribution information monthly + $chartInfoMonthly = CRM_Contribute_BAO_Contribution_Utils::contributionChartMonthly($selectedYear); + + $chartData = $abbrMonthNames = array(); + if (is_array($chartInfoMonthly)) { + for ($i = 1; $i <= 12; $i++) { + $abbrMonthNames[$i] = strftime('%b', mktime(0, 0, 0, $i, 10, 1970)); + } + + foreach ($abbrMonthNames as $monthKey => $monthName) { + $val = CRM_Utils_Array::value($monthKey, $chartInfoMonthly['By Month'], 0); + + // don't include zero value month. + if (!$val && ($chartType != 'bvg')) { + continue; + } + + //build the params for chart. + $chartData['by_month']['values'][$monthName] = $val; + } + $chartData['by_month']['legend'] = 'By Month' . ' - ' . $selectedYear; + + // handle onclick event. + $chartData['by_month']['on_click_fun_name'] = 'byMonthOnClick'; + $chartData['by_month']['yname'] = ts('Contribution'); + } + + //take contribution information by yearly + $chartInfoYearly = CRM_Contribute_BAO_Contribution_Utils::contributionChartYearly(); + + //get the years. + $this->_years = $chartInfoYearly['By Year']; + $hasContributions = FALSE; + if (is_array($chartInfoYearly)) { + $hasContributions = TRUE; + $chartData['by_year']['legend'] = 'By Year'; + $chartData['by_year']['values'] = $chartInfoYearly['By Year']; + + // handle onclick event. + $chartData['by_year']['on_click_fun_name'] = 'byYearOnClick'; + $chartData['by_year']['yname'] = ts('Total Amount'); + } + $this->assign('hasContributions', $hasContributions); + + // process the data. + $chartCnt = 1; + + $monthlyChart = $yearlyChart = FALSE; + + foreach ($chartData as $chartKey => & $values) { + $chartValues = CRM_Utils_Array::value('values', $values); + + if (!is_array($chartValues) || empty($chartValues)) { + continue; + } + if ($chartKey == 'by_year') { + $yearlyChart = TRUE; + if (!empty($config->fiscalYearStart) && ($config->fiscalYearStart['M'] !== 1 || $config->fiscalYearStart['d'] !== 1)) { + $values['xLabelAngle'] = 45 ; + } else { + $values['xLabelAngle'] = 0 ; + } + } + if ($chartKey == 'by_month') { + $monthlyChart = TRUE; + } + + $values['divName'] = "open_flash_chart_{$chartKey}"; + $funName = ($chartType == 'bvg') ? 'barChart' : 'pieChart'; + + // build the chart objects. + eval("\$values['object'] = CRM_Utils_OpenFlashChart::" . $funName . '( $values );'); + + //build the urls. + $urlCnt = 0; + foreach ($chartValues as $index => $val) { + $urlParams = NULL; + if ($chartKey == 'by_month') { + $monthPosition = array_search($index, $abbrMonthNames); + $startDate = CRM_Utils_Date::format(array('Y' => $selectedYear, 'M' => $monthPosition)); + $endDate = date('Ymd', mktime(0, 0, 0, $monthPosition + 1, 0, $selectedYear)); + $urlParams = "reset=1&force=1&status=1&start={$startDate}&end={$endDate}&test=0"; + } + elseif ($chartKey == 'by_year') { + $startDate = CRM_Utils_Date::format(array('Y' => substr($index,0,4))); + $endDate = date('Ymd', mktime(0, 0, 0, 13, 0, substr($index,0,4))); + $urlParams = "reset=1&force=1&status=1&start={$startDate}&end={$endDate}&test=0"; + } + if ($urlParams) { + $values['on_click_urls']["url_" . $urlCnt++] = CRM_Utils_System::url('civicrm/contribute/search', + $urlParams, TRUE, FALSE, FALSE + ); + } + } + + // calculate chart size. + $xSize = 400; + $ySize = 300; + if ($chartType == 'bvg') { + $ySize = 250; + $xSize = 60 * count($chartValues); + + // reduce x size by 100 for by_month + if ($chartKey == 'by_month') { + $xSize -= 100; + } + + //hack to show tooltip. + if ($xSize < 150) { + $xSize = 150; + } + } + $values['size'] = array('xSize' => $xSize, 'ySize' => $ySize); + } + + // finally assign this chart data to template. + $this->assign('hasYearlyChart', $yearlyChart); + $this->assign('hasByMonthChart', $monthlyChart); + $this->assign('hasOpenFlashChart', empty($chartData) ? FALSE : TRUE); + $this->assign('openFlashChartData', json_encode($chartData)); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage.php b/CRM/Contribute/Form/ContributionPage.php new file mode 100644 index 0000000000..8cb79069e2 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage.php @@ -0,0 +1,426 @@ +_id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, NULL, 'REQUEST' + ); + $this->assign('contributionPageID', $this->_id); + + // get the requested action + $this->_action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // setting title and 3rd level breadcrumb for html page if contrib page exists + if ($this->_id) { + $title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $this->_id, 'title'); + + if ($this->_action == CRM_Core_Action::UPDATE) { + $this->_single = TRUE; + } + } + + // set up tabs + CRM_Contribute_Form_ContributionPage_TabHeader::build($this); + + if ($this->_action == CRM_Core_Action::UPDATE) { + CRM_Utils_System::setTitle(ts('Configure Page - %1', array(1 => $title))); + } + elseif ($this->_action == CRM_Core_Action::VIEW) { + CRM_Utils_System::setTitle(ts('Preview Page - %1', array(1 => $title))); + } + elseif ($this->_action == CRM_Core_Action::DELETE) { + CRM_Utils_System::setTitle(ts('Delete Page - %1', array(1 => $title))); + } + + //cache values. + $this->_values = $this->get('values'); + if (!is_array($this->_values)) { + $this->_values = array(); + if (isset($this->_id) && $this->_id) { + $params = array('id' => $this->_id); + CRM_Core_DAO::commonRetrieve('CRM_Contribute_DAO_ContributionPage', $params, $this->_values); + } + $this->set('values', $this->_values); + } + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $this->applyFilter('__ALL__', 'trim'); + + $session = CRM_Core_Session::singleton(); + $this->_cancelURL = CRM_Utils_Array::value('cancelURL', $_POST); + + if (!$this->_cancelURL) { + $this->_cancelURL = CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1'); + } + + if ($this->_cancelURL) { + $this->addElement('hidden', 'cancelURL', $this->_cancelURL); + } + + + if ($this->_single) { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'upload', + 'name' => ts('Save and Done'), + 'spacing' => '         ', + 'subName' => 'done', + ), + array( + 'type' => 'submit', + 'name' => ts('Save and Next'), + 'spacing' => '                 ', + 'subName' => 'savenext', + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + else { + $buttons = array(); + if (!$this->_first) { + $buttons[] = array( + 'type' => 'back', + 'name' => ts('<< Previous'), + 'spacing' => '     ', + ); + } + $buttons[] = array( + 'type' => 'next', + 'name' => ts('Continue >>'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ); + $buttons[] = array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ); + + $this->addButtons($buttons); + } + + $session->replaceUserContext($this->_cancelURL); + // views are implemented as frozen form + if ($this->_action & CRM_Core_Action::VIEW) { + $this->freeze(); + $this->addElement('button', 'done', ts('Done'), array('onclick' => "location.href='civicrm/admin/custom/group?reset=1&action=browse'")); + } + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return void + */ + function setDefaultValues() { + //some child classes calling setdefaults directly w/o preprocess. + $this->_values = $this->get('values'); + if (!is_array($this->_values)) { + $this->_values = array(); + if (isset($this->_id) && $this->_id) { + $params = array('id' => $this->_id); + CRM_Core_DAO::commonRetrieve('CRM_Contribute_DAO_ContributionPage', $params, $this->_values); + } + $this->set('values', $this->_values); + } + $defaults = $this->_values; + + $config = CRM_Core_Config::singleton(); + if (isset($this->_id)) { + + //set defaults for pledgeBlock values. + $pledgeBlockParams = array( + 'entity_id' => $this->_id, + 'entity_table' => ts('civicrm_contribution_page'), + ); + $pledgeBlockDefaults = array(); + CRM_Pledge_BAO_PledgeBlock::retrieve($pledgeBlockParams, $pledgeBlockDefaults); + if ($this->_pledgeBlockID = CRM_Utils_Array::value('id', $pledgeBlockDefaults)) { + $defaults['is_pledge_active'] = TRUE; + } + $pledgeBlock = array( + 'is_pledge_interval', 'max_reminders', + 'initial_reminder_day', 'additional_reminder_day', + ); + foreach ($pledgeBlock as $key) { + $defaults[$key] = CRM_Utils_Array::value($key, $pledgeBlockDefaults); + } + if (CRM_Utils_Array::value('pledge_frequency_unit', $pledgeBlockDefaults)) { + $defaults['pledge_frequency_unit'] = array_fill_keys(explode(CRM_Core_DAO::VALUE_SEPARATOR, + $pledgeBlockDefaults['pledge_frequency_unit'] + ), '1'); + } + + // fix the display of the monetary value, CRM-4038 + if (isset($defaults['goal_amount'])) { + $defaults['goal_amount'] = CRM_Utils_Money::format($defaults['goal_amount'], NULL, '%a'); + } + + // get price set of type contributions + //this is the value for stored in db if price set extends contribution + $usedFor = 2; + $this->_priceSetID = CRM_Price_BAO_Set::getFor('civicrm_contribution_page', $this->_id, $usedFor, 1); + if ($this->_priceSetID) { + $defaults['price_set_id'] = $this->_priceSetID; + } + + if (CRM_Utils_Array::value('end_date', $defaults)) { + list($defaults['end_date'], $defaults['end_date_time']) = CRM_Utils_Date::setDateDefaults($defaults['end_date']); + } + + if (CRM_Utils_Array::value('start_date', $defaults)) { + list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults($defaults['start_date']); + } + } + else { + $defaults['is_active'] = 1; + // set current date as start date + list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults(); + } + + if (!isset($defaults['for_organization'])) { + $defaults['for_organization'] = ts('I am contributing on behalf of an organization.'); + } + + if (CRM_Utils_Array::value('recur_frequency_unit', $defaults)) { + $defaults['recur_frequency_unit'] = array_fill_keys(explode(CRM_Core_DAO::VALUE_SEPARATOR, + $defaults['recur_frequency_unit'] + ), '1'); + } + else { + # CRM 10860 + $defaults['recur_frequency_unit'] = array('month' => 1); + } + + if (CRM_Utils_Array::value('is_for_organization', $defaults)) { + $defaults['is_organization'] = 1; + } + else { + $defaults['is_for_organization'] = 1; + } + + // confirm page starts out enabled + if (!isset($defaults['is_confirm_enabled'])) { + $defaults['is_confirm_enabled'] = 1; + } + + return $defaults; + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + $pageId = $this->get('id'); + //page is newly created. + if ($pageId && !$this->_id) { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1')); + } + } + + function endPostProcess() { + // make submit buttons keep the current working tab opened, or save and next tab + if ($this->_action & CRM_Core_Action::UPDATE) { + $className = CRM_Utils_String::getClassName($this->_name); + + //retrieve list of pages from StateMachine and find next page + //this is quite painful because StateMachine is full of protected variables + //so we have to retrieve all pages, find current page, and then retrieve next + $stateMachine = new CRM_Contribute_StateMachine_ContributionPage($this); + $states = $stateMachine->getStates(); + $statesList = array_keys($states); + $currKey = array_search($className, $statesList); + $nextPage = (array_key_exists($currKey + 1, $statesList)) ? $statesList[$currKey + 1] : ''; + + //unfortunately, some classes don't map to subpage names, so we alter the exceptions + + switch ($className) { + case 'Contribute': + $attributes = $this->getVar('_attributes'); + $subPage = strtolower(basename(CRM_Utils_Array::value('action', $attributes))); + $subPageName = ucFirst($subPage); + if ($subPage == 'friend') { + $nextPage = 'custom'; + } + else { + $nextPage = 'settings'; + } + break; + + case 'MembershipBlock': + $subPage = 'membership'; + $subPageName = 'MembershipBlock'; + $nextPage = 'thankyou'; + break; + + default: + $subPage = strtolower($className); + $subPageName = $className; + $nextPage = strtolower($nextPage); + + if ($subPage == 'amount') { + $nextPage = 'membership'; + } + elseif ($subPage == 'thankyou') { + $nextPage = 'friend'; + } + break; + } + + CRM_Core_Session::setStatus(ts("'%1' information has been saved.", + array(1 => $subPageName) + ), ts('Saved'), 'success'); + + $this->postProcessHook(); + + if ($this->controller->getButtonName('submit') == "_qf_{$className}_next") { + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/admin/contribute/{$subPage}", + "action=update&reset=1&id={$this->_id}" + )); + } + elseif ($this->controller->getButtonName('submit') == "_qf_{$className}_submit_savenext") { + if ($nextPage) { + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/admin/contribute/{$nextPage}", + "action=update&reset=1&id={$this->_id}" + )); + } + else { + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/admin/contribute", + "reset=1" + )); + } + } + else { + CRM_Utils_System::redirect(CRM_Utils_System::url("civicrm/admin/contribute", 'reset=1')); + } + } + } + + function getTemplateFileName() { + if ($this->controller->getPrint() == CRM_Core_Smarty::PRINT_NOFORM || + $this->getVar('_id') <= 0 || + ($this->_action & CRM_Core_Action::DELETE) || + (CRM_Utils_String::getClassName($this->_name) == 'AddProduct') + ) { + return parent::getTemplateFileName(); + } + else { + // hack lets suppress the form rendering for now + self::$_template->assign('isForm', FALSE); + return 'CRM/Contribute/Form/ContributionPage/Tab.tpl'; + } + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/AddProduct.php b/CRM/Contribute/Form/ContributionPage/AddProduct.php new file mode 100644 index 0000000000..3a9761e848 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/AddProduct.php @@ -0,0 +1,297 @@ +_products = CRM_Contribute_PseudoConstant::products($this->_id); + $this->_pid = CRM_Utils_Request::retrieve('pid', 'Positive', + $this, FALSE, 0 + ); + + if ($this->_pid) { + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->id = $this->_pid; + $dao->find(TRUE); + $temp = CRM_Contribute_PseudoConstant::products(); + $this->_products[$dao->product_id] = $temp[$dao->product_id]; + } + + //$this->_products = array_merge(array('' => '-- Select Product --') , $this->_products ); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return void + */ + function setDefaultValues() { + $defaults = array(); + + if ($this->_pid) { + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->id = $this->_pid; + $dao->find(TRUE); + $defaults['product_id'] = $dao->product_id; + $defaults['financial_type_id'] = $dao->financial_type_id; + $defaults['weight'] = $dao->weight; + } else { + $dao = new CRM_Contribute_DAO_Product(); + $dao->id = key($this->_products); + $dao->find(TRUE); + $defaults['financial_type_id'] = $dao->financial_type_id; + } + if (!isset($defaults['weight']) || !($defaults['weight'])) { + $pageID = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $pageID; + $dao->find(TRUE); + $premiumID = $dao->id; + + $sql = 'SELECT max( weight ) as max_weight FROM civicrm_premiums_product WHERE premiums_id = %1'; + $params = array(1 => array($premiumID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + $dao->fetch(); + $defaults['weight'] = $dao->max_weight + 1; + } + RETURN $defaults; + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $urlParams = 'civicrm/admin/contribute/premium'; + if ($this->_action & CRM_Core_Action::DELETE) { + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id); + $session->pushUserContext($url); + if (CRM_Utils_Request::retrieve('confirmed', 'Boolean', + CRM_Core_DAO::$_nullObject, '', '', 'GET' + )) { + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->id = $this->_pid; + $dao->delete(); + CRM_Core_Session::setStatus(ts('Selected Premium Product has been removed from this Contribution Page.'), ts('Saved'), 'success'); + CRM_Utils_System::redirect($url); + } + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'spacing' => '    ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + return; + } + + if ($this->_action & CRM_Core_Action::PREVIEW) { + CRM_Contribute_BAO_Premium::buildPremiumPreviewBlock($this, NULL, $this->_pid); + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Done with Preview'), + 'isDefault' => TRUE, + ), + ) + ); + return; + } + + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id); + $session->pushUserContext($url); + + $this->add('select', 'product_id', ts('Select the Product') . ' ', $this->_products, TRUE); + + $this->addElement('text', 'weight', ts('Weight'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_PremiumsProduct', 'weight')); + + $financialType = CRM_Contribute_PseudoConstant::financialType( ); + $premiumFinancialType = array(); + CRM_Core_PseudoConstant::populate( + $premiumFinancialType, + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = True, + $retrieve = 'entity_id', + $filter = null, + 'account_relationship = 8' + ); + + $costFinancialType = array(); + CRM_Core_PseudoConstant::populate( + $costFinancialType, + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = True, + $retrieve = 'entity_id', + $filter = null, + 'account_relationship = 7' + ); + $productFinancialType = array_intersect($costFinancialType, $premiumFinancialType); + foreach( $financialType as $key => $financialTypeName ){ + if(!in_array( $key, $productFinancialType)) + unset( $financialType[$key] ); + } + if( count( $financialType ) ){ + $this->assign( 'financialType', $financialType ); + } + $this->add( + 'select', + 'financial_type_id', + ts( 'Financial Type' ), + array(''=>ts('- select -')) + $financialType + ); + $this->addRule('weight', ts('Please enter integer value for weight'), 'integer'); + $session->pushUserContext(CRM_Utils_System::url($urlParams, 'action=update&reset=1&id=' . $this->_id)); + + if ($this->_single) { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Save'), + 'spacing' => '    ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + else { + parent::buildQuickForm(); + } + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + $urlParams = 'civicrm/admin/contribute/premium'; + if ($this->_action & CRM_Core_Action::PREVIEW) { + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id); + $single = $session->get('singleForm'); + CRM_Utils_System::redirect($url); + return; + } + + if ($this->_action & CRM_Core_Action::DELETE) { + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id); + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->id = $this->_pid; + $dao->delete(); + CRM_Core_Session::setStatus(ts('Selected Premium Product has been removed from this Contribution Page.'), ts('Saved'), 'success'); + CRM_Utils_System::redirect($url); + } + else { + $session = CRM_Core_Session::singleton(); + $url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id); + if ($this->_pid) { + $params['id'] = $this->_pid; + } + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $this->_id; + $dao->find(TRUE); + $premiumID = $dao->id; + $params['premiums_id'] = $premiumID; + + $oldWeight = NULL; + if ($this->_pid) { + $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_PremiumsProduct', $this->_pid, 'weight', 'id'); + } + + // updateOtherWeights needs to filter on premiums_id + $filter = array('premiums_id' => $params['premiums_id']); + $params['weight'] = CRM_Utils_Weight::updateOtherWeights('CRM_Contribute_DAO_PremiumsProduct', $oldWeight, $params['weight'], $filter); + + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->copyValues($params); + $dao->save(); + CRM_Utils_System::redirect($url); + } + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Add Premium to Contribution Page'); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/Amount.php b/CRM/Contribute/Form/ContributionPage/Amount.php new file mode 100644 index 0000000000..46c6d94acb --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/Amount.php @@ -0,0 +1,718 @@ +addElement('checkbox', 'is_allow_other_amount', ts('Allow other amounts'), NULL, array('onclick' => "minMax(this);showHideAmountBlock( this, 'is_allow_other_amount' );")); + $this->add('text', 'min_amount', ts('Minimum Amount'), array('size' => 8, 'maxlength' => 8)); + $this->addRule('min_amount', ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('9.99', ' '))), 'money'); + + $this->add('text', 'max_amount', ts('Maximum Amount'), array('size' => 8, 'maxlength' => 8)); + $this->addRule('max_amount', ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('99.99', ' '))), 'money'); + + $default = array(); + $this->add('hidden', "price_field_id", '', array('id' => "price_field_id")); + $this->add('hidden', "price_field_other", '', array('id' => "price_field_option")); + for ($i = 1; $i <= self::NUM_OPTION; $i++) { + // label + $this->add('text', "label[$i]", ts('Label'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'label')); + + $this->add('hidden', "price_field_value[$i]", '', array('id' => "price_field_value[$i]")); + + // value + $this->add('text', "value[$i]", ts('Value'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionValue', 'value')); + $this->addRule("value[$i]", ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('99.99', ' '))), 'money'); + + // default + $default[] = $this->createElement('radio', NULL, NULL, NULL, $i); + } + + $this->addGroup($default, 'default'); + + $this->addElement('checkbox', 'amount_block_is_active', ts('Contribution Amounts section enabled'), NULL, array('onclick' => "showHideAmountBlock( this, 'amount_block_is_active' );")); + + $this->addElement('checkbox', 'is_monetary', ts('Execute real-time monetary transactions')); + + $paymentProcessor = CRM_Core_PseudoConstant::paymentProcessor(); + $recurringPaymentProcessor = array(); + + if (!empty($paymentProcessor)) { + $paymentProcessorIds = implode(',', array_keys($paymentProcessor)); + $query = " +SELECT id + FROM civicrm_payment_processor + WHERE id IN ({$paymentProcessorIds}) + AND is_recur = 1"; + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $recurringPaymentProcessor[] = $dao->id; + } + } + $this->assign('recurringPaymentProcessor', $recurringPaymentProcessor); + if (count($paymentProcessor)) { + $this->assign('paymentProcessor', $paymentProcessor); + } + + $this->addCheckBox('payment_processor', ts('Payment Processor'), + array_flip($paymentProcessor), + NULL, NULL, NULL, NULL, + array('  ', '  ', '  ', '
    ') + ); + + + //check if selected payment processor supports recurring payment + if (!empty($recurringPaymentProcessor)) { + $this->addElement('checkbox', 'is_recur', ts('Recurring contributions'), NULL, + array('onclick' => "showHideByValue('is_recur',true,'recurFields','table-row','radio',false);") + ); + $this->addCheckBox('recur_frequency_unit', ts('Supported recurring units'), + CRM_Core_OptionGroup::values('recur_frequency_units', FALSE, FALSE, FALSE, NULL, 'name'), + NULL, NULL, NULL, NULL, + array('  ', '  ', '  ', '
    ') + ); + $this->addElement('checkbox', 'is_recur_interval', ts('Support recurring intervals')); + $this->addElement('checkbox', 'is_recur_installments', ts('Offer installments')); + } + + // add pay later options + $this->addElement('checkbox', 'is_pay_later', ts('Pay later option'), NULL); + $this->addElement('textarea', 'pay_later_text', ts('Pay later label'), + CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'pay_later_text'), + FALSE + ); + $this->addElement('textarea', 'pay_later_receipt', ts('Pay later instructions'), + CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'pay_later_receipt'), + FALSE + ); + + //add partial payment options + + // add price set fields + $price = CRM_Price_BAO_Set::getAssoc(FALSE, 'CiviContribute'); + if (CRM_Utils_System::isNull($price)) { + $this->assign('price', FALSE); + } + else { + $this->assign('price', TRUE); + } + $this->add('select', 'price_set_id', ts('Price Set'), + array( + '' => ts('- none -')) + $price, + NULL, array('onchange' => "showHideAmountBlock( this.value, 'price_set_id' );") + ); + //CiviPledge fields. + $config = CRM_Core_Config::singleton(); + if (in_array('CiviPledge', $config->enableComponents)) { + $this->assign('civiPledge', TRUE); + $this->addElement('checkbox', 'is_pledge_active', ts('Pledges'), + NULL, array('onclick' => "showHideAmountBlock( this, 'is_pledge_active' ); return showHideByValue('is_pledge_active',true,'pledgeFields','table-row','radio',false);") + ); + $this->addCheckBox('pledge_frequency_unit', ts('Supported pledge frequencies'), + CRM_Core_OptionGroup::values('recur_frequency_units', FALSE, FALSE, FALSE, NULL, 'name'), + NULL, NULL, NULL, NULL, + array('  ', '  ', '  ', '
    ') + ); + $this->addElement('checkbox', 'is_pledge_interval', ts('Allow frequency intervals')); + $this->addElement('text', 'initial_reminder_day', ts('Send payment reminder'), array('size' => 3)); + $this->addElement('text', 'max_reminders', ts('Send up to'), array('size' => 3)); + $this->addElement('text', 'additional_reminder_day', ts('Send additional reminders'), array('size' => 3)); + } + + //add currency element. + $this->addCurrency('currency', ts('Currency')); + + $this->addFormRule(array('CRM_Contribute_Form_ContributionPage_Amount', 'formRule'), $this); + + parent::buildQuickForm(); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return void + */ + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + $title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $this->_id, 'title'); + CRM_Utils_System::setTitle(ts('Contribution Amounts (%1)', array(1 => $title))); + + if (!CRM_Utils_Array::value('pay_later_text', $defaults)) { + $defaults['pay_later_text'] = ts('I will send payment by check'); + } + + if (CRM_Utils_Array::value('amount_block_is_active', $defaults)) { + + if ($priceSetId = CRM_Price_BAO_Set::getFor('civicrm_contribution_page', $this->_id, NULL)) { + if ($isQuick = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $priceSetId, 'is_quick_config')) { + $this->assign('isQuick', $isQuick); + //$priceField = CRM_Core_DAO::getFieldValue( 'CRM_Price_DAO_Field', $priceSetId, 'id', 'price_set_id' ); + $options = $pFIDs = array(); + $priceFieldParams = array('price_set_id' => $priceSetId); + $priceFields = CRM_Core_DAO::commonRetrieveAll('CRM_Price_DAO_Field', 'price_set_id', $priceSetId, $pFIDs, $return = array('html_type', 'name', 'is_active')); + foreach ($priceFields as $priceField) { + if ($priceField['id'] && $priceField['html_type'] == 'Radio' && $priceField['name'] == 'contribution_amount') { + $defaults['price_field_id'] = $priceField['id']; + $priceFieldOptions = CRM_Price_BAO_FieldValue::getValues($priceField['id'], $options, 'id', 1); + $countRow = 0; + foreach ($options as $optionId => $optionValue) { + $countRow++; + $defaults['value'][$countRow] = $optionValue['amount']; + $defaults['label'][$countRow] = CRM_Utils_Array::value('label', $optionValue); + $defaults['name'][$countRow] = CRM_Utils_Array::value('name', $optionValue); + $defaults['weight'][$countRow] = $optionValue['weight']; + + $defaults["price_field_value"][$countRow] = $optionValue['id']; + if ($optionValue['is_default']) { + $defaults['default'] = $countRow; + } + } + } + elseif ($priceField['id'] && $priceField['html_type'] == 'Text' && $priceField['name'] = 'other_amount' && $priceField['is_active']) { + $defaults['price_field_other'] = $priceField['id']; + } + } + } + } + + if (CRM_Utils_Array::value('value', $defaults) && is_array($defaults['value'])) { + + // CRM-4038: fix value display + foreach ($defaults['value'] as & $amount) { + $amount = trim(CRM_Utils_Money::format($amount, ' ')); + } + } + } + + // fix the display of the monetary value, CRM-4038 + if (isset($defaults['min_amount'])) { + $defaults['min_amount'] = CRM_Utils_Money::format($defaults['min_amount'], NULL, '%a'); + } + if (isset($defaults['max_amount'])) { + $defaults['max_amount'] = CRM_Utils_Money::format($defaults['max_amount'], NULL, '%a'); + } + + if (CRM_Utils_Array::value('payment_processor', $defaults)) { + $defaults['payment_processor'] = array_fill_keys(explode(CRM_Core_DAO::VALUE_SEPARATOR, + $defaults['payment_processor'] + ), '1'); + } + return $defaults; + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + $errors = array(); + //as for separate membership payment we has to have + //contribution amount section enabled, hence to disable it need to + //check if separate membership payment enabled, + //if so disable first separate membership payment option + //then disable contribution amount section. CRM-3801, + + $membershipBlock = new CRM_Member_DAO_MembershipBlock(); + $membershipBlock->entity_table = 'civicrm_contribution_page'; + $membershipBlock->entity_id = $self->_id; + $membershipBlock->is_active = 1; + $hasMembershipBlk = FALSE; + if ($membershipBlock->find(TRUE)) { + if (CRM_Utils_Array::value('amount_block_is_active', $fields) && + ($setID = CRM_Price_BAO_Set::getFor('civicrm_contribution_page', $self->_id, NULL, 1)) + ) { + $extends = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Set', $setID, 'extends'); + if ($extends && $extends == CRM_Core_Component::getComponentID('CiviMember')) { + $errors['amount_block_is_active'] = ts('You cannot use a Membership Price Set when the Contribution Amounts section is enabled. Click the Memberships tab above, and select your Membership Price Set on that form. Membership Price Sets may include additional fields for non-membership options that require an additional fee (e.g. magazine subscription) or an additional voluntary contribution.'); + return $errors; + } + } + $hasMembershipBlk = TRUE; + if ($membershipBlock->is_separate_payment && !$fields['amount_block_is_active']) { + $errors['amount_block_is_active'] = ts('To disable Contribution Amounts section you need to first disable Separate Membership Payment option from Membership Settings.'); + } + } + + $minAmount = CRM_Utils_Array::value('min_amount', $fields); + $maxAmount = CRM_Utils_Array::value('max_amount', $fields); + if (!empty($minAmount) && !empty($maxAmount)) { + $minAmount = CRM_Utils_Rule::cleanMoney($minAmount); + $maxAmount = CRM_Utils_Rule::cleanMoney($maxAmount); + if ((float ) $minAmount > (float ) $maxAmount) { + $errors['min_amount'] = ts('Minimum Amount should be less than Maximum Amount'); + } + } + + if (isset($fields['is_pay_later'])) { + if (empty($fields['pay_later_text'])) { + $errors['pay_later_text'] = ts('Please enter the text for the \'pay later\' checkbox displayed on the contribution form.'); + } + if (empty($fields['pay_later_receipt'])) { + $errors['pay_later_receipt'] = ts('Please enter the instructions to be sent to the contributor when they choose to \'pay later\'.'); + } + } + + // don't allow price set w/ membership signup, CRM-5095 + if ($priceSetId = CRM_Utils_Array::value('price_set_id', $fields)) { + // don't allow price set w/ membership. + if ($hasMembershipBlk) { + $errors['price_set_id'] = ts('You cannot enable both a Contribution Price Set and Membership Signup on the same online contribution page.'); + } + } + else { + if (isset($fields['is_recur'])) { + if (empty($fields['recur_frequency_unit'])) { + $errors['recur_frequency_unit'] = ts('At least one recurring frequency option needs to be checked.'); + } + } + + // validation for pledge fields. + if (CRM_Utils_array::value('is_pledge_active', $fields)) { + if (empty($fields['pledge_frequency_unit'])) { + $errors['pledge_frequency_unit'] = ts('At least one pledge frequency option needs to be checked.'); + } + if (CRM_Utils_array::value('is_recur', $fields)) { + $errors['is_recur'] = ts('You cannot enable both Recurring Contributions AND Pledges on the same online contribution page.'); + } + } + + // If Contribution amount section is enabled, then + // Allow other amounts must be enabeld OR the Fixed Contribution + // Contribution options must contain at least one set of values. + if (CRM_Utils_Array::value('amount_block_is_active', $fields)) { + if (!CRM_Utils_Array::value('is_allow_other_amount', $fields) && + !$priceSetId + ) { + //get the values of amount block + $values = CRM_Utils_Array::value('value', $fields); + $isSetRow = FALSE; + for ($i = 1; $i < self::NUM_OPTION; $i++) { + if ((isset($values[$i]) && (strlen(trim($values[$i])) > 0))) { + $isSetRow = TRUE; + } + } + if (!$isSetRow) { + $errors['amount_block_is_active'] = ts('If you want to enable the \'Contribution Amounts section\', you need to either \'Allow Other Amounts\' and/or enter at least one row in the \'Fixed Contribution Amounts\' table.'); + } + } + } + } + + if (CRM_Utils_Array::value('is_recur_interval', $fields)) { + foreach(array_keys($fields['payment_processor']) as $paymentProcessorID) { + $paymentProcessorTypeId = CRM_Core_DAO::getFieldValue( + 'CRM_Financial_DAO_PaymentProcessor', + $paymentProcessorID, + 'payment_processor_type_id' + ); + $paymentProcessorType = CRM_Core_PseudoConstant::paymentProcessorType(false, $paymentProcessorTypeId, 'name'); + if ($paymentProcessorType == 'Google_Checkout') { + $errors['is_recur_interval'] = ts('Google Checkout does not support recurring intervals'); + break; + } + } + } + + return $errors; + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + if (array_key_exists('payment_processor', $params)) { + if (array_key_exists(CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessor', 'AuthNet', + 'id', 'payment_processor_type_id' + ), + CRM_Utils_Array::value('payment_processor', $params) + )) { + CRM_Core_Session::setStatus(ts(' Please note that the Authorize.net payment processor only allows recurring contributions and auto-renew memberships with payment intervals from 7-365 days or 1-12 months (i.e. not greater than 1 year).'), '', 'alert'); + } + } + + // check for price set. + $priceSetID = CRM_Utils_Array::value('price_set_id', $params); + + // get required fields. + $fields = array( + 'id' => $this->_id, + 'is_recur' => FALSE, + 'min_amount' => "null", + 'max_amount' => "null", + 'is_monetary' => FALSE, + 'is_pay_later' => FALSE, + 'is_recur_interval' => FALSE, + 'is_recur_installments' => FALSE, + 'recur_frequency_unit' => "null", + 'default_amount_id' => "null", + 'is_allow_other_amount' => FALSE, + 'amount_block_is_active' => FALSE, + ); + $resetFields = array(); + if ($priceSetID) { + $resetFields = array('min_amount', 'max_amount', 'is_allow_other_amount'); + } + + if (!CRM_Utils_Array::value('is_recur', $params)) { + $resetFields = array_merge($resetFields, array('is_recur_interval', 'recur_frequency_unit')); + } + + foreach ($fields as $field => $defaultVal) { + $val = CRM_Utils_Array::value($field, $params, $defaultVal); + if (in_array($field, $resetFields)) { + $val = $defaultVal; + } + + if (in_array($field, array( + 'min_amount', 'max_amount'))) { + $val = CRM_Utils_Rule::cleanMoney($val); + } + + $params[$field] = $val; + } + + if ($params['is_recur']) { + $params['recur_frequency_unit'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_keys($params['recur_frequency_unit']) + ); + $params['is_recur_interval'] = CRM_Utils_Array::value('is_recur_interval', $params, FALSE); + $params['is_recur_installments'] = CRM_Utils_Array::value('is_recur_installments', $params, FALSE); + } + + if (array_key_exists('payment_processor', $params) && + !CRM_Utils_System::isNull($params['payment_processor']) + ) { + $params['payment_processor'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($params['payment_processor'])); + } + else { + $params['payment_processor'] = 'null'; + } + + $contributionPage = CRM_Contribute_BAO_ContributionPage::create($params); + $contributionPageID = $contributionPage->id; + + // prepare for data cleanup. + $deleteAmountBlk = $deletePledgeBlk = $deletePriceSet = FALSE; + if ($this->_priceSetID) { + $deletePriceSet = TRUE; + } + if ($this->_pledgeBlockID) { + $deletePledgeBlk = TRUE; + } + if (!empty($this->_amountBlock)) { + $deleteAmountBlk = TRUE; + } + + if ($contributionPageID) { + + if (CRM_Utils_Array::value('amount_block_is_active', $params)) { + // handle price set. + if ($priceSetID) { + // add/update price set. + $deletePriceSet = FALSE; + if (CRM_Utils_Array::value('price_field_id', $params) || CRM_Utils_Array::value('price_field_other', $params) ) { + $deleteAmountBlk = TRUE; + } + + CRM_Price_BAO_Set::addTo('civicrm_contribution_page', $contributionPageID, $priceSetID); + } + else { + + $deletePriceSet = FALSE; + // process contribution amount block + $deleteAmountBlk = FALSE; + + $labels = CRM_Utils_Array::value('label', $params); + $values = CRM_Utils_Array::value('value', $params); + $default = CRM_Utils_Array::value('default', $params); + + $options = array(); + for ($i = 1; $i < self::NUM_OPTION; $i++) { + if (isset($values[$i]) && + (strlen(trim($values[$i])) > 0) + ) { + $options[] = array('label' => trim($labels[$i]), + 'value' => CRM_Utils_Rule::cleanMoney(trim($values[$i])), + 'weight' => $i, + 'is_active' => 1, + 'is_default' => $default == $i, + ); + } + } + /* || CRM_Utils_Array::value( 'price_field_value', $params )|| CRM_Utils_Array::value( 'price_field_other', $params )*/ + if (!empty($options) || CRM_Utils_Array::value('is_allow_other_amount', $params)) { + $fieldParams['is_quick_config'] = 1; + $noContriAmount = NULL; + $usedPriceSetId = CRM_Price_BAO_Set::getFor('civicrm_contribution_page', $this->_id, 3); + if (!(CRM_Utils_Array::value('price_field_id', $params) || CRM_Utils_Array::value('price_field_other', $params)) && !$usedPriceSetId) { + $pageTitle = strtolower(CRM_Utils_String::munge($this->_values['title'], '_', 245)); + $setParams['title'] = $this->_values['title']; + if (!CRM_Core_DAO::getFieldValue('CRM_Price_BAO_Set', $pageTitle, 'id', 'name')) { + $setParams['name'] = $pageTitle; + } + elseif (!CRM_Core_DAO::getFieldValue('CRM_Price_BAO_Set', $pageTitle . '_' . $this->_id, 'id', 'name')) { + $setParams['name'] = $pageTitle . '_' . $this->_id; + } + else { + $timeSec = explode(".", microtime(true)); + $setParams['name'] = $pageTitle . '_' . date('is', $timeSec[0]) . $timeSec[1]; + } + $setParams['is_quick_config'] = 1; + $setParams['extends'] = CRM_Core_Component::getComponentID('CiviContribute'); + $priceSet = CRM_Price_BAO_Set::create($setParams); + $priceSetId = $priceSet->id; + } + elseif ($usedPriceSetId && !CRM_Utils_Array::value('price_field_id', $params)) { + $priceSetId = $usedPriceSetId; + } + else { + if ($priceFieldId = CRM_Utils_Array::value('price_field_id', $params)) { + foreach ($params['price_field_value'] as $arrayID => $fieldValueID) { + if (empty($params['label'][$arrayID]) && empty($params['value'][$arrayID]) && !empty($fieldValueID)) { + CRM_Price_BAO_FieldValue::setIsActive($fieldValueID, '0'); + unset($params['price_field_value'][$arrayID]); + } + } + if (implode('', $params['price_field_value'])) { + $fieldParams['id'] = CRM_Utils_Array::value('price_field_id', $params); + $fieldParams['option_id'] = $params['price_field_value']; + } + else { + $noContriAmount = 0; + CRM_Price_BAO_Field::setIsActive($priceFieldId, '0'); + } + } + else $priceFieldId = CRM_Utils_Array::value('price_field_other', $params); + $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Field', $priceFieldId, 'price_set_id'); + } + CRM_Price_BAO_Set::addTo('civicrm_contribution_page', $this->_id, $priceSetId); + if (!empty($options)) { + $editedFieldParams = array( + 'price_set_id' => $priceSetId, + 'name' => 'contribution_amount', + ); + $editedResults = array(); + $noContriAmount = 1; + CRM_Price_BAO_Field::retrieve($editedFieldParams, $editedResults); + if (!CRM_Utils_Array::value('id', $editedResults)) { + $fieldParams['name'] = strtolower(CRM_Utils_String::munge("Contribution Amount", '_', 245)); + $fieldParams['label'] = "Contribution Amount"; + } + else { + $fieldParams['id'] = CRM_Utils_Array::value('id', $editedResults); + } + + $fieldParams['price_set_id'] = $priceSetId; + $fieldParams['is_active'] = 1; + $fieldParams['weight'] = 2; + + if (CRM_Utils_Array::value('is_allow_other_amount', $params)) { + $fieldParams['is_required'] = 0; + } + else { + $fieldParams['is_required'] = 1; + } + $fieldParams['html_type'] = 'Radio'; + $fieldParams['option_label'] = $params['label']; + $fieldParams['option_amount'] = $params['value']; + $fieldParams['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $this->_values); + foreach ($options as $value) { + $fieldParams['option_weight'][$value['weight']] = $value['weight']; + } + $fieldParams['default_option'] = $params['default']; + $priceField = CRM_Price_BAO_Field::create($fieldParams); + } + if (CRM_Utils_Array::value('is_allow_other_amount', $params) && !CRM_Utils_Array::value('price_field_other', $params)) { + $editedFieldParams = array( + 'price_set_id' => $priceSetId, + 'name' => 'other_amount', + ); + $editedResults = array(); + + CRM_Price_BAO_Field::retrieve($editedFieldParams, $editedResults); + + if (!$priceFieldID = CRM_Utils_Array::value('id', $editedResults)) { + $fieldParams = array( + 'name' => 'other_amount', + 'label' => 'Other Amount', + 'price_set_id' => $priceSetId, + 'html_type' => 'Text', + 'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $this->_values), + 'is_display_amounts' => 0, + 'weight' => 3, + ); + $fieldParams['option_weight'][1] = 1; + $fieldParams['option_amount'][1] = 1; + if (!$noContriAmount) { + $fieldParams['is_required'] = 1; + $fieldParams['option_label'][1] = 'Contribution Amount'; + } else { + $fieldParams['is_required'] = 0; + $fieldParams['option_label'][1] = 'Other Amount'; + } + + $priceField = CRM_Price_BAO_Field::create($fieldParams); + } else { + if (!CRM_Utils_Array::value('is_active', $editedResults)) { + CRM_Price_BAO_Field::setIsActive($priceFieldID, '1'); + } + } + } elseif (!CRM_Utils_Array::value('is_allow_other_amount', $params) && CRM_Utils_Array::value('price_field_other', $params)) { + CRM_Price_BAO_Field::setIsActive($params['price_field_other'], '0'); + } elseif ($priceFieldID = CRM_Utils_Array::value('price_field_other', $params)) { + $priceFieldValueID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_FieldValue', $priceFieldID, 'id', 'price_field_id' ); + if (!$noContriAmount) { + CRM_Core_DAO::setFieldValue('CRM_Price_DAO_Field', $priceFieldID, 'is_required', 1); + CRM_Core_DAO::setFieldValue('CRM_Price_DAO_FieldValue', $priceFieldValueID, 'label', 'Contribution Amount' ); + } else { + CRM_Core_DAO::setFieldValue('CRM_Price_DAO_Field', $priceFieldID, 'is_required', 0 ); + CRM_Core_DAO::setFieldValue('CRM_Price_DAO_FieldValue', $priceFieldValueID, 'label', 'Other Amount' ); + } + } + } + + if (CRM_Utils_Array::value('is_pledge_active', $params)) { + $deletePledgeBlk = FALSE; + $pledgeBlockParams = array( + 'entity_id' => $contributionPageID, + 'entity_table' => ts('civicrm_contribution_page'), + ); + if ($this->_pledgeBlockID) { + $pledgeBlockParams['id'] = $this->_pledgeBlockID; + } + $pledgeBlock = array( + 'pledge_frequency_unit', 'max_reminders', + 'initial_reminder_day', 'additional_reminder_day', + ); + foreach ($pledgeBlock as $key) { + $pledgeBlockParams[$key] = CRM_Utils_Array::value($key, $params); + } + $pledgeBlockParams['is_pledge_interval'] = CRM_Utils_Array::value('is_pledge_interval', + $params, FALSE + ); + // create pledge block. + CRM_Pledge_BAO_PledgeBlock::create($pledgeBlockParams); + } + } + } + else { + if (CRM_Utils_Array::value('price_field_id', $params) || CRM_Utils_Array::value('price_field_other', $params)) { + $usedPriceSetId = CRM_Price_BAO_Set::getFor('civicrm_contribution_page', $this->_id, 3); + if ($usedPriceSetId) { + if (CRM_Utils_Array::value('price_field_id', $params)) { + CRM_Price_BAO_Field::setIsActive($params['price_field_id'], '0'); + } + if (CRM_Utils_Array::value('price_field_other', $params)) { + CRM_Price_BAO_Field::setIsActive($params['price_field_other'], '0'); + } + } + else { + $deleteAmountBlk = TRUE; + $deletePriceSet = TRUE; + } + } + } + + // delete pledge block. + if ($deletePledgeBlk) { + CRM_Pledge_BAO_PledgeBlock::deletePledgeBlock($this->_pledgeBlockID); + } + + // delete previous price set. + if ($deletePriceSet) { + CRM_Price_BAO_Set::removeFrom('civicrm_contribution_page', $contributionPageID); + } + + if ($deleteAmountBlk ) { + $priceField = CRM_Utils_Array::value('price_field_id', $params)?$params['price_field_id']:CRM_Utils_Array::value('price_field_other', $params); + if ($priceField) { + $priceSetID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_Field', $priceField, 'price_set_id'); + CRM_Price_BAO_Set::setIsQuickConfig($priceSetID,0); + } + } + } + parent::endPostProcess(); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Amounts'); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/Custom.php b/CRM/Contribute/Form/ContributionPage/Custom.php new file mode 100644 index 0000000000..709a7782be --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/Custom.php @@ -0,0 +1,217 @@ + $value) { + if (array_key_exists( $key, $profiles)) { + unset($profiles[$key]); + } + } + + if (empty($profiles)) { + $this->assign('noProfile', TRUE); + } + + $this->add('select', 'custom_pre_id', ts('Include Profile') . '
    ' . ts('(top of page)'), array('' => ts('- select -')) + $profiles); + $this->add('select', 'custom_post_id', ts('Include Profile') . '
    ' . ts('(bottom of page)'), array('' => ts('- select -')) + $profiles); + + $this->addFormRule(array('CRM_Contribute_Form_ContributionPage_Custom', 'formRule'), $this->_id); + + parent::buildQuickForm(); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return void + */ + function setDefaultValues() { + $defaults = parent::setDefaultValues(); + + if ($this->_id) { + $title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $this->_id, 'title'); + CRM_Utils_System::setTitle(ts('Include Profiles (%1)', array(1 => $title))); + } + + + $ufJoinParams = array( + 'module' => 'CiviContribute', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $this->_id, + ); + list($defaults['custom_pre_id'], + $defaults['custom_post_id'] + ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + + return $defaults; + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + if ($this->_action & CRM_Core_Action::UPDATE) { + $params['id'] = $this->_id; + } + + $transaction = new CRM_Core_Transaction(); + + // also update uf join table + $ufJoinParams = array( + 'is_active' => 1, + 'module' => 'CiviContribute', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $this->_id, + ); + + // first delete all past entries + CRM_Core_BAO_UFJoin::deleteAll($ufJoinParams); + + if (!empty($params['custom_pre_id'])) { + $ufJoinParams['weight'] = 1; + $ufJoinParams['uf_group_id'] = $params['custom_pre_id']; + CRM_Core_BAO_UFJoin::create($ufJoinParams); + } + + unset($ufJoinParams['id']); + + if (!empty($params['custom_post_id'])) { + $ufJoinParams['weight'] = 2; + $ufJoinParams['uf_group_id'] = $params['custom_post_id']; + CRM_Core_BAO_UFJoin::create($ufJoinParams); + } + + $transaction->commit(); + parent::endPostProcess(); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Include Profiles'); + } + + /** + * global form rule + * + * @param array $fields the input form values + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $contributionPageId) { + $errors = array(); + $preProfileType = $postProfileType = NULL; + // for membership profile make sure Membership section is enabled + // get membership section for this contribution page + $dao = new CRM_Member_DAO_MembershipBlock(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $contributionPageId; + + $membershipEnable = FALSE; + + if ($dao->find(TRUE) && $dao->is_active) { + $membershipEnable = TRUE; + } + + if ($fields['custom_pre_id']) { + $preProfileType = CRM_Core_BAO_UFField::getProfileType($fields['custom_pre_id']); + } + + if ($fields['custom_post_id']) { + $postProfileType = CRM_Core_BAO_UFField::getProfileType($fields['custom_post_id']); + } + + $errorMsg = ts('You must enable the Membership Block for this Contribution Page if you want to include a Profile with Membership fields.'); + + if (($preProfileType == 'Membership') && !$membershipEnable) { + $errors['custom_pre_id'] = $errorMsg; + } + + if (($postProfileType == 'Membership') && !$membershipEnable) { + $errors['custom_post_id'] = $errorMsg; + } + + $behalf = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $contributionPageId, 'is_for_organization'); + if ($fields['custom_pre_id']) { + $errorMsg = ts('You should move the membership related fields in the "On Behalf" profile for this Contribution Page'); + if ($preProfileType == 'Membership' && $behalf) { + $errors['custom_pre_id'] = isset($errors['custom_pre_id']) ? $errors['custom_pre_id'] . $errorMsg : $errorMsg; + } + } + + if ($fields['custom_post_id']) { + $errorMsg = ts('You should move the membership related fields in the "On Behalf" profile for this Contribution Page'); + if ($postProfileType == 'Membership' && $behalf) { + $errors['custom_post_id'] = isset($errors['custom_post_id']) ? $errors['custom_post_id'] . $errorMsg : $errorMsg; + } + } + return empty($errors) ? TRUE : $errors; + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/Delete.php b/CRM/Contribute/Form/ContributionPage/Delete.php new file mode 100644 index 0000000000..28c1962391 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/Delete.php @@ -0,0 +1,156 @@ +_action)) { + CRM_Core_Error::fatal(ts('You do not have permission to access this page')); + } + + $dao = new CRM_Contribute_DAO_Contribution(); + $dao->contribution_page_id = $this->_id; + + if ($dao->find(TRUE)) { + $this->_relatedContributions = TRUE; + $this->assign('relatedContributions', TRUE); + } + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->_title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $this->_id, 'title'); + $this->assign('title', $this->_title); + + //if there are contributions related to Contribution Page + //then onle cancel button is displayed + $buttons = array(); + if (!$this->_relatedContributions) { + $buttons[] = array( + 'type' => 'next', + 'name' => ts('Delete Contribution Page'), + 'isDefault' => TRUE, + ); + } + + $buttons[] = array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ); + + $this->addButtons($buttons); + } + + /** + * Process the form when submitted + * + * @return void + * @access public + */ + public function postProcess() { + $transaction = new CRM_Core_Transaction(); + + // first delete the join entries associated with this contribution page + $dao = new CRM_Core_DAO_UFJoin(); + + $params = array( + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $this->_id, + ); + $dao->copyValues($params); + $dao->delete(); + + //next delete the membership block fields + $dao = new CRM_Member_DAO_MembershipBlock(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $this->_id; + $dao->delete(); + + //next delete the pcp block fields + $dao = new CRM_PCP_DAO_PCPBlock(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $this->_id; + $dao->delete(); + + // need to delete premiums. CRM-4586 + CRM_Contribute_BAO_Premium::deletePremium($this->_id); + + // price set cleanup, CRM-5527 + CRM_Price_BAO_Set::removeFrom('civicrm_contribution_page', $this->_id); + + // finally delete the contribution page + $dao = new CRM_Contribute_DAO_ContributionPage(); + $dao->id = $this->_id; + $dao->delete(); + + $transaction->commit(); + + CRM_Core_Session::setStatus(ts("The contribution page '%1' has been deleted.", array(1 => $this->_title)), ts('Deleted'), 'success'); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/Premium.php b/CRM/Contribute/Form/ContributionPage/Premium.php new file mode 100644 index 0000000000..b1e4c6f527 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/Premium.php @@ -0,0 +1,154 @@ +_id)) { + $title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $this->_id, 'title'); + CRM_Utils_System::setTitle(ts('Premiums (%1)', array(1 => $title))); + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $this->_id; + $dao->find(TRUE); + CRM_Core_DAO::storeValues($dao, $defaults); + } + return $defaults; + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Premium'); + $this->addElement('checkbox', 'premiums_active', ts('Premiums Section Enabled?'), NULL, array('onclick' => "premiumBlock(this);")); + + $this->addElement('text', 'premiums_intro_title', ts('Title'), $attributes['premiums_intro_title']); + + $this->add('textarea', 'premiums_intro_text', ts('Introductory Message'), 'rows=5, cols=50'); + + $this->add('text', 'premiums_contact_email', ts('Contact Email') . ' ', $attributes['premiums_contact_email']); + + $this->addRule('premiums_contact_email', ts('Please enter a valid email address for Contact Email') . ' ', 'email'); + + $this->add('text', 'premiums_contact_phone', ts('Contact Phone'), $attributes['premiums_contact_phone']); + + $this->addRule('premiums_contact_phone', ts('Please enter a valid phone number.'), 'phone'); + + $this->addElement('checkbox', 'premiums_display_min_contribution', ts('Display Minimum Contribution Amount?')); + + // CRM-10999 Control label and position for No Thank-you radio button + $this->add('text', 'premiums_nothankyou_label', ts('No Thank-you Label'), $attributes['premiums_nothankyou_label'], TRUE); + $positions = array(1 => ts('Before Premiums'), 2 => ts('After Premiums')); + $this->add('select','premiums_nothankyou_position', ts('No Thank-you Option'), $positions); + $showForm = TRUE; + + if ($this->_single) { + if ($this->_id) { + $daoPremium = new CRM_Contribute_DAO_Premium(); + $daoPremium->entity_id = $this->_id; + $daoPremium->entity_table = 'civicrm_contribution_page'; + $daoPremium->premiums_active = 1; + if ($daoPremium->find(TRUE)) { + $showForm = FALSE; + } + } + } + $this->assign('showForm', $showForm); + + parent::buildQuickForm(); + + $premiumPage = new CRM_Contribute_Page_Premium(); + $premiumPage->browse(); + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + // we do this in case the user has hit the forward/back button + + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $this->_id; + $dao->find(TRUE); + $premiumID = $dao->id; + if ($premiumID) { + $params['id'] = $premiumID; + } + + $params['premiums_active'] = CRM_Utils_Array::value('premiums_active', $params, FALSE); + $params['premiums_display_min_contribution'] = CRM_Utils_Array::value('premiums_display_min_contribution', $params, FALSE); + $params['entity_table'] = 'civicrm_contribution_page'; + $params['entity_id'] = $this->_id; + + $dao = new CRM_Contribute_DAO_Premium(); + $dao->copyValues($params); + $dao->save(); + parent::endPostProcess(); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Premiums'); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/Settings.php b/CRM/Contribute/Form/ContributionPage/Settings.php new file mode 100644 index 0000000000..39afc21a22 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/Settings.php @@ -0,0 +1,333 @@ +_id) { + $title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', + $this->_id, + 'title' + ); + CRM_Utils_System::setTitle(ts('Title and Settings (%1)', + array(1 => $title) + )); + + $ufJoinParams = array( + 'module' => 'OnBehalf', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $this->_id, + ); + $defaults['onbehalf_profile_id'] = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + } + else { + CRM_Utils_System::setTitle(ts('Title and Settings')); + } + + return $defaults; + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + + $this->_first = TRUE; + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage'); + + // financial Type + $financialType = CRM_Financial_BAO_FinancialType::getIncomeFinancialType(); + $this->add('select', 'financial_type_id', + ts('Financial Type'), + $financialType, + TRUE + ); + + // name + $this->add('text', 'title', ts('Title'), $attributes['title'], TRUE); + + //CRM-7362 --add campaigns. + CRM_Campaign_BAO_Campaign::addCampaign($this, CRM_Utils_Array::value('campaign_id', $this->_values)); + + $this->addWysiwyg('intro_text', ts('Introductory Message'), $attributes['intro_text']); + + $this->addWysiwyg('footer_text', ts('Footer Message'), $attributes['footer_text']); + + // is on behalf of an organization ? + $this->addElement('checkbox', 'is_organization', ts('Allow individuals to contribute and / or signup for membership on behalf of an organization?'), NULL, array('onclick' => "showHideByValue('is_organization',true,'for_org_text','table-row','radio',false);showHideByValue('is_organization',true,'for_org_option','table-row','radio',false);")); + + $required = array('Contact', 'Organization'); + $optional = array('Contribution', 'Membership'); + + $profiles = CRM_Core_BAO_UFGroup::getValidProfiles($required, $optional); + //Check profiles for Organization subtypes + $contactSubType = CRM_Contact_BAO_ContactType::subTypes('Organization'); + foreach ($contactSubType as $type) { + $required = array('Contact', $type); + $subTypeProfiles = CRM_Core_BAO_UFGroup::getValidProfiles($required, $optional); + foreach ($subTypeProfiles as $profileId => $profileName) { + $profiles[$profileId] = $profileName; + } + } + + $requiredProfileFields = array('organization_name', 'email'); + + if (!empty($profiles)) { + foreach ($profiles as $id => $dontCare) { + $validProfile = CRM_Core_BAO_UFGroup::checkValidProfile($id, $requiredProfileFields); + if (!$validProfile) { + unset($profiles[$id]); + } + } + } + + if (empty($profiles)) { + $invalidProfiles = TRUE; + $this->assign('invalidProfiles', $invalidProfiles); + } + + $this->add('select', 'onbehalf_profile_id', ts('Organization Profile'), + array( + '' => ts('- select -')) + $profiles + ); + + $options = array(); + $options[] = $this->createElement('radio', NULL, NULL, ts('Optional'), 1); + $options[] = $this->createElement('radio', NULL, NULL, ts('Required'), 2); + $this->addGroup($options, 'is_for_organization', ts('')); + $this->add('textarea', 'for_organization', ts('On behalf of Label'), $attributes['for_organization']); + + // collect goal amount + $this->add('text', 'goal_amount', ts('Goal Amount'), array('size' => 8, 'maxlength' => 12)); + $this->addRule('goal_amount', ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('99.99', ' '))), 'money'); + + // is confirmation page enabled? + $this->addElement('checkbox', 'is_confirm_enabled', ts('Use a confirmation page?')); + + // is this page shareable through social media ? + $this->addElement('checkbox', 'is_share', ts('Allow sharing through social media?')); + + // is this page active ? + $this->addElement('checkbox', 'is_active', ts('Is this Online Contribution Page Active?')); + + // should the honor be enabled + $this->addElement('checkbox', 'honor_block_is_active', ts('Honoree Section Enabled'), NULL, array('onclick' => "showHonor()")); + + $this->add('text', 'honor_block_title', ts('Honoree Section Title'), $attributes['honor_block_title']); + + $this->add('textarea', 'honor_block_text', ts('Honoree Introductory Message'), $attributes['honor_block_text']); + + // add optional start and end dates + $this->addDateTime('start_date', ts('Start Date')); + $this->addDateTime('end_date', ts('End Date')); + + $this->addFormRule(array('CRM_Contribute_Form_ContributionPage_Settings', 'formRule'), $this->_id); + + parent::buildQuickForm(); + } + + /** + * global validation rules for the form + * + * @param array $values posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($values, $files, $contributionPageId) { + $errors = array(); + + //CRM-4286 + if (strstr($values['title'], '/')) { + $errors['title'] = ts("Please do not use '/' in Title"); + } + + if (CRM_Utils_Array::value('is_organization', $values) && + !CRM_Utils_Array::value('onbehalf_profile_id', $values) + ) { + $errors['onbehalf_profile_id'] = ts('Please select a profile to collect organization information on this contribution page.'); + } + + //CRM-11494 + $start = CRM_Utils_Date::processDate($values['start_date']); + $end = CRM_Utils_Date::processDate($values['end_date']); + if (($end < $start) && ($end != 0)) { + $errors['end_date'] = ts('End date should be after Start date.'); + } + + //dont allow on behalf of save when + //pre or post profile consists of membership fields + if ($contributionPageId && CRM_Utils_Array::value('is_organization', $values)) { + $ufJoinParams = array( + 'module' => 'CiviContribute', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $contributionPageId, + ); + + list($contributionProfiles['custom_pre_id'], + $contributionProfiles['custom_post_id'] + ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams); + + $conProfileType = NULL; + if ($contributionProfiles['custom_pre_id']) { + $preProfileType = CRM_Core_BAO_UFField::getProfileType($contributionProfiles['custom_pre_id']); + if ($preProfileType == 'Membership') { + $conProfileType = "'Includes Profile (top of page)'"; + } + } + + if ($contributionProfiles['custom_post_id']) { + $postProfileType = CRM_Core_BAO_UFField::getProfileType($contributionProfiles['custom_post_id']); + if ($postProfileType == 'Membership') { + $conProfileType = empty($conProfileType) ? "'Includes Profile (bottom of page)'" : "{$conProfileType} and 'Includes Profile (bottom of page)'"; + } + } + if (!empty($conProfileType)) { + $errors['is_organization'] = ts("You should move the membership related fields configured in %1 to the 'On Behalf' profile for this Contribution Page", array(1 => $conProfileType)); + } + } + return $errors; + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + // we do this in case the user has hit the forward/back button + if ($this->_id) { + $params['id'] = $this->_id; + } + else { + $session = CRM_Core_Session::singleton(); + $params['created_id'] = $session->get('userID'); + $params['created_date'] = date('YmdHis'); + $config = CRM_Core_Config::singleton(); + $params['currency'] = $config->defaultCurrency; + } + + $params['is_confirm_enabled'] = CRM_Utils_Array::value('is_confirm_enabled', $params, FALSE); + $params['is_share'] = CRM_Utils_Array::value('is_share', $params, FALSE); + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['is_credit_card_only'] = CRM_Utils_Array::value('is_credit_card_only', $params, FALSE); + $params['honor_block_is_active'] = CRM_Utils_Array::value('honor_block_is_active', $params, FALSE); + $params['is_for_organization'] = CRM_Utils_Array::value('is_organization', $params) ? CRM_Utils_Array::value('is_for_organization', $params, FALSE) : 0; + + $params['start_date'] = CRM_Utils_Date::processDate($params['start_date'], $params['start_date_time'], TRUE); + $params['end_date'] = CRM_Utils_Date::processDate($params['end_date'], $params['end_date_time'], TRUE); + + $params['goal_amount'] = CRM_Utils_Rule::cleanMoney($params['goal_amount']); + + if (!$params['honor_block_is_active']) { + $params['honor_block_title'] = NULL; + $params['honor_block_text'] = NULL; + } + + $dao = CRM_Contribute_BAO_ContributionPage::create($params); + + // make entry in UF join table for onbehalf of org profile + $ufJoinParams = array( + 'is_active' => 1, + 'module' => 'OnBehalf', + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $dao->id, + ); + + // first delete all past entries + CRM_Core_BAO_UFJoin::deleteAll($ufJoinParams); + + if (CRM_Utils_Array::value('onbehalf_profile_id', $params)) { + $ufJoinParams['weight'] = 1; + $ufJoinParams['uf_group_id'] = $params['onbehalf_profile_id']; + CRM_Core_BAO_UFJoin::create($ufJoinParams); + } + + $this->set('id', $dao->id); + if ($this->_action & CRM_Core_Action::ADD) { + $url = 'civicrm/admin/contribute/amount'; + $urlParams = "action=update&reset=1&id={$dao->id}"; + // special case for 'Save and Done' consistency. + if ($this->controller->getButtonName('submit') == '_qf_Amount_upload_done') { + $url = 'civicrm/admin/contribute'; + $urlParams = 'reset=1'; + CRM_Core_Session::setStatus(ts("'%1' information has been saved.", + array(1 => $this->getTitle()) + ), ts('Saved'), 'success'); + } + + CRM_Utils_System::redirect(CRM_Utils_System::url($url, $urlParams)); + } + parent::endPostProcess(); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Title and Settings'); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/TabHeader.php b/CRM/Contribute/Form/ContributionPage/TabHeader.php new file mode 100644 index 0000000000..6038d57b95 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/TabHeader.php @@ -0,0 +1,193 @@ +get('tabHeader'); + if (!$tabs || !CRM_Utils_Array::value('reset', $_GET)) { + $tabs = self::process($form); + $form->set('tabHeader', $tabs); + } + $form->assign_by_ref('tabHeader', $tabs); + $form->assign('selectedTab', self::getCurrentTab($tabs)); + return $tabs; + } + + static function process(&$form) { + if ($form->getVar('_id') <= 0) { + return NULL; + } + + $tabs = array( + 'settings' => array('title' => ts('Title'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'amount' => array('title' => ts('Amounts'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'membership' => array('title' => ts('Memberships'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'thankyou' => array('title' => ts('Receipt'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'friend' => array('title' => ts('Tell a Friend'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'custom' => array('title' => ts('Profiles'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'premium' => array('title' => ts('Premiums'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'widget' => array('title' => ts('Widgets'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + 'pcp' => array('title' => ts('Personal Campaigns'), + 'link' => NULL, + 'valid' => FALSE, + 'active' => FALSE, + 'current' => FALSE, + ), + ); + + $contribPageId = $form->getVar('_id'); + $fullName = $form->getVar('_name'); + $className = CRM_Utils_String::getClassName($fullName); + + // Hack for special cases. + switch ($className) { + case 'Contribute': + $attributes = $form->getVar('_attributes'); + $class = strtolower(basename(CRM_Utils_Array::value('action', $attributes))); + break; + + case 'MembershipBlock': + $class = 'membership'; + break; + + default: + $class = strtolower($className); + break; + } + + if (array_key_exists($class, $tabs)) { + $tabs[$class]['current'] = TRUE; + $qfKey = $form->get('qfKey'); + if ($qfKey) { + $tabs[$class]['qfKey'] = "&qfKey={$qfKey}"; + } + } + + if ($contribPageId) { + $reset = CRM_Utils_Array::value('reset', $_GET) ? 'reset=1&' : ''; + + foreach ($tabs as $key => $value) { + if (!isset($tabs[$key]['qfKey'])) { + $tabs[$key]['qfKey'] = NULL; + } + + $tabs[$key]['link'] = + CRM_Utils_System::url( + "civicrm/admin/contribute/{$key}", + "{$reset}action=update&snippet=5&id={$contribPageId}{$tabs[$key]['qfKey']}" + ); + $tabs[$key]['active'] = $tabs[$key]['valid'] = TRUE; + } + //get all section info. + $contriPageInfo = CRM_Contribute_BAO_ContributionPage::getSectionInfo(array($contribPageId)); + + foreach ($contriPageInfo[$contribPageId] as $section => $info) { + if (!$info) { + $tabs[$section]['valid'] = FALSE; + } + } + } + return $tabs; + } + + static function reset(&$form) { + $tabs = self::process($form); + $form->set('tabHeader', $tabs); + } + + static function getCurrentTab($tabs) { + static $current = FALSE; + + if ($current) { + return $current; + } + + if (is_array($tabs)) { + foreach ($tabs as $subPage => $pageVal) { + if ($pageVal['current'] === TRUE) { + $current = $subPage; + break; + } + } + } + + $current = $current ? $current : 'settings'; + return $current; + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/ThankYou.php b/CRM/Contribute/Form/ContributionPage/ThankYou.php new file mode 100644 index 0000000000..ebce2b23c1 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/ThankYou.php @@ -0,0 +1,143 @@ +_id, 'title'); + CRM_Utils_System::setTitle(ts('Thank-you and Receipting (%1)', array(1 => $title))); + return parent::setDefaultValues(); + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + $this->registerRule('emailList', 'callback', 'emailList', 'CRM_Utils_Rule'); + + // thank you title and text (html allowed in text) + $this->add('text', 'thankyou_title', ts('Thank-you Page Title'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'thankyou_title'), TRUE); + $this->addWysiwyg('thankyou_text', ts('Thank-you Message'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'thankyou_text')); + $this->addWysiwyg('thankyou_footer', ts('Thank-you Page Footer'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'thankyou_footer')); + + $this->addElement('checkbox', 'is_email_receipt', ts('Email Receipt to Contributor?'), NULL, array('onclick' => "showReceipt()")); + $this->add('text', 'receipt_from_name', ts('Receipt From Name'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'receipt_from_name')); + $this->add('text', 'receipt_from_email', ts('Receipt From Email'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'receipt_from_email')); + $this->add('textarea', 'receipt_text', ts('Receipt Message'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'receipt_text')); + + $this->add('text', 'cc_receipt', ts('CC Receipt To'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'cc_receipt')); + $this->addRule('cc_receipt', ts('Please enter a valid list of comma delimited email addresses'), 'emailList'); + + $this->add('text', 'bcc_receipt', ts('BCC Receipt To'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionPage', 'bcc_receipt')); + $this->addRule('bcc_receipt', ts('Please enter a valid list of comma delimited email addresses'), 'emailList'); + + parent::buildQuickForm(); + $this->addFormRule(array('CRM_Contribute_Form_ContributionPage_ThankYou', 'formRule'), $this); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $options) { + $errors = array(); + + // if is_email_receipt is set, the receipt message must be non-empty + if (CRM_Utils_Array::value('is_email_receipt', $fields)) { + //added for CRM-1348 + $email = trim(CRM_Utils_Array::value('receipt_from_email', $fields)); + if (empty($email) || !CRM_Utils_Rule::email($email)) { + $errors['receipt_from_email'] = ts('A valid Receipt From Email address must be specified if Email Receipt to Contributor is enabled'); + } + } + return $errors; + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + $params['id'] = $this->_id; + $params['is_email_receipt'] = CRM_Utils_Array::value('is_email_receipt', $params, FALSE); + if (!$params['is_email_receipt']) { + $params['receipt_from_name'] = NULL; + $params['receipt_from_email'] = NULL; + $params['receipt_text'] = NULL; + $params['cc_receipt'] = NULL; + $params['bcc_receipt'] = NULL; + } + + $dao = CRM_Contribute_BAO_ContributionPage::create($params); + parent::endPostProcess(); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Thanks and Receipt'); + } +} + diff --git a/CRM/Contribute/Form/ContributionPage/Widget.php b/CRM/Contribute/Form/ContributionPage/Widget.php new file mode 100644 index 0000000000..f6b2ba0256 --- /dev/null +++ b/CRM/Contribute/Form/ContributionPage/Widget.php @@ -0,0 +1,260 @@ +_widget = new CRM_Contribute_DAO_Widget(); + $this->_widget->contribution_page_id = $this->_id; + if (!$this->_widget->find(TRUE)) { + $this->_widget = NULL; + } + else { + $this->assign('widget_id', $this->_widget->id); + + // check of home url is set, if set then it flash widget might be in use. + $this->assign('showStatus', FALSE); + if ($this->_widget->url_homepage) { + $this->assign('showStatus', TRUE); + } + } + + $this->assign('cpageId', $this->_id); + + $config = CRM_Core_Config::singleton(); + $title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', + $this->_id, + 'title' + ); + + $this->_fields = array('title' => array(ts('Title'), + 'text', + FALSE, + $title, + ), + 'url_logo' => array(ts('URL to Logo Image'), + 'text', + FALSE, + NULL, + ), + 'button_title' => array(ts('Button Title'), + 'text', + FALSE, + ts('Contribute!'), + ), + ); + + $this->_colorFields = array('color_title' => array(ts('Title Text Color'), + 'text', + FALSE, + '#2786C2', + ), + 'color_bar' => array(ts('Progress Bar Color'), + 'text', + FALSE, + '#FFFFFF', + ), + 'color_main_text' => array(ts('Additional Text Color'), + 'text', + FALSE, + '#FFFFFF', + ), + 'color_main' => array(ts('Background Color'), + 'text', + FALSE, + '#96C0E7', + ), + 'color_main_bg' => array(ts('Background Color Top Area'), + 'text', + FALSE, + '#B7E2FF', + ), + 'color_bg' => array(ts('Border Color'), + 'text', + FALSE, + '#96C0E7', + ), + 'color_about_link' => array(ts('Button Link Color'), + 'text', + FALSE, + '#556C82', + ), + 'color_button' => array(ts('Button Background Color'), + 'text', + FALSE, + '#FFFFFF', + ), + 'color_homepage_link' => array(ts('Homepage Link Color'), + 'text', + FALSE, + '#FFFFFF', + ), + ); + } + + function setDefaultValues() { + $defaults = array(); + // check if there is a widget already created + if ($this->_widget) { + CRM_Core_DAO::storeValues($this->_widget, $defaults); + } + else { + foreach ($this->_fields as $name => $val) { + $defaults[$name] = $val[3]; + } + foreach ($this->_colorFields as $name => $val) { + $defaults[$name] = $val[3]; + } + $defaults['about'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', + $this->_id, + 'intro_text' + ); + } + + $showHide = new CRM_Core_ShowHideBlocks(); + $showHide->addHide('id-colors'); + $showHide->addToTemplate(); + return $defaults; + } + + function buildQuickForm() { + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Widget'); + + $this->addElement('checkbox', + 'is_active', + ts('Enable Widget?'), + NULL, + array('onclick' => "widgetBlock(this)") + ); + + $this->addWysiwyg('about', ts('About'), $attributes['about']); + + foreach ($this->_fields as $name => $val) { + $this->add($val[1], + $name, + $val[0], + $attributes[$name], + $val[2] + ); + } + foreach ($this->_colorFields as $name => $val) { + $this->add($val[1], + $name, + $val[0], + $attributes[$name], + $val[2] + ); + } + + $this->assign_by_ref('fields', $this->_fields); + $this->assign_by_ref('colorFields', $this->_colorFields); + + $this->_refreshButtonName = $this->getButtonName('refresh'); + $this->addElement('submit', + $this->_refreshButtonName, + ts('Save and Preview') + ); + parent::buildQuickForm(); + $this->addFormRule(array('CRM_Contribute_Form_ContributionPage_Widget', 'formRule'), $this); + } + + /** + * Function for validation + * + * @param array $params (ref.) an assoc array of name/value pairs + * + * @return mixed true or array of errors + * @access public + * @static + */ + public static function formRule($params, $files, $self) { + $errors = array(); + if (CRM_Utils_Array::value('is_active', $params)) { + if (!CRM_Utils_Array::value('title', $params)) { + $errors['title'] = ts('Title is a required field.'); + } + if (!CRM_Utils_Array::value('about', $params)) { + $errors['about'] = ts('About is a required field.'); + } + + foreach ($params as $key => $val) { + if (substr($key, 0, 6) == 'color_' && !CRM_Utils_Array::value($key, $params)) { + $errors[$key] = ts('%1 is a required field.', array(1 => $self->_colorFields[$key][0])); + } + } + } + return empty($errors) ? TRUE : $errors; + } + + function postProcess() { + //to reset quickform elements of next (pcp) page. + if ($this->controller->getNextName('Widget') == 'PCP') { + $this->controller->resetPage('PCP'); + } + + // get the submitted form values. + $params = $this->controller->exportValues($this->_name); + + if ($this->_widget) { + $params['id'] = $this->_widget->id; + } + $params['contribution_page_id'] = $this->_id; + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['url_homepage'] = 'null'; + + $widget = new CRM_Contribute_DAO_Widget(); + $widget->copyValues($params); + $widget->save(); + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->_refreshButtonName) { + return; + } + parent::endPostProcess(); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Widget Settings'); + } +} + diff --git a/CRM/Contribute/Form/ContributionView.php b/CRM/Contribute/Form/ContributionView.php new file mode 100644 index 0000000000..90bf09dade --- /dev/null +++ b/CRM/Contribute/Form/ContributionView.php @@ -0,0 +1,225 @@ +get('id'); + $values = $ids = array(); + $params = array('id' => $id); + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $this->assign('context', $context); + + CRM_Contribute_BAO_Contribution::getValues($params, $values, $ids); + + $softParams = array('contribution_id' => CRM_Utils_Array::value('contribution_id', $values)); + if ($softContribution = CRM_Contribute_BAO_Contribution::getSoftContribution($softParams, TRUE)) { + $values = array_merge($values, $softContribution); + } + CRM_Contribute_BAO_Contribution::resolveDefaults($values); + + if (CRM_Utils_Array::value('contribution_page_id', $values)) { + $contribPages = CRM_Contribute_PseudoConstant::contributionPage(NULL, TRUE); + $values['contribution_page_title'] = CRM_Utils_Array::value(CRM_Utils_Array::value('contribution_page_id', $values), $contribPages); + } + + // get recieved into i.e to_financial_account_id from last trxn + $financialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($values['contribution_id'], 'DESC'); + $values['to_financial_account'] = ''; + if (CRM_Utils_Array::value('financialTrxnId', $financialTrxnId)) { + $values['to_financial_account_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $financialTrxnId['financialTrxnId'], 'to_financial_account_id'); + if ($values['to_financial_account_id']) { + $values['to_financial_account'] = CRM_Contribute_PseudoConstant::financialAccount($values['to_financial_account_id']); + } + } + + if (CRM_Utils_Array::value('honor_contact_id', $values)) { + $sql = "SELECT display_name FROM civicrm_contact WHERE id = %1"; + $params = array(1 => array($values['honor_contact_id'], 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$values[honor_contact_id]"); + $values['honor_display'] = "" . $dao->display_name . ""; + } + $honor = CRM_Core_PseudoConstant::honor(); + $values['honor_type'] = CRM_Utils_Array::value(CRM_Utils_Array::value('honor_type_id', $values), $honor); + } + + if (CRM_Utils_Array::value('contribution_recur_id', $values)) { + $sql = "SELECT installments, frequency_interval, frequency_unit FROM civicrm_contribution_recur WHERE id = %1"; + $params = array(1 => array($values['contribution_recur_id'], 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + $values['recur_installments'] = $dao->installments; + $values['recur_frequency_unit'] = $dao->frequency_unit; + $values['recur_frequency_interval'] = $dao->frequency_interval; + } + } + + $groupTree = CRM_Core_BAO_CustomGroup::getTree('Contribution', $this, $id, 0, CRM_Utils_Array::value('financial_type_id', $values)); + CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree); + + $premiumId = NULL; + if ($id) { + $dao = new CRM_Contribute_DAO_ContributionProduct(); + $dao->contribution_id = $id; + if ($dao->find(TRUE)) { + $premiumId = $dao->id; + $productID = $dao->product_id; + } + } + + if ($premiumId) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $productID; + $productDAO->find(TRUE); + + $this->assign('premium', $productDAO->name); + $this->assign('option', $dao->product_option); + $this->assign('fulfilled', $dao->fulfilled_date); + } + + // Get Note + $noteValue = CRM_Core_BAO_Note::getNote(CRM_Utils_Array::value('id', $values), 'civicrm_contribution'); + $values['note'] = array_values($noteValue); + + // show billing address location details, if exists + if (CRM_Utils_Array::value('address_id', $values)) { + $addressParams = array('id' => CRM_Utils_Array::value('address_id', $values)); + $addressDetails = CRM_Core_BAO_Address::getValues($addressParams, FALSE, 'id'); + $addressDetails = array_values($addressDetails); + $values['billing_address'] = $addressDetails[0]['display']; + } + + //get soft credit record if exists. + if ($softContribution = CRM_Contribute_BAO_Contribution::getSoftContribution($softParams)) { + + $softContribution['softCreditToName'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $softContribution['soft_credit_to'], 'display_name' + ); + //hack to avoid dispalyName conflict + //for viewing softcredit record. + $softContribution['displayName'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', + $values['contact_id'], 'display_name' + ); + $values = array_merge($values, $softContribution); + } + + $lineItems = array(); + if ($id) { + $lineItem = CRM_Price_BAO_LineItem::getLineItems($id, 'contribution', 1); + empty($lineItem) ? null :$lineItems[] = $lineItem; + } + $this->assign('lineItem', empty($lineItems) ? FALSE : $lineItems); + $values['totalAmount'] = $values['total_amount']; + + //do check for campaigns + if ($campaignId = CRM_Utils_Array::value('campaign_id', $values)) { + $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns($campaignId); + $values['campaign'] = $campaigns[$campaignId]; + } + + // assign values to the template + $this->assign($values); + + $displayName = CRM_Contact_BAO_Contact::displayName($values['contact_id']); + $this->assign('displayName', $displayName); + + // Check if this is default domain contact CRM-10482 + if (CRM_Contact_BAO_Contact::checkDomainContact($values['contact_id'])) { + $displayName .= ' (' . ts('default organization') . ')'; + } + + // omitting contactImage from title for now since the summary overlay css doesn't work outside of our crm-container + CRM_Utils_System::setTitle(ts('View Contribution from') . ' ' . $displayName); + + // add viewed contribution to recent items list + $url = CRM_Utils_System::url('civicrm/contact/view/contribution', + "action=view&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home" + ); + + $title = $displayName . ' - (' . CRM_Utils_Money::format($values['total_amount']) . ' ' . ' - ' . $values['financial_type'] . ')'; + + $recentOther = array(); + if (CRM_Core_Permission::checkActionPermission('CiviContribute', CRM_Core_Action::UPDATE)) { + $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/contact/view/contribution', + "action=update&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home" + ); + } + if (CRM_Core_Permission::checkActionPermission('CiviContribute', CRM_Core_Action::DELETE)) { + $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/contribution', + "action=delete&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home" + ); + } + CRM_Utils_Recent::add($title, + $url, + $values['id'], + 'Contribution', + $values['contact_id'], + NULL, + $recentOther + ); + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + $this->addButtons(array( + array( + 'type' => 'cancel', + 'name' => ts('Done'), + 'spacing' => '         ', + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Contribute/Form/ManagePremiums.php b/CRM/Contribute/Form/ManagePremiums.php new file mode 100644 index 0000000000..a68eadbfc8 --- /dev/null +++ b/CRM/Contribute/Form/ManagePremiums.php @@ -0,0 +1,417 @@ +_id) { + $params = array('id' => $this->_id); + CRM_Contribute_BAO_ManagePremiums::retrieve($params, $tempDefaults); + $imageUrl = (isset($tempDefaults['image'])) ? $tempDefaults['image'] : ""; + if (isset($tempDefaults['image']) && isset($tempDefaults['thumbnail'])) { + $defaults['imageUrl'] = $tempDefaults['image']; + $defaults['thumbnailUrl'] = $tempDefaults['thumbnail']; + $defaults['imageOption'] = 'thumbnail'; + // assign thumbnailUrl to template so we can display current image in update mode + $this->assign('thumbnailUrl', $defaults['thumbnailUrl']); + } + else { + $defaults['imageOption'] = 'noImage'; + } + if (isset($tempDefaults['thumbnail']) && isset($tempDefaults['image'])) { + $this->assign('thumbURL', $tempDefaults['thumbnail']); + $this->assign('imageURL', $tempDefaults['image']); + } + if (isset($tempDefaults['period_type'])) { + $this->assign('showSubscriptions', TRUE); + } + } + + return $defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + //parent::buildQuickForm( ); + + if ($this->_action & CRM_Core_Action::PREVIEW) { + CRM_Contribute_BAO_Premium::buildPremiumPreviewBlock($this, $this->_id); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Done with Preview'), + 'isDefault' => TRUE, + ), + ) + ); + + return; + } + + if ($this->_action & CRM_Core_Action::DELETE) { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Delete'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + return; + } + + $this->applyFilter('__ALL__', 'trim'); + $this->add('text', 'name', ts('Name'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'name'), TRUE); + $this->addRule('name', ts('A product with this name already exists. Please select another name.'), 'objectExists', array('CRM_Contribute_DAO_Product', $this->_id)); + $this->add('text', 'sku', ts('SKU'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'sku')); + + $this->add('textarea', 'description', ts('Description'), 'rows=3, cols=60'); + + $image['image'] = $this->createElement('radio', NULL, NULL, ts('Upload from my computer'), 'image', 'onclick="add_upload_file_block(\'image\');'); + $image['thumbnail'] = $this->createElement('radio', NULL, NULL, ts('Display image and thumbnail from these locations on the web:'), 'thumbnail', 'onclick="add_upload_file_block(\'thumbnail\');'); + $image['default_image'] = $this->createElement('radio', NULL, NULL, ts('Use default image'), 'default_image', 'onclick="add_upload_file_block(\'default\');'); + $image['noImage'] = $this->createElement('radio', NULL, NULL, ts('Do not display an image'), 'noImage', 'onclick="add_upload_file_block(\'noImage\');'); + + $this->addGroup($image, 'imageOption', ts('Premium Image')); + $this->addRule('imageOption', ts('Please select an option for the premium image.'), 'required'); + + $this->addElement('text', 'imageUrl', ts('Image URL')); + $this->addRule('imageUrl', 'Please enter the valid URL to display this image.', 'url'); + $this->addElement('text', 'thumbnailUrl', ts('Thumbnail URL')); + $this->addRule('thumbnailUrl', 'Please enter the valid URL to display a thumbnail of this image.', 'url'); + + $this->add('file', 'uploadFile', ts('Image File Name'), 'onChange="select_option();"'); + + + $this->add('text', 'price', ts('Market Value'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'price'), TRUE); + $this->addRule('price', ts('Please enter the Market Value for this product.'), 'money'); + + $this->add('text', 'cost', ts('Actual Cost of Product'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'cost')); + $this->addRule('price', ts('Please enter the Actual Cost of Product.'), 'money'); + + $this->add('text', 'min_contribution', ts('Minimum Contribution Amount'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'min_contribution'), TRUE); + $this->addRule('min_contribution', ts('Please enter a monetary value for the Minimum Contribution Amount.'), 'money'); + + $this->add('textarea', 'options', ts('Options'), 'rows=3, cols=60'); + + $this->add('select', 'period_type', ts('Period Type'), array('' => '- select -', 'rolling' => 'Rolling', 'fixed' => 'Fixed')); + + $this->add('text', 'fixed_period_start_day', ts('Fixed Period Start Day'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'fixed_period_start_day')); + + + $this->add('Select', 'duration_unit', ts('Duration Unit'), array('' => '- select period -', 'day' => 'Day', 'week' => 'Week', 'month' => 'Month', 'year' => 'Year')); + + $this->add('text', 'duration_interval', ts('Duration'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'duration_interval')); + + $this->add('Select', 'frequency_unit', ts('Frequency Unit'), array('' => '- select period -', 'day' => 'Day', 'week' => 'Week', 'month' => 'Month', 'year' => 'Year')); + + $this->add('text', 'frequency_interval', ts('Frequency'), CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Product', 'frequency_interval')); + + //Financial Type CRM-11106 + $financialType = CRM_Contribute_PseudoConstant::financialType( ); + $premiumFinancialType = array(); + CRM_Core_PseudoConstant::populate( + $premiumFinancialType, + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = True, + $retrieve = 'entity_id', + $filter = null, + 'account_relationship = 8' + ); + + $costFinancialType = array(); + CRM_Core_PseudoConstant::populate( + $costFinancialType, + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = True, + $retrieve = 'entity_id', + $filter = null, + 'account_relationship = 7' + ); + $productFinancialType = array_intersect($costFinancialType, $premiumFinancialType); + foreach( $financialType as $key => $financialTypeName ){ + if(!in_array( $key, $productFinancialType)) + unset( $financialType[$key] ); + } + if( count( $financialType ) ){ + $this->assign( 'financialType', $financialType ); + } + $this->add( + 'select', + 'financial_type_id', + ts( 'Financial Type' ), + array(''=>ts('- select -')) + $financialType + ); + + $this->add('checkbox', 'is_active', ts('Enabled?')); + + $this->addFormRule(array('CRM_Contribute_Form_ManagePremiums', 'formRule')); + + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + $this->assign('productId', $this->_id); + } + + /** + * Function for validation + * + * @param array $params (ref.) an assoc array of name/value pairs + * + * @return mixed true or array of errors + * @access public + * @static + */ + public function formRule($params, $files) { + if (isset($params['imageOption'])) { + if ($params['imageOption'] == 'thumbnail') { + if (!$params['imageUrl']) { + $errors['imageUrl'] = 'Image URL is Required '; + } + if (!$params['thumbnailUrl']) { + $errors['thumbnailUrl'] = 'Thumbnail URL is Required '; + } + } + } + + $fileLocation = $files['uploadFile']['tmp_name']; + if ($fileLocation != "") { + list($width, $height) = getimagesize($fileLocation); + + if (($width < 80 || $width > 500) || ($height < 80 || $height > 500)) { + //$errors ['uploadFile'] = "Please Enter files with dimensions between 80 x 80 and 500 x 500," . " Dimensions of this file is ".$width."X".$height; + } + } + + if (!$params['period_type']) { + if ($params['fixed_period_start_day'] || $params['duration_unit'] || $params['duration_interval'] || + $params['frequency_unit'] || $params['frequency_interval'] + ) { + $errors['period_type'] = ts('Please select the Period Type for this subscription or service.'); + } + } + + if ($params['period_type'] == 'fixed' && !$params['fixed_period_start_day']) { + $errors['fixed_period_start_day'] = ts('Please enter a Fixed Period Start Day for this subscription or service.'); + } + + if ($params['duration_unit'] && !$params['duration_interval']) { + $errors['duration_interval'] = ts('Please enter the Duration Interval for this subscription or service.'); + } + + if ($params['duration_interval'] && !$params['duration_unit']) { + $errors['duration_unit'] = ts('Please enter the Duration Unit for this subscription or service.'); + } + + if ($params['frequency_interval'] && !$params['frequency_unit']) { + $errors['frequency_unit'] = ts('Please enter the Frequency Unit for this subscription or service.'); + } + + if ($params['frequency_unit'] && !$params['frequency_interval']) { + $errors['frequency_interval'] = ts('Please enter the Frequency Interval for this subscription or service.'); + } + + + return empty($errors) ? TRUE : $errors; + } + + /** + * Function to process the form + * + * @access public + * + * @return None + */ + public function postProcess() { + + if ($this->_action & CRM_Core_Action::PREVIEW) { + return; + } + + if ($this->_action & CRM_Core_Action::DELETE) { + CRM_Contribute_BAO_ManagePremiums::del($this->_id); + CRM_Core_Session::setStatus(ts('Selected Premium Product type has been deleted.'), ts('Deleted'), 'info'); + } + else { + $params = $this->controller->exportValues($this->_name); + $imageFile = CRM_Utils_Array::value('uploadFile', $params); + $imageFile = $imageFile['name']; + + $config = CRM_Core_Config::singleton(); + + $ids = array(); + $error = FALSE; + // store the submitted values in an array + + // FIX ME + if (CRM_Utils_Array::value('imageOption', $params, FALSE)) { + $value = CRM_Utils_Array::value('imageOption', $params, FALSE); + if ($value == 'image') { + + // to check wether GD is installed or not + $gdSupport = CRM_Utils_System::getModuleSetting('gd', 'GD Support'); + if($gdSupport) { + if($imageFile) { + $error = false; + $params['image'] = $this->_resizeImage($imageFile, "_full", 200, 200); + $params['thumbnail'] = $this->_resizeImage($imageFile, "_thumb", 50, 50); + } + } else { + $error = true; + $params['image'] = $config->resourceBase . 'i/contribute/default_premium.jpg'; + $params['thumbnail'] = $config->resourceBase . 'i/contribute/default_premium_thumb.jpg'; + } + } elseif ($value == 'thumbnail') { + $params['image'] = $params['imageUrl']; + $params['thumbnail'] = $params['thumbnailUrl']; + } elseif ($value == 'default_image') { + $url = parse_url($config->userFrameworkBaseURL); + $params['image'] = $config->resourceBase . 'i/contribute/default_premium.jpg'; + $params['thumbnail'] = $config->resourceBase . 'i/contribute/default_premium_thumb.jpg'; + } else { + $params['image'] = ""; + $params['thumbnail'] = ""; + } + } + + if ($this->_action & CRM_Core_Action::UPDATE) { + $ids['premium'] = $this->_id; + } + + // fix the money fields + foreach (array( + 'cost', 'price', 'min_contribution') as $f) { + $params[$f] = CRM_Utils_Rule::cleanMoney($params[$f]); + } + + $premium = CRM_Contribute_BAO_ManagePremiums::add($params, $ids); + if ($error) { + CRM_Core_Session::setStatus(ts('No thumbnail of your image was created because the GD image library is not currently compiled in your PHP installation. Product is currently configured to use default thumbnail image. If you have a local thumbnail image you can upload it separately and input the thumbnail URL by editing this premium.'), ts('Notice'), 'alert'); + } + else { + CRM_Core_Session::setStatus(ts("The Premium '%1' has been saved.", array(1 => $premium->name)), ts('Saved'), 'success'); + } + } + } + + /** + * Resize a premium image to a different size + * + * @access private + * + * @return Path to image + */ + private function _resizeImage($filename, $resizedName, $width, $height) { + // figure out the new filename + $pathParts = pathinfo($filename); + $newFilename = $pathParts['dirname']."/".$pathParts['filename'].$resizedName.".".$pathParts['extension']; + + // get image about original image + $imageInfo = getimagesize($filename); + $widthOrig = $imageInfo[0]; + $heightOrig = $imageInfo[1]; + $image = imagecreatetruecolor($width, $height); + if($imageInfo['mime'] == 'image/gif') { + $source = imagecreatefromgif($filename); + } elseif($imageInfo['mime'] == 'image/png') { + $source = imagecreatefrompng($filename); + } else { + $source = imagecreatefromjpeg($filename); + } + + // resize + imagecopyresized($image, $source, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig); + + // save the resized image + $fp = fopen($newFilename, 'w+'); + ob_start(); + ImageJPEG($image); + $image_buffer = ob_get_contents(); + ob_end_clean(); + ImageDestroy($image); + fwrite($fp, $image_buffer); + rewind($fp); + fclose($fp); + + // return the URL to link to + $config = CRM_Core_Config::singleton(); + return $config->imageUploadURL.basename($newFilename); + } +} + diff --git a/CRM/Contribute/Form/Search.php b/CRM/Contribute/Form/Search.php new file mode 100644 index 0000000000..fdafe0b881 --- /dev/null +++ b/CRM/Contribute/Form/Search.php @@ -0,0 +1,561 @@ +set('searchFormName', 'Search'); + + /** + * set the button names + */ + $this->_searchButtonName = $this->getButtonName('refresh'); + $this->_printButtonName = $this->getButtonName('next', 'print'); + $this->_actionButtonName = $this->getButtonName('next', 'action'); + + $this->_done = FALSE; + $this->defaults = array(); + + /* + * we allow the controller to set force/reset externally, useful when we are being + * driven by the wizard framework + */ + + $this->_reset = CRM_Utils_Request::retrieve('reset', 'Boolean', CRM_Core_DAO::$_nullObject); + $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE); + $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this); + $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'search'); + + $this->assign("context", $this->_context); + + // get user submitted values + // get it from controller only if form has been submitted, else preProcess has set this + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + } + else { + $this->_formValues = $this->get('formValues'); + } + + //membership ID + $memberShipId = CRM_Utils_Request::retrieve('memberId', 'Positive', $this); + if (isset($memberShipId)) { + $this->_formValues['contribution_membership_id'] = $memberShipId; + } + $participantId = CRM_Utils_Request::retrieve('participantId', 'Positive', $this); + if (isset($participantId)) { + $this->_formValues['contribution_participant_id'] = $participantId; + } + + if ($this->_force) { + $this->postProcess(); + $this->set('force', 0); + } + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $selector = new CRM_Contribute_Selector_Search($this->_queryParams, + $this->_action, + NULL, + $this->_single, + $this->_limit, + $this->_context + ); + $prefix = NULL; + if ($this->_context == 'user') { + $prefix = $this->_prefix; + } + + $this->assign("{$prefix}limit", $this->_limit); + $this->assign("{$prefix}single", $this->_single); + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::TRANSFER, + $prefix + ); + + $controller->setEmbedded(TRUE); + $controller->moveFromSessionToTemplate(); + + $this->assign('contributionSummary', $this->get('summary')); + } + + function setDefaultValues() { + if (!CRM_Utils_Array::value('contribution_status', + $this->_defaults + )) { + $this->_defaults['contribution_status'][1] = 1; + } + return $this->_defaults; + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // text for sort_name + $this->addElement('text', + 'sort_name', + ts('Contributor Name or Email'), + CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', + 'sort_name' + ) + ); + + $this->_group = CRM_Core_PseudoConstant::group(); + + // multiselect for groups + if ($this->_group) { + $this->add('select', 'group', ts('Groups'), $this->_group, FALSE, + array('id' => 'group', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + + // multiselect for tags + require_once 'CRM/Core/BAO/Tag.php'; + $contactTags = CRM_Core_BAO_Tag::getTags(); + + if ($contactTags) { + $this->add('select', 'contact_tags', ts('Tags'), $contactTags, FALSE, + array('id' => 'contact_tags', 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + + CRM_Contribute_BAO_Query::buildSearchForm($this); + + /* + * add form checkboxes for each row. This is needed out here to conform to QF protocol + * of all elements being declared in builQuickForm + */ + + $rows = $this->get('rows'); + if (is_array($rows)) { + if (!$this->_single) { + $this->addElement('checkbox', + 'toggleSelect', + NULL, + NULL, + array('onclick' => "toggleTaskAction( true ); return toggleCheckboxVals('mark_x_',this);") + ); + foreach ($rows as $row) { + $this->addElement('checkbox', $row['checkbox'], + NULL, NULL, + array('onclick' => "toggleTaskAction( true ); return checkSelectedBox('" . $row['checkbox'] . "');") + ); + } + } + + $total = $cancel = 0; + + $permission = CRM_Core_Permission::getPermission(); + + $tasks = array('' => ts('- actions -')) + CRM_Contribute_Task::permissionedTaskTitles($permission); + $this->add('select', 'task', ts('Actions:') . ' ', $tasks); + $this->add('submit', $this->_actionButtonName, ts('Go'), + array( + 'class' => 'form-submit', + 'id' => 'Go', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 0);", + ) + ); + + $this->add('submit', $this->_printButtonName, ts('Print'), + array( + 'class' => 'form-submit', + 'onclick' => "return checkPerformAction('mark_x', '" . $this->getName() . "', 1);", + ) + ); + + // need to perform tasks on all or selected items ? using radio_ts(task selection) for it + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_sel', array('checked' => 'checked')); + $this->addElement('radio', 'radio_ts', NULL, '', 'ts_all', array('onclick' => $this->getName() . ".toggleSelect.checked = false; toggleCheckboxVals('mark_x_',this); toggleTaskAction( true );")); + } + + // add buttons + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * The post processing of the form gets done here. + * + * Key things done during post processing are + * - check for reset or next request. if present, skip post procesing. + * - now check if user requested running a saved search, if so, then + * the form values associated with the saved search are used for searching. + * - if user has done a submit with new values the regular post submissing is + * done. + * The processing consists of using a Selector / Controller framework for getting the + * search results. + * + * @param + * + * @return void + * @access public + */ + function postProcess() { + if ($this->_done) { + return; + } + + $this->_done = TRUE; + + if (!empty($_POST)) { + $this->_formValues = $this->controller->exportValues($this->_name); + } + + $this->fixFormValues(); + + // we don't show test contributions in Contact Summary / User Dashboard + // in Search mode by default we hide test contributions + if (!CRM_Utils_Array::value('contribution_test', + $this->_formValues + )) { + $this->_formValues["contribution_test"] = 0; + } + + foreach (array( + 'contribution_amount_low', 'contribution_amount_high') as $f) { + if (isset($this->_formValues[$f])) { + $this->_formValues[$f] = CRM_Utils_Rule::cleanMoney($this->_formValues[$f]); + } + } + + $config = CRM_Core_Config::singleton(); + $tags = CRM_Utils_Array::value('contact_tags', $this->_formValues); + if ($tags && !is_array($tags)) { + unset($this->_formValues['contact_tags']); + $this->_formValues['contact_tags'][$tags] = 1; + } + + if ($tags && is_array($tags)) { + unset($this->_formValues['contact_tags']); + foreach($tags as $notImportant => $tagID) { + $this->_formValues['contact_tags'][$tagID] = 1; + } + } + + + if (!$config->groupTree) { + $group = CRM_Utils_Array::value('group', $this->_formValues); + if ($group && !is_array($group)) { + unset($this->_formValues['group']); + $this->_formValues['group'][$group] = 1; + } + + if ($group && is_array($group)) { + unset($this->_formValues['group']); + foreach($group as $notImportant => $groupID) { + $this->_formValues['group'][$groupID] = 1; + } + } + + } + + CRM_Core_BAO_CustomValue::fixFieldValueOfTypeMemo($this->_formValues); + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + + $this->set('formValues', $this->_formValues); + $this->set('queryParams', $this->_queryParams); + + $buttonName = $this->controller->getButtonName(); + if ($buttonName == $this->_actionButtonName || $buttonName == $this->_printButtonName) { + // check actionName and if next, then do not repeat a search, since we are going to the next page + + // hack, make sure we reset the task values + $stateMachine = &$this->controller->getStateMachine(); + $formName = $stateMachine->getTaskFormName(); + $this->controller->resetPage($formName); + return; + } + + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues); + $selector = new CRM_Contribute_Selector_Search($this->_queryParams, + $this->_action, + NULL, + $this->_single, + $this->_limit, + $this->_context + ); + $selector->setKey($this->controller->_key); + + $prefix = NULL; + if ($this->_context == 'basic' || $this->_context == 'user') { + $prefix = $this->_prefix; + } + + $controller = new CRM_Core_Selector_Controller($selector, + $this->get(CRM_Utils_Pager::PAGE_ID), + $sortID, + CRM_Core_Action::VIEW, + $this, + CRM_Core_Selector_Controller::SESSION, + $prefix + ); + $controller->setEmbedded(TRUE); + + $query = &$selector->getQuery(); + if ($this->_context == 'user') { + $query->setSkipPermission(TRUE); + } + $summary = &$query->summaryContribution($this->_context); + $this->set('summary', $summary); + $this->assign('contributionSummary', $summary); + $controller->run(); + } + + function fixFormValues() { + // if this search has been forced + // then see if there are any get values, and if so over-ride the post values + // note that this means that GET over-rides POST :) + + if (!$this->_force) { + return; + } + + $status = CRM_Utils_Request::retrieve('status', 'String', + CRM_Core_DAO::$_nullObject + ); + if ($status) { + $this->_formValues['contribution_status_id'] = array($status => 1); + $this->_defaults['contribution_status_id'] = array($status => 1); + } + + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this); + + if ($cid) { + $cid = CRM_Utils_Type::escape($cid, 'Integer'); + if ($cid > 0) { + $this->_formValues['contact_id'] = $cid; + list($display, $image) = CRM_Contact_BAO_Contact::getDisplayAndImage($cid); + $this->_defaults['sort_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, + 'sort_name' + ); + // also assign individual mode to the template + $this->_single = TRUE; + } + } + + $lowDate = CRM_Utils_Request::retrieve('start', 'Timestamp', + CRM_Core_DAO::$_nullObject + ); + if ($lowDate) { + $lowDate = CRM_Utils_Type::escape($lowDate, 'Timestamp'); + $date = CRM_Utils_Date::setDateDefaults($lowDate); + $this->_formValues['contribution_date_low'] = $this->_defaults['contribution_date_low'] = $date[0]; + } + + $highDate = CRM_Utils_Request::retrieve('end', 'Timestamp', + CRM_Core_DAO::$_nullObject + ); + if ($highDate) { + $highDate = CRM_Utils_Type::escape($highDate, 'Timestamp'); + $date = CRM_Utils_Date::setDateDefaults($highDate); + $this->_formValues['contribution_date_high'] = $this->_defaults['contribution_date_high'] = $date[0]; + } + + if ($highDate || $lowDate) { + //set the Choose Date Range value + $this->_formValues['contribution_date_relative'] = 0; + } + + $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive', + $this + ); + + $test = CRM_Utils_Request::retrieve('test', 'Boolean', + CRM_Core_DAO::$_nullObject + ); + if (isset($test)) { + $test = CRM_Utils_Type::escape($test, 'Boolean'); + $this->_formValues['contribution_test'] = $test; + } + //Recurring id + $recur = CRM_Utils_Request::retrieve('recur', 'Positive', $this, FALSE); + if ($recur) { + $this->_formValues['contribution_recur_id'] = $recur; + $this->_formValues['contribution_recurring'] = 1; + } + + //check for contribution page id. + $contribPageId = CRM_Utils_Request::retrieve('pid', 'Positive', $this); + if ($contribPageId) { + $this->_formValues['contribution_page_id'] = $contribPageId; + } + + //give values to default. + $this->_defaults = $this->_formValues; + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Find Contributions'); + } +} + diff --git a/CRM/Contribute/Form/SearchContribution.php b/CRM/Contribute/Form/SearchContribution.php new file mode 100644 index 0000000000..a0dbe9d3b3 --- /dev/null +++ b/CRM/Contribute/Form/SearchContribution.php @@ -0,0 +1,85 @@ +add('text', 'title', ts('Find'), $attributes); + + $financial_account = CRM_Contribute_PseudoConstant::financialType( ); + foreach($financial_account as $contributionId => $contributionName) { + $this->addElement('checkbox', "financial_type_id[$contributionId]", 'Financial Type', $contributionName); + } + + CRM_Campaign_BAO_Campaign::addCampaignInComponentSearch($this); + + $this->addButtons(array( + array( + 'type' => 'refresh', + 'name' => ts('Search'), + 'isDefault' => TRUE, + ), + )); + } + + function postProcess() { + $params = $this->controller->exportValues($this->_name); + $parent = $this->controller->getParent(); + $parent->set('searchResult', 1); + if (!empty($params)) { + $fields = array( 'title', 'financial_type_id', 'campaign_id' ); + foreach ($fields as $field) { + if (isset($params[$field]) && + !CRM_Utils_System::isNull($params[$field]) + ) { + $parent->set($field, $params[$field]); + } + else { + $parent->set($field, NULL); + } + } + } + } +} + diff --git a/CRM/Contribute/Form/Task.php b/CRM/Contribute/Form/Task.php new file mode 100644 index 0000000000..41256e4839 --- /dev/null +++ b/CRM/Contribute/Form/Task.php @@ -0,0 +1,189 @@ +_contributionIds = array(); + + $values = $form->controller->exportValues($form->get('searchFormName')); + + $form->_task = $values['task']; + $contributeTasks = CRM_Contribute_Task::tasks(); + $form->assign('taskName', $contributeTasks[$form->_task]); + + $ids = array(); + if ($values['radio_ts'] == 'ts_sel') { + foreach ($values as $name => $value) { + if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) { + $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN); + } + } + } + else { + $queryParams = $form->get('queryParams'); + $sortOrder = null; + if ( $form->get( CRM_Utils_Sort::SORT_ORDER ) ) { + $sortOrder = $form->get( CRM_Utils_Sort::SORT_ORDER ); + } + + $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_CONTRIBUTE + ); + $query->_distinctComponentClause = ' civicrm_contribution.id'; + $query->_groupByComponentClause = ' GROUP BY civicrm_contribution.id '; + + $result = $query->searchQuery(0, 0, $sortOrder); + while ($result->fetch()) { + $ids[] = $result->contribution_id; + } + $form->assign('totalSelectedContributions', $form->get('rowCount')); + } + + if (!empty($ids)) { + $form->_componentClause = ' civicrm_contribution.id IN ( ' . implode(',', $ids) . ' ) '; + + $form->assign('totalSelectedContributions', count($ids)); + } + + $form->_contributionIds = $form->_componentIds = $ids; + + //set the context for redirection for any task actions + $session = CRM_Core_Session::singleton(); + + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + + $searchFormName = strtolower($form->get('searchFormName')); + if ($searchFormName == 'search') { + $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/search', $urlParams)); + } + else { + $session->replaceUserContext(CRM_Utils_System::url("civicrm/contact/search/$searchFormName", + $urlParams + )); + } + } + + /** + * Given the contribution id, compute the contact id + * since its used for things like send email + */ + public function setContactIDs() { + $this->_contactIds = &CRM_Core_DAO::getContactIDsFromComponent($this->_contributionIds, + 'civicrm_contribution' + ); + } + + /** + * simple shell that derived classes can call to add buttons to + * the form with a customized title for the main Submit + * + * @param string $title title of the main button + * @param string $type button type for the form after processing + * + * @return void + * @access public + */ + function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) { + $this->addButtons(array( + array( + 'type' => $nextType, + 'name' => $title, + 'isDefault' => TRUE, + ), + array( + 'type' => $backType, + 'name' => ts('Cancel'), + ), + ) + ); + } +} + diff --git a/CRM/Contribute/Form/Task/Batch.php b/CRM/Contribute/Form/Task/Batch.php new file mode 100644 index 0000000000..92c90bb9de --- /dev/null +++ b/CRM/Contribute/Form/Task/Batch.php @@ -0,0 +1,276 @@ + ts('Name')), + CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'contact_autocomplete_options', + TRUE, NULL, FALSE, 'name', TRUE + ) + ); + //get the read only field data. + $returnProperties = array_fill_keys(array_keys($readOnlyFields), 1); + $contactDetails = CRM_Contact_BAO_Contact_Utils::contactDetails($this->_contributionIds, + 'CiviContribute', $returnProperties + ); + $this->assign('contactDetails', $contactDetails); + $this->assign('readOnlyFields', $readOnlyFields); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + $ufGroupId = $this->get('ufGroupId'); + + if (!$ufGroupId) { + CRM_Core_Error::fatal('ufGroupId is missing'); + } + $this->_title = ts('Batch Update for Contributions') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId); + CRM_Utils_System::setTitle($this->_title); + + $this->addDefaultButtons(ts('Save')); + $this->_fields = array(); + $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW); + + // remove file type field and then limit fields + $suppressFields = FALSE; + $removehtmlTypes = array('File', 'Autocomplete-Select'); + foreach ($this->_fields as $name => $field) { + if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) && + in_array($this->_fields[$name]['html_type'], $removehtmlTypes) + ) { + $suppressFields = TRUE; + unset($this->_fields[$name]); + } + + //fix to reduce size as we are using this field in grid + if (is_array($field['attributes']) && $this->_fields[$name]['attributes']['size'] > 19) { + //shrink class to "form-text-medium" + $this->_fields[$name]['attributes']['size'] = 19; + } + } + + $this->_fields = array_slice($this->_fields, 0, $this->_maxFields); + + $this->addButtons(array( + array( + 'type' => 'submit', + 'name' => ts('Update Contribution(s)'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + + $this->assign('profileTitle', $this->_title); + $this->assign('componentIds', $this->_contributionIds); + $fileFieldExists = FALSE; + + //load all campaigns. + if (array_key_exists('contribution_campaign_id', $this->_fields)) { + $this->_componentCampaigns = array(); + CRM_Core_PseudoConstant::populate($this->_componentCampaigns, + 'CRM_Contribute_DAO_Contribution', + TRUE, 'campaign_id', 'id', + ' id IN (' . implode(' , ', array_values($this->_contributionIds)) . ' ) ' + ); + } + + //fix for CRM-2752 + $customFields = CRM_Core_BAO_CustomField::getFields('Contribution'); + foreach ($this->_contributionIds as $contributionId) { + $typeId = CRM_Core_DAO::getFieldValue( "CRM_Contribute_DAO_Contribution", $contributionId, 'financial_type_id' ); + foreach ($this->_fields as $name => $field) { + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) { + $customValue = CRM_Utils_Array::value($customFieldID, $customFields); + if (CRM_Utils_Array::value('extends_entity_column_value', $customValue)) { + $entityColumnValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, + $customValue['extends_entity_column_value'] + ); + } + + if (CRM_Utils_Array::value($typeId, $entityColumnValue) || + CRM_Utils_System::isNull($entityColumnValue[$typeId]) + ) { + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contributionId); + } + } + else { + // handle non custom fields + CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contributionId); + } + } + } + + $this->assign('fields', $this->_fields); + + // don't set the status message when form is submitted. + $buttonName = $this->controller->getButtonName('submit'); + + if ($suppressFields && $buttonName != '_qf_Batch_next') { + CRM_Core_Session::setStatus(ts("FILE or Autocomplete Select type field(s) in the selected profile are not supported for Batch Update and have been excluded."), ts('Unsupported Field Type'), 'error'); + } + + $this->addDefaultButtons(ts('Update Contributions')); + } + + /** + * This function sets the default values for the form. + * + * @access public + * + * @return None + */ + function setDefaultValues() { + if (empty($this->_fields)) { + return; + } + + $defaults = array(); + foreach ($this->_contributionIds as $contributionId) { + $details[$contributionId] = array(); + CRM_Core_BAO_UFGroup::setProfileDefaults(NULL, $this->_fields, $defaults, FALSE, $contributionId, 'Contribute'); + } + + return $defaults; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->exportValues(); + $dates = array( + 'receive_date', + 'receipt_date', + 'thankyou_date', + 'cancel_date', + ); + if (isset($params['field'])) { + foreach ($params['field'] as $key => $value) { + + $value['custom'] = CRM_Core_BAO_CustomField::postProcess($value, + CRM_Core_DAO::$_nullObject, + $key, + 'Contribution' + ); + + $ids['contribution'] = $key; + foreach ($dates as $val) { + if (isset($value[$val])) { + $value[$val] = CRM_Utils_Date::processDate($value[$val]); + } + } + if (CRM_Utils_Array::value('financial_type', $value)) { + $value['financial_type_id'] = $value['financial_type']; + } + + if (CRM_Utils_Array::value('payment_instrument', $value)) { + $value['payment_instrument_id'] = $value['payment_instrument']; + } + + if (CRM_Utils_Array::value('contribution_source', $value)) { + $value['source'] = $value['contribution_source']; + } + + unset($value['financial_type']); + unset($value['contribution_source']); + $contribution = CRM_Contribute_BAO_Contribution::add($value, $ids); + + // add custom field values + if (CRM_Utils_Array::value('custom', $value) && + is_array($value['custom']) + ) { + CRM_Core_BAO_CustomValueTable::store($value['custom'], 'civicrm_contribution', $contribution->id); + } + } + CRM_Core_Session::setStatus(ts("Your updates have been saved."), ts('Saved'), 'success'); + } + else { + CRM_Core_Session::setStatus(ts("No updates have been saved."), ts('Not Saved'), 'alert'); + } + } + //end of function +} + diff --git a/CRM/Contribute/Form/Task/Delete.php b/CRM/Contribute/Form/Task/Delete.php new file mode 100644 index 0000000000..fc11524515 --- /dev/null +++ b/CRM/Contribute/Form/Task/Delete.php @@ -0,0 +1,94 @@ +addDefaultButtons(ts('Delete Contributions'), 'done'); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $deletedContributions = 0; + foreach ($this->_contributionIds as $contributionId) { + if (CRM_Contribute_BAO_Contribution::deleteContribution($contributionId)) { + $deletedContributions++; + } + } + + CRM_Core_Session::setStatus(ts('Deleted Contribution(s): %1', array(1 => $deletedContributions)), '', 'info'); + CRM_Core_Session::setStatus(ts('Total Selected Contribution(s): %1', array(1 => count($this->_contributionIds))), '', 'info'); + } +} + diff --git a/CRM/Contribute/Form/Task/Email.php b/CRM/Contribute/Form/Task/Email.php new file mode 100644 index 0000000000..48f684b1e3 --- /dev/null +++ b/CRM/Contribute/Form/Task/Email.php @@ -0,0 +1,99 @@ +assign('single', $this->_single); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('emailTask', TRUE); + + CRM_Contact_Form_Task_EmailCommon::buildQuickForm($this); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + CRM_Contact_Form_Task_EmailCommon::postProcess($this); + } +} + diff --git a/CRM/Contribute/Form/Task/PDF.php b/CRM/Contribute/Form/Task/PDF.php new file mode 100644 index 0000000000..56fe36533b --- /dev/null +++ b/CRM/Contribute/Form/Task/PDF.php @@ -0,0 +1,267 @@ +_contributionIds = array($id); + $this->_componentClause = " civicrm_contribution.id IN ( $id ) "; + $this->_single = TRUE; + $this->assign('totalSelectedContributions', 1); + } + else { + parent::preProcess(); + } + + // check that all the contribution ids have pending status + $query = " +SELECT count(*) +FROM civicrm_contribution +WHERE contribution_status_id != 1 +AND {$this->_componentClause}"; + $count = CRM_Core_DAO::singleValueQuery($query); + if ($count != 0) { + CRM_Core_Error::statusBounce("Please select only online contributions with Completed status."); + } + + // we have all the contribution ids, so now we get the contact ids + parent::setContactIDs(); + $this->assign('single', $this->_single); + + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); + $urlParams = 'force=1'; + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams .= "&qfKey=$qfKey"; + } + + $url = CRM_Utils_System::url('civicrm/contribute/search', $urlParams); + $breadCrumb = array( + array('url' => $url, + 'title' => ts('Search Results'), + )); + + CRM_Utils_System::appendBreadCrumb($breadCrumb); + CRM_Utils_System::setTitle(ts('Print Contribution Receipts')); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + + $this->addElement('radio', 'output', NULL, ts('Email Receipts'), 'email_receipt', + array('onClick' => "document.getElementById('selectPdfFormat').style.display = 'none';") + ); + $this->addElement('radio', 'output', NULL, ts('PDF Receipts'), 'pdf_receipt', + array('onClick' => "document.getElementById('selectPdfFormat').style.display = 'block';") + ); + $this->addRule('output', ts('Selection required'), 'required'); + + $this->add('select', 'pdf_format_id', ts('Page Format'), + array(0 => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE) + ); + + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Process Receipt(s)'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Set default values + */ + function setDefaultValues() { + $defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues(); + return array('pdf_format_id' => $defaultFormat['id']); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + // get all the details needed to generate a receipt + $contribIDs = implode(',', $this->_contributionIds); + + $details = CRM_Contribute_Form_Task_Status::getDetails($contribIDs); + + $baseIPN = new CRM_Core_Payment_BaseIPN(); + + $message = array(); + $template = CRM_Core_Smarty::singleton(); + + $params = $this->controller->exportValues($this->_name); + + $createPdf = FALSE; + if ($params['output'] == "pdf_receipt") { + $createPdf = TRUE; + } + + $excludeContactIds = array(); + if (!$createPdf) { + $returnProperties = array( + 'email' => 1, + 'do_not_email' => 1, + 'is_deceased' => 1, + 'on_hold' => 1, + ); + + list($contactDetails) = CRM_Utils_Token::getTokenDetails($this->_contactIds, $returnProperties, FALSE, FALSE); + $suppressedEmails = 0; + foreach ($contactDetails as $id => $values) { + if (empty($values['email']) || + CRM_Utils_Array::value('do_not_email', $values) || + CRM_Utils_Array::value('is_deceased', $values) || + CRM_Utils_Array::value('on_hold', $values) + ) { + $suppressedEmails++; + $excludeContactIds[] = $values['contact_id']; + } + } + } + + foreach ($details as $contribID => $detail) { + $input = $ids = $objects = array(); + + if (in_array($detail['contact'], $excludeContactIds)) { + continue; + } + + $input['component'] = $detail['component']; + + $ids['contact'] = $detail['contact']; + $ids['contribution'] = $contribID; + $ids['contributionRecur'] = NULL; + $ids['contributionPage'] = NULL; + $ids['membership'] = CRM_Utils_Array::value('membership', $detail); + $ids['participant'] = CRM_Utils_Array::value('participant', $detail); + $ids['event'] = CRM_Utils_Array::value('event', $detail); + + if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) { + CRM_Core_Error::fatal(); + } + + $contribution = &$objects['contribution']; + // CRM_Core_Error::debug('o',$objects); + + + // set some fake input values so we can reuse IPN code + $input['amount'] = $contribution->total_amount; + $input['is_test'] = $contribution->is_test; + $input['fee_amount'] = $contribution->fee_amount; + $input['net_amount'] = $contribution->net_amount; + $input['trxn_id'] = $contribution->trxn_id; + $input['trxn_date'] = isset($contribution->trxn_date) ? $contribution->trxn_date : NULL; + + // CRM_Contribute_BAO_Contribution::composeMessageArray expects mysql formatted date + $objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date); + + // CRM_Core_Error::debug('input',$input); + + $values = array(); + $mail = $baseIPN->sendMail($input, $ids, $objects, $values, FALSE, $createPdf); + + if ($mail['html']) { + $message[] = $mail['html']; + } + else { + $message[] = nl2br($mail['body']); + } + + // reset template values before processing next transactions + $template->clearTemplateVars(); + } + if ($createPdf) { + CRM_Utils_PDF_Utils::html2pdf($message, + 'civicrmContributionReceipt.pdf', + FALSE, + $params['pdf_format_id'] + ); + CRM_Utils_System::civiExit(); + } + else { + if ($suppressedEmails) { + $status = ts('Email was NOT sent to %1 contacts (no email address on file, or communication preferences specify DO NOT EMAIL, or contact is deceased).', array(1 => $suppressedEmails)); + $msgTitle = ts('Email Error'); + $msgType = 'error'; + } + else { + $status = ts('Your mail has been sent.'); + $msgTitle = ts('Sent'); + $msgType = 'success'; + } + CRM_Core_Session::setStatus($status, $msgTitle, $msgType); + } + } +} + diff --git a/CRM/Contribute/Form/Task/PDFLetter.php b/CRM/Contribute/Form/Task/PDFLetter.php new file mode 100644 index 0000000000..785b2aa493 --- /dev/null +++ b/CRM/Contribute/Form/Task/PDFLetter.php @@ -0,0 +1,146 @@ +skipOnHold = $this->skipDeceased = FALSE; + CRM_Contact_Form_Task_PDFLetterCommon::preProcess($this); + + // store case id if present + $this->_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this, FALSE); + + // retrieve contact ID if this is 'single' mode + $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE); + + $this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE); + + if ($cid) { + CRM_Contact_Form_Task_PDFLetterCommon::preProcessSingle($this, $cid); + $this->_single = TRUE; + $this->_cid = $cid; + } + else { + parent::preProcess(); + } + $this->assign('single', $this->_single); + } + + function setDefaultValues() { + $defaults = array(); + if (isset($this->_activityId)) { + $params = array('id' => $this->_activityId); + CRM_Activity_BAO_Activity::retrieve($params, $defaults); + $defaults['html_message'] = $defaults['details']; + } + $defaults = $defaults + CRM_Contact_Form_Task_PDFLetterCommon::setDefaultValues(); + return $defaults; + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + //enable form element + $this->assign('suppressForm', FALSE); + + // use contact form as a base + CRM_Contact_Form_Task_PDFLetterCommon::buildQuickForm($this); + + // specific need for contributions + $this->add('static', 'more_options_header', NULL, ts('Record Update Options')); + $this->add('checkbox', 'receipt_update', ts('Update receipt dates for these contributions'), FALSE); + $this->add('checkbox', 'thankyou_update', ts('Update thank-you dates for these contributions'), FALSE); + //$this->add( 'checkbox', 'group_recurring_contribution', ts('Group recurring contribution (1 letter by recurring contribution for the choosen period)'), false ); + + // Group options for tokens are not yet implemented. dgg + $options = array(ts('Contact'), ts('Recurring')); + $this->addRadio('is_group_by', ts('Grouping contributions in one letter based on'), $options, array(), "
    ", FALSE); + + $this->addButtons(array( + array( + 'type' => 'submit', + 'name' => ts('Make Thank-you Letters'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Done'), + ), + ) + ); + + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + // TODO: rewrite using contribution token and one letter by contribution + $this->setContactIDs(); + + CRM_Contribute_Form_Task_PDFLetterCommon::postProcess($this); + } +} + diff --git a/CRM/Contribute/Form/Task/PDFLetterCommon.php b/CRM/Contribute/Form/Task/PDFLetterCommon.php new file mode 100644 index 0000000000..6daa42386f --- /dev/null +++ b/CRM/Contribute/Form/Task/PDFLetterCommon.php @@ -0,0 +1,115 @@ +skipOnHold) ? $form->skipOnHold : FALSE; + $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE; + + foreach ($form->getVar('_contributionIds') as $item => $contributionId) { + + // get contact information + $contactId = civicrm_api("Contribution", "getvalue", array('version' => '3', 'id' => $contributionId, 'return' => 'contact_id')); + $params = array('contact_id' => $contactId); + + list($contact) = CRM_Utils_Token::getTokenDetails($params, + $returnProperties, + $skipOnHold, + $skipDeceased, + NULL, + $messageToken, + 'CRM_Contribution_Form_Task_PDFLetterCommon' + ); + if (civicrm_error($contact)) { + $notSent[] = $contributionId; + continue; + } + + // get contribution information + $params = array('contribution_id' => $contributionId); + $contribution = CRM_Utils_Token::getContributionTokenDetails($params, + $returnProperties, + NULL, + $messageToken, + 'CRM_Contribution_Form_Task_PDFLetterCommon' + ); + if (civicrm_error($contribution)) { + $notSent[] = $contributionId; + continue; + } + + $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken); + $tokenHtml = CRM_Utils_Token::replaceContributionTokens($tokenHtml, $contribution[$contributionId], TRUE, $messageToken); + $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE); + + if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) { + $smarty = CRM_Core_Smarty::singleton(); + // also add the tokens to the template + $smarty->assign_by_ref('contact', $contact); + $tokenHtml = $smarty->fetch("string:$tokenHtml"); + } + + $html[] = $tokenHtml; + + // update dates (do it for each contribution including grouped recurring contribution) + if ($receipt_update) { + $result = CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'receipt_date', $nowDate); + // We can't use CRM_Core_Error::fatal here because the api error elevates the exception level. FIXME. dgg + if ($result) { + $receipts++; + } + } + if ($thankyou_update) { + $result = CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'thankyou_date', $nowDate); + // We can't use CRM_Core_Error::fatal here because the api error elevates the exception level. FIXME. dgg + if ($result) { + $thanks++; + } + } + } + + self::createActivities($form, $html_message, $form->_contactIds); + + CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues); + + $form->postProcessHook(); + + if ($receipts) { + $updateStatus = ts('Receipt date has been updated for %1 contributions.', array(1 => $receipts)); + } + if ($thanks) { + $updateStatus .= ' ' . ts('Thank-you date has been updated for %1 contributions.', array(1 => $thanks)); + } + + if ($updateStatus) { + CRM_Core_Session::setStatus($updateStatus); + } + + CRM_Utils_System::civiExit(1); + } + //end of function +} + diff --git a/CRM/Contribute/Form/Task/PickProfile.php b/CRM/Contribute/Form/Task/PickProfile.php new file mode 100644 index 0000000000..b3ff90608b --- /dev/null +++ b/CRM/Contribute/Form/Task/PickProfile.php @@ -0,0 +1,154 @@ +_userContext = $session->readUserContext(); + + CRM_Utils_System::setTitle(ts('Batch Update Contributions via Profile')); + + $validate = FALSE; + //validations + if (count($this->_contributionIds) > $this->_maxContributions) { + CRM_Core_Session::setStatus(ts("The maximum number of contributions you can select for Batch Update is %1. You have selected %2. Please select fewer contributions from your search results and try again.", array(1 => $this->_maxContributions, 2 => count($this->_contributionIds))), ts('Batch Update Error'), 'error'); + $validate = TRUE; + } + + // than redirect + if ($validate) { + CRM_Utils_System::redirect($this->_userContext); + } + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + function buildQuickForm() { + + $types = array('Contribution'); + $profiles = CRM_Core_BAO_UFGroup::getProfiles($types, TRUE); + + if (empty($profiles)) { + CRM_Core_Session::setStatus(ts("You will need to create a Profile containing the %1 fields you want to edit before you can use Batch Update via Profile. Navigate to Administer CiviCRM >> CiviCRM Profile to configure a Profile. Consult the online Administrator documentation for more information.", array(1 => $types[0])), 'Profile Required', 'error'); + CRM_Utils_System::redirect($this->_userContext); + } + + $ufGroupElement = $this->add('select', 'uf_group_id', ts('Select Profile'), + array( + '' => ts('- select profile -')) + $profiles, TRUE + ); + $this->addDefaultButtons(ts('Continue >>')); + } + + /** + * Add local and global form rules + * + * @access protected + * + * @return void + */ + function addRules() { + $this->addFormRule(array('CRM_Contribute_Form_Task_PickProfile', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + return TRUE; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->exportValues(); + + $this->set('ufGroupId', $params['uf_group_id']); + + // also reset the batch page so it gets new values from the db + $this->controller->resetPage('Batch'); + } + //end of function +} + diff --git a/CRM/Contribute/Form/Task/Print.php b/CRM/Contribute/Form/Task/Print.php new file mode 100644 index 0000000000..1fbaf374d7 --- /dev/null +++ b/CRM/Contribute/Form/Task/Print.php @@ -0,0 +1,108 @@ +controller->setPrint(1); + + // get the formatted params + $queryParams = $this->get('queryParams'); + + $sortID = NULL; + if ($this->get(CRM_Utils_Sort::SORT_ID)) { + $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID), + $this->get(CRM_Utils_Sort::SORT_DIRECTION) + ); + } + + $selector = new CRM_Contribute_Selector_Search($queryParams, $this->_action, $this->_componentClause); + $controller = new CRM_Core_Selector_Controller($selector, NULL, $sortID, CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::SCREEN); + $controller->setEmbedded(TRUE); + $controller->run(); + } + + /** + * Build the form - it consists of + * - displaying the QILL (query in local language) + * - displaying elements for saving the search + * + * @access public + * + * @return void + */ + function buildQuickForm() { + // + // just need to add a javacript to popup the window for printing + // + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Print Contributions'), + 'js' => array('onclick' => 'window.print()'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Done'), + ), + ) + ); + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return void + */ + public function postProcess() { + // redirect to the main search page after printing is over + } +} + diff --git a/CRM/Contribute/Form/Task/Result.php b/CRM/Contribute/Form/Task/Result.php new file mode 100644 index 0000000000..12356a1835 --- /dev/null +++ b/CRM/Contribute/Form/Task/Result.php @@ -0,0 +1,68 @@ +addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Contribute/Form/Task/SearchTaskHookSample.php b/CRM/Contribute/Form/Task/SearchTaskHookSample.php new file mode 100644 index 0000000000..98567f3d66 --- /dev/null +++ b/CRM/Contribute/Form/Task/SearchTaskHookSample.php @@ -0,0 +1,94 @@ +_contributionIds); + + $query = " + SELECT co.total_amount as amount, + co.receive_date as receive_date, + co.source as source, + ct.display_name as display_name + FROM civicrm_contribution co +INNER JOIN civicrm_contact ct ON ( co.contact_id = ct.id ) + WHERE co.id IN ( $contribIDs )"; + + $dao = CRM_Core_DAO::executeQuery($query, + CRM_Core_DAO::$_nullArray + ); + + while ($dao->fetch()) { + $rows[] = array( + 'display_name' => $dao->display_name, + 'amount' => $dao->amount, + 'source' => $dao->source, + 'receive_date' => $dao->receive_date, + ); + } + $this->assign('rows', $rows); + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'done', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } +} + diff --git a/CRM/Contribute/Form/Task/Status.php b/CRM/Contribute/Form/Task/Status.php new file mode 100644 index 0000000000..541ac15694 --- /dev/null +++ b/CRM/Contribute/Form/Task/Status.php @@ -0,0 +1,342 @@ +_contributionIds = array($id); + $this->_componentClause = " civicrm_contribution.id IN ( $id ) "; + $this->_single = TRUE; + $this->assign('totalSelectedContributions', 1); + } + else { + parent::preProcess(); + } + + // check that all the contribution ids have pending status + $query = " +SELECT count(*) +FROM civicrm_contribution +WHERE contribution_status_id != 2 +AND {$this->_componentClause}"; + $count = CRM_Core_DAO::singleValueQuery($query, + CRM_Core_DAO::$_nullArray + ); + if ($count != 0) { + CRM_Core_Error::statusBounce(ts('Please select only online contributions with Pending status.')); + } + + // we have all the contribution ids, so now we get the contact ids + parent::setContactIDs(); + $this->assign('single', $this->_single); + } + + /** + * Build the form + * + * @access public + * + * @return void + */ + public function buildQuickForm() { + $status = CRM_Contribute_PseudoConstant::contributionStatus(); + unset($status[2]); + unset($status[5]); + unset($status[6]); + $this->add('select', 'contribution_status_id', + ts('Contribution Status'), + $status, + TRUE + ); + + $contribIDs = implode(',', $this->_contributionIds); + $query = " +SELECT c.id as contact_id, + co.id as contribution_id, + c.display_name as display_name, + co.total_amount as amount, + co.receive_date as receive_date, + co.source as source, + co.payment_instrument_id as paid_by, + co.check_number as check_no +FROM civicrm_contact c, + civicrm_contribution co +WHERE co.contact_id = c.id +AND co.id IN ( $contribIDs )"; + $dao = CRM_Core_DAO::executeQuery($query, + CRM_Core_DAO::$_nullArray + ); + + // build a row for each contribution id + $this->_rows = array(); + $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution'); + $defaults = array(); + $now = date("m/d/Y"); + $paidByOptions = array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument(); + + while ($dao->fetch()) { + $row['contact_id'] = $dao->contact_id; + $row['contribution_id'] = $dao->contribution_id; + $row['display_name'] = $dao->display_name; + $row['amount'] = $dao->amount; + $row['source'] = $dao->source; + $row['trxn_id'] = &$this->addElement('text', "trxn_id_{$row['contribution_id']}", ts('Transaction ID')); + $this->addRule("trxn_id_{$row['contribution_id']}", + ts('This Transaction ID already exists in the database. Include the account number for checks.'), + 'objectExists', + array('CRM_Contribute_DAO_Contribution', $dao->contribution_id, 'trxn_id') + ); + + + $row['fee_amount'] = &$this->add('text', "fee_amount_{$row['contribution_id']}", ts('Fee Amount'), + $attributes['fee_amount'] + ); + $this->addRule("fee_amount_{$row['contribution_id']}", ts('Please enter a valid amount.'), 'money'); + $defaults["fee_amount_{$row['contribution_id']}"] = 0.0; + + $row['trxn_date'] = &$this->addDate("trxn_date_{$row['contribution_id']}", FALSE, + ts('Receipt Date'), array('formatType' => 'activityDate') + ); + $defaults["trxn_date_{$row['contribution_id']}"] = $now; + + $this->add("text", "check_number_{$row['contribution_id']}", ts('Check Number')); + $defaults["check_number_{$row['contribution_id']}"] = $dao->check_no; + + $this->add("select", "payment_instrument_id_{$row['contribution_id']}", ts('Paid By'), $paidByOptions); + $defaults["payment_instrument_id_{$row['contribution_id']}"] = $dao->paid_by; + + $this->_rows[] = $row; + } + + $this->assign_by_ref('rows', $this->_rows); + $this->setDefaults($defaults); + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Update Pending Status'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'back', + 'name' => ts('Cancel'), + ), + ) + ); + + $this->addFormRule(array('CRM_Contribute_Form_Task_Status', 'formRule')); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields) { + $seen = $errors = array(); + foreach ($fields as $name => $value) { + if (strpos($name, 'trxn_id_') !== FALSE) { + if ($fields[$name]) { + if (array_key_exists($value, $seen)) { + $errors[$name] = ts('Transaction ID\'s must be unique. Include the account number for checks.'); + } + $seen[$value] = 1; + } + } + + if ((strpos($name, 'check_number_') !== FALSE) && $value) { + $contribID = substr($name, 13); + + if ($fields["payment_instrument_id_{$contribID}"] != CRM_Core_OptionGroup::getValue('payment_instrument', 'Check', 'name')) { + $errors["payment_instrument_id_{$contribID}"] = ts("Paid By should be Check when a check number is entered for a contribution."); + } + } + } + return empty($errors) ? TRUE : $errors; + } + + /** + * process the form after the input has been submitted and validated + * + * @access public + * + * @return None + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + $statusID = CRM_Utils_Array::value('contribution_status_id', $params); + + $baseIPN = new CRM_Core_Payment_BaseIPN(); + + $transaction = new CRM_Core_Transaction(); + + // get the missing pieces for each contribution + $contribIDs = implode(',', $this->_contributionIds); + $details = self::getDetails($contribIDs); + $template = CRM_Core_Smarty::singleton(); + + // for each contribution id, we just call the baseIPN stuff + foreach ($this->_rows as $row) { + $input = $ids = $objects = array(); + $input['component'] = $details[$row['contribution_id']]['component']; + + $ids['contact'] = $row['contact_id']; + $ids['contribution'] = $row['contribution_id']; + $ids['contributionRecur'] = NULL; + $ids['contributionPage'] = NULL; + $ids['membership'] = CRM_Utils_Array::value('membership', $details[$row['contribution_id']]); + $ids['participant'] = CRM_Utils_Array::value('participant', $details[$row['contribution_id']]); + $ids['event'] = CRM_Utils_Array::value('event', $details[$row['contribution_id']]); + + if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) { + CRM_Core_Error::fatal(); + } + + $contribution = &$objects['contribution']; + + $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, + 'name' + ); + + if ($statusID == array_search('Cancelled', $contributionStatuses)) { + $baseIPN->cancelled($objects, $transaction); + $transaction->commit(); + continue; + } + elseif ($statusID == array_search('Failed', $contributionStatuses)) { + $baseIPN->failed($objects, $transaction); + $transaction->commit(); + continue; + } + + // status is not pending + if ($contribution->contribution_status_id != array_search('Pending', + $contributionStatuses + )) { + $transaction->commit(); + continue; + } + + // set some fake input values so we can reuse IPN code + $input['amount'] = $contribution->total_amount; + $input['is_test'] = $contribution->is_test; + $input['fee_amount'] = $params["fee_amount_{$row['contribution_id']}"]; + $input['check_number'] = $params["check_number_{$row['contribution_id']}"]; + $input['payment_instrument_id'] = $params["payment_instrument_id_{$row['contribution_id']}"]; + $input['net_amount'] = $contribution->total_amount - $input['fee_amount']; + + if (!empty($params["trxn_id_{$row['contribution_id']}"])) { + $input['trxn_id'] = trim($params["trxn_id_{$row['contribution_id']}"]); + } + else { + $input['trxn_id'] = $contribution->invoice_id; + } + $input['trxn_date'] = CRM_Utils_Date::processDate($params["trxn_date_{$row['contribution_id']}"]); + + $baseIPN->completeTransaction($input, $ids, $objects, $transaction, FALSE); + + // reset template values before processing next transactions + $template->clearTemplateVars(); + } + + CRM_Core_Session::setStatus(ts('Contribution status has been updated for selected record(s).'), ts('Status Updated'), 'success'); + } + + static function &getDetails($contributionIDs) { + $query = " +SELECT c.id as contribution_id, + c.contact_id as contact_id , + mp.membership_id as membership_id , + pp.participant_id as participant_id , + p.event_id as event_id +FROM civicrm_contribution c +LEFT JOIN civicrm_membership_payment mp ON mp.contribution_id = c.id +LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id +LEFT JOIN civicrm_participant p ON pp.participant_id = p.id +WHERE c.id IN ( $contributionIDs )"; + + $rows = array(); + $dao = CRM_Core_DAO::executeQuery($query, + CRM_Core_DAO::$_nullArray + ); + $rows = array(); + + while ($dao->fetch()) { + $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute'; + $rows[$dao->contribution_id]['contact'] = $dao->contact_id; + if ($dao->membership_id) { + if (!array_key_exists('membership', $rows[$dao->contribution_id])) { + $rows[$dao->contribution_id]['membership'] = array(); + } + $rows[$dao->contribution_id]['membership'][] = $dao->membership_id; + } + if ($dao->participant_id) { + $rows[$dao->contribution_id]['participant'] = $dao->participant_id; + } + if ($dao->event_id) { + $rows[$dao->contribution_id]['event'] = $dao->event_id; + } + } + return $rows; + } +} + diff --git a/CRM/Contribute/Form/UpdateBilling.php b/CRM/Contribute/Form/UpdateBilling.php new file mode 100644 index 0000000000..0053030900 --- /dev/null +++ b/CRM/Contribute/Form/UpdateBilling.php @@ -0,0 +1,442 @@ +_mid = CRM_Utils_Request::retrieve('mid', 'Integer', $this, FALSE); + $this->_crid = CRM_Utils_Request::retrieve('crid', 'Integer', $this, FALSE); + if ($this->_crid) { + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_crid, 'recur', 'info'); + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_crid, 'recur', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_crid); + + // Are we cancelling a recurring contribution that is linked to an auto-renew membership? + if ($this->_subscriptionDetails->membership_id) { + $this->_mid = $this->_subscriptionDetails->membership_id; + } + } + + $this->_coid = CRM_Utils_Request::retrieve('coid', 'Integer', $this, FALSE); + if ($this->_coid) { + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'info'); + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_coid, 'contribution'); + } + + if ($this->_mid) { + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_mid, 'membership', 'info'); + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_mid, 'membership', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_mid, 'membership'); + $membershipTypes = CRM_Member_PseudoConstant::membershipType(); + $membershipTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_mid, 'membership_type_id'); + $this->assign('membershipType', CRM_Utils_Array::value($membershipTypeId, $membershipTypes)); + $this->_mode = 'auto_renew'; + } + + if ((!$this->_crid && !$this->_coid && !$this->_mid) || + ($this->_subscriptionDetails == CRM_Core_DAO::$_nullObject) + ) { + CRM_Core_Error::fatal('Required information missing.'); + } + if (!CRM_Core_Permission::check('edit contributions')) { + $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE); + if (!CRM_Contact_BAO_Contact_Utils::validChecksum($this->_subscriptionDetails->contact_id, $userChecksum)) { + CRM_Core_Error::fatal(ts('You do not have permission to cancel subscription.')); + } + $this->_selfService = TRUE; + } + + if (!$this->_paymentProcessorObj->isSupported('updateSubscriptionBillingInfo')) { + CRM_Core_Error::fatal(ts("%1 processor doesn't support updating subscription billing details.", + array(1 => $this->_paymentProcessorObj->_processorName) + )); + } + $this->assign('paymentProcessor', $this->_paymentProcessor); + + // get the billing location type + $locationTypes = CRM_Core_PseudoConstant::locationType(); + $this->_bltID = array_search('Billing', $locationTypes); + $this->assign('bltID', $this->_bltID); + if (!$this->_bltID) { + CRM_Core_Error::fatal(ts('Please set a location type of %1', array(1 => 'Billing'))); + } + + $this->assign('frequency_unit', $this->_subscriptionDetails->frequency_unit); + $this->assign('frequency_interval', $this->_subscriptionDetails->frequency_interval); + $this->assign('amount', $this->_subscriptionDetails->amount); + $this->assign('installments', $this->_subscriptionDetails->installments); + $this->assign('mode', $this->_mode); + + // handle context redirection + CRM_Contribute_BAO_ContributionRecur::setSubscriptionContext(); + } + + function setDefaultValues() { + $this->_defaults = array(); + + if ($this->_subscriptionDetails->contact_id) { + $options = array(); + $fields = array(); + $names = array( + 'first_name', 'middle_name', 'last_name', "street_address-{$this->_bltID}", "city-{$this->_bltID}", + "postal_code-{$this->_bltID}", "country_id-{$this->_bltID}", "state_province_id-{$this->_bltID}", + ); + foreach ($names as $name) { + $fields[$name] = 1; + } + $fields["state_province-{$this->_bltID}"] = 1; + $fields["country-{$this->_bltID}"] = 1; + $fields["email-{$this->_bltID}"] = 1; + $fields['email-Primary'] = 1; + + CRM_Core_BAO_UFGroup::setProfileDefaults($this->_subscriptionDetails->contact_id, $fields, $this->_defaults); + + // use primary email address if billing email address is empty + if (empty($this->_defaults["email-{$this->_bltID}"]) && + !empty($this->_defaults['email-Primary']) + ) { + $this->_defaults["email-{$this->_bltID}"] = $this->_defaults['email-Primary']; + } + + foreach ($names as $name) { + if (!empty($this->_defaults[$name])) { + $this->_defaults['billing_' . $name] = $this->_defaults[$name]; + } + } + } + + + $config = CRM_Core_Config::singleton(); + // set default country from config if no country set + if (!CRM_Utils_Array::value("billing_country_id-{$this->_bltID}", $this->_defaults)) { + $this->_defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry; + } + + // now fix all state country selectors + CRM_Core_BAO_Address::fixAllStateSelects($this, $this->_defaults); + + return $this->_defaults; + } + + /** + * Function to build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $type = 'next'; + if ( $this->_selfService ) { + $type = 'submit'; + } + + $this->addButtons(array( + array( + 'type' => $type, + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + + CRM_Core_Payment_Form::buildCreditCard($this); + $this->addFormRule(array('CRM_Contribute_Form_UpdateBilling', 'formRule'), $this); + } + + /** + * global form rule + * + * @param array $fields the input form values + * @param array $files the uploaded files if any + * @param array $options additional user data + * + * @return true if no errors, else array of errors + * @access public + * @static + */ + static function formRule($fields, $files, $self) { + foreach ($self->_fields as $name => $fld) { + if ($fld['is_required'] && + CRM_Utils_System::isNull(CRM_Utils_Array::value($name, $fields)) + ) { + $errors[$name] = ts('%1 is a required field.', array(1 => $fld['title'])); + } + } + + // make sure that credit card number and cvv are valid + if (CRM_Utils_Array::value('credit_card_type', $fields)) { + if (CRM_Utils_Array::value('credit_card_number', $fields) && + !CRM_Utils_Rule::creditCardNumber($fields['credit_card_number'], $fields['credit_card_type']) + ) { + $errors['credit_card_number'] = ts('Please enter a valid Credit Card Number'); + } + + if (CRM_Utils_Array::value('cvv2', $fields) && + !CRM_Utils_Rule::cvv($fields['cvv2'], $fields['credit_card_type']) + ) { + $errors['cvv2'] = ts('Please enter a valid Credit Card Verification Number'); + } + } + return empty($errors) ? TRUE : $errors; + } + + /** + * Process the form + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->controller->exportValues($this->_name); + $status = NULL; + + // now set the values for the billing location. + foreach ($this->_fields as $name => $value) { + $fields[$name] = 1; + } + $fields["email-{$this->_bltID}"] = 1; + + $processorParams = array(); + foreach ($params as $key => $val) { + $key = str_replace('billing_', '', $key); + list($key) = explode('-', $key); + $processorParams[$key] = $val; + } + $processorParams['state_province'] = CRM_Core_PseudoConstant::stateProvince($params["billing_state_province_id-{$this->_bltID}"], FALSE); + $processorParams['country'] = CRM_Core_PseudoConstant::country($params["billing_country_id-{$this->_bltID}"], FALSE); + $processorParams['month'] = $processorParams['credit_card_exp_date']['M']; + $processorParams['year'] = $processorParams['credit_card_exp_date']['Y']; + $processorParams['subscriptionId'] = $this->_subscriptionDetails->subscription_id; + $processorParams['amount'] = $this->_subscriptionDetails->amount; + + $updateSubscription = $this->_paymentProcessorObj->updateSubscriptionBillingInfo($message, $processorParams); + + if (is_a($updateSubscription, 'CRM_Core_Error')) { + CRM_Core_Error::displaySessionError($updateSubscription); + } + elseif ($updateSubscription) { + $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_subscriptionDetails->contact_id, 'contact_type'); + $contact = &CRM_Contact_BAO_Contact::createProfileContact($params, + $fields, + $this->_subscriptionDetails->contact_id, + NULL, + NULL, + $ctype + ); + + // build tpl params + if ($this->_subscriptionDetails->membership_id) { + $inputParams = array('id' => $this->_subscriptionDetails->membership_id); + CRM_Member_BAO_Membership::getValues($inputParams, $tplParams); + $tplParams = $tplParams[$this->_subscriptionDetails->membership_id]; + $tplParams['membership_status'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', $tplParams['status_id']); + $tplParams['membershipType'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $tplParams['membership_type_id']); + $status = ts('Billing details for your automatically renewed %1 membership have been updated.', + array(1 => $tplParams['membershipType']) + ); + $msgTitle = ts('Details Updated'); + $msgType = 'success'; + } + else { + $status = ts('Billing details for the recurring contribution of %1, every %2 %3 have been updated.', + array( + 1 => $this->_subscriptionDetails->amount, + 2 => $this->_subscriptionDetails->frequency_interval, + 3 => $this->_subscriptionDetails->frequency_unit + ) + ); + $msgTitle = ts('Details Updated'); + $msgType = 'success'; + + $tplParams = array( + 'recur_frequency_interval' => $this->_subscriptionDetails->frequency_interval, + 'recur_frequency_unit' => $this->_subscriptionDetails->frequency_unit, + 'amount' => $this->_subscriptionDetails->amount, + ); + } + + // format new address for display + $addressParts = array("street_address", "city", "postal_code", "state_province", "country"); + foreach ($addressParts as $part) { + $addressParts[$part] = CRM_Utils_Array::value($part, $processorParams); + } + $tplParams['address'] = CRM_Utils_Address::format($addressParts); + + // format old address to store in activity details + $this->_defaults["state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvince($this->_defaults["state_province-{$this->_bltID}"], FALSE); + $this->_defaults["country-{$this->_bltID}"] = CRM_Core_PseudoConstant::country($this->_defaults["country-{$this->_bltID}"], FALSE); + $addressParts = array("street_address", "city", "postal_code", "state_province", "country"); + foreach ($addressParts as $part) { + $key = "{$part}-{$this->_bltID}"; + $addressParts[$part] = CRM_Utils_Array::value($key, $this->_defaults); + } + $this->_defaults['address'] = CRM_Utils_Address::format($addressParts); + + // format new billing name + $name = $processorParams['first_name']; + if (CRM_Utils_Array::value('middle_name', $processorParams)) { + $name .= " {$processorParams['middle_name']}"; + } + $name .= ' ' . $processorParams['last_name']; + $name = trim($name); + $tplParams['billingName'] = $name; + + // format old billing name + $name = $this->_defaults['first_name']; + if (CRM_Utils_Array::value('middle_name', $this->_defaults)) { + $name .= " {$this->_defaults['middle_name']}"; + } + $name .= ' ' . $this->_defaults['last_name']; + $name = trim($name); + $this->_defaults['billingName'] = $name; + + $message .= " +

    New Billing Name and Address +
    ============================== +
    {$tplParams['billingName']} +
    {$tplParams['address']} + +

    Previous Billing Name and Address +
    ================================== +
    {$this->_defaults['billingName']} +
    {$this->_defaults['address']}"; + + $activityParams = array( + 'source_contact_id' => $this->_subscriptionDetails->contact_id, + 'activity_type_id' => CRM_Core_OptionGroup::getValue('activity_type', + 'Update Recurring Contribution Billing Details', + 'name' + ), + 'subject' => ts('Recurring Contribution Billing Details Updated'), + 'details' => $message, + 'activity_date_time' => date('YmdHis'), + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + 'Completed', + 'name' + ), + ); + $session = CRM_Core_Session::singleton(); + $cid = $session->get('userID'); + if ($cid) { + $activityParams['target_contact_id'][] = $activityParams['source_contact_id']; + $activityParams['source_contact_id'] = $cid; + } + CRM_Activity_BAO_Activity::create($activityParams); + + // send notification + if ($this->_subscriptionDetails->contribution_page_id) { + CRM_Core_DAO::commonRetrieveAll('CRM_Contribute_DAO_ContributionPage', 'id', + $this->_subscriptionDetails->contribution_page_id, $value, array( + 'title', + 'receipt_from_name', + 'receipt_from_email', + ) + ); + $receiptFrom = '"' . CRM_Utils_Array::value('receipt_from_name', $value[$this->_subscriptionDetails->contribution_page_id]) . '" <' . $value[$this->_subscriptionDetails->contribution_page_id]['receipt_from_email'] . '>'; + } + else { + $domainValues = CRM_Core_BAO_Domain::getNameAndEmail(); + $receiptFrom = "$domainValues[0] <$domainValues[1]>"; + } + list($donorDisplayName, $donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($this->_subscriptionDetails->contact_id); + $tplParams['contact'] = array('display_name' => $donorDisplayName); + + $date = CRM_Utils_Date::format($processorParams['credit_card_exp_date']); + $tplParams['credit_card_exp_date'] = CRM_Utils_Date::mysqlToIso($date); + $tplParams['credit_card_number'] = CRM_Utils_System::mungeCreditCard($processorParams['credit_card_number']); + $tplParams['credit_card_type'] = $processorParams['credit_card_type']; + + $sendTemplateParams = array( + 'groupName' => $this->_subscriptionDetails->membership_id ? 'msg_tpl_workflow_membership' : 'msg_tpl_workflow_contribution', + 'valueName' => $this->_subscriptionDetails->membership_id ? 'membership_autorenew_billing' : 'contribution_recurring_billing', + 'contactId' => $this->_subscriptionDetails->contact_id, + 'tplParams' => $tplParams, + 'isTest' => $this->_subscriptionDetails->is_test, + 'PDFFilename' => 'receipt.pdf', + 'from' => $receiptFrom, + 'toName' => $donorDisplayName, + 'toEmail' => $donorEmail, + ); + list($sent) = CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + } + else { + $status = ts('There was some problem updating the billing details.'); + $msgTitle = ts('Update Error'); + $msgType = 'error'; + } + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + if ( $userID && $status) { + $session->setStatus($status, $msgTitle, $msgType); + } else if (!$userID) { + if ($status) + CRM_Utils_System::setUFMessage($status); + $result = (int) ($updateSubscription && isset($ctype)); + if (isset($tplParams)) + $session->set('resultParams', $tplParams); + return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/subscriptionstatus', + "reset=1&task=billing&result={$result}")); + } + } +} + diff --git a/CRM/Contribute/Form/UpdateSubscription.php b/CRM/Contribute/Form/UpdateSubscription.php new file mode 100644 index 0000000000..a0e51e90d8 --- /dev/null +++ b/CRM/Contribute/Form/UpdateSubscription.php @@ -0,0 +1,322 @@ +_crid = CRM_Utils_Request::retrieve('crid', 'Integer', $this, FALSE); + if ($this->_crid) { + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_crid, 'recur', 'info'); + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_crid, 'recur', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_crid); + } + + $this->_coid = CRM_Utils_Request::retrieve('coid', 'Integer', $this, FALSE); + if ($this->_coid) { + $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'info'); + $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'obj'); + $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_coid, 'contribution'); + } + + if ((!$this->_crid && !$this->_coid) || + ($this->_subscriptionDetails == CRM_Core_DAO::$_nullObject) + ) { + CRM_Core_Error::fatal('Required information missing.'); + } + + if ($this->_subscriptionDetails->membership_id && $this->_subscriptionDetails->auto_renew) { + CRM_Core_Error::fatal(ts('You cannot update the subscription.')); + } + + if (!CRM_Core_Permission::check('edit contributions')) { + $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE); + if (!CRM_Contact_BAO_Contact_Utils::validChecksum($this->_subscriptionDetails->contact_id, $userChecksum)) { + CRM_Core_Error::fatal(ts('You do not have permission to update subscription.')); + } + $this->_selfService = TRUE; + } + $this->assign('self_service', $this->_selfService); + + if (!$this->_paymentProcessorObj->isSupported('changeSubscriptionAmount')) { + $userAlert = "" . ts('Updates made using this form will change the recurring contribution information stored in your CiviCRM database, but will NOT be sent to the payment processor. You must enter the same changes using the payment processor web site.', + array( 1 => $this->_paymentProcessorObj->_processorName ) ) . ''; + CRM_Core_Session::setStatus($userAlert, ts('Warning'), 'alert'); + } + + $this->assign('isChangeSupported', $this->_paymentProcessorObj->isSupported('changeSubscriptionAmount')); + $this->assign('paymentProcessor', $this->_paymentProcessor); + $this->assign('frequency_unit', $this->_subscriptionDetails->frequency_unit); + $this->assign('frequency_interval', $this->_subscriptionDetails->frequency_interval); + + if ($this->_subscriptionDetails->contact_id) { + list($this->_donorDisplayName, $this->_donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($this->_subscriptionDetails->contact_id); + } + + CRM_Utils_System::setTitle(ts('Update Recurring Contribution')); + + // handle context redirection + CRM_Contribute_BAO_ContributionRecur::setSubscriptionContext(); + } + + /** + * This function sets the default values for the form. Note that in edit/view mode + * the default values are retrieved from the database + * + * @access public + * + * @return None + */ + function setDefaultValues() { + + $this->_defaults = array(); + $this->_defaults['amount'] = $this->_subscriptionDetails->amount; + $this->_defaults['installments'] = $this->_subscriptionDetails->installments; + $this->_defaults['is_notify'] = 1; + + return $this->_defaults; + } + + /** + * Function to actually build the components of the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + // define the fields + $this->addMoney('amount', ts('Recurring Contribution Amount'), TRUE, + array( + 'size' => 20), TRUE, + 'currency', NULL, TRUE + ); + + $this->add('text', 'installments', ts('Number of Installments'), array('size' => 20), TRUE); + + if ($this->_donorEmail) { + $this->add('checkbox', 'is_notify', ts('Notify Contributor?')); + } + + $type = 'next'; + if ( $this->_selfService ) { + $type = 'submit'; + } + + // define the buttons + $this->addButtons(array( + array( + 'type' => $type, + 'name' => ts('Save'), + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * This function is called after the user submits the form + * + * @access public + * + * @return None + */ + public function postProcess() { + // store the submitted values in an array + $params = $this->exportValues(); + + if ($this->_selfService && $this->_donorEmail) { + // for self service force notify + $params['is_notify'] = 1; + } + + // if this is an update of an existing recurring contribution, pass the ID + $params['id'] = $this->_subscriptionDetails->recur_id; + $message = ''; + + $params['subscriptionId'] = $this->_subscriptionDetails->subscription_id; + $updateSubscription = true; + if ($this->_paymentProcessorObj->isSupported('changeSubscriptionAmount')) { + $updateSubscription = $this->_paymentProcessorObj->changeSubscriptionAmount($message, $params); + } + if (is_a($updateSubscription, 'CRM_Core_Error')) { + CRM_Core_Error::displaySessionError($updateSubscription); + $status = ts('Could not update the Recurring contribution details'); + $msgTitle = ts('Update Error'); + $msgType = 'error'; + } + elseif ($updateSubscription) { + // save the changes + $result = CRM_Contribute_BAO_ContributionRecur::add($params); + $status = ts('Recurring contribution has been updated to: %1, every %2 %3(s) for %4 installments.', + array(1 => CRM_Utils_Money::format($params['amount'], $this->_subscriptionDetails->currency), + 2 => $this->_subscriptionDetails->frequency_interval, + 3 => $this->_subscriptionDetails->frequency_unit, + 4 => $params['installments'] + ) + ); + + $msgTitle = ts('Update Success'); + $msgType = 'success'; + + $contactID = $this->_subscriptionDetails->contact_id; + + if ($this->_subscriptionDetails->amount != $params['amount']) { + $message .= "
    " . ts("Recurring contribution amount has been updated from %1 to %2 for this subscription.", + array( + 1 => CRM_Utils_Money::format($this->_subscriptionDetails->amount, $this->_subscriptionDetails->currency), + 2 => CRM_Utils_Money::format($params['amount'], $this->_subscriptionDetails->currency) + )) . ' '; + } + + if ($this->_subscriptionDetails->installments != $params['installments']) { + $message .= "
    " . ts("Recurring contribution installments have been updated from %1 to %2 for this subscription.", array(1 => $this->_subscriptionDetails->installments, 2 => $params['installments'])) . ' '; + } + + $activityParams = array( + 'source_contact_id' => $contactID, + 'activity_type_id' => CRM_Core_OptionGroup::getValue('activity_type', + 'Update Recurring Contribution', + 'name' + ), + 'subject' => ts('Recurring Contribution Updated'), + 'details' => $message, + 'activity_date_time' => date('YmdHis'), + 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', + 'Completed', + 'name' + ), + ); + $session = CRM_Core_Session::singleton(); + $cid = $session->get('userID'); + + if ($cid) { + $activityParams['target_contact_id'][] = $activityParams['source_contact_id']; + $activityParams['source_contact_id'] = $cid; + } + CRM_Activity_BAO_Activity::create($activityParams); + + if (CRM_Utils_Array::value('is_notify', $params)) { + // send notification + if ($this->_subscriptionDetails->contribution_page_id) { + CRM_Core_DAO::commonRetrieveAll('CRM_Contribute_DAO_ContributionPage', 'id', + $this->_subscriptionDetails->contribution_page_id, $value, array( + 'title', + 'receipt_from_name', + 'receipt_from_email', + ) + ); + $receiptFrom = '"' . CRM_Utils_Array::value('receipt_from_name', $value[$this->_subscriptionDetails->contribution_page_id]) . '" <' . $value[$this->_subscriptionDetails->contribution_page_id]['receipt_from_email'] . '>'; + } + else { + $domainValues = CRM_Core_BAO_Domain::getNameAndEmail(); + $receiptFrom = "$domainValues[0] <$domainValues[1]>"; + } + + list($donorDisplayName, $donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($contactID); + + $tplParams = array( + 'recur_frequency_interval' => $this->_subscriptionDetails->frequency_interval, + 'recur_frequency_unit' => $this->_subscriptionDetails->frequency_unit, + 'amount' => CRM_Utils_Money::format($params['amount']), + 'installments' => $params['installments'], + ); + + $tplParams['contact'] = array('display_name' => $donorDisplayName); + $tplParams['receipt_from_email'] = $receiptFrom; + + $sendTemplateParams = array( + 'groupName' => 'msg_tpl_workflow_contribution', + 'valueName' => 'contribution_recurring_edit', + 'contactId' => $contactID, + 'tplParams' => $tplParams, + 'isTest' => $this->_subscriptionDetails->is_test, + 'PDFFilename' => 'receipt.pdf', + 'from' => $receiptFrom, + 'toName' => $donorDisplayName, + 'toEmail' => $donorEmail, + ); + list($sent) = CRM_Core_BAO_MessageTemplates::sendTemplate($sendTemplateParams); + } + } + + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + if ( $userID && $status) { + CRM_Core_Session::setStatus($status, $msgTitle, $msgType); + } else if (!$userID) { + if ($status) + CRM_Utils_System::setUFMessage($status); + // keep result as 1, since we not displaying anything on the redirected page anyway + return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/subscriptionstatus', + "reset=1&task=update&result=1")); + } + } +} + diff --git a/CRM/Contribute/Import/Controller.php b/CRM/Contribute/Import/Controller.php new file mode 100644 index 0000000000..d98ad15bc2 --- /dev/null +++ b/CRM/Contribute/Import/Controller.php @@ -0,0 +1,58 @@ +_stateMachine = new CRM_Contribute_Import_StateMachine($this, $action); + + // create and instantiate the pages + $this->addPages($this->_stateMachine, $action); + + // add all the actions + $config = CRM_Core_Config::singleton(); + $this->addActions($config->uploadDir, array('uploadFile')); + } +} + diff --git a/CRM/Contribute/Import/Field.php b/CRM/Contribute/Import/Field.php new file mode 100644 index 0000000000..745ba58dee --- /dev/null +++ b/CRM/Contribute/Import/Field.php @@ -0,0 +1,202 @@ +_name = $name; + $this->_title = $title; + $this->_type = $type; + $this->_headerPattern = $headerPattern; + $this->_dataPattern = $dataPattern; + $this->_softCreditField = $softCreditField; + $this->_value = NULL; + } + + function resetValue() { + $this->_value = NULL; + } + + /** + * the value is in string format. convert the value to the type of this field + * and set the field value with the appropriate type + */ + function setValue($value) { + $this->_value = $value; + } + + function validate() { + + if (CRM_Utils_System::isNull($this->_value)) { + return TRUE; + } + + switch ($this->_name) { + case 'contact_id': + // note: we validate extistence of the contact in API, upon + // insert (it would be too costlty to do a db call here) + return CRM_Utils_Rule::integer($this->_value); + + case 'receive_date': + case 'cancel_date': + case 'receipt_date': + case 'thankyou_date': + return CRM_Utils_Rule::date($this->_value); + + case 'non_deductible_amount': + case 'total_amount': + case 'fee_amount': + case 'net_amount': + return CRM_Utils_Rule::money($this->_value); + + case 'trxn_id': + static $seenTrxnIds = array(); + if (in_array($this->_value, $seenTrxnIds)) { + return FALSE; + } + elseif ($this->_value) { + $seenTrxnIds[] = $this->_value; + return TRUE; + } + else { + $this->_value = NULL; + return TRUE; + } + break; + + case 'currency': + return CRM_Utils_Rule::currencyCode($this->_value); + + case 'financial_type': + static $contributionTypes = NULL; + if (!$contributionTypes) { + $contributionTypes = CRM_Contribute_PseudoConstant::financialType(); + } + if (in_array($this->_value, $contributionTypes)) { + return TRUE; + } + else { + return FALSE; + } + break; + + case 'payment_instrument': + static $paymentInstruments = NULL; + if (!$paymentInstruments) { + $paymentInstruments = CRM_Contribute_PseudoConstant::paymentInstrument(); + } + if (in_array($this->_value, $paymentInstruments)) { + return TRUE; + } + else { + return FALSE; + } + break; + + default: + break; + } + + // check whether that's a valid custom field id + // and if so, check the contents' validity + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($this->_name)) { + static $customFields = NULL; + if (!$customFields) { + $customFields = CRM_Core_BAO_CustomField::getFields('Contribution'); + } + if (!array_key_exists($customFieldID, $customFields)) { + return FALSE; + } + return CRM_Core_BAO_CustomValue::typecheck($customFields[$customFieldID]['data_type'], $this->_value); + } + + return TRUE; + } +} + diff --git a/CRM/Contribute/Import/Form/MapField.php b/CRM/Contribute/Import/Form/MapField.php new file mode 100644 index 0000000000..7aaca3f379 --- /dev/null +++ b/CRM/Contribute/Import/Form/MapField.php @@ -0,0 +1,679 @@ + $re) { + // Skip empty key/patterns + if (!$key || !$re || strlen("$re") < 5) { + continue; + } + + // Scan through the headerPatterns defined in the schema for a match + if (preg_match($re, $header)) { + $this->_fieldUsed[$key] = TRUE; + return $key; + } + } + return ''; + } + + /** + * Guess at the field names given the data and patterns from the schema + * + * @param patterns + * @param index + * + * @return string + * @access public + */ + public function defaultFromData(&$patterns, $index) { + $best = ''; + $bestHits = 0; + $n = count($this->_dataValues); + + foreach ($patterns as $key => $re) { + // Skip empty key/patterns + if (!$key || !$re || strlen("$re") < 5) { + continue; + } + + /* Take a vote over the preview data set */ + + $hits = 0; + for ($i = 0; $i < $n; $i++) { + if (preg_match($re, $this->_dataValues[$i][$index])) { + $hits++; + } + } + + if ($hits > $bestHits) { + $bestHits = $hits; + $best = $key; + } + } + + if ($best != '') { + $this->_fieldUsed[$best] = TRUE; + } + return $best; + } + + /** + * Function to set variables up before form is built + * + * @return void + * @access public + */ + public function preProcess() { + $this->_mapperFields = $this->get('fields'); + asort($this->_mapperFields); + + $this->_columnCount = $this->get('columnCount'); + $this->assign('columnCount', $this->_columnCount); + $this->_dataValues = $this->get('dataValues'); + $this->assign('dataValues', $this->_dataValues); + + $skipColumnHeader = $this->controller->exportValue('UploadFile', 'skipColumnHeader'); + $this->_onDuplicate = $this->get('onDuplicate', isset($onDuplicate) ? $onDuplicate : ""); + + if ($skipColumnHeader) { + $this->assign('skipColumnHeader', $skipColumnHeader); + $this->assign('rowDisplayCount', 3); + /* if we had a column header to skip, stash it for later */ + + $this->_columnHeaders = $this->_dataValues[0]; + } + else { + $this->assign('rowDisplayCount', 2); + } + $highlightedFields = array(); + $highlightedFields[] = 'financial_type'; + //CRM-2219 removing other required fields since for updation only + //invoice id or trxn id or contribution id is required. + if ($this->_onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_UPDATE) { + $remove = array('contribution_contact_id', 'email', 'first_name', 'last_name', 'external_identifier'); + foreach ($remove as $value) { + unset($this->_mapperFields[$value]); + } + + //modify field title only for update mode. CRM-3245 + foreach (array( + 'contribution_id', 'invoice_id', 'trxn_id') as $key) { + $this->_mapperFields[$key] .= ' (match to contribution record)'; + $highlightedFields[] = $key; + } + } + elseif ($this->_onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_SKIP) { + unset($this->_mapperFields['contribution_id']); + $highlightedFieldsArray = array('contribution_contact_id', 'email', 'first_name', 'last_name', 'external_identifier', 'total_amount'); + foreach ($highlightedFieldsArray as $name) { + $highlightedFields[] = $name; + } + } + + // modify field title for contribution status + $this->_mapperFields['contribution_status_id'] = ts('Contribution Status'); + + $this->assign('highlightedFields', $highlightedFields); + } + + /** + * Function to actually build the form + * + * @return void + * @access public + */ + public function buildQuickForm() { + //to save the current mappings + if (!$this->get('savedMapping')) { + $saveDetailsName = ts('Save this field mapping'); + $this->applyFilter('saveMappingName', 'trim'); + $this->add('text', 'saveMappingName', ts('Name')); + $this->add('text', 'saveMappingDesc', ts('Description')); + } + else { + $savedMapping = $this->get('savedMapping'); + + list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingRelation) = CRM_Core_BAO_Mapping::getMappingFields($savedMapping); + + $mappingName = $mappingName[1]; + $mappingContactType = $mappingContactType[1]; + $mappingLocation = CRM_Utils_Array::value('1', CRM_Utils_Array::value(1, $mappingLocation)); + $mappingPhoneType = CRM_Utils_Array::value('1', CRM_Utils_Array::value(1, $mappingPhoneType)); + $mappingRelation = CRM_Utils_Array::value('1', CRM_Utils_Array::value(1, $mappingRelation)); + + //mapping is to be loaded from database + + $params = array('id' => $savedMapping); + $temp = array(); + $mappingDetails = CRM_Core_BAO_Mapping::retrieve($params, $temp); + + $this->assign('loadedMapping', $mappingDetails->name); + $this->set('loadedMapping', $savedMapping); + + $getMappingName = new CRM_Core_DAO_Mapping(); + $getMappingName->id = $savedMapping; + $getMappingName->mapping_type = 'Import Contributions'; + $getMappingName->find(); + while ($getMappingName->fetch()) { + $mapperName = $getMappingName->name; + } + + $this->assign('savedName', $mapperName); + + $this->add('hidden', 'mappingId', $savedMapping); + + $this->addElement('checkbox', 'updateMapping', ts('Update this field mapping'), NULL); + $saveDetailsName = ts('Save as a new field mapping'); + $this->add('text', 'saveMappingName', ts('Name')); + $this->add('text', 'saveMappingDesc', ts('Description')); + } + + $this->addElement('checkbox', 'saveMapping', $saveDetailsName, NULL, array('onclick' => "showSaveDetails(this)")); + + $this->addFormRule(array('CRM_Contribute_Import_Form_MapField', 'formRule'), $this); + + //-------- end of saved mapping stuff --------- + + $defaults = array(); + $mapperKeys = array_keys($this->_mapperFields); + $hasHeaders = !empty($this->_columnHeaders); + $headerPatterns = $this->get('headerPatterns'); + $dataPatterns = $this->get('dataPatterns'); + $hasLocationTypes = $this->get('fieldTypes'); + + + /* Initialize all field usages to false */ + + foreach ($mapperKeys as $key) { + $this->_fieldUsed[$key] = FALSE; + } + $this->_location_types = CRM_Core_PseudoConstant::locationType(); + $sel1 = $this->_mapperFields; + + if (!$this->get('onDuplicate')) { + unset($sel1['id']); + unset($sel1['contribution_id']); + } + + // start of soft credit section + // get contact type for this import + $contactTypeId = $this->get('contactType'); + $contactTypes = array( + CRM_Contribute_Import_Parser::CONTACT_INDIVIDUAL => 'Individual', + CRM_Contribute_Import_Parser::CONTACT_HOUSEHOLD => 'Household', + CRM_Contribute_Import_Parser::CONTACT_ORGANIZATION => 'Organization', + ); + + $contactType = $contactTypes[$contactTypeId]; + + // get imporatable fields for contact type + $contactFields = CRM_Contact_BAO_Contact::importableFields($contactType, NULL); + + // get the Dedupe rule for this contact type and build soft credit array + $ruleParams = array( + 'contact_type' => $contactType, + 'used' => 'Unsupervised', + ); + $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); + $softCreditFields = array(); + if (is_array($fieldsArray)) { + foreach ($fieldsArray as $value) { + //skip if there is no dupe rule + if ($value == 'none') { + continue; + } + $softCreditFields[$value] = $contactFields[trim($value)]['title']; + } + } + + $softCreditFields['contact_id'] = ts('Contact ID'); + $softCreditFields['external_identifier'] = ts('External Identifier'); + + $sel2['soft_credit'] = $softCreditFields; + + // end of soft credit section + + $js = "\n"; + $this->assign('initHideBoxes', $js); + + //set warning if mismatch in more than + if (isset($mappingName)) { + if (($this->_columnCount != count($mappingName))) { + $warning++; + } + } + if ($warning != 0 && $this->get('savedMapping')) { + $session = CRM_Core_Session::singleton(); + $session->setStatus(ts('The data columns in this import file appear to be different from the saved mapping. Please verify that you have selected the correct saved mapping before continuing.')); + } + else { + $session = CRM_Core_Session::singleton(); + $session->setStatus(NULL); + } + + $this->setDefaults($defaults); + + $this->addButtons(array( + array( + 'type' => 'back', + 'name' => ts('<< Previous'), + ), + array( + 'type' => 'next', + 'name' => ts('Continue >>'), + 'spacing' => '          ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * global validation rules for the form + * + * @param array $fields posted values of the form + * + * @return array list of errors to be posted back to the form + * @static + * @access public + */ + static function formRule($fields, $files, $self) { + $errors = array(); + $fieldMessage = NULL; + + if (!array_key_exists('savedMapping', $fields)) { + $importKeys = array(); + foreach ($fields['mapper'] as $mapperPart) { + $importKeys[] = $mapperPart[0]; + } + + $contactTypeId = $self->get('contactType'); + $contactTypes = array( + CRM_Contribute_Import_Parser::CONTACT_INDIVIDUAL => 'Individual', + CRM_Contribute_Import_Parser::CONTACT_HOUSEHOLD => 'Household', + CRM_Contribute_Import_Parser::CONTACT_ORGANIZATION => 'Organization', + ); + $params = array( + 'used' => 'Unsupervised', + 'contact_type' => $contactTypes[$contactTypeId], + ); + list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); + $weightSum = 0; + foreach ($importKeys as $key => $val) { + if (array_key_exists($val, $ruleFields)) { + $weightSum += $ruleFields[$val]; + } + } + foreach ($ruleFields as $field => $weight) { + $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; + } + + // FIXME: should use the schema titles, not redeclare them + $requiredFields = array( + 'contribution_contact_id' => ts('Contact ID'), + 'total_amount' => ts('Total Amount'), + 'financial_type' => ts('Financial Type') + ); + + foreach ($requiredFields as $field => $title) { + if (!in_array($field, $importKeys)) { + if ($field == 'contribution_contact_id') { + if (!($weightSum >= $threshold || in_array('external_identifier', $importKeys)) && + $self->_onDuplicate != CRM_Contribute_Import_Parser::DUPLICATE_UPDATE + ) { + $errors['_qf_default'] .= ts('Missing required contact matching fields.') . " $fieldMessage " . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array( + 1 => $threshold)) . '
    '; + } + elseif ($self->_onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_UPDATE && + !(in_array('invoice_id', $importKeys) || in_array('trxn_id', $importKeys) || + in_array('contribution_id', $importKeys) + ) + ) { + $errors['_qf_default'] .= ts('Invoice ID or Transaction ID or Contribution ID are required to match to the existing contribution records in Update mode.') . '
    '; + } + } + else { + if ($self->_onDuplicate != CRM_Contribute_Import_Parser::DUPLICATE_UPDATE) { + $errors['_qf_default'] .= ts('Missing required field: %1', array( + 1 => $title)) . '
    '; + } + } + } + } + + //at least one field should be mapped during update. + if ($self->_onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_UPDATE) { + $atleastOne = FALSE; + foreach ($self->_mapperFields as $key => $field) { + if (in_array($key, $importKeys) && + !in_array($key, array('doNotImport', 'contribution_id', 'invoice_id', 'trxn_id')) + ) { + $atleastOne = TRUE; + break; + } + } + if (!$atleastOne) { + $errors['_qf_default'] .= ts('At least one contribution field needs to be mapped for update during update mode.') . '
    '; + } + } + } + + if (CRM_Utils_Array::value('saveMapping', $fields)) { + $nameField = CRM_Utils_Array::value('saveMappingName', $fields); + if (empty($nameField)) { + $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); + } + else { + $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Contribution', 'name'); + if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { + $errors['saveMappingName'] = ts('Duplicate Import Contribution Mapping Name'); + } + } + } + + if (!empty($errors)) { + if (!empty($errors['saveMappingName'])) { + $_flag = 1; + $assignError = new CRM_Core_Page(); + $assignError->assign('mappingDetailsError', $_flag); + } + return $errors; + } + + return TRUE; + } + + /** + * Process the mapped fields and map it into the uploaded file + * preview the file and extract some summary statistics + * + * @return void + * @access public + */ + public function postProcess() { + $params = $this->controller->exportValues('MapField'); + + //reload the mapfield if load mapping is pressed + if (!empty($params['savedMapping'])) { + $this->set('savedMapping', $params['savedMapping']); + $this->controller->resetPage($this->_name); + return; + } + + $fileName = $this->controller->exportValue('UploadFile', 'uploadFile'); + $skipColumnHeader = $this->controller->exportValue('UploadFile', 'skipColumnHeader'); + + $config = CRM_Core_Config::singleton(); + $seperator = $config->fieldSeparator; + + $mapper = $mapperKeys = $mapperKeysMain = $mapperSoftCredit = $softCreditFields = $mapperPhoneType = array(); + $mapperKeys = $this->controller->exportValue($this->_name, 'mapper'); + + for ($i = 0; $i < $this->_columnCount; $i++) { + $mapper[$i] = $this->_mapperFields[$mapperKeys[$i][0]]; + $mapperKeysMain[$i] = $mapperKeys[$i][0]; + + if (isset($mapperKeys[$i][0]) && $mapperKeys[$i][0] == 'soft_credit') { + $mapperSoftCredit[$i] = $mapperKeys[$i][1]; + list($first, $second) = explode('_', $mapperSoftCredit[$i]); + $softCreditFields[$i] = ucwords($first . " " . $second); + } + else { + $mapperSoftCredit[$i] = $softCreditFields[$i] = NULL; + $softCreditFields[$i] = NULL; + } + } + + $this->set('mapper', $mapper); + $this->set('softCreditFields', $softCreditFields); + + // store mapping Id to display it in the preview page + $this->set('loadMappingId', CRM_Utils_Array::value('mappingId', $params)); + + //Updating Mapping Records + if (CRM_Utils_Array::value('updateMapping', $params)) { + $mappingFields = new CRM_Core_DAO_MappingField(); + $mappingFields->mapping_id = $params['mappingId']; + $mappingFields->find(); + + $mappingFieldsId = array(); + while ($mappingFields->fetch()) { + if ($mappingFields->id) { + $mappingFieldsId[$mappingFields->column_number] = $mappingFields->id; + } + } + + for ($i = 0; $i < $this->_columnCount; $i++) { + $updateMappingFields = new CRM_Core_DAO_MappingField(); + $updateMappingFields->id = $mappingFieldsId[$i]; + $updateMappingFields->mapping_id = $params['mappingId']; + $updateMappingFields->column_number = $i; + $updateMappingFields->name = $mapper[$i]; + + //reuse contact_type field in db to store fields associated with soft credit + $updateMappingFields->contact_type = isset($mapperSoftCredit[$i]) ? $mapperSoftCredit[$i] : NULL; + $updateMappingFields->save(); + } + } + + //Saving Mapping Details and Records + if (CRM_Utils_Array::value('saveMapping', $params)) { + $mappingParams = array( + 'name' => $params['saveMappingName'], + 'description' => $params['saveMappingDesc'], + 'mapping_type_id' => CRM_Core_OptionGroup::getValue('mapping_type', + 'Import Contribution', + 'name' + ), + ); + $saveMapping = CRM_Core_BAO_Mapping::add($mappingParams); + + for ($i = 0; $i < $this->_columnCount; $i++) { + $saveMappingFields = new CRM_Core_DAO_MappingField(); + $saveMappingFields->mapping_id = $saveMapping->id; + $saveMappingFields->column_number = $i; + $saveMappingFields->name = $mapper[$i]; + + //reuse contact_type field in db to store fields associated with soft credit + $saveMappingFields->contact_type = isset($mapperSoftCredit[$i]) ? $mapperSoftCredit[$i] : NULL; + $saveMappingFields->save(); + } + $this->set('savedMapping', $saveMappingFields->mapping_id); + } + + $parser = new CRM_Contribute_Import_Parser_Contribution($mapperKeysMain, $mapperSoftCredit, $mapperPhoneType); + $parser->run($fileName, $seperator, $mapper, $skipColumnHeader, + CRM_Contribute_Import_Parser::MODE_PREVIEW, $this->get('contactType') + ); + + // add all the necessary variables to the form + $parser->set($this); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Match Fields'); + } +} + diff --git a/CRM/Contribute/Import/Form/Preview.php b/CRM/Contribute/Import/Form/Preview.php new file mode 100644 index 0000000000..28038f6df4 --- /dev/null +++ b/CRM/Contribute/Import/Form/Preview.php @@ -0,0 +1,226 @@ +controller->exportValue('UploadFile', 'skipColumnHeader'); + + //get the data from the session + $dataValues = $this->get('dataValues'); + $mapper = $this->get('mapper'); + $softCreditFields = $this->get('softCreditFields'); + $invalidRowCount = $this->get('invalidRowCount'); + $conflictRowCount = $this->get('conflictRowCount'); + $mismatchCount = $this->get('unMatchCount'); + + //get the mapping name displayed if the mappingId is set + $mappingId = $this->get('loadMappingId'); + if ($mappingId) { + $mapDAO = new CRM_Core_DAO_Mapping(); + $mapDAO->id = $mappingId; + $mapDAO->find(TRUE); + $this->assign('loadedMapping', $mappingId); + $this->assign('savedName', $mapDAO->name); + } + + if ($skipColumnHeader) { + $this->assign('skipColumnHeader', $skipColumnHeader); + $this->assign('rowDisplayCount', 3); + } + else { + $this->assign('rowDisplayCount', 2); + } + + if ($invalidRowCount) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::ERROR . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + + if ($conflictRowCount) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::CONFLICT . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + + if ($mismatchCount) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::NO_MATCH . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + + $properties = array( + 'mapper', 'softCreditFields', + 'dataValues', 'columnCount', + 'totalRowCount', 'validRowCount', + 'invalidRowCount', 'conflictRowCount', + 'downloadErrorRecordsUrl', + 'downloadConflictRecordsUrl', + 'downloadMismatchRecordsUrl', + ); + + foreach ($properties as $property) { + $this->assign($property, $this->get($property)); + } + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + + $this->addButtons(array( + array( + 'type' => 'back', + 'name' => ts('<< Previous'), + ), + array( + 'type' => 'next', + 'name' => ts('Import Now >>'), + 'spacing' => '          ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Preview'); + } + + /** + * Process the mapped fields and map it into the uploaded file + * preview the file and extract some summary statistics + * + * @return void + * @access public + */ + public function postProcess() { + $fileName = $this->controller->exportValue('UploadFile', 'uploadFile'); + $skipColumnHeader = $this->controller->exportValue('UploadFile', 'skipColumnHeader'); + $invalidRowCount = $this->get('invalidRowCount'); + $conflictRowCount = $this->get('conflictRowCount'); + $onDuplicate = $this->get('onDuplicate'); + + $config = CRM_Core_Config::singleton(); + $seperator = $config->fieldSeparator; + + $mapper = $this->controller->exportValue('MapField', 'mapper'); + $mapperKeys = array(); + $mapperSoftCredit = array(); + $mapperPhoneType = array(); + + foreach ($mapper as $key => $value) { + $mapperKeys[$key] = $mapper[$key][0]; + if (isset($mapper[$key][0]) && $mapper[$key][0] == 'soft_credit') { + $mapperSoftCredit[$key] = $mapper[$key][1]; + } + else { + $mapperSoftCredit[$key] = NULL; + } + } + + $parser = new CRM_Contribute_Import_Parser_Contribution($mapperKeys, $mapperSoftCredit, $mapperPhoneType); + + $mapFields = $this->get('fields'); + + foreach ($mapper as $key => $value) { + $header = array(); + if (isset($mapFields[$mapper[$key][0]])) { + $header[] = $mapFields[$mapper[$key][0]]; + } + $mapperFields[] = implode(' - ', $header); + } + $parser->run($fileName, $seperator, + $mapperFields, + $skipColumnHeader, + CRM_Contribute_Import_Parser::MODE_IMPORT, + $this->get('contactType'), + $onDuplicate + ); + + // add all the necessary variables to the form + $parser->set($this, CRM_Contribute_Import_Parser::MODE_IMPORT); + + // check if there is any error occured + + $errorStack = CRM_Core_Error::singleton(); + $errors = $errorStack->getErrors(); + $errorMessage = array(); + + if (is_array($errors)) { + foreach ($errors as $key => $value) { + $errorMessage[] = $value['message']; + } + + $errorFile = $fileName['name'] . '.error.log'; + + if ($fd = fopen($errorFile, 'w')) { + fwrite($fd, implode('\n', $errorMessage)); + } + fclose($fd); + + $this->set('errorFile', $errorFile); + $urlParams = 'type=' . CRM_Contribute_Import_Parser::ERROR . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + $urlParams = 'type=' . CRM_Contribute_Import_Parser::CONFLICT . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadConflictRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + $urlParams = 'type=' . CRM_Contribute_Import_Parser::NO_MATCH . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + } +} + diff --git a/CRM/Contribute/Import/Form/Summary.php b/CRM/Contribute/Import/Form/Summary.php new file mode 100644 index 0000000000..982289593f --- /dev/null +++ b/CRM/Contribute/Import/Form/Summary.php @@ -0,0 +1,142 @@ +assign('errorFile', $this->get('errorFile')); + + $totalRowCount = $this->get('totalRowCount'); + $relatedCount = $this->get('relatedCount'); + $totalRowCount += $relatedCount; + $this->set('totalRowCount', $totalRowCount); + + $invalidRowCount = $this->get('invalidRowCount'); + $invalidSoftCreditRowCount = $this->get('invalidSoftCreditRowCount'); + if ($invalidSoftCreditRowCount) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadSoftCreditErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + $validSoftCreditRowCount = $this->get('validSoftCreditRowCount'); + $invalidPledgePaymentRowCount = $this->get('invalidPledgePaymentRowCount'); + if ($invalidPledgePaymentRowCount) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadPledgePaymentErrorRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + $validPledgePaymentRowCount = $this->get('validPledgePaymentRowCount'); + $conflictRowCount = $this->get('conflictRowCount'); + $duplicateRowCount = $this->get('duplicateRowCount'); + $onDuplicate = $this->get('onDuplicate'); + $mismatchCount = $this->get('unMatchCount'); + if ($duplicateRowCount > 0) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::DUPLICATE . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadDuplicateRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + elseif ($mismatchCount) { + $urlParams = 'type=' . CRM_Contribute_Import_Parser::NO_MATCH . '&parser=CRM_Contribute_Import_Parser'; + $this->set('downloadMismatchRecordsUrl', CRM_Utils_System::url('civicrm/export', $urlParams)); + } + else { + $duplicateRowCount = 0; + $this->set('duplicateRowCount', $duplicateRowCount); + } + + $this->assign('dupeError', FALSE); + + if ($onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_UPDATE) { + $dupeActionString = ts('These records have been updated with the imported data.'); + } + elseif ($onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_FILL) { + $dupeActionString = ts('These records have been filled in with the imported data.'); + } + else { + /* Skip by default */ + + $dupeActionString = ts('These records have not been imported.'); + + $this->assign('dupeError', TRUE); + + /* only subtract dupes from succesful import if we're skipping */ + + $this->set('validRowCount', $totalRowCount - $invalidRowCount - + $conflictRowCount - $duplicateRowCount - $mismatchCount - $invalidSoftCreditRowCount - $invalidPledgePaymentRowCount + ); + } + $this->assign('dupeActionString', $dupeActionString); + + $properties = array('totalRowCount', 'validRowCount', 'invalidRowCount', 'validSoftCreditRowCount', 'invalidSoftCreditRowCount', 'conflictRowCount', 'downloadConflictRecordsUrl', 'downloadErrorRecordsUrl', 'duplicateRowCount', 'downloadDuplicateRecordsUrl', 'downloadMismatchRecordsUrl', 'groupAdditions', 'unMatchCount', 'validPledgePaymentRowCount', 'invalidPledgePaymentRowCount', 'downloadPledgePaymentErrorRecordsUrl', 'downloadSoftCreditErrorRecordsUrl'); + foreach ($properties as $property) { + $this->assign($property, $this->get($property)); + } + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + $this->addButtons(array( + array( + 'type' => 'next', + 'name' => ts('Done'), + 'isDefault' => TRUE, + ), + ) + ); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Summary'); + } +} + diff --git a/CRM/Contribute/Import/Form/UploadFile.php b/CRM/Contribute/Import/Form/UploadFile.php new file mode 100644 index 0000000000..e76f8fc9fd --- /dev/null +++ b/CRM/Contribute/Import/Form/UploadFile.php @@ -0,0 +1,206 @@ +pushUserContext(CRM_Utils_System::url('civicrm/contribute/import', 'reset=1')); + } + + /** + * Function to actually build the form + * + * @return None + * @access public + */ + public function buildQuickForm() { + //Setting Upload File Size + $config = CRM_Core_Config::singleton(); + if ($config->maxImportFileSize >= 8388608) { + $uploadFileSize = 8388608; + } + else { + $uploadFileSize = $config->maxImportFileSize; + } + $uploadSize = round(($uploadFileSize / (1024 * 1024)), 2); + + $this->assign('uploadSize', $uploadSize); + + $this->add('file', 'uploadFile', ts('Import Data File'), 'size=30 maxlength=255', TRUE); + + $this->addRule('uploadFile', ts('A valid file must be uploaded.'), 'uploadedfile'); + $this->addRule('uploadFile', ts('File size should be less than %1 MBytes (%2 bytes)', array(1 => $uploadSize, 2 => $uploadFileSize)), 'maxfilesize', $uploadFileSize); + $this->setMaxFileSize($uploadFileSize); + $this->addRule('uploadFile', ts('Input file must be in CSV format'), 'utf8File'); + + $this->addElement('checkbox', 'skipColumnHeader', ts('First row contains column headers')); + + $duplicateOptions = array(); + $duplicateOptions[] = $this->createElement('radio', + NULL, NULL, ts('Insert new contributions'), CRM_Contribute_Import_Parser::DUPLICATE_SKIP + ); + $duplicateOptions[] = $this->createElement('radio', + NULL, NULL, ts('Update existing contributions'), CRM_Contribute_Import_Parser::DUPLICATE_UPDATE + ); + $this->addGroup($duplicateOptions, 'onDuplicate', + ts('Import mode') + ); + + //get the saved mapping details + $mappingArray = CRM_Core_BAO_Mapping::getMappings(CRM_Core_OptionGroup::getValue('mapping_type', + 'Import Contribution', + 'name' + )); + $this->assign('savedMapping', $mappingArray); + $this->add('select', 'savedMapping', ts('Mapping Option'), array('' => ts('- select -')) + $mappingArray); + $this->addElement('submit', 'loadMapping', ts('Load Mapping'), NULL, array('onclick' => 'checkSelect()')); + + if ($loadeMapping = $this->get('loadedMapping')) { + $this->assign('loadedMapping', $loadeMapping); + $this->setDefaults(array('savedMapping' => $loadeMapping)); + } + + $this->setDefaults(array( + 'onDuplicate' => + CRM_Contribute_Import_Parser::DUPLICATE_SKIP, + )); + + //contact types option + $contactOptions = array(); + if (CRM_Contact_BAO_ContactType::isActive('Individual')) { + $contactOptions[] = $this->createElement('radio', + NULL, NULL, ts('Individual'), CRM_Contribute_Import_Parser::CONTACT_INDIVIDUAL + ); + } + if (CRM_Contact_BAO_ContactType::isActive('Household')) { + $contactOptions[] = $this->createElement('radio', + NULL, NULL, ts('Household'), CRM_Contribute_Import_Parser::CONTACT_HOUSEHOLD + ); + } + if (CRM_Contact_BAO_ContactType::isActive('Organization')) { + $contactOptions[] = $this->createElement('radio', + NULL, NULL, ts('Organization'), CRM_Contribute_Import_Parser::CONTACT_ORGANIZATION + ); + } + + $this->addGroup($contactOptions, 'contactType', + ts('Contact Type') + ); + + $this->setDefaults(array( + 'contactType' => + CRM_Contribute_Import_Parser::CONTACT_INDIVIDUAL, + )); + + //build date formats + CRM_Core_Form_Date::buildAllowedDateFormats($this); + + $this->addButtons(array( + array( + 'type' => 'upload', + 'name' => ts('Continue >>'), + 'spacing' => '          ', + 'isDefault' => TRUE, + ), + array( + 'type' => 'cancel', + 'name' => ts('Cancel'), + ), + ) + ); + } + + /** + * Process the uploaded file + * + * @return void + * @access public + */ + public function postProcess() { + $this->controller->resetPage('MapField'); + + $fileName = $this->controller->exportValue($this->_name, 'uploadFile'); + $skipColumnHeader = $this->controller->exportValue($this->_name, 'skipColumnHeader'); + $onDuplicate = $this->controller->exportValue($this->_name, 'onDuplicate'); + $contactType = $this->controller->exportValue($this->_name, 'contactType'); + $dateFormats = $this->controller->exportValue($this->_name, 'dateFormats'); + $savedMapping = $this->controller->exportValue($this->_name, 'savedMapping'); + + $this->set('onDuplicate', $onDuplicate); + $this->set('contactType', $contactType); + $this->set('dateFormats', $dateFormats); + $this->set('savedMapping', $savedMapping); + + $session = CRM_Core_Session::singleton(); + $session->set("dateTypes", $dateFormats); + + $config = CRM_Core_Config::singleton(); + $seperator = $config->fieldSeparator; + + $mapper = array(); + + $parser = new CRM_Contribute_Import_Parser_Contribution($mapper); + $parser->setMaxLinesToProcess(100); + $parser->run($fileName, $seperator, + $mapper, + $skipColumnHeader, + CRM_Contribute_Import_Parser::MODE_MAPFIELD, $contactType + ); + + // add all the necessary variables to the form + $parser->set($this); + } + + /** + * Return a descriptive name for the page, used in wizard header + * + * @return string + * @access public + */ + public function getTitle() { + return ts('Upload Data'); + } +} + diff --git a/CRM/Contribute/Import/Parser.php b/CRM/Contribute/Import/Parser.php new file mode 100644 index 0000000000..3aa3c4ea25 --- /dev/null +++ b/CRM/Contribute/Import/Parser.php @@ -0,0 +1,897 @@ +_maxLinesToProcess = 0; + $this->_maxErrorCount = self::MAX_ERRORS; + } + + abstract function init(); + function run($fileName, + $seperator = ',', + &$mapper, + $skipColumnHeader = FALSE, + $mode = self::MODE_PREVIEW, + $contactType = self::CONTACT_INDIVIDUAL, + $onDuplicate = self::DUPLICATE_SKIP + ) { + if (!is_array($fileName)) { + CRM_Core_Error::fatal(); + } + $fileName = $fileName['name']; + + switch ($contactType) { + case self::CONTACT_INDIVIDUAL: + $this->_contactType = 'Individual'; + break; + + case self::CONTACT_HOUSEHOLD: + $this->_contactType = 'Household'; + break; + + case self::CONTACT_ORGANIZATION: + $this->_contactType = 'Organization'; + } + + $this->init(); + + $this->_haveColumnHeader = $skipColumnHeader; + + $this->_seperator = $seperator; + + $fd = fopen($fileName, "r"); + if (!$fd) { + return FALSE; + } + + $this->_lineCount = $this->_warningCount = $this->_validSoftCreditRowCount = $this->_validPledgePaymentRowCount = 0; + $this->_invalidRowCount = $this->_validCount = $this->_invalidSoftCreditRowCount = $this->_invalidPledgePaymentRowCount = 0; + $this->_totalCount = $this->_conflictCount = 0; + + $this->_errors = array(); + $this->_warnings = array(); + $this->_conflicts = array(); + $this->_pledgePaymentErrors = array(); + $this->_softCreditErrors = array(); + + $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2); + + if ($mode == self::MODE_MAPFIELD) { + $this->_rows = array(); + } + else { + $this->_activeFieldCount = count($this->_activeFields); + } + + while (!feof($fd)) { + $this->_lineCount++; + + $values = fgetcsv($fd, 8192, $seperator); + if (!$values) { + continue; + } + + self::encloseScrub($values); + + // skip column header if we're not in mapfield mode + if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) { + $skipColumnHeader = FALSE; + continue; + } + + /* trim whitespace around the values */ + + $empty = TRUE; + foreach ($values as $k => $v) { + $values[$k] = trim($v, " \t\r\n"); + } + + if (CRM_Utils_System::isNull($values)) { + continue; + } + + $this->_totalCount++; + + if ($mode == self::MODE_MAPFIELD) { + $returnCode = $this->mapField($values); + } + elseif ($mode == self::MODE_PREVIEW) { + $returnCode = $this->preview($values); + } + elseif ($mode == self::MODE_SUMMARY) { + $returnCode = $this->summary($values); + } + elseif ($mode == self::MODE_IMPORT) { + $returnCode = $this->import($onDuplicate, $values); + } + else { + $returnCode = self::ERROR; + } + + // note that a line could be valid but still produce a warning + if ($returnCode == self::VALID) { + $this->_validCount++; + if ($mode == self::MODE_MAPFIELD) { + $this->_rows[] = $values; + $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); + } + } + + if ($returnCode == self::SOFT_CREDIT) { + $this->_validSoftCreditRowCount++; + $this->_validCount++; + if ($mode == self::MODE_MAPFIELD) { + $this->_rows[] = $values; + $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); + } + } + + if ($returnCode == self::PLEDGE_PAYMENT) { + $this->_validPledgePaymentRowCount++; + $this->_validCount++; + if ($mode == self::MODE_MAPFIELD) { + $this->_rows[] = $values; + $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); + } + } + + if ($returnCode == self::WARNING) { + $this->_warningCount++; + if ($this->_warningCount < $this->_maxWarningCount) { + $this->_warningCount[] = $line; + } + } + + if ($returnCode == self::ERROR) { + $this->_invalidRowCount++; + if ($this->_invalidRowCount < $this->_maxErrorCount) { + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_errors[] = $values; + } + } + + if ($returnCode == self::PLEDGE_PAYMENT_ERROR) { + $this->_invalidPledgePaymentRowCount++; + if ($this->_invalidPledgePaymentRowCount < $this->_maxErrorCount) { + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_pledgePaymentErrors[] = $values; + } + } + + if ($returnCode == self::SOFT_CREDIT_ERROR) { + $this->_invalidSoftCreditRowCount++; + if ($this->_invalidSoftCreditRowCount < $this->_maxErrorCount) { + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_softCreditErrors[] = $values; + } + } + + if ($returnCode == self::CONFLICT) { + $this->_conflictCount++; + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_conflicts[] = $values; + } + + if ($returnCode == self::DUPLICATE) { + if ($returnCode == self::MULTIPLE_DUPE) { + /* TODO: multi-dupes should be counted apart from singles + * on non-skip action */ + } + $this->_duplicateCount++; + $recordNumber = $this->_lineCount; + if ($this->_haveColumnHeader) { + $recordNumber--; + } + array_unshift($values, $recordNumber); + $this->_duplicates[] = $values; + if ($onDuplicate != self::DUPLICATE_SKIP) { + $this->_validCount++; + } + } + + // we give the derived class a way of aborting the process + // note that the return code could be multiple code or'ed together + if ($returnCode == self::STOP) { + break; + } + + // if we are done processing the maxNumber of lines, break + if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) { + break; + } + } + + fclose($fd); + + if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) { + $customHeaders = $mapper; + + $customfields = CRM_Core_BAO_CustomField::getFields('Contribution'); + foreach ($customHeaders as $key => $value) { + if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) { + $customHeaders[$key] = $customfields[$id][0]; + } + } + if ($this->_invalidRowCount) { + // removed view url for invlaid contacts + $headers = array_merge(array(ts('Line Number'), + ts('Reason'), + ), + $customHeaders + ); + $this->_errorFileName = self::errorFileName(self::ERROR); + self::exportCSV($this->_errorFileName, $headers, $this->_errors); + } + + if ($this->_invalidPledgePaymentRowCount) { + // removed view url for invlaid contacts + $headers = array_merge(array(ts('Line Number'), + ts('Reason'), + ), + $customHeaders + ); + $this->_pledgePaymentErrorsFileName = self::errorFileName(self::PLEDGE_PAYMENT_ERROR); + self::exportCSV($this->_pledgePaymentErrorsFileName, $headers, $this->_pledgePaymentErrors); + } + + if ($this->_invalidSoftCreditRowCount) { + // removed view url for invlaid contacts + $headers = array_merge(array(ts('Line Number'), + ts('Reason'), + ), + $customHeaders + ); + $this->_softCreditErrorsFileName = self::errorFileName(self::SOFT_CREDIT_ERROR); + self::exportCSV($this->_softCreditErrorsFileName, $headers, $this->_softCreditErrors); + } + + if ($this->_conflictCount) { + $headers = array_merge(array(ts('Line Number'), + ts('Reason'), + ), + $customHeaders + ); + $this->_conflictFileName = self::errorFileName(self::CONFLICT); + self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts); + } + if ($this->_duplicateCount) { + $headers = array_merge(array(ts('Line Number'), + ts('View Contribution URL'), + ), + $customHeaders + ); + + $this->_duplicateFileName = self::errorFileName(self::DUPLICATE); + self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates); + } + } + //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount"; + return $this->fini(); + } + + abstract function mapField(&$values); + abstract function preview(&$values); + abstract function summary(&$values); + abstract function import($onDuplicate, &$values); + + abstract function fini(); + + /** + * Given a list of the importable field keys that the user has selected + * set the active fields array to this list + * + * @param array mapped array of values + * +pppp * @return void + * @access public + */ + function setActiveFields($fieldKeys) { + $this->_activeFieldCount = count($fieldKeys); + foreach ($fieldKeys as $key) { + if (empty($this->_fields[$key])) { + $this->_activeFields[] = new CRM_Contribute_Import_Field('', ts('- do not import -')); + } + else { + $this->_activeFields[] = clone($this->_fields[$key]); + } + } + } + + function setActiveFieldSoftCredit($elements) { + for ($i = 0; $i < count($elements); $i++) { + $this->_activeFields[$i]->_softCreditField = $elements[$i]; + } + } + + function setActiveFieldValues($elements, &$erroneousField) { + $maxCount = count($elements) < $this->_activeFieldCount ? count($elements) : $this->_activeFieldCount; + for ($i = 0; $i < $maxCount; $i++) { + $this->_activeFields[$i]->setValue($elements[$i]); + } + + // reset all the values that we did not have an equivalent import element + for (; $i < $this->_activeFieldCount; $i++) { + $this->_activeFields[$i]->resetValue(); + } + + // now validate the fields and return false if error + $valid = self::VALID; + for ($i = 0; $i < $this->_activeFieldCount; $i++) { + if (!$this->_activeFields[$i]->validate()) { + // no need to do any more validation + $erroneousField = $i; + $valid = self::ERROR; + break; + } + } + return $valid; + } + + /** + * function to format the field values for input to the api + * + * @return array (reference ) associative array of name/value pairs + * @access public + */ + function &getActiveFieldParams() { + $params = array(); + for ($i = 0; $i < $this->_activeFieldCount; $i++) { + if (isset($this->_activeFields[$i]->_value)) { + if (isset($this->_activeFields[$i]->_softCreditField)) { + if (!isset($params[$this->_activeFields[$i]->_name])) { + $params[$this->_activeFields[$i]->_name] = array(); + } + $params[$this->_activeFields[$i]->_name][$this->_activeFields[$i]->_softCreditField] = $this->_activeFields[$i]->_value; + } + + if (!isset($params[$this->_activeFields[$i]->_name])) { + if (!isset($this->_activeFields[$i]->_softCreditField)) { + $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value; + } + } + } + } + return $params; + } + + function getSelectValues() { + $values = array(); + foreach ($this->_fields as $name => $field) { + $values[$name] = $field->_title; + } + return $values; + } + + function getSelectTypes() { + $values = array(); + foreach ($this->_fields as $name => $field) { + if (isset($field->_hasLocationType)) { + $values[$name] = $field->_hasLocationType; + } + } + return $values; + } + + function getHeaderPatterns() { + $values = array(); + foreach ($this->_fields as $name => $field) { + if (isset($field->_headerPattern)) { + $values[$name] = $field->_headerPattern; + } + } + return $values; + } + + function getDataPatterns() { + $values = array(); + foreach ($this->_fields as $name => $field) { + $values[$name] = $field->_dataPattern; + } + return $values; + } + + function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') { + if (empty($name)) { + $this->_fields['doNotImport'] = new CRM_Contribute_Import_Field($name, $title, $type, $headerPattern, $dataPattern); + } + else { + $tempField = CRM_Contact_BAO_Contact::importableFields('All', NULL); + if (!array_key_exists($name, $tempField)) { + $this->_fields[$name] = new CRM_Contribute_Import_Field($name, $title, $type, $headerPattern, $dataPattern); + } + else { + $this->_fields[$name] = new CRM_Import_Field($name, $title, $type, $headerPattern, $dataPattern, + CRM_Utils_Array::value('hasLocationType', $tempField[$name]) + ); + } + } + } + + /** + * setter function + * + * @param int $max + * + * @return void + * @access public + */ + function setMaxLinesToProcess($max) { + $this->_maxLinesToProcess = $max; + } + + /** + * Store parser values + * + * @param CRM_Core_Session $store + * + * @return void + * @access public + */ + function set($store, $mode = self::MODE_SUMMARY) { + $store->set('fileSize', $this->_fileSize); + $store->set('lineCount', $this->_lineCount); + $store->set('seperator', $this->_seperator); + $store->set('fields', $this->getSelectValues()); + $store->set('fieldTypes', $this->getSelectTypes()); + + $store->set('headerPatterns', $this->getHeaderPatterns()); + $store->set('dataPatterns', $this->getDataPatterns()); + $store->set('columnCount', $this->_activeFieldCount); + + $store->set('totalRowCount', $this->_totalCount); + $store->set('validRowCount', $this->_validCount); + $store->set('invalidRowCount', $this->_invalidRowCount); + $store->set('invalidSoftCreditRowCount', $this->_invalidSoftCreditRowCount); + $store->set('validSoftCreditRowCount', $this->_validSoftCreditRowCount); + $store->set('invalidPledgePaymentRowCount', $this->_invalidPledgePaymentRowCount); + $store->set('validPledgePaymentRowCount', $this->_validPledgePaymentRowCount); + $store->set('conflictRowCount', $this->_conflictCount); + + switch ($this->_contactType) { + case 'Individual': + $store->set('contactType', CRM_Contribute_Import_Parser::CONTACT_INDIVIDUAL); + break; + + case 'Household': + $store->set('contactType', CRM_Contribute_Import_Parser::CONTACT_HOUSEHOLD); + break; + + case 'Organization': + $store->set('contactType', CRM_Contribute_Import_Parser::CONTACT_ORGANIZATION); + } + + if ($this->_invalidRowCount) { + $store->set('errorsFileName', $this->_errorFileName); + } + if ($this->_conflictCount) { + $store->set('conflictsFileName', $this->_conflictFileName); + } + if (isset($this->_rows) && !empty($this->_rows)) { + $store->set('dataValues', $this->_rows); + } + + if ($this->_invalidPledgePaymentRowCount) { + $store->set('pledgePaymentErrorsFileName', $this->_pledgePaymentErrorsFileName); + } + + if ($this->_invalidSoftCreditRowCount) { + $store->set('softCreditErrorsFileName', $this->_softCreditErrorsFileName); + } + + if ($mode == self::MODE_IMPORT) { + $store->set('duplicateRowCount', $this->_duplicateCount); + if ($this->_duplicateCount) { + $store->set('duplicatesFileName', $this->_duplicateFileName); + } + } + //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount"; + } + + /** + * Export data to a CSV file + * + * @param string $filename + * @param array $header + * @param data $data + * + * @return void + * @access public + */ + static function exportCSV($fileName, $header, $data) { + $output = array(); + $fd = fopen($fileName, 'w'); + + foreach ($header as $key => $value) { + $header[$key] = "\"$value\""; + } + $config = CRM_Core_Config::singleton(); + $output[] = implode($config->fieldSeparator, $header); + + foreach ($data as $datum) { + foreach ($datum as $key => $value) { + if (is_array($value[0])) { + foreach ($value[0] as $k1 => $v1) { + if ($k1 == 'location_type_id') { + continue; + } + $datum[$k1] = $v1; + } + } + else { + $datum[$key] = "\"$value\""; + } + } + $output[] = implode($config->fieldSeparator, $datum); + } + fwrite($fd, implode("\n", $output)); + fclose($fd); + } + + /** + * Remove single-quote enclosures from a value array (row) + * + * @param array $values + * @param string $enclosure + * + * @return void + * @static + * @access public + */ + static function encloseScrub(&$values, $enclosure = "'") { + if (empty($values)) { + return; + } + + foreach ($values as $k => $v) { + $values[$k] = preg_replace("/^$enclosure(.*) $enclosure$/", '$1', $v); + } + } + + function errorFileName($type) { + $fileName = NULL; + if (empty($type)) { + return $fileName; + } + + $config = CRM_Core_Config::singleton(); + $fileName = $config->uploadDir . "sqlImport"; + + switch ($type) { + case CRM_Contribute_Import_Parser::ERROR: + case CRM_Contribute_Import_Parser::NO_MATCH: + case CRM_Contribute_Import_Parser::CONFLICT: + case CRM_Contribute_Import_Parser::DUPLICATE: + //here constants get collides. + if ($type == CRM_Contribute_Import_Parser::ERROR) { + $type = CRM_Import_Parser::ERROR; + } + elseif ($type == CRM_Contribute_Import_Parser::NO_MATCH) { + $type = CRM_Import_Parser::NO_MATCH; + } + elseif ($type == CRM_Contribute_Import_Parser::CONFLICT) { + $type = CRM_Import_Parser::CONFLICT; + } + else { + $type = CRM_Import_Parser::DUPLICATE; + } + $fileName = CRM_Import_Parser::errorFileName($type); + break; + + case CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR: + $fileName .= '.softCreditErrors'; + break; + + case CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR: + $fileName .= '.pledgePaymentErrors'; + break; + } + + return $fileName; + } + + function saveFileName($type) { + $fileName = NULL; + if (empty($type)) { + return $fileName; + } + + switch ($type) { + case CRM_Contribute_Import_Parser::ERROR: + case CRM_Contribute_Import_Parser::NO_MATCH: + case CRM_Contribute_Import_Parser::CONFLICT: + case CRM_Contribute_Import_Parser::DUPLICATE: + //here constants get collides. + if ($type == CRM_Contribute_Import_Parser::ERROR) { + $type = CRM_Import_Parser::ERROR; + } + elseif ($type == CRM_Contribute_Import_Parser::NO_MATCH) { + $type = CRM_Import_Parser::NO_MATCH; + } + elseif ($type == CRM_Contribute_Import_Parser::CONFLICT) { + $type = CRM_Import_Parser::CONFLICT; + } + else { + $type = CRM_Import_Parser::DUPLICATE; + } + $fileName = CRM_Import_Parser::saveFileName($type); + break; + + case CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR: + $fileName = 'Import_Soft_Credit_Errors.csv'; + break; + + case CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR: + $fileName = 'Import_Pledge_Payment_Errors.csv'; + break; + } + + return $fileName; + } +} + diff --git a/CRM/Contribute/Import/Parser/Contribution.php b/CRM/Contribute/Import/Parser/Contribution.php new file mode 100644 index 0000000000..2650193b3d --- /dev/null +++ b/CRM/Contribute/Import/Parser/Contribution.php @@ -0,0 +1,587 @@ +_mapperKeys = &$mapperKeys; + $this->_mapperSoftCredit = &$mapperSoftCredit; + } + + /** + * the initializer code, called before the processing + * + * @return void + * @access public + */ + function init() { + $fields = CRM_Contribute_BAO_Contribution::importableFields($this->_contactType, FALSE); + + $fields = array_merge($fields, + array('soft_credit' => array('title' => ts('Soft Credit'), + 'softCredit' => TRUE, + 'headerPattern' => '/Soft Credit/i', + )) + ); + + // add pledge fields only if its is enabled + if (CRM_Core_Permission::access('CiviPledge')) { + $pledgeFields = array('pledge_payment' => array('title' => ts('Pledge Payment'), + 'headerPattern' => '/Pledge Payment/i', + ), + 'pledge_id' => array('title' => ts('Pledge ID'), + 'headerPattern' => '/Pledge ID/i', + ), + ); + + $fields = array_merge($fields, $pledgeFields); + } + foreach ($fields as $name => $field) { + $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT); + $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//'); + $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//'); + $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']); + } + + $this->_newContributions = array(); + + $this->setActiveFields($this->_mapperKeys); + $this->setActiveFieldSoftCredit($this->_mapperSoftCredit); + + // FIXME: we should do this in one place together with Form/MapField.php + $this->_contactIdIndex = -1; + $this->_totalAmountIndex = -1; + $this->_contributionTypeIndex = -1; + + $index = 0; + foreach ($this->_mapperKeys as $key) { + switch ($key) { + case 'contribution_contact_id': + $this->_contactIdIndex = $index; + break; + + case 'total_amount': + $this->_totalAmountIndex = $index; + break; + + case 'financial_type': + $this->_contributionTypeIndex = $index; + break; + } + $index++; + } + } + + /** + * handle the values in mapField mode + * + * @param array $values the array of values belonging to this line + * + * @return boolean + * @access public + */ + function mapField(&$values) { + return CRM_Contribute_Import_Parser::VALID; + } + + /** + * handle the values in preview mode + * + * @param array $values the array of values belonging to this line + * + * @return boolean the result of this processing + * @access public + */ + function preview(&$values) { + return $this->summary($values); + } + + /** + * handle the values in summary mode + * + * @param array $values the array of values belonging to this line + * + * @return boolean the result of this processing + * @access public + */ + function summary(&$values) { + $erroneousField = NULL; + $response = $this->setActiveFieldValues($values, $erroneousField); + + $params = &$this->getActiveFieldParams(); + $errorMessage = NULL; + + //for date-Formats + $session = CRM_Core_Session::singleton(); + $dateType = $session->get('dateTypes'); + foreach ($params as $key => $val) { + if ($val) { + switch ($key) { + case 'receive_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Import_Parser_Contact::addToErrorMsg('Receive Date', $errorMessage); + } + break; + + case 'cancel_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Import_Parser_Contact::addToErrorMsg('Cancel Date', $errorMessage); + } + break; + + case 'receipt_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Import_Parser_Contact::addToErrorMsg('Receipt date', $errorMessage); + } + break; + + case 'thankyou_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Import_Parser_Contact::addToErrorMsg('Thankyou Date', $errorMessage); + } + break; + } + } + } + //date-Format part ends + + $params['contact_type'] = 'Contribution'; + + //checking error in custom data + CRM_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage); + + if ($errorMessage) { + $tempMsg = "Invalid value for field(s) : $errorMessage"; + array_unshift($values, $tempMsg); + $errorMessage = NULL; + return CRM_Contribute_Import_Parser::ERROR; + } + + return CRM_Contribute_Import_Parser::VALID; + } + + /** + * handle the values in import mode + * + * @param int $onDuplicate the code for what action to take on duplicates + * @param array $values the array of values belonging to this line + * + * @return boolean the result of this processing + * @access public + */ + function import($onDuplicate, &$values) { + // first make sure this is a valid line + $response = $this->summary($values); + if ($response != CRM_Contribute_Import_Parser::VALID) { + return $response; + } + + $params = &$this->getActiveFieldParams(); + $formatted = array('version' => 3); + + // don't add to recent items, CRM-4399 + $formatted['skipRecentView'] = TRUE; + + //for date-Formats + $session = CRM_Core_Session::singleton(); + $dateType = $session->get('dateTypes'); + + $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $params)); + + foreach ($params as $key => $val) { + if ($val) { + switch ($key) { + case 'pledge_payment': + $params[$key] = CRM_Utils_String::strtobool($val); + break; + } + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { + if ($customFields[$customFieldID]['data_type'] == 'Date') { + CRM_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key); + unset($params[$key]); + } + elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { + $params[$key] = CRM_Utils_String::strtoboolstr($val); + } + } + } + } + //date-Format part ends + + static $indieFields = NULL; + if ($indieFields == NULL) { + $tempIndieFields = CRM_Contribute_DAO_Contribution::import(); + $indieFields = $tempIndieFields; + } + + $paramValues = array(); + foreach ($params as $key => $field) { + if ($field == NULL || $field === '') { + continue; + } + $paramValues[$key] = $field; + } + + //import contribution record according to select contact type + if ($onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_SKIP && + (CRM_Utils_Array::value('contribution_contact_id', $paramValues) || + CRM_Utils_Array::value('external_identifier', $paramValues) + ) + ) { + $paramValues['contact_type'] = $this->_contactType; + } + elseif ($onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_UPDATE && + ($paramValues['contribution_id'] || $values['trxn_id'] || $paramValues['invoice_id']) + ) { + $paramValues['contact_type'] = $this->_contactType; + } + elseif (!empty($params['soft_credit'])) { + $paramValues['contact_type'] = $this->_contactType; + } + elseif (CRM_Utils_Array::value('pledge_payment', $paramValues)) { + $paramValues['contact_type'] = $this->_contactType; + } + + //need to pass $onDuplicate to check import mode. + if (CRM_Utils_Array::value('pledge_payment', $paramValues)) { + $paramValues['onDuplicate'] = $onDuplicate; + } + require_once 'CRM/Utils/DeprecatedUtils.php'; + $formatError = _civicrm_api3_deprecated_formatted_param($paramValues, $formatted, TRUE); + + if ($formatError) { + array_unshift($values, $formatError['error_message']); + if (CRM_Utils_Array::value('error_data', $formatError) == 'soft_credit') { + return CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR; + } + elseif (CRM_Utils_Array::value('error_data', $formatError) == 'pledge_payment') { + return CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR; + } + return CRM_Contribute_Import_Parser::ERROR; + } + + if ($onDuplicate != CRM_Contribute_Import_Parser::DUPLICATE_UPDATE) { + $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, + CRM_Core_DAO::$_nullObject, + NULL, + 'Contribution' + ); + } + else { + //fix for CRM-2219 - Update Contribution + // onDuplicate == CRM_Contribute_Import_Parser::DUPLICATE_UPDATE + if (CRM_Utils_Array::value('invoice_id',$paramValues) || + CRM_Utils_Array::value('trxn_id', $paramValues) || $paramValues['contribution_id']) { + $dupeIds = array( + 'id' => CRM_Utils_Array::value('contribution_id', $paramValues), + 'trxn_id' => CRM_Utils_Array::value('trxn_id', $paramValues), + 'invoice_id' => CRM_Utils_Array::value('invoice_id', $paramValues), + ); + + $ids['contribution'] = CRM_Contribute_BAO_Contribution::checkDuplicateIds($dupeIds); + + if ($ids['contribution']) { + $formatted['id'] = $ids['contribution']; + $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, + CRM_Core_DAO::$_nullObject, + $formatted['id'], + 'Contribution' + ); + //process note + if (CRM_Utils_Array::value('note', $paramValues)) { + $noteID = array(); + $contactID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $ids['contribution'], 'contact_id'); + $daoNote = new CRM_Core_BAO_Note(); + $daoNote->entity_table = 'civicrm_contribution'; + $daoNote->entity_id = $ids['contribution']; + if ($daoNote->find(TRUE)) { + $noteID['id'] = $daoNote->id; + } + + $noteParams = array( + 'entity_table' => 'civicrm_contribution', + 'note' => $paramValues['note'], + 'entity_id' => $ids['contribution'], + 'contact_id' => $contactID, + ); + CRM_Core_BAO_Note::add($noteParams, $noteID); + unset($formatted['note']); + } + + //need to check existing soft credit contribution, CRM-3968 + if (CRM_Utils_Array::value('soft_credit_to', $formatted)) { + $dupeSoftCredit = array( + 'contact_id' => $formatted['soft_credit_to'], + 'contribution_id' => $ids['contribution'], + ); + $existingSoftCredit = CRM_Contribute_BAO_Contribution::getSoftContribution($dupeSoftCredit); + if (CRM_Utils_Array::value('soft_credit_id', $existingSoftCredit)) { + $formatted['softID'] = $existingSoftCredit['soft_credit_id']; + } + } + + $newContribution = CRM_Contribute_BAO_Contribution::create($formatted, $ids); + + $this->_newContributions[] = $newContribution->id; + + //return soft valid since we need to show how soft credits were added + if (CRM_Utils_Array::value('soft_credit_to', $formatted)) { + return CRM_Contribute_Import_Parser::SOFT_CREDIT; + } + + // process pledge payment assoc w/ the contribution + return self::processPledgePayments($formatted); + + return CRM_Contribute_Import_Parser::VALID; + } + else { + $labels = array( + 'id' => 'Contribution ID', + 'trxn_id' => 'Transaction ID', + 'invoice_id' => 'Invoice ID', + ); + foreach ($dupeIds as $k => $v) { + if ($v) { + $errorMsg[] = "$labels[$k] $v"; + } + } + $errorMsg = implode(' AND ', $errorMsg); + array_unshift($values, 'Matching Contribution record not found for ' . $errorMsg . '. Row was skipped.'); + return CRM_Contribute_Import_Parser::ERROR; + } + } + } + + if ($this->_contactIdIndex < 0) { + // set the contact type if its not set + if (!isset($paramValues['contact_type'])) { + $paramValues['contact_type'] = $this->_contactType; + } + + $paramValues['version'] = 3; + //retrieve contact id using contact dedupe rule + require_once 'CRM/Utils/DeprecatedUtils.php'; + $error = _civicrm_api3_deprecated_check_contact_dedupe($paramValues); + + if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) { + $matchedIDs = explode(',', $error['error_message']['params'][0]); + if (count($matchedIDs) > 1) { + array_unshift($values, 'Multiple matching contact records detected for this row. The contribution was not imported'); + return CRM_Contribute_Import_Parser::ERROR; + } + else { + $cid = $matchedIDs[0]; + $formatted['contact_id'] = $cid; + + $newContribution = civicrm_api('contribution', 'create', $formatted); + if (civicrm_error($newContribution)) { + if (is_array($newContribution['error_message'])) { + array_unshift($values, $newContribution['error_message']['message']); + if ($newContribution['error_message']['params'][0]) { + return CRM_Contribute_Import_Parser::DUPLICATE; + } + } + else { + array_unshift($values, $newContribution['error_message']); + return CRM_Contribute_Import_Parser::ERROR; + } + } + + $this->_newContributions[] = $newContribution['id']; + $formatted['contribution_id'] = $newContribution['id']; + + //return soft valid since we need to show how soft credits were added + if (CRM_Utils_Array::value('soft_credit_to', $formatted)) { + return CRM_Contribute_Import_Parser::SOFT_CREDIT; + } + + // process pledge payment assoc w/ the contribution + return self::processPledgePayments($formatted); + + return CRM_Contribute_Import_Parser::VALID; + } + } + else { + // Using new Dedupe rule. + $ruleParams = array( + 'contact_type' => $this->_contactType, + 'used' => 'Unsupervised', + ); + $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); + + foreach ($fieldsArray as $value) { + if (array_key_exists(trim($value), $params)) { + $paramValue = $params[trim($value)]; + if (is_array($paramValue)) { + $disp .= $params[trim($value)][0][trim($value)] . " "; + } + else { + $disp .= $params[trim($value)] . " "; + } + } + } + + if (CRM_Utils_Array::value('external_identifier', $params)) { + if ($disp) { + $disp .= "AND {$params['external_identifier']}"; + } + else { + $disp = $params['external_identifier']; + } + } + + array_unshift($values, 'No matching Contact found for (' . $disp . ')'); + return CRM_Contribute_Import_Parser::ERROR; + } + } + else { + if (CRM_Utils_Array::value('external_identifier', $paramValues)) { + $checkCid = new CRM_Contact_DAO_Contact(); + $checkCid->external_identifier = $paramValues['external_identifier']; + $checkCid->find(TRUE); + if ($checkCid->id != $formatted['contact_id']) { + array_unshift($values, 'Mismatch of External identifier :' . $paramValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id']); + return CRM_Contribute_Import_Parser::ERROR; + } + } + $newContribution = civicrm_api('contribution', 'create', $formatted); + if (civicrm_error($newContribution)) { + if (is_array($newContribution['error_message'])) { + array_unshift($values, $newContribution['error_message']['message']); + if ($newContribution['error_message']['params'][0]) { + return CRM_Contribute_Import_Parser::DUPLICATE; + } + } + else { + array_unshift($values, $newContribution['error_message']); + return CRM_Contribute_Import_Parser::ERROR; + } + } + + $this->_newContributions[] = $newContribution['id']; + $formatted['contribution_id'] = $newContribution['id']; + + //return soft valid since we need to show how soft credits were added + if (CRM_Utils_Array::value('soft_credit_to', $formatted)) { + return CRM_Contribute_Import_Parser::SOFT_CREDIT; + } + + // process pledge payment assoc w/ the contribution + return self::processPledgePayments($formatted); + + return CRM_Contribute_Import_Parser::VALID; + } + } + + /** + * Function to process pledge payments + */ + function processPledgePayments(&$formatted) { + if (CRM_Utils_Array::value('pledge_payment_id', $formatted) && + CRM_Utils_Array::value('pledge_id', $formatted) + ) { + //get completed status + $completeStatusID = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name'); + + //need to update payment record to map contribution_id + CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_PledgePayment', $formatted['pledge_payment_id'], + 'contribution_id', $formatted['contribution_id'] + ); + + CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($formatted['pledge_id'], + array($formatted['pledge_payment_id']), + $completeStatusID, + NULL, + $formatted['total_amount'] + ); + + return CRM_Contribute_Import_Parser::PLEDGE_PAYMENT; + } + } + + /** + * Get the array of succesfully imported contribution id's + * + * @return array + * @access public + */ + function &getImportedContributions() { + return $this->_newContributions; + } + + /** + * the initializer code, called before the processing + * + * @return void + * @access public + */ + function fini() {} +} + diff --git a/CRM/Contribute/Import/StateMachine.php b/CRM/Contribute/Import/StateMachine.php new file mode 100644 index 0000000000..a18f76c832 --- /dev/null +++ b/CRM/Contribute/Import/StateMachine.php @@ -0,0 +1,63 @@ +_pages = array( + 'CRM_Contribute_Import_Form_UploadFile' => NULL, + 'CRM_Contribute_Import_Form_MapField' => NULL, + 'CRM_Contribute_Import_Form_Preview' => NULL, + 'CRM_Contribute_Import_Form_Summary' => NULL, + ); + + $this->addSequentialPages($this->_pages, $action); + } +} + diff --git a/CRM/Contribute/Info.php b/CRM/Contribute/Info.php new file mode 100644 index 0000000000..5edfad758c --- /dev/null +++ b/CRM/Contribute/Info.php @@ -0,0 +1,118 @@ + 'CiviContribute', + 'translatedName' => ts('CiviContribute'), + 'title' => ts('CiviCRM Contribution Engine'), + 'search' => 1, + 'showActivitiesInCore' => 1, + ); + } + + // docs inherited from interface + public function getPermissions() { + return array( + 'access CiviContribute', + 'edit contributions', + 'make online contributions', + 'delete in CiviContribute', + ); + } + + + // docs inherited from interface + public function getUserDashboardElement() { + return array('name' => ts('Contributions'), + 'title' => ts('Your Contribution(s)'), + 'perm' => array('make online contributions'), + 'weight' => 10, + ); + } + + // docs inherited from interface + public function registerTab() { + return array('title' => ts('Contributions'), + 'url' => 'contribution', + 'weight' => 20, + ); + } + + // docs inherited from interface + public function registerAdvancedSearchPane() { + return array('title' => ts('Contributions'), + 'weight' => 20, + ); + } + + // docs inherited from interface + public function getActivityTypes() { + return NULL; + } + + // add shortcut to Create New + public function creatNewShortcut(&$shortCuts, $newCredit) { + if (CRM_Core_Permission::check('access CiviContribute') && + CRM_Core_Permission::check('edit contributions') + ) { + $shortCuts = array_merge($shortCuts, array( + array('path' => 'civicrm/contribute/add', + 'query' => "reset=1&action=add&context=standalone", + 'ref' => 'new-contribution', + 'title' => ts('Contribution'), + ))); + if ($newCredit) { + $title = ts('Contribution') . '
      (' . ts('credit card') . ')'; + $shortCuts = array_merge($shortCuts, array( + array('path' => 'civicrm/contribute/add', + 'query' => "reset=1&action=add&context=standalone&mode=live", + 'ref' => 'new-contribution-cc', + 'title' => $title, + ))); + } + } + } +} + diff --git a/CRM/Contribute/Page/ContributionPage.php b/CRM/Contribute/Page/ContributionPage.php new file mode 100644 index 0000000000..18f4b70eb0 --- /dev/null +++ b/CRM/Contribute/Page/ContributionPage.php @@ -0,0 +1,668 @@ + array( + 'name' => ts('Make a Copy'), + 'url' => CRM_Utils_System::currentPath(), + 'qs' => 'action=copy&gid=%%id%%', + 'title' => ts('Make a Copy of CiviCRM Contribution Page'), + 'extra' => 'onclick = "return confirm(\'' . $copyExtra . '\');"', + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'title' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contribute_BAO_ContributionPage' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contribute_BAO_ContributionPage' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => CRM_Utils_System::currentPath(), + 'qs' => 'action=delete&reset=1&id=%%id%%', + 'title' => ts('Delete Custom Field'), + 'extra' => 'onclick = "return confirm(\'' . $deleteExtra . '\');"', + ), + ); + } + return self::$_actionLinks; + } + + /** + * Get the configure action links for this page. + * + * @return array $_configureActionLinks + * + */ + function &configureActionLinks() { + // check if variable _actionsLinks is populated + if (!isset(self::$_configureActionLinks)) { + $urlString = 'civicrm/admin/contribute/'; + $urlParams = 'reset=1&action=update&id=%%id%%'; + + self::$_configureActionLinks = array( + CRM_Core_Action::ADD => array( + 'name' => ts('Title and Settings'), + 'title' => ts('Title and Settings'), + 'url' => $urlString . 'settings', + 'qs' => $urlParams, + 'uniqueName' => 'settings', + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Contribution Amounts'), + 'title' => ts('Contribution Amounts'), + 'url' => $urlString . 'amount', + 'qs' => $urlParams, + 'uniqueName' => 'amount', + ), + CRM_Core_Action::VIEW => array( + 'name' => ts('Membership Settings'), + 'title' => ts('Membership Settings'), + 'url' => $urlString . 'membership', + 'qs' => $urlParams, + 'uniqueName' => 'membership', + ), + CRM_Core_Action::EXPORT => array( + 'name' => ts('Thank-you and Receipting'), + 'title' => ts('Thank-you and Receipting'), + 'url' => $urlString . 'thankyou', + 'qs' => $urlParams, + 'uniqueName' => 'thankyou', + ), + CRM_Core_Action::BASIC => array( + 'name' => ts('Tell a Friend'), + 'title' => ts('Tell a Friend'), + 'url' => $urlString . 'friend', + 'qs' => $urlParams, + 'uniqueName' => 'friend', + ), + CRM_Core_Action::PROFILE => array( + 'name' => ts('Include Profiles'), + 'title' => ts('Include Profiles'), + 'url' => $urlString . 'custom', + 'qs' => $urlParams, + 'uniqueName' => 'custom', + ), + CRM_Core_Action::MAP => array( + 'name' => ts('Contribution Widget'), + 'title' => ts('Contribution Widget'), + 'url' => $urlString . 'widget', + 'qs' => $urlParams, + 'uniqueName' => 'widget', + ), + CRM_Core_Action::FOLLOWUP => array( + 'name' => ts('Premiums'), + 'title' => ts('Premiums'), + 'url' => $urlString . 'premium', + 'qs' => $urlParams, + 'uniqueName' => 'premium', + ), + CRM_Core_Action::ADVANCED => array( + 'name' => ts('Personal Campaign Pages'), + 'title' => ts('Personal Campaign Pages'), + 'url' => $urlString . 'pcp', + 'qs' => $urlParams, + 'uniqueName' => 'pcp', + ), + ); + } + + return self::$_configureActionLinks; + } + + /** + * Get the online contribution links. + * + * @return array $_onlineContributionLinks. + * + */ + function &onlineContributionLinks() { + if (!isset(self::$_onlineContributionLinks)) { + $urlString = 'civicrm/contribute/transact'; + $urlParams = 'reset=1&id=%%id%%'; + self::$_onlineContributionLinks = array( + CRM_Core_Action::RENEW => array( + 'name' => ts('Live Page'), + 'title' => ts('Live Page'), + 'url' => $urlString, + 'qs' => $urlParams, + 'fe' => TRUE, + 'uniqueName' => 'live_page', + ), + CRM_Core_Action::PREVIEW => array( + 'name' => ts('Test-drive'), + 'title' => ts('Test-drive'), + 'url' => $urlString, + 'qs' => $urlParams . '&action=preview', + 'uniqueName' => 'test_drive', + ), + ); + } + + return self::$_onlineContributionLinks; + } + + /** + * Get the contributions links. + * + * @return array $_contributionLinks + * + */ + function &contributionLinks() { + if (!isset(self::$_contributionLinks)) { + //get contribution dates. + $dates = CRM_Contribute_BAO_Contribution::getContributionDates(); + foreach (array( + 'now', 'yearDate', 'monthDate') as $date) { + $$date = $dates[$date]; + } + $yearNow = $yearDate + 10000; + + $urlString = 'civicrm/contribute/search'; + $urlParams = 'reset=1&pid=%%id%%&force=1&test=0'; + + self::$_contributionLinks = array( + CRM_Core_Action::DETACH => array( + 'name' => ts('Current Month-To-Date'), + 'title' => ts('Current Month-To-Date'), + 'url' => $urlString, + 'qs' => "{$urlParams}&start={$monthDate}&end={$now}", + 'uniqueName' => 'current_month_to_date', + ), + CRM_Core_Action::REVERT => array( + 'name' => ts('Fiscal Year-To-Date'), + 'title' => ts('Fiscal Year-To-Date'), + 'url' => $urlString, + 'qs' => "{$urlParams}&start={$yearDate}&end={$yearNow}", + 'uniqueName' => 'fiscal_year_to_date', + ), + CRM_Core_Action::BROWSE => array( + 'name' => ts('Cumulative'), + 'title' => ts('Cumulative'), + 'url' => $urlString, + 'qs' => "{$urlParams}&start=&end=$now", + 'uniqueName' => 'cumulative', + ), + ); + } + + return self::$_contributionLinks; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // get the requested action + $action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + + // set breadcrumb to append to 2nd layer pages + $breadCrumb = array(array('title' => ts('Manage Contribution Pages'), + 'url' => CRM_Utils_System::url(CRM_Utils_System::currentPath(), + 'reset=1' + ), + )); + + // what action to take ? + if ($action & CRM_Core_Action::ADD) { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url(CRM_Utils_System::currentPath(), + 'action=browse&reset=1' + )); + + $controller = new CRM_Contribute_Controller_ContributionPage(NULL, $action); + CRM_Utils_System::setTitle(ts('Manage Contribution Page')); + CRM_Utils_System::appendBreadCrumb($breadCrumb); + return $controller->run(); + } + elseif ($action & CRM_Core_Action::UPDATE) { + $config = CRM_Core_Config::singleton(); + + // assign vars to templates + $this->assign('id', $id); + $this->assign('title', CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $id, 'title')); + $this->assign('is_active', CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $id, 'is_active')); + if (in_array('CiviMember', $config->enableComponents)) { + $this->assign('CiviMember', TRUE); + } + } + elseif ($action & CRM_Core_Action::COPY) { + $session = CRM_Core_Session::singleton(); + CRM_Core_Session::setStatus(ts('A copy of the contribution page has been created'), ts('Successfully Copied'), 'success'); + $this->copy(); + } + elseif ($action & CRM_Core_Action::DELETE) { + CRM_Utils_System::appendBreadCrumb($breadCrumb); + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url(CRM_Utils_System::currentPath(), + 'reset=1&action=browse' + )); + + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + $query = " +SELECT ccp.title +FROM civicrm_contribution_page ccp +JOIN civicrm_pcp cp ON ccp.id = cp.page_id +WHERE cp.page_id = {$id} +AND cp.page_type = 'contribute' +"; + + if ($pageTitle = CRM_Core_DAO::singleValueQuery($query)) { + CRM_Core_Session::setStatus(ts('The \'%1\' cannot be deleted! You must Delete all Personal Campaign Page(s) related with this contribution page prior to deleting the page.', array(1 => $pageTitle)), ts('Deletion Error'), 'error'); + + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1')); + } + + $controller = new CRM_Core_Controller_Simple('CRM_Contribute_Form_ContributionPage_Delete', + 'Delete Contribution Page', + CRM_Core_Action::DELETE + ); + $controller->set('id', $id); + $controller->process(); + return $controller->run(); + } + else { + // finally browse the contribution pages + $this->browse(); + + CRM_Utils_System::setTitle(ts('Manage Contribution Pages')); + } + + return parent::run(); + } + + /** + * This function is to make a copy of a contribution page, including + * all the fields in the page + * + * @return void + * @access public + */ + function copy() { + $gid = CRM_Utils_Request::retrieve('gid', 'Positive', + $this, TRUE, 0, 'GET' + ); + + CRM_Contribute_BAO_ContributionPage::copy($gid); + + CRM_Utils_System::redirect(CRM_Utils_System::url(CRM_Utils_System::currentPath(), 'reset=1')); + } + + /** + * Browse all contribution pages + * + * @return void + * @access public + * @static + */ + function browse($action = NULL) { + $this->_sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', + 'String', + $this + ); + $createdId = CRM_Utils_Request::retrieve('cid', 'Positive', + $this, FALSE, 0 + ); + + if ($this->_sortByCharacter == 1 || + !empty($_POST) + ) { + $this->_sortByCharacter = ''; + $this->set('sortByCharacter', ''); + } + + $this->search(); + + $params = array(); + + $whereClause = $this->whereClause($params, FALSE); + $this->pagerAToZ($whereClause, $params); + + $params = array(); + $whereClause = $this->whereClause($params, TRUE); + $this->pager($whereClause, $params); + + list($offset, $rowCount) = $this->_pager->getOffsetAndRowCount(); + + //check for delete CRM-4418 + $allowToDelete = CRM_Core_Permission::check('delete in CiviContribute'); + + $query = " + SELECT id + FROM civicrm_contribution_page + WHERE $whereClause + LIMIT $offset, $rowCount"; + $contribPage = CRM_Core_DAO::executeQuery($query, $params, TRUE, 'CRM_Contribute_DAO_ContributionPage'); + $contribPageIds = array(); + while ($contribPage->fetch()) { + $contribPageIds[$contribPage->id] = $contribPage->id; + } + //get all section info. + $contriPageSectionInfo = CRM_Contribute_BAO_ContributionPage::getSectionInfo($contribPageIds); + + $query = " +SELECT * +FROM civicrm_contribution_page +WHERE $whereClause +ORDER BY title asc + LIMIT $offset, $rowCount"; + + $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, 'CRM_Contribute_DAO_ContributionPage'); + + //get all campaigns. + $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + + //get configure actions links. + $configureActionLinks = self::configureActionLinks(); + + while ($dao->fetch()) { + $contribution[$dao->id] = array(); + CRM_Core_DAO::storeValues($dao, $contribution[$dao->id]); + + // form all action links + $action = array_sum(array_keys($this->actionLinks())); + + //add configure actions links. + $action += array_sum(array_keys($configureActionLinks)); + + //add online contribution links. + $action += array_sum(array_keys(self::onlineContributionLinks())); + + //add contribution search links. + $action += array_sum(array_keys(self::contributionLinks())); + + if ($dao->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + //CRM-4418 + if (!$allowToDelete) { + $action -= CRM_Core_Action::DELETE; + } + + //build the configure links. + $sectionsInfo = CRM_Utils_Array::value($dao->id, $contriPageSectionInfo, array()); + $contribution[$dao->id]['configureActionLinks'] = CRM_Core_Action::formLink(self::formatConfigureLinks($sectionsInfo), + $action, + array('id' => $dao->id), + ts('Configure'), + TRUE + ); + + //build the contributions links. + $contribution[$dao->id]['contributionLinks'] = CRM_Core_Action::formLink(self::contributionLinks(), + $action, + array('id' => $dao->id), + ts('Contributions'), + TRUE + ); + + //build the online contribution links. + $contribution[$dao->id]['onlineContributionLinks'] = CRM_Core_Action::formLink(self::onlineContributionLinks(), + $action, + array('id' => $dao->id), + ts('Links'), + TRUE + ); + + //build the normal action links. + $contribution[$dao->id]['action'] = CRM_Core_Action::formLink(self::actionLinks(), + $action, + array('id' => $dao->id), + ts('more'), + TRUE + ); + + //show campaigns on selector. + $contribution[$dao->id]['campaign'] = CRM_Utils_Array::value($dao->campaign_id, $allCampaigns); + } + + if (isset($contribution)) { + $this->assign('rows', $contribution); + } + } + + function search() { + if (isset($this->_action) & + (CRM_Core_Action::ADD | + CRM_Core_Action::UPDATE | + CRM_Core_Action::DELETE + ) + ) { + return; + } + + $form = new CRM_Core_Controller_Simple('CRM_Contribute_Form_SearchContribution', + ts('Search Contribution'), + CRM_Core_Action::ADD + ); + $form->setEmbedded(TRUE); + $form->setParent($this); + $form->process(); + $form->run(); + } + + function whereClause(&$params, $sortBy = TRUE) { + $values = $clauses = array(); + $title = $this->get('title'); + $createdId = $this->get('cid'); + + if ($createdId) { + $clauses[] = "(created_id = {$createdId})"; + } + + if ($title) { + $clauses[] = "title LIKE %1"; + if (strpos($title, '%') !== FALSE) { + $params[1] = array(trim($title), 'String', FALSE); + } + else { + $params[1] = array(trim($title), 'String', TRUE); + } + } + + $value = $this->get( 'financial_type_id' ); + $val = array(); + if ($value) { + if (is_array($value)) { + foreach ($value as $k => $v) { + if ($v) { + $val[$k] = $k; + } + } + $type = implode(',', $val); + } + + $clauses[] = "financial_type_id IN ({$type})"; + } + + if ($sortBy && + $this->_sortByCharacter !== NULL + ) { + $clauses[] = "title LIKE '" . strtolower(CRM_Core_DAO::escapeWildCardString($this->_sortByCharacter)) . "%'"; + } + + $campainIds = $this->get('campaign_id'); + if (!CRM_Utils_System::isNull($campainIds)) { + if (!is_array($campainIds)) { + $campaignIds = array($campaignIds); + } + $clauses[] = '( campaign_id IN ( ' . implode(' , ', array_values($campainIds)) . ' ) )'; + } + + if (empty($clauses)) { + // Let template know if user has run a search or not + $this->assign('isSearch', 0); + return 1; + } + else { + $this->assign('isSearch', 1); + } + + return implode(' AND ', $clauses); + } + + function pager($whereClause, $whereParams) { + + $params['status'] = ts('Contribution %%StatusMessage%%'); + $params['csvString'] = NULL; + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + $params['rowCount'] = $this->get(CRM_Utils_Pager::PAGE_ROWCOUNT); + if (!$params['rowCount']) { + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + } + + $query = " +SELECT count(id) + FROM civicrm_contribution_page + WHERE $whereClause"; + + $params['total'] = CRM_Core_DAO::singleValueQuery($query, $whereParams); + + $this->_pager = new CRM_Utils_Pager($params); + $this->assign_by_ref('pager', $this->_pager); + } + + function pagerAtoZ($whereClause, $whereParams) { + + $query = " + SELECT DISTINCT UPPER(LEFT(title, 1)) as sort_name + FROM civicrm_contribution_page + WHERE $whereClause + ORDER BY LEFT(title, 1) +"; + $dao = CRM_Core_DAO::executeQuery($query, $whereParams); + + $aToZBar = CRM_Utils_PagerAToZ::getAToZBar($dao, $this->_sortByCharacter, TRUE); + $this->assign('aToZ', $aToZBar); + } + + function formatConfigureLinks($sectionsInfo) { + //build the formatted configure links. + $formattedConfLinks = self::configureActionLinks(); + foreach ($formattedConfLinks as $act => & $link) { + $sectionName = CRM_Utils_Array::value('uniqueName', $link); + if (!$sectionName) { + continue; + } + + $classes = array(); + if (isset($link['class'])) { + $classes = $link['class']; + } + + if (!CRM_Utils_Array::value($sectionName, $sectionsInfo)) { + $classes = array(); + if (isset($link['class'])) { + $classes = $link['class']; + } + $link['class'] = array_merge($classes, array('disabled')); + } + } + + return $formattedConfLinks; + } +} + diff --git a/CRM/Contribute/Page/ContributionRecur.php b/CRM/Contribute/Page/ContributionRecur.php new file mode 100644 index 0000000000..9a05df42bf --- /dev/null +++ b/CRM/Contribute/Page/ContributionRecur.php @@ -0,0 +1,113 @@ +id = $this->_id; + if ($recur->find(TRUE)) { + $values = array(); + CRM_Core_DAO::storeValues($recur, $values); + // if there is a payment processor ID, get the name of the payment processor + if (CRM_Utils_Array::value('payment_processor_id', $values)) { + $values['payment_processor'] = CRM_Core_DAO::getFieldValue( + 'CRM_Financial_DAO_PaymentProcessor', + $values['payment_processor_id'], + 'name' + ); + } + // get contribution status label + if (CRM_Utils_Array::value('contribution_status_id', $values)) { + $values['contribution_status'] = CRM_Core_OptionGroup::getLabel('contribution_status', $values['contribution_status_id']); + } + + $this->assign('recur', $values); + } + } + + function preProcess() { + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'view'); + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + // set page title + CRM_Contact_Page_View::setTitle($this->_contactId); + + $this->assign('action', $this->_action); + + if ($this->_permission == CRM_Core_Permission::EDIT && !CRM_Core_Permission::check('edit contributions')) { + // demote to view since user does not have edit contrib rights + $this->_permission = CRM_Core_Permission::VIEW; + $this->assign('permission', 'view'); + } + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->view(); + } + + return parent::run(); + } +} + diff --git a/CRM/Contribute/Page/DashBoard.php b/CRM/Contribute/Page/DashBoard.php new file mode 100644 index 0000000000..ce1c640d6c --- /dev/null +++ b/CRM/Contribute/Page/DashBoard.php @@ -0,0 +1,128 @@ +assign($aName, $$aName); + } + + //for contribution tabular View + $buildTabularView = CRM_Utils_Array::value('showtable', $_GET, FALSE); + $this->assign('buildTabularView', $buildTabularView); + if ($buildTabularView) { + return; + } + + // Check for admin permission to see if we should include the Manage Contribution Pages action link + $isAdmin = 0; + if (CRM_Core_Permission::check('administer CiviCRM')) { + $isAdmin = 1; + } + $this->assign('isAdmin', $isAdmin); + } + + /** + * This function is the main function that is called when the page loads, + * it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + $controller = new CRM_Core_Controller_Simple('CRM_Contribute_Form_Search', + ts('Contributions'), NULL + ); + $controller->setEmbedded(TRUE); + + $controller->set('limit', 10); + $controller->set('force', 1); + $controller->set('context', 'dashboard'); + $controller->process(); + $controller->run(); + $chartForm = new CRM_Core_Controller_Simple('CRM_Contribute_Form_ContributionCharts', + ts('Contributions Charts'), NULL + ); + + $chartForm->setEmbedded(TRUE); + $chartForm->process(); + $chartForm->run(); + + return parent::run(); + } +} + diff --git a/CRM/Contribute/Page/ManagePremiums.php b/CRM/Contribute/Page/ManagePremiums.php new file mode 100644 index 0000000000..6cd14349dd --- /dev/null +++ b/CRM/Contribute/Page/ManagePremiums.php @@ -0,0 +1,206 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/contribute/managePremiums', + 'qs' => 'action=update&id=%%id%%&reset=1', + 'title' => ts('Edit Premium'), + ), + CRM_Core_Action::PREVIEW => array( + 'name' => ts('Preview'), + 'url' => 'civicrm/admin/contribute/managePremiums', + 'qs' => 'action=preview&id=%%id%%', + 'title' => ts('Preview Premium'), + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Disable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contribute_BAO_ManagePremiums' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + 'title' => ts('Disable Premium'), + ), + CRM_Core_Action::ENABLE => array( + 'name' => ts('Enable'), + 'extra' => 'onclick = "enableDisable( %%id%%,\'' . 'CRM_Contribute_BAO_ManagePremiums' . '\',\'' . 'disable-enable' . '\' );"', + 'ref' => 'enable-action', + 'title' => ts('Enable Premium'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/admin/contribute/managePremiums', + 'qs' => 'action=delete&id=%%id%%', + 'title' => ts('Delete Premium'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + + // get the requested action + $action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + + // what action to take ? + if ($action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::PREVIEW)) { + $this->edit($action, $id, TRUE); + } + // finally browse the custom groups + $this->browse(); + + // parent run + return parent::run(); + } + + /** + * Browse all custom data groups. + * + * + * @return void + * @access public + * @static + */ + function browse() { + // get all custom groups sorted by weight + $premiums = array(); + $dao = new CRM_Contribute_DAO_Product(); + $dao->orderBy('name'); + $dao->find(); + + while ($dao->fetch()) { + $premiums[$dao->id] = array(); + CRM_Core_DAO::storeValues($dao, $premiums[$dao->id]); + // form all action links + $action = array_sum(array_keys($this->links())); + + + if ($dao->is_active) { + $action -= CRM_Core_Action::ENABLE; + } + else { + $action -= CRM_Core_Action::DISABLE; + } + + $premiums[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(), + $action, + array('id' => $dao->id) + ); + //Financial Type + if( !empty( $dao->financial_type_id ) ){ + require_once 'CRM/Core/DAO.php'; + $premiums[$dao->id]['financial_type_id'] = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_FinancialType', $dao->financial_type_id, 'name' ); + } + } + $this->assign('rows', $premiums); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Contribute_Form_ManagePremiums'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Manage Premiums'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return 'civicrm/admin/contribute/managePremiums'; + } +} + diff --git a/CRM/Contribute/Page/Premium.php b/CRM/Contribute/Page/Premium.php new file mode 100644 index 0000000000..bec789a06f --- /dev/null +++ b/CRM/Contribute/Page/Premium.php @@ -0,0 +1,222 @@ + array( + 'name' => ts('Edit'), + 'url' => 'civicrm/admin/contribute/addProductToPage', + 'qs' => 'action=update&id=%%id%%&pid=%%pid%%&reset=1', + 'title' => ts('Edit Premium'), + ), + CRM_Core_Action::PREVIEW => array( + 'name' => ts('Preview'), + 'url' => 'civicrm/admin/contribute/addProductToPage', + 'qs' => 'action=preview&id=%%id%%&pid=%%pid%%', + 'title' => ts('Preview Premium'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Remove'), + 'url' => 'civicrm/admin/contribute/addProductToPage', + 'qs' => 'action=delete&id=%%id%%&pid=%%pid%%', + 'extra' => 'onclick = "if (confirm(\'' . $deleteExtra . '\') ) this.href+=\'&confirmed=1\'; else return false;"', + 'title' => ts('Disable Premium'), + ), + ); + } + return self::$_links; + } + + /** + * Run the page. + * + * This method is called after the page is created. It checks for the + * type of action and executes that action. + * Finally it calls the parent's run method. + * + * @return void + * @access public + * + */ + function run() { + // get the requested action + $action = CRM_Utils_Request::retrieve('action', 'String', + // default to 'browse' + $this, FALSE, 'browse' + ); + + // assign vars to templates + $this->assign('action', $action); + $id = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + $this->assign('id', $id); + + $this->edit($action, $id, FALSE, FALSE); + + // this is special case where we need to call browse to list premium + if ($action == CRM_Core_Action::UPDATE) { + $this->browse(); + } + + // parent run + return parent::run(); + } + + /** + * + * @return void + * @access public + * @static + */ + function browse() { + // get all custom groups sorted by weight + $premiums = array(); + $pageID = CRM_Utils_Request::retrieve('id', 'Positive', + $this, FALSE, 0 + ); + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $pageID; + $dao->find(TRUE); + $premiumID = $dao->id; + $this->assign('products', FALSE); + $this->assign('id', $pageID); + if (!$premiumID) { + return; + } + + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->premiums_id = $premiumID; + $dao->orderBy('weight'); + $dao->find(); + + while ($dao->fetch()) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $dao->product_id; + $productDAO->is_active = 1; + + if ($productDAO->find(TRUE)) { + $premiums[$productDAO->id] = array(); + $premiums[$productDAO->id]['weight'] = $dao->weight; + CRM_Core_DAO::storeValues($productDAO, $premiums[$productDAO->id]); + + $action = array_sum(array_keys($this->links())); + + $premiums[$dao->product_id]['action'] = CRM_Core_Action::formLink(self::links(), $action, + array('id' => $pageID, 'pid' => $dao->id) + ); + //Financial Type + if (!empty($dao->financial_type_id)) { + $premiums[$productDAO->id]['financial_type_id'] = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_FinancialType', $dao->financial_type_id, 'name' ); + } + } + } + + if (count(CRM_Contribute_PseudoConstant::products($pageID)) == 0) { + $this->assign('products', FALSE); + } + else { + $this->assign('products', TRUE); + } + + // Add order changing widget to selector + $returnURL = CRM_Utils_System::url('civicrm/admin/contribute/premium', "reset=1&action=update&id={$pageID}"); + $filter = "premiums_id = {$premiumID}"; + CRM_Utils_Weight::addOrder($premiums, 'CRM_Contribute_DAO_PremiumsProduct', + 'id', $returnURL, $filter + ); + $this->assign('rows', $premiums); + } + + /** + * Get name of edit form + * + * @return string Classname of edit form. + */ + function editForm() { + return 'CRM_Contribute_Form_ContributionPage_Premium'; + } + + /** + * Get edit form name + * + * @return string name of this page. + */ + function editName() { + return 'Configure Premiums'; + } + + /** + * Get user context. + * + * @return string user context. + */ + function userContext($mode = NULL) { + return CRM_Utils_System::currentPath(); + } +} + diff --git a/CRM/Contribute/Page/SubscriptionStatus.php b/CRM/Contribute/Page/SubscriptionStatus.php new file mode 100644 index 0000000000..5af37fa296 --- /dev/null +++ b/CRM/Contribute/Page/SubscriptionStatus.php @@ -0,0 +1,63 @@ +assign('task', $task); + $this->assign('result', $result); + + if ( $task == 'billing' ) { + $session = CRM_Core_Session::singleton(); + $tplParams = $session->get('resultParams'); + foreach ( $tplParams as $key => $val ) { + $this->assign($key, $val); + } + } + + return parent::run(); + } +} + diff --git a/CRM/Contribute/Page/Tab.php b/CRM/Contribute/Page/Tab.php new file mode 100644 index 0000000000..0cf65a2860 --- /dev/null +++ b/CRM/Contribute/Page/Tab.php @@ -0,0 +1,534 @@ + array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view/contribution', + 'qs' => 'reset=1&id=%%id%%&cid=%%cid%%&honorId=%%honorId%%&action=view&context=%%cxt%%&selectedChild=contribute', + 'title' => ts('View Contribution'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/view/contribution', + 'qs' => 'reset=1&action=update&id=%%id%%&cid=%%cid%%&honorId=%%honorId%%&context=%%cxt%%&subType=%%contributionType%%', + 'title' => ts('Edit Contribution'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/contribution', + 'qs' => 'reset=1&action=delete&id=%%id%%&cid=%%cid%%&honorId=%%honorId%%&context=%%cxt%%', + 'title' => ts('Delete Contribution'), + ), + ); + } + return self::$_honorLinks; + } + //end of function + + /** + * This method returns the links that are given for recur search row. + * currently the links added for each row are: + * - View + * - Edit + * - Cancel + * + * @return array + * @access public + * + */ + static function &recurLinks($recurID = FALSE, $context = 'contribution') { + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'title' => ts('View Recurring Payment'), + 'url' => 'civicrm/contact/view/contributionrecur', + 'qs' => "reset=1&id=%%crid%%&cid=%%cid%%&context={$context}", + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'title' => ts('Edit Recurring Payment'), + 'url' => 'civicrm/contribute/updaterecur', + 'qs' => "reset=1&action=update&crid=%%crid%%&cid=%%cid%%&context={$context}", + ), + CRM_Core_Action::DISABLE => array( + 'name' => ts('Cancel'), + 'title' => ts('Cancel'), + 'extra' => 'onclick = "enableDisable( %%crid%%,\'' . 'CRM_Contribute_BAO_ContributionRecur' . '\',\'' . 'enable-disable' . '\' );"', + 'ref' => 'disable-action', + ), + ); + } + + if ($recurID) { + $paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($recurID, 'recur', 'obj'); + if (is_object( $paymentProcessorObj) && $paymentProcessorObj->isSupported('cancelSubscription')) { + unset(self::$_links[CRM_Core_Action::DISABLE]['extra'], self::$_links[CRM_Core_Action::DISABLE]['ref']); + self::$_links[CRM_Core_Action::DISABLE]['url'] = "civicrm/contribute/unsubscribe"; + self::$_links[CRM_Core_Action::DISABLE]['qs'] = "reset=1&crid=%%crid%%&cid=%%cid%%&context={$context}"; + } + if (is_object( $paymentProcessorObj) && $paymentProcessorObj->isSupported('updateSubscriptionBillingInfo')) { + self::$_links[CRM_Core_Action::RENEW] = array('name' => ts('Change Billing Details'), + 'title' => ts('Change Billing Details'), + 'url' => 'civicrm/contribute/updatebilling', + 'qs' => "reset=1&crid=%%crid%%&cid=%%cid%%&context={$context}", + ); + } + } + + return self::$_links; + } + // end function + + /** + * This function is called when action is browse + * + * return null + * @access public + */ + function browse() { + + // add annual contribution + $annual = array(); + list($annual['count'], + $annual['amount'], + $annual['avg'] + ) = CRM_Contribute_BAO_Contribution::annual($this->_contactId); + $this->assign('annual', $annual); + + $controller = new CRM_Core_Controller_Simple( + 'CRM_Contribute_Form_Search', + ts('Contributions'), + $this->_action, + FALSE, FALSE, TRUE + ); + $controller->setEmbedded(TRUE); + $controller->reset(); + $controller->set('cid', $this->_contactId); + $controller->set('crid', $this->_crid); + $controller->set('context', 'contribution'); + $controller->process(); + $controller->run(); + + // add recurring block + $action = array_sum(array_keys($this->recurLinks())); + $params = CRM_Contribute_BAO_ContributionRecur::getRecurContributions($this->_contactId); + + if (!empty($params)) { + foreach ($params as $ids => $recur) { + $action = array_sum(array_keys($this->recurLinks($ids))); + // no action allowed if it's not active + $params[$ids]['is_active'] = ($recur['contribution_status_id'] != 3); + + if ($params[$ids]['is_active']) { + $details = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($params[$ids]['id'], 'recur'); + $hideUpdate = $details->membership_id & $details->auto_renew; + + if ($hideUpdate) { + $action -= CRM_Core_Action::UPDATE; + } + + $params[$ids]['action'] = CRM_Core_Action::formLink(self::recurLinks($ids), $action, + array( + 'cid' => $this->_contactId, + 'crid' => $ids, + 'cxt' => 'contribution', + ) + ); + } + } + // assign vars to templates + $this->assign('action', $this->_action); + $this->assign('recurRows', $params); + $this->assign('recur', TRUE); + } + + //add honor block + // form all action links + $action = array_sum(array_keys($this->honorLinks())); + + $params = array(); + $params = CRM_Contribute_BAO_Contribution::getHonorContacts($this->_contactId); + if (!empty($params)) { + foreach ($params as $ids => $honorId) { + $params[$ids]['action'] = CRM_Core_Action::formLink( + self::honorLinks(), + $action, + array( + 'cid' => $honorId['honorId'], + 'id' => $ids, + 'cxt' => 'contribution', + 'contributionType' => $honorId['type_id'], + 'honorId' => $this->_contactId, + ) + ); + } + + // assign vars to templates + $this->assign('action', $this->_action); + $this->assign('honorRows', $params); + $this->assign('honor', TRUE); + } + + //enable/disable soft credit records for test contribution + $isTest = 0; + if (CRM_Utils_Request::retrieve('isTest', 'Positive', $this)) { + $isTest = 1; + } + $this->assign('isTest', $isTest); + + $softCreditList = CRM_Contribute_BAO_Contribution::getSoftContributionList($this->_contactId, $isTest); + + if (!empty($softCreditList)) { + $softCreditTotals = array(); + + list($softCreditTotals['amount'], + $softCreditTotals['avg'], + $softCreditTotals['currency'] + ) = CRM_Contribute_BAO_Contribution::getSoftContributionTotals($this->_contactId, $isTest); + + $this->assign('softCredit', TRUE); + $this->assign('softCreditRows', $softCreditList); + $this->assign('softCreditTotals', $softCreditTotals); + } + + if ($this->_contactId) { + $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); + $this->assign('displayName', $displayName); + } + } + + /** + * This function is called when action is view + * + * return null + * @access public + */ + function view() { + $controller = new CRM_Core_Controller_Simple( + 'CRM_Contribute_Form_ContributionView', + ts('View Contribution'), + $this->_action + ); + $controller->setEmbedded(TRUE); + $controller->set('id', $this->_id); + $controller->set('cid', $this->_contactId); + + return $controller->run(); + } + + /** + * This function is called when action is update or new + * + * return null + * @access public + */ + function edit() { + // set https for offline cc transaction + $mode = CRM_Utils_Request::retrieve('mode', 'String', $this); + if ($mode == 'test' || $mode == 'live') { + CRM_Utils_System::redirectToSSL(); + } + + $controller = new CRM_Core_Controller_Simple( + 'CRM_Contribute_Form_Contribution', + 'Create Contribution', + $this->_action + ); + $controller->setEmbedded(TRUE); + $controller->set('id', $this->_id); + $controller->set('cid', $this->_contactId); + + return $controller->run(); + } + + function preProcess() { + $context = CRM_Utils_Request::retrieve('context', 'String', $this); + $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse'); + $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this); + + if ($context == 'standalone') { + $this->_action = CRM_Core_Action::ADD; + } + else { + $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); + $this->assign('contactId', $this->_contactId); + + // check logged in url permission + CRM_Contact_Page_View::checkUserPermission($this); + + // set page title + CRM_Contact_Page_View::setTitle($this->_contactId); + } + $this->assign('action', $this->_action); + + if ($this->_permission == CRM_Core_Permission::EDIT && !CRM_Core_Permission::check('edit contributions')) { + // demote to view since user does not have edit contrib rights + $this->_permission = CRM_Core_Permission::VIEW; + $this->assign('permission', 'view'); + } + } + + /** + * This function is the main function that is called when the page + * loads, it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + $this->preProcess(); + + // check if we can process credit card contribs + CRM_Core_Payment::allowBackofficeCreditCard($this); + + $this->setContext(); + + if ($this->_action & CRM_Core_Action::VIEW) { + $this->view(); + } + elseif ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::DELETE)) { + $this->edit(); + } + else { + $this->browse(); + } + + return parent::run(); + } + + function setContext() { + $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); + $context = CRM_Utils_Request::retrieve('context', 'String', + $this, FALSE, 'search' + ); + $compContext = CRM_Utils_Request::retrieve('compContext', 'String', $this); + + //swap the context. + if ($context == 'search' && $compContext) { + $context = $compContext; + } + else { + $compContext = NULL; + } + + // make sure we dont get tricked with a bad key + // so check format + if (!CRM_Core_Key::valid($qfKey)) { + $qfKey = NULL; + } + + $session = CRM_Core_Session::singleton(); + + switch ($context) { + case 'user': + $url = CRM_Utils_System::url('civicrm/user', 'reset=1'); + break; + + case 'dashboard': + $url = CRM_Utils_System::url('civicrm/contribute', + 'reset=1' + ); + break; + + case 'pledgeDashboard': + $url = CRM_Utils_System::url('civicrm/pledge', + 'reset=1' + ); + break; + + case 'contribution': + $honorId = CRM_Utils_Request::retrieve('honorId', 'Positive', $this, FALSE); + + if ($honorId) { + $cid = $honorId; + } + else { + $cid = $this->_contactId; + } + + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&force=1&cid={$cid}&selectedChild=contribute" + ); + break; + + case 'search': + case 'advanced': + $extraParams = "force=1"; + if ($qfKey) { + $extraParams .= "&qfKey=$qfKey"; + } + + $this->assign('searchKey', $qfKey); + if ($context == 'advanced') { + $url = CRM_Utils_System::url('civicrm/contact/search/advanced', $extraParams); + } + else { + $url = CRM_Utils_System::url('civicrm/contribute/search', $extraParams); + } + break; + + case 'home': + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + break; + + case 'activity': + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&force=1&cid={$this->_contactId}&selectedChild=activity" + ); + break; + + case 'member': + case 'membership': + $componentId = CRM_Utils_Request::retrieve('compId', 'Positive', $this); + $componentAction = CRM_Utils_Request::retrieve('compAction', 'Integer', $this); + + $context = 'membership'; + $searchKey = NULL; + if ($compContext) { + $context = 'search'; + if ($qfKey) { + $searchKey = "&key=$qfKey"; + } + $compContext = "&compContext={$compContext}"; + } + if ($componentAction & CRM_Core_Action::VIEW) { + $action = 'view'; + } + else { + $action = 'update'; + } + $url = CRM_Utils_System::url('civicrm/contact/view/membership', + "reset=1&action={$action}&id={$componentId}&cid={$this->_contactId}&context={$context}&selectedChild=member{$searchKey}{$compContext}" + ); + break; + + case 'participant': + $componentId = CRM_Utils_Request::retrieve('compId', 'Positive', $this); + $componentAction = CRM_Utils_Request::retrieve('compAction', 'Integer', $this); + + $context = 'participant'; + $searchKey = NULL; + if ($compContext) { + $context = 'search'; + if ($qfKey) { + $searchKey = "&key=$qfKey"; + } + $compContext = "&compContext={$compContext}"; + } + if ($componentAction == CRM_Core_Action::VIEW) { + $action = 'view'; + } + else { + $action = 'update'; + } + $url = CRM_Utils_System::url('civicrm/contact/view/participant', + "reset=1&action={$action}&id={$componentId}&cid={$this->_contactId}&context={$context}&selectedChild=event{$searchKey}{$compContext}" + ); + break; + + case 'pledge': + $url = CRM_Utils_System::url('civicrm/contact/view', + "reset=1&force=1&cid={$this->_contactId}&selectedChild=pledge" + ); + break; + + case 'standalone': + $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); + break; + + case 'fulltext': + $keyName = '&qfKey'; + $urlParams = 'force=1'; + $urlString = 'civicrm/contact/search/custom'; + if ($this->_action == CRM_Core_Action::UPDATE) { + if ($this->_contactId) { + $urlParams .= '&cid=' . $this->_contactId; + } + $keyName = '&key'; + $urlParams .= '&context=fulltext&action=view'; + $urlString = 'civicrm/contact/view/contribution'; + } + if ($qfKey) { + $urlParams .= "$keyName=$qfKey"; + } + $this->assign('searchKey', $qfKey); + $url = CRM_Utils_System::url($urlString, $urlParams); + break; + + default: + $cid = NULL; + if ($this->_contactId) { + $cid = '&cid=' . $this->_contactId; + } + $url = CRM_Utils_System::url('civicrm/contribute/search', + 'reset=1&force=1' . $cid + ); + break; + } + + $session = CRM_Core_Session::singleton(); + $session->pushUserContext($url); + } +} + diff --git a/CRM/Contribute/Page/UserDashboard.php b/CRM/Contribute/Page/UserDashboard.php new file mode 100644 index 0000000000..e5d277ddc3 --- /dev/null +++ b/CRM/Contribute/Page/UserDashboard.php @@ -0,0 +1,149 @@ +setEmbedded(TRUE); + $controller->reset(); + $controller->set('limit', 12); + $controller->set('cid', $this->_contactId); + $controller->set('context', 'user'); + $controller->set('force', 1); + $controller->process(); + $controller->run(); + + //add honor block + $params = array(); + $params = CRM_Contribute_BAO_Contribution::getHonorContacts($this->_contactId); + + if (!empty($params)) { + // assign vars to templates + $this->assign('honorRows', $params); + $this->assign('honor', TRUE); + } + + + $recur = new CRM_Contribute_DAO_ContributionRecur(); + $recur->contact_id = $this->_contactId; + $recur->is_test = 0; + $recur->find(); + + $config = CRM_Core_Config::singleton(); + + $recurStatus = CRM_Contribute_PseudoConstant::contributionStatus(); + + $recurRow = array(); + $recurIDs = array(); + while ($recur->fetch()) { + $mode = $recur->is_test ? 'test' : 'live'; + $paymentProcessor = CRM_Contribute_BAO_ContributionRecur::getPaymentProcessor($recur->id, + $mode + ); + if (!$paymentProcessor) { + continue; + } + + // note that we are passing a CRM_Core_Page object ($this) as if it were a form here: + $paymentObject = CRM_Core_Payment::singleton($mode, $paymentProcessor, $this); + + require_once 'api/v3/utils.php'; + //@todo calling api functions directly is not supported + _civicrm_api3_object_to_array($recur, $values); + + $values['recur_status'] = $recurStatus[$values['contribution_status_id']]; + $recurRow[$values['id']] = $values; + + $action = array_sum(array_keys(CRM_Contribute_Page_Tab::recurLinks($recur->id, 'dashboard'))); + + $details = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recur->id, 'recur'); + $hideUpdate = $details->membership_id & $details->auto_renew; + + if ($hideUpdate) { + $action -= CRM_Core_Action::UPDATE; + } + + $recurRow[$values['id']]['action'] = CRM_Core_Action::formLink(CRM_Contribute_Page_Tab::recurLinks($recur->id, 'dashboard'), + $action, array( + 'cid' => $this->_contactId, + 'crid' => $values['id'], + 'cxt' => 'contribution', + ) + ); + + $recurIDs[] = $values['id']; + + //reset $paymentObject for checking other paymenet processor + //recurring url + $paymentObject = NULL; + } + if (is_array($recurIDs) && !empty($recurIDs)) { + $getCount = CRM_Contribute_BAO_ContributionRecur::getCount($recurIDs); + foreach ($getCount as $key => $val) { + $recurRow[$key]['completed'] = $val; + $recurRow[$key]['link'] = CRM_Utils_System::url('civicrm/contribute/search', + "reset=1&force=1&recur=$key" + ); + } + } + + $this->assign('recurRows', $recurRow); + if (!empty($recurRow)) { + $this->assign('recur', TRUE); + } + else { + $this->assign('recur', FALSE); + } + } + + /** + * This function is the main function that is called when the page + * loads, it decides the which action has to be taken for the page. + * + * return null + * @access public + */ + function run() { + parent::preProcess(); + $this->listContribution(); + } +} + diff --git a/CRM/Contribute/PseudoConstant.php b/CRM/Contribute/PseudoConstant.php new file mode 100644 index 0000000000..5929744fc0 --- /dev/null +++ b/CRM/Contribute/PseudoConstant.php @@ -0,0 +1,415 @@ + $value) { + $acceptCreditCard[$value] = $value; + } + return $acceptCreditCard; + } + + /** + * Get all premiums + * + * @access public + * + * @return array - array of all Premiums if any + * @static + */ + public static function products($pageID = NULL) { + $products = array(); + $dao = new CRM_Contribute_DAO_Product(); + $dao->is_active = 1; + $dao->orderBy('id'); + $dao->find(); + + while ($dao->fetch()) { + $products[$dao->id] = $dao->name; + } + if ($pageID) { + $dao = new CRM_Contribute_DAO_Premium(); + $dao->entity_table = 'civicrm_contribution_page'; + $dao->entity_id = $pageID; + $dao->find(TRUE); + $premiumID = $dao->id; + + $productID = array(); + + $dao = new CRM_Contribute_DAO_PremiumsProduct(); + $dao->premiums_id = $premiumID; + $dao->find(); + while ($dao->fetch()) { + $productID[$dao->product_id] = $dao->product_id; + } + + $tempProduct = array(); + foreach ($products as $key => $value) { + if (!array_key_exists($key, $productID)) { + $tempProduct[$key] = $value; + } + } + + return $tempProduct; + } + + return $products; + } + + /** + * Get all the contribution statuses + * + * @access public + * + * @return array - array reference of all contribution statuses + * @static + */ + public static function &contributionStatus($id = NULL, $columnName = 'label') { + $cacheKey = $columnName; + if (!isset(self::$contributionStatus[$cacheKey])) { + self::$contributionStatus[$cacheKey] = CRM_Core_OptionGroup::values('contribution_status', + FALSE, FALSE, FALSE, NULL, $columnName + ); + } + $result = self::$contributionStatus[$cacheKey]; + if ($id) { + $result = CRM_Utils_Array::value($id, $result); + } + + return $result; + } + + /** + * Get all the Personal campaign pages + * + * @access public + * + * @return array - array reference of all pcp if any + * @static + */ + public static function &pcPage($pageType = NULL, $id = NULL) { + if (!isset(self::$pcPage[$pageType])) { + if ($pageType) { + $params = "page_type='{$pageType}'"; + } + else { + $params = ''; + } + CRM_Core_PseudoConstant::populate(self::$pcPage[$pageType], + 'CRM_PCP_DAO_PCP', + FALSE, 'title', 'is_active', $params + ); + } + $result = self::$pcPage[$pageType]; + if ($id) { + return $result = CRM_Utils_Array::value($id, $result); + } + + return $result; + } + + /** + * Get all PCP Statuses. + * + * The static array pcpStatus is returned + * + * @access public + * @static + * + * @return array - array reference of all PCP activity statuses + */ + public static function &pcpStatus($column = 'label') { + if (NULL === self::$pcpStatus) { + self::$pcpStatus = array(); + } + if (!array_key_exists($column, self::$pcpStatus)) { + self::$pcpStatus[$column] = array(); + + self::$pcpStatus[$column] = CRM_Core_OptionGroup::values('pcp_status', FALSE, + FALSE, FALSE, NULL, $column + ); + } + return self::$pcpStatus[$column]; + } + + /** + * Get all financial accounts for a Financial type. + * + * The static array $financialTypeAccount is returned + * + * @access public + * @static + * + * @return array - array reference of all financial accounts for a Financial type + */ + public static function financialAccountType($financialTypeId, $relationTypeId = NULL) { + if (!CRM_Utils_Array::value($financialTypeId, self::$financialTypeAccount)) { + $condition = " entity_id = $financialTypeId "; + CRM_Core_PseudoConstant::populate( + self::$financialTypeAccount[$financialTypeId], + 'CRM_Financial_DAO_EntityFinancialAccount', + $all = true, + $retrieve = 'financial_account_id', + $filter = NULL, + $condition, + NULL, + 'account_relationship' + ); + } + + if ($relationTypeId) { + return CRM_Utils_Array::value($relationTypeId, self::$financialTypeAccount[$financialTypeId]); + } + + return self::$financialTypeAccount[$financialTypeId]; + } +} + diff --git a/CRM/Contribute/Selector/Search.php b/CRM/Contribute/Selector/Search.php new file mode 100644 index 0000000000..7cf3364c89 --- /dev/null +++ b/CRM/Contribute/Selector/Search.php @@ -0,0 +1,501 @@ +_queryParams = &$queryParams; + + $this->_single = $single; + $this->_limit = $limit; + $this->_context = $context; + $this->_compContext = $compContext; + + $this->_contributionClause = $contributionClause; + + // type of selector + $this->_action = $action; + + $this->_query = new CRM_Contact_BAO_Query($this->_queryParams, + CRM_Contribute_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CONTRIBUTE, + FALSE + ), + NULL, FALSE, FALSE, + CRM_Contact_BAO_Query::MODE_CONTRIBUTE + ); + $this->_query->_distinctComponentClause = " civicrm_contribution.id"; + $this->_query->_groupByComponentClause = " GROUP BY civicrm_contribution.id "; + } + //end of constructor + + /** + * This method returns the links that are given for each search row. + * currently the links added for each row are + * + * - View + * - Edit + * + * @return array + * @access public + * + */ + static function &links($componentId = NULL, $componentAction = NULL, $key = NULL, $compContext = NULL) { + $extraParams = NULL; + if ($componentId) { + $extraParams = "&compId={$componentId}&compAction={$componentAction}"; + } + if ($compContext) { + $extraParams .= "&compContext={$compContext}"; + } + if ($key) { + $extraParams .= "&key={$key}"; + } + + if (!(self::$_links)) { + self::$_links = array( + CRM_Core_Action::VIEW => array( + 'name' => ts('View'), + 'url' => 'civicrm/contact/view/contribution', + 'qs' => "reset=1&id=%%id%%&cid=%%cid%%&action=view&context=%%cxt%%&selectedChild=contribute{$extraParams}", + 'title' => ts('View Contribution'), + ), + CRM_Core_Action::UPDATE => array( + 'name' => ts('Edit'), + 'url' => 'civicrm/contact/view/contribution', + 'qs' => "reset=1&action=update&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}", + 'title' => ts('Edit Contribution'), + ), + CRM_Core_Action::DELETE => array( + 'name' => ts('Delete'), + 'url' => 'civicrm/contact/view/contribution', + 'qs' => "reset=1&action=delete&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}", + 'title' => ts('Delete Contribution'), + ), + ); + } + return self::$_links; + } + //end of function + + /** + * getter for array of the parameters required for creating pager. + * + * @param + * @access public + */ + function getPagerParams($action, &$params) { + $params['status'] = ts('Contribution') . ' %%StatusMessage%%'; + $params['csvString'] = NULL; + if ($this->_limit) { + $params['rowCount'] = $this->_limit; + } + else { + $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT; + } + + $params['buttonTop'] = 'PagerTopButton'; + $params['buttonBottom'] = 'PagerBottomButton'; + } + //end of function + + /** + * Returns total number of rows for the query. + * + * @param + * + * @return int Total number of rows + * @access public + */ + function getTotalCount($action) { + return $this->_query->searchQuery(0, 0, NULL, + TRUE, FALSE, + FALSE, FALSE, + FALSE, + $this->_contributionClause + ); + } + + /** + * returns all the rows in the given offset and rowCount + * + * @param enum $action the action being performed + * @param int $offset the row number to start from + * @param int $rowCount the number of rows to return + * @param string $sort the sql string that describes the sort order + * @param enum $output what should the result set include (web/email/csv) + * + * @return int the total number of rows for this action + */ + function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { + $result = $this->_query->searchQuery($offset, $rowCount, $sort, + FALSE, FALSE, + FALSE, FALSE, + FALSE, + $this->_contributionClause + ); + // process the result of the query + $rows = array(); + + //CRM-4418 check for view/edit/delete + $permissions = array(CRM_Core_Permission::VIEW); + if (CRM_Core_Permission::check('edit contributions')) { + $permissions[] = CRM_Core_Permission::EDIT; + } + if (CRM_Core_Permission::check('delete in CiviContribute')) { + $permissions[] = CRM_Core_Permission::DELETE; + } + $mask = CRM_Core_Action::mask($permissions); + + $qfKey = $this->_key; + $componentId = $componentContext = NULL; + if ($this->_context != 'contribute') { + $qfKey = CRM_Utils_Request::retrieve('key', 'String', CRM_Core_DAO::$_nullObject); + $componentId = CRM_Utils_Request::retrieve('id', 'Positive', CRM_Core_DAO::$_nullObject); + $componentAction = CRM_Utils_Request::retrieve('action', 'String', CRM_Core_DAO::$_nullObject); + $componentContext = CRM_Utils_Request::retrieve('compContext', 'String', CRM_Core_DAO::$_nullObject); + + if (!$componentContext && + $this->_compContext + ) { + $componentContext = $this->_compContext; + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', CRM_Core_DAO::$_nullObject, NULL, FALSE, 'REQUEST'); + } + } + + // get all contribution status + $contributionStatuses = CRM_Core_OptionGroup::values('contribution_status', + FALSE, FALSE, FALSE, NULL, 'name', FALSE + ); + + //get all campaigns. + $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); + + While ($result->fetch()) { + $row = array(); + // the columns we are interested in + foreach (self::$_properties as $property) { + if (property_exists($result, $property)) { + $row[$property] = $result->$property; + } + } + + //carry campaign on selectors. + $row['campaign'] = CRM_Utils_Array::value($result->contribution_campaign_id, $allCampaigns); + $row['campaign_id'] = $result->contribution_campaign_id; + + // add contribution status name + $row['contribution_status_name'] = CRM_Utils_Array::value($row['contribution_status_id'], + $contributionStatuses + ); + + if ($result->is_pay_later && CRM_Utils_Array::value('contribution_status_name', $row) == 'Pending') { + $row['contribution_status'] .= ' (' . ts('Pay Later') . ')'; + } + elseif (CRM_Utils_Array::value('contribution_status_name', $row) == 'Pending') { + $row['contribution_status'] .= ' (' . ts('Incomplete Transaction') . ')'; + } + + if ($row['is_test']) { + $row['financial_type'] = $row['financial_type'] . ' (' . ts('test') . ')'; + } + + $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->contribution_id; + + + + $actions = array( + 'id' => $result->contribution_id, + 'cid' => $result->contact_id, + 'cxt' => $this->_context, + ); + + $row['action'] = CRM_Core_Action::formLink(self::links($componentId, + $componentAction, + $qfKey, + $componentContext + ), + $mask, $actions + ); + + $row['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? + $result->contact_sub_type : $result->contact_type, FALSE, $result->contact_id + ); + + if (CRM_Utils_Array::value('amount_level', $row)) { + CRM_Event_BAO_Participant::fixEventLevel($row['amount_level']); + } + + $rows[] = $row; + } + + return $rows; + } + + /** + * + * @return array $qill which contains an array of strings + * @access public + */ + + // the current internationalisation is bad, but should more or less work + // for most of "European" languages + public function getQILL() { + return $this->_query->qill(); + } + + /** + * returns the column headers as an array of tuples: + * (name, sortName (key to the sort array)) + * + * @param string $action the action being performed + * @param enum $output what should the result set include (web/email/csv) + * + * @return array the column headers that need to be displayed + * @access public + */ + public function &getColumnHeaders($action = NULL, $output = NULL) { + if (!isset(self::$_columnHeaders)) { + self::$_columnHeaders = array( + array( + 'name' => ts('Amount'), + 'sort' => 'total_amount', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('name' => ts('Type'), + 'sort' => 'financial_type_id', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Source'), + 'sort' => 'contribution_source', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Received'), + 'sort' => 'receive_date', + 'direction' => CRM_Utils_Sort::DESCENDING, + ), + array( + 'name' => ts('Thank-you Sent'), + 'sort' => 'thankyou_date', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Status'), + 'sort' => 'contribution_status_id', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array( + 'name' => ts('Premium'), + 'sort' => 'product_name', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + array('desc' => ts('Actions')), + ); + + if (!$this->_single) { + $pre = array( + array('desc' => ts('Contact Type')), + array( + 'name' => ts('Name'), + 'sort' => 'sort_name', + 'direction' => CRM_Utils_Sort::DONTCARE, + ), + ); + self::$_columnHeaders = array_merge($pre, self::$_columnHeaders); + } + } + return self::$_columnHeaders; + } + + function alphabetQuery() { + return $this->_query->searchQuery(NULL, NULL, NULL, FALSE, FALSE, TRUE); + } + + function &getQuery() { + return $this->_query; + } + + /** + * name of export file. + * + * @param string $output type of output + * + * @return string name of the file + */ + function getExportFileName($output = 'csv') { + return ts('CiviCRM Contribution Search'); + } + + function getSummary() { + return $this->_query->summaryContribution($this->_context); + } +} +//end of class + diff --git a/CRM/Contribute/StateMachine/Contribution.php b/CRM/Contribute/StateMachine/Contribution.php new file mode 100644 index 0000000000..3161ad90e0 --- /dev/null +++ b/CRM/Contribute/StateMachine/Contribution.php @@ -0,0 +1,62 @@ +_pages = array( + 'CRM_Contribute_Form_Contribution_Main' => NULL, + 'CRM_Contribute_Form_Contribution_Confirm' => NULL, + 'CRM_Contribute_Form_Contribution_ThankYou' => NULL, + ); + + $this->addSequentialPages($this->_pages, $action); + } +} + diff --git a/CRM/Contribute/StateMachine/ContributionPage.php b/CRM/Contribute/StateMachine/ContributionPage.php new file mode 100644 index 0000000000..87fc6e058c --- /dev/null +++ b/CRM/Contribute/StateMachine/ContributionPage.php @@ -0,0 +1,77 @@ +set('singleForm', FALSE); + + $config = CRM_Core_Config::singleton(); + + $this->_pages = array( + 'CRM_Contribute_Form_ContributionPage_Settings' => NULL, + 'CRM_Contribute_Form_ContributionPage_Amount' => NULL, + 'CRM_Member_Form_MembershipBlock' => NULL, + 'CRM_Contribute_Form_ContributionPage_ThankYou' => NULL, + 'CRM_Friend_Form_Contribute' => NULL, + 'CRM_PCP_Form_Contribute' => NULL, + 'CRM_Contribute_Form_ContributionPage_Custom' => NULL, + 'CRM_Contribute_Form_ContributionPage_Premium' => NULL, + 'CRM_Contribute_Form_ContributionPage_Widget' => NULL, + ); + + if (!in_array("CiviMember", $config->enableComponents)) { + unset($this->_pages['CRM_Member_Form_MembershipBlock']); + } + + $this->addSequentialPages($this->_pages, $action); + } +} + diff --git a/CRM/Contribute/StateMachine/Search.php b/CRM/Contribute/StateMachine/Search.php new file mode 100644 index 0000000000..002eae2d9e --- /dev/null +++ b/CRM/Contribute/StateMachine/Search.php @@ -0,0 +1,115 @@ +_pages = array(); + + $this->_pages['CRM_Contribute_Form_Search'] = NULL; + list($task, $result) = $this->taskName($controller, 'Search'); + $this->_task = $task; + + if (is_array($task)) { + foreach ($task as $t) { + $this->_pages[$t] = NULL; + } + } + else { + $this->_pages[$task] = NULL; + } + if ($result) { + $this->_pages['CRM_Contribute_Form_Task_Result'] = NULL; + } + $this->addSequentialPages($this->_pages, $action); + } + + /** + * Determine the form name based on the action. This allows us + * to avoid using conditional state machine, much more efficient + * and simpler + * + * @param CRM_Core_Controller $controller the controller object + * + * @return string the name of the form that will handle the task + * @access protected + */ + function taskName($controller, $formName = 'Search') { + // total hack, check POST vars and then session to determine stuff + // fix value if print button is pressed + if (CRM_Utils_Array::value('_qf_' . $formName . '_next_print', $_POST)) { + $value = CRM_Contribute_Task::PRINT_CONTRIBUTIONS; + } + else { + $value = CRM_Utils_Array::value('task', $_POST); + } + if (!isset($value)) { + $value = $this->_controller->get('task'); + } + $this->_controller->set('task', $value); + return CRM_Contribute_Task::getTask($value); + } + + /** + * return the form name of the task + * + * @return string + * @access public + */ + function getTaskFormName() { + return CRM_Utils_String::getClassName($this->_task); + } + + /** + * Since this is a state machine for search and we want to come back to the same state + * we dont want to issue a reset of the state session when we are done processing a task + * + */ + function shouldReset() { + return FALSE; + } +} + diff --git a/CRM/Contribute/Task.php b/CRM/Contribute/Task.php new file mode 100644 index 0000000000..1d583b9a89 --- /dev/null +++ b/CRM/Contribute/Task.php @@ -0,0 +1,196 @@ + array('title' => ts('Delete Contributions'), + 'class' => 'CRM_Contribute_Form_Task_Delete', + 'result' => FALSE, + ), + 2 => array('title' => ts('Print Contributions'), + 'class' => 'CRM_Contribute_Form_Task_Print', + 'result' => FALSE, + ), + 3 => array('title' => ts('Export Contributions'), + 'class' => array( + 'CRM_Export_Form_Select', + 'CRM_Export_Form_Map', + ), + 'result' => FALSE, + ), + 4 => array('title' => ts('Batch Update Contributions Via Profile'), + 'class' => array( + 'CRM_Contribute_Form_Task_PickProfile', + 'CRM_Contribute_Form_Task_Batch', + ), + 'result' => TRUE, + ), + 5 => array('title' => ts('Send Email to Contacts'), + 'class' => 'CRM_Contribute_Form_Task_Email', + 'result' => TRUE, + ), + 6 => array('title' => ts('Update Pending Contribution Status'), + 'class' => 'CRM_Contribute_Form_Task_Status', + 'result' => TRUE, + ), + 7 => array('title' => ts('Print or Email Contribution Receipts'), + 'class' => 'CRM_Contribute_Form_Task_PDF', + 'result' => FALSE, + ), + 8 => array('title' => ts('Thank-you Letters for Contributions'), + 'class' => 'CRM_Contribute_Form_Task_PDFLetter', + 'result' => FALSE, + ), + ); + + //CRM-4418, check for delete + if (!CRM_Core_Permission::check('delete in CiviContribute')) { + unset(self::$_tasks[1]); + } + + CRM_Utils_Hook::searchTasks('contribution', self::$_tasks); + asort(self::$_tasks); + } + + return self::$_tasks; + } + + /** + * These tasks are the core set of task titles + * on contributors + * + * @return array the set of task titles + * @static + * @access public + */ + static function &taskTitles() { + self::tasks(); + $titles = array(); + foreach (self::$_tasks as $id => $value) { + // skip Print Contribution task + if ($id != 2) { + $titles[$id] = $value['title']; + } + } + return $titles; + } + + /** + * show tasks selectively based on the permission level + * of the user + * + * @param int $permission + * + * @return array set of tasks that are valid for the user + * @access public + */ + static function &permissionedTaskTitles($permission) { + $tasks = array(); + if (($permission == CRM_Core_Permission::EDIT) + || CRM_Core_Permission::check('edit contributions') + ) { + $tasks = self::taskTitles(); + } + else { + $tasks = array( + 3 => self::$_tasks[3]['title'], + 5 => self::$_tasks[5]['title'], + 7 => self::$_tasks[7]['title'], + ); + + //CRM-4418, + if (CRM_Core_Permission::check('delete in CiviContribute')) { + $tasks[1] = self::$_tasks[1]['title']; + } + } + return $tasks; + } + + /** + * These tasks are the core set of tasks that the user can perform + * on contributors + * + * @param int $value + * + * @return array the set of tasks for a group of contributors + * @static + * @access public + */ + static function getTask($value) { + self::tasks(); + if (!$value || !CRM_Utils_Array::value($value, self::$_tasks)) { + // make the print task by default + $value = 2; + } + return array( + self::$_tasks[$value]['class'], + self::$_tasks[$value]['result'], + ); + } +} + diff --git a/CRM/Contribute/xml/Menu/Contribute.xml b/CRM/Contribute/xml/Menu/Contribute.xml new file mode 100644 index 0000000000..102e4fdbbf --- /dev/null +++ b/CRM/Contribute/xml/Menu/Contribute.xml @@ -0,0 +1,276 @@ + + + + + civicrm/contribute + CiviContribute Dashboard + CRM_Contribute_Page_DashBoard + access CiviContribute + 1 + 500 + CiviContribute + + + civicrm/contribute/add + New Contribution + CRM_Contribute_Page_Tab + action=add + access CiviContribute + 1 + CiviContribute + + + civicrm/contribute/chart + Contribution Summary - Chart View + CRM_Contribute_Form_ContributionCharts + access CiviContribute + CiviContribute + + + civicrm/contribute/transact + CiviContribute + CRM_Contribute_Controller_Contribution + make online contributions + 0 + true + true + + + civicrm/admin/contribute + Manage Contribution Pages + CRM_Contribute_Page_ContributionPage + CiviContribute allows you to create and maintain any number of Online Contribution Pages. You can create different pages for different programs or campaigns - and customize text, amounts, types of information collected from contributors, etc. + CiviContribute + admin/small/online_contribution_pages.png + 360 + + + civicrm/admin/contribute/settings + Title and Settings + CRM_Contribute_Form_ContributionPage_Settings + 400 + + + civicrm/admin/contribute/amount + Contribution Amounts + CRM_Contribute_Form_ContributionPage_Amount + 410 + + + civicrm/admin/contribute/membership + Membership Section + CRM_Member_Form_MembershipBlock + 420 + + + civicrm/admin/contribute/custom + Include Profiles + CRM_Contribute_Form_ContributionPage_Custom + 430 + + + civicrm/admin/contribute/thankyou + Thank-you and Receipting + CRM_Contribute_Form_ContributionPage_ThankYou + 430 + + + civicrm/admin/contribute/friend + Tell a Friend + CRM_Friend_Form_Contribute + 440 + + + civicrm/admin/contribute/widget + Configure Widget + CRM_Contribute_Form_ContributionPage_Widget + 460 + + + civicrm/admin/contribute/premium + Premiums + CRM_Contribute_Form_ContributionPage_Premium + 470 + + + civicrm/admin/contribute/addProductToPage + Add Products to This Page + CRM_Contribute_Form_ContributionPage_AddProduct + 480 + + + civicrm/admin/contribute/add + New Contribution Page + CRM_Contribute_Controller_ContributionPage + action=add + + + civicrm/admin/contribute/managePremiums + Manage Premiums + CRM_Contribute_Page_ManagePremiums + CiviContribute allows you to configure any number of Premiums which can be offered to contributors as incentives / thank-you gifts. Define the premiums you want to offer here. + CiviContribute + admin/small/Premiums.png + 365 + + + civicrm/admin/financial/financialType + Financial Types + CRM_Financial_Page_FinancialType + Formerly civicrm_contribution_type merged into this table in 4.1 + CiviContribute + 580 + + + civicrm/admin/financial/financialAccount + Financial Accounts + CRM_Financial_Page_FinancialAccount + Financial types are used to categorize contributions for reporting and accounting purposes. These are also referred to as Funds. + CiviContribute + admin/small/contribution_types.png + 370 + + + civicrm/admin/options/payment_instrument + Payment Instruments + CRM_Admin_Page_Options + You may choose to record the payment instrument used for each contribution. Common payment methods are installed by default (e.g. Check, Cash, Credit Card...). If your site requires additional payment methods, add them here. + group=payment_instrument + CiviContribute + admin/small/payment_instruments.png + 380 + + + civicrm/admin/options/accept_creditcard + Accepted Credit Cards + CRM_Admin_Page_Options + Credit card options that will be offered to contributors using your Online Contribution pages. + group=accept_creditcard + CiviContribute + admin/small/accepted_creditcards.png + 395 + + + civicrm/contact/view/contribution + Contributions + CRM_Contribute_Page_Tab + 1 + + + civicrm/contact/view/contributionrecur + Recurring Contributions + CRM_Contribute_Page_ContributionRecur + + + civicrm/contact/view/contribution/additionalinfo + Additional Info + CRM_Contribute_Form_AdditionalInfo + + + civicrm/contribute/search + Find Contributions + CRM_Contribute_Controller_Search + access CiviContribute + 1 + 510 + + + civicrm/contribute/searchBatch + CRM_Contribute_Controller_SearchBatch + access CiviContribute + 1 + 588 + + + civicrm/contribute/import + Import Contributions + CRM_Contribute_Import_Controller + access CiviContribute,edit contributions + 1 + 520 + + + civicrm/contribute/manage + Manage Contribution Pages + CRM_Contribute_Page_ContributionPage + administer CiviCRM,access CiviContribute + 1 + 530 + + + civicrm/contribute/additionalinfo + AdditionalInfo Form + CRM_Contribute_Form_AdditionalInfo + access CiviContribute + 0 + + + civicrm/ajax/permlocation + CRM_Core_Page_AJAX_Location::getPermissionedLocation + make online contributions + + + civicrm/ajax/employer + CRM_Contact_Page_AJAX::getPermissionedEmployer + make online contributions + + + civicrm/contribute/unsubscribe + Cancel Subscription + CRM_Contribute_Form_CancelSubscription + make online contributions + + + civicrm/contribute/onbehalf + CRM_Contribute_Form_Contribution_OnBehalfOf + make online contributions + + + civicrm/contribute/updatebilling + Update Billing Details + CRM_Contribute_Form_UpdateBilling + make online contributions + + + civicrm/contribute/updaterecur + Update Subscription + CRM_Contribute_Form_UpdateSubscription + make online contributions + + + civicrm/contribute/subscriptionstatus + CRM_Contribute_Page_SubscriptionStatus + make online contributions + + + civicrm/admin/financial/financialType/accounts + Financial Type Accounts + CRM_Financial_Page_FinancialTypeAccount + 581 + + + civicrm/financial/batch + Accounting Batch + CRM_Financial_Page_FinancialBatch + create manual batch + 585 + + + civicrm/financial/financialbatches + Accounting Batches + CRM_Financial_Page_Batch + 586 + + + civicrm/batchtransaction + Accounting Batch + CRM_Financial_Page_BatchTransaction + 600 + + + civicrm/financial/batch/export + Accounting Batch Export + CRM_Financial_Form_Export + 610 + + diff --git a/CRM/Contribute/xml/Menu/PCP.xml b/CRM/Contribute/xml/Menu/PCP.xml new file mode 100644 index 0000000000..916b55489d --- /dev/null +++ b/CRM/Contribute/xml/Menu/PCP.xml @@ -0,0 +1,28 @@ + + + + + civicrm/admin/pcp + Personal Campaign Pages + CRM_PCP_Page_PCP + context=contribute + View and manage existing personal campaign pages. + CiviContribute + admin/small/contribution_types.png + 362 + + + civicrm/admin/contribute/pcp + Personal Campaign Pages + CRM_PCP_Form_Contribute + 450 + + + civicrm/contribute/campaign + Setup a Personal Campaign Page - Account Information + CRM_PCP_Controller_PCP + make online contributions + true + 0 + + diff --git a/CRM/Core/Action.php b/CRM/Core/Action.php new file mode 100644 index 0000000000..0c9b7a2dca --- /dev/null +++ b/CRM/Core/Action.php @@ -0,0 +1,365 @@ + self::ADD, + 'update' => self::UPDATE, + 'view' => self::VIEW, + 'delete' => self::DELETE, + 'browse' => self::BROWSE, + 'enable' => self::ENABLE, + 'disable' => self::DISABLE, + 'export' => self::EXPORT, + 'preview' => self::PREVIEW, + 'map' => self::MAP, + 'copy' => self::COPY, + 'profile' => self::PROFILE, + 'renew' => self::RENEW, + 'detach' => self::DETACH, + 'revert' => self::REVERT, + 'close' => self::CLOSE, + 'reopen' => self::REOPEN, + ); + + /** + * the flipped version of the names array, initialized when used + * + * @var array + * @static + */ + static $_description; + + /** + * + * called by the request object to translate a string into a mask + * + * @param string $action the action to be resolved + * + * @return int the action mask corresponding to the input string + * @access public + * @static + * + */ + static function resolve($str) { + $action = 0; + if ($str) { + $items = explode('|', $str); + $action = self::map($items); + } + return $action; + } + + /** + * Given a string or an array of strings, determine the bitmask + * for this set of actions + * + * @param mixed either a single string or an array of strings + * + * @return int the action mask corresponding to the input args + * @access public + * @static + * + */ + static function map($item) { + $mask = 0; + + if (is_array($item)) { + foreach ($item as $it) { + $mask |= self::mapItem($it); + } + return $mask; + } + else { + return self::mapItem($item); + } + } + + /** + * Given a string determine the bitmask for this specific string + * + * @param string the input action to process + * + * @return int the action mask corresponding to the input string + * @access public + * @static + * + */ + static function mapItem($item) { + $mask = CRM_Utils_Array::value(trim($item), self::$_names); + return $mask ? $mask : 0; + } + + /** + * + * Given an action mask, find the corresponding description + * + * @param int the action mask + * + * @return string the corresponding action description + * @access public + * @static + * + */ + static function description($mask) { + if (!isset($_description)) { + self::$_description = array_flip(self::$_names); + } + + return CRM_Utils_Array::value($mask, self::$_description, 'NO DESCRIPTION SET'); + } + + /** + * given a set of links and a mask, return the html action string for + * the links associated with the mask + * + * @param array $links the set of link items + * @param int $mask the mask to be used. a null mask means all items + * @param array $values the array of values for parameter substitution in the link items + * @param string $extraULName enclosed extra links in this UL. + * @param boolean $enclosedAllInSingleUL force to enclosed all links in single UL. + * + * @return string the html string + * @access public + * @static + */ + static function formLink($links, + $mask, + $values, + $extraULName = 'more', + $enclosedAllInSingleUL = FALSE, + $op = NULL, + $objectName = NULL, + $objectId = NULL + ) { + $config = CRM_Core_Config::singleton(); + if (empty($links)) { + return NULL; + } + + + if ($op && $objectName && $objectId) { + CRM_Utils_Hook::links($op, $objectName, $objectId, $links, $mask); + } + + $url = array(); + + $firstLink = TRUE; + foreach ($links as $m => $link) { + if (!$mask || ($mask & $m)) { + $extra = isset($link['extra']) ? self::replace($link['extra'], $values) : NULL; + + $frontend = (isset($link['fe'])) ? TRUE : FALSE; + + $urlPath = NULL; + if (CRM_Utils_Array::value('qs', $link) && + !CRM_Utils_System::isNull($link['qs']) + ) { + $urlPath = CRM_Utils_System::url(self::replace($link['url'], $values), + self::replace($link['qs'], $values), TRUE, NULL, TRUE, $frontend + ); + } + else { + $urlPath = CRM_Utils_Array::value('url', $link); + } + + $classes = 'action-item'; + if ($firstLink) { + $firstLink = FALSE; + $classes .= " action-item-first"; + } + if (isset($link['ref'])) { + $classes .= ' ' . strtolower($link['ref']); + } + + //get the user specified classes in. + if (isset($link['class'])) { + $className = $link['class']; + if (is_array($className)) { + $className = implode(' ', $className); + } + $classes .= ' ' . strtolower($className); + } + + $linkClasses = 'class = "' . $classes . '"'; + + if ($urlPath) { + if ($frontend) { + $extra .= "target=_blank"; + } + $url[] = sprintf('%s', + $urlPath, + $linkClasses, + CRM_Utils_Array::value('title', $link), + $link['name'] + ); + } + else { + $url[] = sprintf('%s', + CRM_Utils_Array::value('title', $link), + $linkClasses, + $link['name'] + ); + } + } + } + + + $result = ''; + $mainLinks = $url; + if ($enclosedAllInSingleUL) { + $allLinks = ''; + CRM_Utils_String::append($allLinks, '
  • ', $mainLinks); + $allLinks = "{$extraULName}"; + $result = "{$allLinks}"; + } + else { + $extra = ''; + $extraLinks = array_splice($url, 2); + if (count($extraLinks) > 1) { + $mainLinks = array_slice($url, 0, 2); + CRM_Utils_String::append($extra, '
  • ', $extraLinks); + $extra = "{$extraULName}"; + } + $resultLinks = ''; + CRM_Utils_String::append($resultLinks, '', $mainLinks); + if ($extra) { + $result = "{$resultLinks}{$extra}"; + } + else { + $result = "{$resultLinks}"; + } + } + + return $result; + } + + /** + * given a string and an array of values, substitute the real values + * in the placeholder in the str in the CiviCRM format + * + * @param string $str the string to be replaced + * @param array $values the array of values for parameter substitution in the str + * + * @return string the substituted string + * @access public + * @static + */ + static function &replace(&$str, &$values) { + foreach ($values as $n => $v) { + $str = str_replace("%%$n%%", $v, $str); + } + return $str; + } + + /** + * get the mask for a permission (view, edit or null) + * + * @param string the permission + * + * @return int the mask for the above permission + * @static + * @access public + */ + static function mask($permissions) { + $mask = NULL; + if (!is_array($permissions) || CRM_Utils_System::isNull($permissions)) { + return $mask; + } + //changed structure since we are handling delete separately - CRM-4418 + if (in_array(CRM_Core_Permission::VIEW, $permissions)) { + $mask |= self::VIEW | self::EXPORT | self::BASIC | self::ADVANCED | self::BROWSE | self::MAP | self::PROFILE; + } + if (in_array(CRM_Core_Permission::DELETE, $permissions)) { + $mask |= self::DELETE; + } + if (in_array(CRM_Core_Permission::EDIT, $permissions)) { + //make sure we make self::MAX_ACTION = 2^n - 1 + //if we add more actions; ( n = total number of actions ) + $mask |= (self::MAX_ACTION & ~self::DELETE); + } + + return $mask; + } +} + diff --git a/CRM/Core/BAO/ActionLog.php b/CRM/Core/BAO/ActionLog.php new file mode 100644 index 0000000000..f68bca4242 --- /dev/null +++ b/CRM/Core/BAO/ActionLog.php @@ -0,0 +1,75 @@ +copyValues($params); + + $edit = ($actionLog->id) ? TRUE : FALSE; + if ($edit) { + CRM_Utils_Hook::pre('edit', 'ActionLog', $actionLog->id, $actionLog); + } + else { + CRM_Utils_Hook::pre('create', 'ActionLog', NULL, $actionLog); + } + + $actionLog->save(); + + if ($edit) { + CRM_Utils_Hook::post('edit', 'ActionLog', $actionLog->id, $actionLog); + } + else { + CRM_Utils_Hook::post('create', 'ActionLog', NULL, $actionLog); + } + + return $actionLog; + } +} + diff --git a/CRM/Core/BAO/ActionSchedule.php b/CRM/Core/BAO/ActionSchedule.php new file mode 100755 index 0000000000..7c20e8ff6e --- /dev/null +++ b/CRM/Core/BAO/ActionSchedule.php @@ -0,0 +1,1034 @@ +id = $id; + } + $dao->find(); + + $mapping = array(); + while ($dao->fetch()) { + $defaults = array(); + CRM_Core_DAO::storeValues($dao, $defaults); + $mapping[$dao->id] = $defaults; + } + $_action_mapping = $mapping; + + return $mapping; + } + + /** + * Retrieve list of selections/drop downs for Scheduled Reminder form + * + * @param bool $id mapping id + * + * @return array associated array of all the drop downs in the form + * @static + * @access public + */ + static function getSelection($id = NULL) { + $mapping = self::getMapping($id); + $activityStatus = CRM_Core_PseudoConstant::activityStatus(); + $activityType = CRM_Core_PseudoConstant::activityType(FALSE) + CRM_Core_PseudoConstant::activityType(FALSE, TRUE); + + $participantStatus = CRM_Event_PseudoConstant::participantStatus(NULL, NULL, 'label'); + $event = CRM_Event_PseudoConstant::event(NULL, FALSE, "( is_template IS NULL OR is_template != 1 )"); + $eventType = CRM_Event_PseudoConstant::eventType(); + $eventTemplate = CRM_Event_PseudoConstant::eventTemplates(); + $autoRenew = CRM_Core_PseudoConstant::autoRenew(); + $membershipType = CRM_Member_PseudoConstant::membershipType(); + + asort($activityType); + + $sel1 = $sel2 = $sel3 = $sel4 = $sel5 = array(); + $options = array('manual' => ts('Choose Recipient(s)'), + 'group' => ts('Select a Group'), + ); + + $entityMapping = array(); + $recipientMapping = array_combine(array_keys($options), array_keys($options)); + + if (!$id) { + $id = 1; + } + + foreach ($mapping as $value) { + $entityValue = CRM_Utils_Array::value('entity_value', $value); + $entityStatus = CRM_Utils_Array::value('entity_status', $value); + $entityRecipient = CRM_Utils_Array::value('entity_recipient', $value); + $valueLabel = array('- ' . strtolower(CRM_Utils_Array::value('entity_value_label', $value)) . ' -'); + $key = CRM_Utils_Array::value('id', $value); + $entityMapping[$key] = CRM_Utils_Array::value('entity', $value); + + $sel1Val = null; + switch ($entityValue) { + case 'activity_type': + if ($value['entity'] == 'civicrm_activity') { + $sel1Val = ts('Activity'); + } + $sel2[$key] = $valueLabel + $activityType; + break; + + case 'event_type': + if ($value['entity'] == 'civicrm_participant') { + $sel1Val = ts('Event Type'); + } + $sel2[$key] = $valueLabel + $eventType; + break; + + case 'event_template': + if ($value['entity'] == 'civicrm_participant') { + $sel1Val = ts('Event Template'); + } + $sel2[$key] = $valueLabel + $eventTemplate; + break; + + case 'civicrm_event': + if ($value['entity'] == 'civicrm_participant') { + $sel1Val = ts('Event Name'); + } + $sel2[$key] = $valueLabel + $event; + break; + + case 'civicrm_membership_type': + if ($value['entity'] == 'civicrm_membership') { + $sel1Val = ts('Membership'); + } + $sel2[$key] = $valueLabel + $membershipType; + break; + } + $sel1[$key] = $sel1Val; + + if ($key == $id) { + if ($startDate = CRM_Utils_Array::value('entity_date_start', $value)) { + $sel4[$startDate] = ucwords(str_replace('_', ' ', $startDate)); + } + if ($endDate = CRM_Utils_Array::value('entity_date_end', $value)) { + $sel4[$endDate] = ucwords(str_replace('_', ' ', $endDate)); + } + + switch ($entityRecipient) { + case 'activity_contacts': + $activityContacts = CRM_Core_PseudoConstant::activityContacts(); + $sel5[$entityRecipient] = $activityContacts + $options; + $recipientMapping += CRM_Core_PseudoConstant::activityContacts('name'); + break; + + case 'event_contacts': + $eventContacts = CRM_Core_PseudoConstant::eventContacts(); + $sel5[$entityRecipient] = $eventContacts + $options; + $recipientMapping += CRM_Core_PseudoConstant::eventContacts('name'); + break; + + case NULL: + $sel5[$entityRecipient] = $options; + break; + } + } + } + $sel3 = $sel2; + + foreach ($mapping as $value) { + $entityStatus = CRM_Utils_Array::value('entity_status', $value); + $statusLabel = array('- ' . strtolower(CRM_Utils_Array::value('entity_status_label', $value)) . ' -'); + $id = CRM_Utils_Array::value('id', $value); + + switch ($entityStatus) { + case 'activity_status': + foreach ($sel3[$id] as $kkey => & $vval) { + $vval = $statusLabel + $activityStatus; + } + break; + + case 'civicrm_participant_status_type': + foreach ($sel3[$id] as $kkey => & $vval) { + $vval = $statusLabel + $participantStatus; + } + break; + + case 'auto_renew_options': + foreach ($sel3[$id] as $kkey => & $vval) { + $auto = 0; + if ($kkey) { + $auto = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $kkey, 'auto_renew'); + } + if ( $auto ) { + $vval = $statusLabel + $autoRenew; + } + else { + $vval = $statusLabel; + } + } + break; + + case '': + $sel3[$id] = ''; + break; + + } + } + + return array( + 'sel1' => $sel1, + 'sel2' => $sel2, + 'sel3' => $sel3, + 'sel4' => $sel4, + 'sel5' => $sel5, + 'entityMapping' => $entityMapping, + 'recipientMapping' => $recipientMapping, + ); + } + + static function getSelection1($id = NULL) { + $mapping = self::getMapping($id); + $sel4 = $sel5 = array(); + $options = array('manual' => ts('Choose Recipient(s)'), + 'group' => ts('Select a Group'), + ); + + $recipientMapping = array_combine(array_keys($options), array_keys($options)); + + foreach ($mapping as $value) { + $entityRecipient = CRM_Utils_Array::value('entity_recipient', $value); + $key = CRM_Utils_Array::value('id', $value); + + if ($startDate = CRM_Utils_Array::value('entity_date_start', $value)) { + $sel4[$startDate] = ucwords(str_replace('_', ' ', $startDate)); + } + if ($endDate = CRM_Utils_Array::value('entity_date_end', $value)) { + $sel4[$endDate] = ucwords(str_replace('_', ' ', $endDate)); + } + + switch ($entityRecipient) { + case 'activity_contacts': + $activityContacts = CRM_Core_PseudoConstant::activityContacts(); + $sel5[$id] = $activityContacts + $options; + $recipientMapping += CRM_Core_PseudoConstant::activityContacts('name'); + break; + + case 'event_contacts': + $eventContacts = CRM_Core_PseudoConstant::eventContacts(); + $sel5[$id] = $eventContacts + $options; + $recipientMapping += CRM_Core_PseudoConstant::eventContacts('name'); + break; + + case NULL: + $sel5[$id] = $options; + break; + } + } + + return array( + 'sel4' => $sel4, + 'sel5' => $sel5[$id], + 'recipientMapping' => $recipientMapping, + ); + } + + /** + * Retrieve list of Scheduled Reminders + * + * @param bool $namesOnly return simple list of names + * + * @return array (reference) reminder list + * @static + * @access public + */ + static function &getList($namesOnly = FALSE, $entityValue = NULL, $id = NULL) { + $activity_type = CRM_Core_PseudoConstant::activityType(FALSE) + CRM_Core_PseudoConstant::activityType(FALSE, TRUE); + $activity_status = CRM_Core_PseudoConstant::activityStatus(); + + $event_type = CRM_Event_PseudoConstant::eventType(); + $civicrm_event = CRM_Event_PseudoConstant::event(NULL, FALSE, "( is_template IS NULL OR is_template != 1 )"); + $civicrm_participant_status_type = CRM_Event_PseudoConstant::participantStatus(NULL, NULL, 'label'); + $event_template = CRM_Event_PseudoConstant::eventTemplates(); + + $auto_renew_options = CRM_Core_PseudoConstant::autoRenew(); + $civicrm_membership_type = CRM_Member_PseudoConstant::membershipType(); + + asort($activity_type); + $entity = array( + 'civicrm_activity' => 'Activity', + 'civicrm_participant' => 'Event', + 'civicrm_membership' => 'Member', + ); + + $query = " +SELECT + title, + cam.entity, + cas.id as id, + cam.entity_value as entityValue, + cas.entity_value as entityValueIds, + cam.entity_status as entityStatus, + cas.entity_status as entityStatusIds, + cas.start_action_date as entityDate, + cas.start_action_offset, + cas.start_action_unit, + cas.start_action_condition, + cas.absolute_date, + is_repeat, + is_active + +FROM civicrm_action_schedule cas +LEFT JOIN civicrm_action_mapping cam ON (cam.id = cas.mapping_id) +"; + $params = CRM_Core_DAO::$_nullArray; + + if ($entityValue and $id) { + $where = " +WHERE cas.entity_value = $id AND + cam.entity_value = '$entityValue'"; + + $query .= $where; + + $params = array(1 => array($id, 'Integer'), + 2 => array($entityValue, 'String'), + ); + } + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $list[$dao->id]['id'] = $dao->id; + $list[$dao->id]['title'] = $dao->title; + $list[$dao->id]['start_action_offset'] = $dao->start_action_offset; + $list[$dao->id]['start_action_unit'] = $dao->start_action_unit; + $list[$dao->id]['start_action_condition'] = $dao->start_action_condition; + $list[$dao->id]['entityDate'] = ucwords(str_replace('_', ' ', $dao->entityDate)); + $list[$dao->id]['absolute_date'] = $dao->absolute_date; + + $status = $dao->entityStatus; + $statusArray = explode(CRM_Core_DAO::VALUE_SEPARATOR, $dao->entityStatusIds); + foreach ($statusArray as & $s) { + $s = CRM_Utils_Array::value($s, $$status); + } + $statusIds = implode(', ', $statusArray); + + $value = $dao->entityValue; + $valueArray = explode(CRM_Core_DAO::VALUE_SEPARATOR, $dao->entityValueIds); + foreach ($valueArray as & $v) { + $v = CRM_Utils_Array::value($v, $$value); + } + $valueIds = implode(', ', $valueArray); + $list[$dao->id]['entity'] = $entity[$dao->entity]; + $list[$dao->id]['value'] = $valueIds; + $list[$dao->id]['status'] = $statusIds; + $list[$dao->id]['is_repeat'] = $dao->is_repeat; + $list[$dao->id]['is_active'] = $dao->is_active; + } + + return $list; + } + + static function sendReminder($contactId, $email, $scheduleID, $from, $tokenParams) { + + $schedule = new CRM_Core_DAO_ActionSchedule(); + $schedule->id = $scheduleID; + + $domain = CRM_Core_BAO_Domain::getDomain(); + $result = NULL; + $hookTokens = array(); + + if ($schedule->find(TRUE)) { + $body_text = $schedule->body_text; + $body_html = $schedule->body_html; + $body_subject = $schedule->subject; + if (!$body_text) { + $body_text = CRM_Utils_String::htmlToText($body_html); + } + + $params = array(array('contact_id', '=', $contactId, 0, 0)); + list($contact, $_) = CRM_Contact_BAO_Query::apiQuery($params); + + //CRM-4524 + $contact = reset($contact); + + if (!$contact || is_a($contact, 'CRM_Core_Error')) { + return NULL; + } + + // merge activity tokens with contact array + $contact = array_merge($contact, $tokenParams); + + //CRM-5734 + CRM_Utils_Hook::tokenValues($contact, $contactId); + + CRM_Utils_Hook::tokens($hookTokens); + $categories = array_keys($hookTokens); + + $type = array('html', 'text'); + + foreach ($type as $key => $value) { + $dummy_mail = new CRM_Mailing_BAO_Mailing(); + $bodyType = "body_{$value}"; + $dummy_mail->$bodyType = $$bodyType; + $tokens = $dummy_mail->getTokens(); + + if ($$bodyType) { + CRM_Utils_Token::replaceGreetingTokens($$bodyType, NULL, $contact['contact_id']); + $$bodyType = CRM_Utils_Token::replaceDomainTokens($$bodyType, $domain, TRUE, $tokens[$value], TRUE); + $$bodyType = CRM_Utils_Token::replaceContactTokens($$bodyType, $contact, FALSE, $tokens[$value], FALSE, TRUE); + $$bodyType = CRM_Utils_Token::replaceComponentTokens($$bodyType, $contact, $tokens[$value], TRUE, FALSE); + $$bodyType = CRM_Utils_Token::replaceHookTokens($$bodyType, $contact, $categories, TRUE); + } + } + $html = $body_html; + $text = $body_text; + + $smarty = CRM_Core_Smarty::singleton(); + foreach (array( + 'text', 'html') as $elem) { + $$elem = $smarty->fetch("string:{$$elem}"); + } + + $matches = array(); + preg_match_all('/(?fetch("string:{$messageSubject}"); + + // set up the parameters for CRM_Utils_Mail::send + $mailParams = array( + 'groupName' => 'Scheduled Reminder Sender', + 'from' => $from, + 'toName' => $contact['display_name'], + 'toEmail' => $email, + 'subject' => $messageSubject, + ); + + if (!$html || $contact['preferred_mail_format'] == 'Text' || + $contact['preferred_mail_format'] == 'Both' + ) { + // render the & entities in text mode, so that the links work + $mailParams['text'] = str_replace('&', '&', $text); + } + if ($html && ($contact['preferred_mail_format'] == 'HTML' || + $contact['preferred_mail_format'] == 'Both' + )) { + $mailParams['html'] = $html; + } + + $result = CRM_Utils_Mail::send($mailParams); + } + $schedule->free(); + + return $result; + } + + /** + * Function to add the schedules reminders in the db + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $ids the array that holds all the db ids + * + * @return object CRM_Core_DAO_ActionSchedule + * @access public + * @static + * + */ + static function add(&$params, &$ids) { + $actionSchedule = new CRM_Core_DAO_ActionSchedule(); + $actionSchedule->copyValues($params); + + return $actionSchedule->save(); + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $values (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_DAO_ActionSchedule object on success, null otherwise + * @access public + * @static + */ + static function retrieve(&$params, &$values) { + if (empty($params)) { + return NULL; + } + $actionSchedule = new CRM_Core_DAO_ActionSchedule(); + + $actionSchedule->copyValues($params); + + if ($actionSchedule->find(TRUE)) { + $ids['actionSchedule'] = $actionSchedule->id; + + CRM_Core_DAO::storeValues($actionSchedule, $values); + + return $actionSchedule; + } + return NULL; + } + + /** + * Function to delete a Reminder + * + * @param int $id ID of the Reminder to be deleted. + * + * @access public + * @static + */ + static function del($id) { + if ($id) { + $dao = new CRM_Core_DAO_ActionSchedule(); + $dao->id = $id; + if ($dao->find(TRUE)) { + $dao->delete(); + return; + } + } + CRM_Core_Error::fatal(ts('Invalid value passed to delete function.')); + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on success, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_ActionSchedule', $id, 'is_active', $is_active); + } + + static function sendMailings($mappingID, $now) { + $domainValues = CRM_Core_BAO_Domain::getNameAndEmail(); + $fromEmailAddress = "$domainValues[0] <$domainValues[1]>"; + + $mapping = new CRM_Core_DAO_ActionMapping(); + $mapping->id = $mappingID; + $mapping->find(TRUE); + + $actionSchedule = new CRM_Core_DAO_ActionSchedule(); + $actionSchedule->mapping_id = $mappingID; + $actionSchedule->is_active = 1; + $actionSchedule->find(FALSE); + + $tokenFields = array(); + $session = CRM_Core_Session::singleton(); + + while ($actionSchedule->fetch()) { + $extraSelect = $extraJoin = $extraWhere = ''; + + if ($actionSchedule->record_activity) { + if ($mapping->entity == 'civicrm_membership') { + $activityTypeID = + CRM_Core_OptionGroup::getValue('activity_type', 'Membership Renewal Reminder', 'name'); + } + else { + $activityTypeID = + CRM_Core_OptionGroup::getValue('activity_type', 'Reminder Sent', 'name'); + } + + $activityStatusID = + CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name'); + } + + if ($mapping->entity == 'civicrm_activity') { + $tokenEntity = 'activity'; + $tokenFields = array('activity_id', 'activity_type', 'subject', 'details', 'activity_date_time'); + $extraSelect = ', ov.label as activity_type, e.id as activity_id'; + $extraJoin = "INNER JOIN civicrm_option_group og ON og.name = 'activity_type' +INNER JOIN civicrm_option_value ov ON e.activity_type_id = ov.value AND ov.option_group_id = og.id"; + $extraWhere = 'AND e.is_current_revision = 1 AND e.is_deleted = 0'; + } + + if ($mapping->entity == 'civicrm_participant') { + $tokenEntity = 'event'; + $tokenFields = array('event_type', 'title', 'event_id', 'start_date', 'end_date', 'summary', 'description', 'location', 'info_url', 'registration_url', 'fee_amount', 'contact_email', 'contact_phone'); + $extraSelect = ', ov.label as event_type, ev.title, ev.id as event_id, ev.start_date, ev.end_date, ev.summary, ev.description, address.street_address, address.city, address.state_province_id, address.postal_code, email.email as contact_email, phone.phone as contact_phone '; + + $extraJoin = " +INNER JOIN civicrm_event ev ON e.event_id = ev.id +INNER JOIN civicrm_option_group og ON og.name = 'event_type' +INNER JOIN civicrm_option_value ov ON ev.event_type_id = ov.value AND ov.option_group_id = og.id +LEFT JOIN civicrm_loc_block lb ON lb.id = ev.loc_block_id +LEFT JOIN civicrm_address address ON address.id = lb.address_id +LEFT JOIN civicrm_email email ON email.id = lb.email_id +LEFT JOIN civicrm_phone phone ON phone.id = lb.phone_id +"; + } + + if ($mapping->entity == 'civicrm_membership') { + $tokenEntity = 'membership'; + $tokenFields = array('fee', 'id', 'join_date', 'start_date', 'end_date', 'status', 'type'); + $extraSelect = ', mt.minimum_fee as fee, e.id as id , e.join_date, e.start_date, e.end_date, ms.name as status, mt.name as type'; + $extraJoin = ' + INNER JOIN civicrm_membership_type mt ON e.membership_type_id = mt.id + INNER JOIN civicrm_membership_status ms ON e.status_id = ms.id'; + } + + $query = " +SELECT reminder.id as reminderID, reminder.*, e.id as entityID, e.* {$extraSelect} +FROM civicrm_action_log reminder +INNER JOIN {$mapping->entity} e ON e.id = reminder.entity_id +{$extraJoin} +WHERE reminder.action_schedule_id = %1 AND reminder.action_date_time IS NULL +{$extraWhere}"; + + $dao = CRM_Core_DAO::executeQuery($query, + array(1 => array($actionSchedule->id, 'Integer')) + ); + + while ($dao->fetch()) { + $entityTokenParams = array(); + foreach ($tokenFields as $field) { + if ($field == 'location') { + $loc = array(); + $stateProvince = CRM_Core_PseudoConstant::stateProvince(); + $loc['street_address'] = $dao->street_address; + $loc['city'] = $dao->city; + $loc['state_province'] = CRM_Utils_array::value($dao->state_province_id, $stateProvince); + $loc['postal_code'] = $dao->postal_code; + $entityTokenParams["{$tokenEntity}." . $field] = CRM_Utils_Address::format($loc); + } + elseif ($field == 'info_url') { + $entityTokenParams["{$tokenEntity}." . $field] = CRM_Utils_System::url('civicrm/event/info', 'reset=1&id=' . $dao->event_id, TRUE, NULL, FALSE); + } + elseif ($field == 'registration_url') { + $entityTokenParams["{$tokenEntity}." . $field] = CRM_Utils_System::url('civicrm/event/register', 'reset=1&id=' . $dao->event_id, TRUE, NULL, FALSE); + } + elseif (in_array($field, array('start_date','end_date','join_date','activity_date_time'))) { + $entityTokenParams["{$tokenEntity}." . $field] = CRM_Utils_Date::customFormat($dao->$field); + } + else { + $entityTokenParams["{$tokenEntity}." . $field] = $dao->$field; + } + } + + $isError = 0; + $errorMsg = ''; + $toEmail = CRM_Contact_BAO_Contact::getPrimaryEmail($dao->contact_id); + if ($toEmail) { + $result = + CRM_Core_BAO_ActionSchedule::sendReminder( + $dao->contact_id, + $toEmail, + $actionSchedule->id, + $fromEmailAddress, + $entityTokenParams + ); + + if (!$result || is_a($result, 'PEAR_Error')) { + // we could not send an email, for now we ignore, CRM-3406 + $isError = 1; + } + } + else { + $isError = 1; + $errorMsg = "Couldn\'t find recipient\'s email address."; + } + + // update action log record + $logParams = array( + 'id' => $dao->reminderID, + 'is_error' => $isError, + 'message' => $errorMsg ? $errorMsg : "null", + 'action_date_time' => $now, + ); + CRM_Core_BAO_ActionLog::create($logParams); + + // insert activity log record if needed + if ($actionSchedule->record_activity) { + $activityParams = array( + 'subject' => $actionSchedule->title, + 'details' => $actionSchedule->body_html, + 'source_contact_id' => $session->get('userID') ? + $session->get('userID') : $dao->contact_id, + 'target_contact_id' => $dao->contact_id, + 'activity_date_time' => date('YmdHis'), + 'status_id' => $activityStatusID, + 'activity_type_id' => $activityTypeID, + 'source_record_id' => $dao->entityID, + ); + $activity = CRM_Activity_BAO_Activity::create($activityParams); + } + } + + $dao->free(); + } + } + + static function buildRecipientContacts($mappingID, $now) { + $actionSchedule = new CRM_Core_DAO_ActionSchedule(); + $actionSchedule->mapping_id = $mappingID; + $actionSchedule->is_active = 1; + $actionSchedule->find(); + + while ($actionSchedule->fetch()) { + $mapping = new CRM_Core_DAO_ActionMapping(); + $mapping->id = $mappingID; + $mapping->find(TRUE); + + $select = $join = $where = array(); + + $value = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($actionSchedule->entity_value, CRM_Core_DAO::VALUE_SEPARATOR) + ); + $value = implode(',', $value); + + $status = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($actionSchedule->entity_status, CRM_Core_DAO::VALUE_SEPARATOR) + ); + $status = implode(',', $status); + + if (!CRM_Utils_System::isNull($mapping->entity_recipient)) { + $recipientOptions = CRM_Core_OptionGroup::values($mapping->entity_recipient); + } + $from = "{$mapping->entity} e"; + + if ($mapping->entity == 'civicrm_activity') { + switch ($recipientOptions[$actionSchedule->recipient]) { + case 'Activity Assignees': + $contactField = 'r.assignee_contact_id'; + $join[] = 'INNER JOIN civicrm_activity_assignment r ON r.activity_id = e.id'; + break; + + case 'Activity Source': + $contactField = 'e.source_contact_id'; + break; + + case 'Activity Targets': + $contactField = 'r.target_contact_id'; + $join[] = 'INNER JOIN civicrm_activity_target r ON r.activity_id = e.id'; + break; + + default: + break; + } + // build where clause + if (!empty($value)) { + $where[] = "e.activity_type_id IN ({$value})"; + } + else { + $where[] = "e.activity_type_id IS NULL"; + } + if (!empty($status)) { + $where[] = "e.status_id IN ({$status})"; + } + $where[] = ' e.is_current_revision = 1 '; + $where[] = ' e.is_deleted = 0 '; + + $dateField = 'e.activity_date_time'; + } + + if ($mapping->entity == 'civicrm_participant') { + $contactField = 'e.contact_id'; + $join[] = 'INNER JOIN civicrm_event r ON e.event_id = r.id'; + if ($actionSchedule->recipient_listing) { + $rList = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($actionSchedule->recipient_listing, CRM_Core_DAO::VALUE_SEPARATOR) + ); + $rList = implode(',', $rList); + + switch ($recipientOptions[$actionSchedule->recipient]) { + case 'Participant Role': + $where[] = "e.role_id IN ({$rList})"; + break; + + default: + break; + } + } + + // build where clause + if (!empty($value)) { + $where[] = ($mapping->entity_value == 'event_type') ? "r.event_type_id IN ({$value})" : "r.id IN ({$value})"; + } + else { + $where[] = ($mapping->entity_value == 'event_type') ? "r.event_type_id IS NULL" : "r.id IS NULL"; + } + + if (!empty($status)) { + $where[] = "e.status_id IN ({$status})"; + } + + $where[] = 'r.is_active = 1'; + $where[] = 'r.is_template = 0'; + $dateField = str_replace('event_', 'r.', $actionSchedule->start_action_date); + } + + $notINClause = ''; + if ($mapping->entity == 'civicrm_membership') { + $contactField = 'e.contact_id'; + + // build where clause + if ( $status == 2 ) { + //auto-renew memberships + $where[] = "e.contribution_recur_id IS NOT NULL "; + } + elseif ( $status == 1 ) { + $where[] = "e.contribution_recur_id IS NULL "; + } + + // build where clause + if (!empty($value)) { + $where[] = "e.membership_type_id IN ({$value})"; + } + else { + $where[] = "e.membership_type_id IS NULL"; + } + + $dateField = str_replace('membership_', 'e.', $actionSchedule->start_action_date); + $notINClause = self::permissionedRelationships($contactField); + } + + if ($actionSchedule->group_id) { + $join[] = "INNER JOIN civicrm_group_contact grp ON {$contactField} = grp.contact_id AND grp.status = 'Added'"; + $where[] = "grp.group_id IN ({$actionSchedule->group_id})"; + } + elseif (!empty($actionSchedule->recipient_manual)) { + $rList = CRM_Utils_Type::escape($actionSchedule->recipient_manual, 'String'); + $where[] = "{$contactField} IN ({$rList})"; + } + + $select[] = "{$contactField} as contact_id"; + $select[] = 'e.id as entity_id'; + $select[] = "'{$mapping->entity}' as entity_table"; + $select[] = "{$actionSchedule->id} as action_schedule_id"; + $reminderJoinClause = "civicrm_action_log reminder ON reminder.contact_id = {$contactField} AND +reminder.entity_id = e.id AND +reminder.entity_table = '{$mapping->entity}' AND +reminder.action_schedule_id = %1"; + + $join[] = "INNER JOIN civicrm_contact c ON c.id = {$contactField}"; + $where[] = 'c.is_deleted = 0'; + + if ($actionSchedule->start_action_date) { + $startDateClause = array(); + $op = ($actionSchedule->start_action_condition == 'before' ? '<=' : '>='); + $operator = ($actionSchedule->start_action_condition == 'before' ? 'DATE_SUB' : 'DATE_ADD'); + $date = $operator . "({$dateField}, INTERVAL {$actionSchedule->start_action_offset} {$actionSchedule->start_action_unit})"; + $startDateClause[] = "'{$now}' >= {$date}"; + if ($mapping->entity == 'civicrm_participant') { + $startDateClause[] = $operator. "({$now}, INTERVAL 1 DAY ) {$op} " . $dateField; + } + else { + $startDateClause[] = "DATE_SUB({$now}, INTERVAL 1 DAY ) <= {$date}"; + } + + $startDate = implode(' AND ', $startDateClause); + } + elseif ($actionSchedule->absolute_date) { + $startDate = "DATEDIFF(DATE('{$now}'),'{$actionSchedule->absolute_date}') = 0"; + } + + // ( now >= date_built_from_start_time ) OR ( now = absolute_date ) + $dateClause = "reminder.id IS NULL AND {$startDate}"; + + // start composing query + $selectClause = 'SELECT ' . implode(', ', $select); + $fromClause = "FROM $from"; + $joinClause = !empty($join) ? implode(' ', $join) : ''; + $whereClause = 'WHERE ' . implode(' AND ', $where); + + $query = " +INSERT INTO civicrm_action_log (contact_id, entity_id, entity_table, action_schedule_id) +{$selectClause} +{$fromClause} +{$joinClause} +LEFT JOIN {$reminderJoinClause} +{$whereClause} AND {$dateClause} {$notINClause}"; + + CRM_Core_DAO::executeQuery($query, array(1 => array($actionSchedule->id, 'Integer'))); + + // if repeat is turned ON: + if ($actionSchedule->is_repeat) { + $repeatEvent = ($actionSchedule->end_action == 'before' ? 'DATE_SUB' : 'DATE_ADD') . "({$dateField}, INTERVAL {$actionSchedule->end_frequency_interval} {$actionSchedule->end_frequency_unit})"; + + if ($actionSchedule->repetition_frequency_unit == 'day') { + $hrs = 24 * $actionSchedule->repetition_frequency_interval; + } + elseif ($actionSchedule->repetition_frequency_unit == 'week') { + $hrs = 24 * $actionSchedule->repetition_frequency_interval * 7; + } + else { + $hrs = $actionSchedule->repetition_frequency_interval; + } + + // (now <= repeat_end_time ) + $repeatEventClause = "'{$now}' <= {$repeatEvent}"; + // diff(now && logged_date_time) >= repeat_interval + $havingClause = "HAVING TIMEDIFF({$now}, latest_log_time) >= TIME('{$hrs}:00:00')"; + $groupByClause = 'GROUP BY reminder.contact_id, reminder.entity_id, reminder.entity_table'; + $selectClause .= ', MAX(reminder.action_date_time) as latest_log_time'; + + $sqlInsertValues = "{$selectClause} +{$fromClause} +{$joinClause} +INNER JOIN {$reminderJoinClause} +{$whereClause} AND {$repeatEventClause} +{$groupByClause} +{$havingClause}"; + + $valsqlInsertValues = CRM_Core_DAO::executeQuery($sqlInsertValues, array(1 => array($actionSchedule->id, 'Integer'))); + + $arrValues = array(); + while ($valsqlInsertValues->fetch()) { + $arrValues[] = "( {$valsqlInsertValues->contact_id}, {$valsqlInsertValues->entity_id}, '{$valsqlInsertValues->entity_table}',{$valsqlInsertValues->action_schedule_id} )"; + } + + $valString = implode(',', $arrValues); + + if ($valString) { + $query = ' + INSERT INTO civicrm_action_log (contact_id, entity_id, entity_table, action_schedule_id) VALUES ' . $valString; + CRM_Core_DAO::executeQuery($query, array(1 => array($actionSchedule->id, 'Integer'))); + } + } + } + } + + static function permissionedRelationships($field) { + $query = ' +SELECT cm.id AS owner_id, cm.contact_id AS owner_contact, m.id AS slave_id, m.contact_id AS slave_contact, cmt.relationship_type_id AS relation_type, rel.contact_id_a, rel.contact_id_b, rel.is_permission_a_b, rel.is_permission_b_a +FROM civicrm_membership m +LEFT JOIN civicrm_membership cm ON cm.id = m.owner_membership_id +LEFT JOIN civicrm_membership_type cmt ON cmt.id = m.membership_type_id +LEFT JOIN civicrm_relationship rel ON ( ( rel.contact_id_a = m.contact_id AND rel.contact_id_b = cm.contact_id AND rel.relationship_type_id = cmt.relationship_type_id ) + OR ( rel.contact_id_a = cm.contact_id AND rel.contact_id_b = m.contact_id AND rel.relationship_type_id = cmt.relationship_type_id ) ) +WHERE m.owner_membership_id IS NOT NULL AND + ( rel.is_permission_a_b = 0 OR rel.is_permission_b_a = 0) + +'; + $excludeIds = array(); + $dao = CRM_Core_DAO::executeQuery($query, array()); + while ($dao->fetch()) { + if ($dao->slave_contact == $dao->contact_id_a && $dao->is_permission_b_a == 0) { + $excludeIds[] = $dao->slave_contact; + } + elseif ($dao->slave_contact == $dao->contact_id_b && $dao->is_permission_a_b == 0) { + $excludeIds[] = $dao->slave_contact; + } + } + + if (!empty($excludeIds)) { + $clause = "AND {$field} NOT IN ( " .implode(', ', $excludeIds) . ' ) '; + return $clause; + } + return NULL; + } + + static function processQueue($now = NULL) { + $now = $now ? CRM_Utils_Time::setTime($now) : CRM_Utils_Time::getTime(); + + $mappings = self::getMapping(); + foreach ($mappings as $mappingID => $mapping) { + self::buildRecipientContacts($mappingID, $now); + self::sendMailings($mappingID, $now); + } + + $result = array( + 'is_error' => 0, + 'messages' => ts('Sent all scheduled reminders successfully'), + ); + return $result; + } + + static function isConfigured($id, $mappingID) { + $queryString = "SELECT count(id) FROM civicrm_action_schedule + WHERE mapping_id = %1 AND + entity_value = %2"; + + $params = array(1 => array($mappingID, 'Integer'), + 2 => array($id, 'Integer'), + ); + return CRM_Core_DAO::singleValueQuery($queryString, $params); + } + + static function getRecipientListing($mappingID, $recipientType) { + $options = array(); + if (!$mappingID || !$recipientType) { + return $options; + } + + $mapping = self::getMapping($mappingID); + + switch ($mapping['entity']) { + case 'civicrm_participant': + $eventContacts = CRM_Core_PseudoConstant::eventContacts('name'); + if (!CRM_Utils_Array::value($recipientType, $eventContacts)) { + return $options; + } + if ($eventContacts[$recipientType] == 'Participant Role') { + $options = CRM_Event_PseudoConstant::participantRole(); + } + break; + } + + return $options; + } +} + diff --git a/CRM/Core/BAO/Address.php b/CRM/Core/BAO/Address.php new file mode 100644 index 0000000000..7c6cb7b9df --- /dev/null +++ b/CRM/Core/BAO/Address.php @@ -0,0 +1,1133 @@ + $params['entity_table'], + 'entity_id' => $params['entity_id'], + ); + $addresses = self::allEntityAddress($entityElements); + } + + $isPrimary = $isBilling = TRUE; + $blocks = array(); + foreach ($params['address'] as $key => $value) { + if (!is_array($value)) { + continue; + } + + $addressExists = self::dataExists($value); + if ( !CRM_Utils_Array::value('id', $value) ) { + if ($updateBlankLocInfo) { + if ((!empty($addresses) || !$addressExists) && array_key_exists($key, $addresses)) { + $value['id'] = $addresses[$key]; + } + } + else { + if (!empty($addresses) && array_key_exists(CRM_Utils_Array::value('location_type_id', $value), $addresses)) { + $value['id'] = $addresses[CRM_Utils_Array::value('location_type_id', $value)]; + } + } + } + + // Note there could be cases when address info already exist ($value[id] is set) for a contact/entity + // BUT info is not present at this time, and therefore we should be really careful when deleting the block. + // $updateBlankLocInfo will help take appropriate decision. CRM-5969 + if (isset($value['id']) && !$addressExists && $updateBlankLocInfo) { + //delete the existing record + CRM_Core_BAO_Block::blockDelete('Address', array('id' => $value['id'])); + continue; + } + elseif (!$addressExists) { + continue; + } + + if ($isPrimary && CRM_Utils_Array::value('is_primary', $value)) { + $isPrimary = FALSE; + } + else { + $value['is_primary'] = 0; + } + + if ($isBilling && CRM_Utils_Array::value('is_billing', $value)) { + $isBilling = FALSE; + } + else { + $value['is_billing'] = 0; + } + + if (!CRM_Utils_Array::value('manual_geo_code', $value)) { + $value['manual_geo_code'] = 0; + } + $value['contact_id'] = $contactId; + $blocks[] = self::add($value, $fixAddress); + } + + return $blocks; + } + + /** + * takes an associative array and adds address + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param boolean $fixAddress true if you need to fix (format) address values + * before inserting in db + * + * @return object CRM_Core_BAO_Address object on success, null otherwise + * @access public + * @static + */ + static function add(&$params, $fixAddress) { + static $customFields = NULL; + $address = new CRM_Core_DAO_Address(); + + // fixAddress mode to be done + if ($fixAddress) { + CRM_Core_BAO_Address::fixAddress($params); + } + + $hook = empty($params['id']) ? 'create' : 'edit'; + CRM_Utils_Hook::pre($hook, 'Address', CRM_Utils_Array::value('id', $params), $params); + + // if id is set & is_primary isn't we can assume no change + if (is_numeric(CRM_Utils_Array::value('is_primary', $params)) || empty($params['id'])) { + CRM_Core_BAO_Block::handlePrimary($params, get_class()); + } + $config = CRM_Core_Config::singleton(); + $address->copyValues($params); + + $address->save(); + + if ($address->id) { + if (!$customFields) { + $customFields = CRM_Core_BAO_CustomField::getFields('Address', FALSE, TRUE); + } + if (!empty($customFields)) { + $addressCustom = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $address->id, + 'Address', + TRUE + ); + } + if (!empty($addressCustom)) { + CRM_Core_BAO_CustomValueTable::store($addressCustom, 'civicrm_address', $address->id); + } + + //call the function to sync shared address + self::processSharedAddress($address->id, $params); + + // call the function to create shared relationships + // we only create create relationship if address is shared by Individual + if ($address->master_id != 'null') { + self::processSharedAddressRelationship($address->master_id, $params); + } + + // lets call the post hook only after we've done all the follow on processing + CRM_Utils_Hook::post($hook, 'Address', $address->id, $address); + } + + return $address; + } + + /** + * format the address params to have reasonable values + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return void + * @access public + * @static + */ + static function fixAddress(&$params) { + if (CRM_Utils_Array::value('billing_street_address', $params)) { + //Check address is comming from online contribution / registration page + //Fixed :CRM-5076 + $billing = array( + 'street_address' => 'billing_street_address', + 'city' => 'billing_city', + 'postal_code' => 'billing_postal_code', + 'state_province' => 'billing_state_province', + 'state_province_id' => 'billing_state_province_id', + 'country' => 'billing_country', + 'country_id' => 'billing_country_id', + ); + + foreach ($billing as $key => $val) { + if ($value = CRM_Utils_Array::value($val, $params)) { + if (CRM_Utils_Array::value($key, $params)) { + unset($params[$val]); + } + else { + //add new key and removed old + $params[$key] = $value; + unset($params[$val]); + } + } + } + } + + /* Split the zip and +4, if it's in US format */ + if (CRM_Utils_Array::value('postal_code', $params) && + preg_match('/^(\d{4,5})[+-](\d{4})$/', + $params['postal_code'], + $match + ) + ) { + $params['postal_code'] = $match[1]; + $params['postal_code_suffix'] = $match[2]; + } + + // add country id if not set + if ((!isset($params['country_id']) || !is_numeric($params['country_id'])) && + isset($params['country']) + ) { + $country = new CRM_Core_DAO_Country(); + $country->name = $params['country']; + if (!$country->find(TRUE)) { + $country->name = NULL; + $country->iso_code = $params['country']; + $country->find(TRUE); + } + $params['country_id'] = $country->id; + } + + // add state_id if state is set + if ((!isset($params['state_province_id']) || !is_numeric($params['state_province_id'])) + && isset($params['state_province']) + ) { + if (!empty($params['state_province'])) { + $state_province = new CRM_Core_DAO_StateProvince(); + $state_province->name = $params['state_province']; + + // add country id if present + if (!empty($params['country_id'])) { + $state_province->country_id = $params['country_id']; + } + + if (!$state_province->find(TRUE)) { + unset($state_province->name); + $state_province->abbreviation = $params['state_province']; + $state_province->find(TRUE); + } + $params['state_province_id'] = $state_province->id; + if (empty($params['country_id'])) { + // set this here since we have it + $params['country_id'] = $state_province->country_id; + } + } + else { + $params['state_province_id'] = 'null'; + } + } + + // add county id if county is set + // CRM-7837 + if ((!isset($params['county_id']) || !is_numeric($params['county_id'])) + && isset($params['county']) && !empty($params['county']) + ) { + $county = new CRM_Core_DAO_County(); + $county->name = $params['county']; + + if (isset($params['state_province_id'])) { + $county->state_province_id = $params['state_province_id']; + } + + if ($county->find(TRUE)) { + $params['county_id'] = $county->id; + } + } + + // currently copy values populates empty fields with the string "null" + // and hence need to check for the string null + if (isset($params['state_province_id']) && + is_numeric($params['state_province_id']) && + (!isset($params['country_id']) || empty($params['country_id'])) + ) { + // since state id present and country id not present, hence lets populate it + // jira issue http://issues.civicrm.org/jira/browse/CRM-56 + $params['country_id'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', + $params['state_province_id'], + 'country_id' + ); + } + + //special check to ignore non numeric values if they are not + //detected by formRule(sometimes happens due to internet latency), also allow user to unselect state/country + if (isset($params['state_province_id'])) { + if (empty($params['state_province_id'])) { + $params['state_province_id'] = 'null'; + } + elseif (!is_numeric($params['state_province_id']) || + ((int ) $params['state_province_id'] < 1000) + ) { + // CRM-3393 ( the hacky 1000 check) + $params['state_province_id'] = 'null'; + } + } + + if (isset($params['country_id'])) { + if (empty($params['country_id'])) { + $params['country_id'] = 'null'; + } + elseif (!is_numeric($params['country_id']) || + ((int ) $params['country_id'] < 1000) + ) { + // CRM-3393 ( the hacky 1000 check) + $params['country_id'] = 'null'; + } + } + + // add state and country names from the ids + if (isset($params['state_province_id']) && is_numeric($params['state_province_id'])) { + $params['state_province'] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($params['state_province_id']); + } + + if (isset($params['country_id']) && is_numeric($params['country_id'])) { + $params['country'] = CRM_Core_PseudoConstant::country($params['country_id']); + } + + $config = CRM_Core_Config::singleton(); + + $asp = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::ADDRESS_STANDARDIZATION_PREFERENCES_NAME, + 'address_standardization_provider' + ); + // clean up the address via USPS web services if enabled + if ($asp === 'USPS' && + $params['country_id'] == 1228 + ) { + CRM_Utils_Address_USPS::checkAddress($params); + + // do street parsing again if enabled, since street address might have changed + $parseStreetAddress = CRM_Utils_Array::value('street_address_parsing', + CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options' + ), + FALSE + ); + + if ($parseStreetAddress && !empty($params['street_address'])) { + foreach (array( + 'street_number', 'street_name', 'street_unit', 'street_number_suffix') as $fld) { + unset($params[$fld]); + } + // main parse string. + $parseString = CRM_Utils_Array::value('street_address', $params); + $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($parseString); + + // merge parse address in to main address block. + $params = array_merge($params, $parsedFields); + } + } + + // add latitude and longitude and format address if needed + if (!empty($config->geocodeMethod) && ($config->geocodeMethod != 'CRM_Utils_Geocode_OpenStreetMaps') && empty($params['manual_geo_code'])) { + $class = $config->geocodeMethod; + $class::format($params); + } + } + + /** + * Check if there is data to create the object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * + * @access public + * @static + */ + static function dataExists(&$params) { + //check if location type is set if not return false + if (!isset($params['location_type_id'])) { + return FALSE; + } + + $config = CRM_Core_Config::singleton(); + foreach ($params as $name => $value) { + if (in_array($name, array( + 'is_primary', 'location_type_id', 'id', 'contact_id', 'is_billing', 'display', 'master_id'))) { + continue; + } + elseif (!CRM_Utils_System::isNull($value)) { + // name could be country or country id + if (substr($name, 0, 7) == 'country') { + // make sure its different from the default country + // iso code + $defaultCountry = $config->defaultContactCountry(); + // full name + $defaultCountryName = $config->defaultContactCountryName(); + + if ($defaultCountry) { + if ($value == $defaultCountry || + $value == $defaultCountryName || + $value == $config->defaultContactCountry + ) { + // do nothing + } + else { + return TRUE; + } + } + else { + // return if null default + return TRUE; + } + } + else { + return TRUE; + } + } + } + + return FALSE; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $entityBlock associated array of fields + * @param boolean $microformat if microformat output is required + * @param int $fieldName conditional field name + * + * @return array $addresses array with address fields + * @access public + * @static + */ + static function &getValues(&$entityBlock, $microformat = FALSE, $fieldName = 'contact_id') { + if (empty($entityBlock)) { + return NULL; + } + $addresses = array(); + $address = new CRM_Core_BAO_Address(); + + if (!CRM_Utils_Array::value('entity_table', $entityBlock)) { + $address->$fieldName = CRM_Utils_Array::value($fieldName, $entityBlock); + } + else { + $addressIds = array(); + $addressIds = self::allEntityAddress($entityBlock); + + if (!empty($addressIds[1])) { + $address->id = $addressIds[1]; + } + else { + return $addresses; + } + } + //get primary address as a first block. + $address->orderBy('is_primary desc, id'); + + $address->find(); + + $count = 1; + while ($address->fetch()) { + // deprecate reference. + if ($count > 1) { + foreach (array( + 'state', 'state_name', 'country', 'world_region') as $fld) { + if (isset($address->$fld))unset($address->$fld); + } + } + $stree = $address->street_address; + $values = array(); + CRM_Core_DAO::storeValues($address, $values); + + // add state and country information: CRM-369 + if (!empty($address->state_province_id)) { + $address->state = CRM_Core_PseudoConstant::stateProvinceAbbreviation($address->state_province_id, FALSE); + $address->state_name = CRM_Core_PseudoConstant::stateProvince($address->state_province_id, FALSE); + } + + if (!empty($address->country_id)) { + $address->country = CRM_Core_PseudoConstant::country($address->country_id); + + //get world region + $regionId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Country', $address->country_id, 'region_id'); + + $address->world_region = CRM_Core_PseudoConstant::worldregion($regionId); + } + + $address->addDisplay($microformat); + + $values['display'] = $address->display; + $values['display_text'] = $address->display_text; + + if (is_numeric($address->master_id)) { + $values['use_shared_address'] = 1; + } + + $addresses[$count] = $values; + + //unset is_primary after first block. Due to some bug in earlier version + //there might be more than one primary blocks, hence unset is_primary other than first + if ($count > 1) { + unset($addresses[$count]['is_primary']); + } + + $count++; + } + + return $addresses; + } + + /** + * Add the formatted address to $this-> display + * + * @param NULL + * + * @return void + * + * @access public + * + */ + function addDisplay($microformat = FALSE) { + $fields = array( + // added this for CRM 1200 + 'address_id' => $this->id, + // CRM-4003 + 'address_name' => str_replace('', ' ', $this->name), + 'street_address' => $this->street_address, + 'supplemental_address_1' => $this->supplemental_address_1, + 'supplemental_address_2' => $this->supplemental_address_2, + 'city' => $this->city, + 'state_province_name' => isset($this->state_name) ? $this->state_name : "", + 'state_province' => isset($this->state) ? $this->state : "", + 'postal_code' => isset($this->postal_code) ? $this->postal_code : "", + 'postal_code_suffix' => isset($this->postal_code_suffix) ? $this->postal_code_suffix : "", + 'country' => isset($this->country) ? $this->country : "", + 'world_region' => isset($this->world_region) ? $this->world_region : "", + ); + + if (isset($this->county_id) && $this->county_id) { + $fields['county'] = CRM_Core_PseudoConstant::county($this->county_id); + } + else { + $fields['county'] = NULL; + } + + $this->display = CRM_Utils_Address::format($fields, NULL, $microformat); + $this->display_text = CRM_Utils_Address::format($fields); + } + + /** + * Get all the addresses for a specified contact_id, with the primary address being first + * + * @param int $id the contact id + * + * @return array the array of adrress data + * @access public + * @static + */ + static function allAddress($id, $updateBlankLocInfo = FALSE) { + if (!$id) { + return NULL; + } + + $query = " +SELECT civicrm_address.id as address_id, civicrm_address.location_type_id as location_type_id +FROM civicrm_contact, civicrm_address +WHERE civicrm_address.contact_id = civicrm_contact.id AND civicrm_contact.id = %1 +ORDER BY civicrm_address.is_primary DESC, address_id ASC"; + $params = array(1 => array($id, 'Integer')); + + $addresses = array(); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $count = 1; + while ($dao->fetch()) { + if ($updateBlankLocInfo) { + $addresses[$count++] = $dao->address_id; + } + else { + $addresses[$dao->location_type_id] = $dao->address_id; + } + } + return $addresses; + } + + /** + * Get all the addresses for a specified location_block id, with the primary address being first + * + * @param array $entityElements the array containing entity_id and + * entity_table name + * + * @return array the array of adrress data + * @access public + * @static + */ + static function allEntityAddress(&$entityElements) { + if (empty($entityElements)) { + return $addresses; + } + + $entityId = $entityElements['entity_id']; + $entityTable = $entityElements['entity_table']; + + $sql = " +SELECT civicrm_address.id as address_id +FROM civicrm_loc_block loc, civicrm_location_type ltype, civicrm_address, {$entityTable} ev +WHERE ev.id = %1 + AND loc.id = ev.loc_block_id + AND civicrm_address.id IN (loc.address_id, loc.address_2_id) + AND ltype.id = civicrm_address.location_type_id +ORDER BY civicrm_address.is_primary DESC, civicrm_address.location_type_id DESC, address_id ASC "; + + $params = array(1 => array($entityId, 'Integer')); + $addresses = array(); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + $locationCount = 1; + while ($dao->fetch()) { + $addresses[$locationCount] = $dao->address_id; + $locationCount++; + } + return $addresses; + } + + static function addStateCountryMap(&$stateCountryMap, $defaults = NULL) { + // first fix the statecountry map if needed + if (empty($stateCountryMap)) { + return; + } + + $config = CRM_Core_Config::singleton(); + if (!isset($config->stateCountryMap)) { + $config->stateCountryMap = array(); + } + + $config->stateCountryMap = array_merge($config->stateCountryMap, $stateCountryMap); + } + + static function fixAllStateSelects(&$form, &$defaults) { + $config = CRM_Core_Config::singleton(); + + if (!empty($config->stateCountryMap)) { + foreach ($config->stateCountryMap as $index => $match) { + if ( + array_key_exists('state_province', $match) && + array_key_exists('country', $match) + ) { + CRM_Contact_Form_Edit_Address::fixStateSelect( + $form, + $match['country'], + $match['state_province'], + CRM_Utils_Array::value('county', $match), + CRM_Utils_Array::value($match['country'], $defaults), + CRM_Utils_Array::value($match['state_province'], $defaults) + ); + } + else { + unset($config->stateCountryMap[$index]); + } + } + } + } + + /** + * Function to get address sequence + * + * @return array of address sequence. + */ + static function addressSequence() { + $config = CRM_Core_Config::singleton(); + $addressSequence = $config->addressSequence(); + + $countryState = $cityPostal = FALSE; + foreach ($addressSequence as $key => $field) { + if ( + in_array($field, array('country', 'state_province')) && + !$countryState + ) { + $countryState = TRUE; + $addressSequence[$key] = 'country_state_province'; + } + elseif ( + in_array($field, array('city', 'postal_code')) && + !$cityPostal + ) { + $cityPostal = TRUE; + $addressSequence[$key] = 'city_postal_code'; + } + elseif ( + in_array($field, array('country', 'state_province', 'city', 'postal_code')) + ) { + unset($addressSequence[$key]); + } + } + + return $addressSequence; + } + + /** + * Parse given street address string in to street_name, + * street_unit, street_number and street_number_suffix + * eg "54A Excelsior Ave. Apt 1C", or "917 1/2 Elm Street" + * + * NB: civic street formats for en_CA and fr_CA used by default if those locales are active + * otherwise en_US format is default action + * + * @param string Street address including number and apt + * @param string Locale - to set locale used to parse address + * + * @return array $parseFields parsed fields values. + * @access public + * @static + */ + static function parseStreetAddress($streetAddress, $locale = NULL) { + $config = CRM_Core_Config::singleton(); + + /* locales supported include: + * en_US - http://pe.usps.com/cpim/ftp/pubs/pub28/pub28.pdf + * en_CA - http://www.canadapost.ca/tools/pg/manual/PGaddress-e.asp + * fr_CA - http://www.canadapost.ca/tools/pg/manual/PGaddress-f.asp + * NB: common use of comma after street number also supported + * default is en_US + */ + + $supportedLocalesForParsing = array('en_US', 'en_CA', 'fr_CA'); + if (!$locale) { + $locale = $config->lcMessages; + } + // as different locale explicitly requested but is not available, display warning message and set $locale = 'en_US' + if (!in_array($locale, $supportedLocalesForParsing)) { + CRM_Core_Session::setStatus(ts('Unsupported locale specified to parseStreetAddress: %1. Proceeding with en_US locale.', array(1 => $locale)), ts('Unsupported Locale'), 'alert'); + $locale = 'en_US'; + } + $parseFields = array( + 'street_name' => '', + 'street_unit' => '', + 'street_number' => '', + 'street_number_suffix' => '', + ); + + if (empty($streetAddress)) { + return $parseFields; + } + + $streetAddress = trim($streetAddress); + + $matches = array(); + if (in_array($locale, array( + 'en_CA', 'fr_CA')) && preg_match('/^([A-Za-z0-9]+)[ ]*\-[ ]*/', $streetAddress, $matches)) { + $parseFields['street_unit'] = $matches[1]; + // unset from rest of street address + $streetAddress = preg_replace('/^([A-Za-z0-9]+)[ ]*\-[ ]*/', '', $streetAddress); + } + + // get street number and suffix. + $matches = array(); + //alter street number/suffix handling so that we accept -digit + if (preg_match('/^[A-Za-z0-9]+([\S]+)/', $streetAddress, $matches)) { + // check that $matches[0] is numeric, else assume no street number + if (preg_match('/^(\d+)/', $matches[0])) { + $streetNumAndSuffix = $matches[0]; + + // get street number. + $matches = array(); + if (preg_match('/^(\d+)/', $streetNumAndSuffix, $matches)) { + $parseFields['street_number'] = $matches[0]; + $suffix = preg_replace('/^(\d+)/', '', $streetNumAndSuffix); + $parseFields['street_number_suffix'] = trim($suffix); + } + + // unset from main street address. + $streetAddress = preg_replace('/^[A-Za-z0-9]+([\S]+)/', '', $streetAddress); + $streetAddress = trim($streetAddress); + } + } + elseif (preg_match('/^(\d+)/', $streetAddress, $matches)) { + $parseFields['street_number'] = $matches[0]; + // unset from main street address. + $streetAddress = preg_replace('/^(\d+)/', '', $streetAddress); + $streetAddress = trim($streetAddress); + } + + // suffix might be like 1/2 + $matches = array(); + if (preg_match('/^\d\/\d/', $streetAddress, $matches)) { + $parseFields['street_number_suffix'] .= $matches[0]; + + // unset from main street address. + $streetAddress = preg_replace('/^\d+\/\d+/', '', $streetAddress); + $streetAddress = trim($streetAddress); + } + + // now get the street unit. + // supportable street unit formats. + $streetUnitFormats = array( + 'APT', 'APARTMENT', 'BSMT', 'BASEMENT', 'BLDG', 'BUILDING', + 'DEPT', 'DEPARTMENT', 'FL', 'FLOOR', 'FRNT', 'FRONT', + 'HNGR', 'HANGER', 'LBBY', 'LOBBY', 'LOWR', 'LOWER', + 'OFC', 'OFFICE', 'PH', 'PENTHOUSE', 'TRLR', 'TRAILER', + 'UPPR', 'RM', 'ROOM', 'SIDE', 'SLIP', 'KEY', + 'LOT', 'PIER', 'REAR', 'SPC', 'SPACE', + 'STOP', 'STE', 'SUITE', 'UNIT', '#', + ); + + // overwriting $streetUnitFormats for 'en_CA' and 'fr_CA' locale + if (in_array($locale, array( + 'en_CA', 'fr_CA'))) { + $streetUnitFormats = array('APT', 'APP', 'SUITE', 'BUREAU', 'UNIT'); + } + + $streetUnitPreg = '/(' . implode('|\s', $streetUnitFormats) . ')(.+)?/i'; + $matches = array(); + if (preg_match($streetUnitPreg, $streetAddress, $matches)) { + $parseFields['street_unit'] = trim($matches[0]); + $streetAddress = str_replace($matches[0], '', $streetAddress); + $streetAddress = trim($streetAddress); + } + + // consider remaining string as street name. + $parseFields['street_name'] = $streetAddress; + + //run parsed fields through stripSpaces to clean + foreach ($parseFields as $parseField => $value) { + $parseFields[$parseField] = CRM_Utils_String::stripSpaces($value); + } + + return $parseFields; + } + + /** + * Validate the address fields based on the address options enabled + * in the Address Settings + * + * @param array $fields an array of importable/exportable contact fields + * + * @return array $fields an array of contact fields and only the enabled address options + * @access public + * @static + */ + static function validateAddressOptions($fields) { + static $addressOptions = NULL; + if (!$addressOptions) { + $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, + 'address_options', TRUE, NULL, TRUE + ); + } + + if (is_array($fields) && !empty($fields)) { + foreach ($addressOptions as $key => $value) { + if (!$value && isset($fields[$key])) { + unset($fields[$key]); + } + } + } + return $fields; + } + + /** + * Check if current address is used by any other contacts + * + * @param int $addressId address id + * + * @return count of contacts that use this shared address + * @access public + * @static + */ + static function checkContactSharedAddress($addressId) { + $query = 'SELECT count(id) FROM civicrm_address WHERE master_id = %1'; + return CRM_Core_DAO::singleValueQuery($query, array(1 => array($addressId, 'Integer'))); + } + + /** + * Function to check if current address fields are shared with any other address + * + * @param array $fields address fields in profile + * @param int $contactId contact id + * + * @access public + * @static + */ + static function checkContactSharedAddressFields(&$fields, $contactId) { + if (!$contactId || !is_array($fields) || empty($fields)) { + return; + } + + $sharedLocations = array(); + + $query = " +SELECT is_primary, + location_type_id + FROM civicrm_address + WHERE contact_id = %1 + AND master_id IS NOT NULL"; + + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($contactId, 'Positive'))); + while ($dao->fetch()) { + $sharedLocations[$dao->location_type_id] = $dao->location_type_id; + if ($dao->is_primary) { + $sharedLocations['Primary'] = 'Primary'; + } + } + + //no need to process further. + if (empty($sharedLocations)) { + return; + } + + $addressFields = array( + 'city', + 'county', + 'country', + 'geo_code_1', + 'geo_code_2', + 'postal_code', + 'address_name', + 'state_province', + 'street_address', + 'postal_code_suffix', + 'supplemental_address_1', + 'supplemental_address_2', + ); + + foreach ($fields as $name => & $values) { + if (!is_array($values) || empty($values)) { + continue; + } + + $nameVal = explode('-', $values['name']); + $fldName = CRM_Utils_Array::value(0, $nameVal); + $locType = CRM_Utils_Array::value(1, $nameVal); + if (CRM_Utils_Array::value('location_type_id', $values)) { + $locType = $values['location_type_id']; + } + + if (in_array($fldName, $addressFields) && + in_array($locType, $sharedLocations) + ) { + $values['is_shared'] = TRUE; + } + } + } + + /** + * Function to update the shared addresses if master address is modified + * + * @param int $addressId address id + * @param array $params associated array of address params + * + * @return void + * @access public + * @static + */ + static function processSharedAddress($addressId, $params) { + $query = 'SELECT id FROM civicrm_address WHERE master_id = %1'; + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($addressId, 'Integer'))); + + // unset contact id + $skipFields = array('is_primary', 'location_type_id', 'is_billing', 'master_id', 'contact_id'); + foreach ($skipFields as $value) { + unset($params[$value]); + } + + $addressDAO = new CRM_Core_DAO_Address(); + while ($dao->fetch()) { + $addressDAO->copyValues($params); + $addressDAO->id = $dao->id; + $addressDAO->save(); + $addressDAO->free(); + } + } + + /** + * Function to create relationship between contacts who share an address + * + * Note that currently we create relationship only for Individual contacts + * Individual + Household and Individual + Orgnization + * + * @param int $masterAddressId master address id + * @param array $params associated array of submitted values + * + * @return void + * @access public + * @static + */ + static function processSharedAddressRelationship($masterAddressId, $params) { + if (!$masterAddressId) { + return; + } + // get the contact type of contact being edited / created + $currentContactType = CRM_Contact_BAO_Contact::getContactType($params['contact_id']); + $currentContactId = $params['contact_id']; + + // if current contact is not of type individual return + if ($currentContactType != 'Individual') { + return; + } + + // get the contact id and contact type of shared contact + // check the contact type of shared contact, return if it is of type Individual + + $query = 'SELECT cc.id, cc.contact_type + FROM civicrm_contact cc INNER JOIN civicrm_address ca ON cc.id = ca.contact_id + WHERE ca.id = %1'; + + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($masterAddressId, 'Integer'))); + + $dao->fetch(); + + // if current contact is not of type individual return, since we don't create relationship between + // 2 individuals + if ($dao->contact_type == 'Individual') { + return; + } + $sharedContactType = $dao->contact_type; + $sharedContactId = $dao->id; + + // create relationship between ontacts who share an address + if ($sharedContactType == 'Organization') { + return CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($currentContactId, $sharedContactId); + } + else { + // get the relationship type id of "Household Member of" + $relationshipType = 'Household Member of'; + } + + $cid = array('contact' => $currentContactId); + + $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', $relationshipType, 'id', 'name_a_b'); + + if (!$relTypeId) { + CRM_Core_Error::fatal(ts("You seem to have deleted the relationship type '%1'", array(1 => $relationshipType))); + } + + // create relationship + $relationshipParams = array( + 'is_active' => TRUE, + 'relationship_type_id' => $relTypeId . '_a_b', + 'contact_check' => array($sharedContactId => TRUE), + ); + + list($valid, $invalid, $duplicate, + $saved, $relationshipIds + ) = CRM_Contact_BAO_Relationship::create($relationshipParams, $cid); + } + + /** + * Function to check and set the status for shared address delete + * + * @param int $addressId address id + * @param int $contactId contact id + * @param boolean $returnStatus by default false + * + * @return string $statusMessage + * @access public + * @static + */ + static function setSharedAddressDeleteStatus($addressId = NULL, $contactId = NULL, $returnStatus = FALSE) { + // check if address that is being deleted has any shared + if ($addressId) { + $entityId = $addressId; + $query = 'SELECT cc.id, cc.display_name + FROM civicrm_contact cc INNER JOIN civicrm_address ca ON cc.id = ca.contact_id + WHERE ca.master_id = %1'; + } + else { + $entityId = $contactId; + $query = 'SELECT cc.id, cc.display_name + FROM civicrm_address ca1 + INNER JOIN civicrm_address ca2 ON ca1.id = ca2.master_id + INNER JOIN civicrm_contact cc ON ca2.contact_id = cc.id + WHERE ca1.contact_id = %1'; + } + + $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($entityId, 'Integer'))); + + $deleteStatus = array(); + $sharedContactList = array(); + $statusMessage = NULL; + $addressCount = 0; + while ($dao->fetch()) { + if (empty($deleteStatus)) { + $deleteStatus[] = ts('The following contact(s) have address records which were shared with the address you removed from this contact. These address records are no longer shared - but they have not been removed or altered.'); + } + + $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$dao->id}"); + $sharedContactList[] = "{$dao->display_name}"; + $deleteStatus[] = "{$dao->display_name}"; + + $addressCount++; + } + + if (!empty($deleteStatus)) { + $statusMessage = implode('
    ', $deleteStatus) . '
    '; + } + + if (!$returnStatus) { + CRM_Core_Session::setStatus($statusMessage, '', 'info'); + } + else { + return array( + 'contactList' => $sharedContactList, + 'count' => $addressCount, + ); + } + } +} diff --git a/CRM/Core/BAO/Block.php b/CRM/Core/BAO/Block.php new file mode 100644 index 0000000000..92ff98a561 --- /dev/null +++ b/CRM/Core/BAO/Block.php @@ -0,0 +1,522 @@ + array('email'), + 'phone' => array('phone'), + 'im' => array('name'), + 'openid' => array('openid') + ); + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param Object $block typically a Phone|Email|IM|OpenID object + * @param string $blockName name of the above object + * @param array $params input parameters to find object + * @param array $values output values of the object + * + * @return array of $block objects. + * @access public + * @static + */ + static function &getValues($blockName, $params) { + if (empty($params)) { + return NULL; + } + eval('$block = new CRM_Core_BAO_' . $blockName . '( );'); + + $blocks = array(); + if (!isset($params['entity_table'])) { + $block->contact_id = $params['contact_id']; + if (!$block->contact_id) { + CRM_Core_Error::fatal(); + } + $blocks = self::retrieveBlock($block, $blockName); + } + else { + $blockIds = self::getBlockIds($blockName, NULL, $params); + + if (empty($blockIds)) { + return $blocks; + } + + $count = 1; + foreach ($blockIds as $blockId) { + eval('$block = new CRM_Core_BAO_' . $blockName . '( );'); + $block->id = $blockId['id']; + $getBlocks = self::retrieveBlock($block, $blockName); + $blocks[$count++] = array_pop($getBlocks); + } + } + + return $blocks; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param Object $block typically a Phone|Email|IM|OpenID object + * @param string $blockName name of the above object + * @param array $values output values of the object + * + * @return array of $block objects. + * @access public + * @static + */ + static function retrieveBlock(&$block, $blockName) { + // we first get the primary location due to the order by clause + $block->orderBy('is_primary desc, id'); + $block->find(); + + $count = 1; + $blocks = array(); + while ($block->fetch()) { + CRM_Core_DAO::storeValues($block, $blocks[$count]); + //unset is_primary after first block. Due to some bug in earlier version + //there might be more than one primary blocks, hence unset is_primary other than first + if ($count > 1) { + unset($blocks[$count]['is_primary']); + } + $count++; + } + + return $blocks; + } + + /** + * check if the current block object has any valid data + * + * @param array $blockFields array of fields that are of interest for this object + * @param array $params associated array of submitted fields + * + * @return boolean true if the block has data, otherwise false + * @access public + * @static + */ + static function dataExists($blockFields, &$params) { + foreach ($blockFields as $field) { + if (CRM_Utils_System::isNull(CRM_Utils_Array::value($field, $params))) { + return FALSE; + } + } + return TRUE; + } + + /** + * check if the current block exits + * + * @param string $blockName bloack name + * @param array $params associated array of submitted fields + * + * @return boolean true if the block exits, otherwise false + * @access public + * @static + */ + static function blockExists($blockName, &$params) { + // return if no data present + if (!CRM_Utils_Array::value($blockName, $params) || !is_array($params[$blockName])) { + return FALSE; + } + + return TRUE; + } + + /** + * Function to get all block ids for a contact + * + * @param string $blockName block name + * @param int $contactId contact id + * + * @return array $contactBlockIds formatted array of block ids + * + * @access public + * @static + */ + static function getBlockIds($blockName, $contactId = NULL, $entityElements = NULL, $updateBlankLocInfo = FALSE) { + $allBlocks = array(); + $name = ucfirst($blockName); + if ($blockName == 'im') { + $name = 'IM'; + } + elseif ($blockName == 'openid') { + $name = 'OpenID'; + } + + if ($contactId) { + eval('$allBlocks = CRM_Core_BAO_' . $name . '::all' . $name . 's( $contactId, $updateBlankLocInfo );'); + } + elseif (!empty($entityElements) && $blockName != 'openid') { + eval('$allBlocks = CRM_Core_BAO_' . $name . '::allEntity' . $name . 's( $entityElements );'); + } + + return $allBlocks; + } + + /** + * takes an associative array and creates a block + * + * @param string $blockName block name + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $requiredFields fields that's are required in a block + * + * @return object CRM_Core_BAO_Block object on success, null otherwise + * @access public + * @static + */ + static function create($blockName, &$params, $entity = NULL, $contactId = NULL) { + if (!self::blockExists($blockName, $params)) { + return NULL; + } + + $name = ucfirst($blockName); + $contactId = NULL; + $isPrimary = $isBilling = TRUE; + $entityElements = $blocks = array(); + + if ($entity) { + $entityElements = array( + 'entity_table' => $params['entity_table'], + 'entity_id' => $params['entity_id'], + ); + } + else { + $contactId = $params['contact_id']; + } + + $updateBlankLocInfo = CRM_Utils_Array::value('updateBlankLocInfo', $params, FALSE); + + //get existsing block ids. + $blockIds = self::getBlockIds($blockName, $contactId, $entityElements, $updateBlankLocInfo); + + if (!$updateBlankLocInfo) { + $resetPrimaryId = NULL; + $primaryId = FALSE; + foreach ($params[$blockName] as $count => $value) { + $blockId = CRM_Utils_Array::value('id', $value); + if ($blockId) { + if (is_array($blockIds) + && array_key_exists($blockId, $blockIds) + ) { + unset($blockIds[$blockId]); + } + else { + unset($value['id']); + } + } + //lets allow to update primary w/ more cleanly. + if (!$resetPrimaryId && + CRM_Utils_Array::value('is_primary', $value) + ) { + $primaryId = TRUE; + if (is_array($blockIds)) { + foreach ($blockIds as $blockId => $blockValue) { + if (CRM_Utils_Array::value('is_primary', $blockValue)) { + $resetPrimaryId = $blockId; + break; + } + } + } + if ($resetPrimaryId) { + eval('$block = new CRM_Core_BAO_' . $blockName . '( );'); + $block->selectAdd(); + $block->selectAdd("id, is_primary"); + $block->id = $resetPrimaryId; + if ($block->find(TRUE)) { + $block->is_primary = FALSE; + $block->save(); + } + $block->free(); + } + } + } + } + + foreach ($params[$blockName] as $count => $value) { + if (!is_array($value)) { + continue; + } + $contactFields = array( + 'contact_id' => $contactId, + 'location_type_id' => CRM_Utils_Array::value('location_type_id', $value), + ); + + //check for update + if (!CRM_Utils_Array::value('id', $value) && + is_array($blockIds) && !empty($blockIds) + ) { + foreach ($blockIds as $blockId => $blockValue) { + if ($updateBlankLocInfo) { + if (CRM_Utils_Array::value($count, $blockIds)) { + $value['id'] = $blockIds[$count]['id']; + unset($blockIds[$count]); + } + } + else { + if ($blockValue['locationTypeId'] == CRM_Utils_Array::value('location_type_id', $value)) { + $valueId = FALSE; + + if ($blockName == 'phone') { + $phoneTypeBlockValue = CRM_Utils_Array::value('phoneTypeId', $blockValue); + if ($phoneTypeBlockValue == $value['phone_type_id']) { + $valueId = TRUE; + } + } + elseif ($blockName == 'im') { + $providerBlockValue = CRM_Utils_Array::value('providerId', $blockValue); + if ($providerBlockValue == $value['provider_id']) { + $valueId = TRUE; + } + } + else { + $valueId = TRUE; + } + + if ($valueId) { + //assigned id as first come first serve basis + $value['id'] = $blockValue['id']; + if (!$primaryId && CRM_Utils_Array::value('is_primary', $blockValue)) { + $value['is_primary'] = $blockValue['is_primary']; + } + unset($blockIds[$blockId]); + break; + } + } + } + } + } + + $dataExits = self::dataExists(self::$requiredBlockFields[$blockName], $value); + + // Note there could be cases when block info already exist ($value[id] is set) for a contact/entity + // BUT info is not present at this time, and therefore we should be really careful when deleting the block. + // $updateBlankLocInfo will help take appropriate decision. CRM-5969 + if (CRM_Utils_Array::value('id', $value) && !$dataExits && $updateBlankLocInfo) { + //delete the existing record + self::blockDelete($blockName, array('id' => $value['id'])); + continue; + } + elseif (!$dataExits) { + continue; + } + + if ($isPrimary && CRM_Utils_Array::value('is_primary', $value)) { + $contactFields['is_primary'] = $value['is_primary']; + $isPrimary = FALSE; + } + else { + $contactFields['is_primary'] = 0; + } + + if ($isBilling && CRM_Utils_Array::value('is_billing', $value)) { + $contactFields['is_billing'] = $value['is_billing']; + $isBilling = FALSE; + } + else { + $contactFields['is_billing'] = 0; + } + + $blockFields = array_merge($value, $contactFields); + eval('$blocks[] = CRM_Core_BAO_' . $name . '::add( $blockFields );'); + } + + // we need to delete blocks that were deleted during update + if ($updateBlankLocInfo && !empty($blockIds)) { + foreach ($blockIds as $deleteBlock) { + if (!CRM_Utils_Array::value('id', $deleteBlock)) { + continue; + } + self::blockDelete($blockName, array('id' => $deleteBlock['id'])); + } + } + + return $blocks; + } + + /** + * Function to delete block + * + * @param string $blockName block name + * @param int $params associates array + * + * @return void + * @static + */ + static function blockDelete($blockName, $params) { + $name = ucfirst($blockName); + if ($blockName == 'im') { + $name = 'IM'; + } + elseif ($blockName == 'openid') { + $name = 'OpenID'; + } + + require_once "CRM/Core/DAO/{$name}.php"; + eval('$block = new CRM_Core_DAO_' . $name . '( );'); + + $block->copyValues($params); + /* + * CRM-11006 add call to pre and post hook for delete action + */ + CRM_Utils_Hook::pre('delete', $name, $block->id, CRM_Core_DAO::$_nullArray); + $block->delete(); + CRM_Utils_Hook::post('delete', $name, $block->id, $block); + } + + /** + * Handling for is_primary. + * $params is_primary could be + * # 1 - find other entries with is_primary = 1 & reset them to 0 + * # 0 - make sure at least one entry is set to 1 + * - if no other entry is 1 change to 1 + * - if one other entry exists change that to 1 + * - if more than one other entry exists change first one to 1 + * @fixme - perhaps should choose by location_type + * # empty - same as 0 as once we have checked first step + * we know if it should be 1 or 0 + * + * if $params['id'] is set $params['contact_id'] may need to be retrieved + * + * @param array $params + * @static + */ + public static function handlePrimary(&$params, $class) { + switch ($class) { + case 'CRM_Core_BAO_Phone': + $table = 'civicrm_phone'; + break; + + case 'CRM_Core_BAO_Email': + $table = 'civicrm_email'; + break; + + case 'CRM_Core_BAO_Address': + $table = 'civicrm_address'; + break; + } + // if id is set & we don't have contact_id we need to retrieve it + $contactId = null; + if (!empty($params['id']) && empty($params['contact_id'])) { + $entity = new $class(); + $entity->id = $params['id']; + $entity->find(TRUE); + $contactId = $entity->contact_id; + } + elseif (CRM_Utils_Array::value('contact_id', $params)) { + $contactId = $params['contact_id']; + } + if ( !$contactId ) { + // entity not associated with contact so concept of is_primary not relevant + return; + } + + // if params is_primary then set all others to not be primary & exit out + if (CRM_Utils_Array::value('is_primary', $params)) { + $sql = "UPDATE $table SET is_primary = 0 WHERE contact_id = %1"; + $sqlParams = array(1 => array($contactId, 'Integer')); + // we don't want to create unecessary entries in the log_ tables so exclude the one we are working on + if(!empty($params['id'])){ + $sql .= " AND id <> %2"; + $sqlParams[2] = array($params['id'], 'Integer'); + } + CRM_Core_DAO::executeQuery($sql, $sqlParams); + return; + } + + //Check what other emails exist for the contact + $existingEntities = new $class(); + $existingEntities->contact_id = $contactId; + $existingEntities->orderBy('is_primary DESC'); + if (!$existingEntities->find(TRUE) || (!empty($params['id']) && $existingEntities->id == $params['id'])) { + // ie. if no others is set to be primary then this has to be primary set to 1 so change + $params['is_primary'] = 1; + return; + } + else { + /* + * If the only existing email is the one we are editing then we must set + * is_primary to 1 + * CRM-10451 + */ + if ( $existingEntities->N == 1 && $existingEntities->id == CRM_Utils_Array::value( 'id', $params ) ) { + $params['is_primary'] = 1; + return; + } + + if ($existingEntities->is_primary == 1) { + return; + } + // so at this point we are only dealing with ones explicity setting is_primary to 0 + // since we have reverse sorted by email we can either set the first one to + // primary or return if is already is + $existingEntities->is_primary = 1; + $existingEntities->save(); + } + } + + /** + * Sort location array so primary element is first + * @param Array $location + */ + static function sortPrimaryFirst(&$locations){ + uasort($locations, 'self::primaryComparison'); + } + +/** + * compare 2 locations to see which should go first based on is_primary + * (sort function for sortPrimaryFirst) + * @param array $location1 + * @param array_type $location2 + * @return number + */ + static function primaryComparison($location1, $location2){ + $l1 = CRM_Utils_Array::value('is_primary', $location1); + $l2 = CRM_Utils_Array::value('is_primary', $location2); + if ($l1 == $l2) { + return 0; + } + return ($l1 < $l2) ? -1 : 1; + } +} + diff --git a/CRM/Core/BAO/CMSUser.php b/CRM/Core/BAO/CMSUser.php new file mode 100644 index 0000000000..a5fbc41066 --- /dev/null +++ b/CRM/Core/BAO/CMSUser.php @@ -0,0 +1,494 @@ +userSystem->is_drupal == '1') { + $id = 'uid'; + $mail = 'mail'; + $name = 'name'; + + $result = db_query("SELECT uid, mail, name FROM {users} where mail != ''"); + + if ($config->userFramework == 'Drupal') { + while ($row = $result->fetchAssoc()) { + $rows[] = $row; + } + } + elseif ($config->userFramework == 'Drupal6') { + while ($row = db_fetch_array($result)) { + $rows[] = $row; + } + } + } + elseif ($config->userFramework == 'Joomla') { + $id = 'id'; + $mail = 'email'; + $name = 'name'; + // TODO: Insert code here to populate $rows for Joomla; + } + elseif ($config->userFramework == 'WordPress') { + $id = 'ID'; + $mail = 'user_email'; + } + else { + CRM_Core_Error::fatal('CMS user creation not supported for this framework'); + } + + set_time_limit(300); + + if ($config->userSystem->is_drupal == '1') { + $user = new StdClass(); + $uf = $config->userFramework; + $contactCount = 0; + $contactCreated = 0; + $contactMatching = 0; + foreach ($rows as $row) { + $user->$id = $row[$id]; + $user->$mail = $row[$mail]; + $user->$name = $row[$name]; + $contactCount++; + if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($user, $row[$id], $row[$mail], $uf, 1, 'Individual', TRUE)) { + $contactCreated++; + } + else { + $contactMatching++; + } + if (is_object($match)) { + $match->free(); + } + } + } + elseif ($config->userFramework == 'Joomla') { + + $JUserTable = &JTable::getInstance('User', 'JTable'); + + $db = $JUserTable->getDbo(); + $query = $db->getQuery(TRUE); + $query->select($id . ', ' . $mail . ', ' . $name); + $query->from($JUserTable->getTableName()); + $query->where($mail != ''); + + $db->setQuery($query, 0, $limit); + $users = $db->loadObjectList(); + + $user = new StdClass(); + $uf = $config->userFramework; + $contactCount = 0; + $contactCreated = 0; + $contactMatching = 0; + for ($i = 0; $i < count($users); $i++) { + $user->$id = $users[$i]->$id; + $user->$mail = $users[$i]->$mail; + $user->$name = $users[$i]->$name; + $contactCount++; + if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($user, + $users[$i]->$id, + $users[$i]->$mail, + $uf, + 1, + 'Individual', + TRUE + )) { + $contactCreated++; + } + else { + $contactMatching++; + } + if (is_object($match)) { + $match->free(); + } + } + } + elseif ($config->userFramework == 'WordPress') { + $uf = $config->userFramework; + $contactCount = 0; + $contactCreated = 0; + $contactMatching = 0; + + global $wpdb; + $wpUserIds = $wpdb->get_col( + $wpdb->prepare("SELECT $wpdb->users.ID FROM $wpdb->users") + ); + + foreach ($wpUserIds as $wpUserId) { + $wpUserData = get_userdata($wpUserId); + $contactCount++; + if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($wpUserData, + $wpUserData->$id, + $wpUserData->$mail, + $uf, + 1, + 'Individual', + TRUE + )) { + $contactCreated++; + } + else { + $contactMatching++; + } + if (is_object($match)) { + $match->free(); + } + } + } + //end of schronization code + $status = ts('Synchronize Users to Contacts completed.'); + $status .= ' ' . ts('Checked one user record.', + array( + 'count' => $contactCount, + 'plural' => 'Checked %count user records.' + ) + ); + if ($contactMatching) { + $status .= ' ' . ts('Found one matching contact record.', + array( + 'count' => $contactMatching, + 'plural' => 'Found %count matching contact records.' + ) + ); + } + + $status .= ' ' . ts('Created one new contact record.', + array( + 'count' => $contactCreated, + 'plural' => 'Created %count new contact records.' + ) + ); + CRM_Core_Session::setStatus($status, ts('Saved'), 'success'); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + } + + /** + * Function to create CMS user using Profile + * + * @param array $params associated array + * @param string $mail email id for cms user + * + * @return int contact id that has been created + * @access public + * @static + */ + static function create(&$params, $mail) { + $config = CRM_Core_Config::singleton(); + + $ufID = $config->userSystem->createUser($params, $mail); + + //if contact doesn't already exist create UF Match + if ($ufID !== FALSE && + isset($params['contactID']) + ) { + // create the UF Match record + $ufmatch = new CRM_Core_DAO_UFMatch(); + $ufmatch->domain_id = CRM_Core_Config::domainID(); + $ufmatch->uf_id = $ufID; + $ufmatch->contact_id = $params['contactID']; + $ufmatch->uf_name = $params[$mail]; + + if (!$ufmatch->find(TRUE)) { + $ufmatch->save(); + } + } + + return $ufID; + } + + /** + * Function to create Form for CMS user using Profile + * + * @param object $form + * @param integer $gid id of group of profile + * @param bool $emailPresent true if the profile field has email(primary) + * @return FALSE|void WTF + * + * @access public + * @static + */ + static function buildForm(&$form, $gid, $emailPresent, $action = CRM_Core_Action::NONE) { + $config = CRM_Core_Config::singleton(); + $showCMS = FALSE; + + $isDrupal = $config->userSystem->is_drupal; + $isJoomla = ucfirst($config->userFramework) == 'Joomla' ? TRUE : FALSE; + $isWordPress = $config->userFramework == 'WordPress' ? TRUE : FALSE; + + //if CMS is configured for not to allow creating new CMS user, + //don't build the form,Fixed for CRM-4036 + if ($isJoomla) { + $userParams = JComponentHelper::getParams('com_users'); + if (!$userParams->get('allowUserRegistration')) { + return FALSE; + } + } + elseif ($isDrupal && !variable_get('user_register', TRUE)) { + return FALSE; + } + elseif ($isWordPress && !get_option('users_can_register')) { + return FALSE; + } + + if ($gid) { + $isCMSUser = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'is_cms_user'); + } + + // $cms is true when there is email(primary location) is set in the profile field. + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + $showUserRegistration = FALSE; + if ($action) { + $showUserRegistration = TRUE; + } + elseif (!$action && !$userID) { + $showUserRegistration = TRUE; + } + + if ($isCMSUser && $emailPresent) { + if ($showUserRegistration) { + if ($isCMSUser != 2) { + $extra = array( + 'onclick' => "return showHideByValue('cms_create_account','','details','block','radio',false );", + ); + $form->addElement('checkbox', 'cms_create_account', ts('Create an account?'), NULL, $extra); + $required = FALSE; + } + else { + $form->add('hidden', 'cms_create_account', 1); + $required = TRUE; + } + + $form->assign('isCMS', $required); + if (!$userID || $action & CRM_Core_Action::PREVIEW || $action & CRM_Core_Action::PROFILE) { + $form->add('text', 'cms_name', ts('Username'), NULL, $required); + if (($isDrupal && !variable_get('user_email_verification', TRUE)) OR ($isJoomla) OR ($isWordPress)) { + $form->add('password', 'cms_pass', ts('Password')); + $form->add('password', 'cms_confirm_pass', ts('Confirm Password')); + } + + $form->addFormRule(array('CRM_Core_BAO_CMSUser', 'formRule'), $form); + } + $showCMS = TRUE; + } + } + + $destination = $config->userSystem->getLoginDestination($form); + $loginURL = $config->userSystem->getLoginURL($destination); + $form->assign('loginURL', $loginURL); + $form->assign('showCMS', $showCMS); + } + + /* + * Checks that there is a valid username & email + * optionally checks password is present & matches DB & gets the CMS to validate + * + * @params array $fields Posted values of form + * @param array $files uploaded files if any + * @param array $self reference to form object + * + */ + static function formRule($fields, $files, $self) { + if (!CRM_Utils_Array::value('cms_create_account', $fields)) { + return TRUE; + } + + $config = CRM_Core_Config::singleton(); + + $isDrupal = $config->userSystem->is_drupal; + $isJoomla = ucfirst($config->userFramework) == 'Joomla' ? TRUE : FALSE; + $isWordPress = $config->userFramework == 'WordPress' ? TRUE : FALSE; + + $errors = array(); + if ($isDrupal || $isJoomla || $isWordPress) { + $emailName = NULL; + if (!empty($self->_bltID) && array_key_exists("email-{$self->_bltID}", $fields)) { + // this is a transaction related page + $emailName = 'email-' . $self->_bltID; + } else { + // find the email field in a profile page + foreach ($fields as $name => $dontCare) { + if (substr($name, 0, 5) == 'email') { + $emailName = $name; + break; + } + } + } + + if ($emailName == NULL) { + $errors['_qf_default'] == ts('Could not find an email address.'); + return $errors; + } + + if (empty($fields['cms_name'])) { + $errors['cms_name'] = ts('Please specify a username.'); + } + + if (empty($fields[$emailName])) { + $errors[$emailName] = ts('Please specify a valid email address.'); + } + + if (($isDrupal && !variable_get('user_email_verification', TRUE)) OR ($isJoomla) OR ($isWordPress)) { + if (empty($fields['cms_pass']) || + empty($fields['cms_confirm_pass']) + ) { + $errors['cms_pass'] = ts('Please enter a password.'); + } + if ($fields['cms_pass'] != $fields['cms_confirm_pass']) { + $errors['cms_pass'] = ts('Password and Confirm Password values are not the same.'); + } + } + + if (!empty($errors)) { + return $errors; + } + + // now check that the cms db does not have the user name and/or email + if ($isDrupal OR $isJoomla OR $isWordPress) { + $params = array( + 'name' => $fields['cms_name'], + 'mail' => $fields[$emailName], + ); + } + + $config->userSystem->checkUserNameEmailExists($params, $errors, $emailName); + } + return (!empty($errors)) ? $errors : TRUE; + } + + /** + * Function to check if a cms user already exists. + * + * @param Array $contact array of contact-details + * + * @return uid if user exists, false otherwise + * + * @access public + * @static + */ + static function userExists(&$contact) { + $config = CRM_Core_Config::singleton(); + + $isDrupal = $config->userSystem->is_drupal; + $isJoomla = ucfirst($config->userFramework) == 'Joomla' ? TRUE : FALSE; + $isWordPress = $config->userFramework == 'WordPress' ? TRUE : FALSE; + + if (!$isDrupal && !$isJoomla && !$isWordPress) { + die('Unknown user framework'); + } + + // Use UF native framework to fetch data from UF user table + if ($isDrupal) { + $uid = db_query( + "SELECT uid FROM {users} where mail = :email", + array(':email' => $contact['email']) + )->fetchField(); + + if ($uid) { + $contact['user_exists'] = TRUE; + $result = $uid; + } + } + elseif ($isJoomla) { + $mail = $contact['email']; + + $JUserTable = &JTable::getInstance('User', 'JTable'); + + $db = $JUserTable->getDbo(); + $query = $db->getQuery(TRUE); + $query->select('username, email'); + $query->from($JUserTable->getTableName()); + $query->where('(LOWER(email) = LOWER(\'' . $email . '\'))'); + $db->setQuery($query, 0, $limit); + $users = $db->loadAssocList(); + + $row = array();; + if (count($users)) { + $row = $users[0]; + } + + if (!empty($row)) { + $uid = CRM_Utils_Array::value('id', $row); + $contact['user_exists'] = TRUE; + $result = $uid; + } + } + elseif ($isWordPress) { + if (email_exists($params['mail'])) { + $contact['user_exists'] = TRUE; + $userObj = get_user_by('email', $params['mail']); + return $userObj->ID; + } + } + + return $result; + } + + static function &dbHandle(&$config) { + CRM_Core_Error::ignoreException(); + $db_uf = DB::connect($config->userFrameworkDSN); + CRM_Core_Error::setCallback(); + if (!$db_uf || + DB::isError($db_uf) + ) { + $session = CRM_Core_Session::singleton(); + $session->pushUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1')); + CRM_Core_Error::statusBounce(ts("Cannot connect to UF db via %1. Please check the CIVICRM_UF_DSN value in your civicrm.settings.php file", + array(1 => $db_uf->getMessage()) + )); + } + $db_uf->query('/*!40101 SET NAMES utf8 */'); + return $db_uf; + } +} + diff --git a/CRM/Core/BAO/Cache.php b/CRM/Core/BAO/Cache.php new file mode 100644 index 0000000000..f506009414 --- /dev/null +++ b/CRM/Core/BAO/Cache.php @@ -0,0 +1,341 @@ +group_name = $group; + $dao->path = $path; + $dao->component_id = $componentID; + + $data = NULL; + if ($dao->find(TRUE)) { + $data = unserialize($dao->data); + } + $dao->free(); + return $data; + } + + /** + * Retrieve all items in a group + * + * @param string $group (required) The group name of the item + * @param int $componentID The optional component ID (so componenets can share the same name space) + * + * @return object The data if present in cache, else null + * @static + * @access public + */ + static function &getItems($group, $componentID = NULL) { + $dao = new CRM_Core_DAO_Cache(); + + $dao->group_name = $group; + $dao->component_id = $componentID; + $dao->find(); + + $result = array(); // array($path => $data) + while ($dao->fetch()) { + $result[$dao->path] = unserialize($dao->data); + } + $dao->free(); + return $result; + } + + /** + * Store an item in the DB cache + * + * @param object $data (required) A reference to the data that will be serialized and stored + * @param string $group (required) The group name of the item + * @param string $path (required) The path under which this item is stored + * @param int $componentID The optional component ID (so componenets can share the same name space) + * + * @return void + * @static + * @access public + */ + static function setItem(&$data, $group, $path, $componentID = NULL) { + $dao = new CRM_Core_DAO_Cache(); + + $dao->group_name = $group; + $dao->path = $path; + $dao->component_id = $componentID; + + // get a lock so that multiple ajax requests on the same page + // dont trample on each other + // CRM-11234 + $lockName = "civicrm.cache.{$group}_{$path}._{$componentID}"; + $lock = new CRM_Core_Lock($lockName); + if (!$lock->isAcquired()) { + CRM_Core_Error::fatal(); + } + + $dao->find(TRUE); + $dao->data = serialize($data); + $dao->created_date = date('YmdHis'); + $dao->save(); + + $lock->release(); + + $dao->free(); + } + + /** + * Delete all the cache elements that belong to a group OR + * delete the entire cache if group is not specified + * + * @param string $group The group name of the entries to be deleted + * @param string $path path of the item that needs to be deleted + * @param booleab $clearAll clear all caches + * + * @return void + * @static + * @access public + */ + static function deleteGroup($group = NULL, $path = NULL, $clearAll = TRUE) { + $dao = new CRM_Core_DAO_Cache(); + + if (!empty($group)) { + $dao->group_name = $group; + } + + if (!empty($path)) { + $dao->path = $path; + } + + $dao->delete(); + + if ($clearAll) { + // also reset ACL Cache + CRM_ACL_BAO_Cache::resetCache(); + + // also reset memory cache if any + CRM_Utils_System::flushCache(); + } + } + + /** + * The next two functions are internal functions used to store and retrieve session from + * the database cache. This keeps the session to a limited size and allows us to + * create separate session scopes for each form in a tab + * + */ + + /** + * This function takes entries from the session array and stores it in the cache. + * It also deletes the entries from the $_SESSION object (for a smaller session size) + * + * @param array $names Array of session values that should be persisted + * This is either a form name + qfKey or just a form name + * (in the case of profile) + * @param boolean $resetSession Should session state be reset on completion of DB store? + * + * @return void + * @static + * @access private + */ + static function storeSessionToCache($names, $resetSession = TRUE) { + foreach ($names as $key => $sessionName) { + if (is_array($sessionName)) { + $value = null; + if (!empty($_SESSION[$sessionName[0]][$sessionName[1]])) { + $value = $_SESSION[$sessionName[0]][$sessionName[1]]; + } + self::setItem($value, 'CiviCRM Session', "{$sessionName[0]}_{$sessionName[1]}"); + if ($resetSession) { + $_SESSION[$sessionName[0]][$sessionName[1]] = NULL; + unset($_SESSION[$sessionName[0]][$sessionName[1]]); + } + } + else { + $value = null; + if (!empty($_SESSION[$sessionName])) { + $value = $_SESSION[$sessionName]; + } + self::setItem($value, 'CiviCRM Session', $sessionName); + if ($resetSession) { + $_SESSION[$sessionName] = NULL; + unset($_SESSION[$sessionName]); + } + } + } + + self::cleanup(); + } + + /* Retrieve the session values from the cache and populate the $_SESSION array + * + * @param array $names Array of session values that should be persisted + * This is either a form name + qfKey or just a form name + * (in the case of profile) + * + * @return void + * @static + * @access private + */ + + static function restoreSessionFromCache($names) { + foreach ($names as $key => $sessionName) { + if (is_array($sessionName)) { + $value = self::getItem('CiviCRM Session', + "{$sessionName[0]}_{$sessionName[1]}" + ); + if ($value) { + $_SESSION[$sessionName[0]][$sessionName[1]] = $value; + } + } + else { + $value = self::getItem('CiviCRM Session', + $sessionName + ); + if ($value) { + $_SESSION[$sessionName] = $value; + } + } + } + } + + /** + * Do periodic cleanup of the CiviCRM session table. Also delete all session cache entries + * which are a couple of days old. This keeps the session cache to a manageable size + * + * @return void + * @static + * @access private + */ + static function cleanup($session = false, $table = false, $prevNext = false) { + // clean up the session cache every $cacheCleanUpNumber probabilistically + $cleanUpNumber = 757; + + // clean up all sessions older than $cacheTimeIntervalDays days + $timeIntervalDays = 2; + $timeIntervalMins = 30; + + if (mt_rand(1, 100000) % $cleanUpNumber == 0) { + $session = $table = $prevNext = true; + } + + if ( ! $session && ! $table && ! $prevNext ) { + return; + } + + if ( $prevNext ) { + // delete all PrevNext caches + CRM_Core_BAO_PrevNextCache::cleanupCache(); + } + + if ( $table ) { + // also delete all the action temp tables + // that were created the same interval ago + $dao = new CRM_Core_DAO(); + $query = " +SELECT TABLE_NAME as tableName +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA = %1 +AND ( TABLE_NAME LIKE 'civicrm_task_action_temp_%' + OR TABLE_NAME LIKE 'civicrm_export_temp_%' + OR TABLE_NAME LIKE 'civicrm_import_job_%' ) +AND CREATE_TIME < date_sub( NOW( ), INTERVAL $timeIntervalDays day ) +"; + + $params = array(1 => array($dao->database(), 'String')); + $tableDAO = CRM_Core_DAO::executeQuery($query, $params); + $tables = array(); + while ($tableDAO->fetch()) { + $tables[] = $tableDAO->tableName; + } + if (!empty($tables)) { + $table = implode(',', $tables); + // drop leftover temporary tables + CRM_Core_DAO::executeQuery("DROP TABLE $table"); + } + } + + if ( $session ) { + // first delete all sessions which are related to any potential transaction + // page + $transactionPages = array( + 'CRM_Contribute_Controller_Contribution', + 'CRM_Event_Controller_Registration', + ); + + $params = array( + 1 => array(date('Y-m-d H:i:s', time() - $timeIntervalMins * 60), 'String'), + ); + foreach ($transactionPages as $trPage) { + $params[] = array("%${trPage}%", 'String'); + $where[] = 'path LIKE %' . sizeof($params); + } + + $sql = " +DELETE FROM civicrm_cache +WHERE group_name = 'CiviCRM Session' +AND created_date <= %1 +AND (" . implode(' OR ', $where) . ")"; + CRM_Core_DAO::executeQuery($sql, $params); + + $sql = " +DELETE FROM civicrm_cache +WHERE group_name = 'CiviCRM Session' +AND created_date < date_sub( NOW( ), INTERVAL $timeIntervalDays DAY ) +"; + CRM_Core_DAO::executeQuery($sql); + } +} +} + diff --git a/CRM/Core/BAO/ConfigSetting.php b/CRM/Core/BAO/ConfigSetting.php new file mode 100644 index 0000000000..4a392d83ce --- /dev/null +++ b/CRM/Core/BAO/ConfigSetting.php @@ -0,0 +1,664 @@ +delete('CRM_Core_Config'); + $config = CRM_Core_Config::singleton(TRUE, TRUE); + } + + /** + * Function to add civicrm settings + * + * @params array $params associated array of civicrm variables + * + * @return null + * @static + */ + static function add(&$params) { + self::fixParams($params); + + // also set a template url so js files can use this + // CRM-6194 + $params['civiRelativeURL'] = CRM_Utils_System::url('CIVI_BASE_TEMPLATE'); + $params['civiRelativeURL'] = str_replace('CIVI_BASE_TEMPLATE', + '', + $params['civiRelativeURL'] + ); + + $domain = new CRM_Core_DAO_Domain(); + $domain->id = CRM_Core_Config::domainID(); + $domain->find(TRUE); + if ($domain->config_backend) { + $values = unserialize($domain->config_backend); + self::formatParams($params, $values); + } + + // CRM-6151 + if (isset($params['localeCustomStrings']) && + is_array($params['localeCustomStrings']) + ) { + $domain->locale_custom_strings = serialize($params['localeCustomStrings']); + } + + // unset any of the variables we read from file that should not be stored in the database + // the username and certpath are stored flat with _test and _live + // check CRM-1470 + $skipVars = self::skipVars(); + foreach ($skipVars as $var) { + unset($params[$var]); + } + + CRM_Core_BAO_Setting::fixAndStoreDirAndURL($params); + + // also skip all Dir Params, we dont need to store those in the DB! + foreach ($params as $name => $val) { + if (substr($name, -3) == 'Dir') { + unset($params[$name]); + } + } + + //keep user preferred language upto date, CRM-7746 + $session = CRM_Core_Session::singleton(); + $lcMessages = CRM_Utils_Array::value('lcMessages', $params); + if ($lcMessages && $session->get('userID')) { + $languageLimit = CRM_Utils_Array::value('languageLimit', $params); + if (is_array($languageLimit) && + !in_array($lcMessages, array_keys($languageLimit)) + ) { + $lcMessages = $session->get('lcMessages'); + } + + $ufm = new CRM_Core_DAO_UFMatch(); + $ufm->contact_id = $session->get('userID'); + if ($lcMessages && $ufm->find(TRUE)) { + $ufm->language = $lcMessages; + $ufm->save(); + $session->set('lcMessages', $lcMessages); + $params['lcMessages'] = $lcMessages; + } + } + + $domain->config_backend = serialize($params); + $domain->save(); + } + + /** + * Function to fix civicrm setting variables + * + * @params array $params associated array of civicrm variables + * + * @return null + * @static + */ + static function fixParams(&$params) { + // in our old civicrm.settings.php we were using ISO code for country and + // province limit, now we have changed it to use ids + + $countryIsoCodes = CRM_Core_PseudoConstant::countryIsoCode(); + + $specialArray = array('countryLimit', 'provinceLimit'); + + foreach ($params as $key => $value) { + if (in_array($key, $specialArray) && is_array($value)) { + foreach ($value as $k => $val) { + if (!is_numeric($val)) { + $params[$key][$k] = array_search($val, $countryIsoCodes); + } + } + } + elseif ($key == 'defaultContactCountry') { + if (!is_numeric($value)) { + $params[$key] = array_search($value, $countryIsoCodes); + } + } + } + } + + /** + * Function to format the array containing before inserting in db + * + * @param array $params associated array of civicrm variables(submitted) + * @param array $values associated array of civicrm variables stored in db + * + * @return null + * @static + */ + static function formatParams(&$params, &$values) { + if (empty($params) || + !is_array($params) + ) { + $params = $values; + } + else { + foreach ($params as $key => $val) { + if (array_key_exists($key, $values)) { + unset($values[$key]); + } + } + $params = array_merge($params, $values); + } + } + + /** + * Function to retrieve the settings values from db + * + * @return array $defaults + * @static + */ + static function retrieve(&$defaults) { + $domain = new CRM_Core_DAO_Domain(); + + //we are initializing config, really can't use, CRM-7863 + $urlVar = 'q'; + if (defined('CIVICRM_UF') && CIVICRM_UF == 'Joomla') { + $urlVar = 'task'; + } + + if (CRM_Core_Config::isUpgradeMode()) { + $domain->selectAdd('config_backend'); + } + elseif (CRM_Utils_Array::value($urlVar, $_GET) == 'admin/modules/list/confirm') { + $domain->selectAdd('config_backend', 'locales'); + } + else { + $domain->selectAdd('config_backend, locales, locale_custom_strings'); + } + + $domain->id = CRM_Core_Config::domainID(); + $domain->find(TRUE); + if ($domain->config_backend) { + $defaults = unserialize($domain->config_backend); + if ($defaults === FALSE || !is_array($defaults)) { + $defaults = array(); + return; + } + + $skipVars = self::skipVars(); + foreach ($skipVars as $skip) { + if (array_key_exists($skip, $defaults)) { + unset($defaults[$skip]); + } + } + + // since language field won't be present before upgrade. + if (CRM_Core_Config::isUpgradeMode()) { + // dont add if its empty + if (!empty($defaults)) { + // retrieve directory and url preferences also + CRM_Core_BAO_Setting::retrieveDirectoryAndURLPreferences($defaults); + } + return; + } + + // check if there are any locale strings + if ($domain->locale_custom_strings) { + $defaults['localeCustomStrings'] = unserialize($domain->locale_custom_strings); + } + else { + $defaults['localeCustomStrings'] = NULL; + } + + // are we in a multi-language setup? + $multiLang = $domain->locales ? TRUE : FALSE; + + // set the current language + $lcMessages = NULL; + + $session = CRM_Core_Session::singleton(); + + // on multi-lang sites based on request and civicrm_uf_match + if ($multiLang) { + $lcMessagesRequest = CRM_Utils_Request::retrieve('lcMessages', 'String', $this); + $languageLimit = array(); + if (array_key_exists('languageLimit', $defaults) && is_array($defaults['languageLimit'])) { + $languageLimit = $defaults['languageLimit']; + } + + if (in_array($lcMessagesRequest, array_keys($languageLimit))) { + $lcMessages = $lcMessagesRequest; + + //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache. + CRM_Core_BAO_Cache::deleteGroup('navigation'); + } + else { + $lcMessagesRequest = NULL; + } + + if (!$lcMessagesRequest) { + $lcMessagesSession = $session->get('lcMessages'); + if (in_array($lcMessagesSession, array_keys($languageLimit))) { + $lcMessages = $lcMessagesSession; + } + else { + $lcMessagesSession = NULL; + } + } + + if ($lcMessagesRequest) { + $ufm = new CRM_Core_DAO_UFMatch(); + $ufm->contact_id = $session->get('userID'); + if ($ufm->find(TRUE)) { + $ufm->language = $lcMessages; + $ufm->save(); + } + $session->set('lcMessages', $lcMessages); + } + + if (!$lcMessages and $session->get('userID')) { + $ufm = new CRM_Core_DAO_UFMatch(); + $ufm->contact_id = $session->get('userID'); + if ($ufm->find(TRUE) && + in_array($ufm->language, array_keys($languageLimit)) + ) { + $lcMessages = $ufm->language; + } + $session->set('lcMessages', $lcMessages); + } + } + global $dbLocale; + + // try to inherit the language from the hosting CMS + if (CRM_Utils_Array::value('inheritLocale', $defaults)) { + // FIXME: On multilanguage installs, CRM_Utils_System::getUFLocale() in many cases returns nothing if $dbLocale is not set + $dbLocale = $multiLang ? "_{$defaults['lcMessages']}" : ''; + $lcMessages = CRM_Utils_System::getUFLocale(); + if ($domain->locales and !in_array($lcMessages, explode(CRM_Core_DAO::VALUE_SEPARATOR, + $domain->locales + ))) { + $lcMessages = NULL; + } + } + + if ($lcMessages) { + // update config lcMessages - CRM-5027 fixed. + $defaults['lcMessages'] = $lcMessages; + } + else { + // if a single-lang site or the above didn't yield a result, use default + $lcMessages = CRM_Utils_Array::value( 'lcMessages', $defaults ); + } + + // set suffix for table names - use views if more than one language + $dbLocale = $multiLang ? "_{$lcMessages}" : ''; + + // FIXME: an ugly hack to fix CRM-4041 + global $tsLocale; + $tsLocale = $lcMessages; + + // FIXME: as bad aplace as any to fix CRM-5428 + // (to be moved to a sane location along with the above) + if (function_exists('mb_internal_encoding')) { + mb_internal_encoding('UTF-8'); + } + } + + // dont add if its empty + if (!empty($defaults)) { + // retrieve directory and url preferences also + CRM_Core_BAO_Setting::retrieveDirectoryAndURLPreferences($defaults); + } + } + + static function getConfigSettings() { + $config = CRM_Core_Config::singleton(); + + $url = $dir = $siteName = $siteRoot = NULL; + if ($config->userFramework == 'Joomla') { + $url = preg_replace('|administrator/components/com_civicrm/civicrm/|', + '', + $config->userFrameworkResourceURL + ); + + // lets use imageUploadDir since we dont mess around with its values + // in the config object, lets kep it a bit generic since folks + // might have different values etc + $dir = preg_replace('|civicrm/templates_c/.*$|', + '', + $config->templateCompileDir + ); + $siteRoot = preg_replace('|/media/civicrm/.*$|', + '', + $config->imageUploadDir + ); + } + else { + $url = preg_replace('|sites/[\w\.\-\_]+/modules/civicrm/|', + '', + $config->userFrameworkResourceURL + ); + + // lets use imageUploadDir since we dont mess around with its values + // in the config object, lets kep it a bit generic since folks + // might have different values etc + $dir = preg_replace('|/files/civicrm/.*$|', + '/files/', + $config->imageUploadDir + ); + + $matches = array(); + if (preg_match('|/sites/([\w\.\-\_]+)/|', + $config->imageUploadDir, + $matches + )) { + $siteName = $matches[1]; + if ($siteName) { + $siteName = "/sites/$siteName/"; + $siteNamePos = strpos($dir, $siteName); + if ($siteNamePos !== FALSE) { + $siteRoot = substr($dir, 0, $siteNamePos); + } + } + } + } + + + return array($url, $dir, $siteName, $siteRoot); + } + + static function getBestGuessSettings() { + $config = CRM_Core_Config::singleton(); + + $url = $config->userFrameworkBaseURL; + $siteName = $siteRoot = NULL; + if ($config->userFramework == 'Joomla') { + $url = preg_replace('|/administrator|', + '', + $config->userFrameworkBaseURL + ); + $siteRoot = preg_replace('|/media/civicrm/.*$|', + '', + $config->imageUploadDir + ); + } + $dir = preg_replace('|civicrm/templates_c/.*$|', + '', + $config->templateCompileDir + ); + + if ($config->userFramework != 'Joomla') { + $matches = array(); + if (preg_match('|/sites/([\w\.\-\_]+)/|', + $config->templateCompileDir, + $matches + )) { + $siteName = $matches[1]; + if ($siteName) { + $siteName = "/sites/$siteName/"; + $siteNamePos = strpos($dir, $siteName); + if ($siteNamePos !== FALSE) { + $siteRoot = substr($dir, 0, $siteNamePos); + } + } + } + } + + return array($url, $dir, $siteName, $siteRoot); + } + + static function doSiteMove($defaultValues = array() ) { + $moveStatus = ts('Beginning site move process...') . '
    '; + // get the current and guessed values + list($oldURL, $oldDir, $oldSiteName, $oldSiteRoot) = self::getConfigSettings(); + list($newURL, $newDir, $newSiteName, $newSiteRoot) = self::getBestGuessSettings(); + + + // retrieve these values from the argument list + $variables = array('URL', 'Dir', 'SiteName', 'SiteRoot', 'Val_1', 'Val_2', 'Val_3'); + $states = array('old', 'new'); + foreach ($variables as $varSuffix) { + foreach ($states as $state) { + $var = "{$state}{$varSuffix}"; + if (!isset($$var)) { + if (isset($defaultValues[$var])) { + $$var = $defaultValues[$var]; + } + else { + $$var = NULL; + } + } + $$var = CRM_Utils_Request::retrieve($var, + 'String', + CRM_Core_DAO::$_nullArray, + FALSE, + $$var, + 'REQUEST' + ); + } + } + + $from = $to = array(); + foreach ($variables as $varSuffix) { + $oldVar = "old{$varSuffix}"; + $newVar = "new{$varSuffix}"; + //skip it if either is empty or both are exactly the same + if ($$oldVar && + $$newVar && + $$oldVar != $$newVar + ) { + $from[] = $$oldVar; + $to[] = $$newVar; + } + } + + $sql = " +SELECT config_backend +FROM civicrm_domain +WHERE id = %1 +"; + $params = array(1 => array(CRM_Core_Config::domainID(), 'Integer')); + $configBackend = CRM_Core_DAO::singleValueQuery($sql, $params); + if (!$configBackend) { + CRM_Core_Error::fatal(ts('Returning early due to unexpected error - civicrm_domain.config_backend column value is NULL. Try visiting CiviCRM Home page.')); + } + $configBackend = unserialize($configBackend); + + $configBackend = str_replace($from, + $to, + $configBackend + ); + + $configBackend = serialize($configBackend); + $sql = " +UPDATE civicrm_domain +SET config_backend = %2 +WHERE id = %1 +"; + $params[2] = array($configBackend, 'String'); + CRM_Core_DAO::executeQuery($sql, $params); + + // Apply the changes to civicrm_option_values + $optionGroups = array('url_preferences', 'directory_preferences'); + foreach ($optionGroups as $option) { + foreach ($variables as $varSuffix) { + $oldVar = "old{$varSuffix}"; + $newVar = "new{$varSuffix}"; + + $from = $$oldVar; + $to = $$newVar; + + if ($from && $to && $from != $to) { + $sql = ' +UPDATE civicrm_option_value +SET value = REPLACE(value, %1, %2) +WHERE option_group_id = ( + SELECT id + FROM civicrm_option_group + WHERE name = %3 ) +'; + $params = array(1 => array($from, 'String'), + 2 => array($to, 'String'), + 3 => array($option, 'String'), + ); + CRM_Core_DAO::executeQuery($sql, $params); + } + } + } + + $moveStatus .= ts('Directory and Resource URLs have been updated in the moved database to reflect current site location.') . '
    '; + + $config = CRM_Core_Config::singleton(); + + // clear the template_c and upload directory also + $config->cleanup(3, TRUE); + $moveStatus .= ts('Template cache and upload directory have been cleared.') . '
    '; + + // clear all caches + CRM_Core_Config::clearDBCache(); + $moveStatus .= ts('Database cache tables cleared.') . '
    '; + + $resetSessionTable = CRM_Utils_Request::retrieve('resetSessionTable', + 'Boolean', + CRM_Core_DAO::$_nullArray, + FALSE, + FALSE, + 'REQUEST' + ); + if ($config->userSystem->is_drupal && + $resetSessionTable + ) { + db_query("DELETE FROM {sessions} WHERE 1"); + $moveStatus .= ts('Drupal session table cleared.') . '
    '; + } + else { + $session = CRM_Core_Session::singleton(); + $session->reset(2); + $moveStatus .= ts('Session has been reset.') . '
    '; + } + + return $moveStatus; + } + + /** + * takes a componentName and enables it in the config + * Primarily used during unit testing + * + * @param string $componentName name of the component to be enabled, needs to be valid + * + * @return boolean - true if valid component name and enabling succeeds, else false + * @static + */ + static function enableComponent($componentName) { + $config = CRM_Core_Config::singleton(); + if (in_array($componentName, $config->enableComponents)) { + // component is already enabled + return TRUE; + } + $components = CRM_Core_Component::getComponents(); + + // return if component does not exist + if (!array_key_exists($componentName, $components)) { + return FALSE; + } + + // get config_backend value + $sql = " +SELECT config_backend +FROM civicrm_domain +WHERE id = %1 +"; + $params = array(1 => array(CRM_Core_Config::domainID(), 'Integer')); + $configBackend = CRM_Core_DAO::singleValueQuery($sql, $params); + + if (!$configBackend) { + static $alreadyVisited = FALSE; + if ($alreadyVisited) { + CRM_Core_Error::fatal(ts('Returning early due to unexpected error - civicrm_domain.config_backend column value is NULL. Try visiting CiviCRM Home page.')); + } + + $alreadyVisited = TRUE; + + // try to recreate the config backend + $config = CRM_Core_Config::singleton(TRUE, TRUE); + return self::enableComponent($componentName); + } + $configBackend = unserialize($configBackend); + + $configBackend['enableComponents'][] = $componentName; + $configBackend['enableComponentIDs'][] = $components[$componentName]->componentID; + + // fix the config object + $config->enableComponents = $configBackend['enableComponents']; + $config->enableComponentIDs = $configBackend['enableComponentIDs']; + + // also force reset of component array + CRM_Core_Component::getEnabledComponents(TRUE); + + // check if component is already there, is so return + $configBackend = serialize($configBackend); + $sql = " +UPDATE civicrm_domain +SET config_backend = %2 +WHERE id = %1 +"; + $params[2] = array($configBackend, 'String'); + CRM_Core_DAO::executeQuery($sql, $params); + + return TRUE; + } + + static function skipVars() { + return array( + 'dsn', 'templateCompileDir', + 'userFrameworkDSN', + 'userFramework', + 'userFrameworkBaseURL', 'userFrameworkClass', 'userHookClass', + 'userPermissionClass', 'userFrameworkURLVar', 'userFrameworkVersion', + 'newBaseURL', 'newBaseDir', 'newSiteName', 'configAndLogDir', + 'qfKey', 'gettextResourceDir', 'cleanURL', + 'locale_custom_strings', 'localeCustomStrings', + 'autocompleteContactSearch', + 'autocompleteContactReference', + 'checksumTimeout', + ); + } +} + diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php new file mode 100644 index 0000000000..09dfa9a9fe --- /dev/null +++ b/CRM/Core/BAO/CustomField.php @@ -0,0 +1,2394 @@ + Description + * @access public + * @static + */ + static function &dataType() { + if (!(self::$_dataType)) { + self::$_dataType = array( + 'String' => ts('Alphanumeric'), + 'Int' => ts('Integer'), + 'Float' => ts('Number'), + 'Money' => ts('Money'), + 'Memo' => ts('Note'), + 'Date' => ts('Date'), + 'Boolean' => ts('Yes or No'), + 'StateProvince' => ts('State/Province'), + 'Country' => ts('Country'), + 'File' => ts('File'), + 'Link' => ts('Link'), + 'ContactReference' => ts('Contact Reference'), + ); + } + return self::$_dataType; + } + + static function dataToHtml() { + if (!self::$_dataToHtml) { + self::$_dataToHtml = array( + array( + 'Text' => 'Text', 'Select' => 'Select', + 'Radio' => 'Radio', 'CheckBox' => 'CheckBox', + 'Multi-Select' => 'Multi-Select', + 'AdvMulti-Select' => 'AdvMulti-Select', + 'Autocomplete-Select' => 'Autocomplete-Select', + ), + array('Text' => 'Text', 'Select' => 'Select', 'Radio' => 'Radio'), + array('Text' => 'Text', 'Select' => 'Select', 'Radio' => 'Radio'), + array('Text' => 'Text', 'Select' => 'Select', 'Radio' => 'Radio'), + array('TextArea' => 'TextArea', 'RichTextEditor' => 'RichTextEditor'), + array('Date' => 'Select Date'), + array('Radio' => 'Radio'), + array('StateProvince' => 'Select State/Province', 'Multi-Select' => 'Multi-Select State/Province'), + array('Country' => 'Select Country', 'Multi-Select' => 'Multi-Select Country'), + array('File' => 'File'), + array('Link' => 'Link'), + array('ContactReference' => 'Autocomplete-Select'), + ); + } + return self::$_dataToHtml; + } + + /** + * takes an associative array and creates a custom field object + * + * This function is invoked from within the web form layer and also from the api layer + * + * @param array $params (reference) an assoc array of name/value pairs + * + * @return object CRM_Core_DAO_CustomField object + * @access public + * @static + */ + static function create(&$params) { + if (!isset($params['id']) && !isset($params['column_name'])) { + // if add mode & column_name not present, calculate it. + $params['column_name'] = strtolower(CRM_Utils_String::munge($params['label'], '_', 32)); + + $params['name'] = CRM_Utils_String::munge($params['label'], '_', 64); + } + elseif (isset($params['id'])) { + $params['column_name'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', + $params['id'], + 'column_name' + ); + } + + $indexExist = FALSE; + //as during create if field is_searchable we had created index. + if (CRM_Utils_Array::value('id', $params)) { + $indexExist = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $params['id'], 'is_searchable'); + } + + if (($params['html_type'] == 'CheckBox' || + $params['html_type'] == 'AdvMulti-Select' || + $params['html_type'] == 'Multi-Select' + ) && + isset($params['default_checkbox_option']) + ) { + $tempArray = array_keys($params['default_checkbox_option']); + $defaultArray = array(); + foreach ($tempArray as $k => $v) { + if ($params['option_value'][$v]) { + $defaultArray[] = $params['option_value'][$v]; + } + } + + if (!empty($defaultArray)) { + // also add the seperator before and after the value per new conventio (CRM-1604) + $params['default_value'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $defaultArray) . CRM_Core_DAO::VALUE_SEPARATOR; + } + } + else { + if (CRM_Utils_Array::value('default_option', $params) + && isset($params['option_value'][$params['default_option']]) + ) { + $params['default_value'] = $params['option_value'][$params['default_option']]; + } + } + $transaction = new CRM_Core_Transaction(); + // create any option group & values if required + if ($params['html_type'] != 'Text' && + in_array($params['data_type'], array( + 'String', 'Int', 'Float', 'Money')) && + !empty($params['option_value']) && is_array($params['option_value']) + ) { + + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', + $params['custom_group_id'], + 'table_name' + ); + + + if ($params['option_type'] == 1) { + // first create an option group for this custom group + $optionGroup = new CRM_Core_DAO_OptionGroup(); + $optionGroup->name = "{$params['column_name']}_" . date('YmdHis'); + $optionGroup->title = $params['label']; + $optionGroup->is_active = 1; + $optionGroup->save(); + $params['option_group_id'] = $optionGroup->id; + + + + foreach ($params['option_value'] as $k => $v) { + if (strlen(trim($v))) { + $optionValue = new CRM_Core_DAO_OptionValue(); + $optionValue->option_group_id = $optionGroup->id; + $optionValue->label = $params['option_label'][$k]; + $optionValue->name = CRM_Utils_String::titleToVar($params['option_label'][$k]); + switch ($params['data_type']) { + case 'Money': + $optionValue->value = CRM_Utils_Rule::cleanMoney($v); + break; + + case 'Int': + $optionValue->value = intval($v); + break; + + case 'Float': + $optionValue->value = floatval($v); + break; + + default: + $optionValue->value = trim($v); + } + + $optionValue->weight = $params['option_weight'][$k]; + $optionValue->is_active = CRM_Utils_Array::value($k, $params['option_status'], FALSE); + $optionValue->save(); + } + } + } + } + + // check for orphan option groups + if (CRM_Utils_Array::value('option_group_id', $params)) { + if (CRM_Utils_Array::value('id', $params)) { + self::fixOptionGroups($params['id'], $params['option_group_id']); + } + + // if we dont have a default value + // retrive it from one of the other custom fields which use this option group + if (!CRM_Utils_Array::value('default_value', $params)) { + //don't insert only value separator as default value, CRM-4579 + $defaultValue = self::getOptionGroupDefault($params['option_group_id'], + $params['html_type'] + ); + + if (!CRM_Utils_System::isNull(explode(CRM_Core_DAO::VALUE_SEPARATOR, + $defaultValue + ))) { + $params['default_value'] = $defaultValue; + } + } + } + + // since we need to save option group id :) + if (!isset($params['attributes']) && strtolower($params['html_type']) == 'textarea') { + $params['attributes'] = 'rows=4, cols=60'; + } + + $customField = new CRM_Core_DAO_CustomField(); + $customField->copyValues($params); + $customField->is_required = CRM_Utils_Array::value('is_required', $params, FALSE); + $customField->is_searchable = CRM_Utils_Array::value('is_searchable', $params, FALSE); + $customField->is_search_range = CRM_Utils_Array::value('is_search_range', $params, FALSE); + $customField->is_active = CRM_Utils_Array::value('is_active', $params, FALSE); + $customField->is_view = CRM_Utils_Array::value('is_view', $params, FALSE); + $customField->save(); + + // make sure all values are present in the object for further processing + $customField->find(TRUE); + + //create/drop the index when we toggle the is_searchable flag + if (CRM_Utils_Array::value('id', $params)) { + self::createField($customField, 'modify', $indexExist); + } + else { + $customField->column_name .= "_{$customField->id}"; + $customField->save(); + // make sure all values are present in the object + $customField->find(TRUE); + + self::createField($customField, 'add'); + } + + // complete transaction + $transaction->commit(); + + CRM_Utils_System::flushCache(); + + return $customField; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * contact_id. We'll tweak this function to be more full featured over a period + * of time. This is the inverse function of create. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_DAO_CustomField object + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + return CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomField', $params, $defaults); + } + + /** + * update the is_active flag in the db + * + * @param int $id Id of the database record + * @param boolean $is_active Value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * + * @access public + * @static + */ + static function setIsActive($id, $is_active) { + + CRM_Utils_System::flushCache(); + + //enable-disable CustomField + CRM_Core_BAO_UFField::setUFField($id, $is_active); + return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_CustomField', $id, 'is_active', $is_active); + } + + /** + * Get the field title. + * + * @param int $id id of field. + * + * @return string name + * + * @access public + * @static + * + */ + public static function getTitle($id) { + return CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $id, 'label'); + } + + /** + * Store and return an array of all active custom fields. + * + * @param string $customDataType type of Custom Data + * @param boolean $showAll If true returns all fields (includes disabled fields) + * @param boolean $inline If true returns all inline fields (includes disabled fields) + * @param int $customDataSubType Custom Data sub type value + * @param int $customDataSubName Custom Data sub name value + * @param boolean $onlyParent return only top level custom data, for eg, only Participant and ignore subname and subtype + * @param boolean $onlySubType return only custom data for subtype + * @param boolean $checkPermission if false, do not include permissioning clause + * + * @return array $fields - an array of active custom fields. + * + * @access public + * @static + */ + public static function &getFields($customDataType = 'Individual', + $showAll = FALSE, + $inline = FALSE, + $customDataSubType = NULL, + $customDataSubName = NULL, + $onlyParent = FALSE, + $onlySubType = FALSE, + $checkPermission = TRUE + ) { + if ($customDataType && + !is_array($customDataType) + ) { + + if (in_array($customDataType, + CRM_Contact_BAO_ContactType::subTypes() + )) { + // This is the case when getFieldsForImport() requires fields + // limited strictly to a subtype. + $customDataSubType = $customDataType; + $customDataType = CRM_Contact_BAO_ContactType::getBasicType($customDataType); + $onlySubType = TRUE; + } + + if (in_array($customDataType, + array_keys(CRM_Core_SelectValues::customGroupExtends()) + )) { + // this makes the method flexible to support retrieving fields + // for multiple extends value. + $customDataType = array($customDataType); + } + } + + if ($customDataSubType && !is_array($customDataSubType)) { + $customDataSubType = explode(CRM_Core_DAO::VALUE_SEPARATOR, + trim($customDataSubType, CRM_Core_DAO::VALUE_SEPARATOR) + ); + } + + if (is_array($customDataType)) { + $cacheKey = implode('_', $customDataType); + } + else { + $cacheKey = $customDataType; + } + + $cacheKey .= !empty($customDataSubType) ? ('_' . implode('_', $customDataSubType)) : '_0'; + $cacheKey .= $customDataSubName ? "{$customDataSubName}_" : '_0'; + $cacheKey .= $showAll ? '_1' : '_0'; + $cacheKey .= $inline ? '_1_' : '_0_'; + $cacheKey .= $onlyParent ? '_1_' : '_0_'; + $cacheKey .= $onlySubType ? '_1_' : '_0_'; + $cacheKey .= $checkPermission ? '_1_' : '_0_'; + + $cgTable = CRM_Core_DAO_CustomGroup::getTableName(); + + // also get the permission stuff here + if ($checkPermission) { + $permissionClause = CRM_Core_Permission::customGroupClause(CRM_Core_Permission::VIEW, + "{$cgTable}." + ); + } + else { + $permissionClause = '(1)'; + } + + // lets md5 permission clause and take first 8 characters + $cacheKey .= substr(md5($permissionClause), 0, 8); + + if (strlen($cacheKey) > 40) { + $cacheKey = md5($cacheKey); + } + + if (!self::$_importFields || + CRM_Utils_Array::value($cacheKey, self::$_importFields) === NULL + ) { + if (!self::$_importFields) { + self::$_importFields = array(); + } + + // check if we can retrieve from database cache + $fields = CRM_Core_BAO_Cache::getItem('contact fields', "custom importableFields $cacheKey"); + + if ($fields === NULL) { + $cfTable = self::getTableName(); + + $extends = ''; + if (is_array($customDataType)) { + $value = NULL; + foreach ($customDataType as $dataType) { + if (in_array($dataType, + array_keys(CRM_Core_SelectValues::customGroupExtends()) + )) { + if (in_array($dataType, array( + 'Individual', 'Household', 'Organization'))) { + $val = "'" . CRM_Utils_Type::escape($dataType, 'String') . "', 'Contact' "; + } + else { + $val = "'" . CRM_Utils_Type::escape($dataType, 'String') . "'"; + } + $value = $value ? $value . ", {$val}" : $val; + } + } + if ($value) { + $extends = "AND $cgTable.extends IN ( $value ) "; + } + } + + if ($onlyParent) { + $extends .= " AND $cgTable.extends_entity_column_value IS NULL AND $cgTable.extends_entity_column_id IS NULL "; + } + + $query = "SELECT $cfTable.id, $cfTable.label, + $cgTable.title, + $cfTable.data_type, $cfTable.html_type, + $cfTable.options_per_line, $cfTable.text_length, + $cfTable.custom_group_id, + $cgTable.extends, $cfTable.is_search_range, + $cgTable.extends_entity_column_value, + $cgTable.extends_entity_column_id, + $cfTable.is_view, + $cfTable.option_group_id, + $cfTable.date_format, + $cfTable.time_format, + $cgTable.is_multiple + FROM $cfTable + INNER JOIN $cgTable + ON $cfTable.custom_group_id = $cgTable.id + WHERE ( 1 ) "; + + if (!$showAll) { + $query .= " AND $cfTable.is_active = 1 AND $cgTable.is_active = 1 "; + } + + if ($inline) { + $query .= " AND $cgTable.style = 'Inline' "; + } + + //get the custom fields for specific type in + //combination with fields those support any type. + if (!empty($customDataSubType)) { + $subtypeClause = array(); + foreach ($customDataSubType as $subtype) { + $subtype = CRM_Core_DAO::VALUE_SEPARATOR . $subtype . CRM_Core_DAO::VALUE_SEPARATOR; + $subtypeClause[] = "$cgTable.extends_entity_column_value LIKE '%{$subtype}%'"; + } + if (!$onlySubType) { + $subtypeClause[] = "$cgTable.extends_entity_column_value IS NULL"; + } + $query .= " AND ( " . implode(' OR ', $subtypeClause) . " )"; + } + + if ($customDataSubName) { + $query .= " AND ( $cgTable.extends_entity_column_id = $customDataSubName ) "; + } + + // also get the permission stuff here + if ($checkPermission) { + $permissionClause = CRM_Core_Permission::customGroupClause(CRM_Core_Permission::VIEW, + "{$cgTable}.", TRUE + ); + } + else { + $permissionClause = '(1)'; + } + + $query .= " $extends AND $permissionClause + ORDER BY $cgTable.weight, $cgTable.title, + $cfTable.weight, $cfTable.label"; + + $dao = CRM_Core_DAO::executeQuery($query); + + $fields = array(); + while (($dao->fetch()) != NULL) { + $fields[$dao->id]['label'] = $dao->label; + $fields[$dao->id]['groupTitle'] = $dao->title; + $fields[$dao->id]['data_type'] = $dao->data_type; + $fields[$dao->id]['html_type'] = $dao->html_type; + $fields[$dao->id]['text_length'] = $dao->text_length; + $fields[$dao->id]['options_per_line'] = $dao->options_per_line; + $fields[$dao->id]['custom_group_id'] = $dao->custom_group_id; + $fields[$dao->id]['extends'] = $dao->extends; + $fields[$dao->id]['is_search_range'] = $dao->is_search_range; + $fields[$dao->id]['extends_entity_column_value'] = $dao->extends_entity_column_value; + $fields[$dao->id]['extends_entity_column_id'] = $dao->extends_entity_column_id; + $fields[$dao->id]['is_view'] = $dao->is_view; + $fields[$dao->id]['is_multiple'] = $dao->is_multiple; + $fields[$dao->id]['option_group_id'] = $dao->option_group_id; + $fields[$dao->id]['date_format'] = $dao->date_format; + $fields[$dao->id]['time_format'] = $dao->time_format; + } + + CRM_Core_BAO_Cache::setItem($fields, + 'contact fields', + "custom importableFields $cacheKey" + ); + } + self::$_importFields[$cacheKey] = $fields; + } + + return self::$_importFields[$cacheKey]; + } + + /** + * Return the field ids and names (with groups) for import purpose. + * + * @param int $contactType Contact type + * @param boolean $showAll If true returns all fields (includes disabled fields) + * @param boolean $onlyParent return fields ONLY related to basic types + * @param boolean $search when called from search and multiple records need to be returned + * @param boolean $checkPermission if false, do not include permissioning clause + * + * @return array $fields - + * + * @access public + * @static + */ + public static function &getFieldsForImport($contactType = 'Individual', + $showAll = FALSE, + $onlyParent = FALSE, + $search = FALSE, + $checkPermission = TRUE, + $withMultiple = FALSE + ) { + // Note: there are situations when we want getFieldsForImport() return fields related + // ONLY to basic contact types, but NOT subtypes. And thats where $onlyParent is helpful + $fields = &self::getFields($contactType, + $showAll, + FALSE, + NULL, + NULL, + $onlyParent, + FALSE, + $checkPermission + ); + + $importableFields = array(); + foreach ($fields as $id => $values) { + // for now we should not allow multiple fields in profile / export etc, hence unsetting + if (!$search && + (CRM_Utils_Array::value('is_multiple', $values) && !$withMultiple) + ) { + continue; + } + + /* generate the key for the fields array */ + + $key = "custom_$id"; + + $regexp = preg_replace('/[.,;:!?]/', '', CRM_Utils_Array::value(0, $values)); + $importableFields[$key] = array( + 'name' => $key, + 'title' => CRM_Utils_Array::value('label', $values), + 'headerPattern' => '/' . preg_quote($regexp, '/') . '/', + 'import' => 1, + 'custom_field_id' => $id, + 'options_per_line' => CRM_Utils_Array::value('options_per_line', $values), + 'data_type' => CRM_Utils_Array::value('data_type', $values), + 'html_type' => CRM_Utils_Array::value('html_type', $values), + 'is_search_range' => CRM_Utils_Array::value('is_search_range', $values), + ); + + // CRM-6681, pass date and time format when html_type = Select Date + if (CRM_Utils_Array::value('html_type', $values) == 'Select Date') { + $importableFields[$key]['date_format'] = CRM_Utils_Array::value('date_format', $values); + $importableFields[$key]['time_format'] = CRM_Utils_Array::value('time_format', $values); + } + } + + return $importableFields; + } + + /** + * Get the field id from an import key + * + * @param string $key The key to parse + * + * @return int|null The id (if exists) + * @access public + * @static + */ + public static function getKeyID($key, $all = FALSE) { + $match = array(); + if (preg_match('/^custom_(\d+)_?(-?\d+)?$/', $key, $match)) { + if (!$all) { + return $match[1]; + } + else { + return array( + $match[1], + CRM_Utils_Array::value(2, $match), + ); + } + } + return $all ? array( + NULL, NULL) : NULL; + } + + /** + * Use the cache to get all values of a specific custom field + * + * @param int $fieldID the custom field ID + * + * @return object $field the field object + * @static + * public + */ + static function getFieldObject($fieldID) { + $field = new CRM_Core_DAO_CustomField(); + + // check if we can get the field values from the system cache + $cacheKey = "CRM_Core_DAO_CustomField_{$fieldID}"; + $cache = CRM_Utils_Cache::singleton(); + $fieldValues = $cache->get($cacheKey); + if (empty($fieldValues)) { + $field->id = $fieldID; + if (!$field->find(TRUE)) { + CRM_Core_Error::fatal(); + } + + $fieldValues = array(); + CRM_Core_DAO::storeValues($field, $fieldValues); + + $cache->set($cacheKey, $fieldValues); + } + else { + $field->copyValues($fieldValues); + } + + return $field; + } + + /** + * This function for building custom fields + * + * @param object $qf form object (reference) + * @param string $elementName name of the custom field + * @param boolean $inactiveNeeded + * @param boolean $userRequired true if required else false + * @param boolean $search true if used for search else false + * @param string $label label for custom field + * + * @access public + * @static + */ + public static function addQuickFormElement(&$qf, + $elementName, + $fieldId, + $inactiveNeeded = FALSE, + $useRequired = TRUE, + $search = FALSE, + $label = NULL + ) { + // we use $_POST directly, since we dont want to use session memory, CRM-4677 + if (isset($_POST['_qf_Relationship_refresh']) && + ($_POST['_qf_Relationship_refresh'] == 'Search' || + $_POST['_qf_Relationship_refresh'] == 'Search Again' + ) + ) { + $useRequired = FALSE; + } + + $field = self::getFieldObject($fieldId); + + // Fixed for Issue CRM-2183 + if ($field->html_type == 'TextArea' && $search) { + $field->html_type = 'Text'; + } + + if (!isset($label)) { + $label = $field->label; + } + + /** + * at some point in time we might want to split the below into small functions + **/ + + switch ($field->html_type) { + case 'Text': + if ($field->is_search_range && $search) { + $qf->add('text', $elementName . '_from', $label . ' ' . ts('From'), $field->attributes); + $qf->add('text', $elementName . '_to', ts('To'), $field->attributes); + } + else { + $element = &$qf->add(strtolower($field->html_type), $elementName, $label, + $field->attributes, + $useRequired && !$search + ); + } + break; + + case 'TextArea': + $attributes = ''; + if ($field->note_rows) { + $attributes .= 'rows=' . $field->note_rows; + } + else { + $attributes .= 'rows=4'; + } + + if ($field->note_columns) { + $attributes .= ' cols=' . $field->note_columns; + } + else { + $attributes .= ' cols=60'; + } + $element = &$qf->add(strtolower($field->html_type), + $elementName, + $label, + $attributes, + $useRequired && !$search + ); + break; + + case 'Select Date': + if ($field->is_search_range && $search) { + $qf->addDate($elementName . '_from', $label . ' - ' . ts('From'), FALSE, + array( + 'format' => $field->date_format, + 'timeFormat' => $field->time_format, + 'startOffset' => $field->start_date_years, + 'endOffset' => $field->end_date_years, + ) + ); + + $qf->addDate($elementName . '_to', ts('To'), FALSE, + array( + 'format' => $field->date_format, + 'timeFormat' => $field->time_format, + 'startOffset' => $field->start_date_years, + 'endOffset' => $field->end_date_years, + ) + ); + } + else { + $required = $useRequired && !$search; + + $qf->addDate($elementName, $label, $required, array( + 'format' => $field->date_format, + 'timeFormat' => $field->time_format, + 'startOffset' => $field->start_date_years, + 'endOffset' => $field->end_date_years, + )); + } + break; + + case 'Radio': + $choice = array(); + if ($field->data_type != 'Boolean') { + $customOption = &CRM_Core_BAO_CustomOption::valuesByID($field->id, + $field->option_group_id + ); + foreach ($customOption as $v => $l) { + $choice[] = $qf->createElement('radio', NULL, '', $l, (string)$v, $field->attributes); + } + $qf->addGroup($choice, $elementName, $label); + } + else { + $choice[] = $qf->createElement('radio', NULL, '', ts('Yes'), '1', $field->attributes); + $choice[] = $qf->createElement('radio', NULL, '', ts('No'), '0', $field->attributes); + $qf->addGroup($choice, $elementName, $label); + } + if ($useRequired && !$search) { + $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); + } + break; + + case 'Select': + $selectOption = &CRM_Core_BAO_CustomOption::valuesByID($field->id, + $field->option_group_id + ); + $qf->add('select', $elementName, $label, + array( + '' => ts('- select -')) + $selectOption, + $useRequired && !$search + ); + break; + + //added for select multiple + + case 'AdvMulti-Select': + $selectOption = &CRM_Core_BAO_CustomOption::valuesByID($field->id, + $field->option_group_id + ); + if ($search && + count($selectOption) > 1 + ) { + $selectOption['CiviCRM_OP_OR'] = ts('Select to match ANY; unselect to match ALL'); + } + + $include =& $qf->addElement( + 'advmultiselect', + $elementName, + $label, $selectOption, + array( + 'size' => 5, + 'style' => '', + 'class' => 'advmultiselect', + ) + ); + + $include->setButtonAttributes('add', array('value' => ts('Add >>'))); + $include->setButtonAttributes('remove', array('value' => ts('<< Remove'))); + + if ($useRequired && !$search) { + $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); + } + break; + + case 'Multi-Select': + $selectOption = &CRM_Core_BAO_CustomOption::valuesByID($field->id, + $field->option_group_id + ); + if ($search && + count($selectOption) > 1 + ) { + $selectOption['CiviCRM_OP_OR'] = ts('Select to match ANY; unselect to match ALL'); + } + $qf->addElement('select', $elementName, $label, $selectOption, array('size' => '5', 'multiple')); + + if ($useRequired && !$search) { + $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); + } + break; + + case 'CheckBox': + $customOption = CRM_Core_BAO_CustomOption::valuesByID($field->id, + $field->option_group_id + ); + $check = array(); + foreach ($customOption as $v => $l) { + $check[] = &$qf->addElement('advcheckbox', $v, NULL, $l); + } + if ($search && + count($check) > 1 + ) { + $check[] = &$qf->addElement('advcheckbox', 'CiviCRM_OP_OR', NULL, ts('Check to match ANY; uncheck to match ALL')); + } + $qf->addGroup($check, $elementName, $label); + if ($useRequired && !$search) { + $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); + } + break; + + case 'File': + // we should not build upload file in search mode + if ($search) { + return; + } + $qf->add( + strtolower($field->html_type), + $elementName, + $label, + $field->attributes, + $useRequired && !$search + ); + $qf->addUploadElement($elementName); + break; + + case 'Select State/Province': + //Add State + $stateOption = array('' => ts('- select -')) + CRM_Core_PseudoConstant::stateProvince(); + $qf->add('select', $elementName, $label, $stateOption, + $useRequired && !$search + ); + break; + + case 'Multi-Select State/Province': + //Add Multi-select State/Province + $stateOption = CRM_Core_PseudoConstant::stateProvince(); + + $qf->addElement('select', $elementName, $label, $stateOption, array('size' => '5', 'multiple')); + if ($useRequired && !$search) { + $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); + } + break; + + case 'Select Country': + //Add Country + $countryOption = array('' => ts('- select -')) + CRM_Core_PseudoConstant::country(); + $qf->add('select', $elementName, $label, $countryOption, + $useRequired && !$search + ); + break; + + case 'Multi-Select Country': + //Add Country + $countryOption = CRM_Core_PseudoConstant::country(); + $qf->addElement('select', $elementName, $label, $countryOption, array('size' => '5', 'multiple')); + if ($useRequired && !$search) { + $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); + } + break; + + case 'RichTextEditor': + $qf->addWysiwyg($elementName, $label, array('rows' => $field->note_rows, 'cols' => $field->note_columns), $search); + break; + + case 'Autocomplete-Select': + $qf->add('text', $elementName, $label, $field->attributes, + $useRequired && !$search + ); + + $hiddenEleName = $elementName . '_id'; + if (substr($elementName, -1) == ']') { + $hiddenEleName = substr($elementName, 0, -1) . '_id]'; + } + $qf->addElement('hidden', $hiddenEleName, '', array('id' => str_replace(array(']', '['), array('', '_'), $hiddenEleName))); + + static $customUrls = array(); + if ($field->data_type == 'ContactReference') { + //$urlParams = "className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1&reset=1&context=customfield&id={$field->id}"; + $urlParams = "context=customfield&id={$field->id}"; + + $customUrls[$elementName] = CRM_Utils_System::url('civicrm/ajax/contactref', + $urlParams, + FALSE, NULL, FALSE + ); + + $actualElementValue = $qf->getSubmitValue($hiddenEleName); + $qf->addRule($elementName, ts('Select a valid contact for %1.', array(1 => $label)), 'validContact', $actualElementValue); + } + else { + $customUrls[$elementName] = CRM_Utils_System::url('civicrm/ajax/auto', + "reset=1&ogid={$field->option_group_id}&cfid={$field->id}", + FALSE, NULL, FALSE + ); + $qf->addRule($elementName, ts('Select a valid value for %1.', array(1 => $label)), + 'autocomplete', array( + 'fieldID' => $field->id, + 'optionGroupID' => $field->option_group_id, + ) + ); + } + + $qf->assign('customUrls', $customUrls); + break; + } + + switch ($field->data_type) { + case 'Int': + // integers will have numeric rule applied to them. + if ($field->is_search_range && $search) { + $qf->addRule($elementName . '_from', ts('%1 From must be an integer (whole number).', array(1 => $label)), 'integer'); + $qf->addRule($elementName . '_to', ts('%1 To must be an integer (whole number).', array(1 => $label)), 'integer'); + } + else { + $qf->addRule($elementName, ts('%1 must be an integer (whole number).', array(1 => $label)), 'integer'); + } + break; + + case 'Float': + if ($field->is_search_range && $search) { + $qf->addRule($elementName . '_from', ts('%1 From must be a number (with or without decimal point).', array(1 => $label)), 'numeric'); + $qf->addRule($elementName . '_to', ts('%1 To must be a number (with or without decimal point).', array(1 => $label)), 'numeric'); + } + else { + $qf->addRule($elementName, ts('%1 must be a number (with or without decimal point).', array(1 => $label)), 'numeric'); + } + break; + + case 'Money': + if ($field->is_search_range && $search) { + $qf->addRule($elementName . '_from', ts('%1 From must in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money'); + $qf->addRule($elementName . '_to', ts('%1 To must in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money'); + } + else { + $qf->addRule($elementName, ts('%1 must be in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money'); + } + break; + + case 'Link': + $qf->add( + 'text', + $elementName, + $label, + array( + 'onfocus' => "if (!this.value) { this.value='http://';} else return false", + 'onblur' => "if ( this.value == 'http://') { this.value='';} else return false", + ), + $useRequired && !$search + ); + $qf->addRule($elementName, ts('Enter a valid Website.'), 'wikiURL'); + break; + } + if ($field->is_view && !$search) { + $qf->freeze($elementName); + } + } + + /** + * Delete the Custom Field. + * + * @param object $field - the field object + * + * @return boolean + * + * @access public + * @static + * + */ + public static function deleteField($field) { + CRM_Utils_System::flushCache(); + + // first delete the custom option group and values associated with this field + if ($field->option_group_id) { + //check if option group is related to any other field, if + //not delete the option group and related option values + self::checkOptionGroup($field->option_group_id); + } + + // next drop the column from the custom value table + self::createField($field, 'delete'); + + $field->delete(); + CRM_Core_BAO_UFField::delUFField($field->id); + CRM_Utils_Weight::correctDuplicateWeights('CRM_Core_DAO_CustomField'); + + return; + } + + /** + * Given a custom field value, its id and the set of options + * find the display value for this field + * + * @param mixed $value the custom field value + * @param int $id the custom field id + * @param int $options the assoc array of option name/value pairs + * + * @return string the display value + * + * @static + * @access public + */ + static function getDisplayValue($value, $id, &$options, $contactID = NULL, $fieldID = NULL) { + $option = &$options[$id]; + $attributes = &$option['attributes']; + $html_type = $attributes['html_type']; + $data_type = $attributes['data_type']; + $format = CRM_Utils_Array::value('format', $attributes); + + return self::getDisplayValueCommon($value, + $option, + $html_type, + $data_type, + $format, + $contactID, + $fieldID + ); + } + + static function getDisplayValueCommon($value, + &$option, + $html_type, + $data_type, + $format = NULL, + $contactID = NULL, + $fieldID = NULL + ) { + $display = $value; + + if ($fieldID && + (($html_type == 'Radio' && $data_type != 'Boolean') || + ($html_type == 'Autocomplete-Select' && $data_type != 'ContactReference') || + $html_type == 'Select' || + $html_type == 'CheckBox' || + $html_type == 'AdvMulti-Select' || + $html_type == 'Multi-Select' + ) + ) { + CRM_Utils_Hook::customFieldOptions($fieldID, $option); + } + + switch ($html_type) { + case 'Radio': + if ($data_type == 'Boolean') { + $display = $value ? ts('Yes') : ts('No'); + } + else { + $display = CRM_Utils_Array::value($value, $option); + } + break; + + case 'Autocomplete-Select': + if ($data_type == 'ContactReference' && + $value + ) { + $display = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'display_name'); + } + else { + $display = CRM_Utils_Array::value($value, $option); + } + break; + + case 'Select': + $display = CRM_Utils_Array::value($value, $option); + break; + + case 'CheckBox': + case 'AdvMulti-Select': + case 'Multi-Select': + if (is_array($value)) { + $checkedData = $value; + } + else { + $checkedData = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($value, 1, -1) + ); + if ($html_type == 'CheckBox') { + $newData = array(); + foreach ($checkedData as $v) { + $newData[$v] = 1; + } + $checkedData = $newData; + } + } + + $v = array(); + $p = array(); + foreach ($checkedData as $key => $val) { + if ($key === 'CiviCRM_OP_OR') { + continue; + } + + if ($html_type == 'CheckBox') { + if ($val) { + $p[] = $key; + $v[] = CRM_Utils_Array::value($key, $option); + } + } + else { + $p[] = $val; + $v[] = CRM_Utils_Array::value($val, $option); + } + } + if (!empty($v)) { + $display = implode(', ', $v); + } + break; + + case 'Select Date': + if (is_array($value)) { + foreach ($value as $key => $val) { + $display[$key] = CRM_Utils_Date::customFormat($val); + } + } + else { + // remove time element display if time is not set + if (empty($option['attributes']['time_format'])) { + $value = substr($value, 0, 10); + } + $display = CRM_Utils_Date::customFormat($value); + } + break; + + case 'Select State/Province': + if (empty($value)) { + $display = ''; + } + else { + $display = CRM_Core_PseudoConstant::stateProvince($value); + } + break; + + case 'Multi-Select State/Province': + if (is_array($value)) { + $checkedData = $value; + } + else { + $checkedData = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($value, 1, -1) + ); + } + + $states = CRM_Core_PseudoConstant::stateProvince(); + $display = NULL; + foreach ($checkedData as $stateID) { + if ($display) { + $display .= ', '; + } + $display .= $states[$stateID]; + } + break; + + case 'Select Country': + if (empty($value)) { + $display = ''; + } + else { + $display = CRM_Core_PseudoConstant::country($value); + } + break; + + case 'Multi-Select Country': + if (is_array($value)) { + $checkedData = $value; + } + else { + $checkedData = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($value, 1, -1) + ); + } + + $countries = CRM_Core_PseudoConstant::country(); + $display = NULL; + foreach ($checkedData as $countryID) { + if ($display) { + $display .= ', '; + } + $display .= $countries[$countryID]; + } + break; + + case 'File': + if ($contactID) { + $url = self::getFileURL($contactID, $fieldID, $value); + if ($url) { + $display = $url['file_url']; + } + } + break; + + case 'TextArea': + if (empty($value)) { + $display = ''; + } + else { + $display = nl2br($value); + } + break; + + case 'Link': + if (empty($value)) { + $display = ''; + } + else { + $display = $value; + } + } + + return $display ? $display : $value; + } + + /** + * Function to set default values for custom data used in profile + * + * @params int $customFieldId custom field id + * @params string $elementName custom field name + * @params array $defaults associated array of fields + * @params int $contactId contact id + * @param int $mode profile mode + * @param mixed $value if passed - dont fetch value from db, + * just format the given value + * @static + * @access public + */ + static function setProfileDefaults($customFieldId, + $elementName, + &$defaults, + $contactId = NULL, + $mode = NULL, + $value = NULL + ) { + //get the type of custom field + $customField = new CRM_Core_BAO_CustomField(); + $customField->id = $customFieldId; + $customField->find(TRUE); + + if (!$contactId) { + if ($mode == CRM_Profile_Form::MODE_CREATE) { + $value = $customField->default_value; + } + } + else { + if (!isset($value)) { + $info = self::getTableColumnGroup($customFieldId); + $query = "SELECT {$info[0]}.{$info[1]} as value FROM {$info[0]} WHERE {$info[0]}.entity_id = {$contactId}"; + $result = CRM_Core_DAO::executeQuery($query); + if ($result->fetch()) { + $value = $result->value; + } + } + + if ($customField->data_type == 'Country') { + if (!$value) { + $config = CRM_Core_Config::singleton(); + if ($config->defaultContactCountry) { + $value = $config->defaultContactCountry(); + } + } + } + } + + //set defaults if mode is registration + if (!trim($value) && + ($value !== 0) && + (!in_array($mode, array(CRM_Profile_Form::MODE_EDIT, CRM_Profile_Form::MODE_SEARCH))) + ) { + $value = $customField->default_value; + } + + if ($customField->data_type == 'Money' && isset($value)) { + $value = number_format($value, 2); + } + switch ($customField->html_type) { + case 'CheckBox': + case 'AdvMulti-Select': + case 'Multi-Select': + $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldId, FALSE); + $defaults[$elementName] = array(); + $checkedValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($value, 1, -1) + ); + foreach ($customOption as $val) { + if (in_array($val['value'], $checkedValue)) { + if ($customField->html_type == 'CheckBox') { + $defaults[$elementName][$val['value']] = 1; + } + elseif ($customField->html_type == 'Multi-Select' || + $customField->html_type == 'AdvMulti-Select' + ) { + $defaults[$elementName][$val['value']] = $val['value']; + } + } + } + break; + + case 'Select Date': + if ($value) { + list($defaults[$elementName], $defaults[$elementName . '_time']) = CRM_Utils_Date::setDateDefaults( + $value, + NULL, + $customField->date_format, + $customField->time_format + ); + } + break; + + case 'Autocomplete-Select': + if ($customField->data_type == 'ContactReference') { + if (is_numeric($value)) { + $defaults[$elementName . '_id'] = $value; + $defaults[$elementName] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name'); + } + } + else { + $label = CRM_Core_BAO_CustomOption::getOptionLabel($customField->id, $value); + $defaults[$elementName . '_id'] = $value; + $defaults[$elementName] = $label; + } + break; + + default: + $defaults[$elementName] = $value; + } + } + + static function getFileURL($contactID, $cfID, $fileID = NULL, $absolute = FALSE) { + if ($contactID) { + if (!$fileID) { + $params = array('id' => $cfID); + $defaults = array(); + CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomField', $params, $defaults); + $columnName = $defaults['column_name']; + + //table name of custom data + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', + $defaults['custom_group_id'], + 'table_name', 'id' + ); + + //query to fetch id from civicrm_file + $query = "SELECT {$columnName} FROM {$tableName} where entity_id = {$contactID}"; + $fileID = CRM_Core_DAO::singleValueQuery($query); + } + + $result = array(); + if ($fileID) { + $fileType = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_File', + $fileID, + 'mime_type', + 'id' + ); + $result['file_id'] = $fileID; + + if ($fileType == 'image/jpeg' || + $fileType == 'image/pjpeg' || + $fileType == 'image/gif' || + $fileType == 'image/x-png' || + $fileType == 'image/png' + ) { + $entityId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', + $fileID, + 'entity_id', + 'id' + ); + list($path) = CRM_Core_BAO_File::path($fileID, $entityId, NULL, NULL); + list($imageWidth, $imageHeight) = getimagesize($path); + list($imageThumbWidth, $imageThumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($imageWidth, $imageHeight); + $url = CRM_Utils_System::url('civicrm/file', + "reset=1&id=$fileID&eid=$contactID", + $absolute, NULL, TRUE, TRUE + ); + $result['file_url'] = ""; + // for non image files + } + else { + $uri = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_File', + $fileID, + 'uri' + ); + $url = CRM_Utils_System::url('civicrm/file', + "reset=1&id=$fileID&eid=$contactID", + $absolute, NULL, TRUE, TRUE + ); + $result['file_url'] = "{$uri}"; + } + } + return $result; + } + } + + /** + * Format custom fields before inserting + * + * @param int $customFieldId custom field id + * @param array $customFormatted formatted array + * @param mix $value value of custom field + * @param string $customFieldExtend custom field extends + * @param int $customValueId custom option value id + * @param int $entityId entity id (contribution, membership...) + * @param boolean $inline consider inline custom groups only + * @param boolean $checkPermission if false, do not include permissioning clause + * + * @return array $customFormatted formatted custom field array + * @static + */ + static function formatCustomField($customFieldId, &$customFormatted, $value, + $customFieldExtend, $customValueId = NULL, + $entityId = NULL, + $inline = FALSE, + $checkPermission = TRUE + ) { + //get the custom fields for the entity + //subtype and basic type + $customDataSubType = NULL; + if (in_array($customFieldExtend, + CRM_Contact_BAO_ContactType::subTypes() + )) { + // This is the case when getFieldsForImport() requires fields + // of subtype and its parent.CRM-5143 + $customDataSubType = $customFieldExtend; + $customFieldExtend = CRM_Contact_BAO_ContactType::getBasicType($customDataSubType); + } + + $customFields = CRM_Core_BAO_CustomField::getFields($customFieldExtend, + FALSE, + $inline, + $customDataSubType, + NULL, + FALSE, + FALSE, + $checkPermission + ); + + if (!array_key_exists($customFieldId, $customFields)) { + return; + } + + // return if field is a 'code' field + if (CRM_Utils_Array::value('is_view', $customFields[$customFieldId])) { + return; + } + + list($tableName, $columnName, $groupID) = self::getTableColumnGroup($customFieldId); + + if (is_array($customFieldExtend)) { + $customFieldExtend = $customFieldExtend[0]; + } + if (!$customValueId && + // we always create new entites for is_multiple unless specified + !$customFields[$customFieldId]['is_multiple'] && + $entityId + ) { + $query = " +SELECT id + FROM $tableName + WHERE entity_id={$entityId}"; + + $customValueId = CRM_Core_DAO::singleValueQuery($query); + } + + //fix checkbox, now check box always submits values + if ($customFields[$customFieldId]['html_type'] == 'CheckBox') { + if ($value) { + // Note that only during merge this is not an array, and you can directly use value + if (is_array($value)) { + $selectedValues = array(); + foreach ($value as $selId => $val) { + if ($val) { + $selectedValues[] = $selId; + } + } + if (!empty($selectedValues)) { + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + $selectedValues + ) . CRM_Core_DAO::VALUE_SEPARATOR; + } + else { + $value = ''; + } + } + } + } + + if ($customFields[$customFieldId]['html_type'] == 'Multi-Select' || + $customFields[$customFieldId]['html_type'] == 'AdvMulti-Select' + ) { + if ($value) { + // Note that only during merge this is not an array, + // and you can directly use value, CRM-4385 + if (is_array($value)) { + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, + array_values($value) + ) . CRM_Core_DAO::VALUE_SEPARATOR; + } + } + else { + $value = ''; + } + } + + if (($customFields[$customFieldId]['html_type'] == 'Multi-Select' || + $customFields[$customFieldId]['html_type'] == 'AdvMulti-Select' || + $customFields[$customFieldId]['html_type'] == 'CheckBox' + ) && + $customFields[$customFieldId]['data_type'] == 'String' && + !empty($customFields[$customFieldId]['text_length']) && + !empty($value) + ) { + // lets make sure that value is less than the length, else we'll + // be losing some data, CRM-7481 + if (strlen($value) >= $customFields[$customFieldId]['text_length']) { + // need to do a few things here + + // 1. lets find a new length + $newLength = $customFields[$customFieldId]['text_length']; + $minLength = strlen($value); + while ($newLength < $minLength) { + $newLength = $newLength * 2; + } + + // set the custom field meta data to have a length larger than value + // alter the custom value table column to match this length + CRM_Core_BAO_SchemaHandler::alterFieldLength($customFieldId, $tableName, $columnName, $newLength); + } + } + + $date = NULL; + if ($customFields[$customFieldId]['data_type'] == 'Date') { + if (!CRM_Utils_System::isNull($value)) { + $format = $customFields[$customFieldId]['date_format']; + $date = CRM_Utils_Date::processDate($value, NULL, FALSE, 'YmdHis', $format); + } + $value = $date; + } + + if ($customFields[$customFieldId]['data_type'] == 'Float' || + $customFields[$customFieldId]['data_type'] == 'Money' + ) { + if (!$value) { + $value = 0; + } + + if ($customFields[$customFieldId]['data_type'] == 'Money') { + $value = CRM_Utils_Rule::cleanMoney($value); + } + } + + if (($customFields[$customFieldId]['data_type'] == 'StateProvince' || + $customFields[$customFieldId]['data_type'] == 'Country' + ) && + empty($value) + ) { + // CRM-3415 + $value = 0; + } + + $fileId = NULL; + + if ($customFields[$customFieldId]['data_type'] == 'File') { + if (empty($value)) { + return; + } + + $config = CRM_Core_Config::singleton(); + + $fName = $value['name']; + $mimeType = $value['type']; + + $filename = pathinfo($fName, PATHINFO_BASENAME); + + // rename this file to go into the secure directory + if (!rename($fName, $config->customFileUploadDir . $filename)) { + CRM_Core_Error::statusBounce(ts('Could not move custom file to custom upload directory')); + break; + } + + if ($customValueId) { + $query = " +SELECT $columnName + FROM $tableName + WHERE id = %1"; + $params = array(1 => array($customValueId, 'Integer')); + $fileId = CRM_Core_DAO::singleValueQuery($query, $params); + } + + $fileDAO = new CRM_Core_DAO_File(); + + if ($fileId) { + $fileDAO->id = $fileId; + } + + $fileDAO->uri = $filename; + $fileDAO->mime_type = $mimeType; + $fileDAO->upload_date = date('Ymdhis'); + $fileDAO->save(); + $fileId = $fileDAO->id; + $value = $filename; + } + + if (!is_array($customFormatted)) { + $customFormatted = array(); + } + + if (!array_key_exists($customFieldId, $customFormatted)) { + $customFormatted[$customFieldId] = array(); + } + + $index = -1; + if ($customValueId) { + $index = $customValueId; + } + + if (!array_key_exists($index, $customFormatted[$customFieldId])) { + $customFormatted[$customFieldId][$index] = array(); + } + $customFormatted[$customFieldId][$index] = array( + 'id' => $customValueId > 0 ? $customValueId : NULL, + 'value' => $value, + 'type' => $customFields[$customFieldId]['data_type'], + 'custom_field_id' => $customFieldId, + 'custom_group_id' => $groupID, + 'table_name' => $tableName, + 'column_name' => $columnName, + 'file_id' => $fileId, + 'is_multiple' => $customFields[$customFieldId]['is_multiple'], + ); + + //we need to sort so that custom fields are created in the order of entry + krsort($customFormatted[$customFieldId]); + return $customFormatted; + } + + static function &defaultCustomTableSchema(&$params) { + // add the id and extends_id + $table = array( + 'name' => $params['name'], + 'is_multiple' => $params['is_multiple'], + 'attributes' => "ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci", + 'fields' => array( + array( + 'name' => 'id', + 'type' => 'int unsigned', + 'primary' => TRUE, + 'required' => TRUE, + 'attributes' => 'AUTO_INCREMENT', + 'comment' => 'Default MySQL primary key', + ), + array( + 'name' => 'entity_id', + 'type' => 'int unsigned', + 'required' => TRUE, + 'comment' => 'Table that this extends', + 'fk_table_name' => $params['extends_name'], + 'fk_field_name' => 'id', + 'fk_attributes' => 'ON DELETE CASCADE', + ), + ), + ); + + if (!$params['is_multiple']) { + $table['indexes'] = array( + array( + 'unique' => TRUE, + 'field_name_1' => 'entity_id', + ), + ); + } + return $table; + } + + static function createField($field, $operation, $indexExist = FALSE, $triggerRebuild = TRUE) { + $tableName = CRM_Core_DAO::getFieldValue( + 'CRM_Core_DAO_CustomGroup', + $field->custom_group_id, + 'table_name' + ); + + $params = array( + 'table_name' => $tableName, + 'operation' => $operation, + 'name' => $field->column_name, + 'type' => CRM_Core_BAO_CustomValueTable::fieldToSQLType( + $field->data_type, + $field->text_length + ), + 'required' => $field->is_required, + 'searchable' => $field->is_searchable, + ); + + if ($operation == 'delete') { + $fkName = "{$tableName}_{$field->column_name}"; + if (strlen($fkName) >= 48) { + $fkName = substr($fkName, 0, 32) . '_' . substr(md5($fkName), 0, 16); + } + $params['fkName'] = $fkName; + } + if ($field->data_type == 'Country' && $field->html_type == 'Select Country') { + $params['fk_table_name'] = 'civicrm_country'; + $params['fk_field_name'] = 'id'; + $params['fk_attributes'] = 'ON DELETE SET NULL'; + } + elseif ($field->data_type == 'Country' && $field->html_type == 'Multi-Select Country') { + $params['type'] = 'varchar(255)'; + } + elseif ($field->data_type == 'StateProvince' && $field->html_type == 'Select State/Province') { + $params['fk_table_name'] = 'civicrm_state_province'; + $params['fk_field_name'] = 'id'; + $params['fk_attributes'] = 'ON DELETE SET NULL'; + } + elseif ($field->data_type == 'StateProvince' && $field->html_type == 'Multi-Select State/Province') { + $params['type'] = 'varchar(255)'; + } + elseif ($field->data_type == 'File') { + $params['fk_table_name'] = 'civicrm_file'; + $params['fk_field_name'] = 'id'; + $params['fk_attributes'] = 'ON DELETE SET NULL'; + } + elseif ($field->data_type == 'ContactReference') { + $params['fk_table_name'] = 'civicrm_contact'; + $params['fk_field_name'] = 'id'; + $params['fk_attributes'] = 'ON DELETE SET NULL'; + } + if ($field->default_value) { + $params['default'] = "'{$field->default_value}'"; + } + + CRM_Core_BAO_SchemaHandler::alterFieldSQL($params, $indexExist, $triggerRebuild); + } + + /** + * Determine whether it would be safe to move a field + * + * @param int $fieldID FK to civicrm_custom_field + * @param int $newGroupID FK to civicrm_custom_group + * + * @return array( + string) or TRUE + */ + static function _moveFieldValidate($fieldID, $newGroupID) { + $errors = array(); + + $field = new CRM_Core_DAO_CustomField(); + $field->id = $fieldID; + if (!$field->find(TRUE)) { + $errors['fieldID'] = 'Invalid ID for custom field'; + return $errors; + } + + $oldGroup = new CRM_Core_DAO_CustomGroup(); + $oldGroup->id = $field->custom_group_id; + if (!$oldGroup->find(TRUE)) { + $errors['fieldID'] = 'Invalid ID for old custom group'; + return $errors; + } + + $newGroup = new CRM_Core_DAO_CustomGroup(); + $newGroup->id = $newGroupID; + if (!$newGroup->find(TRUE)) { + $errors['newGroupID'] = 'Invalid ID for new custom group'; + return $errors; + } + + $query = " +SELECT b.id +FROM civicrm_custom_field a +INNER JOIN civicrm_custom_field b +WHERE a.id = %1 +AND a.label = b.label +AND b.custom_group_id = %2 +"; + $params = array( + 1 => array($field->id, 'Integer'), + 2 => array($newGroup->id, 'Integer'), + ); + $count = CRM_Core_DAO::singleValueQuery($query, $params); + if ($count > 0) { + $errors['newGroupID'] = ts('A field of the same label exists in the destination group'); + } + + $tableName = $oldGroup->table_name; + $columnName = $field->column_name; + + $query = " +SELECT count(*) +FROM $tableName +WHERE $columnName is not null +"; + $count = CRM_Core_DAO::singleValueQuery($query, + CRM_Core_DAO::$_nullArray + ); + if ($count > 0) { + $query = " +SELECT extends +FROM civicrm_custom_group +WHERE id IN ( %1, %2 ) +"; + $params = array(1 => array($oldGroup->id, 'Integer'), + 2 => array($newGroup->id, 'Integer'), + ); + + $dao = CRM_Core_DAO::executeQuery($query, $params); + $extends = array(); + while ($dao->fetch()) { + $extends[] = $dao->extends; + } + if ($extends[0] != $extends[1]) { + $errors['newGroupID'] = ts('The destination group extends a different entity type.'); + } + } + + return empty($errors) ? TRUE : $errors; + } + + /** + * Move a custom data field from one group (table) to another + * + * @param int $fieldID FK to civicrm_custom_field + * @param int $newGroupID FK to civicrm_custom_group + * + * @return void + */ + static function moveField($fieldID, $newGroupID) { + $validation = self::_moveFieldValidate($fieldID, $newGroupID); + if (TRUE !== $validation) { + CRM_Core_Error::fatal(implode(' ', $validation)); + } + $field = new CRM_Core_DAO_CustomField(); + $field->id = $fieldID; + $field->find(TRUE); + + $newGroup = new CRM_Core_DAO_CustomGroup(); + $newGroup->id = $newGroupID; + $newGroup->find(TRUE); + + $oldGroup = new CRM_Core_DAO_CustomGroup(); + $oldGroup->id = $field->custom_group_id; + $oldGroup->find(TRUE); + + $add = clone$field; + $add->custom_group_id = $newGroup->id; + self::createField($add, 'add'); + + $sql = "INSERT INTO {$newGroup->table_name} (entity_id, {$field->column_name}) + SELECT entity_id, {$field->column_name} FROM {$oldGroup->table_name} + ON DUPLICATE KEY UPDATE {$field->column_name} = {$oldGroup->table_name}.{$field->column_name} + "; + CRM_Core_DAO::executeQuery($sql); + + $del = clone$field; + $del->custom_group_id = $oldGroup->id; + self::createField($del, 'delete'); + + $add->save(); + + CRM_Utils_System::flushCache(); + } + + /** + * Get the database table name and column name for a custom field + * + * @param int $fieldID - the fieldID of the custom field + * @param boolean $force - force the sql to be run again (primarily used for tests) + * + * @return array - fatal is fieldID does not exists, else array of tableName, columnName + * @static + * @public + */ + static function getTableColumnGroup($fieldID, $force = FALSE) { + $cacheKey = "CRM_Core_DAO_CustomField_CustomGroup_TableColumn_{$fieldID}"; + $cache = CRM_Utils_Cache::singleton(); + $fieldValues = $cache->get($cacheKey); + if (empty($fieldValues) || $force) { + $query = " +SELECT cg.table_name, cf.column_name, cg.id +FROM civicrm_custom_group cg, + civicrm_custom_field cf +WHERE cf.custom_group_id = cg.id +AND cf.id = %1"; + $params = array(1 => array($fieldID, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + + if (!$dao->fetch()) { + CRM_Core_Error::fatal(); + } + $dao->free(); + $fieldValues = array($dao->table_name, $dao->column_name, $dao->id); + $cache->set($cacheKey, $fieldValues); + } + return $fieldValues; + } + + /** + * Function to get custom option groups + * + * @params array $includeFieldIds ids of custom fields for which + * option groups must be included. + * + * Currently this is required in the cases where option groups are to be included + * for inactive fields : CRM-5369 + * + * @access public + * + * @return $customOptionGroup + * @static + */ + public static function &customOptionGroup($includeFieldIds = NULL) { + static $customOptionGroup = NULL; + + $cacheKey = (empty($includeFieldIds)) ? 'onlyActive' : 'force'; + if ($cacheKey == 'force') { + $customOptionGroup[$cacheKey] = NULL; + } + + if (!CRM_Utils_Array::value($cacheKey, $customOptionGroup)) { + $whereClause = '( g.is_active = 1 AND f.is_active = 1 )'; + + //support for single as well as array format. + if (!empty($includeFieldIds)) { + if (is_array($includeFieldIds)) { + $includeFieldIds = implode(',', $includeFieldIds); + } + $whereClause .= "OR f.id IN ( $includeFieldIds )"; + } + + $query = " + SELECT g.id, g.title + FROM civicrm_option_group g +INNER JOIN civicrm_custom_field f ON ( g.id = f.option_group_id ) + WHERE {$whereClause}"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $customOptionGroup[$cacheKey][$dao->id] = $dao->title; + } + } + + return $customOptionGroup[$cacheKey]; + } + + /** + * Function to fix orphan groups + * + * @params int $customFieldId custom field id + * @params int $optionGroupId option group id + * + * @access public + * + * @return void + * @static + */ + static function fixOptionGroups($customFieldId, $optionGroupId) { + // check if option group belongs to any custom Field else delete + // get the current option group + $currentOptionGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', + $customFieldId, + 'option_group_id' + ); + // get the updated option group + // if both are same return + if ($currentOptionGroupId == $optionGroupId) { + return; + } + + // check if option group is related to any other field + self::checkOptionGroup($currentOptionGroupId); + } + + /** + * Function to check if option group is related to more than one + * custom field + * + * @params int $optionGroupId option group id + * + * @return + * @static + */ + static function checkOptionGroup($optionGroupId) { + $query = " +SELECT count(*) +FROM civicrm_custom_field +WHERE option_group_id = {$optionGroupId}"; + + $count = CRM_Core_DAO::singleValueQuery($query); + + if ($count < 2) { + //delete the option group + CRM_Core_BAO_OptionGroup::del($optionGroupId); + } + } + + static function getOptionGroupDefault($optionGroupId, $htmlType) { + $query = " +SELECT default_value, html_type +FROM civicrm_custom_field +WHERE option_group_id = {$optionGroupId} +AND default_value IS NOT NULL +ORDER BY html_type"; + + $dao = CRM_Core_DAO::executeQuery($query); + $defaultValue = NULL; + $defaultHTMLType = NULL; + while ($dao->fetch()) { + if ($dao->html_type == $htmlType) { + return $dao->default_value; + } + if ($defaultValue == NULL) { + $defaultValue = $dao->default_value; + $defaultHTMLType = $dao->html_type; + } + } + + // some conversions are needed if either the old or new has a html type which has potential + // multiple default values. + if (($htmlType == 'CheckBox' || $htmlType == 'Multi-Select') && + ($defaultHTMLType != 'CheckBox' && $defaultHTMLType != 'Multi-Select') + ) { + $defaultValue = CRM_Core_DAO::VALUE_SEPARATOR . $defaultValue . CRM_Core_DAO::VALUE_SEPARATOR; + } + elseif (($defaultHTMLType == 'CheckBox' || $defaultHTMLType == 'Multi-Select') && + ($htmlType != 'CheckBox' && $htmlType != 'Multi-Select') + ) { + $defaultValue = substr($defaultValue, 1, -1); + $values = explode(CRM_Core_DAO::VALUE_SEPARATOR, + substr($defaultValue, 1, -1) + ); + $defaultValue = $values[0]; + } + + return $defaultValue; + } + + static function postProcess(&$params, + &$customFields, + $entityID, + $customFieldExtends, + $inline = FALSE + ) { + $customData = array(); + + foreach ($params as $key => $value) { + if ($customFieldInfo = CRM_Core_BAO_CustomField::getKeyID($key, TRUE)) { + + // for autocomplete transfer hidden value instead of label + if ($params[$key] && isset($params[$key . '_id'])) { + $value = $params[$key . '_id']; + } + + // we need to append time with date + if ($params[$key] && isset($params[$key . '_time'])) { + $value .= ' ' . $params[$key . '_time']; + } + + CRM_Core_BAO_CustomField::formatCustomField($customFieldInfo[0], + $customData, + $value, + $customFieldExtends, + $customFieldInfo[1], + $entityID, + $inline + ); + } + } + return $customData; + } + + static function buildOption($field, &$options) { + $options['attributes'] = array( + 'label' => $field['label'], + 'data_type' => $field['data_type'], + 'html_type' => $field['html_type'], + ); + + $optionGroupID = NULL; + if (($field['html_type'] == 'CheckBox' || + $field['html_type'] == 'Radio' || + $field['html_type'] == 'Select' || + $field['html_type'] == 'AdvMulti-Select' || + $field['html_type'] == 'Multi-Select' || + ($field['html_type'] == 'Autocomplete-Select' && $field['data_type'] != 'ContactReference') + )) { + if ($field['option_group_id']) { + $optionGroupID = $field['option_group_id']; + } + elseif ($field['data_type'] != 'Boolean') { + CRM_Core_Error::fatal(); + } + } + + // build the cache for custom values with options (label => value) + if ($optionGroupID != NULL) { + $query = " +SELECT label, value + FROM civicrm_option_value + WHERE option_group_id = $optionGroupID +"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + if ($field['data_type'] == 'Int' || $field['data_type'] == 'Float') { + $num = round($dao->value, 2); + $options["$num"] = $dao->label; + } + else { + $options[$dao->value] = $dao->label; + } + } + + CRM_Utils_Hook::customFieldOptions($field['id'], $options); + } + } + + static function getCustomFieldID($fieldLabel, $groupTitle = NULL) { + $params = array(1 => array($fieldLabel, 'String')); + if ($groupTitle) { + $params[2] = array($groupTitle, 'String'); + $sql = " +SELECT f.id +FROM civicrm_custom_field f +INNER JOIN civicrm_custom_group g ON f.custom_group_id = g.id +WHERE ( f.label = %1 OR f.name = %1 ) +AND ( g.title = %2 OR g.name = %2 ) +"; + } + else { + $sql = " +SELECT f.id +FROM civicrm_custom_field f +WHERE ( f.label = %1 OR f.name = %1 ) +"; + } + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch() && + $dao->N == 1 + ) { + return $dao->id; + } + else { + return NULL; + } + } + + /** + * Given ID of a custom field, return its name as well as the name of the custom group it belongs to. + * + */ + static function getNameFromID($ids) { + if (is_array($ids)) { + $ids = implode(',', $ids); + } + $sql = " +SELECT f.id, f.name AS field_name, f.label AS field_label, g.name AS group_name, g.title AS group_title +FROM civicrm_custom_field f +INNER JOIN civicrm_custom_group g ON f.custom_group_id = g.id +WHERE f.id IN ($ids)"; + + + $dao = CRM_Core_DAO::executeQuery($sql); + $result = array(); + while ($dao->fetch()) { + $result[$dao->id] = array( + 'field_name' => $dao->field_name, + 'field_label' => $dao->field_label, + 'group_name' => $dao->group_name, + 'group_title' => $dao->group_title, + ); + } + return $result; + } + + /** + * Validate custom data. + * + * @param array $params custom data submitted. + * ie array( 'custom_1' => 'validate me' ); + * + * @return array $errors validation errors. + * @static + */ + static function validateCustomData($params) { + $errors = array(); + if (!is_array($params) || empty($params)) { + return $errors; + } + + + //pick up profile fields. + $profileFields = array(); + $ufGroupId = CRM_Utils_Array::value('ufGroupId', $params); + if ($ufGroupId) { + $profileFields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, + FALSE, + CRM_Core_Action::VIEW + ); + } + + //lets start w/ params. + foreach ($params as $key => $value) { + $customFieldID = self::getKeyID($key); + if (!$customFieldID) { + continue; + } + + //load the structural info for given field. + $field = new CRM_Core_DAO_CustomField(); + $field->id = $customFieldID; + if (!$field->find(TRUE)) { + continue; + } + $dataType = $field->data_type; + + $profileField = CRM_Utils_Array::value($key, $profileFields, array()); + $fieldTitle = CRM_Utils_Array::value('title', $profileField); + $isRequired = CRM_Utils_Array::value('is_required', $profileField); + if (!$fieldTitle) { + $fieldTitle = $field->label; + } + + //no need to validate. + if (CRM_Utils_System::isNull($value) && !$isRequired) { + continue; + } + + //lets validate first for required field. + if ($isRequired && CRM_Utils_System::isNull($value)) { + $errors[$key] = ts('%1 is a required field.', array(1 => $fieldTitle)); + continue; + } + + //now time to take care of custom field form rules. + $ruleName = $errorMsg = NULL; + switch ($dataType) { + case 'Int': + $ruleName = 'integer'; + $errorMsg = ts('%1 must be an integer (whole number).', + array(1 => $fieldTitle) + ); + break; + + case 'Money': + $ruleName = 'money'; + $errorMsg = ts('%1 must in proper money format. (decimal point/comma/space is allowed).', + array(1 => $fieldTitle) + ); + break; + + case 'Float': + $ruleName = 'numeric'; + $errorMsg = ts('%1 must be a number (with or without decimal point).', + array(1 => $fieldTitle) + ); + break; + + case 'Link': + $ruleName = 'wikiURL'; + $errorMsg = ts('%1 must be valid Website.', + array(1 => $fieldTitle) + ); + break; + } + + if ($ruleName && !CRM_Utils_System::isNull($value)) { + $valid = FALSE; + $funName = "CRM_Utils_Rule::{$ruleName}"; + if (is_callable($funName)) { + $valid = call_user_func($funName, $value); + } + if (!$valid) { + $errors[$key] = $errorMsg; + } + } + } + + return $errors; + } + + static function isMultiRecordField($customId) { + $isMultipleWithGid = FALSE; + if (!is_numeric($customId)) { + $customId = self::getKeyID($customId); + } + if (is_numeric($customId)) { + $sql = "SELECT cg.id cgId + FROM civicrm_custom_group cg + INNER JOIN civicrm_custom_field cf + ON cg.id = cf.custom_group_id +WHERE cf.id = %1 AND cg.is_multiple = 1"; + $params[1] = array($customId, 'Integer'); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + if ($dao->cgId) { + $isMultipleWithGid = $dao->cgId; + } + } + } + + return $isMultipleWithGid; + } +} + diff --git a/CRM/Core/BAO/CustomGroup.php b/CRM/Core/BAO/CustomGroup.php new file mode 100644 index 0000000000..27459a4478 --- /dev/null +++ b/CRM/Core/BAO/CustomGroup.php @@ -0,0 +1,2091 @@ +title = $params['title']; + + if (in_array($params['extends'][0], + array( + 'ParticipantRole', + 'ParticipantEventName', + 'ParticipantEventType', + ) + )) { + $group->extends = 'Participant'; + } + else { + $group->extends = $params['extends'][0]; + } + + $group->extends_entity_column_id = 'null'; + if ( + $params['extends'][0] == 'ParticipantRole' || + $params['extends'][0] == 'ParticipantEventName' || + $params['extends'][0] == 'ParticipantEventType' + ) { + $group->extends_entity_column_id = + CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $params['extends'][0], 'value', 'name'); + } + + //this is format when form get submit. + $extendsChildType = CRM_Utils_Array::value(1, $params['extends']); + //lets allow user to pass direct child type value, CRM-6893 + if (CRM_Utils_Array::value('extends_entity_column_value', $params)) { + $extendsChildType = $params['extends_entity_column_value']; + } + if (!CRM_Utils_System::isNull($extendsChildType)) { + $extendsChildType = implode(CRM_Core_DAO::VALUE_SEPARATOR, $extendsChildType); + if (CRM_Utils_Array::value(0, $params['extends']) == 'Relationship') { + $extendsChildType = str_replace(array('_a_b', '_b_a'), array('', ''), $extendsChildType); + } + if (substr($extendsChildType, 0, 1) != CRM_Core_DAO::VALUE_SEPARATOR) { + $extendsChildType = CRM_Core_DAO::VALUE_SEPARATOR . $extendsChildType . CRM_Core_DAO::VALUE_SEPARATOR; + } + } + else { + $extendsChildType = 'null'; + } + $group->extends_entity_column_value = $extendsChildType; + + if (isset($params['id'])) { + $oldWeight = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $params['id'], 'weight', 'id'); + } + else { + $oldWeight = 0; + } + $group->weight = CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_CustomGroup', $oldWeight, CRM_Utils_Array::value('weight', $params, FALSE)); + $fields = array('style', 'collapse_display', 'collapse_adv_display', 'help_pre', 'help_post', 'is_active', 'is_multiple'); + foreach ($fields as $field) { + $group->$field = CRM_Utils_Array::value($field, $params, FALSE); + } + $group->max_multiple = isset($params['is_multiple']) ? (isset($params['max_multiple']) && + $params['max_multiple'] >= '0' + ) ? $params['max_multiple'] : 'null' : 'null'; + + $tableName = $oldTableName = NULL; + if (isset($params['id'])) { + $group->id = $params['id']; + //check whether custom group was changed from single-valued to multiple-valued + $isMultiple = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', + $params['id'], + 'is_multiple' + ); + + if ((CRM_Utils_Array::value('is_multiple', $params) || $isMultiple) && + ($params['is_multiple'] != $isMultiple) + ) { + $oldTableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', + $params['id'], + 'table_name' + ); + } + } + else { + $group->created_id = CRM_Utils_Array::value('created_id', $params); + $group->created_date = CRM_Utils_Array::value('created_date', $params); + + // we do this only once, so name never changes + if (isset($params['name'])) { + $group->name = CRM_Utils_String::munge($params['name'], '_', 64); + } + else { + $group->name = CRM_Utils_String::munge($group->title, '_', 64); + } + + // lets create the table associated with the group and save it + $tableName = $group->table_name = "civicrm_value_" . strtolower($group->name); + } + + // enclose the below in a transaction + $transaction = new CRM_Core_Transaction(); + + $group->save(); + if ($tableName) { + // now append group id to table name, this prevent any name conflicts + // like CRM-2742 + $tableName .= "_{$group->id}"; + $group->table_name = $tableName; + CRM_Core_DAO::setFieldValue('CRM_Core_DAO_CustomGroup', + $group->id, + 'table_name', + $tableName + ); + + // now create the table associated with this group + self::createTable($group); + } + elseif ($oldTableName) { + CRM_Core_BAO_SchemaHandler::changeUniqueToIndex($oldTableName, CRM_Utils_Array::value('is_multiple', $params)); + } + + if (CRM_Utils_Array::value('overrideFKConstraint', $params) == 1) { + $table = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', + $params['id'], + 'table_name' + ); + CRM_Core_BAO_SchemaHandler::changeFKConstraint($table, self::mapTableName($params['extends'][0])); + } + $transaction->commit(); + + // reset the cache + CRM_Utils_System::flushCache(); + + if ($tableName) { + CRM_Utils_Hook::post('create', 'CustomGroup', $group->id, $group); + } + else { + CRM_Utils_Hook::post('edit', 'CustomGroup', $group->id, $group); + } + + return $group; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * contact_id. We'll tweak this function to be more full featured over a period + * of time. This is the inverse function of create. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_DAO_CustomGroup object + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + return CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomGroup', $params, $defaults); + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + * @access public + */ + static function setIsActive($id, $is_active) { + // reset the cache + CRM_Core_BAO_Cache::deleteGroup('contact fields'); + + if (!$is_active) { + CRM_Core_BAO_UFField::setUFFieldStatus($id, $is_active); + } + + return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_CustomGroup', $id, 'is_active', $is_active); + } + + /** + * Determine if given entity (sub)type has any custom groups + * + * @param string $extends e.g. "Individual", "Activity" + * @param int $columnId e.g. custom-group matching mechanism (usu NULL for matching on sub type-id); see extends_entity_column_id + * @param string $columnValue e.g. "Student" or "3" or "3\05"; see extends_entity_column_value + */ + public static function hasCustomGroup($extends, $columnId, $columnValue) { + $dao = new CRM_Core_DAO_CustomGroup(); + $dao->extends = $extends; + $dao->extends_entity_column_id = $columnId; + $escapedValue = CRM_Core_DAO::VALUE_SEPARATOR . CRM_Core_DAO::escapeString($columnValue) . CRM_Core_DAO::VALUE_SEPARATOR; + $dao->whereAdd("extends_entity_column_value LIKE \"%$escapedValue%\""); + //$dao->extends_entity_column_value = $columnValue; + return $dao->find() ? TRUE : FALSE; + } + + /** + * Determine if there are any CustomGroups for the given $activityTypeId. + * If none found, create one. + * + * @param int $activityTypeId + * @return bool TRUE if a group is found or created; FALSE on error + */ + public static function autoCreateByActivityType($activityTypeId) { + if (self::hasCustomGroup('Activity', NULL, $activityTypeId)) { + return TRUE; + } + $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE, FALSE); // everything + $params = array( + 'version' => 3, + 'extends' => 'Activity', + 'extends_entity_column_id' => NULL, + 'extends_entity_column_value' => CRM_Utils_Array::implodePadded(array($activityTypeId)), + 'title' => ts('%1 Questions', array(1 => $activityTypes[$activityTypeId])), + 'style' => 'Inline', + 'is_active' => 1, + ); + $result = civicrm_api('CustomGroup', 'create', $params); + return ! $result['is_error']; + } + + /** + * Get custom groups/fields for type of entity. + * + * An array containing all custom groups and their custom fields is returned. + * + * @param string $entityType - of the contact whose contact type is needed + * @param int $entityId - optional - id of entity if we need to populate the tree with custom values. + * @param int $groupId - optional group id (if we need it for a single group only) + * - if groupId is 0 it gets for inline groups only + * - if groupId is -1 we get for all groups + * + * @return array $groupTree - array consisting of all groups and fields and optionally populated with custom data values. + * + * @access public + * + * @static + * + */ + public static function &getTree($entityType, + &$form, + $entityID = NULL, + $groupID = NULL, + $subType = NULL, + $subName = NULL, + $fromCache = TRUE + ) { + if ($entityID) { + $entityID = CRM_Utils_Type::escape($entityID, 'Integer'); + } + + // create a new tree + $strSelect = $strFrom = $strWhere = $orderBy = ''; + $tableData = array(); + + // using tableData to build the queryString + $tableData = array( + 'civicrm_custom_field' => + array( + 'id', + 'label', + 'column_name', + 'data_type', + 'html_type', + 'default_value', + 'attributes', + 'is_required', + 'is_view', + 'help_pre', + 'help_post', + 'options_per_line', + 'start_date_years', + 'end_date_years', + 'date_format', + 'time_format', + 'option_group_id', + ), + 'civicrm_custom_group' => + array( + 'id', + 'name', + 'table_name', + 'title', + 'help_pre', + 'help_post', + 'collapse_display', + 'is_multiple', + 'extends', + 'extends_entity_column_id', + 'extends_entity_column_value', + 'max_multiple', + ), + ); + + // create select + $select = array(); + foreach ($tableData as $tableName => $tableColumn) { + foreach ($tableColumn as $columnName) { + $alias = $tableName . "_" . $columnName; + $select[] = "{$tableName}.{$columnName} as {$tableName}_{$columnName}"; + } + } + $strSelect = "SELECT " . implode(', ', $select); + + // from, where, order by + $strFrom = " +FROM civicrm_custom_group +LEFT JOIN civicrm_custom_field ON (civicrm_custom_field.custom_group_id = civicrm_custom_group.id) +"; + + // if entity is either individual, organization or household pls get custom groups for 'contact' too. + if ($entityType == "Individual" || $entityType == 'Organization' || $entityType == 'Household') { + $in = "'$entityType', 'Contact'"; + } + elseif (strpos($entityType, "'") !== FALSE) { + // this allows the calling function to send in multiple entity types + $in = $entityType; + } + else { + // quote it + $in = "'$entityType'"; + } + + if ($subType) { + $subTypeClause = ''; + if (is_array($subType)) { + $subType = implode(',', $subType); + } + if (strpos($subType, ',')) { + $subTypeParts = explode(',', $subType); + $subTypeClauses = array(); + foreach ($subTypeParts as $subTypePart) { + $subTypePart = CRM_Core_DAO::VALUE_SEPARATOR . trim($subTypePart, CRM_Core_DAO::VALUE_SEPARATOR) . CRM_Core_DAO::VALUE_SEPARATOR; + $subTypeClauses[] = "civicrm_custom_group.extends_entity_column_value LIKE '%$subTypePart%'"; + } + $subTypeClause = '(' . implode(' OR ', $subTypeClauses) . " OR civicrm_custom_group.extends_entity_column_value IS NULL )"; + } + else { + $subType = CRM_Core_DAO::VALUE_SEPARATOR . trim($subType, CRM_Core_DAO::VALUE_SEPARATOR) . CRM_Core_DAO::VALUE_SEPARATOR; + + $subTypeClause = "( civicrm_custom_group.extends_entity_column_value LIKE '%$subType%' + OR civicrm_custom_group.extends_entity_column_value IS NULL )"; + } + + $strWhere = " +WHERE civicrm_custom_group.is_active = 1 + AND civicrm_custom_field.is_active = 1 + AND civicrm_custom_group.extends IN ($in) + AND $subTypeClause +"; + if ($subName) { + $strWhere .= " AND civicrm_custom_group.extends_entity_column_id = {$subName} "; + } + } + else { + $strWhere = " +WHERE civicrm_custom_group.is_active = 1 + AND civicrm_custom_field.is_active = 1 + AND civicrm_custom_group.extends IN ($in) + AND civicrm_custom_group.extends_entity_column_value IS NULL +"; + } + + $params = array(); + if ($groupID > 0) { + // since we want a specific group id we add it to the where clause + $strWhere .= " AND civicrm_custom_group.id = %1"; + $params[1] = array($groupID, 'Integer'); + } + elseif (!$groupID) { + // since groupID is false we need to show all Inline groups + $strWhere .= " AND civicrm_custom_group.style = 'Inline'"; + } + + // ensure that the user has access to these custom groups + $strWhere .= " AND " . CRM_Core_Permission::customGroupClause(CRM_Core_Permission::VIEW, + 'civicrm_custom_group.' + ); + + $orderBy = " +ORDER BY civicrm_custom_group.weight, + civicrm_custom_group.title, + civicrm_custom_field.weight, + civicrm_custom_field.label +"; + + // final query string + $queryString = "$strSelect $strFrom $strWhere $orderBy"; + + // lets see if we can retrieve the groupTree from cache + $cacheString = $queryString; + if ( $groupID > 0 ) { + $cacheString .= "_{$groupID}"; + } else { + $cacheString .= "_Inline"; + } + + $cacheKey = "CRM_Core_DAO_CustomGroup_Query " . md5($cacheString); + + $cache = CRM_Utils_Cache::singleton(); + + if ($fromCache) { + $groupTree = $cache->get($cacheKey); + } + + if (empty($groupTree)) { + $groupTree = array(); + $crmDAO = CRM_Core_DAO::executeQuery($queryString, $params); + + $customValueTables = array(); + + // process records + while ($crmDAO->fetch()) { + // get the id's + $groupID = $crmDAO->civicrm_custom_group_id; + $fieldId = $crmDAO->civicrm_custom_field_id; + + // create an array for groups if it does not exist + if (!array_key_exists($groupID, $groupTree)) { + $groupTree[$groupID] = array(); + $groupTree[$groupID]['id'] = $groupID; + + // populate the group information + foreach ($tableData['civicrm_custom_group'] as $fieldName) { + $fullFieldName = "civicrm_custom_group_$fieldName"; + if ($fieldName == 'id' || + is_null($crmDAO->$fullFieldName) + ) { + continue; + } + // CRM-5507 + if ($fieldName == 'extends_entity_column_value' && $subType) { + $groupTree[$groupID]['subtype'] = trim($subType, CRM_Core_DAO::VALUE_SEPARATOR); + } + $groupTree[$groupID][$fieldName] = $crmDAO->$fullFieldName; + } + $groupTree[$groupID]['fields'] = array(); + + $customValueTables[$crmDAO->civicrm_custom_group_table_name] = array(); + } + + // add the fields now (note - the query row will always contain a field) + // we only reset this once, since multiple values come is as multiple rows + if (!array_key_exists($fieldId, $groupTree[$groupID]['fields'])) { + $groupTree[$groupID]['fields'][$fieldId] = array(); + } + + $customValueTables[$crmDAO->civicrm_custom_group_table_name][$crmDAO->civicrm_custom_field_column_name] = 1; + $groupTree[$groupID]['fields'][$fieldId]['id'] = $fieldId; + // populate information for a custom field + foreach ($tableData['civicrm_custom_field'] as $fieldName) { + $fullFieldName = "civicrm_custom_field_$fieldName"; + if ($fieldName == 'id' || + is_null($crmDAO->$fullFieldName) + ) { + continue; + } + $groupTree[$groupID]['fields'][$fieldId][$fieldName] = $crmDAO->$fullFieldName; + } + } + + if (!empty($customValueTables)) { + $groupTree['info'] = array('tables' => $customValueTables); + } + + $cache->set($cacheKey, $groupTree); + } + + // now that we have all the groups and fields, lets get the values + // since we need to know the table and field names + + // add info to groupTree + if (isset($groupTree['info']) && !empty($groupTree['info'])) { + $select = $from = $where = array(); + foreach ($groupTree['info']['tables'] as $table => $fields) { + $from[] = $table; + $select[] = "{$table}.id as {$table}_id"; + $select[] = "{$table}.entity_id as {$table}_entity_id"; + + foreach ($fields as $column => $dontCare) { + $select[] = "{$table}.{$column} as {$table}_{$column}"; + } + + if ($entityID) { + $where[] = "{$table}.entity_id = $entityID"; + } + } + + $groupTree['info']['select'] = $select; + $groupTree['info']['from'] = $from; + $groupTree['info']['where'] = NULL; + + if ($entityID) { + $groupTree['info']['where'] = $where; + $select = implode(', ', $select); + + // this is a hack to find a table that has some values for this + // entityID to make the below LEFT JOIN work (CRM-2518) + $firstTable = NULL; + foreach ($from as $table) { + $query = " +SELECT id +FROM $table +WHERE entity_id = $entityID +"; + $recordExists = CRM_Core_DAO::singleValueQuery($query); + if ($recordExists) { + $firstTable = $table; + break; + } + } + + if ($firstTable) { + $fromSQL = $firstTable; + foreach ($from as $table) { + if ($table != $firstTable) { + $fromSQL .= "\nLEFT JOIN $table USING (entity_id)"; + } + } + + $query = " +SELECT $select + FROM $fromSQL + WHERE {$firstTable}.entity_id = $entityID +"; + + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + foreach ($groupTree as $groupID => $group) { + if ($groupID === 'info') { + continue; + } + $table = $groupTree[$groupID]['table_name']; + foreach ($group['fields'] as $fieldID => $dontCare) { + $column = $groupTree[$groupID]['fields'][$fieldID]['column_name']; + $idName = "{$table}_id"; + $fieldName = "{$table}_{$column}"; + + $dataType = $groupTree[$groupID]['fields'][$fieldID]['data_type']; + if ($dataType == 'File') { + if (isset($dao->$fieldName)) { + $config = CRM_Core_Config::singleton(); + $fileDAO = new CRM_Core_DAO_File(); + $fileDAO->id = $dao->$fieldName; + + if ($fileDAO->find(TRUE)) { + $entityIDName = "{$table}_entity_id"; + $customValue['id'] = $dao->$idName; + $customValue['data'] = $fileDAO->uri; + $customValue['fid'] = $fileDAO->id; + $customValue['fileURL'] = CRM_Utils_System::url('civicrm/file', "reset=1&id={$fileDAO->id}&eid={$dao->$entityIDName}"); + $customValue['displayURL'] = NULL; + $deleteExtra = ts('Are you sure you want to delete attached file.'); + $deleteURL = array( + CRM_Core_Action::DELETE => + array( + 'name' => ts('Delete Attached File'), + 'url' => 'civicrm/file', + 'qs' => 'reset=1&id=%%id%%&eid=%%eid%%&fid=%%fid%%&action=delete', + 'extra' => + 'onclick = "if (confirm( \'' . $deleteExtra . '\' ) ) this.href+=\'&confirmed=1\'; else return false;"', + ), + ); + $customValue['deleteURL'] = CRM_Core_Action::formLink($deleteURL, + CRM_Core_Action::DELETE, + array( + 'id' => $fileDAO->id, + 'eid' => $dao->$entityIDName, + 'fid' => $fieldID, + ) + ); + $customValue['fileName'] = CRM_Utils_File::cleanFileName(basename($fileDAO->uri)); + if ($fileDAO->mime_type == "image/jpeg" || + $fileDAO->mime_type == "image/pjpeg" || + $fileDAO->mime_type == "image/gif" || + $fileDAO->mime_type == "image/x-png" || + $fileDAO->mime_type == "image/png" + ) { + $customValue['displayURL'] = $customValue['fileURL']; + $entityId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', + $fileDAO->id, + 'entity_id', + 'file_id' + ); + $customValue['imageURL'] = str_replace('persist/contribute', 'custom', $config->imageUploadURL) . $fileDAO->uri; + list($path) = CRM_Core_BAO_File::path($fileDAO->id, $entityId, + NULL, NULL + ); + list($imageWidth, $imageHeight) = getimagesize($path); + list($imageThumbWidth, $imageThumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($imageWidth, $imageHeight); + $customValue['imageThumbWidth'] = $imageThumbWidth; + $customValue['imageThumbHeight'] = $imageThumbHeight; + } + } + } + else { + $customValue = array( + 'id' => $dao->$idName, + 'data' => '', + ); + } + } + else { + $customValue = array( + 'id' => $dao->$idName, + 'data' => $dao->$fieldName, + ); + } + if (!array_key_exists('customValue', $groupTree[$groupID]['fields'][$fieldID])) { + $groupTree[$groupID]['fields'][$fieldID]['customValue'] = array(); + } + if (empty($groupTree[$groupID]['fields'][$fieldID]['customValue'])) { + $groupTree[$groupID]['fields'][$fieldID]['customValue'] = array(1 => $customValue); + } + else { + $groupTree[$groupID]['fields'][$fieldID]['customValue'][] = $customValue; + } + } + } + } + } + } + } + + return $groupTree; + } + + /** + * Get the group title. + * + * @param int $id id of group. + * + * @return string title + * + * @access public + * @static + * + */ + public static function getTitle($id) { + return CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $id, 'title'); + } + + /** + * Get custom group details for a group. + * + * An array containing custom group details (including their custom field) is returned. + * + * @param int $groupId - group id whose details are needed + * @param boolean $searchable - is this field searchable + * @param array $extends - which table does it extend if any + * + * @return array $groupTree - array consisting of all group and field details + * + * @access public + * + * @static + * + */ + public static function &getGroupDetail($groupId = NULL, $searchable = NULL, &$extends = NULL) { + // create a new tree + $groupTree = array(); + $select = $from = $where = $orderBy = ''; + + $tableData = array(); + + // using tableData to build the queryString + $tableData = array( + 'civicrm_custom_field' => + array( + 'id', + 'label', + 'data_type', + 'html_type', + 'default_value', + 'attributes', + 'is_required', + 'help_pre', + 'help_post', + 'options_per_line', + 'is_searchable', + 'start_date_years', + 'end_date_years', + 'is_search_range', + 'date_format', + 'time_format', + 'note_columns', + 'note_rows', + 'column_name', + 'is_view', + 'option_group_id', + ), + 'civicrm_custom_group' => + array( + 'id', + 'name', + 'title', + 'help_pre', + 'help_post', + 'collapse_display', + 'collapse_adv_display', + 'extends', + 'extends_entity_column_value', + 'table_name', + ), + ); + + // create select + $select = "SELECT"; + $s = array(); + foreach ($tableData as $tableName => $tableColumn) { + foreach ($tableColumn as $columnName) { + $s[] = "{$tableName}.{$columnName} as {$tableName}_{$columnName}"; + } + } + $select = 'SELECT ' . implode(', ', $s); + $params = array(); + // from, where, order by + $from = " FROM civicrm_custom_field, civicrm_custom_group"; + $where = " WHERE civicrm_custom_field.custom_group_id = civicrm_custom_group.id + AND civicrm_custom_group.is_active = 1 + AND civicrm_custom_field.is_active = 1 "; + if ($groupId) { + $params[1] = array($groupId, 'Integer'); + $where .= " AND civicrm_custom_group.id = %1"; + } + + if ($searchable) { + $where .= " AND civicrm_custom_field.is_searchable = 1"; + } + + if ($extends) { + $clause = array(); + foreach ($extends as $e) { + $clause[] = "civicrm_custom_group.extends = '$e'"; + } + $where .= " AND ( " . implode(' OR ', $clause) . " ) "; + + //include case activities customdata if case is enabled + if (in_array('Activity', $extends)) { + $extendValues = implode(',', array_keys(CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'label', TRUE))); + $where .= " AND ( civicrm_custom_group.extends_entity_column_value IS NULL OR REPLACE( civicrm_custom_group.extends_entity_column_value, %2, ' ') IN ($extendValues) ) "; + $params[2] = array(CRM_Core_DAO::VALUE_SEPARATOR, 'String'); + } + } + + // ensure that the user has access to these custom groups + $where .= " AND " . CRM_Core_Permission::customGroupClause(CRM_Core_Permission::VIEW, + 'civicrm_custom_group.' + ); + + $orderBy = " ORDER BY civicrm_custom_group.weight, civicrm_custom_field.weight"; + + // final query string + $queryString = $select . $from . $where . $orderBy; + + // dummy dao needed + $crmDAO = CRM_Core_DAO::executeQuery($queryString, $params); + + // process records + while ($crmDAO->fetch()) { + $groupId = $crmDAO->civicrm_custom_group_id; + $fieldId = $crmDAO->civicrm_custom_field_id; + + // create an array for groups if it does not exist + if (!array_key_exists($groupId, $groupTree)) { + $groupTree[$groupId] = array(); + $groupTree[$groupId]['id'] = $groupId; + + foreach ($tableData['civicrm_custom_group'] as $v) { + $fullField = "civicrm_custom_group_" . $v; + + if ($v == 'id' || is_null($crmDAO->$fullField)) { + continue; + } + + $groupTree[$groupId][$v] = $crmDAO->$fullField; + } + + $groupTree[$groupId]['fields'] = array(); + } + + // add the fields now (note - the query row will always contain a field) + $groupTree[$groupId]['fields'][$fieldId] = array(); + $groupTree[$groupId]['fields'][$fieldId]['id'] = $fieldId; + + foreach ($tableData['civicrm_custom_field'] as $v) { + $fullField = "civicrm_custom_field_" . $v; + if ($v == 'id' || is_null($crmDAO->$fullField)) { + continue; + } + $groupTree[$groupId]['fields'][$fieldId][$v] = $crmDAO->$fullField; + } + } + + return $groupTree; + } + + public static function &getActiveGroups($entityType, $path, $cidToken = '%%cid%%') { + // for Group's + $customGroupDAO = new CRM_Core_DAO_CustomGroup(); + + // get only 'Tab' groups + $customGroupDAO->whereAdd("style = 'Tab'"); + $customGroupDAO->whereAdd("is_active = 1"); + + // add whereAdd for entity type + self::_addWhereAdd($customGroupDAO, $entityType, $cidToken); + + $groups = array(); + + $permissionClause = CRM_Core_Permission::customGroupClause(CRM_Core_Permission::VIEW, NULL, TRUE); + $customGroupDAO->whereAdd($permissionClause); + + // order by weight + $customGroupDAO->orderBy('weight'); + $customGroupDAO->find(); + + // process each group with menu tab + while ($customGroupDAO->fetch()) { + $group = array(); + $group['id'] = $customGroupDAO->id; + $group['path'] = $path; + $group['title'] = "$customGroupDAO->title"; + $group['query'] = "reset=1&gid={$customGroupDAO->id}&cid={$cidToken}"; + $group['extra'] = array('gid' => $customGroupDAO->id); + $group['table_name'] = $customGroupDAO->table_name; + $groups[] = $group; + } + + return $groups; + } + + /** + * Get the table name for the entity type + * currently if entity type is 'Contact', 'Individual', 'Household', 'Organization' + * tableName is 'civicrm_contact' + * + * @param string $entityType what entity are we extending here ? + * + * @return string $tableName + * + * @access private + * @static + * + */ + private static function _getTableName($entityType) { + $tableName = ''; + switch ($entityType) { + case 'Contact': + case 'Individual': + case 'Household': + case 'Organization': + $tableName = 'civicrm_contact'; + break; + + case 'Contribution': + $tableName = 'civicrm_contribution'; + break; + + case 'Group': + $tableName = 'civicrm_group'; + break; + // DRAFTING: Verify if we cannot make it pluggable + + case 'Activity': + $tableName = 'civicrm_activity'; + break; + + case 'Relationship': + $tableName = 'civicrm_relationship'; + break; + + case 'Membership': + $tableName = 'civicrm_membership'; + break; + + case 'Participant': + $tableName = 'civicrm_participant'; + break; + + case 'Event': + $tableName = 'civicrm_event'; + break; + + case 'Grant': + $tableName = 'civicrm_grant'; + break; + // need to add cases for Location, Address + } + + return $tableName; + } + + /** + * Get a list of custom groups which extend a given entity type. + * If there are custom-groups which only apply to certain subtypes, + * those WILL be included. + * + * @param $entityType string + * @return CRM_Core_DAO_CustomGroup + */ + static function getAllCustomGroupsByBaseEntity($entityType) { + $customGroupDAO = new CRM_Core_DAO_CustomGroup(); + self::_addWhereAdd($customGroupDAO, $entityType, NULL, TRUE); + return $customGroupDAO; + } + + /** + * Add the whereAdd clause for the DAO depending on the type of entity + * the custom group is extending. + * + * @param object CRM_Core_DAO_CustomGroup (reference) - Custom Group DAO. + * @param string $entityType - what entity are we extending here ? + * + * @return void + * + * @access private + * @static + * + */ + private static function _addWhereAdd(&$customGroupDAO, $entityType, $entityID = NULL, $allSubtypes = FALSE) { + $addSubtypeClause = FALSE; + + switch ($entityType) { + case 'Contact': + // if contact, get all related to contact + $extendList = "'Contact','Individual','Household','Organization'"; + $customGroupDAO->whereAdd("extends IN ( $extendList )"); + if (!$allSubtypes) { + $addSubtypeClause = TRUE; + } + break; + + case 'Individual': + case 'Household': + case 'Organization': + // is I/H/O then get I/H/O and contact + $extendList = "'Contact','$entityType'"; + $customGroupDAO->whereAdd("extends IN ( $extendList )"); + if (!$allSubtypes) { + $addSubtypeClause = TRUE; + } + break; + + case 'Location': + case 'Address': + case 'Activity': + case 'Contribution': + case 'Membership': + case 'Participant': + $customGroupDAO->whereAdd("extends IN ('$entityType')"); + break; + } + + if ($addSubtypeClause) { + $csType = is_numeric($entityID) ? CRM_Contact_BAO_Contact::getContactSubType($entityID) : FALSE; + + if (!empty($csType)) { + $subtypeClause = array(); + foreach ($csType as $subtype) { + $subtype = CRM_Core_DAO::VALUE_SEPARATOR . $subtype . CRM_Core_DAO::VALUE_SEPARATOR; + $subtypeClause[] = "extends_entity_column_value LIKE '%{$subtype}%'"; + } + $subtypeClause[] = "extends_entity_column_value IS NULL"; + $customGroupDAO->whereAdd("( " . implode(' OR ', $subtypeClause) . " )"); + } + else { + $customGroupDAO->whereAdd("extends_entity_column_value IS NULL"); + } + } + } + + /** + * Delete the Custom Group. + * + * @param $group object the DAO custom group object + * @param $force boolean whether to force the deletion, even if there are custom fields + * + * @return boolean false if field exists for this group, true if group gets deleted. + * + * @access public + * @static + * + */ + public static function deleteGroup($group, $force = FALSE) { + + //check wheter this contain any custom fields + $customField = new CRM_Core_DAO_CustomField(); + $customField->custom_group_id = $group->id; + $customField->find(); + + // return early if there are custom fields and we're not + // forcing the delete, otherwise delete the fields one by one + while ($customField->fetch()) { + if (!$force) { + return FALSE; + } + CRM_Core_BAO_CustomField::deleteField($customField); + } + + // drop the table associated with this custom group + CRM_Core_BAO_SchemaHandler::dropTable($group->table_name); + + //delete custom group + $group->delete(); + + CRM_Utils_Hook::post('delete', 'CustomGroup', $group->id, $group); + + return TRUE; + } + + static function setDefaults(&$groupTree, &$defaults, $viewMode = FALSE, $inactiveNeeded = FALSE, $action = CRM_Core_Action::NONE) { + foreach ($groupTree as $id => $group) { + if (!isset($group['fields'])) { + continue; + } + $groupId = CRM_Utils_Array::value('id', $group); + foreach ($group['fields'] as $field) { + if (CRM_Utils_Array::value('element_value', $field) !== NULL) { + $value = $field['element_value']; + } + elseif (CRM_Utils_Array::value('default_value', $field) !== NULL && + ($action != CRM_Core_Action::UPDATE || + // CRM-7548 + !array_key_exists('element_value', $field) + ) + ) { + $value = $viewMode ? NULL : $field['default_value']; + } + else { + continue; + } + + $fieldId = $field['id']; + $elementName = $field['element_name']; + switch ($field['html_type']) { + case 'Multi-Select': + case 'AdvMulti-Select': + case 'CheckBox': + $defaults[$elementName] = array(); + $customOption = CRM_Core_BAO_CustomOption::getCustomOption($field['id'], $inactiveNeeded); + if ($viewMode) { + $checkedData = explode(CRM_Core_DAO::VALUE_SEPARATOR, substr($value, 1, -1)); + if (isset($value)) { + foreach ($customOption as $customValue => $customLabel) { + if (in_array($customValue, $checkedData)) { + if ($field['html_type'] == 'CheckBox') { + $defaults[$elementName][$customValue] = 1; + } + else { + $defaults[$elementName][$customValue] = $customValue; + } + } + else { + $defaults[$elementName][$customValue] = 0; + } + } + } + } + else { + if (isset($field['customValue']['data'])) { + $checkedData = explode(CRM_Core_DAO::VALUE_SEPARATOR, substr($field['customValue']['data'], 1, -1)); + foreach ($customOption as $val) { + if (in_array($val['value'], $checkedData)) { + if ($field['html_type'] == 'CheckBox') { + $defaults[$elementName][$val['value']] = 1; + } + else { + $defaults[$elementName][$val['value']] = $val['value']; + } + } + else { + $defaults[$elementName][$val['value']] = 0; + } + } + } + else { + $checkedValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, substr($value, 1, -1)); + foreach ($customOption as $val) { + if (in_array($val['value'], $checkedValue)) { + if ($field['html_type'] == 'CheckBox') { + $defaults[$elementName][$val['value']] = 1; + } + else { + $defaults[$elementName][$val['value']] = $val['value']; + } + } + } + } + } + break; + + case 'Select Date': + if (isset($value)) { + if (empty($field['time_format'])) { + list($defaults[$elementName]) = CRM_Utils_Date::setDateDefaults($value, NULL, + $field['date_format'] + ); + } + else { + $timeElement = $elementName . '_time'; + if (substr($elementName, -1) == ']') { + $timeElement = substr($elementName, 0, -1) . '_time]'; + } + list($defaults[$elementName], $defaults[$timeElement]) = CRM_Utils_Date::setDateDefaults($value, NULL, $field['date_format'], $field['time_format']); + } + } + break; + + case 'Multi-Select Country': + case 'Multi-Select State/Province': + if (isset($value)) { + $checkedValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + foreach ($checkedValue as $val) { + if ($val) { + $defaults[$elementName][$val] = $val; + } + } + } + break; + + case 'Select Country': + if ($value) { + $defaults[$elementName] = $value; + } + else { + $config = CRM_Core_Config::singleton(); + $defaults[$elementName] = $config->defaultContactCountry; + } + break; + + case 'Autocomplete-Select': + $hiddenEleName = $elementName . '_id'; + if (substr($elementName, -1) == ']') { + $hiddenEleName = substr($elementName, 0, -1) . '_id]'; + } + if ($field['data_type'] == "ContactReference") { + if (is_numeric($value)) { + $defaults[$hiddenEleName] = $value; + $defaults[$elementName] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name'); + } + } + else { + $label = CRM_Core_BAO_CustomOption::getOptionLabel($field['id'], $value); + $defaults[$hiddenEleName] = $value; + $defaults[$elementName] = $label; + } + break; + + default: + if ($field['data_type'] == "Float") { + $defaults[$elementName] = (float)$value; + } + elseif ($field['data_type'] == 'Money' && + $field['html_type'] == 'Text' + ) { + $defaults[$elementName] = CRM_Utils_Money::format($value, NULL, '%a'); + } + else { + $defaults[$elementName] = $value; + } + } + } + } + } + + static function postProcess(&$groupTree, &$params, $skipFile = FALSE) { + // Get the Custom form values and groupTree + // first reset all checkbox and radio data + foreach ($groupTree as $groupID => $group) { + if ($groupID === 'info') { + continue; + } + foreach ($group['fields'] as $field) { + $fieldId = $field['id']; + + //added Multi-Select option in the below if-statement + if ($field['html_type'] == 'CheckBox' || $field['html_type'] == 'Radio' || + $field['html_type'] == 'AdvMulti-Select' || $field['html_type'] == 'Multi-Select' + ) { + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = 'NULL'; + } + + $v = NULL; + foreach ($params as $key => $val) { + if (preg_match('/^custom_(\d+)_?(-?\d+)?$/', $key, $match) && + $match[1] == $field['id'] + ) { + $v = $val; + } + } + + + if (!isset($groupTree[$groupID]['fields'][$fieldId]['customValue'])) { + // field exists in db so populate value from "form". + $groupTree[$groupID]['fields'][$fieldId]['customValue'] = array(); + } + + switch ($groupTree[$groupID]['fields'][$fieldId]['html_type']) { + + //added for CheckBox + + case 'CheckBox': + if (!empty($v)) { + $customValue = array_keys($v); + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $customValue) . CRM_Core_DAO::VALUE_SEPARATOR; + } + else { + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = NULL; + } + break; + + //added for Advanced Multi-Select + + case 'AdvMulti-Select': + //added for Multi-Select + case 'Multi-Select': + if (!empty($v)) { + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $v) . CRM_Core_DAO::VALUE_SEPARATOR; + } + else { + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = NULL; + } + break; + + case 'Select Date': + $date = CRM_Utils_Date::processDate($v); + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = $date; + break; + + case 'File': + if ($skipFile) { + continue; + } + + //store the file in d/b + $entityId = explode('=', $groupTree['info']['where'][0]); + $fileParams = array('upload_date' => date('Ymdhis')); + + if ($groupTree[$groupID]['fields'][$fieldId]['customValue']['fid']) { + $fileParams['id'] = $groupTree[$groupID]['fields'][$fieldId]['customValue']['fid']; + } + if (!empty($v)) { + $fileParams['uri'] = $v['name']; + $fileParams['mime_type'] = $v['type']; + CRM_Core_BAO_File::filePostProcess($v['name'], + $groupTree[$groupID]['fields'][$fieldId]['customValue']['fid'], + $groupTree[$groupID]['table_name'], + trim($entityId[1]), + FALSE, + TRUE, + $fileParams, + 'custom_' . $fieldId, + $v['type'] + ); + } + $defaults = array(); + $paramsFile = array( + 'entity_table' => $groupTree[$groupID]['table_name'], + 'entity_id' => $entityId[1], + ); + + CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_EntityFile', + $paramsFile, + $defaults + ); + + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = $defaults['file_id']; + break; + + default: + $groupTree[$groupID]['fields'][$fieldId]['customValue']['data'] = $v; + break; + } + } + } + } + + /** + * generic function to build all the form elements for a specific group tree + * + * @param CRM_Core_Form $form the form object + * @param array $groupTree the group tree object + * @param string $showName + * @param string $hideName + * + * @return void + * @access public + * @static + */ + static function buildQuickForm(&$form, + &$groupTree, + $inactiveNeeded = FALSE, + $groupCount = 1, + $prefix = '' + ) { + + $form->assign_by_ref("{$prefix}groupTree", $groupTree); + $sBlocks = array(); + $hBlocks = array(); + + // this is fix for date field + $form->assign('currentYear', date('Y')); + + foreach ($groupTree as $id => $group) { + + CRM_Core_ShowHideBlocks::links($form, $group['title'], '', ''); + + $groupId = CRM_Utils_Array::value('id', $group); + foreach ($group['fields'] as $field) { + $required = CRM_Utils_Array::value('is_required', $field); + //fix for CRM-1620 + if ($field['data_type'] == 'File') { + if (isset($field['customValue']['data'])) { + $required = 0; + } + } + + $fieldId = $field['id']; + $elementName = $field['element_name']; + CRM_Core_BAO_CustomField::addQuickFormElement($form, $elementName, $fieldId, $inactiveNeeded, $required); + } + } + } + + /** + * Function to extract the get params from the url, validate + * and store it in session + * + * @param CRM_Core_Form $form the form object + * @param string $type the type of custom group we are using + * + * @return void + * @access public + * @static + */ + static function extractGetParams(&$form, $type) { + // if not GET params return + if (empty($_GET)) { + return; + } + + $groupTree = CRM_Core_BAO_CustomGroup::getTree($type, $form); + $customValue = array(); + $htmlType = array('CheckBox', 'Multi-Select', 'AdvMulti-Select', 'Select', 'Radio'); + + foreach ($groupTree as $group) { + if (!isset($group['fields'])) { + continue; + } + foreach ($group['fields'] as $key => $field) { + $fieldName = 'custom_' . $key; + $value = CRM_Utils_Request::retrieve($fieldName, 'String', $form); + + if ($value) { + $valid = FALSE; + if (!in_array($field['html_type'], $htmlType) || + $field['data_type'] == 'Boolean' + ) { + $valid = CRM_Core_BAO_CustomValue::typecheck($field['data_type'], $value); + } + if ($field['html_type'] == 'CheckBox' || + $field['html_type'] == 'AdvMulti-Select' || + $field['html_type'] == 'Multi-Select' + ) { + $value = str_replace("|", ",", $value); + $mulValues = explode(',', $value); + $customOption = CRM_Core_BAO_CustomOption::getCustomOption($key, TRUE); + $val = array(); + foreach ($mulValues as $v1) { + foreach ($customOption as $coID => $coValue) { + if (strtolower(trim($coValue['label'])) == strtolower(trim($v1))) { + $val[$coValue['value']] = 1; + } + } + } + if (!empty($val)) { + $value = $val; + $valid = TRUE; + } + else { + $value = NULL; + } + } + elseif ($field['html_type'] == 'Select' || + ($field['html_type'] == 'Radio' && + $field['data_type'] != 'Boolean' + ) + ) { + $customOption = CRM_Core_BAO_CustomOption::getCustomOption($key, TRUE); + foreach ($customOption as $customID => $coValue) { + if (strtolower(trim($coValue['label'])) == strtolower(trim($value))) { + $value = $coValue['value']; + $valid = TRUE; + } + } + } + elseif ($field['data_type'] == 'Date') { + if (!empty($value)) { + $time = NULL; + if (CRM_Utils_Array::value('time_format', $field)) { + $time = CRM_Utils_Request::retrieve($fieldName . '_time', 'String', $form); + } + list($value, $time) = CRM_Utils_Date::setDateDefaults($value . ' ' . $time); + if (CRM_Utils_Array::value('time_format', $field)) { + $customValue[$fieldName . '_time'] = $time; + } + } + $valid = TRUE; + } + + if ($valid) { + $customValue[$fieldName] = $value; + } + } + } + } + + return $customValue; + } + + /** + * Function to check the type of custom field type (eg: Used for Individual, Contribution, etc) + * this function is used to get the custom fields of a type (eg: Used for Individual, Contribution, etc ) + * + * @param int $customFieldId custom field id + * @param array $removeCustomFieldTypes remove custom fields of a type eg: array("Individual") ; + * + * + * @return boolean false if it matches else true + * @static + * @access public + */ + static function checkCustomField($customFieldId, &$removeCustomFieldTypes) { + $query = "SELECT cg.extends as extends + FROM civicrm_custom_group as cg, civicrm_custom_field as cf + WHERE cg.id = cf.custom_group_id + AND cf.id =" . CRM_Utils_Type::escape($customFieldId, 'Integer'); + + $extends = CRM_Core_DAO::singleValueQuery($query); + + if (in_array($extends, $removeCustomFieldTypes)) { + return FALSE; + } + return TRUE; + } + + static function mapTableName($table) { + switch ($table) { + case 'Contact': + case 'Individual': + case 'Household': + case 'Organization': + return 'civicrm_contact'; + + case 'Activity': + return 'civicrm_activity'; + + case 'Group': + return 'civicrm_group'; + + case 'Contribution': + return 'civicrm_contribution'; + + case 'Relationship': + return 'civicrm_relationship'; + + case 'Event': + return 'civicrm_event'; + + case 'Membership': + return 'civicrm_membership'; + + case 'Participant': + case 'ParticipantRole': + case 'ParticipantEventName': + case 'ParticipantEventType': + return 'civicrm_participant'; + + case 'Grant': + return 'civicrm_grant'; + + case 'Pledge': + return 'civicrm_pledge'; + + case 'Address': + return 'civicrm_address'; + + case 'Campaign': + return 'civicrm_campaign'; + + default: + $query = " +SELECT IF( EXISTS(SELECT name FROM civicrm_contact_type WHERE name like %1), 1, 0 )"; + $qParams = array(1 => array($table, 'String')); + $result = CRM_Core_DAO::singleValueQuery($query, $qParams); + + if ($result) { + return 'civicrm_contact'; + } + else { + $extendObjs = CRM_Core_OptionGroup::values('cg_extend_objects', FALSE, FALSE, FALSE, NULL, 'name'); + if (array_key_exists($table, $extendObjs)) { + return $extendObjs[$table]; + } + CRM_Core_Error::fatal(); + } + } + } + + static function createTable($group) { + $params = array( + 'name' => $group->table_name, + 'is_multiple' => $group->is_multiple ? 1 : 0, + 'extends_name' => self::mapTableName($group->extends), + ); + + $tableParams = CRM_Core_BAO_CustomField::defaultCustomTableSchema($params); + + CRM_Core_BAO_SchemaHandler::createTable($tableParams); + } + + /** + * Function returns formatted groupTree, sothat form can be easily build in template + * + * @param array $groupTree associated array + * @param int $groupCount group count by default 1, but can varry for multiple value custom data + * @param object form object + * + * @return array $formattedGroupTree + */ + static function formatGroupTree(&$groupTree, $groupCount = 1, &$form) { + $formattedGroupTree = array(); + $uploadNames = array(); + + foreach ($groupTree as $key => $value) { + if ($key === 'info') { + continue; + } + + // add group information + $formattedGroupTree[$key]['name'] = CRM_Utils_Array::value('name', $value); + $formattedGroupTree[$key]['title'] = CRM_Utils_Array::value('title', $value); + $formattedGroupTree[$key]['help_pre'] = CRM_Utils_Array::value('help_pre', $value); + $formattedGroupTree[$key]['help_post'] = CRM_Utils_Array::value('help_post', $value); + $formattedGroupTree[$key]['collapse_display'] = CRM_Utils_Array::value('collapse_display', $value); + $formattedGroupTree[$key]['collapse_adv_display'] = CRM_Utils_Array::value('collapse_adv_display', $value); + + // this params needed of bulding multiple values + $formattedGroupTree[$key]['is_multiple'] = CRM_Utils_Array::value('is_multiple', $value); + $formattedGroupTree[$key]['extends'] = CRM_Utils_Array::value('extends', $value); + $formattedGroupTree[$key]['extends_entity_column_id'] = CRM_Utils_Array::value('extends_entity_column_id', $value); + $formattedGroupTree[$key]['extends_entity_column_value'] = CRM_Utils_Array::value('extends_entity_column_value', $value); + $formattedGroupTree[$key]['subtype'] = CRM_Utils_Array::value('subtype', $value); + $formattedGroupTree[$key]['max_multiple'] = CRM_Utils_Array::value('max_multiple', $value); + + // add field information + foreach ($value['fields'] as $k => $properties) { + $properties['element_name'] = "custom_{$k}_-{$groupCount}"; + if (isset($properties['customValue']) && !CRM_Utils_system::isNull($properties['customValue'])) { + if (isset($properties['customValue'][$groupCount])) { + $properties['element_name'] = "custom_{$k}_{$properties['customValue'][$groupCount]['id']}"; + $formattedGroupTree[$key]['table_id'] = $properties['customValue'][$groupCount]['id']; + if ($properties['data_type'] == 'File') { + $properties['element_value'] = $properties['customValue'][$groupCount]; + $uploadNames[] = $properties['element_name']; + } + else { + $properties['element_value'] = $properties['customValue'][$groupCount]['data']; + } + } + } + unset($properties['customValue']); + $formattedGroupTree[$key]['fields'][$k] = $properties; + } + } + + if ($form) { + // hack for field type File + $formUploadNames = $form->get('uploadNames'); + if (is_array($formUploadNames)) { + $uploadNames = array_unique(array_merge($formUploadNames, $uploadNames)); + } + + $form->set('uploadNames', $uploadNames); + } + + return $formattedGroupTree; + } + + /** + * Build custom data view + * @param object $form page object + * @param array $groupTree associated array + * @param boolean $returnCount true if customValue count needs to be returned + */ + static function buildCustomDataView(&$form, &$groupTree, $returnCount = FALSE, $gID = NULL, $prefix = NULL) { + foreach ($groupTree as $key => $group) { + if ($key === 'info') { + continue; + } + + foreach ($group['fields'] as $k => $properties) { + $groupID = $group['id']; + if (!empty($properties['customValue'])) { + foreach ($properties['customValue'] as $values) { + $details[$groupID][$values['id']]['title'] = CRM_Utils_Array::value('title', $group); + $details[$groupID][$values['id']]['name'] = CRM_Utils_Array::value('name', $group); + $details[$groupID][$values['id']]['help_pre'] = CRM_Utils_Array::value('help_pre', $group); + $details[$groupID][$values['id']]['help_post'] = CRM_Utils_Array::value('help_post', $group); + $details[$groupID][$values['id']]['collapse_display'] = CRM_Utils_Array::value('collapse_display', $group); + $details[$groupID][$values['id']]['collapse_adv_display'] = CRM_Utils_Array::value('collapse_adv_display', $group); + $details[$groupID][$values['id']]['fields'][$k] = array('field_title' => CRM_Utils_Array::value('label', $properties), + 'field_type' => CRM_Utils_Array::value('html_type', + $properties + ), + 'field_data_type' => CRM_Utils_Array::value('data_type', + $properties + ), + 'field_value' => self::formatCustomValues($values, + $properties + ), + 'options_per_line' => CRM_Utils_Array::value('options_per_line', + $properties + ), + ); + // also return contact reference contact id if user has view all or edit all contacts perm + if ((CRM_Core_Permission::check('view all contacts') || CRM_Core_Permission::check('edit all contacts')) + && $details[$groupID][$values['id']]['fields'][$k]['field_data_type'] == 'ContactReference' + ) { + $details[$groupID][$values['id']]['fields'][$k]['contact_ref_id'] = CRM_Utils_Array::value('data', $values); + } + } + } + else { + $details[$groupID][0]['title'] = CRM_Utils_Array::value('title', $group); + $details[$groupID][0]['name'] = CRM_Utils_Array::value('name', $group); + $details[$groupID][0]['help_pre'] = CRM_Utils_Array::value('help_pre', $group); + $details[$groupID][0]['help_post'] = CRM_Utils_Array::value('help_post', $group); + $details[$groupID][0]['collapse_display'] = CRM_Utils_Array::value('collapse_display', $group); + $details[$groupID][0]['collapse_adv_display'] = CRM_Utils_Array::value('collapse_adv_display', $group); + $details[$groupID][0]['fields'][$k] = array('field_title' => CRM_Utils_Array::value('label', $properties)); + } + } + } + + if ($returnCount) { + //return a single value count if group id is passed to function + //else return a groupId and count mapped array + if (!empty($gID)){ + return count($details[$gID]); + } + else { + foreach( $details as $key => $value ) { + $countValue[$key] = count($details[$key]); + } + return $countValue; + } + } + else { + $form->assign_by_ref("{$prefix}viewCustomData", $details); + return $details; + } + } + + /** + * Format custom value according to data, view mode + * + * @param array $values associated array of custom values + * @param array $field associated array + * @param boolean $dncOptionPerLine true if optionPerLine should not be consider + * + */ + static function formatCustomValues(&$values, &$field, $dncOptionPerLine = FALSE) { + $value = $values['data']; + + //changed isset CRM-4601 + if (CRM_Utils_System::isNull($value)) { + return; + } + + $htmlType = CRM_Utils_Array::value('html_type', $field); + $dataType = CRM_Utils_Array::value('data_type', $field); + $option_group_id = CRM_Utils_Array::value('option_group_id', $field); + $timeFormat = CRM_Utils_Array::value('time_format', $field); + $optionPerLine = CRM_Utils_Array::value('options_per_line', $field); + + $freezeString = ""; + $freezeStringChecked = ""; + + switch ($dataType) { + case 'Date': + $customTimeFormat = ''; + $customFormat = NULL; + + switch ($timeFormat) { + case 1: + $customTimeFormat = '%l:%M %P'; + break; + + case 2: + $customTimeFormat = '%H:%M'; + break; + + default: + // if time is not selected remove time from value + $value = substr($value, 0, 10); + } + + $supportableFormats = array( + 'mm/dd' => "%B %E%f $customTimeFormat", + 'dd-mm' => "%E%f %B $customTimeFormat", + 'yy' => "%Y $customTimeFormat", + 'M yy' => "%b %Y $customTimeFormat", + 'yy-mm' => "%Y-%m $customTimeFormat" + ); + + if ($format = CRM_Utils_Array::value('date_format', $field)) { + if (array_key_exists($format, $supportableFormats)) { + $customFormat = $supportableFormats["$format"]; + } + } + + $retValue = CRM_Utils_Date::customFormat($value, $customFormat); + break; + + case 'Boolean': + if ($value == '1') { + $retValue = $freezeStringChecked . ts('Yes') . "\n"; + } + else { + $retValue = $freezeStringChecked . ts('No') . "\n"; + } + break; + + case 'Link': + if ($value) { + $retValue = CRM_Utils_System::formatWikiURL($value); + } + break; + + case 'File': + $retValue = $values; + break; + + case 'ContactReference': + if (CRM_Utils_Array::value('data', $values)) { + $retValue = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $values['data'], 'display_name'); + } + break; + + case 'Memo': + $retValue = $value; + break; + + case 'Float': + if ($htmlType == 'Text') { + $retValue = (float)$value; + break; + } + case 'Money': + if ($htmlType == 'Text') { + $retValue = CRM_Utils_Money::format($value, NULL, '%a'); + break; + } + case 'String': + case 'Int': + if (in_array($htmlType, array('Text', 'TextArea'))) { + $retValue = $value; + break; + } + // note that if its not text / textarea, the code falls thru and executes + // the below case also + case 'StateProvince': + case 'Country': + $options = array(); + $coDAO = NULL; + + //added check for Multi-Select in the below if-statement + $customData[] = $value; + + //form custom data for multiple-valued custom data + switch ($htmlType) { + case 'Multi-Select Country': + case 'Select Country': + $customData = $value; + if (!is_array($value)) { + $customData = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + } + $query = " + SELECT id as value, name as label + FROM civicrm_country"; + $coDAO = CRM_Core_DAO::executeQuery($query); + break; + + case 'Select State/Province': + case 'Multi-Select State/Province': + $customData = $value; + if (!is_array($value)) { + $customData = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + } + + $query = " + SELECT id as value, name as label + FROM civicrm_state_province"; + $coDAO = CRM_Core_DAO::executeQuery($query); + break; + + case 'Select': + $customData = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + if ($option_group_id) { + $options = CRM_Core_BAO_OptionValue::getOptionValuesAssocArray($option_group_id); + } + break; + + case 'CheckBox': + case 'AdvMulti-Select': + case 'Multi-Select': + $customData = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); + default: + if ($option_group_id) { + $options = CRM_Core_BAO_OptionValue::getOptionValuesAssocArray($option_group_id); + } + } + + if (is_object($coDAO)) { + while ($coDAO->fetch()) { + $options[$coDAO->value] = $coDAO->label; + } + } + + CRM_Utils_Hook::customFieldOptions($field['id'], $options, FALSE); + + $retValue = NULL; + foreach ($options as $optionValue => $optionLabel) { + if ($dataType == 'Money') { + foreach ($customData as $k => $v) { + $customData[] = CRM_Utils_Money::format($v, NULL, '%a'); + } + } + + //to show only values that are checked + if (in_array((string) $optionValue, $customData)) { + $checked = in_array($optionValue, $customData) ? $freezeStringChecked : $freezeString; + if (!$optionPerLine || $dncOptionPerLine) { + if ($retValue) { + $retValue .= ", "; + } + $retValue .= $checked . $optionLabel; + } + else { + $retValue[] = $checked . $optionLabel; + } + } + } + break; + } + + //special case for option per line formatting + if ($optionPerLine > 1 && is_array($retValue)) { + $rowCounter = 0; + $fieldCounter = 0; + $displayValues = array(); + $displayString = ''; + foreach ($retValue as $val) { + if ($displayString) { + $displayString .= ", "; + } + + $displayString .= $val; + $rowCounter++; + $fieldCounter++; + + if (($rowCounter == $optionPerLine) || ($fieldCounter == count($retValue))) { + $displayValues[] = $displayString; + $displayString = ''; + $rowCounter = 0; + } + } + $retValue = $displayValues; + } + + $retValue = isset($retValue) ? $retValue : NULL; + return $retValue; + } + + /** + * Get the custom group titles by custom field ids. + * + * @param array $fieldIds - array of custom field ids. + * + * @return array $groupLabels - array consisting of groups and fields labels with ids. + * @access public + */ + public static function getGroupTitles($fieldIds) { + if (!is_array($fieldIds) && empty($fieldIds)) { + return; + } + + $groupLabels = array(); + $fIds = "(" . implode(',', $fieldIds) . ")"; + + $query = " +SELECT civicrm_custom_group.id as groupID, civicrm_custom_group.title as groupTitle, + civicrm_custom_field.label as fieldLabel, civicrm_custom_field.id as fieldID + FROM civicrm_custom_group, civicrm_custom_field + WHERE civicrm_custom_group.id = civicrm_custom_field.custom_group_id + AND civicrm_custom_field.id IN {$fIds}"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $groupLabels[$dao->fieldID] = array( + 'fieldID' => $dao->fieldID, + 'fieldLabel' => $dao->fieldLabel, + 'groupID' => $dao->groupID, + 'groupTitle' => $dao->groupTitle, + ); + } + + return $groupLabels; + } + + static function dropAllTables() { + $query = "SELECT table_name FROM civicrm_custom_group"; + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $query = "DROP TABLE IF EXISTS {$dao->table_name}"; + CRM_Core_DAO::executeQuery($query); + } + } + + /** + * Check whether custom group is empty or not. + * + * @param int $gID - custom group id. + * + * @return boolean true if empty otherwise false. + * @access public + */ + static function isGroupEmpty($gID) { + if (!$gID) { + return; + } + + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', + $gID, + 'table_name' + ); + + $query = "SELECT count(id) FROM {$tableName} WHERE id IS NOT NULL LIMIT 1"; + $value = CRM_Core_DAO::singleValueQuery($query); + + if (empty($value)) { + return TRUE; + } + + return FALSE; + } + + /** + * Get the list of types for objects that a custom group extends to. + * + * @param array $types - var which should have the list appended. + * + * @return array of types. + * @access public + */ + static function getExtendedObjectTypes(&$types = array( )) { + static $flag = FALSE, $objTypes = array(); + + if (!$flag) { + $extendObjs = array(); + CRM_Core_OptionValue::getValues(array('name' => 'cg_extend_objects'), $extendObjs); + + foreach ($extendObjs as $ovId => $ovValues) { + if ($ovValues['description']) { + // description is expected to be a callback func to subtypes + list($callback, $args) = explode(';', trim($ovValues['description'])); + + if (!empty($args)) { + eval('$args = ' . $args . ';'); + } + else { + $args = array(); + } + + if (!is_array($args)) { + CRM_Core_Error::fatal('Arg is not of type array'); + } + + list($className) = explode('::', $callback); + require_once (str_replace('_',DIRECTORY_SEPARATOR, $className) . '.php'); + + $objTypes[$ovValues['value']] = call_user_func_array($callback, $args); + } + } + $flag = TRUE; + } + + $types = array_merge($types, $objTypes); + return $objTypes; + } + + function hasReachedMaxLimit($customGroupId, $entityId) { + //check whether the group is multiple + $isMultiple = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'is_multiple'); + $isMultiple = ($isMultiple) ? TRUE : FALSE; + $hasReachedMax = FALSE; + if ($isMultiple && + ($maxMultiple = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'max_multiple'))) { + if (!$maxMultiple) { + $hasReachedMax = FALSE; + } else { + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'table_name'); + //count the number of entries for a entity + $sql = "SELECT COUNT(id) FROM {$tableName} WHERE entity_id = %1"; + $params = array(1 => array($entityId, 'Integer')); + $count = CRM_Core_DAO::singleValueQuery($sql, $params); + + if ($count >= $maxMultiple) { + $hasReachedMax = TRUE; + } + } + } + return $hasReachedMax; + } + + } + diff --git a/CRM/Core/BAO/CustomOption.php b/CRM/Core/BAO/CustomOption.php new file mode 100644 index 0000000000..d15fc98ed2 --- /dev/null +++ b/CRM/Core/BAO/CustomOption.php @@ -0,0 +1,295 @@ +copyValues($params); + if ($customOption->find(TRUE)) { + CRM_Core_DAO::storeValues($customOption, $defaults); + return $customOption; + } + return NULL; + } + + /** + * Returns all active options ordered by weight for a given field + * + * @param int $fieldId field whose options are needed + * @param boolean $inactiveNeeded do we need inactive options ? + * + * @return array $customOption all active options for fieldId + * @static + */ + static function getCustomOption( + $fieldID, + $inactiveNeeded = FALSE + ) { + $options = array(); + if (!$fieldID) { + return $options; + } + + $field = CRM_Core_BAO_CustomField::getFieldObject($fieldID); + + // get the option group id + $optionGroupID = $field->option_group_id; + if (!$optionGroupID) { + return $options; + } + + $optionValues = CRM_Core_BAO_OptionValue::getOptionValuesArray($optionGroupID); + + foreach ($optionValues as $id => $value) { + if (!$inactiveNeeded && !CRM_Utils_Array::value('is_active', $value)) { + continue; + } + + $options[$id] = array(); + $options[$id]['id'] = $id; + $options[$id]['label'] = $value['label']; + $options[$id]['value'] = $value['value']; + } + + CRM_Utils_Hook::customFieldOptions($fieldID, $options, TRUE); + + return $options; + } + + /** + * Returns the option label for a custom field with a specific value. Handles all + * custom field data and html types + * + * @param $fieldId int the custom field ID + * @pram $value string the value (typically from the DB) of this custom field + * @param $htmlType string the html type of the field (optional) + * @param $dataType string the data type of the field (optional) + * + * @return string the label to display for this custom field + * @static + * @access public + */ + static function getOptionLabel($fieldId, $value, $htmlType = NULL, $dataType = NULL) { + if (!$fieldId) { + return NULL; + } + + if (!$htmlType || !$dataType) { + $sql = " +SELECT html_type, data_type +FROM civicrm_custom_field +WHERE id = %1 +"; + $params = array(1 => array($fieldId, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + if ($dao->fetch()) { + $htmlType = $dao->html_type; + $dataType = $dao->data_type; + } + else { + CRM_Core_Error::fatal(); + } + } + + $options = NULL; + switch ($htmlType) { + case 'CheckBox': + case 'Multi-Select': + case 'AdvMulti-Select': + case 'Select': + case 'Radio': + case 'Autocomplete-Select': + if (!in_array($dataType, array( + 'Boolean', 'ContactReference'))) { + $options = self::valuesByID($fieldId); + } + } + + return CRM_Core_BAO_CustomField::getDisplayValueCommon($value, + $options, + $htmlType, + $dataType + ); + } + + /** + * Function to delete Option + * + * param $optionId integer option id + * + * @static + * @access public + */ + static function del($optionId) { + // get the customFieldID + $query = " +SELECT f.id as id, f.data_type as dataType +FROM civicrm_option_value v, + civicrm_option_group g, + civicrm_custom_field f +WHERE v.id = %1 +AND g.id = f.option_group_id +AND g.id = v.option_group_id"; + $params = array(1 => array($optionId, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + if ($dao->fetch()) { + if (in_array($dao->dataType, + array('Int', 'Float', 'Money', 'Boolean') + )) { + $value = 0; + } + else { + $value = ''; + } + $params = array( + 'optionId' => $optionId, + 'fieldId' => $dao->id, + 'value' => $value, + ); + // delete this value from the tables + self::updateCustomValues($params); + + // also delete this option value + $query = " +DELETE +FROM civicrm_option_value +WHERE id = %1"; + $params = array(1 => array($optionId, 'Integer')); + CRM_Core_DAO::executeQuery($query, $params); + } + } + + static function updateCustomValues($params) { + $optionDAO = new CRM_Core_DAO_OptionValue(); + $optionDAO->id = $params['optionId']; + $optionDAO->find(TRUE); + $oldValue = $optionDAO->value; + + // get the table, column, html_type and data type for this field + $query = " +SELECT g.table_name as tableName , + f.column_name as columnName, + f.data_type as dataType, + f.html_type as htmlType +FROM civicrm_custom_group g, + civicrm_custom_field f +WHERE f.custom_group_id = g.id + AND f.id = %1"; + $queryParams = array(1 => array($params['fieldId'], 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $queryParams); + if ($dao->fetch()) { + if ($dao->dataType == 'Money') { + $params['value'] = CRM_Utils_Rule::cleanMoney($params['value']); + } + switch ($dao->htmlType) { + case 'Autocomplete-Select': + case 'Select': + case 'Radio': + $query = " +UPDATE {$dao->tableName} +SET {$dao->columnName} = %1 +WHERE id = %2"; + if ($dao->dataType == 'Auto-complete') { + $dataType = "String"; + } + else { + $dataType = $dao->dataType; + } + $queryParams = array( + 1 => array($params['value'], + $dataType, + ), + 2 => array( + $params['optionId'], + 'Integer', + ), + ); + break; + + case 'AdvMulti-Select': + case 'Multi-Select': + case 'CheckBox': + $oldString = CRM_Core_DAO::VALUE_SEPARATOR . $oldValue . CRM_Core_DAO::VALUE_SEPARATOR; + $newString = CRM_Core_DAO::VALUE_SEPARATOR . $params['value'] . CRM_Core_DAO::VALUE_SEPARATOR; + $query = " +UPDATE {$dao->tableName} +SET {$dao->columnName} = REPLACE( {$dao->columnName}, %1, %2 )"; + $queryParams = array(1 => array($oldString, 'String'), + 2 => array($newString, 'String'), + ); + break; + + default: + CRM_Core_Error::fatal(); + } + $dao = CRM_Core_DAO::executeQuery($query, $queryParams); + } + } + + static function &valuesByID($customFieldID, $optionGroupID = NULL) { + if (!$optionGroupID) { + $optionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', + $customFieldID, + 'option_group_id' + ); + } + + $options = CRM_Core_OptionGroup::valuesByID($optionGroupID); + + CRM_Utils_Hook::customFieldOptions($customFieldID, $options, FALSE); + + return $options; + } +} + diff --git a/CRM/Core/BAO/CustomQuery.php b/CRM/Core/BAO/CustomQuery.php new file mode 100644 index 0000000000..f1fb79b5c6 --- /dev/null +++ b/CRM/Core/BAO/CustomQuery.php @@ -0,0 +1,659 @@ + 'civicrm_contact', + 'Individual' => 'civicrm_contact', + 'Household' => 'civicrm_contact', + 'Organization' => 'civicrm_contact', + 'Contribution' => 'civicrm_contribution', + 'Membership' => 'civicrm_membership', + 'Participant' => 'civicrm_participant', + 'Group' => 'civicrm_group', + 'Relationship' => 'civicrm_relationship', + 'Event' => 'civicrm_event', + 'Case' => 'civicrm_case', + 'Activity' => 'civicrm_activity', + 'Pledge' => 'civicrm_pledge', + 'Grant' => 'civicrm_grant', + 'Address' => 'civicrm_address', + ); + + /** + * class constructor + * + * Takes in a set of custom field ids andsets up the data structures to + * generate a query + * + * @param array $ids the set of custom field ids + * + * @access public + */ function __construct($ids, $contactSearch = FALSE) { + $this->_ids = &$ids; + + $this->_select = array(); + $this->_element = array(); + $this->_tables = array(); + $this->_whereTables = array(); + $this->_where = array(); + $this->_qill = array(); + $this->_options = array(); + + $this->_fields = array(); + $this->_contactSearch = $contactSearch; + + if (empty($this->_ids)) { + return; + } + + // initialize the field array + $tmpArray = array_keys($this->_ids); + $idString = implode(',', $tmpArray); + $query = " +SELECT f.id, f.label, f.data_type, + f.html_type, f.is_search_range, + f.option_group_id, f.custom_group_id, + f.column_name, g.table_name, + f.date_format,f.time_format + FROM civicrm_custom_field f, + civicrm_custom_group g + WHERE f.custom_group_id = g.id + AND g.is_active = 1 + AND f.is_active = 1 + AND f.id IN ( $idString )"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + // get the group dao to figure which class this custom field extends + $extends = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $dao->custom_group_id, 'extends'); + if (array_key_exists($extends, self::$extendsMap)) { + $extendsTable = self::$extendsMap[$extends]; + } + elseif (in_array($extends, CRM_Contact_BAO_ContactType::subTypes())) { + // if $extends is a subtype, refer contact table + $extendsTable = self::$extendsMap['Contact']; + } + $this->_fields[$dao->id] = array( + 'id' => $dao->id, + 'label' => $dao->label, + 'extends' => $extendsTable, + 'data_type' => $dao->data_type, + 'html_type' => $dao->html_type, + 'is_search_range' => $dao->is_search_range, + 'column_name' => $dao->column_name, + 'table_name' => $dao->table_name, + 'option_group_id' => $dao->option_group_id, + ); + + // store it in the options cache to make things easier + // during option lookup + $this->_options[$dao->id] = array(); + $this->_options[$dao->id]['attributes'] = array( + 'label' => $dao->label, + 'data_type' => $dao->data_type, + 'html_type' => $dao->html_type, + ); + + $optionGroupID = NULL; + $htmlTypes = array('CheckBox', 'Radio', 'Select', 'Multi-Select', 'AdvMulti-Select', 'Autocomplete-Select'); + if (in_array($dao->html_type, $htmlTypes) && $dao->data_type != 'ContactReference') { + if ($dao->option_group_id) { + $optionGroupID = $dao->option_group_id; + } + elseif ($dao->data_type != 'Boolean') { + $errorMessage = ts("The custom field %1 is corrupt. Please delete and re-build the field", + array(1 => $dao->label) + ); + CRM_Core_Error::fatal($errorMessage); + } + } + elseif ($dao->html_type == 'Select Date') { + $this->_options[$dao->id]['attributes']['date_format'] = $dao->date_format; + $this->_options[$dao->id]['attributes']['time_format'] = $dao->time_format; + } + + // build the cache for custom values with options (label => value) + if ($optionGroupID != NULL) { + $query = " +SELECT label, value + FROM civicrm_option_value + WHERE option_group_id = $optionGroupID +"; + + $option = CRM_Core_DAO::executeQuery($query); + while ($option->fetch()) { + $dataType = $this->_fields[$dao->id]['data_type']; + if ($dataType == 'Int' || $dataType == 'Float') { + $num = round($option->value, 2); + $this->_options[$dao->id]["$num"] = $option->label; + } + else { + $this->_options[$dao->id][$option->value] = $option->label; + } + } + $options = $this->_options[$dao->id]; + //unset attributes to avoid confussion + unset($options['attributes']); + CRM_Utils_Hook::customFieldOptions($dao->id, $options, FALSE); + } + } + } + + /** + * generate the select clause and the associated tables + * for the from clause + * + * @param NULL + * + * @return void + * @access public + */ + function select() { + if (empty($this->_fields)) { + return; + } + + foreach ($this->_fields as $id => $field) { + $name = $field['table_name']; + $fieldName = 'custom_' . $field['id']; + $this->_select["{$name}_id"] = "{$name}.id as {$name}_id"; + $this->_element["{$name}_id"] = 1; + $this->_select[$fieldName] = "{$field['table_name']}.{$field['column_name']} as $fieldName"; + $this->_element[$fieldName] = 1; + $joinTable = NULL; + if ($field['extends'] == 'civicrm_contact') { + $joinTable = 'contact_a'; + } + elseif ($field['extends'] == 'civicrm_contribution') { + $joinTable = 'civicrm_contribution'; + } + elseif ($field['extends'] == 'civicrm_participant') { + $joinTable = 'civicrm_participant'; + } + elseif ($field['extends'] == 'civicrm_membership') { + $joinTable = 'civicrm_membership'; + } + elseif ($field['extends'] == 'civicrm_pledge') { + $joinTable = 'civicrm_pledge'; + } + elseif ($field['extends'] == 'civicrm_activity') { + $joinTable = 'civicrm_activity'; + } + elseif ($field['extends'] == 'civicrm_relationship') { + $joinTable = 'civicrm_relationship'; + } + elseif ($field['extends'] == 'civicrm_grant') { + $joinTable = 'civicrm_grant'; + } + elseif ($field['extends'] == 'civicrm_address') { + $joinTable = 'civicrm_address'; + } + elseif ($field['extends'] == 'civicrm_case') { + $joinTable = 'civicrm_case'; + } + + if ($joinTable) { + $this->_tables[$name] = "\nLEFT JOIN $name ON $name.entity_id = $joinTable.id"; + if ($this->_ids[$id]) { + $this->_whereTables[$name] = $this->_tables[$name]; + } + if ($joinTable != 'contact_a') { + $this->_whereTables[$joinTable] = $this->_tables[$joinTable] = 1; + } + elseif ($this->_contactSearch) { + CRM_Contact_BAO_Query::$_openedPanes[ts('Custom Fields')] = TRUE; + } + } + } + } + + /** + * generate the where clause and also the english language + * equivalent + * + * @param NULL + * + * @return void + * + * @access public + */ + function where() { + //CRM_Core_Error::debug( 'fld', $this->_fields ); + //CRM_Core_Error::debug( 'ids', $this->_ids ); + + foreach ($this->_ids as $id => $values) { + + // Fixed for Isuue CRM 607 + if (CRM_Utils_Array::value($id, $this->_fields) === NULL || + !$values + ) { + continue; + } + + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + + foreach ($values as $tuple) { + list($name, $op, $value, $grouping, $wildcard) = $tuple; + + // fix $value here to escape sql injection attacks + $field = $this->_fields[$id]; + $qillValue = CRM_Core_BAO_CustomField::getDisplayValue($value, $id, $this->_options); + + if (!is_array($value)) { + $value = CRM_Core_DAO::escapeString(trim($value)); + } + + $fieldName = "{$field['table_name']}.{$field['column_name']}"; + switch ($field['data_type']) { + case 'String': + $sql = "$fieldName"; + // if we are coming in from listings, + // for checkboxes the value is already in the right format and is NOT an array + if (is_array($value)) { + + //ignoring $op value for checkbox and multi select + $sqlValue = array(); + $sqlOP = ' AND '; + $sqlOPlabel = ts('match ALL'); + if ($field['html_type'] == 'CheckBox') { + foreach ($value as $k => $v) { + if ($v) { + if ($k == 'CiviCRM_OP_OR') { + $sqlOP = ' OR '; + $sqlOPlabel = ts('match ANY'); + continue; + } + + $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $k . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; + } + } + //if user check only 'CiviCRM_OP_OR' check box + //of custom checkbox field, then ignore this field. + if (!empty($sqlValue)) { + $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) '; + $this->_qill[$grouping][] = "{$field['label']} $op $qillValue ( $sqlOPlabel )"; + } + // for multi select + } + else { + foreach ($value as $k => $v) { + if ($v == 'CiviCRM_OP_OR') { + $sqlOP = ' OR '; + $sqlOPlabel = ts('match ANY'); + continue; + } + $v = CRM_Core_DAO::escapeString($v); + $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; + } + //if user select only 'CiviCRM_OP_OR' value + //of custom multi select field, then ignore this field. + if (!empty($sqlValue)) { + $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) '; + $this->_qill[$grouping][] = "$field[label] $op $qillValue ( $sqlOPlabel )"; + } + } + } + else { + if ($field['is_search_range'] && is_array($value)) { + $this->searchRange($field['id'], + $field['label'], + $field['data_type'], + $fieldName, + $value, + $grouping + ); + } + else { + if ($field['html_type'] == 'Autocomplete-Select') { + $wildcard = FALSE; + $val = array_search($value, $this->_options[$field['id']]); + } + elseif (in_array($field['html_type'], array( + 'Select', 'Radio'))) { + $wildcard = FALSE; + $val = CRM_Utils_Type::escape($value, 'String'); + } + else { + $val = CRM_Utils_Type::escape($strtolower(trim($value)), 'String'); + } + + if ($wildcard) { + $val = $strtolower(CRM_Core_DAO::escapeString($val)); + $val = "%$val%"; + $op = 'LIKE'; + } + + //FIX for custom data query fired against no value(NULL/NOT NULL) + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($sql, $op, $val, $field['data_type']); + $this->_qill[$grouping][] = "$field[label] $op $qillValue"; + } + } + continue; + + case 'ContactReference': + $label = $value ? CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name') : ''; + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); + $this->_qill[$grouping][] = $field['label'] . " $op $label"; + continue; + + case 'Int': + if ($field['is_search_range'] && is_array($value)) { + $this->searchRange($field['id'], $field['label'], $field['data_type'], $fieldName, $value, $grouping); + } + else { + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer'); + $this->_qill[$grouping][] = $field['label'] . " $op $value"; + } + continue; + + case 'Boolean': + if (strtolower($value) == 'yes' || strtolower($value) == strtolower(ts('Yes'))) { + $value = 1; + } + else { + $value = (int) $value; + } + $value = ($value == 1) ? 1 : 0; + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer'); + $value = $value ? ts('Yes') : ts('No'); + $this->_qill[$grouping][] = $field['label'] . " {$op} {$value}"; + continue; + + case 'Link': + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); + $this->_qill[$grouping][] = $field['label'] . " $op $value"; + continue; + + case 'Float': + if ($field['is_search_range'] && is_array($value)) { + $this->searchRange($field['id'], $field['label'], $field['data_type'], $fieldName, $value, $grouping); + } + else { + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float'); + $this->_qill[$grouping][] = $field['label'] . " {$op} {$value}"; + } + continue; + + case 'Money': + if ($field['is_search_range'] && is_array($value)) { + foreach ($value as $key => $val) { + $moneyFormat = CRM_Utils_Rule::cleanMoney($value[$key]); + $value[$key] = $moneyFormat; + } + $this->searchRange($field['id'], $field['label'], $field['data_type'], $fieldName, $value, $grouping); + } + else { + $moneyFormat = CRM_Utils_Rule::cleanMoney($value); + $value = $moneyFormat; + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float'); + $this->_qill[$grouping][] = $field['label'] . " {$op} {$value}"; + } + continue; + + case 'Memo': + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); + $this->_qill[$grouping][] = "$field[label] $op $value"; + continue; + + case 'Date': + $fromValue = CRM_Utils_Array::value('from', $value); + $toValue = CRM_Utils_Array::value('to', $value); + + if (!$fromValue && !$toValue) { + if (!CRM_Utils_Date::processDate($value) && $op != 'IS NULL' && $op != 'IS NOT NULL') { + continue; + } + + // hack to handle yy format during search + if (is_numeric($value) && strlen($value) == 4) { + $value = "01-01-{$value}"; + } + + $date = CRM_Utils_Date::processDate($value); + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $date, 'String'); + $this->_qill[$grouping][] = $field['label'] . " {$op} " . CRM_Utils_Date::customFormat($date); + } + else { + if (is_numeric($fromValue) && strlen($fromValue) == 4) { + $fromValue = "01-01-{$fromValue}"; + } + + if (is_numeric($toValue) && strlen($toValue) == 4) { + $toValue = "01-01-{$toValue}"; + } + + // TO DO: add / remove time based on date parts + $fromDate = CRM_Utils_Date::processDate($fromValue); + $toDate = CRM_Utils_Date::processDate($toValue); + if (!$fromDate && !$toDate) { + continue; + } + if ($fromDate) { + $this->_where[$grouping][] = "$fieldName >= $fromDate"; + $this->_qill[$grouping][] = $field['label'] . ' >= ' . CRM_Utils_Date::customFormat($fromDate); + } + if ($toDate) { + $this->_where[$grouping][] = "$fieldName <= $toDate"; + $this->_qill[$grouping][] = $field['label'] . ' <= ' . CRM_Utils_Date::customFormat($toDate); + } + } + continue; + + case 'StateProvince': + case 'Country': + if (!is_array($value)) { + $this->_where[$grouping][] = "$fieldName {$op} " . CRM_Utils_Type::escape($value, 'Int'); + $this->_qill[$grouping][] = $field['label'] . " {$op} {$qillValue}"; + } + else { + $sqlOP = ' AND '; + $sqlOPlabel = ts('match ALL'); + foreach ($value as $k => $v) { + if ($v == 'CiviCRM_OP_OR') { + $sqlOP = ' OR '; + $sqlOPlabel = ts('match ANY'); + continue; + } + $sqlValue[] = "( $fieldName like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; + } + + //if user select only 'CiviCRM_OP_OR' value + //of custom multi select field, then ignore this field. + if (!empty($sqlValue)) { + $this->_where[$grouping][] = " ( " . implode($sqlOP, $sqlValue) . " ) "; + $this->_qill[$grouping][] = "$field[label] $op $qillValue ( $sqlOPlabel )"; + } + } + continue; + + case 'File': + if ( $op == 'IS NULL' || $op == 'IS NOT NULL' || $op == 'IS EMPTY' || $op == 'IS NOT EMPTY' ) { + switch ($op) { + case 'IS EMPTY': + $op = 'IS NULL'; + break; + case 'IS NOT EMPTY': + $op = 'IS NOT NULL'; + break; + } + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op); + $this->_qill[$grouping][] = $field['label'] . " {$op} "; + } + continue; + } + } + } + } + + /** + * function that does the actual query generation + * basically ties all the above functions together + * + * @param NULL + * + * @return array array of strings + * @access public + */ + function query() { + $this->select(); + + $this->where(); + + $whereStr = NULL; + if (!empty($this->_where)) { + $clauses = array(); + foreach ($this->_where as $grouping => $values) { + if (!empty($values)) { + $clauses[] = ' ( ' . implode(' AND ', $values) . ' ) '; + } + } + if (!empty($clauses)) { + $whereStr = ' ( ' . implode(' OR ', $clauses) . ' ) '; + } + } + + return array(implode(' , ', $this->_select), + implode(' ', $this->_tables), + $whereStr, + ); + } + + function searchRange(&$id, &$label, $type, $fieldName, &$value, &$grouping) { + $qill = array(); + + if (isset($value['from'])) { + $val = CRM_Utils_Type::escape($value['from'], $type); + + if ($type == 'String') { + $this->_where[$grouping][] = "$fieldName >= '$val'"; + } + else { + $this->_where[$grouping][] = "$fieldName >= $val"; + } + $qill[] = ts('greater than or equal to \'%1\'', array(1 => $value['from'])); + } + + if (isset($value['to'])) { + $val = CRM_Utils_Type::escape($value['to'], $type); + if ($type == 'String') { + $this->_where[$grouping][] = "$fieldName <= '$val'"; + } + else { + $this->_where[$grouping][] = "$fieldName <= $val"; + } + $qill[] = ts('less than or equal to \'%1\'', array(1 => $value['to'])); + } + + if (!empty($qill)) { + $this->_qill[$grouping][] = $label . ' - ' . implode(' ' . ts('and') . ' ', $qill); + } + } +} + diff --git a/CRM/Core/BAO/CustomValue.php b/CRM/Core/BAO/CustomValue.php new file mode 100644 index 0000000000..ba86d72e8b --- /dev/null +++ b/CRM/Core/BAO/CustomValue.php @@ -0,0 +1,219 @@ + $state) { + $valid = array_key_exists(strtolower(trim($state)), + array_change_key_case(array_flip(CRM_Core_PseudoConstant::stateProvinceAbbreviation()), CASE_LOWER) + ) || array_key_exists(strtolower(trim($state)), + array_change_key_case(array_flip(CRM_Core_PseudoConstant::stateProvince()), CASE_LOWER) + ); + if (!$valid) { + break; + } + } + return $valid; + + case 'Country': + + //fix multi select country, CRM-3437 + $valid = FALSE; + $mulValues = explode(',', $value); + foreach ($mulValues as $key => $country) { + $valid = array_key_exists(strtolower(trim($country)), + array_change_key_case(array_flip(CRM_Core_PseudoConstant::countryIsoCode()), CASE_LOWER) + ) || array_key_exists(strtolower(trim($country)), + array_change_key_case(array_flip(CRM_Core_PseudoConstant::country()), CASE_LOWER) + ); + if (!$valid) { + break; + } + } + return $valid; + + case 'Link': + return CRM_Utils_Rule::url($value); + } + return FALSE; + } + + /** + * given a 'civicrm' type string, return the mysql data store area + * + * @param string $type the civicrm type string + * + * @return the mysql data store placeholder + * @access public + * @static + */ + public static function typeToField($type) { + switch ($type) { + case 'String': + case 'File': + return 'char_data'; + + case 'Boolean': + case 'Int': + case 'StateProvince': + case 'Country': + case 'Auto-complete': + return 'int_data'; + + case 'Float': + return 'float_data'; + + case 'Money': + return 'decimal_data'; + + case 'Memo': + return 'memo_data'; + + case 'Date': + return 'date_data'; + + case 'Link': + return 'char_data'; + + default: + return NULL; + } + } + + + public static function fixFieldValueOfTypeMemo(&$formValues) { + if (empty($formValues)) { + return NULL; + } + foreach (array_keys($formValues) as $key) { + if (substr($key, 0, 7) != 'custom_') { + continue; + } + elseif (empty($formValues[$key])) { + continue; + } + + $htmlType = CRM_Core_DAO::getFieldValue('CRM_Core_BAO_CustomField', + substr($key, 7), 'html_type' + ); + if (($htmlType == 'TextArea') && + !((substr($formValues[$key], 0, 1) == '%') || + (substr($formValues[$key], -1, 1) == '%') + ) + ) { + $formValues[$key] = '%' . $formValues[$key] . '%'; + } + + $dataType = CRM_Core_DAO::getFieldValue('CRM_Core_BAO_CustomField', + substr($key, 7), 'data_type' + ); + if (($dataType == 'ContactReference') && ($htmlType == 'Autocomplete-Select')) { + $formValues[$key] = $formValues[$key . '_id']; + } + } + } + + /** + * Function to delet option value give an option value and custom group id + * + * @param int $customValueID custom value ID + * @param int $customGroupID custom group ID + * + * @return void + * @static + */ + static function deleteCustomValue($customValueID, $customGroupID) { + // first we need to find custom value table, from custom group ID + $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupID, 'table_name'); + + // delete custom value from corresponding custom value table + $sql = "DELETE FROM {$tableName} WHERE id = {$customValueID}"; + CRM_Core_DAO::executeQuery($sql); + + CRM_Utils_Hook::custom('delete', + $customGroupID, + NULL, + $customValueID + ); + } +} + diff --git a/CRM/Core/BAO/CustomValueTable.php b/CRM/Core/BAO/CustomValueTable.php new file mode 100644 index 0000000000..861f546903 --- /dev/null +++ b/CRM/Core/BAO/CustomValueTable.php @@ -0,0 +1,670 @@ + $tables) { + foreach ($tables as $index => $fields) { + $sqlOP = NULL; + $hookID = NULL; + $hookOP = NULL; + $entityID = NULL; + $isMultiple = FALSE; + $set = array(); + $params = array(); + $count = 1; + foreach ($fields as $field) { + if (!$sqlOP) { + $entityID = $field['entity_id']; + $hookID = $field['custom_group_id']; + $isMultiple = $field['is_multiple']; + if (array_key_exists('id', $field)) { + $sqlOP = "UPDATE $tableName "; + $where = " WHERE id = %{$count}"; + $params[$count] = array($field['id'], 'Integer'); + $count++; + $hookOP = 'edit'; + } + else { + $sqlOP = "INSERT INTO $tableName "; + $where = NULL; + $hookOP = 'create'; + } + } + + // fix the value before we store it + $value = $field['value']; + $type = $field['type']; + switch ($type) { + case 'StateProvince': + $type = 'Integer'; + if (is_array($value)) { + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $value) . CRM_Core_DAO::VALUE_SEPARATOR; + $type = 'String'; + } + elseif (!is_numeric($value)) { + //fix for multi select state, CRM-3437 + $mulValues = explode(',', $value); + $validStates = array(); + foreach ($mulValues as $key => $stateVal) { + $states = array(); + $states['state_province'] = trim($stateVal); + + CRM_Utils_Array::lookupValue($states, 'state_province', + CRM_Core_PseudoConstant::stateProvince(), TRUE + ); + if (!CRM_Utils_Array::value('state_province_id', $states)) { + CRM_Utils_Array::lookupValue($states, 'state_province', + CRM_Core_PseudoConstant::stateProvinceAbbreviation(), TRUE + ); + } + $validStates[] = $states['state_province_id']; + } + $value = implode(CRM_Core_DAO::VALUE_SEPARATOR, + $validStates + ); + $type = 'String'; + } + elseif (!$value) { + // CRM-3415 + // using type of timestamp allows us to sneak in a null into db + // gross but effective hack + $value = NULL; + $type = 'Timestamp'; + } + break; + + case 'Country': + $type = 'Integer'; + if (is_array($value)) { + $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $value) . CRM_Core_DAO::VALUE_SEPARATOR; + $type = 'String'; + } + elseif (!is_numeric($value)) { + //fix for multi select country, CRM-3437 + $mulValues = explode(',', $value); + $validCountries = array(); + foreach ($mulValues as $key => $countryVal) { + $countries = array(); + $countries['country'] = trim($countryVal); + CRM_Utils_Array::lookupValue($countries, 'country', + CRM_Core_PseudoConstant::country(), TRUE + ); + if (!CRM_Utils_Array::value('country_id', $countries)) { + CRM_Utils_Array::lookupValue($countries, 'country', + CRM_Core_PseudoConstant::countryIsoCode(), TRUE + ); + } + $validCountries[] = $countries['country_id']; + } + $value = implode(CRM_Core_DAO::VALUE_SEPARATOR, + $validCountries + ); + $type = 'String'; + } + elseif (!$value) { + // CRM-3415 + // using type of timestamp allows us to sneak in a null into db + // gross but effective hack + $value = NULL; + $type = 'Timestamp'; + } + break; + + case 'File': + if (!$field['file_id']) { + CRM_Core_Error::fatal(); + } + + // need to add/update civicrm_entity_file + $entityFileDAO = new CRM_Core_DAO_EntityFile(); + $entityFileDAO->file_id = $field['file_id']; + $entityFileDAO->find(TRUE); + + $entityFileDAO->entity_table = $field['table_name']; + $entityFileDAO->entity_id = $field['entity_id']; + $entityFileDAO->file_id = $field['file_id']; + $entityFileDAO->save(); + $entityFileDAO->free(); + $value = $field['file_id']; + $type = 'String'; + break; + + case 'Date': + $value = CRM_Utils_Date::isoToMysql($value); + break; + + case 'Int': + if (is_numeric($value)) { + $type = 'Integer'; + } + else { + $type = 'Timestamp'; + } + break; + + case 'ContactReference': + if ($value == NULL) { + $type = 'Timestamp'; + } + else { + $type = 'Integer'; + } + break; + + case 'RichTextEditor': + $type = 'String'; + break; + + case 'Boolean': + //fix for CRM-3290 + $value = CRM_Utils_String::strtoboolstr($value); + if ($value === FALSE) { + $type = 'Timestamp'; + } + break; + + default: + break; + } + $set[$field['column_name']] = "%{$count}"; + $params[$count] = array($value, $type); + $count++; + } + + if (!empty($set)) { + $setClause = array(); + foreach ($set as $n => $v) { + $setClause[] = "$n = $v"; + } + $setClause = implode(',', $setClause); + if (!$where) { + // do this only for insert + $set['entity_id'] = "%{$count}"; + $params[$count] = array($entityID, 'Integer'); + $count++; + + $fieldNames = implode(',', array_keys($set)); + $fieldValues = implode(',', array_values($set)); + $query = "$sqlOP ( $fieldNames ) VALUES ( $fieldValues )"; + // for multiple values we dont do on duplicate key update + if (!$isMultiple) { + $query .= " ON DUPLICATE KEY UPDATE $setClause"; + } + } + else { + $query = "$sqlOP SET $setClause $where"; + } + $dao = CRM_Core_DAO::executeQuery($query, $params); + + CRM_Utils_Hook::custom($hookOP, + $hookID, + $entityID, + $fields + ); + } + } + } + } + + /** + * given a field return the mysql data type associated with it + * + * @param string $type the civicrm type string + * + * @return the mysql data store placeholder + * @access public + * @static + */ + public static function fieldToSQLType($type, $maxLength = 255) { + if (!isset($maxLength) || + !is_numeric($maxLength) || + $maxLength <= 0 + ) { + $maxLength = 255; + } + + switch ($type) { + case 'String': + case 'Link': + return "varchar($maxLength)"; + + case 'Boolean': + return 'tinyint'; + + case 'Int': + return 'int'; + // the below three are FK's, and have constraints added to them + + case 'ContactReference': + case 'StateProvince': + case 'Country': + case 'File': + return 'int unsigned'; + + case 'Float': + return 'double'; + + case 'Money': + return 'decimal(20,2)'; + + case 'Memo': + case 'RichTextEditor': + return 'text'; + + case 'Date': + return 'datetime'; + + default: + CRM_Core_Error::fatal(); + } + } + + static function store(&$params, $entityTable, $entityID) { + $cvParams = array(); + foreach ($params as $fieldID => $param) { + foreach ($param as $index => $customValue) { + $cvParam = array( + 'entity_table' => $entityTable, + 'entity_id' => $entityID, + 'value' => $customValue['value'], + 'type' => $customValue['type'], + 'custom_field_id' => $customValue['custom_field_id'], + 'custom_group_id' => $customValue['custom_group_id'], + 'table_name' => $customValue['table_name'], + 'column_name' => $customValue['column_name'], + 'is_multiple' => CRM_Utils_Array::value('is_multiple', $customValue), + 'file_id' => $customValue['file_id'], + ); + + // fix Date type to be timestamp, since that is how we store in db + if ($cvParam['type'] == 'Date') { + $cvParam['type'] = 'Timestamp'; + } + + if (CRM_Utils_Array::value('id', $customValue)) { + $cvParam['id'] = $customValue['id']; + } + if (!array_key_exists($customValue['table_name'], $cvParams)) { + $cvParams[$customValue['table_name']] = array(); + } + + if (!array_key_exists($index, $cvParams[$customValue['table_name']])) { + $cvParams[$customValue['table_name']][$index] = array(); + } + + $cvParams[$customValue['table_name']][$index][] = $cvParam; + } + } + if (!empty($cvParams)) { + self::create($cvParams); + } + } + + static function postProcess(&$params, &$customFields, $entityTable, $entityID, $customFieldExtends) { + $customData = CRM_Core_BAO_CustomField::postProcess($params, + $customFields, + $entityID, + $customFieldExtends + ); + + if (!empty($customData)) { + self::store($customData, $entityTable, $entityID); + } + } + + /** + * Return an array of all custom values associated with an entity. + * + * @param int $entityID Identification number of the entity + * @param string $entityType Type of entity that the entityID corresponds to, specified + * as a string with format "''". Comma separated + * list may be used to specify OR matches. Allowable values + * are enumerated types in civicrm_custom_group.extends field. + * Optional. Default value assumes entityID references a + * contact entity. + * @param array $fieldIDs optional list of fieldIDs that we want to retrieve. If this + * is set the entityType is ignored + * + * @return array $fields Array of custom values for the entity with key=>value + * pairs specified as civicrm_custom_field.id => custom value. + * Empty array if no custom values found. + * @access public + * @static + */ + public static function &getEntityValues($entityID, $entityType = NULL, $fieldIDs = NULL, $formatMultiRecordField = FALSE) { + if (!$entityID) { + // adding this here since an empty contact id could have serious repurcussions + // like looping forever + CRM_Core_Error::fatal('Please file an issue with the backtrace'); + return NULL; + } + + $cond = array(); + if ($entityType) { + $cond[] = "cg.extends IN ( '$entityType' )"; + } + if ($fieldIDs && + is_array($fieldIDs) + ) { + $fieldIDList = implode(',', $fieldIDs); + $cond[] = "cf.id IN ( $fieldIDList )"; + } + if (empty($cond)) { + $cond[] = "cg.extends IN ( 'Contact', 'Individual', 'Household', 'Organization' )"; + } + $cond = implode(' AND ', $cond); + + // first find all the fields that extend this type of entity + $query = " +SELECT cg.table_name, + cg.id as groupID, + cg.is_multiple, + cf.column_name, + cf.id as fieldID +FROM civicrm_custom_group cg, + civicrm_custom_field cf +WHERE cf.custom_group_id = cg.id +AND cg.is_active = 1 +AND cf.is_active = 1 +AND $cond +"; + $dao = CRM_Core_DAO::executeQuery($query); + + $select = $fields = $isMultiple = array(); + + while ($dao->fetch()) { + if (!array_key_exists($dao->table_name, $select)) { + $fields[$dao->table_name] = array(); + $select[$dao->table_name] = array(); + } + $fields[$dao->table_name][] = $dao->fieldID; + $select[$dao->table_name][] = "{$dao->column_name} AS custom_{$dao->fieldID}"; + $isMultiple[$dao->table_name] = $dao->is_multiple ? TRUE : FALSE; + } + + $result = array(); + foreach ($select as $tableName => $clauses) { + $query = "SELECT id, " . implode(', ', $clauses) . " FROM $tableName WHERE entity_id = $entityID"; + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + foreach ($fields[$tableName] as $fieldID) { + $fieldName = "custom_{$fieldID}"; + if ($isMultiple[$tableName]) { + if ($formatMultiRecordField) { + $result["{$dao->id}"]["{$fieldID}"] = $dao->$fieldName; + } else { + $result["{$fieldID}_{$dao->id}"] = $dao->$fieldName; + } + } + else { + $result[$fieldID] = $dao->$fieldName; + } + } + } + } + return $result; + } + + /** + * Function to take in an array of entityID, custom_XXX => value + * and set the value in the appropriate table. Should also be able + * to set the value to null. Follows api parameter/return conventions + * + * @array $params + * + * @return array + * @static + */ + static function setValues(&$params) { + + if (!isset($params['entityID']) || + CRM_Utils_Type::escape($params['entityID'], 'Integer', FALSE) === NULL + ) { + return CRM_Core_Error::createAPIError(ts('entityID needs to be set and of type Integer')); + } + + // first collect all the id/value pairs. The format is: + // custom_X => value or custom_X_VALUEID => value (for multiple values), VALUEID == -1, -2 etc for new insertions + $values = array(); + $fieldValues = array(); + foreach ($params as $n => $v) { + if ($customFieldInfo = CRM_Core_BAO_CustomField::getKeyID($n, TRUE)) { + $fieldID = (int ) $customFieldInfo[0]; + if (CRM_Utils_Type::escape($fieldID, 'Integer', FALSE) === NULL) { + return CRM_Core_Error::createAPIError(ts('field ID needs to be of type Integer for index %1', + array(1 => $fieldID) + )); + } + if (!array_key_exists($fieldID, $fieldValues)) { + $fieldValues[$fieldID] = array(); + } + $id = -1; + if ($customFieldInfo[1]) { + $id = (int ) $customFieldInfo[1]; + } + $fieldValues[$fieldID][] = array( + 'value' => $v, + 'id' => $id, + ); + } + } + + $fieldIDList = implode(',', array_keys($fieldValues)); + + // format it so that we can just use create + $sql = " +SELECT cg.table_name as table_name , + cg.id as cg_id , + cg.is_multiple as is_multiple, + cf.column_name as column_name, + cf.id as cf_id , + cf.data_type as data_type +FROM civicrm_custom_group cg, + civicrm_custom_field cf +WHERE cf.custom_group_id = cg.id +AND cf.id IN ( $fieldIDList ) +"; + + $dao = CRM_Core_DAO::executeQuery($sql); + $cvParams = array(); + + while ($dao->fetch()) { + $dataType = $dao->data_type == 'Date' ? 'Timestamp' : $dao->data_type; + foreach ($fieldValues[$dao->cf_id] as $fieldValue) { + // Format null values correctly + if ($fieldValue['value'] === NULL || $fieldValue['value'] === '') { + switch ($dataType) { + case 'String': + case 'Int': + case 'Link': + case 'Boolean': + $fieldValue['value'] = ''; + break; + + case 'Timestamp': + $fieldValue['value'] = NULL; + break; + + case 'StateProvince': + case 'Country': + case 'Money': + case 'Float': + $fieldValue['value'] = (int)0; + break; + } + } + // Ensure that value is of the right data type + elseif (CRM_Utils_Type::escape($fieldValue['value'], $dataType, FALSE) === NULL) { + return CRM_Core_Error::createAPIError(ts('value: %1 is not of the right field data type: %2', + array( + 1 => $fieldValue['value'], + 2 => $dao->data_type + ) + )); + } + + $cvParam = array( + 'entity_id' => $params['entityID'], + 'value' => $fieldValue['value'], + 'type' => $dataType, + 'custom_field_id' => $dao->cf_id, + 'custom_group_id' => $dao->cg_id, + 'table_name' => $dao->table_name, + 'column_name' => $dao->column_name, + 'is_multiple' => $dao->is_multiple, + ); + + if (!array_key_exists($dao->table_name, $cvParams)) { + $cvParams[$dao->table_name] = array(); + } + + if (!array_key_exists($fieldValue['id'], $cvParams[$dao->table_name])) { + $cvParams[$dao->table_name][$fieldValue['id']] = array(); + } + + if ($fieldValue['id'] > 0) { + $cvParam['id'] = $fieldValue['id']; + } + $cvParams[$dao->table_name][$fieldValue['id']][] = $cvParam; + } + } + + if (!empty($cvParams)) { + self::create($cvParams); + return array('is_error' => 0, 'result' => 1); + } + + return CRM_Core_Error::createAPIError(ts('Unknown error')); + } + + /** + * Function to take in an array of entityID, custom_ID + * and gets the value from the appropriate table. + * + * To get the values of custom fields with IDs 13 and 43 for contact ID 1327, use: + * $params = array( 'entityID' => 1327, 'custom_13' => 1, 'custom_43' => 1 ); + * + * Entity Type will be infered by the custom fields you request + * Specify $params['entityType'] if you do not supply any custom fields to return + * and entity type is other than Contact + * + * @array $params + * + * @return array + * @static + */ + static function &getValues(&$params) { + if (empty($params)) { + return NULL; + } + if (!isset($params['entityID']) || + CRM_Utils_Type::escape($params['entityID'], + 'Integer', FALSE + ) === NULL + ) { + return CRM_Core_Error::createAPIError(ts('entityID needs to be set and of type Integer')); + } + + // first collect all the ids. The format is: + // custom_ID + $fieldIDs = array(); + foreach ($params as $n => $v) { + $key = $idx = NULL; + if (substr($n, 0, 7) == 'custom_') { + $idx = substr($n, 7); + if (CRM_Utils_Type::escape($idx, 'Integer', FALSE) === NULL) { + return CRM_Core_Error::createAPIError(ts('field ID needs to be of type Integer for index %1', + array(1 => $idx) + )); + } + $fieldIDs[] = (int ) $idx; + } + } + + $default = array('Contact', 'Individual', 'Household', 'Organization'); + if (!($type = CRM_Utils_Array::value('entityType', $params)) || + in_array($params['entityType'], $default) + ) { + $type = NULL; + } + else { + $entities = CRM_Core_SelectValues::customGroupExtends(); + if (!array_key_exists($type, $entities)) { + if (in_array($type, $entities)) { + $type = $entities[$type]; + if (in_array($type, $default)) { + $type = NULL; + } + } + else { + return CRM_Core_Error::createAPIError(ts('Invalid entity type') . ': "' . $type . '"'); + } + } + } + + $values = self::getEntityValues($params['entityID'], + $type, + $fieldIDs + ); + if (empty($values)) { + // note that this behaviour is undesirable from an API point of view - it should return an empty array + // since this is also called by the merger code & not sure the consequences of changing + // are just handling undoing this in the api layer. ie. converting the error back into a success + $result = array( + 'is_error' => 1, + 'error_message' => 'No values found for the specified entity ID and custom field(s).', + ); + return $result; + } + else { + $result = array( + 'is_error' => 0, + 'entityID' => $params['entityID'], + ); + foreach ($values as $id => $value) { + $result["custom_{$id}"] = $value; + } + return $result; + } + } +} + diff --git a/CRM/Core/BAO/Dashboard.php b/CRM/Core/BAO/Dashboard.php new file mode 100644 index 0000000000..703a067ac9 --- /dev/null +++ b/CRM/Core/BAO/Dashboard.php @@ -0,0 +1,458 @@ +is_active = 1; + } + + $dao->domain_id = CRM_Core_Config::domainID(); + + $dao->find(); + while ($dao->fetch()) { + if (!self::checkPermission($dao->permission, $dao->permission_operator)) { + continue; + } + + $values = array(); + CRM_Core_DAO::storeValues($dao, $values); + $dashlets[$dao->id] = $values; + } + + return $dashlets; + } + + /** + * Function to get the list of dashlets for a contact + * + * Initializes the dashboard with defaults if this is the user's first visit to their dashboard + * + * @param boolean $flatFormat this is true if you want simple associated array of contact dashlets + * + * @return array $dashlets array of dashlets + * @access public + * @static + */ + static function getContactDashlets($flatFormat = FALSE) { + $dashlets = array(); + + $contactID = CRM_Core_Session::singleton()->get('userID'); + + // get contact dashboard dashlets + $hasDashlets = FALSE; + $dao = new CRM_Contact_DAO_DashboardContact(); + $dao->contact_id = $contactID; + $dao->orderBy('column_no asc, weight asc'); + $dao->find(); + while ($dao->fetch()) { + $hasDashlets = TRUE; + if (!$flatFormat) { + if ($dao->is_active) { + // append weight so that order is preserved. + $dashlets[$dao->column_no]["{$dao->weight}-{$dao->dashboard_id}"] = $dao->is_minimized; + } + } + else { + $dashlets[$dao->dashboard_id] = $dao->dashboard_id; + } + } + + if ($flatFormat) { + return $dashlets; + } + + // If empty then initialize contact dashboard for this user + if (!$hasDashlets) { + $defaultDashlets = self::getDashlets(); + if ($defaultDashlets) { + // Add dashlet entries for logged in contact + // TODO: need to optimize this sql + $items = ''; + foreach ($defaultDashlets as $key => $values) { + // Set civicrm blog as default enabled + $default = $values['url'] == 'civicrm/dashlet/blog&reset=1&snippet=5' ? 1 : 0; + $items .= ($items ? ', ' : '') . "($key, $contactID, $default, $default)"; + } + $query = "INSERT INTO civicrm_dashboard_contact (dashboard_id, contact_id, column_no, is_active) VALUES $items"; + CRM_Core_DAO::executeQuery($query); + } + } + + return $dashlets; + } + + /** + * Function to check dashlet permission for current user + * + * @param string permission string + * + * @return boolean true if use has permission else false + */ + static function checkPermission($permission, $operator) { + if ($permission) { + $permissions = explode(',', $permission); + $config = CRM_Core_Config::singleton(); + + static $allComponents; + if (!$allComponents) { + $allComponents = CRM_Core_Component::getNames(); + } + + $hasPermission = FALSE; + foreach ($permissions as $key) { + $showDashlet = TRUE; + + $componentName = NULL; + if (strpos($key, 'access') === 0) { + $componentName = trim(substr($key, 6)); + if (!in_array($componentName, $allComponents)) { + $componentName = NULL; + } + } + + // hack to handle case permissions + if (!$componentName && in_array($key, array( + 'access my cases and activities', 'access all cases and activities'))) { + $componentName = 'CiviCase'; + } + + //hack to determine if it's a component related permission + if ($componentName) { + if (!in_array($componentName, $config->enableComponents) || + !CRM_Core_Permission::check($key) + ) { + $showDashlet = FALSE; + if ($operator == 'AND') { + return $showDashlet; + } + } + else { + $hasPermission = TRUE; + } + } + elseif (!CRM_Core_Permission::check($key)) { + $showDashlet = FALSE; + if ($operator == 'AND') { + return $showDashlet; + } + } + else { + $hasPermission = TRUE; + } + } + + if (!$showDashlet && !$hasPermission) { + return FALSE; + } + else { + return TRUE; + } + } + else { + // if permission is not set consider everyone has permission to access it. + return TRUE; + } + } + + /** + * Function to get details of each dashlets + * + * @param int $dashletID widget ID + * + * @return array associted array title and content + * @access public + * @static + */ + static function getDashletInfo($dashletID) { + $dashletInfo = array(); + + $params = array(1 => array($dashletID, 'Integer')); + $query = "SELECT label, url, fullscreen_url, is_fullscreen FROM civicrm_dashboard WHERE id = %1"; + $dashboadDAO = CRM_Core_DAO::executeQuery($query, $params); + $dashboadDAO->fetch(); + + // build the content + $dao = new CRM_Contact_DAO_DashboardContact(); + + $session = CRM_Core_Session::singleton(); + $dao->contact_id = $session->get('userID'); + $dao->dashboard_id = $dashletID; + $dao->find(TRUE); + + //reset content based on the cache time set in config + $createdDate = strtotime($dao->created_date); + $dateDiff = round(abs(time() - $createdDate) / 60); + + $config = CRM_Core_Config::singleton(); + if ($config->dashboardCacheTimeout <= $dateDiff) { + $dao->content = NULL; + } + + // if content is empty and url is set, retrieve it from url + if (!$dao->content && $dashboadDAO->url) { + $url = $dashboadDAO->url; + + // CRM-7087 + // -lets use relative url for internal use. + // -make sure relative url should not be htmlize. + if (substr($dashboadDAO->url, 0, 4) != 'http') { + $urlParam = CRM_Utils_System::explode('&', $dashboadDAO->url, 2); + $url = CRM_Utils_System::url($urlParam[0], $urlParam[1], TRUE, NULL, FALSE); + } + + //get content from url + $dao->content = CRM_Utils_System::getServerResponse($url); + $dao->created_date = date("YmdHis"); + $dao->save(); + } + + $dashletInfo = array( + 'title' => $dashboadDAO->label, + 'content' => $dao->content, + ); + + if ($dashboadDAO->is_fullscreen) { + $fullscreenUrl = $dashboadDAO->fullscreen_url; + if (substr($fullscreenUrl, 0, 4) != 'http') { + $urlParam = CRM_Utils_System::explode('&', $dashboadDAO->fullscreen_url, 2); + $fullscreenUrl = CRM_Utils_System::url($urlParam[0], $urlParam[1], TRUE, NULL, FALSE); + } + $dashletInfo['fullscreenUrl'] = $fullscreenUrl; + } + return $dashletInfo; + } + + /** + * Function to save changes made by use to the Dashlet + * + * @param array $columns associated array + * + * @return void + * @access public + * @static + */ + static function saveDashletChanges($columns) { + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + + //we need to get existing dashletes, so we know when to update or insert + $contactDashlets = CRM_Core_BAO_Dashboard::getContactDashlets(true); + + $dashletIDs = array(); + if (is_array($columns)) { + foreach ($columns as $colNo => $dashlets) { + if (!is_integer($colNo)) { + continue; + } + $weight = 1; + foreach ($dashlets as $dashletID => $isMinimized) { + $isMinimized = (int) $isMinimized; + if (in_array($dashletID, $contactDashlets)) { + $query = " UPDATE civicrm_dashboard_contact + SET weight = {$weight}, is_minimized = {$isMinimized}, column_no = {$colNo}, is_active = 1 + WHERE dashboard_id = {$dashletID} AND contact_id = {$contactID} "; + } + else { + $query = " INSERT INTO civicrm_dashboard_contact + ( weight, is_minimized, column_no, is_active, dashboard_id, contact_id ) + VALUES( {$weight}, {$isMinimized}, {$colNo}, 1, {$dashletID}, {$contactID} )"; + } + // fire update query for each column + $dao = CRM_Core_DAO::executeQuery($query); + + $dashletIDs[] = $dashletID; + $weight++; + } + } + } + + if (!empty($dashletIDs)) { + // we need to disable widget that removed + $updateQuery = " UPDATE civicrm_dashboard_contact + SET is_active = 0 + WHERE dashboard_id NOT IN ( " . implode(',', $dashletIDs) . ") AND contact_id = {$contactID}"; + } + else { + // this means all widgets are disabled + $updateQuery = " UPDATE civicrm_dashboard_contact + SET is_active = 0 + WHERE contact_id = {$contactID}"; + } + + CRM_Core_DAO::executeQuery($updateQuery); + } + + /** + * Function to add dashlets + * + * @param array $params associated array + * + * @return object $dashlet returns dashlet object + * @access public + * @static + */ + static function addDashlet(&$params) { + + // special case to handle duplicate entires for report instances + $dashboardID = NULL; + if (CRM_Utils_Array::value('instanceURL', $params)) { + $query = "SELECT id + FROM `civicrm_dashboard` + WHERE url LIKE '" . CRM_Utils_Array::value('instanceURL', $params) . "&%'"; + $dashboardID = CRM_Core_DAO::singleValueQuery($query); + } + + $dashlet = new CRM_Core_DAO_Dashboard(); + + if (!$dashboardID) { + // check url is same as exiting entries, if yes just update existing + $dashlet->url = CRM_Utils_Array::value('url', $params); + $dashlet->find(TRUE); + } + else { + $dashlet->id = $dashboardID; + } + + if (is_array(CRM_Utils_Array::value('permission', $params))) { + $params['permission'] = implode(',', $params['permission']); + } + $dashlet->copyValues($params); + + $dashlet->domain_id = CRM_Core_Config::domainID(); + + $dashlet->save(); + + // now we need to make dashlet entries for each contact + self::addContactDashlet($dashlet); + + return $dashlet; + } + + /** + * Update contact dashboard with new dashlet + * + * @param object: $dashlet + * + * @return void + * @static + */ + static function addContactDashlet($dashlet) { + $admin = CRM_Core_Permission::check('administer CiviCRM'); + + // if dashlet is created by admin then you need to add it all contacts. + // else just add to contact who is creating this dashlet + $contactIDs = array(); + if ($admin) { + $query = "SELECT distinct( contact_id ) + FROM civicrm_dashboard_contact + WHERE contact_id NOT IN ( + SELECT distinct( contact_id ) + FROM civicrm_dashboard_contact WHERE dashboard_id = {$dashlet->id} + )"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $contactIDs[] = $dao->contact_id; + } + } + else { + //Get the id of Logged in User + $session = CRM_Core_Session::singleton(); + $contactIDs[] = $session->get('userID'); + } + + if (!empty($contactIDs)) { + foreach ($contactIDs as $contactID) { + $valuesArray[] = " ( {$dashlet->id}, {$contactID} )"; + } + + $valuesString = implode(',', $valuesArray); + $query = " + INSERT INTO civicrm_dashboard_contact ( dashboard_id, contact_id ) + VALUES {$valuesString}"; + + CRM_Core_DAO::executeQuery($query); + } + } + + /** + * Function to reset dashlet cache + * + * @param int $contactID reset cache only for specific contact + * + * @return void + * @static + */ + static function resetDashletCache($contactID = null) { + $whereClause = null; + $params = array(); + if ($contactID) { + $whereClause = "WHERE contact_id = %1"; + $params[1] = array($contactID, 'Integer'); + } + $query = "UPDATE civicrm_dashboard_contact SET content = NULL $whereClause"; + $dao = CRM_Core_DAO::executeQuery($query, $params); + } + + /** + * Delete Dashlet + * + * @return void + * @static + */ + static function deleteDashlet($dashletID) { + $dashlet = new CRM_Core_DAO_Dashboard(); + $dashlet->id = $dashletID; + $dashlet->delete(); + } +} + diff --git a/CRM/Core/BAO/Discount.php b/CRM/Core/BAO/Discount.php new file mode 100644 index 0000000000..9acd5f4255 --- /dev/null +++ b/CRM/Core/BAO/Discount.php @@ -0,0 +1,144 @@ +entity_id = $entityId; + $discount->entity_table = $entityTable; + if ($discount->delete()) { + return TRUE; + } + return FALSE; + } + + /** + * + * The function extracts all the params it needs to create a + * discount object. the params array contains additional unused name/value + * pairs + * + * @param array $params (reference) an assoc array of name/value pairs + * + * @return object CRM_Core_DAO_Discount object on success, otherwise null + * @access public + * @static + */ + static function add(&$params) { + $discount = new CRM_Core_DAO_Discount( ); + $discount->copyValues($params); + $discount->save(); + return $discount; + } + + /** + * Determine whether the given table/id + * has discount associated with it + * + * @param integer $entityId entity id to be searched + * @param string $entityTable entity table to be searched + * + * @return array $optionGroupIDs option group Ids associated with discount + * + */ + static function getOptionGroup($entityId, $entityTable) { + $optionGroupIDs = array(); + $dao = new CRM_Core_DAO_Discount( ); + $dao->entity_id = $entityId; + $dao->entity_table = $entityTable; + $dao->find(); + while ($dao->fetch()) { + $optionGroupIDs[$dao->id] = $dao->price_set_id; + } + return $optionGroupIDs; + } + + /** + * Determine in which discount set the registration date falls + * + * @param integer $entityId entity id to be searched + * @param string $entityTable entity table to be searched + * + * @return integer $dao->id discount id of the set which matches + * the date criteria + */ + static function findSet($entityID, $entityTable) { + if (empty($entityID) || + empty($entityTable) + ) { + // adding this here, to trap errors if values are not sent + CRM_Core_Error::fatal(); + return NULL; + } + + $dao = new CRM_Core_DAO_Discount( ); + $dao->entity_id = $entityID; + $dao->entity_table = $entityTable; + $dao->find(); + + while ($dao->fetch()) { + $endDate = $dao->end_date; + // if end date is not we consider current date as end date + if (!$endDate) { + $endDate = date('Ymd'); + } + $falls = CRM_Utils_Date::getRange($dao->start_date, $endDate); + if ($falls == TRUE) { + return $dao->id; + } + } + return FALSE; + } + +} + diff --git a/CRM/Core/BAO/Domain.php b/CRM/Core/BAO/Domain.php new file mode 100644 index 0000000000..e925d26d2d --- /dev/null +++ b/CRM/Core/BAO/Domain.php @@ -0,0 +1,299 @@ +id = CRM_Core_Config::domainID(); + if (!$domain->find(TRUE)) { + CRM_Core_Error::fatal(); + } + } + return $domain; + } + + /** + * Change active domain (ie. to perform a temporary action) such as changing + * config for all domains + * + * Switching around the global domain variable is very risky business. This + * is ONLY used as a hack to allow CRM_Core_BAO_Setting::setItems to manipulate + * the civicrm_domain.config_backend in multiple domains. When/if config_backend + * goes away, this hack should be removed. + * + * @param integer $domainID id for domain you want to set as current + * @deprecated + * @see http://issues.civicrm.org/jira/browse/CRM-11204 + */ + static function setDomain($domainID){ + CRM_Core_Config::domainID($domainID); + self::getDomain($domainID); + } + + /** + * Reset domain to default (ie. as loaded from settings). This is the + * counterpart to CRM_Core_BAO_Domain::setDomain. + * + * @param integer $domainID id for domain you want to set as current + * @deprecated + * @see CRM_Core_BAO_Domain::setDomain + */ + static function resetDomain(){ + CRM_Core_Config::domainID(null, true); + self::getDomain(null, true); + } + + static function version( $skipUsingCache = false ) { + return CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', + CRM_Core_Config::domainID(), + 'version', + 'id', + $skipUsingCache + ); + } + + /** + * Get the location values of a domain + * + * @param NULL + * + * @return array Location::getValues + * @access public + */ + function &getLocationValues() { + if ($this->_location == NULL) { + $domain = self::getDomain(null); + $params = array( + 'contact_id' => $domain->contact_id + ); + $this->_location = CRM_Core_BAO_Location::getValues($params, TRUE); + + if (empty($this->_location)) { + $this->_location = NULL; + } + } + return $this->_location; + } + + /** + * Save the values of a domain + * + * @return domain array + * @access public + */ + static function edit(&$params, &$id) { + $domain = new CRM_Core_DAO_Domain(); + $domain->id = $id; + $domain->copyValues($params); + $domain->save(); + return $domain; + } + + /** + * Create a new domain + * + * @return domain array + * @access public + */ + static function create($params) { + $domain = new CRM_Core_DAO_Domain(); + $domain->copyValues($params); + $domain->save(); + return $domain; + } + + static function multipleDomains() { + $session = CRM_Core_Session::singleton(); + + $numberDomains = $session->get('numberDomains'); + if (!$numberDomains) { + $query = "SELECT count(*) from civicrm_domain"; + $numberDomains = CRM_Core_DAO::singleValueQuery($query); + $session->set('numberDomains', $numberDomains); + } + return $numberDomains > 1 ? TRUE : FALSE; + } + + static function getNameAndEmail($skipFatal = FALSE) { + $fromEmailAddress = CRM_Core_OptionGroup::values('from_email_address', NULL, NULL, NULL, ' AND is_default = 1'); + if (!empty($fromEmailAddress)) { + foreach ($fromEmailAddress as $key => $value) { + $email = CRM_Utils_Mail::pluckEmailFromHeader($value); + $fromArray = explode('"', $value); + $fromName = CRM_Utils_Array::value(1, $fromArray); + break; + } + return array($fromName, $email); + } + elseif ($skipFatal) { + return array('', ''); + } + + $url = CRM_Utils_System::url('civicrm/admin/domain', + 'action=update&reset=1' + ); + $status = ts("There is no valid default from email address configured for the domain. You can configure here Configure From Email Address.", array(1 => $url)); + + CRM_Core_Error::fatal($status); + } + + static function addContactToDomainGroup($contactID) { + $groupID = self::getGroupId(); + + if ($groupID) { + $contactIDs = array($contactID); + CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIDs, $groupID); + + return $groupID; + } + return FALSE; + } + + static function getGroupId() { + static $groupID = NULL; + + if ($groupID) { + return $groupID; + } + + $domainGroupID = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'domain_group_id' + ); + $multisite = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, + 'is_enabled' + ); + + if ($domainGroupID) { + $groupID = $domainGroupID; + } + elseif ($multisite) { + // create a group with that of domain name + $title = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', + CRM_Core_Config::domainID(), 'name' + ); + $groupID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', + $title, 'id', 'title', true + ); + if (empty($groupID) && !empty($title)) { + $groupParams = array( + 'title' => $title, + 'is_active' => 1, + 'no_parent' => 1, + ); + $group = CRM_Contact_BAO_Group::create($groupParams); + $groupID = $group->id; + } + } + return $groupID ? $groupID : FALSE; + } + + static function isDomainGroup($groupId) { + $domainGroupID = self::getGroupId(); + return $domainGroupID == $groupId ? TRUE : FALSE; + } + + static function getChildGroupIds() { + $domainGroupID = self::getGroupId(); + $childGrps = array(); + + if ($domainGroupID) { + $childGrps = CRM_Contact_BAO_GroupNesting::getChildGroupIds($domainGroupID); + $childGrps[] = $domainGroupID; + } + return $childGrps; + } + + // function to retrieve a list of contact-ids that belongs to current domain/site. + static function getContactList() { + $siteGroups = CRM_Core_BAO_Domain::getChildGroupIds(); + $siteContacts = array(); + + if (!empty($siteGroups)) { + $query = " + SELECT cc.id + FROM civicrm_contact cc + INNER JOIN civicrm_group_contact gc ON + (gc.contact_id = cc.id AND gc.status = 'Added' AND gc.group_id IN (" . implode(',', $siteGroups) . "))"; + + $dao = CRM_Core_DAO::executeQuery($query); + while ($dao->fetch()) { + $siteContacts[] = $dao->id; + } + } + return $siteContacts; + } +} + diff --git a/CRM/Core/BAO/Email.php b/CRM/Core/BAO/Email.php new file mode 100644 index 0000000000..20b45ed096 --- /dev/null +++ b/CRM/Core/BAO/Email.php @@ -0,0 +1,310 @@ +copyValues($params); + + // lower case email field to optimize queries + $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'; + $email->email = $strtolower($email->email); + + // since we're setting bulkmail for 1 of this contact's emails, first reset all their emails to is_bulkmail false + // (only 1 email address can have is_bulkmail = true) + if ($email->is_bulkmail != 'null' && $params['contact_id'] && !self::isMultipleBulkMail()) { + $sql = " +UPDATE civicrm_email +SET is_bulkmail = 0 +WHERE contact_id = {$params['contact_id']} +"; + CRM_Core_DAO::executeQuery($sql); + } + + // handle if email is on hold + self::holdEmail($email); + + $email->save(); + + CRM_Utils_Hook::post($hook, 'Email', $email->id, $email); + return $email; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $entityBlock input parameters to find object + * + * @return boolean + * @access public + * @static + */ + static function &getValues($entityBlock) { + return CRM_Core_BAO_Block::getValues('email', $entityBlock); + } + + /** + * Get all the emails for a specified contact_id, with the primary email being first + * + * @param int $id the contact id + * + * @return array the array of email id's + * @access public + * @static + */ + static function allEmails($id, $updateBlankLocInfo = FALSE) { + if (!$id) { + return NULL; + } + + $query = " +SELECT email, + civicrm_location_type.name as locationType, + civicrm_email.is_primary as is_primary, + civicrm_email.on_hold as on_hold, + civicrm_email.id as email_id, + civicrm_email.location_type_id as locationTypeId +FROM civicrm_contact +LEFT JOIN civicrm_email ON ( civicrm_email.contact_id = civicrm_contact.id ) +LEFT JOIN civicrm_location_type ON ( civicrm_email.location_type_id = civicrm_location_type.id ) +WHERE civicrm_contact.id = %1 +ORDER BY civicrm_email.is_primary DESC, email_id ASC "; + $params = array( + 1 => array( + $id, + 'Integer', + ), + ); + + $emails = $values = array(); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $count = 1; + while ($dao->fetch()) { + $values = array( + 'locationType' => $dao->locationType, + 'is_primary' => $dao->is_primary, + 'on_hold' => $dao->on_hold, + 'id' => $dao->email_id, + 'email' => $dao->email, + 'locationTypeId' => $dao->locationTypeId, + ); + + if ($updateBlankLocInfo) { + $emails[$count++] = $values; + } + else { + $emails[$dao->email_id] = $values; + } + } + return $emails; + } + + /** + * Get all the emails for a specified location_block id, with the primary email being first + * + * @param array $entityElements the array containing entity_id and + * entity_table name + * + * @return array the array of email id's + * @access public + * @static + */ + static function allEntityEmails(&$entityElements) { + if (empty($entityElements)) { + return NULL; + } + + $entityId = $entityElements['entity_id']; + $entityTable = $entityElements['entity_table']; + + + $sql = " SELECT email, ltype.name as locationType, e.is_primary as is_primary, e.on_hold as on_hold,e.id as email_id, e.location_type_id as locationTypeId +FROM civicrm_loc_block loc, civicrm_email e, civicrm_location_type ltype, {$entityTable} ev +WHERE ev.id = %1 +AND loc.id = ev.loc_block_id +AND e.id IN (loc.email_id, loc.email_2_id) +AND ltype.id = e.location_type_id +ORDER BY e.is_primary DESC, email_id ASC "; + + $params = array( + 1 => array( + $entityId, + 'Integer', + ), + ); + + $emails = array(); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + while ($dao->fetch()) { + $emails[$dao->email_id] = array( + 'locationType' => $dao->locationType, + 'is_primary' => $dao->is_primary, + 'on_hold' => $dao->on_hold, + 'id' => $dao->email_id, + 'email' => $dao->email, + 'locationTypeId' => $dao->locationTypeId, + ); + } + + return $emails; + } + + /** + * Function to set / reset hold status for an email + * + * @param object $email email object + * + * @return void + * @static + */ + static function holdEmail(&$email) { + //check for update mode + if ($email->id) { + $params = array(1 => array($email->id, 'Integer')); + if ($email->on_hold && $email->on_hold != 'null') { + $sql = " +SELECT id +FROM civicrm_email +WHERE id = %1 +AND hold_date IS NULL +"; + if (CRM_Core_DAO::singleValueQuery($sql, $params)) { + $email->hold_date = date('YmdHis'); + $email->reset_date = 'null'; + } + } + elseif ($email->on_hold == 'null') { + $sql = " +SELECT id +FROM civicrm_email +WHERE id = %1 +AND hold_date IS NOT NULL +AND reset_date IS NULL +"; + if (CRM_Core_DAO::singleValueQuery($sql, $params)) { + //set reset date only if it is not set and if hold date is set + $email->on_hold = FALSE; + $email->hold_date = 'null'; + $email->reset_date = date('YmdHis'); + } + } + } + else { + if (($email->on_hold != 'null') && $email->on_hold) { + $email->hold_date = date('YmdHis'); + } + } + } + + /** + * Build From Email as the combination of all the email ids of the logged in user and + * the domain email id + * + * @return array an array of email ids + * @access public + * @static + */ + static function getFromEmail() { + $session = CRM_Core_Session::singleton(); + $contactID = $session->get('userID'); + $fromEmailValues = array(); + + // add the domain email id + $domainEmail = CRM_Core_BAO_Domain::getNameAndEmail(); + $domainEmail = "$domainEmail[0] <$domainEmail[1]>"; + $fromEmailValues[$domainEmail] = htmlspecialchars($domainEmail); + + // add logged in user's active email ids + if ($contactID) { + $contactEmails = self::allEmails($contactID); + $fromDisplayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'display_name'); + + foreach ($contactEmails as $emailId => $emailVal) { + $email = trim($emailVal['email']); + if (!$email || $emailVal['on_hold']) { + continue; + } + $fromEmail = "$fromDisplayName <$email>"; + $fromEmailHtml = htmlspecialchars($fromEmail) . ' ' . $emailVal['locationType']; + + if (CRM_Utils_Array::value('is_primary', $emailVal)) { + $fromEmailHtml .= ' ' . ts('(preferred)'); + } + $fromEmailValues[$fromEmail] = $fromEmailHtml; + } + } + return $fromEmailValues; + } + + static function isMultipleBulkMail() { + return CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'civimail_multiple_bulk_emails', NULL, FALSE); + } +} + diff --git a/CRM/Core/BAO/EntityTag.php b/CRM/Core/BAO/EntityTag.php new file mode 100644 index 0000000000..9602f50845 --- /dev/null +++ b/CRM/Core/BAO/EntityTag.php @@ -0,0 +1,389 @@ +entity_id = $entityID; + $entityTag->entity_table = $entityTable; + $entityTag->find(); + + while ($entityTag->fetch()) { + $tags[$entityTag->tag_id] = $entityTag->tag_id; + } + return $tags; + } + + /** + * takes an associative array and creates a entityTag object + * + * the function extract all the params it needs to initialize the create a + * group object. the params array could contain additional unused name/value + * pairs + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return object CRM_Core_BAO_EntityTag object + * @access public + * @static + */ + static function add(&$params) { + $dataExists = self::dataExists($params); + if (!$dataExists) { + return NULL; + } + + $entityTag = new CRM_Core_BAO_EntityTag(); + $entityTag->copyValues($params); + + // dont save the object if it already exists, CRM-1276 + if (!$entityTag->find(TRUE)) { + $entityTag->save(); + + //invoke post hook on entityTag + // we are using this format to keep things consistent between the single and bulk operations + // so a bit different from other post hooks + $object = array(0 => array(0 => $params['entity_id']), 1 => $params['entity_table']); + CRM_Utils_Hook::post('create', 'EntityTag', $params['tag_id'], $object); + } + return $entityTag; + } + + /** + * Check if there is data to create the object + * + * @params array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * @access public + * @static + */ + static function dataExists(&$params) { + return ($params['tag_id'] == 0) ? FALSE : TRUE; + } + + /** + * Function to delete the tag for a contact + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return object CRM_Core_BAO_EntityTag object + * @access public + * @static + * + */ + static function del(&$params) { + $entityTag = new CRM_Core_BAO_EntityTag(); + $entityTag->copyValues($params); + if ($entityTag->find(TRUE)) { + $entityTag->delete(); + + //invoke post hook on entityTag + $object = array(0 => array(0 => $params['entity_id']), 1 => $params['entity_table']); + CRM_Utils_Hook::post('delete', 'EntityTag', $params['tag_id'], $object); + } + } + + /** + * Given an array of entity ids and entity table, add all the entity to the tags + * + * @param array $entityIds (reference ) the array of entity ids to be added + * @param int $tagId the id of the tag + * @params string $entityTable name of entity table default:civicrm_contact + * + * @return array (total, added, notAdded) count of enities added to tag + * @access public + * @static + */ + static function addEntitiesToTag(&$entityIds, $tagId, $entityTable = 'civicrm_contact') { + $numEntitiesAdded = 0; + $numEntitiesNotAdded = 0; + $entityIdsAdded = array(); + + foreach ($entityIds as $entityId) { + $tag = new CRM_Core_DAO_EntityTag(); + + $tag->entity_id = $entityId; + $tag->tag_id = $tagId; + $tag->entity_table = $entityTable; + if (!$tag->find()) { + $tag->save(); + $entityIdsAdded[] = $entityId; + $numEntitiesAdded++; + } + else { + $numEntitiesNotAdded++; + } + } + + //invoke post hook on entityTag + $object = array($entityIdsAdded, $entityTable); + CRM_Utils_Hook::post('create', 'EntityTag', $tagId, $object); + + // reset the group contact cache for all groups + // if tags are being used in a smart group + CRM_Contact_BAO_GroupContactCache::remove(); + + return array(count($entityIds), $numEntitiesAdded, $numEntitiesNotAdded); + } + + /** + * Given an array of entity ids and entity table, remove entity(s) tags + * + * @param array $entityIds (reference ) the array of entity ids to be removed + * @param int $tagId the id of the tag + * @params string $entityTable name of entity table default:civicrm_contact + * + * @return array (total, removed, notRemoved) count of entities removed from tags + * @access public + * @static + */ + static function removeEntitiesFromTag(&$entityIds, $tagId, $entityTable = 'civicrm_contact') { + $numEntitiesRemoved = 0; + $numEntitiesNotRemoved = 0; + $entityIdsRemoved = array(); + + foreach ($entityIds as $entityId) { + $tag = new CRM_Core_DAO_EntityTag(); + + $tag->entity_id = $entityId; + $tag->tag_id = $tagId; + $tag->entity_table = $entityTable; + if ($tag->find()) { + $tag->delete(); + $entityIdsRemoved[] = $entityId; + $numEntitiesRemoved++; + } + else { + $numEntitiesNotRemoved++; + } + } + + //invoke post hook on entityTag + $object = array($entityIdsRemoved, $entityTable); + CRM_Utils_Hook::post('delete', 'EntityTag', $tagId, $object); + + // reset the group contact cache for all groups + // if tags are being used in a smart group + CRM_Contact_BAO_GroupContactCache::remove(); + + return array(count($entityIds), $numEntitiesRemoved, $numEntitiesNotRemoved); + } + + /** + * takes an associative array and creates tag entity record for all tag entities + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $contactId contact id + * + * @return void + * @access public + * @static + */ + static function create(&$params, $entityTable, $entityID) { + // get categories for the entity id + $entityTag = CRM_Core_BAO_EntityTag::getTag($entityID, $entityTable); + + // get the list of all the categories + $allTag = CRM_Core_BAO_Tag::getTags($entityTable); + + // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input + if (!is_array($params)) { + $params = array(); + } + + // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input + if (!is_array($entityTag)) { + $entityTag = array(); + } + + // check which values has to be inserted/deleted for contact + foreach ($allTag as $key => $varValue) { + $tagParams['entity_table'] = $entityTable; + $tagParams['entity_id'] = $entityID; + $tagParams['tag_id'] = $key; + + if (array_key_exists($key, $params) && !array_key_exists($key, $entityTag)) { + // insert a new record + CRM_Core_BAO_EntityTag::add($tagParams); + } + elseif (!array_key_exists($key, $params) && array_key_exists($key, $entityTag)) { + // delete a record for existing contact + CRM_Core_BAO_EntityTag::del($tagParams); + } + } + } + + /** + * This function returns all entities assigned to a specific tag + * + * @param object $tag an object of a tag. + * + * @return array $contactIds array of contact ids + * @access public + */ + function getEntitiesByTag($tag) { + $contactIds = array(); + $entityTagDAO = new CRM_Core_DAO_EntityTag(); + $entityTagDAO->tag_id = $tag->id; + $entityTagDAO->find(); + while ($entityTagDAO->fetch()) { + $contactIds[] = $entityTagDAO->contact_id; + } + return $contactIds; + } + + /** + * Function to get contact tags + */ + static function getContactTags($contactID, $count = FALSE) { + $contactTags = array(); + if (!$count) { + $select = "SELECT name "; + } + else { + $select = "SELECT count(*) as cnt"; + } + + $query = "{$select} + FROM civicrm_tag ct + INNER JOIN civicrm_entity_tag et ON ( ct.id = et.tag_id AND + et.entity_id = {$contactID} AND + et.entity_table = 'civicrm_contact' AND + ct.is_tagset = 0 )"; + + $dao = CRM_Core_DAO::executeQuery($query); + + if ($count) { + $dao->fetch(); + return $dao->cnt; + } + + while ($dao->fetch()) { + $contactTags[] = $dao->name; + } + + return $contactTags; + } + + /** + * Function to get child contact tags given parentId + */ + static function getChildEntityTags($parentId, $entityId, $entityTable = 'civicrm_contact') { + $entityTags = array(); + $query = "SELECT ct.id as tag_id, name FROM civicrm_tag ct + INNER JOIN civicrm_entity_tag et ON ( et.entity_id = {$entityId} AND + et.entity_table = '{$entityTable}' AND et.tag_id = ct.id) + WHERE ct.parent_id = {$parentId}"; + + $dao = CRM_Core_DAO::executeQuery($query); + + while ($dao->fetch()) { + $entityTags[$dao->tag_id] = array( + 'id' => $dao->tag_id, + 'name' => $dao->name, + ); + } + + return $entityTags; + } + + /** + * Function to merge two tags: tag B into tag A. + */ + function mergeTags($tagAId, $tagBId) { + $queryParams = array(1 => array($tagBId, 'Integer'), + 2 => array($tagAId, 'Integer'), + ); + + // re-compute used_for field + $query = "SELECT id, name, used_for FROM civicrm_tag WHERE id IN (%1, %2)"; + $dao = CRM_Core_DAO::executeQuery($query, $queryParams); + $tags = array(); + while ($dao->fetch()) { + $label = ($dao->id == $tagAId) ? 'tagA' : 'tagB'; + $tags[$label] = $dao->name; + $tags["{$label}_used_for"] = $dao->used_for ? explode(",", $dao->used_for) : array(); + } + $usedFor = array_merge($tags["tagA_used_for"], $tags["tagB_used_for"]); + $usedFor = implode(',', array_unique($usedFor)); + $tags["tagB_used_for"] = explode(",", $usedFor); + + // get all merge queries together + $sqls = array( + // 1. update entity tag entries + "UPDATE civicrm_entity_tag SET tag_id = %1 WHERE tag_id = %2", + // 2. update used_for info for tag B + "UPDATE civicrm_tag SET used_for = '{$usedFor}' WHERE id = %1", + // 3. remove tag A, if tag A is getting merged into B + "DELETE FROM civicrm_tag WHERE id = %2", + // 4. remove duplicate entity tag records + "DELETE et2.* from civicrm_entity_tag et1 INNER JOIN civicrm_entity_tag et2 ON et1.entity_table = et2.entity_table AND et1.entity_id = et2.entity_id AND et1.tag_id = et2.tag_id WHERE et1.id < et2.id", + ); + $tables = array('civicrm_entity_tag', 'civicrm_tag'); + + // Allow hook_civicrm_merge() to add SQL statements for the merge operation AND / OR + // perform any other actions like logging + CRM_Utils_Hook::merge('sqls', $sqls, $tagAId, $tagBId, $tables); + + // call the SQL queries in one transaction + $transaction = new CRM_Core_Transaction(); + foreach ($sqls as $sql) { + CRM_Core_DAO::executeQuery($sql, $queryParams, TRUE, NULL, TRUE); + } + $transaction->commit(); + + $tags['status'] = TRUE; + return $tags; + } +} + diff --git a/CRM/Core/BAO/Extension.php b/CRM/Core/BAO/Extension.php new file mode 100644 index 0000000000..f2f18b5ca6 --- /dev/null +++ b/CRM/Core/BAO/Extension.php @@ -0,0 +1,112 @@ +copyValues($params); + if ($extension->find(TRUE)) { + CRM_Core_DAO::storeValues($extension, $defaults); + return $extension; + } + return NULL; + } + + /** + * Function to delete an extension + * + * @param int $id Id of the extension to be deleted. + * + * @return void + * + * @access public + * @static + */ + static function del($id) { + $extension = new CRM_Core_DAO_Extension(); + $extension->id = $id; + return $extension->delete(); + } + + /** + * Change the schema version of an extension + * + * @param $fullName string, the fully-qualified name (eg "com.example.myextension") + * @param $schemaVersion string + * @return void + */ + static function setSchemaVersion($fullName, $schemaVersion) { + $sql = 'UPDATE civicrm_extension SET schema_version = %1 WHERE full_name = %2'; + $params = array( + 1 => array($schemaVersion, 'String'), + 2 => array($fullName, 'String'), + ); + return CRM_Core_DAO::executeQuery($sql, $params); + } + + /** + * Determine the schema version of an extension + * + * @param $fullName string, the fully-qualified name (eg "com.example.myextension") + * @return string + */ + static function getSchemaVersion($fullName) { + $sql = 'SELECT schema_version FROM civicrm_extension WHERE full_name = %1'; + $params = array( + 1 => array($fullName, 'String'), + ); + return CRM_Core_DAO::singleValueQuery($sql, $params); + } + +} diff --git a/CRM/Core/BAO/File.php b/CRM/Core/BAO/File.php new file mode 100644 index 0000000000..c11b92a5a2 --- /dev/null +++ b/CRM/Core/BAO/File.php @@ -0,0 +1,551 @@ +entity_table = $entityTable; + } + $entityFileDAO->entity_id = $entityID; + $entityFileDAO->file_id = $fileID; + + if ($entityFileDAO->find(TRUE)) { + $fileDAO = new CRM_Core_DAO_File(); + $fileDAO->id = $fileID; + if ($fileDAO->find(TRUE)) { + $config = CRM_Core_Config::singleton(); + $path = $config->customFileUploadDir . $fileDAO->uri; + + if (file_exists($path) && is_readable($path)) { + return array($path, $fileDAO->mime_type); + } + } + } + + return array(NULL, NULL); + } + + + static function filePostProcess( + $data, + $fileTypeID, + $entityTable, + $entityID, + $entitySubtype, + $overwrite = TRUE, + $fileParams = NULL, + $uploadName = 'uploadFile', + $mimeType = null + ) { + if (!$mimeType) { + CRM_Core_Error::fatal(ts('Mime Type is now a required parameter')); + } + + $config = CRM_Core_Config::singleton(); + + $path = explode('/', $data); + $filename = $path[count($path) - 1]; + + // rename this file to go into the secure directory + if ($entitySubtype) { + $directoryName = $config->customFileUploadDir . $entitySubtype . DIRECTORY_SEPARATOR . $entityID; + } + else { + $directoryName = $config->customFileUploadDir; + } + + CRM_Utils_File::createDir($directoryName); + + if (!rename($data, $directoryName . DIRECTORY_SEPARATOR . $filename)) { + CRM_Core_Error::fatal(ts('Could not move custom file to custom upload directory')); + break; + } + + // to get id's + if ($overwrite && $fileTypeID) { + list($sql, $params) = self::sql($entityTable, $entityID, $fileTypeID); + } + else { + list($sql, $params) = self::sql($entityTable, $entityID, NULL); + } + + $dao = CRM_Core_DAO::executeQuery($sql, $params); + $dao->fetch(); + + $fileDAO = new CRM_Core_DAO_File(); + $op = 'create'; + if (isset($dao->cfID) && $dao->cfID) { + $op = 'edit'; + $fileDAO->id = $dao->cfID; + unlink($directoryName . DIRECTORY_SEPARATOR . $dao->uri); + } + + if (!empty($fileParams)) { + $fileDAO->copyValues($fileParams); + } + + $fileDAO->uri = $filename; + $fileDAO->mime_type = $mimeType; + $fileDAO->file_type_id = $fileTypeID; + $fileDAO->upload_date = date('Ymdhis'); + $fileDAO->save(); + + // need to add/update civicrm_entity_file + $entityFileDAO = new CRM_Core_DAO_EntityFile(); + if (isset($dao->cefID) && $dao->cefID) { + $entityFileDAO->id = $dao->cefID; + } + $entityFileDAO->entity_table = $entityTable; + $entityFileDAO->entity_id = $entityID; + $entityFileDAO->file_id = $fileDAO->id; + $entityFileDAO->save(); + + //save static tags + if (!empty($fileParams['tag'])) { + CRM_Core_BAO_EntityTag::create($fileParams['tag'], 'civicrm_file', $entityFileDAO->id); + } + + //save free tags + if (isset($fileParams['attachment_taglist']) && !empty($fileParams['attachment_taglist'])) { + CRM_Core_Form_Tag::postProcess($fileParams['attachment_taglist'], $entityFileDAO->id, 'civicrm_file', CRM_Core_DAO::$_nullObject); + } + + // lets call the post hook here so attachments code can do the right stuff + CRM_Utils_Hook::post($op, 'File', $fileDAO->id, $fileDAO); + } + + /** + * The $useWhere is used so that the signature matches the parent class + */ + public function delete($useWhere = false) { + list($fileID, $entityID, $fieldID) = func_get_args(); + + $fileDAO = new CRM_Core_DAO_File(); + $fileDAO->id = $fileID; + if (!$fileDAO->find(TRUE)) { + CRM_Core_Error::fatal(); + } + + // lets call a pre hook before the delete, so attachments hooks can get the info before things + // disappear + CRM_Utils_Hook::pre('delete', 'File', $fileID, $fileDAO); + + // get the table and column name + list($tableName, $columnName, $groupID) = CRM_Core_BAO_CustomField::getTableColumnGroup($fieldID); + + $entityFileDAO = new CRM_Core_DAO_EntityFile(); + $entityFileDAO->file_id = $fileID; + $entityFileDAO->entity_id = $entityID; + $entityFileDAO->entity_table = $tableName; + + if (!$entityFileDAO->find(TRUE)) { + CRM_Core_Error::fatal(); + } + + $entityFileDAO->delete(); + $fileDAO->delete(); + + // also set the value to null of the table and column + $query = "UPDATE $tableName SET $columnName = null WHERE $columnName = %1"; + $params = array(1 => array($fileID, 'Integer')); + CRM_Core_DAO::executeQuery($query, $params); + } + + /** + * delete all the files and associated object associated with this + * combination + */ + static function deleteEntityFile($entityTable, $entityID, $fileTypeID = NULL, $fileID = NULL) { + if (empty($entityTable) || empty($entityID)) { + return; + } + + $config = CRM_Core_Config::singleton(); + + list($sql, $params) = self::sql($entityTable, $entityID, $fileTypeID, $fileID); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + + $cfIDs = array(); + $cefIDs = array(); + while ($dao->fetch()) { + $cfIDs[$dao->cfID] = $dao->uri; + $cefIDs[] = $dao->cefID; + } + + if (!empty($cefIDs)) { + $cefIDs = implode(',', $cefIDs); + $sql = "DELETE FROM civicrm_entity_file where id IN ( $cefIDs )"; + CRM_Core_DAO::executeQuery($sql); + } + + if (!empty($cfIDs)) { + // Delete file only if there no any entity using this file. + $deleteFiles = array(); + foreach ($cfIDs as $fId => $fUri) { + //delete tags from entity tag table + $tagParams = array( + 'entity_table' => 'civicrm_file', + 'entity_id' => $fId + ); + + CRM_Core_BAO_EntityTag::del($tagParams); + + if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', $fId, 'id', 'file_id')) { + unlink($config->customFileUploadDir . DIRECTORY_SEPARATOR . $fUri); + $deleteFiles[$fId] = $fId; + } + } + + if (!empty($deleteFiles)) { + $deleteFiles = implode(',', $deleteFiles); + $sql = "DELETE FROM civicrm_file where id IN ( $deleteFiles )"; + CRM_Core_DAO::executeQuery($sql); + } + } + } + + /** + * get all the files and associated object associated with this + * combination + */ + static function getEntityFile($entityTable, $entityID, $addDeleteArgs = false) { + if (empty($entityTable) || !$entityID) { + $results = NULL; + return $results; + } + + $config = CRM_Core_Config::singleton(); + + list($sql, $params) = self::sql($entityTable, $entityID, NULL); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + $results = array(); + while ($dao->fetch()) { + $result['fileID'] = $dao->cfID; + $result['entityID'] = $dao->cefID; + $result['mime_type'] = $dao->mime_type; + $result['fileName'] = $dao->uri; + $result['description'] = $dao->description; + $result['cleanName'] = CRM_Utils_File::cleanFileName($dao->uri); + $result['fullPath'] = $config->customFileUploadDir . DIRECTORY_SEPARATOR . $dao->uri; + $result['url'] = CRM_Utils_System::url('civicrm/file', "reset=1&id={$dao->cfID}&eid={$entityID}"); + $result['href'] = "{$result['cleanName']}"; + $result['tag'] = CRM_Core_BAO_EntityTag::getTag($dao->cfID, 'civicrm_file'); + if ($addDeleteArgs) { + $result['deleteURLArgs'] = self::deleteURLArgs($entityTable, $entityID, $dao->cfID); + } + $results[$dao->cfID] = $result; + } + + //fix tag names + $tags = CRM_Core_PseudoConstant::tag(); + + foreach($results as &$values) { + if (!empty($values['tag'])) { + $tagNames = array(); + foreach( $values['tag'] as $tid ) { + $tagNames[] = $tags[$tid]; + } + $values['tag'] = implode(', ', $tagNames); + } else { + $values['tag'] = ''; + } + } + + $dao->free(); + return $results; + } + + static function sql($entityTable, $entityID, $fileTypeID = NULL, $fileID = NULL) { + $sql = " + SELECT CF.id as cfID, + CF.uri as uri, + CF.mime_type as mime_type, + CF.description as description, + CEF.id as cefID + FROM civicrm_file AS CF + LEFT JOIN civicrm_entity_file AS CEF ON ( CEF.file_id = CF.id ) + WHERE CEF.entity_table = %1 + AND CEF.entity_id = %2"; + + $params = array( + 1 => array($entityTable, 'String'), + 2 => array($entityID, 'Integer'), + ); + + if ($fileTypeID !== NULL) { + $sql .= " AND CF.file_type_id = %3"; + $params[3] = array($fileTypeID, 'Integer'); + } + + if ($fileID !== NULL) { + $sql .= " AND CF.id = %4"; + $params[4] = array($fileID, 'Integer'); + } + + return array($sql, $params); + } + + static function buildAttachment(&$form, $entityTable, $entityID = NULL, $numAttachments = NULL, $ajaxDelete = FALSE) { + + if (!$numAttachments) { + $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + } + // Assign maxAttachments count to template for help message + $form->assign('maxAttachments', $numAttachments); + + $config = CRM_Core_Config::singleton(); + // set default max file size as 2MB + $maxFileSize = $config->maxFileSize ? $config->maxFileSize : 2; + + $currentAttachmentInfo = self::getEntityFile($entityTable, $entityID, TRUE); + $totalAttachments = 0; + if ($currentAttachmentInfo) { + $totalAttachments = count($currentAttachmentInfo); + $form->add('checkbox', 'is_delete_attachment', ts('Delete All Attachment(s)')); + $form->assign('currentAttachmentInfo', $currentAttachmentInfo); + } + else { + $form->assign('currentAttachmentInfo', NULL); + } + + if ( $totalAttachments ) { + if ($totalAttachments >= $numAttachments) { + $numAttachments = 0; + } + else { + $numAttachments -= $totalAttachments; + } + } + + $form->assign('numAttachments', $numAttachments); + + $tags = CRM_Core_BAO_Tag::getTags('civicrm_file'); + + // get tagset info + $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_file'); + + // add attachments + for ($i = 1; $i <= $numAttachments; $i++) { + $form->addElement('file', "attachFile_$i", ts('Attach File'), 'size=30 maxlength=60'); + $form->setMaxFileSize($maxFileSize * 1024 * 1024); + $form->addRule("attachFile_$i", + ts('File size should be less than %1 MByte(s)', + array(1 => $maxFileSize) + ), + 'maxfilesize', + $maxFileSize * 1024 * 1024 + ); + $form->addElement('text', "attachDesc_$i", ts('Description'), 'size=40 maxlength=255'); + + if (!empty($tags)) { + $form->add('select', "tag_$i", ts('Tags'), $tags, FALSE, + array('id' => "tags_$i", 'multiple' => 'multiple', 'title' => ts('- select -')) + ); + } + } + + // build tagset widget + CRM_Core_Form_Tag::buildQuickForm($form, $parentNames, 'civicrm_file', NULL, FALSE, TRUE, FALSE); + } + + /** + * Function to return a clean url string and the number of attachment for a + * given entityTable, entityID + * + * @param $entityTable string The entityTable to which the file is attached + * @param $entityID int The id of the object in the above entityTable + * @param $separator string The string separator where to implode the urls + * + * @return array An array with 2 elements. The string and the number of attachments + * @static + */ + static function attachmentInfo($entityTable, $entityID, $separator = '
    ') { + if (!$entityID) { + return NULL; + } + + $currentAttachments = self::getEntityFile($entityTable, $entityID); + if (!empty($currentAttachments)) { + $currentAttachmentURL = array(); + foreach ($currentAttachments as $fileID => $attach) { + $currentAttachmentURL[] = $attach['href']; + } + return implode($separator, $currentAttachmentURL); + } + return NULL; + } + + static function formatAttachment( + &$formValues, + &$params, + $entityTable, + $entityID = NULL + ) { + + // delete current attachments if applicable + if ($entityID && CRM_Utils_Array::value('is_delete_attachment', $formValues)) { + CRM_Core_BAO_File::deleteEntityFile($entityTable, $entityID); + } + + $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + + $now = date('Ymdhis'); + + // setup all attachments + for ($i = 1; $i <= $numAttachments; $i++) { + $attachName = "attachFile_$i"; + $attachDesc = "attachDesc_$i"; + $attachTags = "tag_$i"; + $attachFreeTags = "attachment_taglist_$i"; + if (isset($formValues[$attachName]) && !empty($formValues[$attachName])) { + // add static tags if selects + $tagParams = array(); + if (!empty($formValues[$attachTags])) { + foreach ($formValues[$attachTags] as $tag) { + $tagParams[$tag] = 1; + } + } + + // we dont care if the file is empty or not + // CRM-7448 + $fileParams = array( + 'uri' => $formValues[$attachName]['name'], + 'type' => $formValues[$attachName]['type'], + 'location' => $formValues[$attachName]['name'], + 'description' => $formValues[$attachDesc], + 'upload_date' => $now, + 'tag' => $tagParams, + 'attachment_taglist' => CRM_Utils_Array::value($attachFreeTags, $formValues, array()) + ); + + $params[$attachName] = $fileParams; + } + } + } + + static function processAttachment(&$params, $entityTable, $entityID) { + $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + + for ($i = 1; $i <= $numAttachments; $i++) { + if ( + isset($params["attachFile_$i"]) && + is_array($params["attachFile_$i"]) + ) { + self::filePostProcess( + $params["attachFile_$i"]['location'], + NULL, + $entityTable, + $entityID, + NULL, + TRUE, + $params["attachFile_$i"], + "attachFile_$i", + $params["attachFile_$i"]['type'] + ); + } + } + } + + static function uploadNames() { + $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + + $names = array(); + for ($i = 1; $i <= $numAttachments; $i++) { + $names[] = "attachFile_{$i}"; + } + $names[] = 'uploadFile'; + return $names; + } + + /* + * Function to copy/attach an existing file to a different entity + * table and id. + */ + static function copyEntityFile($oldEntityTable, $oldEntityId, $newEntityTable, $newEntityId) { + $oldEntityFile = new CRM_Core_DAO_EntityFile(); + $oldEntityFile->entity_id = $oldEntityId; + $oldEntityFile->entity_table = $oldEntityTable; + $oldEntityFile->find(); + + while ($oldEntityFile->fetch()) { + $newEntityFile = new CRM_Core_DAO_EntityFile(); + $newEntityFile->entity_id = $newEntityId; + $newEntityFile->entity_table = $newEntityTable; + $newEntityFile->file_id = $oldEntityFile->file_id; + $newEntityFile->save(); + } + } + + static function deleteURLArgs($entityTable, $entityID, $fileID) { + $params['entityTable'] = $entityTable; + $params['entityID'] = $entityID; + $params['fileID'] = $fileID; + + $signer = new CRM_Utils_Signer(CRM_Core_Key::privateKey(), self::$_signableFields); + $params['_sgn'] = $signer->sign($params); + return CRM_Utils_System::makeQueryString($params); + } + + /** + * function to delete a file attachment from an entity table / entity ID + * + * @static + * @access public + */ + static function deleteAttachment( ) { + $params = array( ); + $params['entityTable'] = CRM_Utils_Request::retrieve( 'entityTable', 'String' , CRM_Core_DAO::$_nullObject, TRUE); + $params['entityID'] = CRM_Utils_Request::retrieve( 'entityID' , 'Positive', CRM_Core_DAO::$_nullObject, TRUE); + $params['fileID'] = CRM_Utils_Request::retrieve( 'fileID' , 'Positive', CRM_Core_DAO::$_nullObject, TRUE); + + $signature = CRM_Utils_Request::retrieve( '_sgn', 'String', CRM_Core_DAO::$_nullObject, TRUE); + + $signer = new CRM_Utils_Signer(CRM_Core_Key::privateKey(), self::$_signableFields); + if (! $signer->validate($signature, $params)) { + CRM_Core_Error::fatal('Request signature is invalid'); + } + + CRM_Core_BAO_File::deleteEntityFile($params['entityTable'], $params['entityID'], NULL, $params['fileID']); + } + +} + diff --git a/CRM/Core/BAO/FinancialTrxn.php b/CRM/Core/BAO/FinancialTrxn.php new file mode 100644 index 0000000000..ed28e23256 --- /dev/null +++ b/CRM/Core/BAO/FinancialTrxn.php @@ -0,0 +1,374 @@ +copyValues($params); + $fids = array(); + if (!CRM_Utils_Rule::currencyCode($trxn->currency)) { + $config = CRM_Core_Config::singleton(); + $trxn->currency = $config->defaultCurrency; + } + + $trxn->save(); + + // save to entity_financial_trxn table + $entityFinancialTrxnParams = + array( + 'entity_table' => "civicrm_contribution", + 'financial_trxn_id' => $trxn->id, + 'amount' => $params['total_amount'], + 'currency' => $trxn->currency, + ); + + if (!empty($trxnEntityTable)) { + $entityFinancialTrxnParams['entity_table'] = $trxnEntityTable['entity_table']; + $entityFinancialTrxnParams['entity_id'] = $trxnEntityTable['entity_id']; + } + else { + $entityFinancialTrxnParams['entity_id'] = $params['contribution_id']; + } + + $entityTrxn = new CRM_Financial_DAO_EntityFinancialTrxn(); + $entityTrxn->copyValues($entityFinancialTrxnParams); + $entityTrxn->save(); + return $trxn; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * contact_id. We'll tweak this function to be more full featured over a period + * of time. This is the inverse function of create. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Contribute_BAO_ContributionType object + * @access public + * @static + */ + static function retrieve( &$params, &$defaults ) { + $financialItem = new CRM_Financial_DAO_FinancialTrxn( ); + $financialItem->copyValues($params); + if ($financialItem->find(true)) { + CRM_Core_DAO::storeValues( $financialItem, $defaults ); + return $financialItem; + } + return null; + } + + /** + * + * Given an entity_id and entity_table, check for corresponding entity_financial_trxn and financial_trxn record. + * NOTE: This should be moved to separate BAO for EntityFinancialTrxn when we start adding more code for that object. + * + * @param string $entityTable name of the entity table usually 'civicrm_contact' + * @param int $entityID id of the entity usually the contactID. + * @param string $orderBy to get single trxn id for a entity table i.e last or first. + * + * @return array( ) reference $tag array of catagory id's the contact belongs to. + * + * @access public + * @static + */ + static function getFinancialTrxnId($entity_id, $orderBy = 'ASC', $newTrxn = FALSE) { + $ids = array('entityFinancialTrxnId' => NULL, 'financialTrxnId' => NULL); + + $condition = ""; + if (!$newTrxn) { + $condition = " AND ((ceft1.entity_table IS NOT NULL) OR (cft.payment_instrument_id IS NOT NULL AND ceft1.entity_table IS NULL)) "; + } + $query = "SELECT ceft.id, ceft.financial_trxn_id FROM `civicrm_financial_trxn` cft +LEFT JOIN civicrm_entity_financial_trxn ceft +ON ceft.financial_trxn_id = cft.id AND ceft.entity_table = 'civicrm_contribution' +LEFT JOIN civicrm_entity_financial_trxn ceft1 +ON ceft1.financial_trxn_id = cft.id AND ceft1.entity_table = 'civicrm_financial_item' +LEFT JOIN civicrm_financial_item cfi ON ceft1.entity_table = 'civicrm_financial_item' and cfi.id = ceft1.entity_id +WHERE ceft.entity_id = %1 AND (cfi.entity_table <> 'civicrm_financial_trxn' or cfi.entity_table is NULL) +{$condition} +ORDER BY cft.id {$orderBy} +LIMIT 1;"; + + $params = array(1 => array($entity_id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + if ($dao->fetch()) { + $ids['entityFinancialTrxnId'] = $dao->id; + $ids['financialTrxnId'] = $dao->financial_trxn_id; + } + return $ids; + } + + /** + * Given an entity_id and entity_table, check for corresponding entity_financial_trxn and financial_trxn record. + * NOTE: This should be moved to separate BAO for EntityFinancialTrxn when we start adding more code for that object. + * + * @param string $entityTable name of the entity table usually 'civicrm_contact' + * @param int $entityID id of the entity usually the contactID. + * + * @return array( ) reference $tag array of catagory id's the contact belongs to. + * + * @access public + * @static + */ + static function getFinancialTrxnTotal($entity_id) { + $query = " + SELECT (ft.amount+SUM(ceft.amount)) AS total FROM civicrm_entity_financial_trxn AS ft +LEFT JOIN civicrm_entity_financial_trxn AS ceft ON ft.financial_trxn_id = ceft.entity_id +WHERE ft.entity_table = 'civicrm_contribution' AND ft.entity_id = %1 + "; + + $sqlParams = array(1 => array($entity_id, 'Integer')); + return CRM_Core_DAO::singleValueQuery($query, $sqlParams); + + } + /** + * Given an financial_trxn_id check for previous entity_financial_trxn. + * + * @param int $financialTrxn_id id of the latest payment. + * + * @return array( ) $payment array of previous payments + * + * @access public + * @static + */ + static function getPayments($financial_trxn_id) { + $query = " +SELECT ef1.financial_trxn_id, sum(ef1.amount) amount +FROM civicrm_entity_financial_trxn ef1 +LEFT JOIN civicrm_entity_financial_trxn ef2 ON ef1.financial_trxn_id = ef2.entity_id +WHERE ef2.financial_trxn_id =%1 + AND ef2.entity_table = 'civicrm_financial_trxn' + AND ef1.entity_table = 'civicrm_financial_item' +GROUP BY ef1.financial_trxn_id +UNION +SELECT ef1.financial_trxn_id, ef1.amount +FROM civicrm_entity_financial_trxn ef1 +LEFT JOIN civicrm_entity_financial_trxn ef2 ON ef1.entity_id = ef2.entity_id +WHERE ef2.financial_trxn_id =%1 + AND ef2.entity_table = 'civicrm_financial_trxn' + AND ef1.entity_table = 'civicrm_financial_trxn'"; + + $sqlParams = array(1 => array($financial_trxn_id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $sqlParams); + $i = 0; + $result = array(); + while ($dao->fetch()) { + $result[$i]['financial_trxn_id'] = $dao->financial_trxn_id; + $result[$i]['amount'] = $dao->amount; + $i++; + } + + if (empty($result)) { + $query = "SELECT sum( amount ) amount FROM civicrm_entity_financial_trxn WHERE financial_trxn_id =%1 AND entity_table = 'civicrm_financial_item'"; + $sqlParams = array(1 => array($financial_trxn_id, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $sqlParams); + + if ($dao->fetch()) { + $result[0]['financial_trxn_id'] = $financial_trxn_id; + $result[0]['amount'] = $dao->amount; + } + } + return $result; + } + + /** + * Given an entity_id and entity_table, check for corresponding entity_financial_trxn and financial_trxn record. + * NOTE: This should be moved to separate BAO for EntityFinancialTrxn when we start adding more code for that object. + * + * @param string $entityTable name of the entity table usually 'civicrm_contact' + * @param int $entityID id of the entity usually the contactID. + * + * @return array( ) reference $tag array of catagory id's the contact belongs to. + * + * @access public + * @static + */ + static function getFinancialTrxnLineTotal($entity_id, $entity_table = 'civicrm_contribution') { + $query = "SELECT lt.price_field_value_id AS id, ft.financial_trxn_id,ft.amount AS amount FROM civicrm_entity_financial_trxn AS ft +LEFT JOIN civicrm_financial_item AS fi ON fi.id = ft.entity_id AND fi.entity_table = 'civicrm_line_item' AND ft.entity_table = 'civicrm_financial_item' +LEFT JOIN civicrm_line_item AS lt ON lt.id = fi.entity_id AND lt.entity_table = %2 +WHERE lt.entity_id = %1 "; + + $sqlParams = array(1 => array($entity_id, 'Integer'), 2 => array($entity_table, 'String')); + $dao = CRM_Core_DAO::executeQuery($query, $sqlParams); + while($dao->fetch()){ + $result[$dao->financial_trxn_id][$dao->id] = $dao->amount; + } + if (!empty($result)) { + return $result; + } + else { + return null; + } + } + + /** + * Delete financial transaction + * + * @return true on success, false otherwise + * @access public + * @static + */ + static function deleteFinancialTrxn($entity_id) { + $fids = self::getFinancialTrxnId($entity_id); + + if ($fids['financialTrxnId']) { + // delete enity financial transaction before financial transaction since financial_trxn_id will be set to null if financial transaction deleted first + $query = 'DELETE FROM civicrm_entity_financial_trxn WHERE financial_trxn_id = %1'; + CRM_Core_DAO::executeQuery($query, array(1 => array($fids['financialTrxnId'], 'Integer'))); + + // delete financial transaction + $query = 'DELETE FROM civicrm_financial_trxn WHERE id = %1'; + CRM_Core_DAO::executeQuery($query, array(1 => array($fids['financialTrxnId'], 'Integer'))); + return TRUE; + } + else { + return FALSE; + } + } + + /** + * create financial transaction for premium + * + * @access public + * @static + */ + static function createPremiumTrxn($params) { + if ((!CRM_Utils_Array::value('financial_type_id', $params) || !CRM_Utils_Array::value('contributionId', $params)) && !CRM_Utils_Array::value('oldPremium', $params)) { + return; + } + + if (CRM_Utils_Array::value('cost', $params)) { + $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); + $financialAccountType = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id']); + $accountRelationship = CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND label IN ('Premiums Inventory Account is', 'Cost of Sales Account is')"); + $toFinancialAccount = CRM_Utils_Array::value('isDeleted', $params) ? 'Premiums Inventory Account is' : 'Cost of Sales Account is'; + $fromFinancialAccount = CRM_Utils_Array::value('isDeleted', $params) ? 'Cost of Sales Account is': 'Premiums Inventory Account is'; + $accountRelationship = array_flip($accountRelationship); + $financialtrxn = array( + 'to_financial_account_id' => $financialAccountType[$accountRelationship[$toFinancialAccount]], + 'from_financial_account_id' => $financialAccountType[$accountRelationship[$fromFinancialAccount]], + 'trxn_date' => date('YmdHis'), + 'total_amount' => CRM_Utils_Array::value('cost', $params) ? $params['cost'] : 0, + 'currency' => CRM_Utils_Array::value('currency', $params), + 'status_id' => array_search('Completed', $contributionStatuses) + ); + $trxnEntityTable['entity_table'] = 'civicrm_contribution'; + $trxnEntityTable['entity_id'] = $params['contributionId']; + CRM_Core_BAO_FinancialTrxn::create($financialtrxn, $trxnEntityTable); + } + + if (CRM_Utils_Array::value('oldPremium', $params)) { + $premiumParams = array( + 'id' => $params['oldPremium']['product_id'] + ); + $productDetails = array(); + CRM_Contribute_BAO_ManagePremiums::retrieve($premiumParams, $productDetails); + $params = array( + 'cost' => CRM_Utils_Array::value('cost', $productDetails), + 'currency' => CRM_Utils_Array::value('currency', $productDetails), + 'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $productDetails), + 'contributionId' => $params['oldPremium']['contribution_id'], + 'isDeleted' => TRUE + ); + CRM_Core_BAO_FinancialTrxn::createPremiumTrxn($params); + } + } + /** + * create financial trxn and items when fee is charged + * + * @params params to create trxn entries + * + * @access public + * @static + */ + + static function recordFees($params) { + $expenseTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Expense Account is' ")); + $domainId = CRM_Core_Config::domainID(); + $amount = 0; + if (CRM_Utils_Array::value('prevContribution', $params)) { + $amount = $params['prevContribution']->fee_amount; + } + $amount = $params['fee_amount'] - $amount; + $financialAccount = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $expenseTypeId); + $params['trxnParams']['from_financial_account_id'] = $params['to_financial_account_id']; + $params['trxnParams']['to_financial_account_id'] = $financialAccount; + $params['trxnParams']['total_amount'] = $amount; + $params['trxnParams']['fee_amount'] = + $params['trxnParams']['net_amount'] = 0; + $params['trxnParams']['status_id'] = CRM_Core_OptionGroup::getValue('contribution_status','Completed','name'); + $params['trxnParams']['contribution_id'] = isset($params['contribution']->id) ? $params['contribution']->id : $params['contribution_id']; + $trxn = self::create($params['trxnParams']); + if (!CRM_Utils_Array::value('entity_id', $params)) { + $financialTrxnID = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($params['trxnParams']['contribution_id'], 'DESC'); + $params['entity_id'] = $financialTrxnID['financialTrxnId']; + } + $fItemParams = + array( + 'financial_account_id' => $financialAccount, + 'contact_id' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', $domainId, 'contact_id'), + 'created_date' => date('YmdHis'), + 'transaction_date' => date('YmdHis'), + 'amount' => $amount, + 'description' => 'Fee', + 'status_id' => CRM_Core_OptionGroup::getValue('financial_item_status','Paid','name'), + 'entity_table' => 'civicrm_financial_trxn', + 'entity_id' => $params['entity_id'], + 'currency' => $params['trxnParams']['currency'], + ); + $trxnIDS['id'] = $trxn->id; + $financialItem = CRM_Financial_BAO_FinancialItem::create($fItemParams, NULL, $trxnIDS); + } +} + diff --git a/CRM/Core/BAO/IM.php b/CRM/Core/BAO/IM.php new file mode 100644 index 0000000000..221a8f5682 --- /dev/null +++ b/CRM/Core/BAO/IM.php @@ -0,0 +1,170 @@ +copyValues($params); + $im->save(); + + CRM_Utils_Hook::post($hook, 'IM', $im->id, $im); + return $im; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array entityBlock input parameters to find object + * + * @return boolean + * @access public + * @static + */ + static function &getValues($entityBlock) { + return CRM_Core_BAO_Block::getValues('im', $entityBlock); + } + + /** + * Get all the ims for a specified contact_id, with the primary im being first + * + * @param int $id the contact id + * + * @return array the array of im details + * @access public + * @static + */ + static function allIMs($id, $updateBlankLocInfo = FALSE) { + if (!$id) { + return NULL; + } + + $query = " +SELECT civicrm_im.name as im, civicrm_location_type.name as locationType, civicrm_im.is_primary as is_primary, +civicrm_im.id as im_id, civicrm_im.location_type_id as locationTypeId, +civicrm_im.provider_id as providerId +FROM civicrm_contact +LEFT JOIN civicrm_im ON ( civicrm_im.contact_id = civicrm_contact.id ) +LEFT JOIN civicrm_location_type ON ( civicrm_im.location_type_id = civicrm_location_type.id ) +WHERE + civicrm_contact.id = %1 +ORDER BY + civicrm_im.is_primary DESC, im_id ASC "; + $params = array(1 => array($id, 'Integer')); + + $ims = $values = array(); + $dao = CRM_Core_DAO::executeQuery($query, $params); + $count = 1; + while ($dao->fetch()) { + $values = array( + 'locationType' => $dao->locationType, + 'is_primary' => $dao->is_primary, + 'id' => $dao->im_id, + 'name' => $dao->im, + 'locationTypeId' => $dao->locationTypeId, + 'providerId' => $dao->providerId, + ); + + if ($updateBlankLocInfo) { + $ims[$count++] = $values; + } + else { + $ims[$dao->im_id] = $values; + } + } + return $ims; + } + + /** + * Get all the ims for a specified location_block id, with the primary im being first + * + * @param array $entityElements the array containing entity_id and + * entity_table name + * + * @return array the array of im details + * @access public + * @static + */ + static function allEntityIMs(&$entityElements) { + if (empty($entityElements)) { + return NULL; + } + + + $entityId = $entityElements['entity_id']; + $entityTable = $entityElements['entity_table']; + + + $sql = "SELECT cim.name as im, ltype.name as locationType, cim.is_primary as is_primary, cim.id as im_id, cim.location_type_id as locationTypeId +FROM civicrm_loc_block loc, civicrm_im cim, civicrm_location_type ltype, {$entityTable} ev +WHERE ev.id = %1 +AND loc.id = ev.loc_block_id +AND cim.id IN (loc.im_id, loc.im_2_id) +AND ltype.id = cim.location_type_id +ORDER BY cim.is_primary DESC, im_id ASC "; + + $params = array(1 => array($entityId, 'Integer')); + + $ims = array(); + $dao = CRM_Core_DAO::executeQuery($sql, $params); + while ($dao->fetch()) { + $ims[$dao->im_id] = array( + 'locationType' => $dao->locationType, + 'is_primary' => $dao->is_primary, + 'id' => $dao->im_id, + 'name' => $dao->im, + 'locationTypeId' => $dao->locationTypeId, + ); + } + return $ims; + } +} + diff --git a/CRM/Core/BAO/Job.php b/CRM/Core/BAO/Job.php new file mode 100644 index 0000000000..b503ad9069 --- /dev/null +++ b/CRM/Core/BAO/Job.php @@ -0,0 +1,146 @@ +copyValues($params); + return $job->save(); + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_DAO_Job object on success, null otherwise + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + $job = new CRM_Core_DAO_Job(); + $job->copyValues($params); + if ($job->find(TRUE)) { + CRM_Core_DAO::storeValues($job, $defaults); + return $job; + } + return NULL; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * + * @access public + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_Job', $id, 'is_active', $is_active); + } + + /** + * Function to delete scheduled job + * + * @param int $jobId ID of the job to be deleted. + * + * @access public + * @static + */ + static function del($jobID) { + if (!$jobID) { + CRM_Core_Error::fatal(ts('Invalid value passed to delete function')); + } + + $dao = new CRM_Core_DAO_Job(); + $dao->id = $jobID; + if (!$dao->find(TRUE)) { + return NULL; + } + + if ($dao->delete()) { + return TRUE; + } + } + + /** + * Trim job table on a regular basis to keep it at a good size + * + * CRM-10513 + */ + static function cleanup($maxEntriesToKeep = 1000, $minDaysToKeep = 30) { + // Prevent the job log from getting too big + // For now, keep last minDays days and at least maxEntries records + $query = 'SELECT COUNT(*) FROM civicrm_job_log'; + $count = CRM_Core_DAO::singleValueQuery($query); + + if ( $count <= $maxEntriesToKeep) { + return; + } + + $count = $count - $maxEntriesToKeep; + + $query = "DELETE FROM civicrm_job_log WHERE run_time < SUBDATE(NOW(), $minDaysToKeep) LIMIT $count"; + CRM_Core_DAO::executeQuery($query); + } + +} diff --git a/CRM/Core/BAO/LabelFormat.php b/CRM/Core/BAO/LabelFormat.php new file mode 100644 index 0000000000..08f8ac64dd --- /dev/null +++ b/CRM/Core/BAO/LabelFormat.php @@ -0,0 +1,521 @@ + array( + // Paper size: names defined in option_value table (option_group = 'paper_size') + 'name' => 'paper-size', + 'type' => CRM_Utils_Type::T_STRING, + 'default' => 'letter', + ), + 'orientation' => array( + // Paper orientation: 'portrait' or 'landscape' + 'name' => 'orientation', + 'type' => CRM_Utils_Type::T_STRING, + 'default' => 'portrait', + ), + 'font-name' => array( + // Font name: 'courier', 'helvetica', 'times' + 'name' => 'font-name', + 'type' => CRM_Utils_Type::T_STRING, + 'default' => 'helvetica', + ), + 'font-size' => array( + // Font size: always in points + 'name' => 'font-size', + 'type' => CRM_Utils_Type::T_INT, + 'default' => 8, + ), + 'font-style' => array( + // Font style: 'B' bold, 'I' italic, 'BI' bold+italic + 'name' => 'font-style', + 'type' => CRM_Utils_Type::T_STRING, + 'default' => '', + ), + 'NX' => array( + // Number of labels horizontally + 'name' => 'NX', + 'type' => CRM_Utils_Type::T_INT, + 'default' => 3, + ), + 'NY' => array( + // Number of labels vertically + 'name' => 'NY', + 'type' => CRM_Utils_Type::T_INT, + 'default' => 10, + ), + 'metric' => array( + // Unit of measurement for all of the following fields + 'name' => 'metric', + 'type' => CRM_Utils_Type::T_STRING, + 'default' => 'mm', + ), + 'lMargin' => array( + // Left margin + 'name' => 'lMargin', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 4.7625, + ), + 'tMargin' => array( + // Right margin + 'name' => 'tMargin', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 12.7, + ), + 'SpaceX' => array( + // Horizontal space between two labels + 'name' => 'SpaceX', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 3.96875, + ), + 'SpaceY' => array( + // Vertical space between two labels + 'name' => 'SpaceY', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 0, + ), + 'width' => array( + // Width of label + 'name' => 'width', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 65.875, + ), + 'height' => array( + // Height of label + 'name' => 'height', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 25.4, + ), + 'lPadding' => array( + // Space between text and left edge of label + 'name' => 'lPadding', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 5.08, + ), + 'tPadding' => array( + // Space between text and top edge of label + 'name' => 'tPadding', + 'type' => CRM_Utils_Type::T_FLOAT, + 'metric' => TRUE, + 'default' => 5.08, + ), + ); + + /** + * Get page orientations recognized by the DOMPDF package used to create PDF letters. + * + * @param void + * + * @return array array of page orientations + * @access public + */ + function getPageOrientations() { + return array( + 'portrait' => ts('Portrait'), + 'landscape' => ts('Landscape'), + ); + } + + /** + * Get font names supported by the TCPDF package used to create PDF labels. + * + * @param void + * + * @return array array of font names + * @access public + */ + function getFontNames() { + $label = new CRM_Utils_PDF_Label(self::getDefaultValues()); + return $label->getFontNames(); + } + + /** + * Get font sizes supported by the TCPDF package used to create PDF labels. + * + * @param void + * + * @return array array of font sizes + * @access public + */ + function getFontSizes() { + return array( + 6 => ts('6 pt'), + 7 => ts('7 pt'), + 8 => ts('8 pt'), + 9 => ts('9 pt'), + 10 => ts('10 pt'), + 11 => ts('11 pt'), + 12 => ts('12 pt'), + 13 => ts('13 pt'), + 14 => ts('14 pt'), + 15 => ts('15 pt'), + ); + } + + /** + * Get measurement units recognized by the TCPDF package used to create PDF labels. + * + * @param void + * + * @return array array of measurement units + * @access public + */ + function getUnits() { + return array( + 'in' => ts('Inches'), + 'cm' => ts('Centimeters'), + 'mm' => ts('Millimeters'), + 'pt' => ts('Points'), + ); + } + + /** + * Get Option Group ID for Label Formats + * + * @param void + * + * @return int Group ID (null if Group ID doesn't exist) + * @access private + */ + private function _getGid() { + if (!self::$_gid) { + self::$_gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'label_format', 'id', 'name'); + if (!self::$_gid) { + CRM_Core_Error::fatal(ts('Label Format Option Group not found in database.')); + } + } + return self::$_gid; + } + + /** + * Add ordering fields to Label Format list + * + * @param array (reference) $list List of Label Formats + * @param string $returnURL URL of page calling this function + * + * @return array (reference) List of Label Formats + * @static + * @access public + */ + static function addOrder(&$list, $returnURL) { + $filter = "option_group_id = " . self::_getGid(); + CRM_Utils_Weight::addOrder($list, 'CRM_Core_DAO_OptionValue', 'id', $returnURL, $filter); + } + + /** + * Retrieve list of Label Formats. + * + * @param bool $namesOnly return simple list of names + * + * @return array (reference) label format list + * @static + * @access public + */ + static function &getList($namesOnly = FALSE) { + static $list = array(); + if (self::_getGid()) { + // get saved label formats from Option Value table + $dao = new CRM_Core_DAO_OptionValue(); + $dao->option_group_id = self::_getGid(); + $dao->is_active = 1; + $dao->orderBy('weight'); + $dao->find(); + while ($dao->fetch()) { + if ($namesOnly) { + $list[$dao->name] = $dao->label; + } + else { + CRM_Core_DAO::storeValues($dao, $list[$dao->id]); + } + } + } + return $list; + } + + /** + * retrieve the default Label Format values + * + * @param NULL + * + * @return array Name/value pairs containing the default Label Format values. + * @static + * @access public + */ + static function &getDefaultValues() { + $params = array('is_active' => 1, 'is_default' => 1); + $defaults = array(); + if (!self::retrieve($params, $defaults)) { + foreach (self::$optionValueFields as $name => $field) { + $defaults[$name] = $field['default']; + } + $filter = array('option_group_id' => self::_getGid()); + $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_OptionValue', $filter); + } + return $defaults; + } + + /** + * Get Label Format from the DB + * + * @param string $field Field name to search by + * @param int $val Field value to search for + * + * @return array $values (reference) associative array of name/value pairs + * @access public + */ + static function &getLabelFormat($field, $val) { + $params = array('is_active' => 1, $field => $val); + $labelFormat = array(); + if (self::retrieve($params, $labelFormat)) { + return $labelFormat; + } + else { + return self::getDefaultValues(); + } + } + + /** + * Get Label Format by Name + * + * @param int $name Label format name. Empty = get default label format + * + * @return array $values (reference) associative array of name/value pairs + * @access public + */ + static function &getByName($name) { + return self::getLabelFormat('name', $name); + } + + /** + * Get Label Format by ID + * + * @param int $id label format id. 0 = get default label format + * + * @return array $values (reference) associative array of name/value pairs + * @access public + */ + static function &getById($id) { + return self::getLabelFormat('id', $id); + } + + /** + * Get Label Format field from associative array + * + * @param string $field name of a label format field + * @param array (reference) $values associative array of name/value pairs containing + * label format field selections + * + * @return value + * @access public + * @static + */ + static function getValue($field, &$values, $default = NULL) { + if (array_key_exists($field, self::$optionValueFields)) { + switch (self::$optionValueFields[$field]['type']) { + case CRM_Utils_Type::T_INT: + return (int)CRM_Utils_Array::value($field, $values, $default); + + case CRM_Utils_Type::T_FLOAT: + // Round float values to three decimal places and trim trailing zeros. + // Add a leading zero to values less than 1. + $f = sprintf('%05.3f', $values[$field]); + $f = rtrim($f, '0'); + $f = rtrim($f, '.'); + return (float)(empty($f) ? '0' : $f); + } + return CRM_Utils_Array::value($field, $values, $default); + } + return $default; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * label id. It also stores all the retrieved values in the default array. + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $values (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_DAO_OptionValue object + * @access public + * @static + */ + static function retrieve(&$params, &$values) { + $optionValue = new CRM_Core_DAO_OptionValue(); + $optionValue->copyValues($params); + $optionValue->option_group_id = self::_getGid(); + if ($optionValue->find(TRUE)) { + // Extract fields that have been serialized in the 'value' column of the Option Value table. + $values = json_decode($optionValue->value, TRUE); + // Add any new fields that don't yet exist in the saved values. + foreach (self::$optionValueFields as $name => $field) { + if (!isset($values[$name])) { + $values[$name] = $field['default']; + if ($field['metric']) { + $values[$name] = CRM_Utils_PDF_Utils::convertMetric($field['default'], + self::$optionValueFields['metric']['default'], + $values['metric'], 3 + ); + } + } + } + // Add fields from the OptionValue base class + CRM_Core_DAO::storeValues($optionValue, $values); + return $optionValue; + } + return NULL; + } + + /** + * Return the name of the group for customized labels + * + * @param void + * + * @return void + * @access public + */ + function customGroupName() { + return ts('Custom'); + } + + /** + * Save the Label Format in the DB + * + * @param array (reference) $values associative array of name/value pairs + * @param int $id id of the database record (null = new record) + * + * @return void + * @access public + */ + function saveLabelFormat(&$values, $id = NULL) { + // get the Option Group ID for Label Formats (create one if it doesn't exist) + $group_id = self::_getGid(); + + // clear other default if this is the new default label format + if ($values['is_default']) { + $query = "UPDATE civicrm_option_value SET is_default = 0 WHERE option_group_id = $group_id"; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + if ($id) { + // fetch existing record + $this->id = $id; + if ($this->find()) { + $this->fetch(); + } + } + else { + // new record + $list = self::getList(TRUE); + $cnt = 1; + while (array_key_exists("custom_$cnt", $list)) $cnt++; + $values['name'] = "custom_$cnt"; + $values['grouping'] = self::customGroupName(); + } + // copy the supplied form values to the corresponding Option Value fields in the base class + foreach ($this->fields() as $name => $field) { + $this->$name = trim(CRM_Utils_Array::value($name, $values, $this->$name)); + if (empty($this->$name)) { + $this->$name = 'null'; + } + } + $this->id = $id; + $this->option_group_id = $group_id; + $this->is_active = 1; + + // serialize label format fields into a single string to store in the 'value' column of the Option Value table + $v = json_decode($this->value, TRUE); + foreach (self::$optionValueFields as $name => $field) { + $v[$name] = self::getValue($name, $values, $v[$name]); + } + $this->value = json_encode($v); + + // make sure serialized array will fit in the 'value' column + $attribute = CRM_Core_DAO::getAttribute('CRM_Core_BAO_LabelFormat', 'value'); + if (strlen($this->value) > $attribute['maxlength']) { + CRM_Core_Error::fatal(ts('Label Format does not fit in database.')); + } + $this->save(); + + // fix duplicate weights + $filter = array('option_group_id' => self::_getGid()); + CRM_Utils_Weight::correctDuplicateWeights('CRM_Core_DAO_OptionValue', $filter); + } + + /** + * Function to delete a Label Format + * + * @param int $id ID of the label format to be deleted. + * + * @access public + * @static + */ + static function del($id) { + if ($id) { + $dao = new CRM_Core_DAO_OptionValue(); + $dao->id = $id; + if ($dao->find(TRUE)) { + if ($dao->option_group_id == self::_getGid()) { + $filter = array('option_group_id' => self::_getGid()); + CRM_Utils_Weight::delWeight('CRM_Core_DAO_OptionValue', $id, $filter); + $dao->delete(); + return; + } + } + } + CRM_Core_Error::fatal(ts('Invalid value passed to delete function.')); + } +} + diff --git a/CRM/Core/BAO/Location.php b/CRM/Core/BAO/Location.php new file mode 100644 index 0000000000..b008ad1a5a --- /dev/null +++ b/CRM/Core/BAO/Location.php @@ -0,0 +1,389 @@ + $params['entity_table'], + 'entity_id' => $params['entity_id'], + ); + + $location['id'] = self::createLocBlock($location, $entityElements); + } + else { + // when we come from a form which displays all the location elements (like the edit form or the inline block + // elements, we can skip the below check. The below check adds quite a feq queries to an already overloaded + // form + if (!CRM_Utils_Array::value('updateBlankLocInfo', $params, FALSE)) { + // make sure contact should have only one primary block, CRM-5051 + self::checkPrimaryBlocks(CRM_Utils_Array::value('contact_id', $params)); + } + } + + return $location; + } + + /** + * Creates the entry in the civicrm_loc_block + * + */ + static function createLocBlock(&$location, &$entityElements) { + $locId = self::findExisting($entityElements); + $locBlock = array(); + + if ($locId) { + $locBlock['id'] = $locId; + } + + foreach (array( + 'phone', 'email', 'im', 'address') as $loc) { + $locBlock["{$loc}_id"] = CRM_Utils_Array::value(0, $location["$loc"]) ? $location["$loc"][0]->id : NULL; + $locBlock["{$loc}_2_id"] = CRM_Utils_Array::value(1, $location["$loc"]) ? $location["$loc"][1]->id : NULL; + } + + $countNull = 0; + foreach ($locBlock as $key => $block) { + if (empty($locBlock[$key])) { + $locBlock[$key] = 'null'; + $countNull++; + } + } + + if (count($locBlock) == $countNull) { + // implies nothing is set. + return NULL; + } + + $locBlockInfo = self::addLocBlock($locBlock); + return $locBlockInfo->id; + } + + /** + * takes an entity array and finds the existing location block + * @access public + * @static + */ + static function findExisting($entityElements) { + $eid = $entityElements['entity_id']; + $etable = $entityElements['entity_table']; + $query = " +SELECT e.loc_block_id as locId +FROM {$etable} e +WHERE e.id = %1"; + + $params = array(1 => array($eid, 'Integer')); + $dao = CRM_Core_DAO::executeQuery($query, $params); + while ($dao->fetch()) { + $locBlockId = $dao->locId; + } + return $locBlockId; + } + + /** + * takes an associative array and adds location block + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return object CRM_Core_BAO_locBlock object on success, null otherwise + * @access public + * @static + */ + static function addLocBlock(&$params) { + $locBlock = new CRM_Core_DAO_LocBlock(); + + $locBlock->copyValues($params); + + return $locBlock->save(); + } + + /** + * This function deletes the Location Block + * + * @param int $locBlockId id of the Location Block + * + * @return void + * @access public + * @static + */ + public static function deleteLocBlock($locBlockId) { + if (!$locBlockId) { + return; + } + + $locBlock = new CRM_Core_DAO_LocBlock(); + $locBlock->id = $locBlockId; + + $locBlock->find(TRUE); + + //resolve conflict of having same ids for multiple blocks + $store = array( + 'IM_1' => $locBlock->im_id, + 'IM_2' => $locBlock->im_2_id, + 'Email_1' => $locBlock->email_id, + 'Email_2' => $locBlock->email_2_id, + 'Phone_1' => $locBlock->phone_id, + 'Phone_2' => $locBlock->phone_2_id, + 'Address_1' => $locBlock->address_id, + 'Address_2' => $locBlock->address_2_id, + ); + $locBlock->delete(); + foreach ($store as $daoName => $id) { + if ($id) { + $daoName = substr($daoName, 0, -2); + eval('$dao = new CRM_Core_DAO_' . $daoName . '( );'); + $dao->id = $id; + $dao->find(TRUE); + $dao->delete(); + $dao->free(); + } + } + } + + /** + * Check if there is data to create the object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return boolean + * @access public + * @static + */ + static function dataExists(&$params) { + // return if no data present + $dataExists = FALSE; + foreach (self::$blocks as $block) { + if (array_key_exists($block, $params)) { + $dataExists = TRUE; + break; + } + } + + return $dataExists; + } + + /** + * Given the list of params in the params array, fetch the object + * and store the values in the values array + * + * @param array $params input parameters to find object + * @param array $values output values of the object + * + * @return array array of objects(CRM_Core_BAO_Location) + * @access public + * @static + */ + static function &getValues($entityBlock, $microformat = FALSE) { + if (empty($entityBlock)) { + return NULL; + } + + $name_map = array( + 'im' => 'IM', + 'openid' => 'OpenID', + ); + + //get all the blocks for this contact + foreach (self::$blocks as $block) { + if (array_key_exists($block, $name_map)) { + $name = $name_map[$block]; + } + else { + $name = ucfirst($block); + } + eval('$blocks[$block] = CRM_Core_BAO_' . $name . '::getValues( $entityBlock, $microformat );'); + } + return $blocks; + } + + /** + * Delete all the block associated with the location + * + * @param int $contactId contact id + * @param int $locationTypeId id of the location to delete + * + * @return void + * @access public + * @static + */ + static function deleteLocationBlocks($contactId, $locationTypeId) { + // ensure that contactId has a value + if (empty($contactId) || + !CRM_Utils_Rule::positiveInteger($contactId) + ) { + CRM_Core_Error::fatal(); + } + + if (empty($locationTypeId) || + !CRM_Utils_Rule::positiveInteger($locationTypeId) + ) { + // so we only delete the blocks which DO NOT have a location type Id + // CRM-3581 + $locationTypeId = 'null'; + } + + static $blocks = array('Address', 'Phone', 'IM', 'OpenID', 'Email'); + + $params = array('contact_id' => $contactId, 'location_type_id' => $locationTypeId); + foreach ($blocks as $name) { + CRM_Core_BAO_Block::blockDelete($name, $params); + } + } + + /* Function to copy or update location block. + * + * @param int $locBlockId location block id. + * @param int $updateLocBlockId update location block id + * @return int newly created/updated location block id. + */ + static function copyLocBlock($locBlockId, $updateLocBlockId = NULL) { + //get the location info. + $defaults = $updateValues = array(); + $locBlock = array('id' => $locBlockId); + CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_LocBlock', $locBlock, $defaults); + + if ($updateLocBlockId) { + //get the location info for update. + $copyLocationParams = array('id' => $updateLocBlockId); + CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_LocBlock', $copyLocationParams, $updateValues); + foreach ($updateValues as $key => $value) { + if ($key != 'id') { + $copyLocationParams[$key] = 'null'; + } + } + } + + //copy all location blocks (email, phone, address, etc) + foreach ($defaults as $key => $value) { + if ($key != 'id') { + $tbl = explode("_", $key); + $name = ucfirst($tbl[0]); + $updateParams = NULL; + if ($updateId = CRM_Utils_Array::value($key, $updateValues)) { + $updateParams = array('id' => $updateId); + } + + $copy = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_' . $name, array('id' => $value), $updateParams); + $copyLocationParams[$key] = $copy->id; + } + } + + $copyLocation = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_LocBlock', + array('id' => $locBlock['id']), + $copyLocationParams + ); + return $copyLocation->id; + } + + /** + * If contact has data for any location block, make sure + * contact should have only one primary block, CRM-5051 + * + * @param int $contactId - contact id + * + * @access public + * @static + */ + static function checkPrimaryBlocks($contactId) { + if (!$contactId) { + return; + } + + // get the loc block ids. + $primaryLocBlockIds = CRM_Contact_BAO_Contact::getLocBlockIds($contactId, array('is_primary' => 1)); + $nonPrimaryBlockIds = CRM_Contact_BAO_Contact::getLocBlockIds($contactId, array('is_primary' => 0)); + + foreach (array( + 'Email', 'IM', 'Phone', 'Address', 'OpenID') as $block) { + $name = strtolower($block); + if (array_key_exists($name, $primaryLocBlockIds) && + !CRM_Utils_System::isNull($primaryLocBlockIds[$name]) + ) { + if (count($primaryLocBlockIds[$name]) > 1) { + // keep only single block as primary. + $primaryId = array_pop($primaryLocBlockIds[$name]); + $resetIds = "(" . implode(',', $primaryLocBlockIds[$name]) . ")"; + // reset all primary except one. + CRM_Core_DAO::executeQuery("UPDATE civicrm_$name SET is_primary = 0 WHERE id IN $resetIds"); + } + } + elseif (array_key_exists($name, $nonPrimaryBlockIds) && + !CRM_Utils_System::isNull($nonPrimaryBlockIds[$name]) + ) { + // data exists and no primary block - make one primary. + CRM_Core_DAO::setFieldValue("CRM_Core_DAO_" . $block, + array_pop($nonPrimaryBlockIds[$name]), 'is_primary', 1 + ); + } + } + } +} + diff --git a/CRM/Core/BAO/LocationType.php b/CRM/Core/BAO/LocationType.php new file mode 100644 index 0000000000..390acc3459 --- /dev/null +++ b/CRM/Core/BAO/LocationType.php @@ -0,0 +1,178 @@ +copyValues($params); + if ($locationType->find(TRUE)) { + CRM_Core_DAO::storeValues($locationType, $defaults); + return $locationType; + } + return NULL; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * + * @access public + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_LocationType', $id, 'is_active', $is_active); + } + + /** + * retrieve the default location_type + * + * @param NULL + * + * @return object The default location type object on success, + * null otherwise + * @static + * @access public + */ + static function &getDefault() { + if (self::$_defaultLocationType == NULL) { + $params = array('is_default' => 1); + $defaults = array(); + self::$_defaultLocationType = self::retrieve($params, $defaults); + } + return self::$_defaultLocationType; + } + + /* + * Get ID of billing location type + * @return integer + */ + static function getBilling() { + if (self::$_billingLocationType == NULL) { + $locationTypes = CRM_Core_PseudoConstant::locationType(); + self::$_billingLocationType = array_search('Billing', $locationTypes); + } + return self::$_billingLocationType; + } + + /** + * Function to add a Location Type + * + * @param array $params reference array contains the values submitted by the form + * @param array $ids reference array contains the id + * + * @access public + * @static + * + * @return object + */ + static function create(&$params) { + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE); + $params['is_reserved'] = CRM_Utils_Array::value('is_reserved', $params, FALSE); + + // action is taken depending upon the mode + $locationType = new CRM_Core_DAO_LocationType(); + $locationType->copyValues($params); + + if ($params['is_default']) { + $query = "UPDATE civicrm_location_type SET is_default = 0"; + CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); + } + + $locationType->save(); + return $locationType; + } + + /** + * Function to delete location Types + * + * @param int $locationTypeId ID of the location type to be deleted. + * + * @access public + * @static + */ + static function del($locationTypeId) { + $entity = array('address', 'phone', 'email', 'im'); + //check dependencies + foreach ($entity as $key) { + if ($key == 'im') { + $name = strtoupper($key); + } + else { + $name = ucfirst($key); + } + require_once (str_replace('_', DIRECTORY_SEPARATOR, 'CRM_Core_DAO_' . $name) . ".php"); + eval('$object = new CRM_Core_DAO_' . $name . '( );'); + $object->location_type_id = $locationTypeId; + $object->delete(); + } + + $locationType = new CRM_Core_DAO_LocationType(); + $locationType->id = $locationTypeId; + $locationType->delete(); + } +} + diff --git a/CRM/Core/BAO/Log.php b/CRM/Core/BAO/Log.php new file mode 100644 index 0000000000..15772e8c65 --- /dev/null +++ b/CRM/Core/BAO/Log.php @@ -0,0 +1,182 @@ +entity_table = $table; + $log->entity_id = $id; + $log->orderBy('modified_date desc'); + $log->limit(1); + $result = CRM_Core_DAO::$_nullObject; + if ($log->find(TRUE)) { + list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($log->modified_id); + $result = array( + 'id' => $log->modified_id, + 'name' => $displayName, + 'image' => $contactImage, + 'date' => $log->modified_date, + ); + } + return $result; + } + + /** + * add log to civicrm_log table + * + * @param array $params array of name-value pairs of log table. + * + * @static + */ + static function add(&$params) { + + $log = new CRM_Core_DAO_Log(); + $log->copyValues($params); + $log->save(); + } + + static function register($contactID, + $tableName, + $tableID, + $userID = NULL + ) { + if (!self::$_processed) { + self::$_processed = array(); + } + + if (!$userID) { + $session = CRM_Core_Session::singleton(); + $userID = $session->get('userID'); + } + + if (!$userID) { + $userID = $contactID; + } + + if (!$userID) { + return; + } + + $log = new CRM_Core_DAO_Log(); + $log->id = NULL; + + if (isset(self::$_processed[$contactID])) { + if (isset(self::$_processed[$contactID][$userID])) { + $log->id = self::$_processed[$contactID][$userID]; + } + self::$_processed[$contactID][$userID] = 1; + } + else { + self::$_processed[$contactID] = array($userID => 1); + } + + $logData = "$tableName,$tableID"; + if (!$log->id) { + $log->entity_table = 'civicrm_contact'; + $log->entity_id = $contactID; + $log->modified_id = $userID; + $log->modified_date = date("YmdHis"); + $log->data = $logData; + $log->save(); + } + else { + $query = " +UPDATE civicrm_log + SET data = concat( data, ':$logData' ) + WHERE id = {$log->id} +"; + CRM_Core_DAO::executeQuery($query); + } + + self::$_processed[$contactID][$userID] = $log->id; + } + + /** + * Function to get log record count for a Contact + * + * @param int $contactId Contact ID + * + * @return int count of log records + * @access public + * @static + */ + static function getContactLogCount($contactID) { + $query = "SELECT count(*) FROM civicrm_log + WHERE civicrm_log.entity_table = 'civicrm_contact' AND civicrm_log.entity_id = {$contactID}"; + return CRM_Core_DAO::singleValueQuery($query); + } + + /** + * Function for find out whether to use logging schema entries for contact + * summary, instead of normal log entries. + * + * @return int report id of Contact Logging Report (Summary) / false + * @access public + * @static + */ + static function useLoggingReport() { + // first check if logging is enabled + $config = CRM_Core_Config::singleton(); + if (!$config->logging) { + return FALSE; + } + + $loggingSchema = new CRM_Logging_Schema(); + + if ($loggingSchema->isEnabled()) { + $params = array('report_id' => 'logging/contact/summary'); + $instance = array(); + CRM_Report_BAO_Instance::retrieve($params, $instance); + + if (!empty($instance) && + (!CRM_Utils_Array::value('permission', $instance) || + (CRM_Utils_Array::value('permission', $instance) && CRM_Core_Permission::check($instance['permission'])) + ) + ) { + return $instance['id']; + } + } + + return FALSE; + } +} + diff --git a/CRM/Core/BAO/MailSettings.php b/CRM/Core/BAO/MailSettings.php new file mode 100644 index 0000000000..e718041715 --- /dev/null +++ b/CRM/Core/BAO/MailSettings.php @@ -0,0 +1,205 @@ +is_default = 1; + $dao->domain_id = CRM_Core_Config::domainID(); + $dao->find(TRUE); + } + return $dao; + } + + /** + * Return the domain from the default set of settings + * + * @return string default domain + */ + static function defaultDomain() { + return self::defaultDAO()->domain; + } + + /** + * Return the localpart from the default set of settings + * + * @return string default localpart + */ + static function defaultLocalpart() { + return self::defaultDAO()->localpart; + } + + /** + * Return the return path from the default set of settings + * + * @return string default return path + */ + static function defaultReturnPath() { + return self::defaultDAO()->return_path; + } + + /** + * Return the "include message ID" flag from the default set of settings. + * + * @return boolean default include message ID + */ + static function includeMessageId() { + return CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, + 'include_message_id', + NULL, + FALSE + ); + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * mail settings id. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_BAO_MailSettings object + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + $mailSettings = new CRM_Core_DAO_MailSettings(); + $mailSettings->copyValues($params); + + $result = NULL; + if ($mailSettings->find(TRUE)) { + CRM_Core_DAO::storeValues($mailSettings, $defaults); + $result = $mailSettings; + } + + return $result; + } + + /** + * function to add new mail Settings. + * + * @param array $params reference array contains the values submitted by the form + * + * @access public + * @static + * + * @return object + */ + static function add(&$params) { + $result = NULL; + if (empty($params)) { + return $result; + } + + $params['is_ssl'] = CRM_Utils_Array::value('is_ssl', $params, FALSE); + $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE); + + //handle is_default. + if ($params['is_default']) { + $query = 'UPDATE civicrm_mail_settings SET is_default = 0 WHERE domain_id = %1'; + $queryParams = array(1 => array(CRM_Core_Config::domainID(), 'Integer')); + CRM_Core_DAO::executeQuery($query, $queryParams); + } + + $mailSettings = new CRM_Core_DAO_MailSettings(); + $mailSettings->copyValues($params); + $result = $mailSettings->save(); + + return $result; + } + + /** + * takes an associative array and creates a mail settings object + * + * @param array $params (reference ) an assoc array of name/value pairs + * + * @return object CRM_Core_BAO_MailSettings object + * @access public + * @static + */ + static function &create(&$params) { + $transaction = new CRM_Core_Transaction(); + + $mailSettings = self::add($params); + if (is_a($mailSettings, 'CRM_Core_Error')) { + $mailSettings->rollback(); + return $mailSettings; + } + + $transaction->commit(); + + return $mailSettings; + } + + /** + * Function to delete the mail settings. + * + * @param int $id mail settings id + * + * @access public + * @static + * + */ + static function deleteMailSettings($id) { + $results = NULL; + $transaction = new CRM_Core_Transaction(); + + $mailSettings = new CRM_Core_DAO_MailSettings(); + $mailSettings->id = $id; + $results = $mailSettings->delete(); + + $transaction->commit(); + + return $results; + } +} + diff --git a/CRM/Core/BAO/Mapping.php b/CRM/Core/BAO/Mapping.php new file mode 100644 index 0000000000..ed870f9bf4 --- /dev/null +++ b/CRM/Core/BAO/Mapping.php @@ -0,0 +1,1213 @@ +copyValues($params); + if ($mapping->find(TRUE)) { + CRM_Core_DAO::storeValues($mapping, $defaults); + return $mapping; + } + return NULL; + } + + /** + * Function to delete the mapping + * + * @param int $id mapping id + * + * @return boolean + * @access public + * @static + * + */ + static function del($id) { + // delete from mapping_field table + $mappingField = new CRM_Core_DAO_MappingField(); + $mappingField->mapping_id = $id; + $mappingField->find(); + while ($mappingField->fetch()) { + $mappingField->delete(); + } + + // delete from mapping table + $mapping = new CRM_Core_DAO_Mapping(); + $mapping->id = $id; + $mapping->delete(); + CRM_Core_Session::setStatus(ts('Selected mapping has been deleted successfully.'), ts('Deleted'), 'success'); + + return TRUE; + } + + /** + * takes an associative array and creates a contact object + * + * The function extract all the params it needs to initialize the create a + * contact object. the params array could contain additional unused name/value + * pairs + * + * @param array $params (reference) an assoc array of name/value pairs + * + * @return object CRM_Core_DAO_Mapper object on success, otherwise null + * @access public + * @static + */ + static function add(&$params) { + $mapping = new CRM_Core_DAO_Mapping(); + $mapping->copyValues($params); + $mapping->save(); + + return $mapping; + } + + /** + * function to get the list of mappings + * + * @params string $mappingTypeId mapping type id + * + * @return array $mapping array of mapping name + * @access public + * @static + */ + static function getMappings($mappingTypeId) { + $mapping = array(); + $mappingDAO = new CRM_Core_DAO_Mapping(); + $mappingDAO->mapping_type_id = $mappingTypeId; + $mappingDAO->find(); + + while ($mappingDAO->fetch()) { + $mapping[$mappingDAO->id] = $mappingDAO->name; + } + + return $mapping; + } + + /** + * function to get the mapping fields + * + * @params int $mappingId mapping id + * + * @return array $mappingFields array of mapping fields + * @access public + * @static + * + */ + static function getMappingFields($mappingId) { + //mapping is to be loaded from database + $mapping = new CRM_Core_DAO_MappingField(); + $mapping->mapping_id = $mappingId; + $mapping->orderBy('column_number'); + $mapping->find(); + + $mappingName = $mappingLocation = $mappingContactType = $mappingPhoneType = array(); + $mappingImProvider = $mappingRelation = $mappingOperator = $mappingValue = $mappingWebsiteType = array(); + while ($mapping->fetch()) { + $mappingName[$mapping->grouping][$mapping->column_number] = $mapping->name; + $mappingContactType[$mapping->grouping][$mapping->column_number] = $mapping->contact_type; + + if (!empty($mapping->location_type_id)) { + $mappingLocation[$mapping->grouping][$mapping->column_number] = $mapping->location_type_id; + } + + if (!empty($mapping->phone_type_id)) { + $mappingPhoneType[$mapping->grouping][$mapping->column_number] = $mapping->phone_type_id; + } + + // get IM service provider type id from mapping fields + if (!empty($mapping->im_provider_id)) { + $mappingImProvider[$mapping->grouping][$mapping->column_number] = $mapping->im_provider_id; + } + + if (!empty($mapping->website_type_id)) { + $mappingWebsiteType[$mapping->grouping][$mapping->column_number] = $mapping->website_type_id; + } + + if (!empty($mapping->relationship_type_id)) { + $mappingRelation[$mapping->grouping][$mapping->column_number] = "{$mapping->relationship_type_id}_{$mapping->relationship_direction}"; + } + + if (!empty($mapping->operator)) { + $mappingOperator[$mapping->grouping][$mapping->column_number] = $mapping->operator; + } + + if (!empty($mapping->value)) { + $mappingValue[$mapping->grouping][$mapping->column_number] = $mapping->value; + } + } + + return array( + $mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, + $mappingImProvider, $mappingRelation, $mappingOperator, $mappingValue, $mappingWebsiteType, + ); + } + + /** + *function to check Duplicate Mapping Name + * + * @params $nameField string mapping Name + * + * @params $mapTypeId string mapping Type + * + * @return boolean + * + */ + static function checkMapping($nameField, $mapTypeId) { + $mapping = new CRM_Core_DAO_Mapping(); + $mapping->name = $nameField; + $mapping->mapping_type_id = $mapTypeId; + if ($mapping->find(TRUE)) { + return TRUE; + } + else { + return FALSE; + } + } + + /** + * Function returns associated array of elements, that will be passed for search + * + * @params int $smartGroupId smart group id + * + * @return $returnFields associated array of elements + * + * @static + * @public + */ + static function getFormattedFields($smartGroupId) { + $returnFields = array(); + + //get the fields from mapping table + $dao = new CRM_Core_DAO_MappingField(); + $dao->mapping_id = $smartGroupId; + $dao->find(); + while ($dao->fetch()) { + $fldName = $dao->name; + if ($dao->location_type_id) { + $fldName .= "-{$dao->location_type_id}"; + } + if ($dao->phone_type) { + $fldName .= "-{$dao->phone_type}"; + } + $returnFields[$fldName]['value'] = $dao->value; + $returnFields[$fldName]['op'] = $dao->operator; + $returnFields[$fldName]['grouping'] = $dao->grouping; + } + return $returnFields; + } + + /** + * Function to build the mapping form + * + * @params object $form form object + * @params string $mappingType mapping type (Export/Import/Search Builder) + * @params int $mappingId mapping id + * @params mixed $columnCount column count is int for and array for search builder + * @params int $blockCount block count (no of blocks shown) + * + * @return none + * @access public + * @static + */ + static function buildMappingForm(&$form, $mappingType = 'Export', $mappingId = NULL, $columnNo, $blockCount = 3, $exportMode = NULL) { + if ($mappingType == 'Export') { + $name = "Map"; + $columnCount = array('1' => $columnNo); + } + elseif ($mappingType == 'Search Builder') { + $name = "Builder"; + $columnCount = $columnNo; + } + + //get the saved mapping details + + if ($mappingType == 'Export') { + $form->applyFilter('saveMappingName', 'trim'); + + //to save the current mappings + if (!isset($mappingId)) { + $saveDetailsName = ts('Save this field mapping'); + $form->add('text', 'saveMappingName', ts('Name')); + $form->add('text', 'saveMappingDesc', ts('Description')); + } + else { + $form->assign('loadedMapping', $mappingId); + + $params = array('id' => $mappingId); + $temp = array(); + $mappingDetails = CRM_Core_BAO_Mapping::retrieve($params, $temp); + + $form->assign('savedName', $mappingDetails->name); + + $form->add('hidden', 'mappingId', $mappingId); + + $form->addElement('checkbox', 'updateMapping', ts('Update this field mapping'), NULL); + $saveDetailsName = ts('Save as a new field mapping'); + $form->add('text', 'saveMappingName', ts('Name')); + $form->add('text', 'saveMappingDesc', ts('Description')); + } + + $form->addElement('checkbox', 'saveMapping', $saveDetailsName, NULL, array('onclick' => "showSaveDetails(this)")); + $form->addFormRule(array('CRM_Export_Form_Map', 'formRule'), $form->get('mappingTypeId')); + } + elseif ($mappingType == 'Search Builder') { + $form->addElement('submit', 'addBlock', ts('Also include contacts where'), + array('class' => 'submit-link') + ); + } + + $defaults = array(); + $hasLocationTypes = array(); + $hasRelationTypes = array(); + $fields = array(); + + if ($mappingType == 'Export') { + $required = TRUE; + } + elseif ($mappingType == 'Search Builder') { + $required = FALSE; + } + + $contactType = array('Individual', 'Household', 'Organization'); + foreach ($contactType as $value) { + $contactFields = CRM_Contact_BAO_Contact::exportableFields($value, FALSE, $required); + // exclude the address options disabled in the Address Settings + $fields[$value] = CRM_Core_BAO_Address::validateAddressOptions($contactFields); + + if ($mappingType == 'Export') { + $relationships = array(); + $relationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, NULL, NULL, $value); + asort($relationshipTypes); + + foreach ($relationshipTypes as $key => $var) { + list($type) = explode('_', $key); + + $relationships[$key]['title'] = $var; + $relationships[$key]['headerPattern'] = '/' . preg_quote($var, '/') . '/'; + $relationships[$key]['export'] = TRUE; + $relationships[$key]['relationship_type_id'] = $type; + $relationships[$key]['related'] = TRUE; + $relationships[$key]['hasRelationType'] = 1; + } + + if (!empty($relationships)) { + $fields[$value] = array_merge($fields[$value], + array('related' => array('title' => ts('- related contact info -'))), + $relationships + ); + } + } + } + + //get the current employer for mapping. + if ($required) { + $fields['Individual']['current_employer']['title'] = ts('Current Employer'); + } + + // add component fields + $compArray = array(); + + //we need to unset groups, tags, notes for component export + if ($exportMode != CRM_Export_Form_Select::CONTACT_EXPORT) { + foreach (array( + 'groups', 'tags', 'notes') as $value) { + unset($fields['Individual'][$value]); + unset($fields['Household'][$value]); + unset($fields['Organization'][$value]); + } + } + + if ($mappingType == 'Search Builder') { + //build the common contact fields array. + $fields['Contact'] = array(); + foreach ($fields['Individual'] as $key => $value) { + if (CRM_Utils_Array::value($key, $fields['Household']) && + CRM_Utils_Array::value($key, $fields['Organization']) + ) { + $fields['Contact'][$key] = $value; + unset($fields['Organization'][$key], + $fields['Household'][$key], + $fields['Individual'][$key]); + } + } + if (array_key_exists('note', $fields['Contact'])) { + $noteTitle = $fields['Contact']['note']['title']; + $fields['Contact']['note']['title'] = $noteTitle . ': ' . ts('Body and Subject'); + $fields['Contact']['note_body'] = array( 'title' => $noteTitle . ': ' . ts('Body only'), 'name' => 'note_body' ); + $fields['Contact']['note_subject'] = array( 'title' => $noteTitle . ': ' . ts('Subject only'), 'name' => 'note_subject' ); + } + } + + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::CONTRIBUTE_EXPORT)) { + if (CRM_Core_Permission::access('CiviContribute')) { + $fields['Contribution'] = CRM_Contribute_BAO_Contribution::exportableFields(); + unset($fields['Contribution']['contribution_contact_id']); + unset($fields['Contribution']['contribution_status_id']); + $compArray['Contribution'] = ts('Contribution'); + } + } + + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::EVENT_EXPORT)) { + if (CRM_Core_Permission::access('CiviEvent')) { + $fields['Participant'] = CRM_Event_BAO_Participant::exportableFields(); + unset($fields['Participant']['participant_contact_id']); + $compArray['Participant'] = ts('Participant'); + } + } + + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::MEMBER_EXPORT)) { + if (CRM_Core_Permission::access('CiviMember')) { + $fields['Membership'] = CRM_Member_BAO_Membership::getMembershipFields($exportMode); + unset($fields['Membership']['membership_contact_id']); + $compArray['Membership'] = ts('Membership'); + } + } + + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::PLEDGE_EXPORT)) { + if (CRM_Core_Permission::access('CiviPledge')) { + $fields['Pledge'] = CRM_Pledge_BAO_Pledge::exportableFields(); + unset($fields['Pledge']['pledge_contact_id']); + $compArray['Pledge'] = ts('Pledge'); + } + } + + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::CASE_EXPORT)) { + if (CRM_Core_Permission::access('CiviCase')) { + $fields['Case'] = CRM_Case_BAO_Case::exportableFields(); + $compArray['Case'] = ts('Case'); + + $fields['Activity'] = CRM_Activity_BAO_Activity::exportableFields('Case'); + $compArray['Activity'] = ts('Case Activity'); + + unset($fields['Case']['case_contact_id']); + } + } + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::GRANT_EXPORT)) { + if (CRM_Core_Permission::access('CiviGrant')) { + $fields['Grant'] = CRM_Grant_BAO_Grant::exportableFields(); + unset($fields['Grant']['grant_contact_id']); + $compArray['Grant'] = ts('Grant'); + } + } + + if (($mappingType == 'Search Builder') || ($exportMode == CRM_Export_Form_Select::ACTIVITY_EXPORT)) { + $fields['Activity'] = CRM_Activity_BAO_Activity::exportableFields('Activity'); + $compArray['Activity'] = ts('Activity'); + } + + //Contact Sub Type For export + $contactSubTypes = array(); + $subTypes = CRM_Contact_BAO_ContactType::subTypeInfo(); + + foreach ($subTypes as $subType => $val) { + //adding subtype specific relationships CRM-5256 + $csRelationships = array(); + + if ($mappingType == 'Export') { + $subTypeRelationshipTypes = + CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, NULL, NULL, $val['parent'], + FALSE, 'label', TRUE, $subType); + + foreach ($subTypeRelationshipTypes as $key => $var) { + if (!array_key_exists($key, $fields[$val['parent']])) { + list($type) = explode('_', $key); + + $csRelationships[$key]['title'] = $var; + $csRelationships[$key]['headerPattern'] = '/' . preg_quote($var, '/') . '/'; + $csRelationships[$key]['export'] = TRUE; + $csRelationships[$key]['relationship_type_id'] = $type; + $csRelationships[$key]['related'] = TRUE; + $csRelationships[$key]['hasRelationType'] = 1; + } + } + } + + $fields[$subType] = $fields[$val['parent']] + $csRelationships; + + //custom fields for sub type + $subTypeFields = CRM_Core_BAO_CustomField::getFieldsForImport($subType); + $fields[$subType] += $subTypeFields; + + if (!empty($subTypeFields) || !empty($csRelationships)) { + $contactSubTypes[$subType] = $val['label']; + } + } + + unset($subTypes); + + foreach ($fields as $key => $value) { + + foreach ($value as $key1 => $value1) { + //CRM-2676, replacing the conflict for same custom field name from different custom group. + $customGroupName = self::getCustomGroupName($key1); + + if ($customGroupName) { + $relatedMapperFields[$key][$key1] = $mapperFields[$key][$key1] = $customGroupName . ': ' . $value1['title']; + } + else { + $relatedMapperFields[$key][$key1] = $mapperFields[$key][$key1] = $value1['title']; + } + if (isset($value1['hasLocationType'])) { + $hasLocationTypes[$key][$key1] = $value1['hasLocationType']; + } + + if (isset($value1['hasRelationType'])) { + $hasRelationTypes[$key][$key1] = $value1['hasRelationType']; + unset($relatedMapperFields[$key][$key1]); + } + } + + if (array_key_exists('related', $relatedMapperFields[$key])) { + unset($relatedMapperFields[$key]['related']); + } + } + + $mapperKeys = array_keys($mapperFields); + + $locationTypes = CRM_Core_PseudoConstant::locationType(); + + $defaultLocationType = CRM_Core_BAO_LocationType::getDefault(); + + /* FIXME: dirty hack to make the default option show up first. This + * avoids a mozilla browser bug with defaults on dynamically constructed + * selector widgets. */ + + + if ($defaultLocationType) { + $defaultLocation = $locationTypes[$defaultLocationType->id]; + unset($locationTypes[$defaultLocationType->id]); + $locationTypes = array( + $defaultLocationType->id => $defaultLocation) + $locationTypes; + } + + $locationTypes = array( + ' ' => ts('Primary')) + $locationTypes; + + // since we need a hierarchical list to display contact types & subtypes, + // this is what we going to display in first selector + $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(FALSE, FALSE); + if ($mappingType == 'Search Builder') { + $contactTypes = array('Contact' => ts('Contacts')) + $contactTypes; + } + + $sel1 = + array('' => ts('- select record type -')) + $contactTypes + $compArray; + + foreach ($sel1 as $key => $sel) { + if ($key) { + asort($mapperFields[$key]); + $sel2[$key] = array('' => ts('- select field -')) + $mapperFields[$key]; + } + } + + $sel3[''] = NULL; + $sel5[''] = NULL; + $phoneTypes = CRM_Core_PseudoConstant::phoneType(); + $imProviders = CRM_Core_PseudoConstant::IMProvider(); + asort($phoneTypes); + + foreach ($sel1 as $k => $sel) { + if ($k) { + foreach ($locationTypes as $key => $value) { + if (trim($key) != '') { + $sel4[$k]['phone'][$key] = &$phoneTypes; + $sel4[$k]['im'][$key] = &$imProviders; + } + } + } + } + + foreach ($sel1 as $k => $sel) { + if ($k) { + foreach ($mapperFields[$k] as $key => $value) { + if (isset($hasLocationTypes[$k][$key])) { + $sel3[$k][$key] = $locationTypes; + } + else { + $sel3[$key] = NULL; + } + } + } + } + + //Array for core fields and relationship custom data + + $relationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, NULL, NULL, NULL, TRUE); + + if ($mappingType == 'Export') { + foreach ($sel1 as $k => $sel) { + if ($k) { + foreach ($mapperFields[$k] as $field => $dontCare) { + if (isset($hasRelationTypes[$k][$field])) { + list($id, $first, $second) = explode('_', $field); + // FIX ME: For now let's not expose custom data related to relationship + $relationshipCustomFields = array(); + //$relationshipCustomFields = self::getRelationTypeCustomGroupData( $id ); + //asort( $relationshipCustomFields ) ; + + $relationshipType = new CRM_Contact_BAO_RelationshipType(); + $relationshipType->id = $id; + if ($relationshipType->find(TRUE)) { + $direction = "contact_sub_type_$second"; + if (isset($relationshipType->$direction)) { + $relatedFields = array_merge((array)$relatedMapperFields[$relationshipType->$direction], (array)$relationshipCustomFields); + } + else { + $target_type = 'contact_type_' . $second; + $relatedFields = array_merge((array)$relatedMapperFields[$relationshipType->$target_type], (array)$relationshipCustomFields); + } + } + $relationshipType->free(); + asort($relatedFields); + $sel5[$k][$field] = $relatedFields; + } + } + } + } + + //Location Type for relationship fields + + foreach ($sel5 as $k => $v) { + if ($v) { + foreach ($v as $rel => $fields) { + foreach ($fields as $field => $fieldLabel) { + if (isset($hasLocationTypes[$k][$field])) { + $sel6[$k][$rel][$field] = $locationTypes; + } + } + } + } + } + + //PhoneTypes for relationship fields + $sel7[''] = NULL; + foreach ($sel6 as $k => $rel) { + if ($k) { + foreach ($rel as $phonekey => $phonevalue) { + foreach ($locationTypes as $locType => $loc) { + if (trim($locType) != '') { + $sel7[$k][$phonekey]['phone'][$locType] = &$phoneTypes; + $sel7[$k][$phonekey]['im'][$locType] = &$imProviders; + } + } + } + } + } + } + + //special fields that have location, hack for primary location + $specialFields = array( + 'street_address', 'supplemental_address_1', 'supplemental_address_2', + 'city', 'postal_code', 'postal_code_suffix', 'geo_code_1', 'geo_code_2', + 'state_province', 'country', 'phone', 'email', 'im', + ); + + if (isset($mappingId)) { + $colCnt = 0; + + list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingImProvider, + $mappingRelation, $mappingOperator, $mappingValue + ) = CRM_Core_BAO_Mapping::getMappingFields($mappingId); + + $blkCnt = count($mappingName); + if ($blkCnt >= $blockCount) { + $blockCount = $blkCnt + 1; + } + for ($x = 1; $x < $blockCount; $x++) { + if (isset($mappingName[$x])) { + $colCnt = count($mappingName[$x]); + if ($colCnt >= $columnCount[$x]) { + $columnCount[$x] = $colCnt; + } + } + } + } + + $form->_blockCount = $blockCount; + $form->_columnCount = $columnCount; + + $form->set('blockCount', $form->_blockCount); + $form->set('columnCount', $form->_columnCount); + + $defaults = $noneArray = $nullArray = array(); + + //used to warn for mismatch column count or mismatch mapping + $warning = 0; + for ($x = 1; $x < $blockCount; $x++) { + + for ($i = 0; $i < $columnCount[$x]; $i++) { + + $sel = &$form->addElement('hierselect', "mapper[$x][$i]", ts('Mapper for Field %1', array(1 => $i)), NULL); + $jsSet = FALSE; + + if (isset($mappingId)) { + $locationId = isset($mappingLocation[$x][$i]) ? $mappingLocation[$x][$i] : 0; + if (isset($mappingName[$x][$i])) { + if (is_array($mapperFields[$mappingContactType[$x][$i]])) { + + if (isset($mappingRelation[$x][$i])) { + + $contactDetails = strtolower(str_replace(" ", "_", $mappingName[$x][$i])); + $relLocationId = isset($mappingLocation[$x][$i]) ? $mappingLocation[$x][$i] : 0; + if (!$relLocationId && in_array($mappingName[$x][$i], $specialFields)) { + $relLocationId = " "; + } + + $relPhoneType = isset($mappingPhoneType[$x][$i]) ? $mappingPhoneType[$x][$i] : NULL; + + $defaults["mapper[$x][$i]"] = array( + $mappingContactType[$x][$i], + $mappingRelation[$x][$i], + $locationId, + $phoneType, + $mappingName[$x][$i], + $relLocationId, + $relPhoneType, + ); + + if (!$locationId) { + $noneArray[] = array($x, $i, 2); + } + if (!$phoneType && !$imProvider) { + $noneArray[] = array($x, $i, 3); + } + if (!$mappingName[$x][$i]) { + $noneArray[] = array($x, $i, 4); + } + if (!$relLocationId) { + $noneArray[] = array($x, $i, 5); + } + if (!$relPhoneType) { + $noneArray[] = array($x, $i, 6); + } + $noneArray[] = array($x, $i, 2); + } + else { + $phoneType = isset($mappingPhoneType[$x][$i]) ? $mappingPhoneType[$x][$i] : NULL; + $imProvider = isset($mappingImProvider[$x][$i]) ? $mappingImProvider[$x][$i] : NULL; + if (!$locationId && in_array($mappingName[$x][$i], $specialFields)) { + $locationId = " "; + } + + $defaults["mapper[$x][$i]"] = array( + $mappingContactType[$x][$i], + $mappingName[$x][$i], + $locationId, + $phoneType, + ); + if (!$mappingName[$x][$i]) { + $noneArray[] = array($x, $i, 1); + } + if (!$locationId) { + $noneArray[] = array($x, $i, 2); + } + if (!$phoneType && !$imProvider) { + $noneArray[] = array($x, $i, 3); + } + + $noneArray[] = array($x, $i, 4); + $noneArray[] = array($x, $i, 5); + $noneArray[] = array($x, $i, 6); + } + + $jsSet = TRUE; + + if (CRM_Utils_Array::value($i, CRM_Utils_Array::value($x, $mappingOperator))) { + $defaults["operator[$x][$i]"] = CRM_Utils_Array::value($i, $mappingOperator[$x]); + } + + if (CRM_Utils_Array::value($i, CRM_Utils_Array::value($x, $mappingValue))) { + $defaults["value[$x][$i]"] = CRM_Utils_Array::value($i, $mappingValue[$x]); + } + } + } + } + //Fix for Search Builder + if ($mappingType == 'Export') { + $j = 7; + } + else { + $j = 4; + } + + $formValues = $form->exportValues(); + if (!$jsSet) { + if (empty($formValues)) { + // Incremented length for third select box(relationship type) + for ($k = 1; $k < $j; $k++) { + $noneArray[] = array($x, $i, $k); + } + } + else { + if (!empty($formValues['mapper'][$x])) { + foreach ($formValues['mapper'][$x] as $value) { + for ($k = 1; $k < $j; $k++) { + if (!isset($formValues['mapper'][$x][$i][$k]) || + (!$formValues['mapper'][$x][$i][$k]) + ) { + $noneArray[] = array($x, $i, $k); + } + else { + $nullArray[] = array($x, $i, $k); + } + } + } + } + else { + for ($k = 1; $k < $j; $k++) { + $noneArray[] = array($x, $i, $k); + } + } + } + } + //Fix for Search Builder + if ($mappingType == 'Export') { + if (!isset($mappingId)) { + if (isset($formValues['mapper']) && + isset($formValues['mapper'][$x][$i][1]) && + array_key_exists($formValues['mapper'][$x][$i][1], $relationshipTypes) + ) { + $sel->setOptions(array($sel1, $sel2, $sel5, $sel6, $sel7, $sel3, $sel4)); + } + else { + $sel->setOptions(array($sel1, $sel2, $sel3, $sel4, $sel5, $sel6, $sel7)); + } + } + else { + $sel->setOptions(array($sel1, $sel2, $sel3, $sel4, $sel5, $sel6, $sel7)); + } + } + else { + $sel->setOptions(array($sel1, $sel2, $sel3, $sel4)); + } + + if ($mappingType == 'Search Builder') { + //CRM -2292, restricted array set + $operatorArray = array( + '' => ts('-operator-'), + '=' => '=', + '!=' => '!=', + '>' => '>', + '<' => '<', + '>=' => '>=', + '<=' => '<=', + 'IN' => 'IN', + 'LIKE' => 'LIKE', + 'RLIKE' => 'RLIKE', + 'IS EMPTY' => 'IS EMPTY', + 'IS NOT EMPTY' => 'IS NOT EMPTY', + 'IS NULL' => 'IS NULL', + 'IS NOT NULL' => 'IS NOT NULL', + ); + + $form->add('select', "operator[$x][$i]", '', $operatorArray); + $form->add('text', "value[$x][$i]", ''); + } + } + //end of columnCnt for + if ($mappingType == 'Search Builder') { + $title = ts('Another search field'); + } + else { + $title = ts('Select more fields'); + } + + $form->addElement('submit', "addMore[$x]", $title, array('class' => 'submit-link')); + } + //end of block for + + $js = "\n"; + + $form->assign('initHideBoxes', $js); + $form->assign('columnCount', $columnCount); + $form->assign('blockCount', $blockCount); + $form->setDefaults($defaults); + + $form->setDefaultAction('refresh'); + } + + /* Function returns all custom fields with group title and + * field label + * @relationshipTypeId related relationship type id + * @return $groupTitle all custom field titles + */ + function getRelationTypeCustomGroupData($relationshipTypeId) { + + $customFields = CRM_Core_BAO_CustomField::getFields('Relationship', NULL, NULL, $relationshipTypeId, NULL, NULL); + $groupTitle = array(); + foreach ($customFields as $krelation => $vrelation) { + $groupTitle[$vrelation['label']] = $vrelation['groupTitle'] . '...' . $vrelation['label']; + } + return $groupTitle; + } + + + /** + * Function returns all Custom group Names + * + * @param customfieldId related custom field id + * @return $customGroupName all custom group names + * @static + */ + static function getCustomGroupName($customfieldId) { + if ($customFieldId = CRM_Core_BAO_CustomField::getKeyID($customfieldId)) { + $customGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $customFieldId, 'custom_group_id'); + $customGroupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupId, 'title'); + + if (strlen($customGroupName) > 13) { + $customGroupName = substr($customGroupName, 0, 10) . '...'; + } + + return $customGroupName; + } + } + + /** + * Function returns associated array of elements, that will be passed for search + * + * @params array $params associated array of submitted values + * @params boolean $row row no of the fields + * + * @return $returnFields formatted associated array of elements + * + * @static + * @public + */ + static function &formattedFields(&$params, $row = FALSE) { + $fields = array(); + + if (empty($params) || !isset($params['mapper'])) { + return $fields; + } + + $types = array('Individual', 'Organization', 'Household'); + foreach ($params['mapper'] as $key => $value) { + $contactType = NULL; + foreach ($value as $k => $v) { + if (in_array($v[0], $types)) { + if ($contactType && $contactType != $v[0]) { + CRM_Core_Error::fatal(ts("Cannot have two clauses with different types: %1, %2", + array(1 => $contactType, 2 => $v[0]) + )); + } + $contactType = $v[0]; + } + if (CRM_Utils_Array::value('1', $v)) { + $fldName = $v[1]; + $v2 = CRM_Utils_Array::value('2', $v); + if ($v2 && trim($v2)) { + $fldName .= "-{$v[2]}"; + } + + $v3 = CRM_Utils_Array::value('3', $v); + if ($v3 && trim($v3)) { + $fldName .= "-{$v[3]}"; + } + + $value = $params['value'][$key][$k]; + if ($fldName == 'group' || $fldName == 'tag') { + $value = trim($value); + $value = str_replace('(', '', $value); + $value = str_replace(')', '', $value); + + $v = explode(',', $value); + $value = array(); + foreach ($v as $i) { + $value[$i] = 1; + } + } + + if ($v[0] == 'Contribution' && substr($fldName, 0, 7) != 'custom_') { + if (substr($fldName, 0, 13) != 'contribution_') { + $fldName = 'contribution_' . $fldName; + } + } + + if ($row) { + $fields[] = array( + $fldName, + $params['operator'][$key][$k], + $value, + $key, + $k, + ); + } + else { + $fields[] = array( + $fldName, + $params['operator'][$key][$k], + $value, + $key, + 0, + ); + } + } + } + if ($contactType) { + $fields[] = array( + 'contact_type', + '=', + $contactType, + $key, + 0, + ); + } + } + + //add sortByCharacter values + if (isset($params['sortByCharacter'])) { + $fields[] = array( + 'sortByCharacter', + '=', + $params['sortByCharacter'], + 0, + 0, + ); + } + + + return $fields; + } + + static function &returnProperties(&$params) { + $fields = array( + 'contact_type' => 1, + 'contact_sub_type' => 1, + 'sort_name' => 1, + ); + + if (empty($params) || empty($params['mapper'])) { + return $fields; + } + + $locationTypes = CRM_Core_PseudoConstant::locationType(); + foreach ($params['mapper'] as $key => $value) { + foreach ($value as $k => $v) { + if (isset($v[1])) { + if ($v[1] == 'groups' || $v[1] == 'tags') { + continue; + } + + if (isset($v[2]) && is_numeric($v[2])) { + if (!array_key_exists('location', $fields)) { + $fields['location'] = array(); + } + + // make sure that we have a location fields and a location type for this + $locationName = $locationTypes[$v[2]]; + if (!array_key_exists($locationName, $fields['location'])) { + $fields['location'][$locationName] = array(); + $fields['location'][$locationName]['location_type'] = $v[2]; + } + + if ($v[1] == 'phone' || $v[1] == 'email' || $v[1] == 'im') { + // phone type handling + if (isset($v[3])) { + $fields['location'][$locationName][$v[1] . "-" . $v[3]] = 1; + } + else { + $fields['location'][$locationName][$v[1]] = 1; + } + } + else { + $fields['location'][$locationName][$v[1]] = 1; + } + } + else { + $fields[$v[1]] = 1; + } + } + } + } + + return $fields; + } + + /** + * save the mapping field info for search builder / export given the formvalues + * + * @param array $params asscociated array of formvalues + * @param int $mappingId mapping id + * + * @return null + * @static + * @access public + */ + static function saveMappingFields(&$params, $mappingId) { + //delete mapping fields records for exixting mapping + $mappingFields = new CRM_Core_DAO_MappingField(); + $mappingFields->mapping_id = $mappingId; + $mappingFields->delete(); + + if (empty($params['mapper'])) { + return; + } + + //save record in mapping field table + foreach ($params['mapper'] as $key => $value) { + $colCnt = 0; + foreach ($value as $k => $v) { + + if (CRM_Utils_Array::value('1', $v)) { + $saveMappingFields = new CRM_Core_DAO_MappingField(); + + $saveMappingFields->mapping_id = $mappingId; + $saveMappingFields->name = CRM_Utils_Array::value('1', $v); + $saveMappingFields->contact_type = CRM_Utils_Array::value('0', $v); + $locationId = CRM_Utils_Array::value('2', $v); + $saveMappingFields->location_type_id = is_numeric($locationId) ? $locationId : NULL; + + if ($v[1] == 'phone') { + $saveMappingFields->phone_type_id = CRM_Utils_Array::value('3', $v); + } + elseif ($v[1] == 'im') { + $saveMappingFields->im_provider_id = CRM_Utils_Array::value('3', $v); + } + + if (CRM_Utils_Array::value('operator', $params)) { + $saveMappingFields->operator = CRM_Utils_Array::value($k, $params['operator'][$key]); + } + if (CRM_Utils_Array::value('value', $params)) { + $saveMappingFields->value = CRM_Utils_Array::value($k, $params['value'][$key]); + } + // Handle mapping for 'related contact' fields + if (count(explode('_', CRM_Utils_Array::value('1', $v))) > 2) { + list($id, $first, $second) = explode('_', CRM_Utils_Array::value('1', $v)); + if (($first == 'a' && $second == 'b') || ($first == 'b' && $second == 'a')) { + + if (CRM_Utils_Array::value('2', $v)) { + $saveMappingFields->name = CRM_Utils_Array::value('2', $v); + } + elseif (CRM_Utils_Array::value('4', $v)) { + $saveMappingFields->name = CRM_Utils_Array::value('4', $v); + } + + if (is_numeric(CRM_Utils_Array::value('3', $v))) { + $locationTypeid = CRM_Utils_Array::value('3', $v); + } + elseif (is_numeric(CRM_Utils_Array::value('5', $v))) { + $locationTypeid = CRM_Utils_Array::value('5', $v); + } + + if (is_numeric(CRM_Utils_Array::value('4', $v))) { + $phoneTypeid = CRM_Utils_Array::value('4', $v); + } + elseif (is_numeric(CRM_Utils_Array::value('6', $v))) { + $phoneTypeid = CRM_Utils_Array::value('6', $v); + } + + $saveMappingFields->location_type_id = is_numeric($locationTypeid) ? $locationTypeid : NULL; + $saveMappingFields->phone_type_id = is_numeric($phoneTypeid) ? $phoneTypeid : NULL; + $saveMappingFields->relationship_type_id = $id; + $saveMappingFields->relationship_direction = "{$first}_{$second}"; + } + } + + $saveMappingFields->grouping = $key; + $saveMappingFields->column_number = $colCnt; + $saveMappingFields->save(); + $colCnt++; + $locationTypeid = $phoneTypeid = NULL; + } + } + } + } +} + diff --git a/CRM/Core/BAO/MessageTemplates.php b/CRM/Core/BAO/MessageTemplates.php new file mode 100644 index 0000000000..eb572fe0b3 --- /dev/null +++ b/CRM/Core/BAO/MessageTemplates.php @@ -0,0 +1,527 @@ +copyValues($params); + if ($messageTemplates->find(TRUE)) { + CRM_Core_DAO::storeValues($messageTemplates, $defaults); + return $messageTemplates; + } + return NULL; + } + + /** + * update the is_active flag in the db + * + * @param int $id id of the database record + * @param boolean $is_active value we want to set the is_active field + * + * @return Object DAO object on sucess, null otherwise + * @static + */ + static function setIsActive($id, $is_active) { + return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_MessageTemplates', $id, 'is_active', $is_active); + } + + /** + * function to add the Message Templates + * + * @param array $params reference array contains the values submitted by the form + * + * @access public + * @static + * + * @return object + */ + static function add(&$params) { + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + + $messageTemplates = new CRM_Core_DAO_MessageTemplates(); + $messageTemplates->copyValues($params); + + $messageTemplates->save(); + return $messageTemplates; + } + + /** + * function to delete the Message Templates + * + * @access public + * @static + * + * @return object + */ + static function del($messageTemplatesID) { + // make sure messageTemplatesID is an integer + if (!CRM_Utils_Rule::positiveInteger($messageTemplatesID)) { + CRM_Core_Error::fatal(ts('Invalid Message template')); + } + + // Set mailing msg template col to NULL + $query = "UPDATE civicrm_mailing + SET msg_template_id = NULL + WHERE msg_template_id = %1"; + CRM_Core_DAO::executeQuery($query, $params); + + $messageTemplates = new CRM_Core_DAO_MessageTemplates(); + $messageTemplates->id = $messageTemplatesID; + $messageTemplates->delete(); + CRM_Core_Session::setStatus(ts('Selected message template has been deleted.'), ts('Deleted'), 'success'); + } + + /** + * function to get the Message Templates + * + * @access public + * @static + * + * @return object + */ + static function getMessageTemplates($all = TRUE) { + $msgTpls = array(); + + $messageTemplates = new CRM_Core_DAO_MessageTemplates(); + $messageTemplates->is_active = 1; + + if (!$all) { + $messageTemplates->workflow_id = 'NULL'; + } + $messageTemplates->find(); + while ($messageTemplates->fetch()) { + $msgTpls[$messageTemplates->id] = $messageTemplates->msg_title; + } + asort($msgTpls); + return $msgTpls; + } + + static function sendReminder($contactId, $email, $messageTemplateID, $from) { + + $messageTemplates = new CRM_Core_DAO_MessageTemplates(); + $messageTemplates->id = $messageTemplateID; + + $domain = CRM_Core_BAO_Domain::getDomain(); + $result = NULL; + $hookTokens = array(); + + if ($messageTemplates->find(TRUE)) { + $body_text = $messageTemplates->msg_text; + $body_html = $messageTemplates->msg_html; + $body_subject = $messageTemplates->msg_subject; + if (!$body_text) { + $body_text = CRM_Utils_String::htmlToText($body_html); + } + + $params = array(array('contact_id', '=', $contactId, 0, 0)); + list($contact, $_) = CRM_Contact_BAO_Query::apiQuery($params); + + //CRM-4524 + $contact = reset($contact); + + if (!$contact || is_a($contact, 'CRM_Core_Error')) { + return NULL; + } + + //CRM-5734 + + // get tokens to be replaced + $tokens = array_merge(CRM_Utils_Token::getTokens($body_text), + CRM_Utils_Token::getTokens($body_html), + CRM_Utils_Token::getTokens($body_subject)); + + // get replacement text for these tokens + $returnProperties = array("preferred_mail_format" => 1); + if (isset($tokens['contact'])) { + foreach ($tokens['contact'] as $key => $value) { + $returnProperties[$value] = 1; + } + } + list($details) = CRM_Utils_Token::getTokenDetails(array($contactId), + $returnProperties, + null, null, false, + $tokens, + 'CRM_Core_BAO_MessageTemplates'); + $contact = reset( $details ); + + // call token hook + $hookTokens = array(); + CRM_Utils_Hook::tokens($hookTokens); + $categories = array_keys($hookTokens); + + // do replacements in text and html body + $type = array('html', 'text'); + foreach ($type as $key => $value) { + $bodyType = "body_{$value}"; + if ($$bodyType) { + CRM_Utils_Token::replaceGreetingTokens($$bodyType, NULL, $contact['contact_id']); + $$bodyType = CRM_Utils_Token::replaceDomainTokens($$bodyType, $domain, true, $tokens, true); + $$bodyType = CRM_Utils_Token::replaceContactTokens($$bodyType, $contact, false, $tokens, false, true); + $$bodyType = CRM_Utils_Token::replaceComponentTokens($$bodyType, $contact, $tokens, true); + $$bodyType = CRM_Utils_Token::replaceHookTokens($$bodyType, $contact , $categories, true); + } + } + $html = $body_html; + $text = $body_text; + + $smarty = CRM_Core_Smarty::singleton(); + foreach (array( + 'text', 'html') as $elem) { + $$elem = $smarty->fetch("string:{$$elem}"); + } + + // do replacements in message subject + $messageSubject = CRM_Utils_Token::replaceContactTokens($body_subject, $contact, false, $tokens); + $messageSubject = CRM_Utils_Token::replaceDomainTokens($messageSubject, $domain, true, $tokens); + $messageSubject = CRM_Utils_Token::replaceComponentTokens($messageSubject, $contact, $tokens, true); + $messageSubject = CRM_Utils_Token::replaceHookTokens($messageSubject, $contact, $categories, true); + + $messageSubject = $smarty->fetch("string:{$messageSubject}"); + + // set up the parameters for CRM_Utils_Mail::send + $mailParams = array( + 'groupName' => 'Scheduled Reminder Sender', + 'from' => $from, + 'toName' => $contact['display_name'], + 'toEmail' => $email, + 'subject' => $messageSubject, + ); + if (!$html || $contact['preferred_mail_format'] == 'Text' || + $contact['preferred_mail_format'] == 'Both' + ) { + // render the & entities in text mode, so that the links work + $mailParams['text'] = str_replace('&', '&', $text); + } + if ($html && ($contact['preferred_mail_format'] == 'HTML' || + $contact['preferred_mail_format'] == 'Both' + )) { + $mailParams['html'] = $html; + } + + $result = CRM_Utils_Mail::send($mailParams); + } + + $messageTemplates->free(); + + return $result; + } + + /** + * Revert a message template to its default subject+text+HTML state + * + * @param integer id id of the template + * + * @return void + */ + static function revert($id) { + $diverted = new self; + $diverted->id = (int) $id; + $diverted->find(1); + + if ($diverted->N != 1) { + CRM_Core_Error::fatal(ts('Did not find a message template with id of %1.', array(1 => $id))); + } + + $orig = new self; + $orig->workflow_id = $diverted->workflow_id; + $orig->is_reserved = 1; + $orig->find(1); + + if ($orig->N != 1) { + CRM_Core_Error::fatal(ts('Message template with id of %1 does not have a default to revert to.', array(1 => $id))); + } + + $diverted->msg_subject = $orig->msg_subject; + $diverted->msg_text = $orig->msg_text; + $diverted->msg_html = $orig->msg_html; + $diverted->pdf_format_id = is_null($orig->pdf_format_id) ? 'null' : $orig->pdf_format_id; + $diverted->save(); + } + + /** + * Send an email from the specified template based on an array of params + * + * @param array $params a string-keyed array of function params, see function body for details + * + * @return array of four parameters: a boolean whether the email was sent, and the subject, text and HTML templates + */ + static function sendTemplate($params) { + $defaults = array( + // option group name of the template + 'groupName' => NULL, + // option value name of the template + 'valueName' => NULL, + // ID of the template + 'messageTemplateID' => NULL, + // contact id if contact tokens are to be replaced + 'contactId' => NULL, + // additional template params (other than the ones already set in the template singleton) + 'tplParams' => array(), + // the From: header + 'from' => NULL, + // the recipient’s name + 'toName' => NULL, + // the recipient’s email - mail is sent only if set + 'toEmail' => NULL, + // the Cc: header + 'cc' => NULL, + // the Bcc: header + 'bcc' => NULL, + // the Reply-To: header + 'replyTo' => NULL, + // email attachments + 'attachments' => NULL, + // whether this is a test email (and hence should include the test banner) + 'isTest' => FALSE, + // filename of optional PDF version to add as attachment (do not include path) + 'PDFFilename' => NULL, + ); + $params = array_merge($defaults, $params); + + if ((!$params['groupName'] || + !$params['valueName'] + ) && + !$params['messageTemplateID'] + ) { + CRM_Core_Error::fatal(ts("Message template's option group and/or option value or ID missing.")); + } + + if ($params['messageTemplateID']) { + // fetch the three elements from the db based on id + $query = 'SELECT msg_subject subject, msg_text text, msg_html html, pdf_format_id format + FROM civicrm_msg_template mt + WHERE mt.id = %1 AND mt.is_default = 1'; + $sqlParams = array(1 => array($params['messageTemplateID'], 'String')); + } + else { + // fetch the three elements from the db based on option_group and option_value names + $query = 'SELECT msg_subject subject, msg_text text, msg_html html, pdf_format_id format + FROM civicrm_msg_template mt + JOIN civicrm_option_value ov ON workflow_id = ov.id + JOIN civicrm_option_group og ON ov.option_group_id = og.id + WHERE og.name = %1 AND ov.name = %2 AND mt.is_default = 1'; + $sqlParams = array(1 => array($params['groupName'], 'String'), 2 => array($params['valueName'], 'String')); + } + $dao = CRM_Core_DAO::executeQuery($query, $sqlParams); + $dao->fetch(); + + if (!$dao->N) { + if ($params['messageTemplateID']) { + CRM_Core_Error::fatal(ts('No such message template: id=%1.', array(1 => $params['messageTemplateID']))); + } + else { + CRM_Core_Error::fatal(ts('No such message template: option group %1, option value %2.', array(1 => $params['groupName'], 2 => $params['valueName']))); + } + } + + $subject = $dao->subject; + $text = $dao->text; + $html = $dao->html; + $format = $dao->format; + $dao->free(); + + // add the test banner (if requested) + if ($params['isTest']) { + $query = "SELECT msg_subject subject, msg_text text, msg_html html + FROM civicrm_msg_template mt + JOIN civicrm_option_value ov ON workflow_id = ov.id + JOIN civicrm_option_group og ON ov.option_group_id = og.id + WHERE og.name = 'msg_tpl_workflow_meta' AND ov.name = 'test_preview' AND mt.is_default = 1"; + $testDao = CRM_Core_DAO::executeQuery($query); + $testDao->fetch(); + + $subject = $testDao->subject . $subject; + $text = $testDao->text . $text; + $html = preg_replace('/html}", $html); + $testDao->free(); + } + + // replace tokens in the three elements (in subject as if it was the text body) + $domain = CRM_Core_BAO_Domain::getDomain(); + $hookTokens = array(); + $mailing = new CRM_Mailing_BAO_Mailing; + $mailing->body_text = $text; + $mailing->body_html = $html; + $tokens = $mailing->getTokens(); + CRM_Utils_Hook::tokens($hookTokens); + $categories = array_keys($hookTokens); + + $contactID = CRM_Utils_Array::value('contactId', $params); + + if ($contactID) { + $contactParams = array('contact_id' => $contactID); + $returnProperties = array(); + + if (isset($tokens['text']['contact'])) { + foreach ($tokens['text']['contact'] as $name) { + $returnProperties[$name] = 1; + } + } + + if (isset($tokens['html']['contact'])) { + foreach ($tokens['html']['contact'] as $name) { + $returnProperties[$name] = 1; + } + } + list($contact) = CRM_Utils_Token::getTokenDetails($contactParams, + $returnProperties, + FALSE, FALSE, NULL, + CRM_Utils_Token::flattenTokens($tokens), + // we should consider adding groupName and valueName here + 'CRM_Core_BAO_MessageTemplate' + ); + $contact = $contact[$contactID]; + } + + $subject = CRM_Utils_Token::replaceDomainTokens($subject, $domain, TRUE, $tokens['text'], TRUE); + $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, TRUE, $tokens['text'], TRUE); + $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html'], TRUE); + + if ($contactID) { + $subject = CRM_Utils_Token::replaceContactTokens($subject, $contact, FALSE, $tokens['text'], FALSE, TRUE); + $text = CRM_Utils_Token::replaceContactTokens($text, $contact, FALSE, $tokens['text'], FALSE, TRUE); + $html = CRM_Utils_Token::replaceContactTokens($html, $contact, FALSE, $tokens['html'], FALSE, TRUE); + + + $contactArray = array($contactID => $contact); + CRM_Utils_Hook::tokenValues($contactArray, + array($contactID), + NULL, + CRM_Utils_Token::flattenTokens($tokens), + // we should consider adding groupName and valueName here + 'CRM_Core_BAO_MessageTemplate' + ); + $contact = $contactArray[$contactID]; + + $subject = CRM_Utils_Token::replaceHookTokens($subject, $contact, $categories, TRUE); + $text = CRM_Utils_Token::replaceHookTokens($text, $contact, $categories, TRUE); + $html = CRM_Utils_Token::replaceHookTokens($html, $contact, $categories, TRUE); + } + + // strip whitespace from ends and turn into a single line + $subject = "{strip}$subject{/strip}"; + + // parse the three elements with Smarty + + + $smarty = CRM_Core_Smarty::singleton(); + foreach ($params['tplParams'] as $name => $value) { + $smarty->assign($name, $value); + } + foreach (array( + 'subject', 'text', 'html') as $elem) { + $$elem = $smarty->fetch("string:{$$elem}"); + } + + // send the template, honouring the target user’s preferences (if any) + $sent = FALSE; + + // create the params array + $params['subject'] = $subject; + $params['text'] = $text; + $params['html'] = $html; + + if ($params['toEmail']) { + $contactParams = array(array('email', 'LIKE', $params['toEmail'], 0, 1)); + list($contact, $_) = CRM_Contact_BAO_Query::apiQuery($contactParams); + + $prefs = array_pop($contact); + + if (isset($prefs['preferred_mail_format']) and $prefs['preferred_mail_format'] == 'HTML') { + $params['text'] = NULL; + } + + if (isset($prefs['preferred_mail_format']) and $prefs['preferred_mail_format'] == 'Text') { + $params['html'] = NULL; + } + + $config = CRM_Core_Config::singleton(); + $pdf_filename = ''; + if ($config->doNotAttachPDFReceipt && + $params['PDFFilename'] && + $params['html'] + ) { + $pdf_filename = $config->templateCompileDir . CRM_Utils_File::makeFileName($params['PDFFilename']); + + //FIXME : CRM-7894 + //xmlns attribute is required in XHTML but it is invalid in HTML, + //Also the namespace "xmlns=http://www.w3.org/1999/xhtml" is default, + //and will be added to the tag even if you do not include it. + $html = preg_replace('/()/', '\1\3\4', $params['html']); + + file_put_contents($pdf_filename, CRM_Utils_PDF_Utils::html2pdf($html, + $params['PDFFilename'], + TRUE, + $format + ) + ); + + if (empty($params['attachments'])) { + $params['attachments'] = array(); + } + $params['attachments'][] = array( + 'fullPath' => $pdf_filename, + 'mime_type' => 'application/pdf', + 'cleanName' => $params['PDFFilename'], + ); + } + + $sent = CRM_Utils_Mail::send($params); + + if ($pdf_filename) { + unlink($pdf_filename); + } + } + + return array($sent, $subject, $text, $html); + } +} + diff --git a/CRM/Core/BAO/Navigation.php b/CRM/Core/BAO/Navigation.php new file mode 100644 index 0000000000..d96e3fa96b --- /dev/null +++ b/CRM/Core/BAO/Navigation.php @@ -0,0 +1,832 @@ +domain_id = CRM_Core_Config::domainID(); + $menu->find(); + + while ($menu->fetch()) { + if ($menu->title) { + $menus[$menu->path] = $menu->title; + } + } + return $menus; + } + + /** + * Function to add/update navigation record + * + * @param array associated array of submitted values + * + * @return object navigation object + * @static + */ + static function add(&$params) { + $navigation = new CRM_Core_DAO_Navigation(); + + $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE); + $params['has_separator'] = CRM_Utils_Array::value('has_separator', $params, FALSE); + + if (!isset($params['id']) || + (CRM_Utils_Array::value( 'parent_id', $params ) != CRM_Utils_Array::value('current_parent_id', $params)) + ) { + /* re/calculate the weight, if the Parent ID changed OR create new menu */ + + if ($navName = CRM_Utils_Array::value('name', $params)) { + $params['name'] = $navName; + } + else { + $params['name'] = $params['label']; + } + + $params['weight'] = self::calculateWeight(CRM_Utils_Array::value('parent_id', $params)); + } + + if (is_array($params['permission'])) { + $params['permission'] = implode(',', $params['permission']); + } + + $navigation->copyValues($params); + + $navigation->domain_id = CRM_Core_Config::domainID(); + + $navigation->save(); + return $navigation; + } + + /** + * Takes a bunch of params that are needed to match certain criteria and + * retrieves the relevant objects. Typically the valid params are only + * contact_id. We'll tweak this function to be more full featured over a period + * of time. This is the inverse function of create. It also stores all the retrieved + * values in the default array + * + * @param array $params (reference ) an assoc array of name/value pairs + * @param array $defaults (reference ) an assoc array to hold the flattened values + * + * @return object CRM_Core_BAO_Navigation object on success, null otherwise + * @access public + * @static + */ + static function retrieve(&$params, &$defaults) { + $navigation = new CRM_Core_DAO_Navigation(); + $navigation->copyValues($params); + + $navigation->domain_id = CRM_Core_Config::domainID(); + + if ($navigation->find(TRUE)) { + CRM_Core_DAO::storeValues($navigation, $defaults); + return $navigation; + } + return NULL; + } + + /** + * Calculate navigation weight + * + * @param $parentID parent_id of a menu + * @param $menuID menu id + * + * @return $weight string + * @static + */ + static function calculateWeight($parentID = NULL, $menuID = NULL) { + $domainID = CRM_Core_Config::domainID(); + + $weight = 1; + // we reset weight for each parent, i.e we start from 1 to n + // calculate max weight for top level menus, if parent id is absent + if (!$parentID) { + $query = "SELECT max(weight) as weight FROM civicrm_navigation WHERE parent_id IS NULL AND domain_id = $domainID"; + } + else { + // if parent is passed, we need to get max weight for that particular parent + $query = "SELECT max(weight) as weight FROM civicrm_navigation WHERE parent_id = {$parentID} AND domain_id = $domainID"; + } + + $dao = CRM_Core_DAO::executeQuery($query); + $dao->fetch(); + return $weight = $weight + $dao->weight; + } + + /** + * Get formatted menu list + * + * @return array $navigations returns associated array + * @static + */ + static function getNavigationList() { + $cacheKeyString = "navigationList"; + $whereClause = ''; + + $config = CRM_Core_Config::singleton(); + + // check if we can retrieve from database cache + $navigations = CRM_Core_BAO_Cache::getItem('navigation', $cacheKeyString); + + if (!$navigations) { + $domainID = CRM_Core_Config::domainID(); + $query = " +SELECT id, label, parent_id, weight, is_active, name +FROM civicrm_navigation WHERE domain_id = $domainID {$whereClause} ORDER BY parent_id, weight ASC"; + $result = CRM_Core_DAO::executeQuery($query); + + $pidGroups = array(); + while ($result->fetch()) { + $pidGroups[$result->parent_id][$result->label] = $result->id; + } + + foreach ($pidGroups[''] as $label => $val) { + $pidGroups[''][$label] = self::_getNavigationValue($val, $pidGroups); + } + + $navigations = array(); + self::_getNavigationLabel($pidGroups[''], $navigations); + + CRM_Core_BAO_Cache::setItem($navigations, 'navigation', $cacheKeyString); + } + return $navigations; + } + + /** + * helper function for getNavigationList( ) + * + * @param array $list menu info + * @param array $navigations navigation menus + * @param string $separator menu separator + */ + static function _getNavigationLabel($list, &$navigations, $separator = '') { + $i18n = CRM_Core_I18n::singleton(); + foreach ($list as $label => $val) { + if ($label == 'navigation_id') { + continue; + } + $translatedLabel = $i18n->crm_translate($label, array('context' => 'menu')); + $navigations[is_array($val) ? $val['navigation_id'] : $val] = "{$separator}{$translatedLabel}"; + if (is_array($val)) { + self::_getNavigationLabel($val, $navigations, $separator . '    '); + } + } + } + + /** + * helper function for getNavigationList( ) + * + * @param string $val menu name + * @param array $pidGroups parent menus + * @return array + */ + static function _getNavigationValue($val, &$pidGroups) { + if (array_key_exists($val, $pidGroups)) { + $list = array('navigation_id' => $val); + foreach ($pidGroups[$val] as $label => $id) { + $list[$label] = self::_getNavigationValue($id, $pidGroups); + } + unset($pidGroups[$val]); + return $list; + } + else { + return $val; + } + } + + /** + * Function to build navigation tree + * + * @param array $navigationTree nested array of menus + * @param int $parentID parent id + * @param boolean $navigationMenu true when called for building top navigation menu + * + * @return array $navigationTree nested array of menus + * @static + */ + static function buildNavigationTree(&$navigationTree, $parentID, $navigationMenu = TRUE) { + $whereClause = " parent_id IS NULL"; + + if ($parentID) { + $whereClause = " parent_id = {$parentID}"; + } + + $domainID = CRM_Core_Config::domainID(); + + // get the list of menus + $query = " +SELECT id, label, url, permission, permission_operator, has_separator, parent_id, is_active, name +FROM civicrm_navigation +WHERE {$whereClause} +AND domain_id = $domainID +ORDER BY parent_id, weight"; + + $navigation = CRM_Core_DAO::executeQuery($query); + $config = CRM_Core_Config::singleton(); + while ($navigation->fetch()) { + $label = $navigation->label; + if (!$navigationMenu) { + $label = addcslashes($label, '"'); + } + + // for each menu get their children + $navigationTree[$navigation->id] = array( + 'attributes' => array('label' => $label, + 'name' => $navigation->name, + 'url' => $navigation->url, + 'permission' => $navigation->permission, + 'operator' => $navigation->permission_operator, + 'separator' => $navigation->has_separator, + 'parentID' => $navigation->parent_id, + 'navID' => $navigation->id, + 'active' => $navigation->is_active, + )); + self::buildNavigationTree($navigationTree[$navigation->id]['child'], $navigation->id, $navigationMenu); + } + + return $navigationTree; + } + + /** + * Function to build menu + * + * @param boolean $json by default output is html + * @param boolean $navigationMenu true when called for building top navigation menu + * + * @return returns html or json object + * @static + */ + static function buildNavigation($json = FALSE, $navigationMenu = TRUE) { + $navigations = array(); + self::buildNavigationTree($navigations, $parent = NULL, $navigationMenu); + $navigationString = NULL; + + // run the Navigation through a hook so users can modify it + CRM_Utils_Hook::navigationMenu($navigations); + + $i18n = CRM_Core_I18n::singleton(); + + //skip children menu item if user don't have access to parent menu item + $skipMenuItems = array(); + foreach ($navigations as $key => $value) { + if ($json) { + if ($navigationString) { + $navigationString .= '},'; + } + $data = $value['attributes']['label']; + $class = ''; + if (!$value['attributes']['active']) { + $class = ', "attr": { "class" : "disabled"} '; + } + $l10nName = $i18n->crm_translate($data, array('context' => 'menu')); + $navigationString .= ' { "attr": { "id" : "node_' . $key . '"}, "data": { "title":"' . $l10nName . '"' . $class . '}'; + } + else { + // Home is a special case + if ($value['attributes']['name'] != 'Home') { + $name = self::getMenuName($value, $skipMenuItems); + if ($name) { + //separator before + if (isset($value['attributes']['separator']) && $value['attributes']['separator'] == 2) { + $navigationString .= '
  • '; + } + $removeCharacters = array('/', '!', '&', '*', ' ', '(', ')', '.'); + $navigationString .= '