Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 10 Next »

Provides a NoSQL database environment for varying numbers of big entities. The data stored in an XML database are held as a big whole XML chunk containing various smaller XML nodes in a tree like structure. There are two types of XML databases used when storing XML data in Emakin; those are process databases and a domain database.

Process Database

Every time a process created in Emakin, a separate XML database is allocated for that process automatically. All the workflows running on Emakin keep their data as XML forms and whenever a workflow gets triggered from a process, its form content and an XML metadata of this workflow gets stored into the corresponding process database alongside under the root node. Any changes made on the flow automatically updates this data, for example taking an action on a task or completing a flow.

The data stored here is almost identical to the data stored in the relational database except for being in XML form. The key difference here is that XML data of a workflow is more compact and easier to obtain and organize to create desired reports with it. Besides retrieving these data from SQL data tables is managed by Emakin's built-in functions in a resctricted aspect. For this reason, using the process data stored in XML databases is more practical when generating report views depending on process data.

Instance Data

The XML metadata stored in the process database is enclosed within <Instance> tags and contains various information about the goings-on of a workflow. Instance node represents the workflow's itself and contains a list of every work item owned. Whenever a work item belonging to a flow is completed, its XML metadata gets stored into its corresponding work items list.

See below for an XML example of instance data:

Instance Data
<Instance>
  <Id>2fbeff56-2574-4950-91b2-11eec2c63586</Id>
  <Number>217</Number>
  <TestMode>True</TestMode>
  <Culture>en-US</Culture>
  <State>Completed</State>
  <Start>2019-03-14T11:02:09.1982068+03:00</Start>
  <End>2019-03-14T11:05:01.5890176+03:00</End>
  <WorkItems>
    <WorkItem>
      <Id>cd4d51a2-0ca0-4b2d-aa5c-a9d8de07243b</Id>
      <Name>Expense Form</Name>
      <Caption>Expense Form</Caption>
      <State>Completed</State>
      <Start>2019-03-14T11:02:09.1982068+03:00</Start>
      <End>2019-03-14T11:04:22.8982862+03:00</End>
      <Duration>2.2283346566666666</Duration>
      <SelectedActionId>05671ad9-65d9-41f6-aa84-20ce2a984676</SelectedActionId>
      <SelectedAction>Submit</SelectedAction>
      <IsDeadlined>False</IsDeadlined>
      <DeadlineDate/>
      <Previous/>
      <CompletedBy Caption="Bülent Yüksel">b8e60233-7fce-4d8d-a597-acd4fd90ce05</CompletedBy>
      <DataId>f2e38788-9dbc-4e80-8c93-0b9410c07642</DataId>
      <DataRoot>ExpenseForm</DataRoot>
    </WorkItem>
    <WorkItem>
      <Id>c026a945-b309-42ee-a335-eade87c79e23</Id>
      <Name>Expense Payment</Name>
      <Caption>Expense Payment</Caption>
      <State>Completed</State>
      <Start>2019-03-14T11:04:44.2056377+03:00</Start>
      <End>2019-03-14T11:04:53.2101814+03:00</End>
      <Duration>0.15007572833333332</Duration>
      <SelectedActionId>4e7a6cb3-b529-492f-b796-6764c86f9956</SelectedActionId>
      <SelectedAction>Completed</SelectedAction>
      <IsDeadlined>False</IsDeadlined>
      <DeadlineDate/>
      <Previous>8c97b0af-4545-49ed-9539-f38ca3284953</Previous>
      <CompletedBy Caption="Bülent Yüksel">b8e60233-7fce-4d8d-a597-acd4fd90ce05</CompletedBy>
      <DataId>f2e38788-9dbc-4e80-8c93-0b9410c07642</DataId>
      <DataRoot>ExpenseForm</DataRoot>
    </WorkItem>
    <WorkItem>
      <Id>7c91dc2c-69ad-4b95-b683-eaded3458934</Id>
      <Name>Expense Form Information</Name>
      <Caption>Expense Form Information</Caption>
      <State>Completed</State>
      <Start>2019-03-14T11:04:53.2101814+03:00</Start>
      <End>2019-03-14T11:05:01.5835033+03:00</End>
      <Duration>0.13955536500000001</Duration>
      <SelectedActionId>6b124053-b249-441b-8e3f-ce114c073da2</SelectedActionId>
      <SelectedAction>Close</SelectedAction>
      <IsDeadlined>False</IsDeadlined>
      <DeadlineDate/>
      <Previous>c026a945-b309-42ee-a335-eade87c79e23</Previous>
      <CompletedBy Caption="Bülent Yüksel">b8e60233-7fce-4d8d-a597-acd4fd90ce05</CompletedBy>
      <DataId>f2e38788-9dbc-4e80-8c93-0b9410c07642</DataId>
      <DataRoot>ExpenseForm</DataRoot>
    </WorkItem>
    <WorkItem>
      <Id>8c97b0af-4545-49ed-9539-f38ca3284953</Id>
      <Name>Manager Approval</Name>
      <Caption>Manager Approval</Caption>
      <State>Completed</State>
      <Start>2019-03-14T11:04:23.0425214+03:00</Start>
      <End>2019-03-14T11:04:44.2056377+03:00</End>
      <Duration>0.352718605</Duration>
      <SelectedActionId>8ee3e1f2-6d82-4bf2-be00-e6263d8d61c4</SelectedActionId>
      <SelectedAction>Approve</SelectedAction>
      <IsDeadlined>False</IsDeadlined>
      <DeadlineDate>2019-03-21T09:00:00+03:00</DeadlineDate>
      <Previous>cd4d51a2-0ca0-4b2d-aa5c-a9d8de07243b</Previous>
      <CompletedBy Caption="Bülent Yüksel">b8e60233-7fce-4d8d-a597-acd4fd90ce05</CompletedBy>
      <DataId>f2e38788-9dbc-4e80-8c93-0b9410c07642</DataId>
      <DataRoot>ExpenseForm</DataRoot>
    </WorkItem>
  </WorkItems>
