Showing posts with label Apex. Show all posts
Showing posts with label Apex. Show all posts

Sunday, December 18, 2022

How do you bind an Apex controller to a Visualforce page?

 In Visualforce, to reference an Apex method in the component markup, you must bind an Apex contoller to the Visualforce page. We do this by specifying  it as an attribute in the <apex:page> tag. 

Here's an example of how to do this:

<apex:page controller="MyController"> <!-- page content goes here --> </apex:page>

In this example, MyController is the name of the Apex controller class that you want to bind to the Visualforce page.

You can also specify multiple controllers by separating them with a comma, like this:

<apex:page controller="MyController1, MyController2"> <!-- page content goes here --> </apex:page>

It's important to note that the Apex controller class must be defined in your organization before you can bind it to a Visualforce page. 

public with sharing class MyController { // controller logic goes here }

Once you have defined your Apex controller class and specified it in the <apex:page> tag, you can use the controller's methods and variables in your Visualforce page to control the page's behavior and display dynamic content.


Thursday, January 21, 2010

What Causes Invalid Apex Classes?

I’ve been training a new group of Salesforce.com Users on how to create change sets in a Sandbox, and deploy simple changes (in this case, Email Templates) to production. When we tried to deploy their change set, we encountered some problems caused by a different user group in the same org:

1.) Validation rules had been implemented by System Administrator users in the other group. The validation rules raised nearly a dozen DmlException errors, because they prevented existing Apex test methods to execute their insert / update operations.



2.) The deployment failed because the organization only had 72% test coverage. I hoped that much of this was caused by those same validation rules, but even after setting the offending validation rules to inactive, the org still had only 74% test coverage.

For this particular org, we have a very loose change management process. Business Owners, who deployed and implemented the instances with the help of a third party consultant, still have free reign in the instance. They don’t understand the impact their changes have on the Apex test methods or underlying applications.

I started reviewing the test classes associated with each DmlException error, and noticed a number of test classes had their “Is Valid” checkbox flag set to false.


I misinterpreted what the Apex Class list view was showing me: I saw the blank checkbox next to the word active and immediately thought “Why is this test class being evaluated, if it isn’t active.” I tweeted the question to the world, and my fellow Salesforce developers came to the rescue.

@dschach reminded me that Apex classes are always active:



So then I started poking around in the online help, I found the following notes about the “is Valid” designator:

"To aid backwards-compatibility, classes are stored with the specified version of the API that was used to compile them. Additionally, classes are stored with an isValid flag that is set to true as long as dependent metadata has not changed since the class was last compiled. If any changes are made to object names or fields that are used in the class, including superficial changes such as edits to an object or field description, or if changes are made to a class that calls this class, the isValid flag is set to false. When a trigger or Web service call invokes the class, the code is recompiled and the user is notified if there are any errors. If there are no errors, the isValid flag is reset to true."

I did a quick review of our Apex classes: 36 were set to Invalid. Ugh, that’s a lot of clean-up, and probably more than I can crank through in a single night.

@greenstork gave some helpful advice:



Alas, not so in our case – each of these 36 apex classes remained invalid, even after being viewed in production.

So what’s next?

1.) Short Term: I need to update the various test classes that flagged the DmlException errors, and modify them to support the recently added validation rules. Beyond that, I’ll need to look at other classes that are weak on test coverage, and move those to 100%. Then I can deploy my user's change sets.

2.) Long Term: The enterprise SFA application is much more complex than when the business owners first deployed and starting using it. Changes, like new validation rules or custom object / field edits can no longer be made in production. The business owners must adopt a more structured change management process, restricting their changes to Sandbox environments and allowing a QA/QC team to review the changes before deploying them to production. (Always a difficult political battle in any organization, but essential!)

3.) I need to update our Salesforce Audit report, with a periodic review of the “IsValid” field on Apex Classes. The purist in me says 36 invalid classes is too high; 0 is about right.

4.) I'm gonna need more coffee.

Sunday, November 1, 2009

Calculating Business Hours

The Problem

