Finding a string embedded with several strings in a single cell - vba

Working on a large macro to automate an end of day email process that involves sending emails to different customers. Everything is working fairly well except in the several instances that some firms have different emails for different employees. It would be simple if these employees were the only ones that would be sent to that email, but that is of course not the case.
I'm struggling to find a solution to finding the names and referencing the email. But referencing multiple names without knowing how many names it could be ahead of time (meaning in the future a firm could have 10 employees with the same email confirmation and some may have as little as 1 (for those that require separate emails per employee)). Would I use an array for this and test against the array? I would also need to store the employee names in order to ensure duplicates aren't created. See Text example and code below:
The names are stored in a sheet named emailMaster in this format say starting in cell(1,3) (Joe GoodGuy; James Johanson; Jimmy TheHat (All encapsulated in one cell)) and the email they correspond to is found at .Offset(0,1). To clarify, these gentlemen may work for the firm "CodersUnited", but their may be another group from the firm "CodersUnited", who require a different email address for their end of day receipts and they could be in cell(1,5) (Jimmy John; Franky TwoToes; Jimmy Hendrix) and their corresponding email found in .Offset(0,1).
Row ____________________C____________________ __D___ ___________________E____________________ __F__
1 Joe GoodGuy; James Johanson; Jimmy TheHat Emails Jimmy John; Frank TwoToes; Jimmy Hendrix Email
The solution below only works if their is one name corresponding to one email. There needs to be multiple names corresponding to one email.
'Gets firm name
If firmName = emailMaster.Cells(emrow_num, 1) Then
continue = False
cFirm = firmName
iFirm = emailMaster.Cells(emrow_num, 2)
If IsEmpty(emailMaster.Cells(emrow_num, 4)) = True Then
firmEmail = emailMaster.Cells(emrow_num, 3)
'Tests for separate employee emails
ElseIf emailMaster.Cells(emrow_num, 4) = "Yes" Then
empSeparate = True
'Captures separate emp email
Set empTestFinder = emailMaster.Rows(emrow_num).Find(empName)
empFinder = empTestFinder.Address
firmEmail = emailMaster.Range(empFinder).Offset(0, 1)
Else
MsgBox ("Firm designated as different emails for employees. Either change designation of firm or add employee. Contact dev for more assistance.")
Exit Sub
End If
End If