</Instance>

Form Data

Similar to the instance metadata, form content generated by the process also gets stored into process database and is enclosed within <form> tags. Every time a work item is completed, its existing XML form data gets updated to reflect the latest changes made on the form.

See below for an XML example of form data:

Form Data
<form Id="f2e38788-9dbc-4e80-8c93-0b9410c07642">
  <ExpenseForm>
    <PersonnelInformation>
      <Owner Caption="Bülent Yüksel" Type="User" Domain="cadf027b-8cc3-41e1-b0e2-ed856a0579fa">b8e60233-7fce-4d8d-a597-acd4fd90ce05</Owner>
      <RegistryNumber>4444</RegistryNumber>
      <Department Caption="Research and Development">c647464d-3745-4373-8309-0cfa0a34ae70</Department>
      <Location Caption=""/>
    </PersonnelInformation>
    <AdvanceInfo>
      <Description/>
      <Amount/>
      <Unit/>
    </AdvanceInfo>
    <ExpenseInformation>
      <Date>2019-03-14T11:02:09.2821462+03:00</Date>
    </ExpenseInformation>
    <ExpenseList>
      <Expense>
        <Id/>
        <Date>2019-03-06T00:00:00+03:00</Date>
        <ExpenseTypeGroup Caption="Transport">16</ExpenseTypeGroup>
        <ExpenseType Caption="Highway">1601</ExpenseType>
        <CostArea/>
        <DocumentDate/>
        <Reason>taxi fare to customer</Reason>
        <DocumentNumber/>
        <DocumentTitle/>
        <DocumentTaxNumber/>
        <Amount>18.00</Amount>
        <Unit Caption="US Dollar">USD</Unit>
        <CrossRate>1.00</CrossRate>
        <ConvertedAmount>18</ConvertedAmount>
        <VAT Caption="8">8</VAT>
      </Expense>
    </ExpenseList>
    <Discussion>
      <ns1:Entries xmlns:ns1="http://schemas.emakin.com/forms/controls"/>
    </Discussion>
    <SetupCheck>
      <FirstManager>c0d262ef-afcb-4ec5-8cba-b402ef13727b</FirstManager>
      <Finance>126945af-5ff5-49ef-8f55-0b702ad06530</Finance>
    </SetupCheck>
  </ExpenseForm>
