← Back to list

Learning by Building: Expense Claims Canvas App with Manager Approval

Building a business app can be one of the best ways to learn Power Apps. In this guide, we learn by building an Expense Claims canvas app…

Chamara Iresh Wijerathna · 2025-09-28 20:25 · 1 claps · 8.0 min read
#canvas-app #powerplatform #cloud-flow #microsoft-power-platform #power-platform-developers
Open on Medium ↗
Wiki topics: TLS · Design Tools & Workflow EDU · Education & Learning

Learning by Building: Expense Claims Canvas App with Manager Approval

Building a business app can be one of the best ways to learn Power Apps. In this guide, we learn by building an Expense Claims canvas app from scratch, including a simple manager approval process. This step-by-step tutorial starts with basics (ideal for beginners) and progresses to more advanced enhancements. We’ll keep the format formal yet easy to follow, with the original project structure (screenshots and steps) preserved for clarity. By the end, you will have a functional expense claim app and understand how to extend it with advanced features like Power Automate flows, custom connectors, and security roles.

Overview and Prerequisites

Scenario: Employees will use the app to submit expense claims (with details like amount, date, category, etc.), and managers will review and approve or reject these claims. We’ll use Microsoft Power Apps (Canvas App) for the user interface and a data source (Dataverse) to store the expense records.

What You Need:

  • Power Apps Access: A Microsoft 365 account with access to Power Apps (any standard license that allows Canvas app creation).
  • Data Storage: Dataverse for storing expense entries.
  • Basic Knowledge: No coding required, but familiarity with Power Apps Studio interface will help. We will explain each step in detail.

Note: Ensure you have appropriate permissions. If using SharePoint, you need permission to create lists on a SharePoint site. If using Dataverse, you need environment access to create tables. Also, if you plan to share the app with others, those users must have access to the underlying data (SharePoint list or Dataverse).

Step 1: Dataverse design — Set Up the Expense Claims Data Source

Before building the app, set up the data structure for expense records:

  • Use Dataverse: Use a Dataverse table to store the data. In Dataverse, you would create a custom table (e.g., Expense Claim) with similar columns. Ensure you enable attachments if you want to allow receipt uploads. Using Dataverse can leverage its security roles and relationships, but for a beginner-friendly approach, SharePoint is perfectly fine.

Tables:

  • Expense Claims — parent record with Name, Description, Employee (lookup to Users), Submission Date, Status Reason (Draft, Submitted, Approved, Rejected), and Total Amount.
  • Expense Claim Items — child records with Category (choice), Amount, and Description.

Rollup for totals

I created a rollup column, Total Amount, on the parent claim. It sums the Amount values of related Expense Claim Items. This guarantees that finance can trust the total without recalculating in reports.

Limitation: Rollups refresh on schedule. If you need instant updates after each item save, write a plugin to calculate and update the parent Total Amount immediately. That way, the employee sees the correct total on screen in real time.

Microsoft doc on rollup columns: Define rollup fields

Step 2 Business workflow for Submission Date

I wrote a classic workflow called Update Submitted Time.

  • Trigger: when a claim Status Reason changes to Submitted.
  • Action: update Submission Date to Modified On.

This guarantees we always capture the exact time the employee pressed submit.

Step 3: Security and access control

  • Employee field auto set — when a new record is created, the Employee field defaults to the logged-in user (LookUp(Users,'Primary Email'=User().Email)).
  • User security — each employee can see only their own records. You can do this with Dataverse security roles, giving read/write access only to records they own.
  • Make the Employee column read‑only in the app to prevent changes after creation.
  • Practical rule — employees cannot edit claims once approved. New claims open in Draft only.

Microsoft doc on security roles: Security model in Dataverse

Step 4: Building the Canvas app

Now we’ll create the canvas app and connect it to the data source:

  1. Open Power Apps Studio: Go to Power Apps Maker Portal and sign in. Ensure you’re in the correct environment (if applicable). On the Home screen, click Create > Blank app > Blank canvas app. Choose the format — for an expense app used on mobile, Phone layout is ideal.
  2. Name the App: When prompted, give your app a name, e.g., “Expense Claims App”, and click Create. This opens Power Apps Studio with a new blank canvas.
  3. Add Data Connection: In the left pane, select Data (database icon), click + Add data, and choose Dataverse, choose your table from Dataverse ) After connecting, the list becomes available as a data source in the app.
  4. Set Up Screens: By default, a new canvas app starts with a single screen (Screen1). Rename this screen (e.g., HomeScreen or SubmitScreen) for clarity.

