function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Kenji776Kenji776 

Save and Return to case button

Hello All.
I have made a new custom object called PETE items. Basically when our software has a bug, we put it into this internal development software (PETE). When phone support people find a bug, they report it through PETE, so it is nice to be able to keep track of what cases are waiting for what development fixes, hence I made the PETE items custom object. I want this to work similar to solutions, and have a few questions. (I am very new to coding s-controls, and have a fundamental understanding of javascript, but all of Salesforce's queries and special commands are very tricky).

1) I pretty much want to replicate the solutions functionality through and through, the attaching, searching, all that good stuff. Does anybody have a way that I can just copy the solutions and all it's functionality and modify it to my needs? I need to keep solutions in tact though. I know this probably isn'g going to happen, just figured it's worth a shot.

2) I want to add a save and return to case button, say you are entering a case, need to create a PETE item, so you click the New on the PETE items related list. This brings you to a screen to enter your PETE item, which is very cool. However, once you save it, I want it to return you to your case you were working on. I planed to make a custom button called "Save and Return" but am confused on how to code it. I have all the field names that could be updated from this form pasted below (straight out of the WSDL).

<complexType name="PETE_Items__c">

    <complexContent>

    <extension base="ens:sObject">

    <sequence>
<element name="Account__c" nillable="true" minOccurs="0" type="tns:ID"/>
<element name="Account__r" nillable="true" minOccurs="0" type="ens:Account"/>
<element name="Attachments" nillable="true" minOccurs="0" type="tns:QueryResult"/>
<element name="Case__c" nillable="true" minOccurs="0" type="tns:ID"/>
<element name="Case__r" nillable="true" minOccurs="0" type="ens:Case"/>
<element name="Change_Type__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="Comments__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="Contact__c" nillable="true" minOccurs="0" type="tns:ID"/>
<element name="Contact__r" nillable="true" minOccurs="0" type="ens:Contact"/>
<element name="CreatedBy" nillable="true" minOccurs="0" type="ens:User"/>
<element name="CreatedById" nillable="true" minOccurs="0" type="tns:ID"/>
<element name="CreatedDate" nillable="true" minOccurs="0" type="xsd:dateTime"/>
<element name="Description__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="Histories" nillable="true" minOccurs="0" type="tns:QueryResult"/>
<element name="How_to_Reproduce__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="IsDeleted" nillable="true" minOccurs="0" type="xsd:boolean"/>
<element name="LastModifiedBy" nillable="true" minOccurs="0" type="ens:User"/>
<element name="LastModifiedById" nillable="true" minOccurs="0" type="tns:ID"/>
<element name="LastModifiedDate" nillable="true" minOccurs="0" type="xsd:dateTime"/>
<element name="Name" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="Notes" nillable="true" minOccurs="0" type="tns:QueryResult"/>
<element name="NotesAndAttachments" nillable="true" minOccurs="0" type="tns:QueryResult"/>
<element name="PETE_ID__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="Present_in_Build__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="ProcessInstances" nillable="true" minOccurs="0" type="tns:QueryResult"/>
<element name="ProcessSteps" nillable="true" minOccurs="0" type="tns:QueryResult"/>
<element name="Subject__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="SystemModstamp" nillable="true" minOccurs="0" type="xsd:dateTime"/>
</sequence>
</extension>
</complexContent>

3) How can I add an "Attach" button to the PETE items related list, say you didn't want to create a new item, but wanted to attach an existing one, what would be the code for that?

4) PETE items, like cases must be attached to contacts and accounts, in a case when you attach it to a contact, the account is automatically filled in, I would like to replicate this behavior. I have 2 lookup fields, but they don't seem to be "linked" so selecting a contact doesn't select an account.

If you have any idea on any of these, or even some links for reading that would help, please let me know. Thank you!
werewolfwerewolf
1) I don't really understand your question here.  You want to use Solutions for PETEs?  Have you considered making a PETE just a record type of Case, rather than recreating it entirely?

2) Bear in mind that you can't make custom buttons on edit screens right now, which sounds like what you're trying to do.  You can make a button on the Case detail page which brings you to a new PETE edit page, though.  To make it return to the Case when saved, just set its retURL and saveURL parameters.

Let's say your PETE custom object has an entity ID of a1v.  Then your custom button should redirect the page to the following URL:

/a1v/e?retURL=/{!Case.Id}&saveURL=/{!Case.Id}

3) It usually goes the other way around, where you go to the PETE you want to parent to the case and set the case ID there.

