Skip to content

feat: Add Travel Request Approval Management App #122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions samples/travel-request-approval/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Travel Request Approval Management Canvas Application

## Summary

Travel Request Approval is a comprehensive corporate travel request solution designed to streamline employee trip approvals while ensuring policy compliance. Transform your travel management process with automated workflows and real-time budget tracking.

📢 This enterprise-ready solution enables organizations to:

✈️ Submit Travel Requests
✅ Track Multi-Level Approvals
📊 Enforce Budget Policies

![Travel Approval Interface](./assets/preview.png)

## Applies to

![Power Apps](https://img.shields.io/badge/Power%20Apps-Yes-green "Yes")

## Compatibility
![Premium License](https://img.shields.io/badge/Premium%20License-Not%20Required-green.svg "No premium required")
![Experimental Features](https://img.shields.io/badge/Experimental%20Features-No-red.svg "Production-ready solution")

## Contributors

* [Summit Baj](https://github.com/summitbaj)

## Version history

Version|Date|Comments
-------|----|--------
1.0|Jan 25, 2025|Initial release

## Prerequisites

- Microsoft Dataverse: **Travel Requests**

## Solution Components

Component|Type
---------|-----
Travel Request App | Canvas App
Travel Request Admin Portal | Model Drivel App
Approval Workflow | Power Automate Flow

## Minimal Path to Awesome

1. [Download](./solution/TravelRequestApprovalApp_1_0_0_2.zip) the solution package
2. Import into Power Apps via **Solutions** > **Import solution**
3. Deploy the Travel Request Approval app to your users

## Using the Source Code

To modify and repackage using Power Apps CLI:

```bash
pac solution pack --folder travel-request-src --zipfile travel-request-approval.zip --processCanvasApps
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions samples/travel-request-approval/assets/sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
[
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/pnp/samples/v1.0/metadata-schema.json",
"name": "travel-request-approval-app",
"version": "1.0.0.0",
"source": "pnp",
"creationDateTime": "2025-01-25T00:00:00.000Z",
"updateDateTime": "2025-01-25T00:00:00.000Z",
"title": "Travel Request Approval Management Canvas App",
"shortDescription": "Streamline employee travel requests with automated approval workflows and policy compliance tracking.",
"longDescription": [
"End-to-end solution for managing corporate travel requests, including multi-level approvals, budget validation, and integration with travel booking systems."
],
"url": "https://github.com/pnp/powerapps-samples/tree/main/samples/travel-request-approval",
"products": [
"Power Apps",
"Power Platform"
],
"tags": [
"POWERAPPS",
"TEMPLATE",
"TRAVEL-REQUESTS",
"APPROVAL-WORKFLOW",
"EXPENSE-MANAGEMENT"
],
"categories": [
"POWERAPPS"
],
"metadata": [
{
"key": "POWERAPPS-MANIFEST-VERSION",
"value": "0.20"
},
{
"key": "POWERAPPS-TYPE",
"value": "Canvas"
},
{
"key": "POWERAPPS-EXPERIMENTAL",
"value": "No"
},
{
"key": "POWERAPPS-PREMIUM",
"value": "No"
},
{
"key": "POWERAPPS-ONPREM",
"value": "No"
},
{
"key": "POWERAPPS-CUSTOMCONNECTOR",
"value": "No"
}
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://github.com/pnp/powerplatform-samples/blob/0e2eaf70c87cbcb5a19a700bb57a8276ecfefbec/samples/travel-request-approval/assets/preview.png",
"alt": "Approval Workflow Preview"
}
],
"authors": [
{
"gitHubAccount": "summitbaj",
"name": "Summit Bajracharya",
"pictureUrl": "https://avatars.githubusercontent.com/u/109615108"
}
],
"references": [
{
"name": "Create a component for canvas apps",
"description": "Components are reusable building blocks for canvas apps so that app makers can create custom controls to use inside an app, or across apps using a component library",
"url": "https://docs.microsoft.com/powerapps/maker/canvas-apps/"
},
{
"name": "Overview of creating apps in Power Apps",
"description": "Power Apps is a high-productivity development platform for business apps.",
"url": "https://docs.microsoft.com/powerapps/maker/"
},
{
"name": "Power Apps canvas apps documentation",
"description": "Design and build a business app from a canvas in Microsoft Power Apps with data from a variety of sources without writing any code using traditional programming languages, such as C#.",
"url": "https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/"
}
]
}
]
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<AppModuleSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SiteMapUniqueName>sb_TravelRequestAdminPortal</SiteMapUniqueName>
<EnableCollapsibleGroups>False</EnableCollapsibleGroups>
<ShowHome>True</ShowHome>
<ShowPinned>True</ShowPinned>
<ShowRecents>True</ShowRecents>
<SiteMap IntroducedVersion="7.0.0.0">
<Area Id="area_a8357d40" ResourceId="SitemapDesigner.NewTitle" DescriptionResourceId="SitemapDesigner.NewTitle" ShowGroups="true" IntroducedVersion="7.0.0.0">
<Titles>
<Title LCID="1033" Title="Area1" />
</Titles>
<Group Id="group_6e1840fb" ResourceId="SitemapDesigner.NewGroup" DescriptionResourceId="SitemapDesigner.NewGroup" IntroducedVersion="7.0.0.0" IsProfile="false" ToolTipResourseId="SitemapDesigner.Unknown">
<Titles>
<Title LCID="1033" Title="Employee Management" />
</Titles>
<SubArea Id="subarea_53a2332b" Icon="/_imgs/imagestrips/transparent_spacer.gif" Entity="systemuser" Client="All,Outlook,OutlookLaptopClient,OutlookWorkstationClient,Web" AvailableOffline="true" PassParams="false" Sku="All,OnPremise,Live,SPLA">
<Titles>
<Title LCID="1033" Title="Employees" />
</Titles>
</SubArea>
<SubArea Id="subarea_70d78656" Icon="/_imgs/imagestrips/transparent_spacer.gif" Entity="position" Client="All,Outlook,OutlookLaptopClient,OutlookWorkstationClient,Web" AvailableOffline="true" PassParams="false" Sku="All,OnPremise,Live,SPLA" />
<SubArea Id="NewSubArea_0c384033" Icon="/_imgs/imagestrips/transparent_spacer.gif" Entity="sb_purposeoftravel" Client="All,Outlook,OutlookLaptopClient,OutlookWorkstationClient,Web" AvailableOffline="true" PassParams="false" Sku="All,OnPremise,Live,SPLA" />
</Group>
<Group Id="group_e814f0d0" ResourceId="SitemapDesigner.NewGroup" DescriptionResourceId="SitemapDesigner.NewGroup" IntroducedVersion="7.0.0.0" IsProfile="false" ToolTipResourseId="SitemapDesigner.Unknown">
<Titles>
<Title LCID="1033" Title="Leave Requests" />
</Titles>
<SubArea Id="subarea_bb57f7a4" Icon="/_imgs/imagestrips/transparent_spacer.gif" Entity="sb_travelrequest" Client="All,Outlook,OutlookLaptopClient,OutlookWorkstationClient,Web" AvailableOffline="true" PassParams="false" Sku="All,OnPremise,Live,SPLA" />
</Group>
<Group Id="group_7822adf1" ResourceId="SitemapDesigner.NewGroup" DescriptionResourceId="SitemapDesigner.NewGroup" IntroducedVersion="7.0.0.0" IsProfile="false" ToolTipResourseId="SitemapDesigner.Unknown">
<Titles>
<Title LCID="1033" Title="Rules" />
</Titles>
<SubArea Id="subarea_461adf7d" Icon="/_imgs/imagestrips/transparent_spacer.gif" Entity="sb_requestrules" Client="All,Outlook,OutlookLaptopClient,OutlookWorkstationClient,Web" AvailableOffline="true" PassParams="false" Sku="All,OnPremise,Live,SPLA" />
</Group>
</Area>
</SiteMap>
<LocalizedNames>
<LocalizedName description="Travel Request Admin Portal" languagecode="1033" />
</LocalizedNames>
</AppModuleSiteMap>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<AppModule>
<UniqueName>sb_TravelRequestAdminPortal</UniqueName>
<IntroducedVersion>1.0.0.0</IntroducedVersion>
<WebResourceId>953b9fac-1e5e-e611-80d6-00155ded156f</WebResourceId>
<OptimizedFor></OptimizedFor>
<statecode>0</statecode>
<statuscode>1</statuscode>
<FormFactor>1</FormFactor>
<ClientType>4</ClientType>
<NavigationType>0</NavigationType>
<AppModuleComponents>
<AppModuleComponent type="1" schemaName="position" />
<AppModuleComponent type="1" schemaName="sb_linemanager" />
<AppModuleComponent type="1" schemaName="sb_purposeoftravel" />
<AppModuleComponent type="1" schemaName="sb_requestrules" />
<AppModuleComponent type="1" schemaName="sb_roles" />
<AppModuleComponent type="1" schemaName="sb_travelrequest" />
<AppModuleComponent type="1" schemaName="sb_userroles" />
<AppModuleComponent type="1" schemaName="systemuser" />
<AppModuleComponent type="26" id="{09ba8524-254e-ed11-bba1-002248212f5a}" />
<AppModuleComponent type="26" id="{57cfb28f-934e-ed11-bba1-002248212f5a}" />
<AppModuleComponent type="60" id="{1fdf4108-b705-4cc9-9b5e-f99fda359afd}" />
<AppModuleComponent type="62" schemaName="sb_TravelRequestAdminPortal" />
</AppModuleComponents>
<AppModuleRoleMaps>
<Role id="{49dc42ed-984e-ed11-bba1-002248212f5a}" />
<Role id="{627090ff-40a3-4053-8790-584edc5be201}" />
<Role id="{119f245c-3cc8-4b62-b31c-d1a046ced15d}" />
</AppModuleRoleMaps>
<LocalizedNames>
<LocalizedName description="Travel Request Admin Portal" languagecode="1033" />
</LocalizedNames>
</AppModule>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<CanvasApp xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>sb_travelrequestapp_71ff6</Name>
<AppVersion>2022-12-11T15:16:56Z</AppVersion>
<Status>Ready</Status>
<CreatedByClientVersion>3.22111.28.0</CreatedByClientVersion>
<MinClientVersion>3.22111.28.0</MinClientVersion>
<Tags>{"primaryDeviceWidth":"2979","primaryDeviceHeight":"1303","supportsPortrait":"true","supportsLandscape":"true","primaryFormFactor":"Phone","publisherVersion":"3.22111.28","minimumRequiredApiVersion":"2.2.0","hasComponent":"true","hasUnlockedComponent":"true","isUnifiedRootApp":"false","sienaVersion":"20221114T150215Z-3.22104.22.0"}</Tags>
<IsCdsUpgraded>0</IsCdsUpgraded>
<GalleryItemId xsi:nil="true"></GalleryItemId>
<BackgroundColor>RGBA(0,176,240,1)</BackgroundColor>
<DisplayName>Travel Request App</DisplayName>
<Description xsi:nil="true"></Description>
<CommitMessage xsi:nil="true"></CommitMessage>
<Publisher xsi:nil="true"></Publisher>
<AuthorizationReferences>[{"resourceId":"powerbi"}]</AuthorizationReferences>
<ConnectionReferences>{}</ConnectionReferences>
<DatabaseReferences>{"default.cds":{"databaseDetails":{"referenceType":"Environmental","environmentName":"default.cds","overrideValues":{"status":"NotSpecified"}},"dataSources":{"Users":{"entitySetName":"systemusers","logicalName":"systemuser"},"Purpose of Travels":{"entitySetName":"sb_purposeoftravels","logicalName":"sb_purposeoftravel"},"Line Managers":{"entitySetName":"sb_linemanagers","logicalName":"sb_linemanager"},"Bulk Delete Failures":{"entitySetName":"bulkdeletefailures","logicalName":"bulkdeletefailure"},"User Roles":{"entitySetName":"sb_userroleses","logicalName":"sb_userroles"},"Roles":{"entitySetName":"sb_roleses","logicalName":"sb_roles"},"Positions":{"entitySetName":"positions","logicalName":"position"},"Duplicate Records":{"entitySetName":"duplicaterecords","logicalName":"duplicaterecord"},"Travel Request Audits":{"entitySetName":"sb_travelrequestaudits","logicalName":"sb_travelrequestaudit"},"Request Rules":{"entitySetName":"sb_requestruleses","logicalName":"sb_requestrules"},"Flight Bookings":{"entitySetName":"sb_flightbookingses","logicalName":"sb_flightbookings"},"Bookings":{"entitySetName":"ctb_bookingses","logicalName":"ctb_bookings"},"Hotel Bookings":{"entitySetName":"sb_hotelbookings","logicalName":"sb_hotelbooking"},"Mailboxes":{"entitySetName":"mailboxes","logicalName":"mailbox"},"Travel Requests":{"entitySetName":"sb_travelrequests","logicalName":"sb_travelrequest"}}}}</DatabaseReferences>
<AppComponents>[]</AppComponents>
<AppComponentDependencies>[]</AppComponentDependencies>
<CanConsumeAppPass>1</CanConsumeAppPass>
<CanvasAppType>0</CanvasAppType>
<BypassConsent>0</BypassConsent>
<AdminControlBypassConsent>0</AdminControlBypassConsent>
<EmbeddedApp xsi:nil="true"></EmbeddedApp>
<IntroducedVersion>1.0</IntroducedVersion>
<CdsDependencies>{"cdsdependencies":[{"logicalname":"systemuser","componenttype":1},{"logicalname":"sb_purposeoftravel","componenttype":1},{"logicalname":"sb_linemanager","componenttype":1},{"logicalname":"bulkdeletefailure","componenttype":1},{"logicalname":"sb_userroles","componenttype":1},{"logicalname":"sb_roles","componenttype":1},{"logicalname":"position","componenttype":1},{"logicalname":"duplicaterecord","componenttype":1},{"logicalname":"sb_travelrequestaudit","componenttype":1},{"logicalname":"sb_requestrules","componenttype":1},{"logicalname":"sb_flightbookings","componenttype":1},{"logicalname":"ctb_bookings","componenttype":1},{"logicalname":"sb_hotelbooking","componenttype":1},{"logicalname":"mailbox","componenttype":1},{"logicalname":"sb_travelrequest","componenttype":1}]}</CdsDependencies>
<IsCustomizable>1</IsCustomizable>
<BackgroundImageUri>/CanvasApps/sb_travelrequestapp_71ff6_BackgroundImageUri</BackgroundImageUri>
<DocumentUri>/CanvasApps/sb_travelrequestapp_71ff6_DocumentUri.msapp</DocumentUri>
</CanvasApp>
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name LocalizedName="User" OriginalName="">SystemUser</Name>
<EntityInfo>
<entity Name="SystemUser" unmodified="1">
<attributes />
</entity>
</EntityInfo>
<SavedQueries />
<RibbonDiffXml />
</Entity>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RibbonDiffXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CustomActions />
<Templates>
<RibbonTemplates Id="Mscrm.Templates"></RibbonTemplates>
</Templates>
<CommandDefinitions />
<RuleDefinitions>
<TabDisplayRules />
<DisplayRules />
<EnableRules />
</RuleDefinitions>
<LocLabels />
</RibbonDiffXml>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<savedqueries xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<savedquery>
<IsCustomizable>1</IsCustomizable>
<CanBeDeleted>1</CanBeDeleted>
<isquickfindquery>0</isquickfindquery>
<isprivate>0</isprivate>
<isdefault>0</isdefault>
<savedqueryid>{09ba8524-254e-ed11-bba1-002248212f5a}</savedqueryid>
<layoutxml>
<grid name="resultset" jump="fullname" select="1" icon="1" preview="1">
<row name="result" id="systemuserid">
<cell name="fullname" width="200" />
<cell name="positionid" width="100" />
<cell name="internalemailaddress" width="100" />
<cell name="address1_telephone1" width="100" />
<cell name="parentsystemuserid" width="100" />
<cell name="businessunitid" width="100" />
</row>
</grid>
</layoutxml>
<querytype>0</querytype>
<fetchxml>
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="systemuser">
<attribute name="fullname" />
<attribute name="systemuserid" />
<attribute name="positionid" />
<attribute name="internalemailaddress" />
<attribute name="address1_telephone1" />
<filter type="and">
<condition attribute="accessmode" operator="not-in">
<value>4</value>
<value>5</value>
<value>1</value>
<value>3</value>
</condition>
<condition attribute="isdisabled" operator="eq" value="0" />
</filter>
<attribute name="businessunitid" />
<attribute name="parentsystemuserid" />
</entity>
</fetch>
</fetchxml>
<IntroducedVersion>1.0.0.0</IntroducedVersion>
<LocalizedNames>
<LocalizedName description="Employees" languagecode="1033" />
</LocalizedNames>
</savedquery>
</savedqueries>
Loading