Use the top ribbon Insert menu to add new screens as needed (Blank screen type). Rename the screen accordingly. Now we have the structure to begin designing the UI on each screen.

At this point, remember to save your app (File > Save) with a meaningful name. It’s good practice to save periodically as you build.

  1. App OnStart
Set(varLocale, "en-GB");

The locale variable is used for consistent date formatting.

  1. Welcome banner — a label saying "Welcome, " & User().FullName. Makes it personal. Color ColorFade(Color.Blue, 0.25)
  2. Claims gallery — shows all claims of the logged-in employee, sorted by submission date descending.
SortByColumns
(    
Filter('Expense Claims', Employee.'Primary Email' = User().Email),    
"ssc_submissiondate",    
SortOrder.Descending 
)

Inside the gallery, add

  • Label lblClaimStatus Text ThisItem.'Status Reason'
  • Label lblClaimTotal Text Text("£" & ThisItem.'Total Amount', "##,###.00")
  • Label lblClaimSubmitted Text Text(ThisItem.'Submission Date', "dd mmm yyyy HH:mm", varLocale)
  • Rectangle rectSelected Visible ThisItem.IsSelected Width 4 at X equals 0 to show a selection bar

TemplateFill If(ThisItem.IsSelected, ColorFade(Color.DarkSeaGreen, 0.5), ColorFade(Color.LightGray, 0.5))

Claim form

Insert an edit form named frmClaim bound to Expense Claims. Item is galClaims.Selected.

  • Employee is prefilled with the logged-in user and is disabled.
  • Submission Date is read-only.
  • Status Reason defaults to Draft when new.

If(frmClaim.Mode=FormMode.New,Choices('Status Reason (Expense Claims)',"Draft"),[Parent.Default])

DisplayMode

If(frmClaim.Mode = FormMode.New, DisplayMode.Disabled, DisplayMode.Edit)

Update cmbStatusReason.Selected.Value

OnSuccess

Notify("Expense Claim saved.", NotificationType.Success);

OnFailure

Notify("Could not save claim: " & frmClaim.Error, NotificationType.Error);
  • Buttons:
  • New → NewForm(frmClaim)
  • Save → SubmitForm(frmClaim)
  • Update → Patch only if Draft

Button btnUpdateClaim DisplayMode

If(
  frmClaim.Mode = FormMode.New,
  DisplayMode.Disabled,
  If(Text(galClaims.Selected.'Status Reason') = "Draft", DisplayMode.Edit, DisplayMode.Disabled)
)

OnSelect

Patch(
  'Expense Claims',
  galClaims.Selected,
  {
    Name: txtClaimName.Text,
    Description: txtClaimDescription.Text,
    'Status Reason': cmbStatusReason.Selected.Value
  }
);

Items gallery

Insert a gallery named galItems showing the selected claim’s items. Show Category, Created On, and Amount.

Gallery name galItems Items galClaims.Selected.'Expense Claim Items' TemplateFill If(ThisItem.IsSelected, ColorFade(Color.DarkSeaGreen, 0.5), Color.White)

Inside the template, add

  • Label lblItemCategory Text ThisItem.Category
  • Label lblItemCreated Text Text(ThisItem.'Created On', "dd mmm yyyy HH:mm", varLocale)
  • Label lblItemAmount Text "£" & Text(ThisItem.Amount, "##,###")

Item form

Insert an edit form named frmItem bound to Expense Claim Items.

DataSource 'Expense Claim Items' Item galItems.Selected

OnSuccess

Notify("Item saved.", NotificationType.Success);
Refresh('Expense Claim Items');
Refresh('Expense Claims'); // refresh rollup total
  • Amount update:
Value(txtItemAmount.Text)
  • Category update:
cmbItemCategory.Selected.Value
  • DefaultSelectedItems [Parent.Default]
  • Parent claim defaults to galClaims.Selected and is hidden.

Item actions

