AppleScript:IF command doesn't execute - if-statement

I am a beginner at AppleScript so I really don't know a lot. I have been trying to make the user select from a list of situations and then based on what they choose have an appropriate response. However, I have run into a few problems:
The script runs but doesn't display the notification.
Is there a better way than just chaining a lot of IF statements?
PS: I am nowhere near finishing this whole script.
on run
choose from list {"Thunderstorm", "Flood", "Heatwave", "Hazmat"} with prompt "Please select one of the emergency situations below" without multiple selections allowed and empty selection allowed
return the result as string
if string is Thunderstorm then display notification "hello"
end run

You made some pretty good guesses about what the sample code you were looking at does; but some of those guesses were wrong. With time you’ll get a better feel for how AppleScript works.
You have the situation names entered correctly as strings in the choose from list line, by surrounding their text with quotes. But in the check to see whether it’s a thunderstorm, you do not surround that text with quotes. AppleScript is looking in a variable called Thunderstorm for its contents, not looking at the string of text “Thunderstorm”.
return the result as string does not create a variable called string but rather ends the handler called run, returning the result to whatever code called run, as a string of text. To assign the result of choose from list to a variable, use something like set theSituation to the result as string.
Here’s an example of how your code might work better:
on run
--get the situation we're dealing with
choose from list {"Thunderstorm", "Flood", "Heatwave", "Hazmat"} with prompt "Please select one of the emergency situations below" without multiple selections allowed and empty selection allowed
copy the result as string to theSituation
--Thunderstorms require that the user be immediately notified
if theSituation is "Thunderstorm" then display notification "hello"
end run
Since you have this as a run handler, you probably don’t want to return any result, as you rarely call run handlers. But if you do need to return the result, the last line of the handler (just before end run) would be:
return theSituation
You might look around for an AppleScript tutorial that fits your needs. Apple has their Introduction to AppleScript Language Guide.
IF statements can be chained using if/else if/else if:
on run
--get the situation we're dealing with
choose from list {"Thunderstorm", "Flood", "Heatwave", "Hazmat"} with prompt "Please select one of the emergency situations below" without multiple selections allowed and empty selection allowed
copy the result as string to theSituation
--Thunderstorms require that the user be immediately notified
if theSituation is "Thunderstorm" then
display notification "hello"
else if theSituation is "Flood" then
display notification "hike pants"
else if theSituation is "Heatwave" then
display notification "Play Bing Crosby"
else if theSituation is "Hazmat" then
display notification "Use highway 183"
end if
end run
There is no switch/case control structure in AppleScript.

Related

How can I loop only the page records from the selected one to the latest?

I'm trying to loop all records displayed in a page, from the selected one to the end of the rows:
For example here, as I'm selecting only the 5th row it will loop through 5th and 6th row (as there are no more rows below)
What I've been trying is this:
ProdOrderLine := Rec;
REPEAT
UNTIL ProdOrderLine.NEXT = 0;
But it will loop through all records in the table which are not even displayed in the page...
How can I loop only the page records from the selected one to the latest?
Try Copy instead of assignment. Assignment only copies values of there field from one instance of record-variable to another, it died not copy filters or keys (sort order).
Alas, I have to mention that this is uncommon scenario to handle records like this in BC. General best practice approach would be to ask user to select all the records he or she needs with the shift+click, ctrl+click or by dragging the mouse. In that case you will use SetSelectionFiler to instantly grab ask the selected records.
This is how it works across the system and this how user should be taught to work. It is a bad idea to add a way to interact with record that only works in one page in the whole system even if users are asking for it bursting into tears. They probably just had this type of interaction in some other system they worked with before. I know this is a tough fight but it worth it. It is for the sake of stability (less coding = less bugs) and predictability (a certain way of interaction works across all the pages) of the system.

How to check if field on desktop application is empty or filled, and if it's filled mark as exception, and if it's empty proceed?

