You need to sign in to do that
Don't have an account?
Issues with Trigger to match fields and copy data based on match
This is kind of a two part question. First off I have a custom object called Country which has a multipicklist field called TimeZone. I have an identical field on Accounts. Ideally I want my trigger to do the following - If an account is created or the billing country is updated I want it to look for an exact match by BillingCountryName in the Account to the Country Records (Name field) and bring back the TimeZone information from the matching country record and plug it into the TimeZone field on the Account. I would also like to have it check US states and give specific time zones for those (so multiple IF statements) before it goes into the lookup portion of the trigger. For right now though I am just trying to get the portion where it searches the records and finds a match and brings back the timezone. I keep receiving an error saying "Compile Error: Invalid type: TimeZone__c at line 19 column 64" I'm sure it's just syntax but I've only done a trigger like this with a standard object so the custom part is throwing me off I think. Here is the code I have thus far:
trigger AccountTimeZone on Account (before insert,before update) {
// gather all the Country Name's in a set
Set<Name> setCountry_cNames = new Set<Name>();
Account[] Acc = Trigger.new;
for (Account a:acc)
{
setCountry_cNames.add(a.BillingCountry);
}
// store each Country Name with it's time zone in a map, such that Country Name => Country.TimeZone__c
Map<Name, TimeZone__c> mapCountrytoTimeZone = new Map<Name, TimeZone__c>();
for(Country__c c : [Select Name, TimeZone__c From Country__c Where Name IN : setCountry__cNames])
{
mapCountrytoTimezone.put(c.Name, c.TimeZone__c);
}
for (Account a:acc)
{
if(a.Timezone__c !=null)
{
a.Timezone__c = mapCountryToTimeZone.get(a.BillingCountry);
}
}
}
Right because at that line you are calling a put method when you should be calling get.
All Answers
When you are declaring your map the type needs to be a data type or an object custom object. Create the map as follows...
Map<String, Country__c> mapCountrytoTimeZone = new Map<String, Country__c>();
Your put methods can stay the same. This should get rid of the compile error. I have never used Name as a type in a map. I usually use String...since name is a string. You may need to switch your set to a Set of String instead of a name as well.
You have taken multi-select picklist field inside a map. this might be a problem.
Map<Name, TimeZone__c> mapCountrytoTimeZone = new Map<Name, TimeZone__c>();
If here you use any other field it would not throw the compile error e.g.
Map<Name, Site> mapCountrytoTimeZone = new Map<Name, Site>();
I changed the fields to text and updated the code to be strings but I keep getting Compile errors. It now says Compile Error: Incompatible value type String for MAP<String,Name> at line 24 column 7 (in red below)and it gives the same error if I change Name to Country__c. I still have to add all the caveats in and I can't even get the basic part to work. I've done this same thing before with IDs on standard objects but for some reason with Names and other fields on a custom object it is giving me issues. Any help would be greatly appreciated.
Thanks,
Amanda
trigger AccountTimeZoneUpdate on Account (before insert,before update) {
// gather all the Country Name's in a set
Set<String> setCountryNames = new Set<String>();
Account[] acc = Trigger.new;
for (Account a:acc)
{
setCountryNames.add(a.BillingCountry);
}
// store each Country Name with it's timezone in a map, such that CountryName =>
Country__c.TimeZone__c
Map<String, Name> mapCountrytoTimezone = new Map<String, Name>();
for(Country__c c : [Select Name, Time_Zone__c From Country__c Where Name IN :
setCountryNames])
{
mapCountrytoTimezone.put(c.Name, c.Time_Zone__c);
}
for (Account a:acc)
{
if(a.BillingCountry !=null)
{
a.TimeZone_2__c = mapCountrytoTimezone.put(a.BillingCountry); //
}
}
}
What datatype is TimeZone__c
TimeZone__c is a multipicklist but in all but the notes I changed it to Time_Zone__c which is a text field.
try a map of String,String...make sure to change it on both sides of the constructor.
If I change both to String on both sides of the map the error changes to
Compile Error: Method does not exist or incorrect signature: [MAP<String,String>].put(String) at line 32 column 30
Thanks,
Amanda
Right because at that line you are calling a put method when you should be calling get.
That worked! My other trigger that is based off IDs uses put in that spot....why would it change to get for this one? Now I just have to figure out how to add multiple if then statements....is that possible? Essentially like a formula but in a trigger? So far all my triggers only have one if statement.
Thanks,
Amanda
Put adds a key and value to the map. Get retrieves the value based off of the key you supply. So in this case you are retrieving the time zone based off of the Country Name key.
Yes you can have multiple if and else statements in a trigger.
I've got my if else statement in and working - just a quick question about if I'm doing my OR statements properly or am I using too much defining? What I've started with is the Eastern Time zone by state and have
if (a.billingcountry == 'United States'&& (a.billingstate == 'CT'|| a.billingstate == 'DC'|| a.billingstate == 'DE'|| a.billingstate == 'FL'|| a.billingstate == 'GA'|| a.billingstate == 'IN'|| a.billingstate == 'ME'|| a.billingstate == 'MD'|| a.billingstate == 'MA'|| a.billingstate == 'MI'|| a.billingstate == 'NH'|| a.billingstate == 'NJ'|| a.billingstate == 'NY'|| a.billingstate == 'NC'|| a.billingstate == 'OH'|| a.billingstate == 'PA'|| a.billingstate == 'RI'|| a.billingstate == 'SC'|| a.billingstate == 'VT'|| a.billingstate == 'VA'|| a.billingstate == 'WV'|| a.billingstate == 'ON'|| a.billingstate == 'QC'|| a.billingstate == 'NB'|| a.billingstate == 'NS'|| a.billingstate == 'NL'|| a.billingstate == 'PE')) {
a.TimeZone__c = 'Eastern Time GMT-5';
Do I need to have a.billingstate == repeated for each state or is there a way to shorten that?
Thanks so much,
Amanda
You have to define it somewhere so this works. If you ever wanted to reuse this in other classes then you may consider creating a static method that you pass the country and state in...then your method could return the time zone. The static method would look like that but it would be reusable.
Can you please mark my previous posts as a solution. Thanks. This way others may view it and benefit.
Thanks so much. Your response regarding methods makes me worry I'm going to have a time trying to get the test class right but we'll see. I posted the final part that got the first section of code working as the solution, although really it was multiple ones together that helped....kinda wish you could mark multiples but I guess it doesn't matter.
Thanks again,
Amanda
Got most of my test class done but I am getting a failure - System.AssertException: Assertion Failed. Says line 34, column 1. Debug log says FATAL_ERROR|System.AssertException: Assertion Failed
Class.AccountTimeZoneUpdate.testTrigger: line 34, column 1
11:51:53.690 (1690610000)|FATAL_ERROR|System.AssertException: Assertion Failed
Class.AccountTimeZoneUpdate.testTrigger: line 34, column 1
11:51:53.121 (1690629000)|
Here is my test class. I tried removing the reload part thinking maybe that was it but that didn't help. Aside from the Assertion failure I don't know how to get it to cover the line in the trigger "mapCountrytoTimezone.put(c.Name, c.TimeZone__c);" but I'm more worried about the Assertion failure.
Thanks so much,
Amanda
You need to insert the Country first for a to work. When a is inserted it is looking for a country object but none exist. All test data has to be created when you use @isTest. You can specify
@isTest
(SeeAllDate = true)
which would allow you to use Country objects you already created. But it is considered best practice to construct your own objects in your test class. This will ensure that when you move this code to another org it will not fail.
So construct and insert all of your Country objects first. One needs to match for each of your accounts. Then insert the accounts.
Currently since there is not a match for a1-a7 those will fail as well until you construct and insert country objects.
Also as a suggestion since you are inserting so many accounts.
It may be best to add them to a List<Account> first then insert them all in one DML. But that is just another best practice.
Andrew,
I tried changing it to insert the two countries I'm testing first and then the accounts but I'm still getting the same assertion error.
You have to query the updated accounts and then assert against the query results. A is a reference to the object you created without the trigger updates to it.
so for example
Before your assert you can do
a = [SELECT TimeZonePickList__c FROM Account WHERE Id = :a.Id];
then your first assertion would work.
I had that in previously and took it out because it seemed like it wasn't doing anything. I just added it back in and tried calling all of them seperately (as you see below) or above each of their assert lines and neither way worked. It is still saying Assert failed. I think the daylight savings time switch must be getting to me or something.
Thanks,
Amanda
for(Account acct : Trigger.new){
if((acct.OS_Address_1__c==null && acct.OS_City__c==null &&
acct.OS_State__c==null && acct.D_B_Country__c==null &&
acct.D_B_Postal_Code__c==null) &&
( acct.BillingStreet !=null || acct.BillingCity !=null ||
acct.BillingCountry !=null || acct.BillingPostalCode !=null ||
acct.OS_Address_1__c = acct.BillingStreet;
acct.OS_City__c = acct.BillingCity;
acct.OS_State__c = acct.BillingState;
acct.D_B_Country__c = acct.BillingCountry;
acct.OS_Postal_Code__c = acct.BillingPostalCode;
}
}
}
I'm not fully following what you are trying to do here. How do you plan to convert a country name of any value to a standard country name? And then why are you copying it to a custom country field? Can you explain this in a bit more detail? Also it would probably be best helped via starting a new Message.
Thanks,
Amanda
Billing Country is text field and can have any value. We need to convert it to Standard Country name before copying it over to custom country field using the ISO – Country mapping.
Fields:Account Object Fields: Countries Object
OS_Address_1__c--Text(200) Country__c -- Picklist
OS_City__c --Text(100) ISO2__c -- Picklist
OS_State__c --Text(100)
OS_Postal_Code__c --Text(40)
D_B_Country__c --Picklist
ISO_Country_Code__c--Text(2)
Standard Fields
Billing Address Address