My client has a Service Level Agreement (SLA) in which they must respond to a certain type of service request within 2 business days. In Salesforce, they were trying to track what % of orders are serviced within the SLA period. To date, they had been calculating the SLA Due Date with a workflow rule. The workflow rule auto-assigned the SLA Due Date with a simple formula: today()+1. This was problematic for two reasons: (1) the formula didn’t factor in weekdays or company holidays, and (2) the process didn’t give consideration to “time of day”.



They understood the first point, but didn’t quite understand the significance of the second point. To illustrate, I described the following scenario: “Let’s consider the ideal case - an order comes in today at precisely 9:00 AM. By your formula, you have all of today and all of tomorrow to finish that order. If it takes you longer than tomorrow, you have exceeded your SLA. Now, let’s suppose an order comes in today at 4:50 PM. By your formula, you have only 10 minutes left from today and all of tomorrow to finish that order – anything after that and you have exceeded your SLA. Also, what happens if an order comes in anytime on a Saturday? By the time you get to work on Monday, you have already exceeded your SLA with the current formula.”


The light bulbs clicked on. We agreed they needed to start tracking the date/time of the order submission, and calculate the SLA Due Date by adding 16 business hours to that Order Submission date/time stamp.


Thought Process -- Getting to the End Solution

A reader recently asked me to share more details about how I get from Problem to Solution, so here we go:

  1. I started by checking out the Workflow formulas; in general, if I can solve a problem with clicks and formulas, rather than code, I’ll take that option. In this case, I couldn’t come up with a simple solution. There are no functions that allow for determining the “Day of Week” in a date field, nor an easy way to exclude company holidays from the SLA Due Date calculation.

  2. Whatever can’t be managed in a formula can almost certainly be managed in an Apex trigger. I visited the Salesforce Developer Community message boards, to see if anyone had done something similar. Before I write any code, I always visit the AppExchange and developer boards, looking for a short cut, inspiration or at least potential gotcha’s that other devs have run into. My quick search didn’t bear much fruit. Blanka and Rup3 had creative formulas that could be used in Workflow rules, but neither solved the problem of company holidays or calculating the value based on business hours. I spot checked a few other posts, but none provided they guidance I needed.

  3. Next, I pondered how non-Salesforce Developers might have tackled this problem. I did a Google search on “calculate business hours” and came up with this interesting post (and code sample) on the Code Project boards. The sample was written by perle1, and was exactly the logic I needed. Well, almost. Whle it would be pretty simple to convert perle1's C++ logic into Apex, his code still hadn’t tackled the problem of holidays.

  4. RTFM - Read the Foolish Manual. Yes, I probably should have done this sooner, perhaps at step 1, but I wasn’t entirely sure what I was looking for until I’d latched on to Perle1’s code. His sample focused my attention on company holidays. It was then that I recalled Company Profile configurations, which are a standard part of your organization setup in Salesforce.com. There had to be a way for my Apex triggers to use and offset with these configuration settings.



So I poked around the Apex Developers Guide, found the BusinessHours object and some nice sample code … and was pleasantly surprised. This was going to be a piece of cake! In fact, it looked like I’d be able to write this trigger in 4 lines of Apex code (compared with Perle1’s 90 lines of C++ code). Plus, I’d have the ability to handle holidays in the business hours calculation – without writing any extra code.


Here's the step-by-step:


1.) First, I entered in all of the company holidays (click Setup -> Company Profile -> Holidays). A nice Salesforce.com feature is that the holidays can be configured as "recurring", so you can set the holiday once, and then never have to worry about it. Recurring holidays are flexible, in that they can be set up to occur on a specific day of the year (i.e., Christmas is December 25th, every year), or on a date pattern (i.e., Labor Day occurs on the 1st Monday of each September).


2.) Next, I set up the business hours for the work group that was using this "Submitted Order" process. In Salesforce, click Setup -> Company Profile -> Business Hours. There was already a Business Hours record labeled "Default". I left that one there, and created a new Business Hours record labeled "BSC". I added in the service teams business hours, and included the company holidays. I set these hours as the new "default" for the org.


3.) Finally, here's the Apex Code that does all the work:


trigger calcBusinessHours on Submitted_Order__c (before insert, before update) {

// Assumes the BSC work hours are the default for the Org
BusinessHours stdBusinessHours = [select id from businesshours where isDefault = true];

for (Submitted_Order__c so : Trigger.new) {
if ((so.WB_Submitted__c != NULL) && (stdBusinessHours != NULL)) {
// BSC works 11.5 hours / day (8:00 AM - 7:30 PM, M-F). Our SLA is 2-days (23 business hours)
so.SLA_Due_Date__c = BusinessHours.addGmt (stdBusinessHours.id, so.WB_Submitted__c, 23 * 60 * 60 * 1000L);
}
}
}



Submitted_Order__c is the custom object that I want to determine the SLA Due Date from. This custom object has a date/time field labeled "WB_Submitted__c", and another date/time field labeled "SLA_Due_Date__c".


The "WB_Submitted__c" field has a date/time value when it is uploaded into Salesforce (by an external process). This is the date and time that the order was submitted to our support services group.


This function is triggered whenever a Submitted_Order__c record is inserted or updated in Salesforce. The trigger grabs the BSC work hours (which we configured as "default" in step 2), and then adds 23 business hours to that value to calculate the SLA_Due_Date__c field. NOTE: You'll want to change this if you're using 8-hour business days.


What if you needed to calculate the number of business hours between two date/time values, and record that into a number field? There's already a BusinessHours.diff method that does that work for you! NOTE: The answer is returned in milliseconds, so you need to do a little math to convert it to hours:


Hours_to_Close__c = BusinessHours.diff (stdBusinessHours.id, so.WB_Submitted__c, so.OA_Complete__c) / 1000 / 60 / 60;


How simple is that? Easy-peasy, lemon-squeezy!

Thursday, September 25, 2008

Calendar Application in Visualforce


Check this out (click to enlarge)! It’s my latest Visualforce application, written with a little help from Ron Hess (Developer Evangelist, Salesforce.com).

Background: Our Customer Support organization schedules periodic Maintenance Windows with our customers. During these scheduled events (usually late evening / early morning), our Support team assists the customer with hardware / software upgrades, mass configuration changes on their equipment, or other “professional services”. Like any organization, we are resource constrained, so we must be careful to not overlap more than 2-3 maintenance windows during the same time period.

Project Need: The Support team wanted an application that allowed them to view all maintenance activity in a monthly calendar format.

Here’s a screenshot of the custom tab, which uses Visualforce and Apex in it’s design. In Calendar mode, the user can see all the activities scheduled for the entire month. They can view activity from previous months, or future scheduled activity, at the click of a mouse.

Each scheduled item is color coded, based on the status of the maintenance activity:

- Black: Requested
- Blue: Scheduled / Resource Assigned
- Green: Success
- Red: Fail / Problems Encountered
- Olive Green: Cancellation

The color-coding updates automatically, whenever the case detail record status changes. For instance, when scheduled (blue) activity is finished, the Support Tech updates the status field in the Maintenance detail record. When this Calendar page is refreshed, the URL link to that activity changes from blue to green.

The Support Managers find this format much more practical than the custom Report / Dashboard views we had created for them previously. Those reports/dashboards provided the same information, but seeing the data in Calendar format is so much easier for them to see what's happening, and when.

