OCL

Basics of OCL

Product line

Standard

|

Expert

Operating mode

CLOUD ABO

|

ON-PREMISES

Modules

Services & CRM

Budget & Phases

Purchases

Resource Planning

Business Intelligence

Created: 20.06.2003
Machine translated
Updated: 07.12.2024 | Added operators for system settings from Vertec 6.7.0.16.


Implementation Using OCL
Session

Member

m:n Shortcuts

Lists (derived ObjectList)

Class Lists
Ocl variables

Compare
String Comparisons

Conditions

Operators

List operators
Conversion operators
Number operators
String-editing Processor Operators System settings operators operators
Editor operators Resource
planning operators System settings operators
Permission check
operators Ocl call operators for custom business logic
operators
Project phase operators Link operators
Power sum
operators
Date operators
Type operators (oclType, oclIsTypeOf, oclIsKindOf, oclAsType)
OCL Call operators Custom business logic operators

Implementation

Navigation and querying in the Vertec object model is done via an object-oriented query language called OCL. A complete language definition can be downloaded as a PDF file via the following link: Ocl manual .

OCL stands for object constraint language and was originally developed as part of the UML standard to formulate validity conditions for object models. Due to its object-oriented capabilities, OCL can also be used as a query language.

The Vertec core includes an OCL interpreter that processes OCL expressions as text and returns the result data from the Vertec objects. The OCL interpreter uses information from the Vertec Model .

Uses of ocl

OCL is used in Vertec in a variety of locations:

An OCL expression is always evaluated against a specific object and returns a result of a specific type. Possible types of results are:

  • Number
  • String (character string)
  • Boolean (logical or Yes / No value)
  • Object
  • List of numbers, strings, booleans or objects

For displaying results, e.g. in list columns, the result is automatically converted to a string. For numbers and strings, this conversion is simple. Booleans are represented as “Y” (yes) or “N” (no). For objects, the default string representation is displayed, which depends on the object class (e.g. code in projects). The representation of lists as a string shows the size of the list.

For expressions in expression folders, the result type must be a list of objects.

Session

The current Vertec session can be accessed in OCL via

TimSession.allInstances->first

A Vertec session has the following attributes:

Result app
.login

Returns the up-to-date logged-in user. See also the article Up-to-date user in expressions .

.instance

A database section can contain a value called InstanceName in the Vertec.ini file. This will then be shown on the Vertec desktop app interface, see the InstanceName section for identifying test installations.

For access via OCL, there is an attribute called InstanceName:

TimSession.allInstances->first.instanceName
.hasGui

The hasGui operator allows you to determine from OCL expressions or scripts whether the client is capable of showing user-specific dialogs, i.e. whether the client is one of the full-featured apps .

TimSession.allInstances->first.hasGui

Return value is either

  • True(desktop app, cloud app and web app), or
  • False(XML Server, Phone app, Outlook app and TaskRunner)

It is important that scripts – especially Event Scripts – do not show dialogs if this is not possible on the client being used, as this may block Vertec.

.appType

Starting with version 6.0. The AppType operator allows you to determine which app you are in from OCL expressions or scripts.

TimSession.allInstances->first.appType

Returns a string with the following possible values:

.appType Significance
Desktop Desktop App
Cloud (disambiguation) Cloud App
Web Web App
XML XML Server
Phone Phone app
Outlook (disambiguation) Outlook App
TaskRunner Planned tasks
In versions between 6.4.0.14 and 6.5, “WebAPI” is returned instead of “Phone”.
.checkfeature(featurecode: string) Checks whether a particular feature is licensed.

TimSession.allInstances->first.checkFeature('fcPhasen')

The feature codes are according to Vertec feature matrix (e.g. fcPhasen for phases).

Return value is False or True.

Member

A member is a property of an object. It is either an association with one or more other objects or an attribute of the object.

Starting from an object, a member name can be specified to access a member. If such a member reference does not appear at the beginning of an expression, it must be separated by a period. Member names must always be lowercase. Examples: code in a list expression of a project list displays the project code in the corresponding column; kunde.name, also in a project list, displays the customer name. This is a link reference (customer) followed by the attribute reference (attributes name of the class Adresseintrag).

By stringing member references together in an OCL expression, arbitrary links in the Vertec object model can be queried.

m:n shortcuts

For m:n links, there is a link table. The link table can be accessed via the lowercase class name of the link table. Here is an example of an excerpt from the UML model user:

To find out what the corresponding link table is called, please refer to the corresponding UML model or contact your Vertec advisor.

Lists (derived objectlist)

A somewhat special type of members in Vertec are computed list attributes. In the OCL editor these are represented as type ObjectList. A so-called Derived ObjectList calculates their value at run time. Unlike Derived Attributes, they do not contain individual values, but return a list.

An example is the list of services on a project. In the model, there are actually only two lists on the project: openservices and billedservices. The list of services, i.e. all open and billed services together, is calculated at runtimes.

The lists provide type information in OCL and can be called as follows:

<Proj>.leistungen.wertext->sum

Class Lists

A class list is the list of all objects of a specific type (class), e.g. all projects or all users of a Vertec installation.

OCL is case sensitive. The OCL interpreter tries to understand everything capitalized as a class name (metatype). On a class, OCL knows the operator allInstances, which gives a list of all instances of the class. For example, Projekt->allInstances gives a list of all projects.

Since class lists are used quite often, Vertec has an abbreviation for them. If a class name is lowercase, it will be interpreted as a class list. Therefore, projekt also means the list of all projects.

Class lists are primarily used as a starting point for expressions from expression folders. Most predefined expression folders in Vertec (e.g. root data users) contain a simple class list as an OCL expression.

