Daylite FScript Recipes

Getting the number of selected objects

tell application "Daylite"
            eval "selectedObjects count."
        end tell

Getting the entity of the selected objects

Useful when needing to test if the user has selected the appropriate type of object or if you need to handle different objects in a different manor.

tell application "Daylite"
            eval "((selectedObjects lastObject) entity) name."
        end tell

Passing an AppleScript argument to the FScript execution context

You can pass AppleScript objects that equate to NSDictionary, NSArray, NSString, NSNumber, NSDate or NSData. NOTE: Please ensure that the last quote and the with are on the same line, otherwise the AppleScript environment misinterprets the command.

set myString to "my test string"
        tell application "Daylite"
            eval "
                cocoa_string := 'Showing how to take in an argument from AppleScript with ' ++ argument.
                alert := NSAlert alertWithMessageText:nil defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:cocoa_string.
                alert runModal.
            " with myString
        end tell

Getting the entity name and primary key of selected objects

Returns an array of dictionaries that represent the selected objects. Extend this recipe to get more values from the objects. See the data model.

identifiers := {}.
        selectedObjects do:[:obj |
            ident := #{'entity' -> ((obj entity) name), 'pkey' -> (obj primaryKeyValue)}.
            identifiers add:ident.

Getting organization counts by category, sorted by value and returning as JSON

cats := objectContext objectsForEntityNamed:'Category' qualifierLocum:'active == 1 and forOrganization == 1' bindings:nil.
        results := {}.
        cats do:[:cat |
            val := objectContext resultCountForEntityNamed:'Organization'
            qualifierLocum:'categoryID == $catID'
            bindings:#{'catID' -> (cat categoryID)}.
            dict := #{'name' -> (cat name), 'cID' -> (cat categoryID), 'value' -> val}.
            results add:dict.
        sorted := results sortedArrayUsingDescriptors:{(NSSortDescriptor sortDescriptorWithKey:'value' ascending:false)}.
        sorted JSONRepresentation.

Get a specific attachment from the selected object

Assuming you add a specifically named attachment to an opportunity. Note: When Daylite gets sandboxed, you may not have access to the cached file, so you'll need to move the bytes over. Also, if you are executing this via AppleScript, you'll need to escape the double quotes with a backslash.

opportunity := selectedObjects lastObject.
        predicate := NSPredicate predicateWithFormat:'displayName = "TheScreenShot"'.
        attachments := opportunity fileAttachments.
        filteredAttachment := (attachments filteredArrayUsingPredicate:predicate) lastObject.
        "Downloads the attachment to the local cache location"
        filteredAttachment retrieveAttachmentWithDelegate:nil error:nil.
        localLocation := filteredAttachment cachedURL.

Convert a locum to a qualifier

In many API calls, we require a qualifier, but sometimes, assembling a qualifier can be a verbose pain. Instead a locum makes for more elegant and expressive code. Here we show you how to convert one.

locumString := 'firstname == $fname AND lastname caseInsensitiveLike $lname'.
        bindingsDictionary := #{'fname' -> 'Bob', 'lname' -> 'Smith*'}.
        qualifier := BDQualifier qualifierWithLocum:locumString bindings:bindingsDictionary.

Get Person creation stats for the last 100 days

This shows how to use the MCReportDateEnumerator to get an array of dates and then shows how get the stats of each day and returns the values as JSON.

start := (NSDate date) mcDateByAddingDays:-100.
        end := NSDate date.
        dates := MCReportDateEnumerator allDailyDatesBetween:start end:end.
        vals := {}.
        dates do:[:date |
            begin := date mcDateAsBeginningOfDay.
            endDay := date mcDateAsEndOfDay.
            c := objectContext resultCountForEntityNamed:'Contact' qualifierLocum:'createDate >= $start and createDate <= $end' bindings:#{'start' -> begin, 'end' -> endDay}.
            vals add:#{'date' -> date mcLongDate, 'count' -> c}.
        vals JSONRepresentation.

Get an object using a string reference identifier

You can uniquely identify an object by combining the entity and the primary key in a string. Here we show how to retrieve an object based on a string identifier. This example assumes there is a person with ID 5400 in the database already.

        object := objectContext objectForStringReferenceIdentifier:'Contact-5400'.
        object firstname.

Get a person using a known primary key

A bit more efficient than the string identifier method.

object := objectContext objectForEntityNamed:'Contact' wherePrimaryKeyValueIs:5400.
        object firstname.

Search for a person using AppleScript argument

        set searchCriteria to {first_name:"Bob", last_name:"Smith*"}
        tell application "Daylite"
            eval "
                see fscript below.
            " with searchCriteria
        end tell
"argument is passed in from the AppleScript environment"
        results := objectContext objectsForEntityNamed:'Contact'
            qualifierLocum:'firstname = $first_name AND lastname like $last_name'
        results primaryKeyValue.

Register and use an arbitrary persistent value (UserDefaults)

Here we show how to add an arbitrary persistent value, accessed by a key, in a similar fashion to NSUserDefaults. A scope value of 0 means the key is globally available. A scope value of 1 means it is for the current user only. A defaultValueType of 1 means it is a string. A defaultValueType of 2 is a properly list (dictionary). Please name your defaults using your company identifier (i.e. com.myCompany) otherwise your defaults may clash with ours (marketcircle) or that of another developer. Keep in mind that global variables are only global once a synchronization cycle has happened, which in some cases may be hours if a user has no access to the server.

        stringDefaultsKey := 'com.marketcircle.example.testnumber'.
        dictionaryDefaultsKey := 'com.marketcircle.example.testdictionary'.
        "Register the number user default"
        MCUserDefaults registerUserDefaultWithKey: stringDefaultsKey
            scope:0 defaultValueType:1 defaultValue:'0'.
        "Register the dictionary user default"
        MCUserDefaults registerUserDefaultWithKey: dictionaryDefaultsKey
            scope:0 defaultValueType:2 defaultValue:nil.
        userDefaults := objectContext userDefaults.
        number := userDefaults intForKey: stringDefaultsKey.
        number := number + 1.
        userDefaults setInt:number forKey: stringDefaultsKey.
        dict := userDefaults mutableDictionaryForKey: dictionaryDefaultsKey.
        (dict == nil) ifTrue: [
            dict := #{}.
        dict setValue:'ABC' forKey:'TheLetters'.
        userDefaults setDictionary:dict forKey: dictionaryDefaultsKey.

Update a value on an Object

This example show how to update an attribute on a specific object. We pass all necessary arguments in this case, but we don't have to. Assumption: Company with ID 20000 exists in the database.

set theRecord to {entity_name:"Organization", primaryKey:20000, newName:"The New Company Inc."}
        tell application "Daylite"
            eval "
                see fscript below.
            " with theRecord
        end tell
company := objectContext objectForEntityNamed:(argument at:'entity_name')
            wherePrimaryKeyValueIs:(argument at:'primaryKey').
        company setName:(argument at:'newName').

Create a Person using values from an AppleScript record

In this example, we create an AppleScript record object with values. The record is passed to the FScript environment as a NSDictionary which we then use to create the object in Daylite. You don't have to use the saveChanges call on objectContext unless you need or want the primary key. We also show, how to link a company to a person and add a job title to that role and then how to add the person and company to the sync list for Daylite on iOS.

set thePerson to {firstname:"Bob", lastname:"Smith8", email:"", phone:"14162331212", web:"", chat:"", city:"Toronto", company:"ABC3 Inc.", jobtitle:"Project Manager"}
        tell application "Daylite"
            eval "
                see fscript below.
            " with thePerson
        end tell
        -- Note the " with thePerson
person := objectContext createObjectForEntityNamed:'Contact' insert:true.
        person setFirstname:(argument at:'firstname').
        person setLastname:(argument at:'lastname').
        phone := person createAndAddToPhones.
        phone parseSinglePhoneString:(argument at:'phone').
        email := person createAndAddToEmailAddresses.
        email setUrl:(argument at:'email').
        address := person createAndAddToGeoAddresses.
        address setCity:(argument at:'city').
        web := person createAndAddToURLAddresses.
        web setUrl:(argument at:'web').
        chat := person createAndAddToIMAddresses.
        chat setUrl:(argument at:'chat').
        company := objectContext createObjectForEntityNamed:'Organization' insert:true.
        company setName:(argument at:'company').
        "The job title is set on the object that links the person and the company"
        role := objectContext linkObject:person toObject:company withRoleType:nil postNotification:false.
        role setName:(argument at:'jobtitle').
        "Add them to the sync list"
        objectContext addContactToContactTouchSyncList:person.
        objectContext addOrganizationToOrganizationTouchSyncList:company.
        objectContext saveChanges.
        person primaryKeyValue.

Find a company or create it if not found

This example searches for a company by name and if it does not exist, creates it. We call save on the objectContext so that we can return the primary key. In real life use, you should probably handle the case of multiples being returned.

set theRecord to {company_name:"ABC27 Inc."}
        tell application "Daylite"
            eval "
                see fscript below.
            " with theRecord
        end tell
"The argument dictionary is passed in from the AppleScript record"
        companies := objectContext objectsForEntityNamed:'Organization'
            qualifierLocum:'name caseInsensitiveLike $company_name'
        company:= companies lastObject.
        (company == nil) ifTrue:[
            company := objectContext createObjectForEntityNamed:'Organization' insert:true.
            company setName:(argument at:'company_name').
            "We don't really have to do this unless we need the primary key"
            objectContext saveChanges.
        company primaryKeyValue.

Set a Category on a Person

Here we show how to get an existing category, which we've gotten from the options cache, and set it on a person. Assumes that peson with id 5400 exists and an active person category by name Client exists.

person := objectContext objectForEntityNamed:'Contact' wherePrimaryKeyValueIs:5400.
        categories := (objectContext optionsCache) valueForKey:'activeContactCategories'.
        category := categories objectWithAttribute:'name' equalTo:'Client'.
        person setCategory:category.
        person primaryKeyValue.

Add and remove a Keyword on a Person

Assumes that person with ID 5400 and keywords 'Non-Profit' and 'Developer' exist.

person := objectContext objectForEntityNamed:'Contact' wherePrimaryKeyValueIs:5400.
        keywords := (objectContext optionsCache) valueForKey:'activeContactKeywords'.
        nonprofit := keywords objectWithAttribute:'name' equalTo:'Non-Profit'.
        developer := keywords objectWithAttribute:'name' equalTo:'Developer'.
        person addToKeywords:nonprofit.
        person removeFromKeywords:developer.
        person primaryKeyValue.

Add a Note to a Person

Adding a note for a person, assuming Person with ID 5400 exists.

person := objectContext objectForStringReferenceIdentifier:'Contact-5400'.
        note := objectContext createObjectForEntityNamed:'Note' insert:true.
        note setTitle:'The title of a note from FScript'.
        note setPlainTextRepresentation:'This is the note body'.
        objectContext linkObject:person toObject:note.

Add a Form to a Person

This example shows how to create a new instance of a form, populate it and then add it to a Person. Example assumes a unmodified Sample database with person ID 5700, form definition "Initial opportunity interview" and the various form fields existing.

person := objectContext objectForEntityNamed:'Contact' wherePrimaryKeyValueIs:5700.
        definitions := (objectContext optionsCache) valueForKey:'activeContactCustomRecordSetDefinitions'.
        definition := definitions objectWithAttribute:'name' equalTo:'Initial opportunity interview'.
        form := objectContext createCustomRecordSetForCustomRecordSetDefinition:definition.
        form setObjectValue:5
            forKey:'How many potential users are there?'.
        form setObjectValue:(NSDate date)
            forKey:'What is your desired target date?'.
        form setObjectValue:'I would like to solve such and such and then I\\'d like to solve this.'
            forKey:'In a nutshell what would you like to achieve?'.
        person addToCustomRecordSets:form.

Use Groupings and SubGroupings on Opportunities

Groupings and subGroupings allow you slice and dice objects to allow you to make some sense from your data. This example is extracted from the Opportunity Analysis PDF report. You can see it in full action there.

        "Set the start and end date"
        inputStartDate := (NSDate date) mcDateByAddingDays:-30.
        inputEndDate := (NSDate date).
        "Get the initial grouping based on opportunity type"
        oppsGrouping := objectContext objectsForEntityNamed:'Opportunity' qualifierLocum:'(completeDate >= $startDate and completeDate <= $endDate) OR (startDate >= $startDate AND startDate <= $endDate) OR (dueDate >= $startDate AND dueDate <= $endDate) OR (createDate >= $startDate AND createDate <= $endDate)' bindings:#{'startDate'->inputStartDate, 'endDate'->inputEndDate} groupedBy:'opportunityType' behavior:kMCReportGroupingByMCPObject.
        "Use in memory filtering (predicates) to get the won opportunities"
        won := oppsGrouping filteredGroupingWithPredicateLocum:'opportunityStateType = 1 AND (completeDate >= $startDate AND completeDate <= $endDate)' bindings:#{'startDate'->inputStartDate, 'endDate'->inputEndDate}.
        open := oppsGrouping filteredGroupingWithPredicateLocum:'opportunityStateType = 0' bindings:nil.
        lost := oppsGrouping filteredGroupingWithPredicateLocum:'opportunityStateType = 4' bindings:nil.
        "We make a new grouping from the in memory objects from the original grouping"
        oppsByUser := oppsGrouping clonedGroupingWithGroupingKey:'assignedTo' behavior:kMCReportGroupingByMCPObject.
        wonByUser := won clonedGroupingWithGroupingKey:'assignedTo' behavior:kMCReportGroupingByMCPObject.
        openByUser := open clonedGroupingWithGroupingKey:'assignedTo' behavior:kMCReportGroupingByMCPObject.
        wonByStateReason := won clonedGroupingWithGroupingKey:'opportunityStateReason' behavior:kMCReportGroupingByMCPObject.
        lostByStateReason := lost clonedGroupingWithGroupingKey:'opportunityStateReason' behavior:kMCReportGroupingByMCPObject.
        "Put the results in a dictionary"
        results := #{'qualifying opportunities' -> (oppsGrouping objects count), 'won' -> (won objects count), 'open' -> (open objects count), 'lost' -> (lost objects count), 'affected users' -> (oppsByUser groupings count), 'users with won opps' -> (wonByUser groupings count), 'won reasons' -> (wonByStateReason groupings count), 'lost reasons' -> (lostByStateReason groupings count)}.