In my view you are mixing three tasks:
modelling your data
determining a convenient method of holding that data in Excel
determining a convenient method of holding that data in VBA variables
You need to tackle these tasks in sequence but be willing to revert to a previous task if you encounter problems attempting the current task..
Below is a data model which I have deduced from your question. This model does not conform to any standard modelling notation but, if you are not a data modeller, I think you will find this notation easier to understand.
You need to send emails to all your customers. I have shown three example customers. At Customer1 there is only one person you send emails to who has there own email address. At Customer2, there are three people to whom you send emails who each have their own email address. Customer3 is more complicated. Person13 has their own address but the other contacts share addresses. For example, EmailAddr5 is shared by Person5, Person6 and Person7.
Customer1────EmailAddr1────Person1
Customer2─┬──EmailAddr2────Person2
├──EmailAddr3────Person3
└──EmailAddr4────Person4
Customer3─┬──EmailAddr5─┬──Person5
│ ├──Person6
│ └──Person7
├──EmailAddr6─┬──Person8
│ ├──Person9
│ ├──Person10
│ ├──Person11
│ └──Person12
└──EmailAddr7────Person13
Is this a correct representation of your data? I would summarise this as:
There are 1 or many PERSONs per EMAILADDR
There are 1 or many EMAILADDRs per CUSTOMER
If you are not familiar with modelling data, this may be confusing at first but I believe that with a little study it will become clear.
The question you need to answer is: “Is this a complete description of my data?” Only when you are convinced there are no special cases not covered by this model can you proceed to Task 2.
Unless your final model is much more complicated than mine, I do not believe you will need two or more worksheets to hold this data. So, task 2 is to map your data model onto an Excel worksheet.
During task2, the person to consider is the user who will create and maintain this data. For example, I would have thought holding multiple people in a single cell would be awkward to maintain. How does this data arrive? Does Acme Supplies tell you to contact John Smith whose email address is Sales#AcmeSuppliers.Com or do they tell you use Sales#AcmeSuppliers.Com to contact any of: Angela Brown, Cherry White and John Smith? If data arrives as “name – address”, the model above may be correct but inconvenient. Would this be a convenient arrangement of the data for the user to maintain?
Acme Supplies | Brown, Angela | Sales#AcmeSuppliers.Com
Acme Supplies | Chester, Neal | Admin#AcmeSuppliers.Com
Acme Supplies | Smith, John | Sales#AcmeSuppliers.Com
Acme Supplies | White, Cherry | Sales#AcmeSuppliers.Com
With this arrangement, there is a row per person per company.
If you really think your data model is correct, how about:
Acme Supplies|Admin#AcmeSuppliers.Com|Chester, Neal|Sales#AcmeSuppliers.Com|Brown, Angela|Smith, John|White, Cherry|
where I am using vertical lines to represent cell boundaries.
What I done is take:
Customer3─┬──EmailAddr5─┬──Person5
│ ├──Person6
│ └──Person7
├──EmailAddr6─┬──Person8
│ ├──Person9
│ ├──Person10
│ ├──Person11
│ └──Person12
└──EmailAddr7────Person13
and arrange it as:
Customer3|EmailAddr5|Person5|Person6|Person7|EmailAddr6|Person8|Person9| and so on
This could work because every address contains the symbol “#” while no name contains this symbol.
As you develop the mapping from the data model to Excel, you may need to revise the data model. Your original model may be technically correct but implementation in Excel may be inconvenient. Provided your revised model can handle any combination of company, address and name you can envisage and providing that revised model maps cleanly to Excel you will be all right.
Lastly, task 3 is to map the Excel worksheet to VBA variables. This depends on how you need to process the data. For example, you might have a list like:
CompanyA, PersonZ
CompanyB, PersonY
CompanyB, PersonX
: :
With this it might be easier to leave the data in the worksheet and have code like this:
For each line of list
Search for Person
If not found
Report “No such person”
Else
Record row on which first Person found
Do While True
If Person belongs to Company Then
Generate email
Exit Do
End If
Search for next Person
If row for Person is the row for the first Person Then
Report “No such person”
Exit Do
End If
Loop
End If
Next
I think the above is as much as I can offer because there is too much uncertainty about your requirement. This may be enough for you to solve your own problem. If not, you need update your question clarify your requirement.

Perhaps you would like a function like the below:
Function FoundEMail(groupArray As Variant, emailArray As Variant) As Boolean
Dim PersonInGroup As Variant, PersonInEMail As Variant, PersonFound As Boolean
For Each PersonInGroup In groupArray
PersonFound = False
For Each PersonInEMail In emailArray
PersonFound = StrConv(Trim(PersonInGroup), vbUpperCase) = StrConv(Trim(PersonInEMail), vbUpperCase)
If PersonFound Then Exit For
Next PersonInEMail
If Not PersonFound Then Exit Function
Next PersonInGroup
FoundEMail = True
End Function
So instead of If firmName = emailMaster.Cells(emrow_num, 1) Then you might have something like If FoundEMail(Split(firmName,";"),Split(emailMaster.Cells(emrow_num, 1),";")) Then

Related

(Neo4j) Carry variable over subsequent queries

I am trying to carry over a variable through 2 subsequent queries. It seems like WITH only helps carry over the variable to the next query, but not any before that. Suggestions?
This is example of what I am trying to do:
Person nodes contain information on publishers, writers and editors (e.g. name, gender, etc.)
Story nodes contain data on Story (e.g. title, publish date, etc.)
IN relationships have categories: created, edited, published.
Return editor-publishers who have edited stories published by another editor-publisher:
assume no duplicate Person names
Find all Persons who have edited at least one story who have also published at least one story
Find list of stories published by these editor-publishers in 1
In all editors of stories in 2, return sublist of these editors also in 1
MATCH (EditorPublisher:Person)-[:IN{category: "published"}]->(:Story) // 1
WHERE (EditorPublisher:Person)-[:IN{category: "edited"}]->(:Story)
WITH COLLECT(EditorPublisher.name) as EditorPublisher_list
MATCH (EditorPublisher_stories:Story)<-[:IN{category: "published"}]-(publisher:Person) // 2
WHERE publisher.name in EditorPublisher_list
WITH EditorPublisher_list // throws error EditorPublisher_list variable not found
WITH COLLECT(EditorPublisher_stories.title) as EditorPublisher_stories_list
MATCH (epe:Person)-[contribution:PLAYED]-(eps:Movie) // 3
WHERE epe.name in EditorPublisher_list
AND eps IN EditorPublisher_stories_list
RETURN epe.name
NVM I got it to work. With does keep the variables if i don't rename them.
I just had to do WITH return.nodes, and call the return.nodes in subsequent queries instead of using in [return.nodes.list]