Caution: Be careful with class lists, because there are Vertec classes that can contain a lot of objects. If you specify a class list in OCL, all objects of that class will be loaded into memory. This can lead to high memory requirements and poor performance, especially with the OpenPerformance or BilledPerformance classes.

Operators

The following operators perform certain transformations on OCL values. An operator is separated within an expression by a leading arrow (->). If there is no likelihood of confusion with a member, a period is also accepted as a separator.

List Operators

Based on a list, there are several operators in OCL that modify the list. Other operators, not mentioned here, appear in “available fields” in the Ocl expression editor .

->size The size operator provides the quantity (quantity of entries) of a list, for example as a list column in a list of address entries projects->size specifies the quantity of projects of each customer.
->select The select operator allows you to filter the contents of a list based on a condition. addressentry->select(projects->size > 0) as an expression of an expression folder returns all addresses assigned to projects (i.e. customers). The argument of the select operator must be a logical (true/false) value.
->reject The reject operator is the opposite of the select operator. It excludes all entries from the list that match the expression. For example, the expression
project worker->reject(name='Administrator’) returns
a list that contains all project workers except the administrator.
->first

The first operator returns the first entry from a list. Most often, the first operator is used when an object is to be used as a result of a selection. Since the ->select operator returns a list as a result, ->first must be applied to it for the result to be a single object. Example:

phase->select(code= 'OFFER’)->first.offenservices->size

indicates the quantity of open services of the “OFFER” phase in a list of projects.

->orderby With the orderby operator, lists can be sorted. address entry->orderby(projects->size) sorts the list of address entries according to the quantity of projects for which they are customers.
->order descending

With the orderdescending operator lists can be sorted in descending order (otherwise the same as ->orderby):

address entry->orderdescending(projects->size)

Note: Used as an expression in an expression folder, these operators have no meaning since the list does the sorting itself.

->orderMulti

The orderMulti operator allows you to sort a list according to different sort criteria. It can be applied to a list in an OCL expression and takes a string as argument. This string contains the different sort criteria as individual OCL expressions, separated by semicolons:

project->ordermulti('projectleiter.name;code.asstring’)

as an expression of an expression folder, it returns a list of all projects, sorted first by the name of the project leader, second by the project code. However, this sorting will only be visible in the list view if you remove the sorting on list columns. Double-click a sorted list column until it no longer displays a sorting arrow.

ordermulti with additional fields

If you want to sort by custom items, you have the problem that you cannot use quotes in the expression. For custom items, this requires a detour via the internal ID of the custom item (settings > custom fields > right mouse button > properties > internal ID):

projekt->ordermulti('projektleiter.name;zusatzfelder ->select(metaZusatzfeld.boldID=<interne ID>)->first.wert')

Depending on the field type, you can query the value as follows:

.wert  .wertBlob  .wertBoolean  .wertInteger  .wertCurrency  .wertDatum  .wertObject
->asSet Starting from a list, you can also specify a member reference. The member reference is then applied to each object in the list. Thus, the result is a list of elements of the member type. Example project.customer returns a list of all customers in an expression folder. The disadvantage of this list is that the customers sometimes appear duplicate, because the expression aggregates all customers by project. This can be solved by using the asSet operator, which converts a list into a set (in the sense of set theory): projekt.customer->asSet returns a distinct list of all customers.
->asSequence Turns an object (or a list) into a list containing the individual object (or, in the case of execution on a list, the items of the list).
->asBag Returns the list with all entries, including duplicates (in contrast to asSet, see above). Since calling a list in the vertec will return a collection with all entries, the explicit specification of asBag is unnecessary.
->union

The union operator allows two lists to be combined into one. It can be applied to a list in an OCL expression and expects another list (collection) as an argument:

openbenefits->union(offeredbenefits)

as an expression on a project returns all open and billed services of the project. This list can be used as normal. The type is always the common base class whose attributes are available. So the above example returns a list of entries of type service. For an expression project->union(address entry), the common base class would be, for example, UserEntry.

->collect The collect operator allows a variable to formulate a complex partial expression only once, but to use it several times.

For example, you want to show the total of the invoices (net) for the last year:

invoices->select(date.year=date.year-1)->collect(turnover+amount of advance-effective advance)->sum

without the collect operator you would have to repeat the whole '->select’ expression for each value (revenue, advance amount etc).

You can also go a step further by assigning the value resulting from the collect to a variable and continuing with it.

As an example, let’s take a list of projects. Each project is located (in this example) either in a “Customer Projects” folder, or in an “Internal Projects” folder, or in an “Order Projects” folder. These folders are subfolders of the “Project Category” folder. In the list, we now want to show either 1, 2, or 3, depending on which folder the project is in the list:

ordner->select(parentordner.bezeichnung='Projektkategorie')  ->first.bezeichnung.substring(1,1)->asSet->collect(x|if x ='K'then  '1'else if x='I'then'2'else if x='A'then'3'  else'Keine Angabe'endif endif endif)->first

The expression assumes a project (every project in the list). folder means the folders in which the project is located. We first look for the subfolder of the project category folder. From this we take the first letter (name.substring(1,1)). This is now a single letter, either “K” or “I” or “A”. Since the collect operator can only be executed on a list, we add a ->asSet. Now we have the ->collect operator: instead of repeating the entire folder->select(...) section for each if query, we can simply use the variable x several times. The x in the brackets refers to the current value. This is our single letter at the moment. Now we can use the x to query this letter and insert the desired value. The whole thing is still a list, but we want to show the single value in the field, so we add a ->first again.

->append(obj) Returns the list that the obj has appended at the end
->at(i) Returns the object at location i. The index i begins with 1.
->count(obj) Specifies how many times obj is included in the list.
->difference(list2) Returns the list that corresponds to the original list without the elements of list2.
->excluding(obj) Returns the list from which the obj was removed.
->includes(obj) Specifies whether obj is included in the list
->includesAll(list2) Specifies whether all objects in list2 are included in the list.
->including(obj) Same as ->append
->intersection(list2) Returns the intersection of the two lists, that is, a list of all objects contained in both lists.
->isEmpty True if no list or length of list=0, otherwise False.
->prepend(obj) Returns the list with the obj at the beginning.
->subsequence(start, stop) Returns a list from index start to and including index stop. The indices are based on 1 and are automatically corrected for valid values (i.e. stop can also be larger than the list length without any errors).
->symmetricDifference(list2) Returns a list of all items in the list that are not in Liste2 and all items in Liste2 that are not in the list.
->sum Sums the numeric values of a list and returns the sum.

Conversion Operators

Often the task is to convert a string to a date value, convert a number to a string, etc. The following is a list of the available conversion operators:

->asString (also .asString) Converts a number or date value to a string.
->dateToFloat Converts a date value into a number (the number tells you little: (quantity of days since 1.1.1900). This operation is mainly used for calculating date values (e.g. adding 30 days to today’s date, see example below).
->floatToDate

Converts a number to a date. The following expression counts 31 days to the date of the entry (e.g. a service):

(datum->dateToFloat+31)->floatToDate
->strToDate

Converts a string to a date. This operator is useful when you need to work with a date that is not previously known or exists only as a string (e.g. when the user queries a date).

The use of strToDate is tricky, because it refers to the current country settings. A strToDate with a string literal of '01.09.2020' goes wrong if a client uses a US date format, for example. In the web app this does not even refer to the local Windows, but to the settings in the web browser (e.g. “English”).

In fixed OCL expressions, therefore, the operator should instead encodeDate which is described below. So do not '01.09.2020'->strToDate, but encodeDate(2020,09,01).

->stringToFloat Converts a string to a number. If the string is not a number, 0 is returned.
->stringToList

Represents a string as a list. Individual words are separated by the word boundary or by a delimeter. Words enclosed in double quotation marks are counted as one word.

TimSession.allinstances->first.login.name.stringToList

Returns the name of the logged-in user as a list. For example,

TimSession.allinstances->first.login.name.stringToList->last

only the surname will be shown.

->isEmpty The operator ->isEmpty returns whether a link member is empty. For example, the expression projektleiter->isEmpty, executed on a project, returns with a Boolean value (true, false) whether a project leader is assigned (true) or not (true).
.isNull/.notNull It is often useful to detect a null value. Starting with version 5.5, this no longer has to be done via a string comparison, but can be queried via the OCL operators isNull and notNull.

Example: instead

projekt->select(betreffend.asstring='') (all projects without regarding)

you can now

projekt->select(betreffend.isNull)

to carry out.

Note: These operators are not to be confused with the isEmpty operator, which queries a shortcut. For example, to know whether a project has assigned a customer, you cannot query with isNull, but with customer->isEmpty.
.asnull/.null Starting with Vertec 6.2.0.4. The OCL null operator makes it possible to obtain null values for any attribute type.

This is useful to render nothing for numeric values instead of 0 without having to convert the entire expression to a string. For example, expressions like:

if usespesen then spesenint.asstring else '' endif
is replaced by the following expression:
if usespesen then spesenint else spesenint.asnull endif

Since OCL is a static and strictly typed language, a null value must also have a type in order to determine the validity of the expression. Therefore, a .asnull operator has been introduced on instances and .null on types:

  • <typ>.null creates a null value from an Ocl type. Using the null operator on type, the above expression would be if usespesen then spesenint else VtcCurrency.null endif.
  • <value>.asnull creates a null value of the same type based on an existing value (member reference), without the need to know the correct name of the type: if usespesen then spesenint else spesenint.asnull endif.
->listToString

Using this operator, lists can be represented in strings. For example, the expression returns:

phasen.code->listToString(',')

executed on a project (e.g. via list settings) the list of phase codes, separated by “,”.

.toLower/.toUpper Very often, the result of an expression is a string. The .toLower operator converts the string to lowercase, the .toUpper operator converts it to uppercase.
.asHMString Interprets a number as a quantity of minutes and formats it as hours:minutes. Negative time values are also supported.
.asTimeString Interprets a number as a quantity of minutes and formats it as the time of day. Negative values are not displayed.
.asMinuteString Interprets a number as a quantity of minutes and formats it according to the format in the system settings. Negative time values are also supported.
.asStringBy
Language(<Sprache>)

Query the corresponding language version of a member. This applies to all MLStrings, which are values that each have their own field for the different languages (examples are services, expense and outlay types). For example, for outlays on an invoice: If you want the French designation of the type, you can use the expression typ.text.asStringByLanguage('FR') happened.

Possible languages / parameters are 'DE’, 'DD’ (from 6.5.0.9), 'FR’, 'IT’, 'EN’ or 'NV’.

Note: This feature returns only the value entered in the MLString field. No translation takes place in the specified language, so if no value is entered in that language, an empty string is returned instead of the native term.

.pad(quantity, placeholder)

The .pad operator populates an integer value with the wildcard symbol up to the quantity of specified symbols. The result is a string.

This is useful, for example, when you need leading zeros for alphanumeric sorting.

6.pad(2,'0') returns 06
6.pad(3,'0') returns 006
...

Number Operators

abs

This operator returns the absolute value of a number.

(-2.8).abs = 2.8
(2.8).abs = 2.8

floor

Round function. Returns the nearest smaller integer from a real number.

(-2.8).floor = -3
(2.8).floor = 2
2.floor = 2

round

Rounds a numeric value to the nearest integer according to the round-to-even rule and returns it as a result.

(-2.8).round = -3
(2.5).round = 2
(2.6).round = 3
(3.5).round = 4

Round to five chunks:

(wert * 20)->round / 20

Round to two decimal places:

(wert * 100)->round / 100

Rounding up from the 5th:

  • For positive real numbers: (wert + 0.5).floor
  • For negative real numbers: (wert - 0.5).floor

See also rounds in scripts on this topic.

String Editing Operators

length

This operator returns the quantity of symbols in a string. For example, the expression addressentry->select(standardzip.length=4) returns all addresses with a four-digit zip code.

substring(start, end) This operator cuts out the symbols between “beginning” (starting at 1) and “end” from a string. For example, the expression code->substring(1,1), executed on a project, returns the first letter of the project code. Another example: you want to show the entry year of the current entry. Vertec saves the entry date in the member “creationdatetime”. The following expression takes the “creationdatetime,” converts it to a string, and sets the last 4 symbols: creationdatetime->asstring->substring(7,10). This method can of course also be used for the up-to-date system date (expression now, can be useful e.g. in connection with memory paths in Word reports, see corresponding articles)
replaceString

The syntax is as follows:

<string>->replaceString(substring, replacement)

You specify the part you want to replace (substring) and the part you want to replace (replacement). The return value is again a string.

For example, you would like to replace all Meyer with Maier in a text:

<text>->replaceString('Meyer’, 'Maier’)

The replace string is case sensitive, i.e. it is case sensitive.

replaceRegex

The syntax is as follows:

<string>->replaceRegex(template, replacement)

Here you can specify a regular expression, a so-called regular expression, both for the part you want to replace (template) and for the part you want to replace (replacement). The return value is again a string.

A small example of what is possible with this:

In a text there are designations of the type <Abschnitt>:<Kapitel>, for example 2:15 or 3:10. You want to swap these designations so that they are represented as 15:2 or 10:3 respectively. This can be done with the following expression:

<text>->replaceRegex('([0-9]*):([0-9]*)', '$2:$1')
Translate

As of Vertec 6.4.0.20. Translates a string value to the latest Vertec Surface Language .

Example:

if projekte->size > 0 then 'Client'.translate else 'Address'.translate endif

on an address list shows in the column the following result for English:

Operators on user entries

On UserEntry (all objects that can be placed in folders, e.g. services, projects, addresses, users, activities, etc.) there are the following operators:

Operator description

->hasBIDataRight: boolean

from Vertec 6.4.0.14:

->hasBIDataRight('Number’):boolean

This operator can be used to check whether the up-to-date logged-in user has the right to the specified BI object.

With the implementation of the rights on the KPIs with version 6.4.0.14, this OCL operator has been changed. From then on, a string with the internal name of the KPI must be specified as a parameter. Example:

projekt->hasBiDataRight('MinutesExt')

checks whether the up-to-date logged-in user on the specified project has the right to the MinutesExt KPI.

This is not backward compatible. The corresponding calls need to be adjusted.

->hastag(tagname): boolean

As of version 6.1.0.10. Query whether the object has set a tag of this name.

For more information, see the article about tags on user records.

->keystring(key): string

->keybool(key): boolean

->keydate(key): datetime or empty

->keyint(key): integer or 0

->keycurr(key): currency or 0.00

Starting with version 6.1.0.10. Operators for typed query of key values on the object.

For more information, see the article about key values on user records.

Processor Operators

Specifically for the class Projektbearbeiter there are the following operators:

Operator description from version
->gettarget time(from, to)

Standard hour in period (minutes)

 

->getWorking time(from, to)

Working time in the period (minutes). Calculated from the sum of all available services plus vacations entered as absences.

 

->received deferral(date)

brings the overtime balance by date-1, unless a forward is entered on date, then this forward is delivered.

 

->Delay date(date)

returns date of last deferral before date

5.4

->Overtime balance(date)

provides overtime balance by date

5.4

->getHolidayDefault(from,to)

Holiday credit within period

 

->getHolidayReference(from,to)

Holiday pay, both absences and holiday benefits

5.4

->getHolidayLecture(date)

brings the vacation balance per date-1, unless a forward is entered on date, then this forward is delivered.

 

->getHolidayLecture date(date):

carries date of last vacation carryover before date

5.4

->getHolidayStart(date)

brings the start date for calculating the holiday credit. Is the next holiday cut-off date after the last forward

5.4

->getHolidayEnd(date)

provides end date for calculation of holiday credit. Is the next holiday period end

5.4

->getHolidayBalance(date)

delivers holiday balance by date

5.4

->getHoliday BalanceDelimited(date)

Calculates the accrued vacation balance per date, taking into account the vacation credit up to the date. Example:

A vacation credit of 200 hours per year is given, specified by the group. The holiday cut-off date is 01.01. On this cut-off date, the employee was credited with a vacation carry-over of 20 hours. This means: The employee has a total vacation credit for the year 2013 of 220 hours.

Now I want to calculate the vacation balance of this employee as of March 31, 2013. There are the following options:

  • getVacation balance(encodeDate(2013,3,31)): Takes the vacation carryover (20 hours) plus the vacation credit (200 hours) and counts the vacation taken in the period up to 31.03.2013. Result: 204:00 hours. This is how many vacations the employee still benefits.
  • getVacation BalanceDelimited(encodeDate(2013,3,31)): Takes the vacation carryover (20 hours) plus the percentage of the vacation credit up to March 31, 2013 (49:19) and counts the vacation taken in the period up to March 31, 2013. Result: 53:19 hours. That’s how much vacation the employee would have had on March 31, 2013.
5.8
->getsalary(from,to)

Salary within the specified period

5.4

->getCommon costs(from,to)

Overheads within the specified period

5.4

->getTargetTimeDefault(from, to)
Calculates the standard time from, to only based on the settings, without taking into account holidays. Entry / exit date is taken into account. 5.4.0.21
->getTargetTimeGroupDefault(from, to)
Calculates the standard hours from, to based on the user’s group preferences. This results in the standard hours if the employee would work 100%. 5.4.0.21
->getTargetTimeOnlyGroupAbw(from, to)

Calculates an employee’s standard hours, taking into account only group-based absences (holidays, etc.).

In contrast to the GetSollzeit operator, absences are taken into account only by the groups. Absences entered on the employee are not taken into account. The employment level of the employee is taken into account.

5.8
->getEmployment degree(date)
Returns the employee’s employment level on a specific date.
The employment level is calculated regardless of whether the employee has standard hours on the effective date or not. The ratio of the standard weekly hours of the user and the group is decisive.
5.4.0.21
->getAbsenceFree(Absence type, from, to)

Operator to determine the free time of a particular type of absence. Example:

Editor->getAwayFree('Holiday’, encodedate(2013, 1, 1), encodedate(2013, 1, 31))

The calculation is as follows:

  1. Calculation of the standard hours for the specified period without taking into account absences.
  2. Calculation of the standard hours taking into account only the free absences of the specified type.
  3. The result is the difference between the two values in minutes (integer).

If a non-existent or incorrect (not free) absence type is specified, the result is 0.

Versions before 5.8

In versions before 5.8, the (language-dependent) designation is used to query the absence type.

If several absences are entered on the same day, Vertec cannot unambiguously determine the impact of each absence because the absence types do not have a sorting according to importance. So if you are also sick on Easter Monday (“holiday”) then the standard hour is correct, but this operator specifies 0 for both “holiday” and “sickness,” since the other absence type also occupies the whole day.

Versions from 5.8

For querying the absence type, the (language-independent) code is used in versions 5.8 and above.

Starting with this version, absence types have a priority attribute. This is taken into account in case of overlapping absences. Any number of overlapping entries are taken into account and the “visibility” of the eligible absences is determined by the priority value on their type.

If the priorities are equal, the following priority rules apply:

  1. For minute absences of different types, the absence with the greater minute value wins.
  2. In the case of minute and full-day absences, the full-day absences wins.
  3. If one absence is defined on the user and one on the user group, the one on the user wins.
  4. In all other cases, the absence with the higher ID, i.e. the one entered later, wins.
5.7
->getHoliday referenceFromw(from, to)

Operator for calculating vacation entitlement taking into account vacations entered only as absences. Example:

Editor->getVacationReferenceAbw(encodedate(2012, 1, 1), encodedate(2012, 1, 31))

As a result, the absences of the type vacation in the corresponding period are returned, in minutes (integer).

For normal vacation calculation the operator
->getVacationReference(from,to) can be used.

5.7
->getTargetTimeGroup(from, to)

This operator returns the standard hour for the group (100%), taking into account absences on the group. Example:

Editor->getTargetGroup(encodedate(2012, 1, 1), encodedate(2012, 1, 31))

As a result, the corresponding standard hour is returned, in minutes (integer).

5.7
->currentAbsences(date)

This operator returns a list of absences used for the specified day. Example:

Editor->currentAbsences(encodedate(2012,6,11))

provides a list of absences entered for this user for 11.06.2012.

5.7
->getTrackingUsers

The getTrackingUsers operator provides a list of all users for which the user is allowed to record services, expenses and outlays.

This is used in the Editor selection field on services, expenses and outlays and can also be queried via OCL.

Example:

TimSession.allinstances->first.login->getTrackingUsers

Returns the list of all users for which the user is allowed to record for the up-to-date logged-in user.

6.0
getPresenceEntries(date)

Returns a list of the day’s presence entries for the user.

bearb.getPresenceEntries(date)

6.2

Ocl ocl operators for resource planning

OCL operators are one way of working with resource planning data. However, there are a variety of other ways. These are described in the article Ocl, python, custom renderer and list controller for resource planning .  

.getResPlanMinutes(Date From, Date To)

Available on project and scheduling editors. Returns the scheduled time for the user in minutes for the specified period.

.

.getResRsrcMinutes(Date From, Date To)

Available on project and scheduling editors. Returns the resource time for the user, in minutes, for the specified period.

This is not the time still available, but the total standard hours relevant to the resource plan. The difference to standard hours is that only absences of the type “free” affect the standard hours, whereas all types of absences (free, vacation, compensation) are deducted from the resource time (see also the table on working time exceptions in the article Absences).

An example can be found here

Calculation of the compensation period for a period

If the effective compensatory absences per user are to be determined for a certain period of time, this can be done as follows:

getSollzeit(von, bis) - getResRsrcMinuten(von, bis) - getferienbezug(von, bis)

The non-working days (Saturday, Sunday, public holidays, etc.) are automatically taken into account.

Example

Example of calculating the compensation period for the month of July:

self.getSollzeit(encodeDate(2013,07,01),encodeDate(2013,07,31))
- self.getResRsrcMinuten(encodeDate(2013,07,01),encodeDate(2013,07,31))
- self.getFerienbezug(encodeDate(2013,07,01),encodeDate(2013,07,31))

Explanation

Absences of the type Free affect the standard hour (minus).

Absences of the type free, vacation and compensation as well as vacations entered as services affect the resource time (minus).

The absences of the free type are thus cancelled out. There are vacations and compensation left over. That is why the vacations still have to be deducted. The time difference is the compensation period.

System settings operators

From Vertec 6.7.0.16 onwards, the OCL operators are available for querying System Settings settings:

  • propertyBool('propertyName’)
  • propertyInt('propertyName’)
  • propertyCurr('propertyName’)
  • propertyDate('propertyName’)
  • propertyString('propertyName’)
  • propertyObject('propertyName’)

These return the value or object stored in the system settings.

For detailed information, see Properties via ocl .

Ocl operators for checkright

Since version 6.0 there are OCL operators for querying user rights. Basically there are 3 types of user rights:

  • Member rights (read, write), can be queried for an individual member.
  • Class or object rights (create, delete, execute, view) can be queried for a class type or for an object.
  • User rights (standard user rights) can be queried on an abstract user (user group or project editor).

The following permission query operators return a Boolean (True/False) value.

Member Rights

The permissions on individual members are queried on the object and the name of the member is passed as an argument:

Operator Legal name
Object->isMemberReadable(memberName) rtRead
Object->isMemberWritable(memberName) rtWrite

 

Class or object rights

OperatorLegal name
Class->isCreatablertCreate
Object->isDeletablertDelete
Object->isExecutablertExecute (Reports and Scripts)
Object->isViewablertSingleForm (can the object be shown in its own window?)

User Rights

When querying the user rights, the name of the corresponding right must be passed:

User->hasRight(rightname)
Legal names for hasRight Standard user rights
'admin’ Awesome
'supervisor’ Project Administrator
'manager’ Project Manager
'self-tracking’ Project Time Tracker
'folderlinks_admin’ Folder links Administrator
'folderlinks_user’ Folder links User
'address_admin’ Address Administrator
'address_user’ Address User
'benchmarking’ Benchmarking
'treeview’ Tree view
'systemproperties’ system settings
'trackingcontroller’ third party tracker
'book’ Post invoices
'book_creditor’ Post accounts payable
'benchmarking_no_users’ Benchmarking without operator numbers
'teamleader’ Team Leader
'export’ Export
'sqlquery’ SQL Query

If an unknown right name is specified, the hasRight operator returns False.

Ocl ocl operators for project entries

Project entries is the collective term for services, expenses and outlays. These, in turn, are divided into open and charged. The assignments to projects, phases and users are defined in the model at the lowest level, i.e. on the open or charged services, expenses or outlays.

For easy access to project, phase and user, the following operators are available from version 5.7:

Operator description
getProject
Returns the project on which the service, expense or outlay was entered.
getPhase
Returns the phase of the project to which the service, expense, or outlay is assigned.
getEditor
Returns the user who entered the service, expense or outlay.

For example, a list of users based on services of an invoice:

services.getEditor->asSet

Vertec versions before 5.7 require casts when accessing a list with a more general type (service, expenses, outlays). For example, a list of users based on services of an invoice:

leistungen->collect(if oclIsTypeOf (VerrechneteLeistung) then oclAsType
 (VerrechneteLeistung).bearbeiter else oclAsType(OffeneLeistung).bearbeiter endif)->asSet

Ocl ocl operators for project phases

phaseGetProject

In versions prior to 6.3, the subphases of a project phase do not have a direct connection to the project to which they belong. The OCL operator phaseGetProject returns the project for any phase or subphase:

self.phaseGetProjekt

Starting with Vertec 6.3, the member owningProjekt can also be used for this purpose.

Operators for links

userentry->getLinks(role)Returns a list of objects linked to the entry under this role.
Project Editor->getLinks('archive entries’)

Power Sum Operators

For optimizing custom evaluations with expression folders and list columns, or for use in custom reports, accelerated summation and grouping is available in the form of an OCL operator groupLeistungen. For more information on the performance totals operators, see the performance totals article.

Date Operators

date
the date operator returns the up-to-date date.
now
the now operator returns the up-to-date date incl. time
dateToFloat
converts a date/time value to a floating point number. The integer percentage is the number of days since December 30, 1899. The fraction indicates the time.
floatToDate
converts a number into a date/time value.
dateToStrGerman
As of Vertec 6.2. Returns the date in German date format as a string.

It sometimes needs date values in German format at certain locations, regardless of up-to-date locale settings (see e.g. from/to arguments in groupPerformance operators).

argobject.eval('creationdatetime.datetostrgerman')
year
calculates the year of a date value.
month
calculates the month (1-12) of a date value.
day
calculates the day of the month of a date value.
hours
returns the hours of the time value as an integer.
minutes
returns the minutes of the time value as an integer.
seconds
returns the seconds of the time value as an integer.
milliseconds
returns the milliseconds of the time value as an integer.
incMonth(quantity)

adds quantity months to a date. You can also use it to count backwards: for example, date.incMonth(-1) counts back one month from the current date.

Note: If the date is at the end of the month and the respective months have different quantities of days, the last day of the month is taken.

Example: incmonth(-1) executed on 31.03.2021 results in 28.02.2021.

incDay(quantity)
adds quantity of days to a date. You can also count back: for example, date.incDay(-10) counts back ten days from the current date.
firstOfYear
calculates for a date the date of the first day of the year (1 January).
lastOfYear
calculates for a date the date of the last day of the year (31 December).
firstOfQuarter
calculates the first day of the quarter.
lastOfQuarter

calculates the last day of the quarter. Example:

self->groupleistungenP(date.firstOfQuarter.asstring,  date.lastOfQuarter.asstring, '')->collect(minutenintoffen+minutenintverrechnet)->sum
as a column expression in a project list shows the entered hours (open) in the up-to-date quarter.
firstOfMonth
calculates the first day of the month.
lastOfMonth
calculates the last day of the month.
MondayOfWeek
calculates the date of the Monday of a week.
encodeDate
(year, month, day)

calculates a date based on numerical values for year, month and day. Example: folder with all invoices created in 2012:

invoice->select((date >= encodeDate(2012,01,01)) and (date <= encodeDate(2012,12,31)))
formatdatetime
(formatstring)
Formats date and time according to format string (from version 5.2.0.15).

Example:

creationdatetime.formatdatetime('c’)-> '16.10.2010 15:24:31'

The format string can contain:

  • c: Displays the date in the global format ShortDateFormat, followed by the time in the global format LongTimeFormat. If it has no time value, only the date is displayed.
  • d: day as number without leading 0s (1-31).
  • dd: day as a two-digit number (01-31).
  • ddd: Day as abbreviation (Mon-Sun) according to global settings (ShortDayNames).
  • dddd: Day as word (Monday-Sunday) according to global settings (LongDayNames).
  • m: Month as a number without a leading 0 (1-12). If m immediately follows h or hh, it is interpreted as a placeholder for minutes instead of the month, and the minutes are shown.
  • mm: Month as a two-digit number (01-12). If mm immediately follows h or hh, it is interpreted as a placeholder for minutes instead of the month, and the minutes are shown.
  • mmm: Month as abbreviation (Jan-Dec) according to global settings (ShortMonthNames).
  • mmmm: Month as word (January-December) according to global settings (LongMonthNames).
  • yy: year as a two-digit number (00-99).
  • yyyy: Year as a four-digit number (0000-9999).
  • h: hours without preceding 0 (0-23).
  • hh: hours as a two-digit number (00-23).
  • n: minutes without leading 0 (0-59).
  • nn: minutes as a two-digit number (00-59).
  • s: seconds without leading 0 (0-59).
  • ss: seconds as a two-digit number (00-59).
  • z: milliseconds without leading 0 (0-999).
  • zz: milliseconds as a three-digit number (000-999).
  • t: Time value in the format of the short time (ShortTimeFormat), e.g. 11:37.
  • tt: Time value in LongTimeFormat, e.g. 11:37:40.
  • /: Date separator according to global settings (DateSeparator).
  • :: Time separator according to global settings (TimeSeparator).
  • xx: Other letters and symbols are not formatted, but are displayed as entered, e.g. hh...mm results in 11...37. Exception: e, g.

OCL Variables

In certain locations, there are OCL variables that can be used to access specific objects. These are:

OCL Variable Use
varLogin
In Expressions on rights , the up-to-date login can be accessed via the variable varLogin can be accessed.
varContainer

From Vertec 6.4.0.21. Access in OCL expressions in lists to the container (folder or LinkContainer).

In addition to the column expressions in the list, the also have access to this context variable.

varContext

As of Vertec 6.6.0.1. Access in OCL expressions to customize list settings. Contains the currently selected entry in the tree. For containers, the value is identical to varContainer (see above).

Specifically in Resource Planning , the variable makes it possible to customize lists depending on whether a resource planning view is shown for individual objects or lists.

It is also available in List Controllers and Custom Renderers . To make the OCL variable easy to use here, both have the self.evalocl() method available, which uses this specific OCL evaluator. The OCL variable is defined only in this evaluator.

varParent

Starting with Vertec 6.4.0.21. Access in OCL expressions in lists to the object to which the container belongs (parent object of the link container).

In addition to the column expressions in the list, the Listexpression and ghostrowlistexpression of a control also have access to this context variable.

varStartDate Starting with Vertec 6.6.0.1, for use in resource planning tables. Contains the start date of the current resource planning view to:
  • Time table: Start date of the first interval in period
  • Pivot table: Interval start date

It is available in resource planning views and the corresponding list controllers, as well as in the custom renderers.

To make it easy to use the OCL variable in and , both have the self.evalocl() method available, which uses this specific OCL evaluator. The OCL variable is defined only in this evaluator.

The container variables varContainer and varParent contain null in the case of a single object.

varEndDate Starting with Vertec 6.6.0.1, for use in resource planning tables. Contains the end date of the resource planning view:
  • Time table: End date of last interval in period
  • Pivot table: End date of interval

It is available in resource planning views and the corresponding list controllers, as well as in the custom renderers.

To make it easy to use the OCL variable in List Controllers and Custom Renderers , both have the self.evalocl() method available, which uses this specific OCL evaluator. The OCL variable is defined only in this evaluator.

The container variables varContainer and varParent contain null in the case of a single object.

varView
Starting with Vertec 6.6.0.1. Specifies the type of list view. Possible values are:
  • default: a standard list view (container)
  • resources: a resource planning view (container or user entry, configured via resource planning view (see 2.5))
  • bi a BI (business intelligence) view.
The variable can be used in the condition of scripts to control which views the script appears in the menu, e.g. (varView='default') or (varView='bi').
var<Feldname>
Starting with Vertec 6.1. Access Query parameters in columns of sql and expression folders .

Comparisons

Comparisons of 2 values (usually a member reference and a constant) are common in OCL expressions, usually as a condition in a select operator.

The simplest form of a comparison is the identity comparison in the form of a “=” symbol:

projekt->select(code='ABC')

returns a list of all projects whose code exactly matches the string ABC. Normally, this list should include only one project.

The well-known operators for greater, lesser, or unequal (<, >, <>) provide additional possibilities for comparisons. Comparisons can be made with strings and with numbers.

Booleans (true/false values) can also be compared.

If you want to query a Boolean value to true, this is done implicitly (if aktiv then.. or bearbeiter->select(aktiv) etc.)

The following Boolean operators return all or all and are used to query values, filter lists, etc.

and

Logical AND, that is, both elements associated with AND must be met.

invoice->select((date >= encodeDate(2012,01,01)) and (date <= encodeDate(2012,12,31)))

or

Logical OR, that is, at least one of the two elements which are connected with OR, must be fulfilled.

xor

Contravalent OR, that is, exactly one of the two elements is fulfilled, either one or the other; neither are both at the same time true nor both at the same time false.

not

The not operator queries Boolean elements for false.

editor->select(not active)

String Comparisons

For string comparisons (or string comparisons) there is also the option to consider substrings. For this purpose there are the following comparison operators:

sqlLike
It has nothing to do with SQL, except that the format of the pattern string follows the convention in the SQL standard. sqllike uses a pattern string for comparison, which can include wildcard characters. The following example returns all projects whose code begins with “AB”:

projekt->select(code->sqllike('AB%'))
sqlLikeCaseInsensitive
Same as the previous sqllike, but case insensitive.

The following symbols can be used as wildcards:

  • '%': Replaces any string of any length. E.g. AA% describes all strings starting with AA.
  • '_': Replaces a single letter. For example, AA_ describes all strings that begin with AA and have exactly one letter after that.
regExpMatch
Is the most universal operator of the three. It expects a so-called regular expression. The following basic elements can be used in Vertec, case-insensitive:

., *, +, [, ], ^, $, –, \

Conditions

An OCL expression can also contain conditions, but because an expression must always have a certain value, unlike programming languages, only if ... then ... else ... endif constructs are possible. An example of an if condition follows in the next section about type operators.

Type operators (ocltype, oclistypeof, ocliskindof, oclastype, containstype)

To find out what type (class) an object is, you can use oclType. For example, in a list column, you can show the type of each entry. An example of this is the Data Type column in Vertec’s standard search.

If you query oclType in expressions or a script, oclType.asstring must be queried, since the oclType itself is None. The list columns do this automatically, but in other locations this must be done explicitly.

There are a number of operators in OCL for converting object types. Of course, you cannot really change the type of an object, OCL is just a query language. However, you may need to specify a type conversion for an OCL expression to be valid.

An example of this are lists of address entries. The class Address entry is the base class for the classes Person, couple, company, contact, Simpleaddress. In most cases, lists of address entries are of the type Collection(address entry). Now the first name attribute of a person object should be displayed in an address list. The OCL expression vorname in the column settings of an address list leads to the error message “first name is not a member of address entry”.

In order to show the desired information (but only for people), the following expression could be given:

if oclIsTypeOf(Person) then oclAsType(Person).vorname else '' endif

The expression refers to the object in the list and contains two type operators. oclIsTypeOf checks if the object is of a specific type, and oclAsType makes the OCL interpreter treat this address as a person and accept the member first name.

If you want to know if an object is an address entry (no matter if it is a person, company, etc.), you can query it with oclIsKindOf. For example, in a list of mixed objects, you want to show the name if it is an address:

if oclIsKindOf(Adresseintrag) then name.asstring else '' endif

Attributes of type TypeList – these are the “classes” attributes e.g. on folders, scripts, reports etc. – contain a list of classes. However, the above operators only work on a single object. To find out if a particular class is included, from Vertec 6.7.0.15 onwards there is the operator containsType on this TypeList attribute. It can be used to query whether a particular class is included in it:

ordner.types.containsType(Projekt) 

Ocl call operators for custom business logic

Starting with Vertec version 6.3.0.12. With the OCL Call operators, specific Python methods can be called from OCL. This makes it possible to write additions to the business logic in Python and use them in different locations instead of the built-in business logic, e.g. in scripts and for presentation in reports.

Because OCL is static and strictly typed, a separate OCL operator is needed for each required combination of return value and arguments. The following are available:

  • callString (-> string)
  • callCurr (-> currency)
  • callCurrDate (date -> currency)
  • callCurrDateDate (date, date -> currency)
  • callStringString (string->string)
  • callCurrString (string -> float)
  • callCurrDateDateString (date, date, string -> float)

The OCL operators are applied to BusinessclassesRoot and all have the name of the implementing Python function as their first argument. This name is given in the form <Modul>.<Funktionsnamen>.

Example

A script module called customlogic is created, in which a feature with the signature

def percentofcompletion(project, eff_date)

The call in OCL would then look like this:
proj->callCurrDate('customlogic.percentofcompletion', somedate), the result of the OCL expression is a Currency value.

The name of the call operator used contains the type of the return value and the arguments (return value Currency “Curr,” argument “Date”).

Important notes

It is important to know that the call operators are queries that execute the corresponding Python code at the time of the query and then show the result. If the data changes in the background, this has no effect on the results of the call operators. These are not automatically recalculated, so the displayed result is only valid at the time of execution.

This means that the call operators are not suitable for locations where dynamic data is to be worked with, e.g. for display on a page.

For list columns, we recommend to use the Custom Renderer instead of call operators, which are subscribed, allow write access, and offer the possibility to set a variety of parameters.

The call operators are suitable in the following cases:

  • In Office reports
  • Via COM extension
  • Via XML queries (e.g. to ensure that an external application has exactly the same data)

In addition, call operators should not be used to modify data, but only to read data. They are not used to trigger operations such as in an event script, but purely for read access.