4) See #1.  The quickest way is not to try to replicate Case but to actually use it.  The other way to do this would be to make an Apex trigger which pulls the account from the contact and fills in the relevant lookup field.
Kenji776Kenji776
Hey, thanks for the reply.
Sorry I didnt' such a great job explaining the situation, you know how it is, once your working on something for a while, you forget not everyone else knows what your doing!
Bascially a PETE is something that will be sent to an external system, our internal development system, so for modularity sake, I wanted to make them into their own objects. This also makes for easier browsing, and the boss seemed to like idea, so I ran with it. I don't want to use solutions for PETE's, I just like how solutions integrate into cases, how they can be attached to multiple cases, easily searched and linked and so on. We did have PETE as a type of case for quite some time, but it got to be kind of unruly with how much extra data had to be stored in each case just for PETE items, especially if they wern't even in a PETE status. Also since they are going to integrate with other systems, making them into their own object gives me a little extra control of data, and such. I made alot of progress, and pretty much have it the way I want it, I just wanted that save and return to case. However, noting that I cannot have buttons on edit screens, I'd be happy with a Goto case link or button, which should be pretty easy, just tag on the case number in a URL and we are good to go. In your sampel of
/a1v/e?retURL=/{!Case.Id}&saveURL=/{!Case.Id}
could you explain that last SaveURL= part? does that really making saving a record, as easy as just putting in the id of the object you want to save? I've been looking for a way to "recreate" the save button, while adding additional functionality, and if it's just that easy, I'll be one happy dude.

About 4, the apex trigger, that is the road I was heading down, to bad I don't know much apex yet, so I was just going to use some javascript to make it fill in the fields when you pressed a "complete this form" button. The apex would be sweet. Any pointers? Sorry I know I ask alot, I don't have alot of resouces to draw on, I am a mediocre programmer who has been put in charge of this system, and they are wanting all kinds of cool things. Before this I was a web dev, working with cold fusion and SQL, trying to learn Apex, and more complex javascript, and how the salesforce API works is proving to be rather challenging. Anywho, thanks for all the help. I'll be looking forward to any additional insight.

Also, just so you know, this is the message from my boss on what he wants:
"A cool new feature would be to have a way after you select a solution to automatically close the case and e-mail the solution to the customer"
That's kinda what spawned this project.


Message Edited by Kenji776 on 02-17-2008 12:28 AM
Kenji776Kenji776
Well I almost have done what I need, now I'm just getting some goofy sObject error. Basically I wrote a button called autofill form, it grabs the case number you specified, and from that is able to deduce the contact name, and the company name related to the item, along with the company identifier (CID). When you press the button, it throws the error


I am not really sure what to do, the object name "PETE_Items__c" does have the __c on it. Below is the code for my button. Any help is appreciated.

<script src="/soap/ajax/9.0/connection.js"></script>
var callback = {
onSuccess : displayResult,
onFailure : displayError
};

var peteResult = sforce.connection.query("SELECT id FROM PETE_Items__c WHERE item_ID__c='{!PETE_Items__c.Item_ID__c}'");

var peteRecords = peteResult.getArray('records');

alert('PETE ID is: ' + peteRecords[0].Id + '.');

//Query Case number from PETE item to pull the Name, and account number

var contactResult = sforce.connection.query("SELECT SuppliedName, AccountId FROM Case WHERE CaseNumber ='{!PETE_Items__c.Case__c}'");

//Set up the contRecords array as a result of the query
var contRecords = contactResult .getArray('records');

//Set the account number as the accountId pulled from the query above
var accountId=contRecords[0].AccountId;

//Query the account object with the info above to pull the actual account name, and the CID.

var accountResult = sforce.connection.query("SELECT Name,CID__c FROM Account WHERE Id='"+accountId+"'");

//Set another array with the results from this last query.
var acctRecords = accountResult.getArray('records');

//Set up a new PETE object
var myObj = new sforce.SObject("PETE_Items__c");

//Assign Values to the various PETE fields
myObj.id = peteRecords[0].Id;
myObj.Contact__r = contRecords[0].SuppliedName;
myObj.Account__r = acctRecords[0].Name;
myObj.CID__c = acctRecords[0].CID__c;

alert('Updating PETE item ' + myObj.id + ' with Contact of ' + myObj.Contact__r + 'and account of' + myObj.Account__r + 'with CID of: ' + myObj.CID__c + '.');
//Push changes into salesforce
 sforce.connection.update([myObj], callback);

function displayResult(result) {
alert("Record updated!");
alert(result);
}