</form>

Domain Database

For every domain hosted on Emakin, a separate XML database is created. This database is reserved for only special use cases and Emakin does not store any data by default. 

General usage examples are as follows:

  • Storing settings for processes
  • Storing scripts that can be used in processes
  • Saving important process parameters
  • Keeping pre-formatted statistics to later display in dashboards

Since this database is reserved for custom usage, there is no default root node so you have to define a unique and describing root name when saving your data.

See below for an XML example of a custom settings data. 

Settings Data
<LRDictionary>
  <Definitions>
    <HRGroup Caption="Designer Specialist">439c9457-297e-47b4-b002-0e82ae1c94d0</HRGroup>
    <HRManager Caption="None"/>
    <LeaveTypes>
      <LeaveType>
        <Name>Annual</Name>
        <Code>A</Code>
        <SubLeaveTypes/>
        <Name_tr>Yıllık</Name_tr>
        <IncludeOnCalculation>True</IncludeOnCalculation>
        <HasSubTypes>false</HasSubTypes>
      </LeaveType>
      <LeaveType>
        <Name>Excuse</Name>
        <Code>E</Code>
        <SubLeaveTypes>
          <SubLeaveType>
            <Id>ac9572db-7045-4a37-a170-1781d56483d3</Id>
            <Name>Sickness</Name>
            <Name_tr>Hastalık</Name_tr>
          </SubLeaveType>
          <SubLeaveType>
            <Id>b2caff73-f308-4b01-979c-321dcb123056</Id>
            <Name>Paternity</Name>
            <Name_tr>Babalık</Name_tr>
          </SubLeaveType>
          <SubLeaveType>
            <Id>23cc603f-d037-4acc-90c9-8dc26aefb05a</Id>
            <Name>Death</Name>
            <Name_tr>Vefat</Name_tr>
          </SubLeaveType>
          <SubLeaveType>
            <Id>bc1f4fbc-1b81-4e92-9daa-b91ca39af77a</Id>
            <Name>Other</Name>
            <Name_tr>Diğer</Name_tr>
          </SubLeaveType>
        </SubLeaveTypes>
        <Name_tr>Mazeret</Name_tr>
        <IncludeOnCalculation/>
        <HasSubTypes>true</HasSubTypes>
      </LeaveType>
    </LeaveTypes>
    <Calculation>var today;
$Calendar2.GetToday('', function(newDate) {
    today = newDate;
});

var results = $Database.Get({
    Parameters: {
        TargetSchema: 'HR',
        TargetTable: 'Employee'
    },
    Columns: [{
            Name: 'Id'
        },
        {
            Name: 'StartDate'
        },
        {
            Name: 'LastAllowanceCalcDate'
        },
        {
            Name: 'RegistryNumber'
        }
    ],
    Where: {
        Criteria: [{
                Name: 'LastAllowanceCalcDate',
                Value: today,
                Comparison: 'LessThanOrEqualTo',
                Condition: 'Or'
            },
            {
                Name: 'LastAllowanceCalcDate',
                Value: null,
                Comparison: 'Equals'
            }
        ]
    }
});

var tempDate = DateTimeOffset.parse('2007.01.01');

console.warn('Script Calculation Started');