Matching an element in a column, to others in the same column

I have columns taken from excel as a dataframe, the columns are as follows:
HolidayTourProvider|Packages|Meals|Accommodation|LocalTravelVehicle|Cancellationfee
Holiday Tour Provider has a couple of company names
Packages, the features provided in each package are mostly the same like
Meals,Accommodation etc... even though one company may call it "Saver", others may call it "Budget". (each of column mostly follow Yes/No, except Local travel vehicle are again car names like Ford Taurus,jeep cherokee etc..
Cancellation amount is integers)
I need to write a function like
match(HolidayTP,Package)
where the user can give input like
match(AdventureLife, Luxury)
then I need to return all the packages that have similar features with Luxury by other Holiday Tour Providers, no matter what name they give the package like 'Semi Lux', 'Comfort' etc...
I want to give a counter for every match and display all the packages that exceed the counter by 3 or 4.
This is my first python code. I am stuck here.
fb is the total df I exported to
def mapHol(HTP, PACKAGE):
mfb = (fb['HTP']== HTP)&(fb['package']== package)
B = fb[mfb]
for i in fb[i]:
for j in B[j]:
if fb[i]==B[j]:
count+=1
I dont know how to proceed, please help me this is my first major project, I started on my own.

How to find results being between two values of different keys with Redis?