function displayError(error) {
alert("oops something went wrong");
alert(+ error);
alert(error);
alert(result);
}



Message Edited by Kenji776 on 02-17-2008 02:40 PM
Kenji776Kenji776
Hey everyone,
Well I managed to fix it, I'll post what I figured out, in hopes of helping any other poor newbs out there. Basically what it seems like is that I was trying to update the wrong field. Contact and Account, which I was trying to update on this PETE object are both lookup fields, so they can what seem to be two names, a C record, and an R record, ex (Account__c and Account__r). This whole time I had been trying to write the account name and the contact name to the R fields, but instead I needed to write the ID's to the the C fields. So I just ajusted my queries to select the ID's, and save those to variables, and push that as an update, and it worked. Attached is the code for my working button. This is onclick javascript in a custom button.

{!requireScript("/soap/ajax/11.1/connection.js")}
try
{
//--------------------Grab the PETE ID and stick it into a variable -------------------------------------
//-------------------- so we can Update this record later -------------------------------------------------

var peteResult = sforce.connection.query("SELECT id FROM PETE_Items__c WHERE item_ID__c='{!PETE_Items__c.Item_ID__c}'");
var peteRecords = peteResult.getArray('records');

//--------------------Use the case number on this item to query -------------------------------------
//--------------------the case for the account and contact id's -----------------------------------------
var contactResult = sforce.connection.query("SELECT ContactId, AccountId FROM Case WHERE CaseNumber ='{!PETE_Items__c.Case__c}'");

var contRecords = contactResult .getArray('records');

//--------------------Set up the accountid var as what we got from above --------------------------
//--------------------Then query the actual account for it's CID and ID--------------------------------

var accountId=contRecords[0].AccountId;
var accountResult = sforce.connection.query("SELECT Name,CID__c, Id FROM Account WHERE Id='"+accountId+"'");
var acctRecords = accountResult.getArray('records');

//Set up a new PETE object
var PETE_Items__c= new sforce.SObject("PETE_Items__c");

//Assign Values to the various PETE fields
PETE_Items__c.Id = peteRecords[0].Id;
PETE_Items__c.Contact__c = contRecords[0].ContactId;
PETE_Items__c.Account__c = acctRecords[0].Id;
PETE_Items__c.CID__c = acctRecords[0].CID__c;

//Push changes into salesforce
  result = sforce.connection.update([PETE_Items__c]);
 
  if (result[0].getBoolean("success")) {
     window.location.reload();
  } else {
    alert("Tried to Autofill form from invalid case. Please make sure the case has both contact and account information associated with it before attempting to use this button.");
  }

}
catch(err)
{
alert("Could not fetch contact information. This attached case must be associated to a contact before using this button.Please go and fill out the case properly before attempting to create a PETE item related to it.");
}

Hope this helps somebody out there so they don't have to go through the same trial and error I did!
HardhatHardhat

Right, the __r fields are actually reference fields with which you can do joins (like you can find the account's name with Account__r.Name, but they're not settable.

I think it would be much better if you were to use a record type on Case rather than create a whole new object.  It's easy enough to modify your reports to exclude cases of that record type, and then you would have everything you need (the contact-account linkage, the solutions) baked in, plus with a record type you could enforce an entirely different layout.  Have you used record types at all?

Kenji776Kenji776
Hardhat,
Thanks for the input. I guess I probably should have asked for the best way to do things before I already had em almost done! Oh well, I'll have to remember that for next time. I have used record types a little, I only found out about them really after record types made some options not visable to some users, and nobody could figure out why. I haven't had a lot of need to hide certain options for users, I suppose when I need to, I'll know what to do. There is probably more to them than just using them to hide options from users, but if so I havn't figured out what they are good for yet. My new object is working pretty much just how I want it to now, I only wish I didn't have to have the user click that autofill button for it to run that S-control, like if I could build it into the save, or use ajax to grab the values as soon as they choose the case. Anyway, thanks again for the help, I'll have to make sure to do more research next time before I just start working, little did I know there was this easier solution all along. Eh, it's done now, so whatever.
HardhatHardhat
Also, what you did might be better done in an Apex trigger, since it wouldn't require the user to click any buttons -- it would just happen, say if the account field were empty but the contact is not then fill the account field with the contact's account.
Kenji776Kenji776
Yes, I would love to do that. I only just started figuring out the javascript stuff, not sure if I have any chance at all of turning that into apex/ajax. Any help would be much appreciated, just some sampel code or something would be great. Buttons suck. Thanks!