microsoft/expense-entry
Processes expense receipts and creates expense report entries following company policies with approval thresholds and validation rules. Use when user says "log this expense", "process this receipt", "create expense entry", "submit expense", "add to expense report", uploads a receipt image, or provides purchase documentation to expense.
npx skills add https://github.com/microsoft/dataverse-business-skills --skill expense-entry
This skill defines the business process for creating expense report entries from receipt information. It enforces company expense policies, proper categorization, and validation rules.
This skill requires an Expense Report table to be created in your Dataverse environment. Use the schema below to create the table, or adapt the skill to work with your existing expense management table.
Create a custom table named Expense Report (logical name will be cr###_expensereport where ### is your publisher prefix) with these columns:
| Display Name | Logical Name | Type | Description |
|-------------|--------------|------|-------------|
| Report ID | cr###_reportid | Text (100) | Unique ID (e.g., ER-2025-1120-001) |
| Report Name | cr###_reportname | Text (200) | Descriptive name |
| Report Status | cr###_reportstatus | Choice | Draft, Submitted, Pending Approval, Approved, Rejected, Paid |
| Total Amount | cr###_totalamount | Currency | Pre-tax expense amount |
| Tax Amount | cr###_taxamount | Currency | Sum of tax amounts |
| Corporate Card Amount | cr###_corporatecardamount | Currency | Amount on corporate card |
| Personal Card Amount | cr###_personalcardamount | Currency | Amount requiring reimbursement |
| Approval Tier | cr###_approvaltier | Choice | None, Manager, Controller, CFO |
| Days Since Expense | cr###_dayssinceexpense | Whole Number | Days between expense and submission |
| Late Submission | cr###_latesubmission | Yes/No | True if > 90 days |
| Billable Amount | cr###_billableamount | Currency | Client-billable portion |
| Internal Amount | cr###_internalamount | Currency | Internal expense portion |
| Project Code | cr###_projectcode | Text (50) | Project code if billable |
| Expense Categories | cr###_expensecategories | Text (500) | Categories (Hotel, Meals, Travel, etc.) |
| Duplicate Status | cr###_duplicatestatus | Choice | No Duplicates, Duplicates Found, Not Checked |
| Policy Violations | cr###_policyviolations | Text (1000) | Any policy violations |
| Merchant Name | cr###_merchantname | Text (200) | Vendor/merchant name |
| Transaction Date | cr###_transactiondate | Date Only | Receipt/transaction date |
| Submission Date | cr###_submissiondate | Date Only | Date submitted |
| Employee | cr###_employee | Lookup (Contact) | Employee who submitted |
| Approved By | cr###_approvedby | Lookup (User) | Approving manager |
| Approved Date | cr###_approveddate | Date Only | Approval date |
> Note: Replace cr###_ with your actual publisher prefix (e.g., contoso_, new_, etc.)
If your organization uses Dynamics 365 Finance, this skill can be adapted to work with the msdyn_expense table from the Expense Management module.
Use this skill when:
DO NOT attempt to create expense entries without this skill - proper categorization and validation are required.
All expense data is stored in your Expense Report table (see Prerequisites for schema). The skill references these fields using placeholder notation:
[reportid]: Unique identifier (e.g., ER-2025-1120-001)[reportstatus]: Draft, Submitted, Pending Approval, Approved, Rejected, Paid[totalamount]: Total expense amount before tax[taxamount]: Sum of all tax amounts[corporatecardamount]: Amount paid with corporate card[personalcardamount]: Amount paid with personal card (requires reimbursement)[approvaltier]: None, Manager, Controller, CFO (based on amount)[dayssinceexpense]: Days between expense and submission[latesubmission]: Yes/No (if > 90 days)[billableamount]: Amount billable to clients[internalamount]: Amount for internal expenses[projectcode]: Project code if billable[expensecategories]: Categories included (e.g., "Hotel, Meals, Travel")[duplicatestatus]: No Duplicates, Duplicates Found, Not Checked[policyviolations]: Any policy violations detectedFrom the receipt, extract:
Based on merchant category and itemized details, assign the correct expense category for the expense_categories field:
approval_tier field)[corporatecardamount] and [personalcardamount])[corporatecardamount] = total amount, [personalcardamount] = 0[personalcardamount] = total amount, [corporatecardamount] = 0[billableamount], [internalamount], [projectcode])[billableamount] = total amount, [internalamount] = 0[projectcode] (search for active projects for that client)[internalamount] = total amount, [billableamount] = 0[projectcode] = empty[duplicatestatus] field)[duplicatestatus] = "Duplicates Found" and DO NOT CREATE[duplicatestatus] = "No Duplicates"[dayssinceexpense] and [latesubmission])[dayssinceexpense] = submission date - transaction date[dayssinceexpense] > 90: Set [latesubmission] = "Yes"[dayssinceexpense] <= 90: Set [latesubmission] = "No"Create record in your Expense Report table with:
Required Fields:
[reportid]: Generate unique ID (format: ER-YYYY-MMDD-XXX)[reportname]: "[Month Year] [Category] - [Employee Name]"[submissiondate]: Today's date (YYYY-MM-DD format)[employee]: Lookup to Contact record for employee[reportstatus]: "Submitted" (or "Draft" if saving for later)[totalamount]: Expense amount before tax (numeric)[taxamount]: Tax amount (numeric)Payment Method Fields:
[corporatecardamount]: Amount paid with corporate card[personalcardamount]: Amount paid with personal cardApproval Fields:
[approvaltier]: Based on amount thresholds from Step 3[approvedby]: Empty (will be filled after approval)[approveddate]: Empty (will be filled after approval)Validation Fields:
[dayssinceexpense]: Calculated in Step 3[latesubmission]: "Yes" or "No" based on 90-day policy[duplicatestatus]: Result from duplicate detection[policyviolations]: Any violations detected (empty if none)Billability Fields:
[billableamount]: Amount billable to clients[internalamount]: Amount for internal expenses[projectcode]: Project code if billableCategory Field:
[expensecategories]: Categories from Step 2 (e.g., "Hotel, Meals, Travel")task record for approverapproval_tier (Manager/Controller/CFO)note linked to ProjectSet [reportstatus] based on approval requirements:
[approvaltier] = "None": Set [reportstatus] = "Approved"[approvaltier] = "Manager", "Controller", or "CFO": Set [reportstatus] = "Pending Approval"Before finalizing expense entry:
[dayssinceexpense] accurately[latesubmission] = "Yes" if > 90 days[duplicatestatus] appropriatelyIf validation fails:
User says: "I bought office supplies for the team yesterday. Create an expense for this receipt: Office Depot, $247.50 total ($227.89 + $19.61 tax), paid Dec 2, 2025 with corporate card. Items: toner cartridge, copy paper, folders."
Actions:
Result:
Expense Report Created: ER-2025-1203-015
Status: Approved (auto-approved)
Amount: $247.50 (Corporate Card)
Category: Office Supplies
No reimbursement needed
No manager approval required
User says: "Log this dinner receipt: The Capital Grille, $425 total ($390 + $35 tax), personal card, client dinner with Contoso team on Dec 5. Attendees: John Smith, Sarah Chen, myself."
Actions:
Result:
Expense Report Created: ER-2025-1206-022
Status: Pending Approval (Manager)
Amount: $425.00 (Personal Card - Reimbursement Required)
Category: Meals
Billable to: Contoso (Project: PROJ-CONTOSO-2025)
Approval task created for: [Manager Name]
User says: "Need to expense this flight from September: Delta Airlines $650, Sept 15, corporate card, NYC to Chicago for internal training."
Actions:
Result:
Expense Report Created: ER-2025-1206-023
Status: Pending Approval (Manager)
Amount: $650.00 (Corporate Card)
Category: Travel
⚠️ Warning: 82 days since expense (90-day limit approaching)
Approval task created for: [Manager Name]
Cause: Expense with same merchant, date, and amount already exists
Solution:
Cause: Receipt information incomplete (no amount, date, or merchant)
Solution:
Cause: Expense older than 90 days
Solution:
[latesubmission] = "Yes"[policyviolations] = "Late submission: [X] days past 90-day limit"Cause: Meal expense > $75/person but no attendee list provided
Solution:
An expense entry is complete and valid when:
[expensecategories][corporatecardamount] or [personalcardamount][duplicatestatus] set[dayssinceexpense] and [latesubmission][billableamount] and [internalamount][approvaltier] requires it[reportstatus] set appropriately based on approval requirementsTake microsoft/expense-entry from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.