Tuesday, May 29, 2012

Things that are missing from Windows Phone 7

I'm really liking my Windows Phone 7 devices (an HTC Trophy 7 and a Nokia Lumia 800), but some features that I'd really like to use are currently missing from the platform. The good news is that most of the current shortcomings could be fixed in software. I figure the most productive thing to do is voting in the two applicable uservoice feedback websites:

Thursday, May 17, 2012

Salesforce - Apex Primitive Data Type for currency fields

The following apex code from another developer (outside my current employer thankfully) was a bit puzzling when I first encountered it:

public OpportunityLineItem workingUnitPrice {set; get;}

// ...

public FooBar() {
    workingUnitPrice = new OpportunityLineItem();
}

// Later, in method bodies etc...

workingUnitPrice.UnitPrice = 1.23;

An instance of OpportunityLineItem was created for the property in the constructor and then only the UnitPrice property was ever assigned to and bound from pages. I believe the intention here was to use a field of type currency.

According to the Currency Field Type docs:

Currency fields contain currency values, such as the ExpectedRevenue field in a Campaign, and are defined as type double.

But under Primitive Data Types - Decimal:

A number that includes a decimal point. Decimal is an arbitrary precision number. Currency fields are automatically assigned the type Decimal.

I've gone with the later and set the scale to 2 on a decimal.

private decimal internalWorkingUnitPrice;
public decimal workingUnitPrice {
 get {
  return internalWorkingUnitPrice;
 }
 set {
  if(value!= null) {
    // Set Scale to match currency
    internalWorkingUnitPrice = value.setScale(2, System.RoundingMode.HALF_UP);
  } else {
    internalWorkingUnitPrice = value;
  }
 }
}

Any related page reference needed to be switched from inputField to inputText or Salesforce gives the error:

Could not resolve the entity from  value binding '{!fooBar.workingUnitPrice}'.
 can only be used with SObject fields.

See also:

Friday, May 11, 2012

Salesforce - Unable to set OpportunityLineItem Quantity or TotalPrice when using Revenue Schedule

On an Org where the Product has been configured to use Revenue Schedules Salesforce was throwing the following exceptions when the Total Price or Quantity was updated directly on the OpportunityLineItem (that was associated with the Product via a PricebookEntry).

Upsert failed. First exception on row 0 with id 00ke0000000V9BDAA0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: TotalPrice (invalid total price change on opportunity line item): [TotalPrice]

Upsert failed. First exception on row 0 with id 00ke0000000V9BDAA0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: Quantity (invalid quantity change on opportunity line item): [Quantity]

It appears that if the OpportunityLineItem.HasRevenueSchedule is true then these fields will be set via the associated OpportunityLineItemSchedule records.

If this object has a revenue schedule, the Quantity and TotalPrice fields can’t be updated. In addition, the Quantity field can’t be updated if this object has a quantity schedule. Update requests aren’t rejected but the updated values are ignored.
[OpportunityLineItem.HasRevenueSchedule]

To change the Quantity on an OpportunityLineItem where HasRevenueSchedule is true any associated OpportunityLineItemSchedule records need to be deleted first. After the Delete you will need to retrieve the updated OpportunityLineItem to adjust the Quantity on or you can get an error about changing the UnitPrice and TotalPrice:

System.DmlException: Update failed. First exception on row 0 with id 00k4000000MXyoHAAT; first error: INVALID_FIELD, Cannot change both 'UnitPrice' and 'TotalPrice' in update call: [UnitPrice]

OpportunityLineItem oli = [Select Id, UnitPrice, TotalPrice, Quantity from OpportunityLineItem where Id = '00k4000000MXyoHAAT']; // Your OLI id here
OpportunityLineItemSchedule olis = [Select Id from OpportunityLineItemSchedule where OpportunityLineItemId = :oli.Id];

Savepoint sp = Database.setSavepoint();

delete olis;

// If the OLI isn't reloaded from the DB after deleting the OpportunityLineItemSchedule 
// records you will get the DmlException about changing both the UnitPrice and the TotalPrice
// due to the changes the deletion causes
oli = [Select Id, UnitPrice, TotalPrice, Quantity from OpportunityLineItem where Id = '00k4000000MXyoHAAT'];