Icon icoNewItem DisplayMode If(Text(galClaims.Selected.'Status Reason') = "Approved", DisplayMode.Disabled, DisplayMode.Edit) OnSelect NewForm(frmItem)

Icon icoSaveItem DisplayMode If(frmItem.Mode = FormMode.New, DisplayMode.Edit, DisplayMode.Disabled) OnSelect SubmitForm(frmItem)

Button btnUpdateItem DisplayMode If(frmItem.Mode = FormMode.New, DisplayMode.Disabled, DisplayMode.Edit) OnSelect

Patch(
  'Expense Claim Items',
  galItems.Selected,
  {
    Description: txtItemDescription.Text,
    Category: cmbItemCategory.Selected.Value,
    Amount: Value(Text(txtItemAmount.Text, "[$-en-US]$#,##0.00"))
  }
);
Refresh('Expense Claim Items');
Refresh('Expense Claims');

Because Amount and Category are required in Dataverse the Canvas form will mark the inputs red if they are empty. You do not need to duplicate this logic.

3. Forms with rules:

  • Employee is read-only because it should always be the current user.
  • Submission Date is read-only; updated by workflow when submitted.
  • Status Reason defaults to Draft for new forms.

4. Item gallery and form:

  • Amount and Category are required because they are required in Dataverse. The app will show red borders automatically if left blank.
  • The New Item button is enabled only if the parent claim is Draft or Submitted. If the claim is approved, items cannot be added.
  • The update button is enabled only in Draft.

Step 5: Flow for Manager Approval

Instead of emailing manually, a cloud flow handles approvals.

  • Trigger: claim row added or modified, Status Reason = Submitted.
  • Action: get Employee record → get Manager (using out of the box Manager lookup) → send Approval to manager email.
  • If Approved: update Status Reason to Approved.
  • If Rejected: update Status Reason to Rejected.

This way, the flow uses organizational hierarchy without custom fields.

Microsoft doc on approvals: Create an approval flow

Get Employee: Use the row ID from the trigger to retrieve the Employee record from the Users table.

Get Manager: Read the Manager lookup field on the Employee record to find their manager. This field exists out of the box in Dynamics 365/Dataverse.

Compose record link: Use a Compose action to build a URL to the claim (Use Environment Variable for Dataverse URL)

Start and wait for an approval: Choose “Approve/Reject — First to respond.” Set Title to include the claim and employee name. Assign to the manager’s primary email. In Details, include Employee name, submission date, total amount, and the link from the Compose step.

Condition: If the outcome is Approve, update the claim’s Status Reason to Approved. Otherwise set it to Rejected

Step 6: Practical rules applied

  • New button — enabled for creating new claims only.
  • Update button — visible only in Draft status.
  • Approved claims — locked for editing and cannot accept new items.
  • Required fields — Amount and Category are required at the Dataverse level, so the Canvas app inherits those rules automatically.

These rules match what real finance teams expect.

Step 7: Why this learning matters

By building this app, a learner sees how Canvas apps go beyond demos. You practice:

  • Using rollup columns and plugins for real totals.
  • Handling workflow automation, like submission timestamps.
  • Applying Dataverse security so employees see only their own records.
  • Creating approval flows that use the existing organizational structure.
  • Building user experience rules, like disabling edits after approval.

Microsoft learning path: Create a canvas app in Power Apps

Closing reflection

This Expense Claims app is one of the best examples to learn Canvas apps because it mirrors a real business process. You start with Dataverse tables, add business rules (required fields, submission workflow, approval flow), and finish with an app that any organization could use.

  • Employees feel safe because they only see their records.
  • Managers get clear approvals with totals and timestamps.
  • Finance gets clean data with validated amounts and categories.

Once you master this, you can expand it: attach receipt images, add multi-level approvals, or connect to finance systems.


메타데이터
post_id
1eaa75f8bc06
slug
learning-by-building-expense-claims-canvas-app-with-manager-approval-1eaa75f8bc06
url
https://medium.com/@chamara.iresh/learning-by-building-expense-claims-canvas-app-with-manager-approval-1eaa75f8bc06
canonical_url
https://medium.com/@chamara.iresh/learning-by-building-expense-claims-canvas-app-with-manager-approval-1eaa75f8bc06
author_url
https://medium.com/@chamara.iresh
status
ok
fetched_at
2026-08-28 02:47:01