This view helps prevent the scheduling of too many maintenance windows in a single night (although I'm going to add an Apex trigger to more tightly enforce that). The Calendar view also allows the support managers to look back at previous months, and see the volume of activity they've worked, including customer cancellations, failed activities, and successful acitivities. The data has always been in Salesforce, we're just displaying it in a different, more intuitive format -- and that's made a huge difference.

I mentioned earlier that this application was written with the help of Ron Hess. In truth, Ron unknowingly helped “jump-start” this project with his detailed post on the Salesforce.com Community forums. It's an old post, dating "way back" to April 2008. In that post, Ron provided some source code for a small calendar application he was using in conjunction with the Event object. I took snipets of that code, expanded on it, and my own calendar page then fell together quite easily.

That’s another great feature of Salesforce.com – the community forums are a great resource for getting information, ideas, and project “jump starts”.

Monday, September 15, 2008

Formating datetime variables in Apex

The current project I’m working on is a custom Visualforce page showing all of the scheduled maintenance activities my Support department has scheduled with our Customers. We have a custom object (Maintenance__c) which describes the details for the maintenance activity, including Start Date/Time and End Date/Time. I wanted to display this information in Calendar format using Visualforce. That way, my users can see, at a glance, what activities are scheduled throughout the month. I’ll show more of the application, as it develops, but for now I’ll focus on my first crisis.

The Problem: I wanted to display the current date in the subtitle of the section header. The code that does this is highlighted in the Page Editor section below, and the Visualforce page is right above it. It looks … fine. But I’m really, really fussy when it comes to page views. I didn’t like how the {!Today()} function returned “00:00:00 GMT” in the middle of the datetime output. Yuck! I wanted to see the information displayed in the “long date” format, just like I see in my Excel worksheets: “Monday, September 15, 2008”. I also didn’t like the fact that the datetime was GMT time, and my users would be mostly viewing this page from Eastern, Mountain or Pacific Time Zones. Apex to the rescue!



The Solution: I haven’t done much date manipulation in Apex, so I pulled out my trusty Apex Language Reference Manual. On page 182, the manual describes how you can use the “format” instance method to manipulate the date format: “format” takes a Java Class SimpleDateFormat string and the local time zone of the current user, and returns the datetime as a string. Perfect!

But what the heck is a “Java Class SimpleDateFormat” string? The document provided a link to the Java Sun website, where I learned all about date and time patterns, and using pattern letters to display full form vs. abbreviated form in datetime strings.

I switched over to my Sandbox, built a very simple Apex class to display the datetime in Microsoft (?) long date format:

public class MaintCalendar {

String LongDate = ' ';

// Init cLongDate with the current Datetime in long date format
public String getLongDate() {
Datetime cDT = System.now();
LongDate = cDT.format('EEEE, MMMM d, yyyy');
return LongDate;
}

}


The first line in my getlongDate method initializes the ‘cDT’ variable with the current datetime. The second line uses the “format” instance method to set a global string variable “LongDate”, using the following SimpleDateFormat string: ‘EEEE, MMMM d, YYYY’ The four letters indicate that the Day, Month and Year should be spelled out in full (non-abbreviated) form.

The code (and the VF page output) is displayed below.



Phew! Am I glad I figured that out. Every time I started working on the Calendar code, that ugly default date format in the {!Today()} function mocked me, telling me that I was making an ugly UI. Well, that’s enough code for this week … for some reason I now have a craving for orange creamsicles. Need to go find an ice cream truck.

Sunday, July 27, 2008

Insomnia



It's back, my dear old friend, Insomnia. Although it's different for me. I don't lie prone in bed, gazing wide-eyed at the cieling. Instead, I sit hunch-back over my keyboard, banging out code and crawling through the web.

Lately, I've been taking a deep dive into Apex and Visualforce, and it's really cool stuff. So cool, in fact, that I'll suddenly be concious of the birds chirping outside my window, and realize that I've been up all night coding again. My last meal was a soggy tuna sandwich about 16 hours earlier.

I do a lot of freelance work, but the current project is for my employer. My boss wants a feature added to Salesforce.com that allows his technical team to send a periodic email status update to various internal audiences when a high priority Case is opened. The tricky part is that there are different rules as to who the email should be sent to, depending on the severity (priority) of the Case and the Customer (Account) who opened the case, and the mail distribution rules change pretty frequently. The users can't easily keep track of these rule changes -- so we're going to let Salesforce.com do it for them. They just need to post the update, and my code under the hood will handle the email template preparation and distrubtion.

Before, I would have just banged this out with an S-control, but I thought I'd try this out with a combination of Apex and VisualForce pages instead. So I added a "Send Alert" button to the Case detail record page layout, and now I'm fighting the learning curve to implent this functionality in Visualforce.

I've poured through wikis, webinars and documentation posted on the Apex Developer Net forums. My mind loses all track of the passage of time, including recollection of when I last slept, when I last ate, when I last interacted with the human race. Still, I've learned a lot, and my "Send Alert Notification" components and pages are looking pretty slick.

I have to shift gears now, because I've been doing all my development (so far) in a production environment ... so naughty, I know. Last night, I hit a wall and realized I needed to create a new Apex Class, and it took me way too long to realize that the reason I couldn't make one was because I wasn't in a Developer edition or sandbox. Ooops.

I haven't done enough with the Sandbox, so now I need to go study up on it. I'll come back and share what I learn.