oli.Quantity = oli.Quantity + 10;
oli.TotalPrice = oli.UnitPrice * oli.Quantity;
update oli;

Database.rollback(sp);

Tuesday, May 8, 2012

Salesforce - Referencing an installed Managed Packages code from Apex

When I first tried to reference an Apex class within an installed managed package I ended up with:

Error: Compile Error: Type is not visible: apexclassinmanagedpackage at line 7 column 36

To make this work I needed to add a specific reference from the Apex class to a version of the managed package in the version settings tab.

From the help documents:

Click Version Settings to specify the version of Apex and the API used with this class. If your organization has installed managed packages from the AppExchange, you can also specify which version of each managed package to use with this class. Use the default values for all versions. This associates the class with the most recent version of Apex and the API, as well as each managed package. You can specify an older version of a managed package if you want to access components or functionality that differs from the most recent package version. You can specify an older version of Apex and the API to maintain specific behavior.

This could also be handled in the <Your Class>.cls-meta.xml file locally.


The class, any applicable constructors, and method being called must also be marked as global rather than public. From the help documents:

  • The public access modifier declares that this class is visible in your application or namespace.
  • The global access modifier declares that this class is known by all Apex code everywhere. All classes that contain methods defined with the webService keyword must be declared as global. If a method or inner class is declared as global, the outer, top-level class must also be defined as global.

Also from the help documents:

global
This means the method or variable can be used by any Apex code that has access to the class, not just the Apex code in the same application. This access modifier should be used for any method that needs to be referenced outside of the application, either in the SOAP API or by other Apex code. If you declare a method or variable as global, you must also declare the class that contains it as global.
Note
We recommend using the global access modifier rarely, if at all. Cross-application dependencies are difficult to maintain.

See Also:

Wednesday, May 2, 2012

Salesforce requirements for enabling Person Accounts in an Org.

The following are the current requirements from Salesforce for enabling Person Accounts in an Org. Including these when raising your support case to have the feature enabled may save you a day of back and forth with support. Of course my blog isn't an offical source of information on the subject and the requirements will change over time so perform these steps at your own risk.

The turn around time to activate this feature could take 2 to 3 business days as the Support Engineer needs to review the technical specifications in your org.

Please agree and reply to this case OR submit a case comment with the following:

1. What is the Organization ID of the production or sandbox? (Navigate to Setup > Company Profile > Company Information):

2. I understand that once Person Accounts is activated, it CAN'T be deactivated (we encourage testing this feature in the sandbox or a Dev/Free Trial org):

3. I’m the system administrator authorized on behalf of this organization to request this feature:

4. I have completed the steps below:

To have Salesforce Support activate person accounts, please follow the instructions below.

PART 1: Create a standard account record type. If you are not familiar with this process, follow these steps:

1. Go to Setup | Customize | Accounts | Record Types
2. Create a New Record Type
3. Use "Business Account" as the record type name. You do not need to enable for Profiles (unless you intend to use this record type). Click Next.
4. Accept all defaults on the next page and click Save.

PART 2: Ensure that your organization-wide sharing settings for your organization have been set for the Contact record to be "Controlled by Parent." This can be verified through the click-path below:

Setup | Administration Setup | Security Controls | Sharing Settings

PART 3: Ensure that all of your profiles that have at least 'Read' permissions on the Account object, also have at least 'Read' permissions on the Contact object. This can be verified for a single profile using the click-path occur, but will need to be verified for all:

Setup | Administration Setup | Manager Users | Profiles

PART 4: Please be aware of the following limitations:

-This feature activation is permanent

-Person accounts are currently not supported in the Offline Edition. Person accounts will not be visible.

-If you are using Outlook or Notes, version 3.2 is required.

-Converting existing customer accounts to person accounts will require a data conversion process. More information about this process can be found here on this B2C Implementation Guide:
https://na3.salesforce.com/help/doc/en/salesforce_B2C_implementation_guide.pdf
https://na3.salesforce.com/help/doc/en/salesforce_B2C_cheatsheet.pdf

Please respond with the required information and your current contact number.

See Also: