Task Based UI @ Siebel 7.8 | Next Tip »Home

Restricting record deletion

OkAvarageGoodVery GoodExcellent (8 votes, average: 4.63 out of 5)
Loading ... Loading ...

Requirement:

We have Opportunities as Parent and Activities (Action BC) as child. Allow users to delete records from an Activities List Applet, only if more than 1 record is present.

Analysis:

Requirement seems pretty simple when we read the requirement statement. One thing is very clear that we have to use scripting. When we have to do scripting there are two important questions that we should ask before we get down to write script

Which event to write the script on?
Why to write script on that event?

I always believe that scripting is easy but to script on right event and in right way is difficult.

Solution:

I came across a script shared by somebody for the solution of the above problem. I will discuss that script before telling you my own version of that script.

function BusComp_PreDeleteRecord ()
{
var currentView = TheApplication().ActiveViewName();
if(currentView =="Opportunity Detail - Activities View")
{
var optyid = TheApplication().ActiveBusObject().GetBusComp("Opportunity").GetFieldValue("Id");
var oBO = TheApplication().GetBusObject("Opportunity");
var oBC = oBO.GetBusComp("Action");
with(oBC)
{
SetViewMode(AllView);
ActivateField("Opportunity Id");
ClearToQuery();
SetSearchSpec("Opportunity Id", optyid);
ExecuteQuery(ForwardBackward);
if(FirstRecord())
{
var isRecord = NextRecord();
if(isRecord < 1)
{
TheApplication().RaiseErrorText("Msg");
return (CancelOperation);
}
}
}
}
oBO = null;
oBC = null;
return (ContinueOperation);
}

At first look the script seems to be fine and will serve the purpose but if you closely analyze the script you will find out there is lot of scope for improvement in the above script. Let’s discuss what is wrong

  • function BusComp_PreDeleteRecord ()
    I think it is a wrong choice of event because if user creates a new record and clicks on UNDO then also PreDeleteRecord and DeleteRecord events are called and in that case also this code is going to execute, which actually is not required.
    Also the statement
    var currentView = TheApplication().ActiveViewName();
    if(currentView =="Opportunity Detail - Activities View")

    is only required because we are writing the script in BC and not on applet. So it will be better to write the script at applet rather than BC
  • ExecuteQuery(ForwardBackward);
    Lot of times we don’t pay attention to cursor mode we are defining while doing ExecuteQueryForwardBackward (which is default cursor mode) is only required if we have to do a Previous Record in our code and in that case it is not required so the cursor mode here should be ForwardOnly.
  • if(FirstRecord()) { var isRecord = NextRecord();
    This code is not required there is function called CountRecords that can give number of records present so the condition should be if(oBC.CountRecords == 1) then error
  • return (CancelOperation);
    There is no need for return(CancelOperation) as RaiseErrorText means that stop execution and next statements are never executed and here that would mean that oBO and oBC are never made null when error is displayed. Always make variables null in finally block.

My Solution:

In Applet PreInvokeMethod write the following script

 if(MethodName == "DeleteRecord")
   {
     if(this.BusComp().CountRecords() == 1)
        {
          TheApplication().RaiseErrorText("Error!!!");
        }
   }

I hope this post puts helps you to write better scripts in future.

  • Share/Bookmark

Related Posts


Article by neel

Authors bio is coming up shortly. neel tagged this post with: , Read 387 articles by neel
  • VerteX
    Well, I meant to use something like this:
    Named Method 1
    "Test", "INVOKE", "Opportunity", "RefreshRecord"

    And calling this method "Test" through Runtime Event every time an activity is deleted. This won't work however with DeleteRecord event since there would be no record to invoke the method on. But PreDeleteRecord will do (RefreshRecord doesn't requery the underlying BC so the activity should be deleted anyway).

    If even PreDeleteRecord wouldn't do the trick, you can always use a Workflow (if you are into sadomasochism) or write a simpe script in Activity.DeleteRecord:

    try {
    ParentBusComp().InvokeMethod ("RefreshRecord")
    } catch (e) {
    }
    // The next line might be needed so that count field is propagated downward (might work without)
    // InvokeMethod ("RefreshBusComp")
  • Y
    I agree with VerteX.
    We faced the same requirement (and same problems as well).

    "Count (MVL)" doesn't work if you do not perform "Refresh" operation.
    Suppose you delete 1 out of 5 Activities present for any Opty, the Field which stores the count of Activities would show 5 (and not 4) unless and until you have performed "Refresh" operation.

    We finally opted for scripting @ BC level (PreDelete event).

    @ VerteX:
    Can you please elaborate your last line - "To prevent this you can use Named Method user property to invoke RefreshRecord on parent buscomp (Opportunity) after an activity is deleted."
  • VerteX
    >> One thing is very clear that we have to use scripting

    Hmm, this is quite unclear to me :)
    What would I do:

    1. Create a field in Opportunities which would calculate Activities count
    Name: Test Count
    Calculated Value: Count ('Action') or whatever MVL there is. Create your own if there is none
    Type: DTYPE_INTEGER
    Link Sprecification: Y

    2. Create a field in Activities which would disable DeleteRecord functionality
    Name: NoDelete Flag
    Calculated Value: ParentFieldValue ('Test Count') <= 1
    Type: DTYPE_BOOL

    3. Create a user property in Activities
    Name: NoDelete Field
    Value: NoDelete Flag

    That is all. Whenever there is only one Activity the DeleteRecord will be disabled (why alert Error!!! anyway?)

    There is a certain drawback in this solution: field Test Count is not refreshed until activities are requeried. That is, user can delete all activities in a row if he presses Ctrl-D continuosly.

    To prevent this you can use Named Method user property to invoke RefreshRecord on parent buscomp (Opportunity) after an activity is deleted.
  • Neha
    Hi Neel,

    I used the following script for restricting the deletion of a record, this does not give any syntax error but it lets delete the record even if it is associated to another record.

    function BusComp_PreDeleteRecord()
    {
    var sPlanId = this.GetFieldValue("Id");
    var oBO : BusObject;
    oBO = TheApplication().GetBusObject("BO1");
    var oBC : BusComp;
    oBC = oBO.GetBusComp("BC1");
    with (oBC)
    {
    SetViewMode(AllView);
    ActivateField("Id1");
    ClearToQuery();
    SetSearchSpec("Id1", sPlanId);
    ExecuteQuery(ForwardOnly);
    If (FirstRecord())
    {
    TheApplication.RaiseErrorText("Error");
    return(CancelOperation);
    }
    }
    oBC = Null;
    oBO = Null;
    return(ContinueOperation);
    }

    Please suggest what is wrong here.

    Thanks.
  • Pankaj
    Neel,

    Just a concern, how will query be fired if MVL is used. Only if you expose this Calculated Count MVL field on Applet, it will fire. right ?
  • Here are my reason to absolutely not go for MVL or Links

    1 Soution

    Imagine that you are at a screen with opportunities list applet at top and opportunities form applet at bottom (No Action BC in picture).

    But because of MVL and Count calculated field there will queries fired on Action BC even though there is no need. In case there were 10 records were to be displayed in list applet 10 queries will be fired on database which are absolutely unncessary.

    and similar is the case with 2nd solution where query will be fired every time action comes into picutre even when user is navigating UI, chaning records or adding records.

    But with scripting in this case our code will only be fired when user actually tries to delete the record and also because we are scripting at applet that means there is no impact on Action BC.

    So, it least in this case I can see Scripting is better than configuration
  • bob
    @Joy : the No Copy and No Delete do not impose the restrict on the deletion of activities, for the restriction you have to use the No delete user property ...
    If you do not set the No Copy flag to yes, when you will copy an activity, the link will try to copy all the linked activity too ... idem for the No delete ...

    @Neel : actually you script is wrong for the reason Mike M. Lin explain.
    But doing the same script out of the contexte will work.

    There are 3 solutions :
    1- link beetween opportunity and its actions
    - a Count(MVL) field on opportunity (CountMVLField)
    - a No Delete user prop on Action with value based on ParentValue( CountMVLField )

    2- link beetween action and its same opportunity actions
    - a Count(MVL) field on action
    - a No Delete user prop on Action with value based on CountMVLField

    3- the scritpt but no in the context...


    The right solution is for me between 2 and 3, it depend on the numbers of actions, links may have bad performance issues.
  • Joy
    I am with you Neel here. Using the solution of BC User Prop will restrict the deletion of Opty record and not the Activity.

    Bob, Can you please explain how will the No Copy and No Delete impose the restrict on the deletion of the Child records only under the condition of the Count(MVL).

    Thnx
  • Be careful Neel. You approach is actually functionally different than the original script. The reason is that you are using the UI instance of the Action buscomp to count records, and the original script does a clean query on the database, based on the parent opportunity.

    Where this differs is when there is a search/filter applied to the Action buscomp, like when a user queries for a subset of activity records.

    If the opportunity had five activities, you should be able to delete any four. However, if the user queried for one of the five activities in the child applet, she would not be able to delete that activity with the revised script - although she would have been able to with the original.

    No comment on what the actual best solution may be ;)
  • Yes,
    Mike you are right. I didn't do a proper analysis of solution I have provided.

    I will have to think about solution again, keeping in mind everything. will update the post to reflect this.
  • Bob
    and of course to prevent loop you should set "No Copy" and "No delete" to "Y" on the MVL
  • Bob
    sorry for my first comment, i was no in a good day ...

    I think we understod you behaviour, the link is between Action.Opportunity Id and Action.Opportunity Id. So earch action will know how many actions are link to the same opportunity.
  • I think I didn't explain it properly.

    We need count of Action Records on Action BC Not on Opportunity.

    If the requirement would have been

    "If there is only 1 record in Activities then don't allow user to delete opporutnity" then your solution would work but in this case we want to stop deletion of activities.

    I hope I am clear now.
  • KL
    Hi,

    Create a Field 'X' with Calculated Field = IIF ([count(MVL Name] > 1, Y, N)

    and the use user property "NoDelete Field"=X on the BC

    Please let me know if this works

    Thanks
    KL
  • Bob,
    It is not everyday that I get such blunt and honest feedback but I guess that is part and parcel of writting.

    But I still would like to know how to use NoDelete userproperty in this case. If I understand correctly this user property takes a field name as an argument that should return a boolean value Y or N.

    Now, here the requiremet is to get a 'Y' value if record count is greater than 1.
    Any idea how get a record count without using script????

    P.S. : It is not a wrong solution. May be not the best but definately not wrong
  • Bob
    In your 3 line script, TheApplication().RaiseErrorText("Error!!!") should be replace by TheApplication().RaiseError("MyMessageCategory");

    And by the way as said by Ayoub the right solution was the use of the NoDelete Field user property.

    If the articles are made to help beginners, make sure not to tell wrong solutions ...

    So thanks to Ayoub for making this totally useless article a little more interesting.
  • Neel,
    I like your short and sweet code style.

    Wouldn't this also work on the BusComp_PreInvokeMethod event? You may have to check for a given view (as you mentioned in your initial post), but then it would fire any time the BC is "in play" vs. having to add that code to every Opty applet.

    Just a thought.
  • Ayoub
    TJ,

    there is a BC user property : "NoDelete Field" with the calculated field (count(MVL)>1) as Value

    So if the Value is 'Y' you could delete, else you couldn't

    thanks
  • TJ
    @Ayoub
    Does siebel provides any user property like that?

    Let if the same condition is on the parent BC. and you have count of child records, in that case can we restrict the user from deleting the header by using a user property?

    thnx in advance.
  • Ayoub
    Neel,

    Yes you are right, I said the MVL is on Opportunity (Opty BC)

    the MVL will have Action is Child BC.

    Sorry for the misunderstanding.
  • Ayoub,

    MVL is used to pull child fields on parent, that means that you can have field calculated field on opporunity and not on child.

    I am not sure how would use count in this case as it will not be available on action
  • Ayoub
    Exactly, you can use Data validation to meet your requirement without coding.

    Also:

    Create an MVL on Action on Opty BC and use a calculated field to hold count(MVL) then use a BC user property Delete records if only count>1

    thank you
  • I remember using Data Validation Manager for similar requirements. The benefit is that you can administratively change the rules (instead of changing the script and redistributing the srf file) and use runtime events to call the Data Validation Manager.

    If you have Siebel 8.0 or later you can also go into using the Haley product to manage the rules.

    As always, your ambassador for less script and more spare time ;-)

    @lex
blog comments powered by Disqus

Polls

Do you like the new Comment System and new look to Site?

View Results

Loading ... Loading ...