I am new to UI path and am trying to build a workflow/sequence to check if a field in my desktop application is filled or not.
If the field is empty then I want to proceed with the process, and if it is filled I want it to be marked as an exception.
I currently have it so the flow goes as follows:
1. Identified element
2. used Text Exists activity for that field, and I inputed "" as the Text
What are the next steps?
It would be better if you used Get Text command, and using if condition, check if the text is null or empty and take action.
First you want to use Get text on the Text box to extract its contents and store this in a variable in UiPath (Note: if you create the variable from the side properties panel it will give it the type GenericValue, you'll want to change this to String)
Next depends an what you mean by filled:
If you want to accept spaces as been filled then you can use String.IsNullOrEmpty(YOUR_VARIABLE)
If you want the filed to be filled with characters that aren't spaces you can use
String.IsNullOrWhiteSpace(YOUR_VARIABLE)
for your exception it will depend on weather you want to throw it as an
Application exception (new System.Exception("EXCEPTION MESSAGE"))
or
Businessexception (new UiPath.Core.BusinessRuleException("EXCEPTION MESSAGE"))
So your workflow will want to look something like this

Searching a large data file for a credit card type and its relevant info

So I am running Python 3.7.1 and I am trying to make a program that pulls out only customers that use an American Express card and display only their name and Email.
I have part of the code that pulls all the customers data that uses the same card type, but it pulls up multiple of the same name and email and all other information. I just can't figure out how to eliminate multiples and only display Name and Email. Below I will show a picture of my code and a screen shot of the output for reference.
My code so far
Output(notice the multiples of Mary and Hunter)
Assuming your file isn't extremely long, consider using Python's set data structure to filter out duplicates. You can check for membership within the set via the in operator (e.g. x in s) and you can add new elements to the set via the add() method (e.g. s.add(x)). At a high level, you want to amend your code to check whether the element is already in your set (in which case you don't need to print it again), and if it is not in the set, add it to ensure you don't print it again.

My test script is not finding items in dynamic web list control - list in code not updated with current info

I am having a problem in QTP with selection of a web list box and I have exhausted what I know to do to resolve it. I am hoping someone can help.
There are 5 controls in a container, 2 webedit controls and 3 weblist controls. Together, they allow entry of accounts associated with a customer, and there can be 16 accounts for any customer. There are only ever five controls active at any time, whether editing or entering information for an account. When the information for an account is entered and accepted, it changes to a read-only table row and a new set of controls appears below it for entry of the next account.
The information entered in these controls is the account number, type, description, designation, and status. The status value is contingent on the designation, and the items in the list change dynamically depending on what the user specifies for the designation. The status list is not enabled until the designation is specified.
After some experimenting with timing, I was able to get past an issue where the status list for the first account was seen by QTP as disabled even though it was clearly enabled. I was then able to advance to entry of the second account.
I change the designation on the second account and try to select an appropriate item (specified in a data table) in the status list. My specification from the data table is never found. I figured it was a problem with verbiage differences and also that I should probably anticipate that and address it now, so I wrote a function to accept three parameters, the list and up to two search items. My function searches the listbox passed to it and looks for a match (full or partial) on the search items it receives. Here is where I encountered a significant problem.
The list of the control my function received was from the previous iteration of the test, corresponding to the designation of that account. This is why my function was not finding the selection item. The list on the screen shows the appropriate items, which suggests that I am looking at the wrong object. I also get the ‘object is disabled’ message when I put my data table value directly into the list with the select statement.
The active controls are displayed below the readonly presentation of the previously entered accounts. I am very new to QTP, but I also read documentation. My only theory at this point is that ATP is not passing the right list to my function… that perhaps that how it was learned included the position, which will change each time. However, the spy identifies the screen control as the same item I processed for the preceding account, which makes my theory suspect. In addition, the other four controls, which are not dynamically changing, do not present the same problem. I can put the information in them consistently.
I apologize for the length of this question, but I wanted to be as thorough and clear as possible. Can anyone help me get past this obstacle.
There are many possiblities why it is exposing this behaviour, so let's start with something simple:
Did you try a myWebList.Refresh call before you do something with the listbox? Refresh re-identifies the object.
Have you put a break point (red dot) inside the custom function. Just see what is happening there. With the debug viewer you can enter a realtime command in the scope of that function like msgbox myWebList.exist(0) or myWebList.Highlight
Can you see how the disabled property is propagated to the webpage? If you can 'Object Spy' it as TO property, you can add it in the GUI Map description.
A more sophisticated aproach is to create a Description with the weblist properties. If you can read the disabled property as an RO property from the 'Object Spy', you can use it as an identifier like "attribute/customDisabledProperty:=false".
If you cannot correctly read the disabled property, you can create a description object and do a count on the amount of items that match that description on that page with numberOfLists = Browser("my browser").Page("my page").ChildObjects(myDescription).Count and get the last list with Set lastList = Browser("my browser").Page("my page").ChildObjects(myDescription)(numberOfLists-1)
Keep us informed. Depending on how this works out, we can work into a direction for a solution.
I figured this out early this morning. There are 4 different list boxes used, each made visible or enabled dependent on the selection of the previous list. This is why the spy found the one listed when I was using it and also why the items in the list were not appropriate to what I had selected and also why it appeared disabled to QTP but enabled to me.
I was selecting the same designation when trying to spy it. It was intuitive that the controls were all the same. I am also a windows programmer and I would have populated the same list each time with the appropriate list items, and I presumed that was what the web developer was doing. It was not and it took some time to figure that out. Now that I figured it out, everything is working fine, and I came back to report that. This was a significant, time-intensive lesson.
Thank you very much for your input. It is still useful because I am very new to QTP and every thing I learn is of value.

sqlite3 transactions and the exec call

I have an entire set of data i want to insert into a table. I am trying to have it insert/update everything OR rollback. I was going to do it in a transaction, but i wasnt sure if the sql_exec() command did the same thing.
My goal was to iterate through the list.
Select from each iteration based on the Primary Key.
If result was found:
append update to string;
else
append insert to string;
Then after iterating through the loop, i would have a giant string and say:
sql_exec(string);
sql_close(db);
Is that how i should do it? I was going to do it on each iteration of the loop, but i didnt think a global rollback if there was an error.
No, you should not append everything into a giant string. If you do, you will need to allocate a whole bunch of memory as you are going, and it will be harder to create good error messages for each individual statement, as you will just get a single error for the entire string. Why spend all of that effort, constructing one big string when SQLite is just going to have to parse it back down into its individual statements again?
Instead, as #Chad suggests, you should just use sqlite3_exec() on a BEGIN statement, which will begin a transaction. Then sqlite3_exec() each statement in turn, and finally sqlite3_exec() a COMMIT or ROLLBACK depending on how everything goes. The BEGIN statement will start a transaction, and all of the statements executed after that will be within that transaction, and so committed or rolled back together. That's what the "A" in ACID stands for; Atomic, as all of the statements in the transaction will be committed or rolled back as if they were a single atomic operation.
Furthermore, you probably shouldn't use sqlite3_exec() if some of the data varies within each statement, such as being read from a file. If you do, a mistake could easily leave you with an SQL injection bug. For instance, if you construct your query by appending strings, and you have strings like char *str = "it's a string" to insert, if you don't quote it properly, your statement could come out like INSERT INTO table VALUES ('it's a string');, which will be an error. Or if someone malicious could write data into this file, then they could cause you to execute any SQL statement they want (imagine if the string were "'); DROP TABLE my_important_table; --"). You may think that no one malicious is going to provide input, but you can still have accidental problems, if someone puts a character that confuses the SQL parser into a string.
Instead, you should use sqlite3_prepare_v2() and sqlite3_bind_...() (where ... is the type, like int or double or text). In order to do this, you use a statement like char *query = "INSERT INTO table VALUES (?)", where you substitute a ? for where you want your parameter to go, prepare it using sqlite3_prepare_v2(db, query, -1, &stmt, NULL), bind the parameter using sqlite3_bind_text(stmt, 1, str, -1, SQLITE_STATIC), then execute the statement with sqlite3_step(stmt). If the statement returns any data, you will get SQLITE_ROW, and can access the data using the various sqlite3_columne_...() functions. Be sure to read the documentation carefully; some of the example parameters I gave may need to change depending on how you use this.
Yes, this is a bit more of a pain than calling sqlite3_exec(), but if your query has any data loaded from external sources (files, user input), this is the only way to do it correctly. sqlite3_exec() is fine to call if the entire text of the query is contained within your source, such as the BEGIN and COMMIT or ROLLBACK statements, or pre-written queries with no parts coming from outside of your program, you just need prepare/bind if there's any chance that an unexpected string could get in.
Finally, you don't need to query whether something is in the database already, and then insert or update it. You can do a INSERT OR REPLACE query, which will either insert a record, or replace one with a matching primary key, which is the equivalent of selecting and then doing an INSERT or an UPDATE, but much quicker and simpler. See the INSERT and "on conflict" documentation for more details.