results.Each(function() {
    if ((this.RegistryNumber != null) &amp;&amp; (this.StartDate != null)) {

        var tickerDate;
				
        if  (this.LastAllowanceCalcDate == null) {
            this.LastAllowanceCalcDate = this.StartDate;
			console.warn("LastAllowanceCalcDate not found, using StartDate");
        }
				
        console.warn('Calculation started for ' + this.RegistryNumber + " - " + this.LastAllowanceCalcDate );
		
		console.warn('Last Calculation Date is ' + this.LastAllowanceCalcDate.getFullYear() + '.' + this.LastAllowanceCalcDate.getMonth() + '.' + this.LastAllowanceCalcDate.getDate());

        tickerDate = this.LastAllowanceCalcDate;
			
        while (tickerDate &lt; today) {
		
			console.warn('Ticker Date is ' + tickerDate.getFullYear() + '.' + tickerDate.getMonth() + '.' + tickerDate.getDate());
			
            var allowance = 0;

            if (this.StartDate.getMonth() == tickerDate.getMonth()) {

                var diff = tickerDate.getFullYear() - this.StartDate.getFullYear();

                if (this.RegistryNumber == '151917') {
                    allowance = 29;
                } else {
                    if (this.StartDate &lt; tempDate) {
                        if (diff &gt;= 0 &amp;&amp; diff &lt;= 5) {
                            allowance = 17;
                        } else if (diff &gt; 5 &amp;&amp; diff &lt;= 10) {
                            allowance = 22;
                        } else if (diff &gt; 10) {
                            allowance = 27;
                        }
                    } else {
                        if (diff &gt;= 0 &amp;&amp; diff &lt;= 5) {
                            allowance = 17;
                        } else if (diff &gt; 5 &amp;&amp; diff &lt;= 14) {
                            allowance = 22;
                        } else if (diff &gt; 14) {
                            allowance = 26;
                        }
                    }
                }

                if (allowance &gt;= 0) {     
                    var strDate = tickerDate.getFullYear() + '.' + tickerDate.getMonth() + '.' + this.StartDate.getDate();
                    var allowedDate = DateTimeOffset.parse(tickerDate.getFullYear() + '.' + tickerDate.getMonth() + '.' + this.StartDate.getDate());
                    var allowanceForCurrentYear =  allowance - Math.round((allowance * (allowedDate.getMonth() / 12)));
                    InsertNewAllowance(this.Id, allowance, strDate, allowanceForCurrentYear);
                }
            }

            $Calendar2.GetStandardCalendar().AddMonths(tickerDate, 1, function(newDate) {
                tickerDate = newDate;
            });
        }

        this.LastAllowanceCalcDate = today;

        console.warn('Calculation ended for ' + this.RegistryNumber);

    }else{
	console.warn("RegistryNumber Number or Employee Start Date not found");
	}

});

console.log('Script Calculation Ended');

results.Save();


function InsertNewAllowance(employeeId, daysGained, strAllowedDate, daysGainedForCurrentYear) {
        
    var allowedDate = DateTimeOffset.parse(strAllowedDate);    

	var leaveResults = $Database.Get({
		Parameters: {
			TargetSchema: 'HR',
			TargetTable: 'LeaveAllowance'
		},
		Columns: [{
				Name: 'Id'
			}
		],
		Where: {
			Criteria: [{
					Name: 'AllowedDate',
					Value: allowedDate,
					Comparison: 'Equals'
				},
				{
					Name: 'Employee',
					Value: employeeId,
					Comparison: 'Equals'
				}
			]
		}
	});
	
	if(leaveResults.RowCount() &lt;= 0) {
        
        console.warn('New allowance detected for date : ' + strAllowedDate);
        
        var table = $Database.Empty({
            Parameters: {
                TargetSchema: 'HR',
                TargetTable: 'LeaveAllowance'
            }
        });

        table.Add({
            Id: Script.NewId(),
            Employee: employeeId,
            AllowedDate: allowedDate,
            DaysGained: daysGained,
            WorkItemId: $WorkItem.Id,
            FormNo: $Instance.Number,
            DaysGainedForCurrentYear : daysGainedForCurrentYear
        });

        table.Save();    
    }
}</Calculation>
    <Manager2Approval/>
    <SecondManagerApprovalExcluded/>
    <DayCountForWeek>5</DayCountForWeek>
  </Definitions>
</LRDictionary>

In this example, settings for the Leave Request process gets stored in domain database and its data is enclosed between <LRDictionary> tags as an arbitrary choice. It includes leave type definitions, their localization data and leave allowance calculation script as javascript code. A settings screen designed in this process loads this XML data and lets users to modify it depending on their needs, which makes this process considerably dynamic and flexible.




  • No labels