I'm creating a game matchmaking system using Redis based on MMR, which is a number that pretty much sums up the skill of a player. Therefore the system can match him/her with others who are pretty much with the same skill.
For example if a player with MMR of 1000 joins the queue, system will try to find other ppl with MMR of range 950 to 1050 to match with this player. But if after one minute it cannot find any player with given stats it will scale up the range to 900 to 1100 (a constant threshold).
What I want to do is really easy with relational database design but I can't figure out how to do it with Redis.
The queue table implementation would be like this:
+----+---------+------+-------+
| ID | USER_ID | MMR | TRIES |
+----+---------+------+-------+
| 1 | 50 | 1000 | 1 |
| 2 | 70 | 1500 | 1 |
| 3 | 350 | 1200 | 1 |
+----+---------+------+-------+
So when a new player queues up, it will check it's MMR against other players in the queue if it finds one between 5% Threshold it will match the two players if not it will add the new player to the table and wait for new players to queue up to compare or to pass 1 minute and the cronjob increment the tries and retry to match players.
The only way I can imagine is to use two separate keys for the low and high of each player in the queue like this
MatchMakingQueue:User:1:Low => 900
MatchMakingQueue:User:1:High => 1100
but the keys will be different and I can't get for example all users in between range of low of 900 to high of 1100!
I hope I've been clear enough any help would be much appreciated.
As #Guy Korland had suggested, a Sorted Set can be used to track and match players based on their MMR, and I do not agree with the OP's "won't scale" comment.
Basically, when a new player joins, the ID is added to a zset with the MMR as its score.
ZADD players:mmr 1000 id:50
The matchmaking is made for each user, e.g. id:50 with the following query:
ZREVRANGEBYSCORE players:mmrs 1050 950 LIMIT 0 2
A match is found if two IDs are returned and at least one of them is different than that of the new player. To make the match, both IDs (the new player's and the matched with one) need to be removed from the set - I'd use a Lua script to implement this piece of logic (matching and removing) for atomicity and communication reduction, but it can be done in the client as well.
There are different ways to keep track of the retries, but perhaps the simplest one is to use another Sorted Set, where the score is that metric.
The following pseudo Redis Lua code is a minimal example of the approach:
local kmmrs, kretries = KEYS[1], KEYS[2]
local id = ARGV[1]
local mmr = redis.call('ZSCORE', kmmrs, id)
local retries = redis.call('ZSCORE', kretries, id)
local min, max = mmr*(1-0.05*retries), mmr*(1+0.05*retries)
local candidates = redis.call('ZREVRANGEBYSCORE', kmmrs, max, min, 'LIMIT', 0, 2)
if #candidates < 2 then
redis.call('ZINCRBY', kretries, 1, id)
return nil
end
local reply
if candidates[1] ~= id then
reply = candidates[1]
else
reply = candidates[2]
end
redis.call('ZREM', kmmrs, id, reply)
redis.call('ZREM', kretries, id, reply)
return reply
Let me get the problem right! Your problem is that you want to find all the users in a given range of MMR value. What if You make other users say that "I'm falling in this range".
Read about Redis Pub/Sub.
When a user joins in, publish its MMR to rest of the players.
Write the code on the user side to check if his/her MMR is falling in the range.
If it is, user will publish back to a channel that it is falling in that range. Else, user will silently discard the message.
repeat these steps if you get no response back in 1 minute.
You can make one channel (let's say MatchMMR) for all users to publish MMR for match request which should be suscribed by all the users. And make user specific channel in case somebody has a MMR in the calculated range.
Form you published messages such that you can send all the information like "retry count", "match range percentage", "MMR value" etc. so that your code at user side can calculate if it is the right fit for the MMR.
Read mode about redis Pub/Sub at: https://redis.io/topics/pubsub

ROR find by sql to grab email addresses out of IBM iSeries (DB2)

We've been continuously working on this issue for a few months and not getting far with it. Since this was first asked, we changed the code (based on what the original developer for the site suggested), but we are still not getting where we need to be.
I'm relatively new to Ruby and am currently taking some courses to learn more about it, so please bear with me. We're using Ruby 1.9 and Rails 3.2 We use AS/400 for our database. We've tried using Active Record for this before, and it doesn't want to work because of our versions of Ruby and Rails being older combined with getting it to connect with the 400.
We have an online ordering site that you have to have an account set up to access. Depending on what type of account you are set up as, you might have to have your order approved by someone. I.e. if I am a drop ship account, my distributor has to approve what I'm ordering. The way it had been set up, the distributor wasn't getting any kind of approval email.
Each account that requires approval has x number of email addresses attached to it of people who are able to approve the order. We have been told that target_email needs to be a string, so we tried numerous ways of making it a string to no avail. As is, it's only sending the first two email, not the approval email. If we run target_email = Contact.find_by_sql ["SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 =''"] in console, it returns the expected email addresses associated with that account. So we know that's working the way it should... but we're at a loss as to what is wrong with the rest of the code.
# notify Customer
Mailer.deliver_order_coastal_notify_email("", "Coastal Pet Online Ordering<noreply#coastalpet.com>", "Order Confirmation", email_details)
target_email = Contact.connection.select_values "SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 =''"
# Order Approval
if sign_on.acctypw1.strip == "DS" or sign_on.acctypw1.strip == "DSD"
# If there is no distributor email address, the mailer model will substitute in the admin's email from their settings
target_email.each do | email_address | Mailer.deliver_order_distributor_approval_email(email_address, 'Coastal Pet Online Ordering<noreply#coastalpet.com>', "Order Confirmation Approval", email_details)
end
# notify Coastal staff
Mailer.deliver_order_coastal_notify_email("", "Coastal Pet Online Ordering<noreply#coastalpet.com>", "Order Confirmation-Notify Staff", email_details)
end
I tried
target_email = Contact.connection.select_values("SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = act223").uniq
This works but it sends emails to multiple accounts why this would happen? I think I need to set a value for act223
act223 = "ACT223"
target_email = Contact.connection.select_values("SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = #{Contact.connection.quote(act223)}").uniq
this throws NameError (undefined local variable or methodact223' for #):`
in development.log.
Here is a link to the relevant table data if more table information is needed just let me know and I can add it to that page. I am looking to do some sort of a join of a field from another table. In this same model I have SignOn.prefdstw1 which gets me the same account number is there a way to Join this field in the query with the 400?
Any help or suggestions would be greatly appreciated! Thank you in advance!
find_by_sql always returns an array of model objects, so
Contact.find_by_sql ["SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 =''"]
is not an array of email addresses - it's an array of Contact objects, with only one object
You could either extract the email addresses from this, using something like
Contact.find_by_sql(["SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 =''"]).collect do |contract|
contact.emal23
end
I'm not entirely sure what rails will do to the uppercased column name.
If you don't want to instantiate a whole Contact object just to get the email you could also do
Contact.where("ACT223 = ''").pluck('EMAL23')
which would return an array of emails, assuming that Rails knows that the correct table to use for this is WEBOEL23 - it's not clear to me whether that is the table for Contact (and thus you've use set_table_name to configure this) or whether Contact is just a random model unrelated to that table.
You could also drop down a level and do
Contact.connection.select_values "SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 =''"
which will also return an array of email addresses.
Inside the each loop, target_email is a bareword variable (without quotes), but the first argument to the mailer is the string (within quotes) 'target_email'.
Remove those quotes to get to this (whitespace added for readability):
target_email.each do | email_address |
Mailer.deliver_order_distributor_approval_email(
email_address,
'Coastal Pet Online Ordering<noreply#coastalpet.com>',
"Order Confirmation Approval",
email_details
)
end
Then the mailer should have access to the email address.

QTP Unable to differentiate Web Table in Application

I am a beginner in QTP and I am working on an application where there are two different web tables displayed.
The second web table is detail description of the first web table so it displays when we select a row in the first web table.
In other words, Each row in the first table is selectable and when selected corresponds to the second web table
Web table 1 contains something like below for a user
RelationShip | Name
Father | AAA
Mother | BBB
Brother | CCC
Sister | DDD
Sister2 | EEE
Web Table 2 Contains detailed information for each row in Web Table 1 as I earlier mentioned. SO for Father, the below table is reflected
Details
Name | AAA
Age | 50
Relationship | Father
and so on
Second User might/might not have brother/sister.
The problem now I am facing is retrieving data from second web table for different entity of first one since all the property of the web table are similar expect the below property
"html ID" which corresponds to - "DetailParty_randomno"
This random number is the one which defines the uniqueness of the second web table, which can be retrieved from the first web table though it isn't found in the properties section when we use the Object spy.
I can see this random number when I view the source code of the page. It's displayed as value entity in the tr tag
Value entity looks like "Party_randomno"
<tr style="background-color:yellow" value="Party_1" onclick="Call peoplehighlight("Party_1")" language="vbscript">
My question is if there a way to retrieve this value for each row and then use it in identifying the second web table?
However I did try to read from second table by hard coding "html id" in webtable property to see if it's being read but it didn't work
So my second question is with respect to the correctness of the below descriptive programming code. Is there something else I need to include/exclude in the WebTable property to find uniqueness.
I also did my research and found that it's useful to use index but I am not aware on how to find the index of a web table? Also the index changes for each user I am searching and hence I need to find the index of the table during run time before using it
BrowserName = Browser("micClass:=Browser").GetROProperty("name")
PageName= Browser("micClass:=Browser").Page("micClass:=Page")GetROProperty("name")
Set desc = Description.Create()
desc("html tag").Value = "tr"
Set Rows = Browser("B").Page("P").Webtable("WT").ChildObjects(desc)
RoCounter = Rows.Count-1
For valuecount = 0 To RoCounter
id= rows(i).Object.GetAttribute("value")
Next
'When the right ID is got, parsing it in the below for WT2 Identification
Set ObjTable = Browser("name:="&Browsername).Page("name:="& Pagename).WebTable("class:=Web_Table", "html id:=Detail"&id)
Update
I was able to get the value from the source code using Motti's code. needed to tweak a little and my descriptive programming had spaces between name and : so the objetct wasn't being recognized. It's solved now.
When looking at the description you gave to your WebTable I find it hard to see what you're trying to achieve. class in QTP is mapped to the html className property are you sure that Web_Table is correct className? Also there is (AFAIK) no class name property in QTP, if you mean the test object type then there's no need to add it since you already said that the object is a WebTable.
To answer your question, in order to add indexing you just add "index:=1" to the smart identification (or in the description if you're using the object repository), note that index is zero based so 1 is the second object that matches the description (if there are more than one, if there is only one the index is ignored).
In order to get the random number you can try something like this (untested)
Set desc = Description.Create()
desc("html tag").Value = "tr"
Set rows = Browser("B").Page("P").WebTable("T").ChildObjects(desc)
For i = 0 To rows.Count - 1
id = rows(i).GetROProperty("value") ' Or whatever you need here
Next