From 7f49edc0c80e7da9bfc097a71b0e28a590ebfd34 Mon Sep 17 00:00:00 2001 From: Troy Simeon Taylor <44444967+troystaylor@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:54:51 -0400 Subject: [PATCH 1/2] Add files via upload --- .../apiDefinition.swagger.json | 3061 +++++++++++++++++ .../Mock Data Generator/apiProperties.json | 72 + .../Mock Data Generator/readme.md | 100 + .../Mock Data Generator/script.csx | 1692 +++++++++ 4 files changed, 4925 insertions(+) create mode 100644 independent-publisher-connectors/Mock Data Generator/apiDefinition.swagger.json create mode 100644 independent-publisher-connectors/Mock Data Generator/apiProperties.json create mode 100644 independent-publisher-connectors/Mock Data Generator/readme.md create mode 100644 independent-publisher-connectors/Mock Data Generator/script.csx diff --git a/independent-publisher-connectors/Mock Data Generator/apiDefinition.swagger.json b/independent-publisher-connectors/Mock Data Generator/apiDefinition.swagger.json new file mode 100644 index 0000000000..2b44aeaec1 --- /dev/null +++ b/independent-publisher-connectors/Mock Data Generator/apiDefinition.swagger.json @@ -0,0 +1,3061 @@ +{ + "swagger": "2.0", + "info": { + "title": "Mock Data Generator", + "description": "Generates realistic mock data for Microsoft business applications including Dataverse, Business Central, Field Service, Project Operations, and Supply Chain Management.", + "version": "1.0.0", + "contact": { + "name": "Troy Taylor", + "email": "troy@troystaylor.com" + } + }, + "host": "troystaylor.com", + "basePath": "/", + "schemes": [ + "https" + ], + "consumes": [], + "produces": [], + "paths": { + "/GetDataverseAccounts": { + "get": { + "tags": [ + "Dataverse", + "Sales Process" + ], + "summary": "Create Dataverse Accounts", + "description": "Generates mock account objects with realistic business data including contact information, addresses, and financial details. These accounts form the foundation for relationship chains - use the same seedValue when calling GetDataverseContacts to create realistic company structures.", + "operationId": "GetDataverseAccounts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of account records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock account data.", + "schema": { + "type": "object", + "properties": { + "accounts": { + "type": "array", + "description": "Array of generated account entities.", + "x-ms-summary": "Accounts", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of accounts returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseContacts": { + "get": { + "tags": [ + "Dataverse", + "Sales Process" + ], + "summary": "Create Dataverse Contacts", + "description": "Generates mock contact objects with realistic personal and professional information including names, contact details, and job information. Contacts are automatically linked to a shared pool of Account IDs for consistent relationships. 💡 Workflow Tip: Call GetDataverseAccounts first, then use the same seedValue here for realistic company structures.", + "operationId": "GetDataverseContacts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of contact records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock contact data.", + "schema": { + "type": "object", + "properties": { + "contacts": { + "type": "array", + "description": "Array of generated contact entities.", + "x-ms-summary": "Contacts", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of contacts returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseLeads": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Leads", + "description": "Generates mock lead objects with realistic prospect information including qualification status, source details, and contact preferences.", + "operationId": "GetDataverseLeads", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of lead records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock lead data.", + "schema": { + "type": "object", + "properties": { + "leads": { + "type": "array", + "description": "Array of generated lead entities.", + "x-ms-summary": "Leads", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of leads returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseOpportunities": { + "get": { + "tags": [ + "Dataverse", + "Sales Process" + ], + "summary": "Create Dataverse Opportunities", + "description": "Generates mock opportunity objects with realistic sales pipeline data including estimated values, close dates, and probability assessments. Opportunities link to the same Account pool for sales process continuity. 💡 Workflow Tip: Use consistent seedValue across Accounts→Contacts→Opportunities for complete sales scenarios.", + "operationId": "GetDataverseOpportunities", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of opportunity records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock opportunity data.", + "schema": { + "type": "object", + "properties": { + "opportunities": { + "type": "array", + "description": "Array of generated opportunity entities.", + "x-ms-summary": "Opportunities", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of opportunities returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseCases": { + "get": { + "tags": [ + "Dataverse", + "Customer Service" + ], + "summary": "Create Dataverse Cases", + "description": "Generates mock case objects with realistic support ticket information including priority levels, status tracking, and resolution details. Cases link to Accounts and Contacts for service continuity. 💡 Workflow Tip: Generate Accounts and Contacts first for complete customer service scenarios.", + "operationId": "GetDataverseCases", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of case records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock case data.", + "schema": { + "type": "object", + "properties": { + "cases": { + "type": "array", + "description": "Array of generated case entities.", + "x-ms-summary": "Cases", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of cases returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseProducts": { + "get": { + "tags": [ + "Dataverse", + "Product Management" + ], + "summary": "Create Dataverse Products", + "description": "Generates mock product objects with realistic catalog information including pricing, categories, and inventory details. Products form the foundation for Quotes and Orders. 💡 Workflow Tip: Generate Products first, then use same seedValue for Quotes→Orders to create realistic product transactions.", + "operationId": "GetDataverseProducts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of product records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock product data.", + "schema": { + "type": "object", + "properties": { + "products": { + "type": "array", + "description": "Array of generated product entities.", + "x-ms-summary": "Products", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of products returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseQuotes": { + "get": { + "tags": [ + "Dataverse", + "Product Management" + ], + "summary": "Create Dataverse Quotes", + "description": "Generates mock quote objects with realistic pricing proposals including line items, discounts, and expiration dates.", + "operationId": "GetDataverseQuotes", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of quote records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock quote data.", + "schema": { + "type": "object", + "properties": { + "quotes": { + "type": "array", + "description": "Array of generated quote entities.", + "x-ms-summary": "Quotes", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of quotes returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseOrders": { + "get": { + "tags": [ + "Dataverse", + "Product Management" + ], + "summary": "Create Dataverse Orders", + "description": "Generates mock order objects with realistic sales transaction data including order items, shipping information, and payment status.", + "operationId": "GetDataverseOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of order records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock order data.", + "schema": { + "type": "object", + "properties": { + "orders": { + "type": "array", + "description": "Array of generated order entities.", + "x-ms-summary": "Orders", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseCampaigns": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Campaigns", + "description": "Generates mock campaign objects with realistic marketing initiative data including budgets, target audiences, and performance metrics.", + "operationId": "GetDataverseCampaigns", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of campaign records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock campaign data.", + "schema": { + "type": "object", + "properties": { + "campaigns": { + "type": "array", + "description": "Array of generated campaign entities.", + "x-ms-summary": "Campaigns", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of campaigns returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseCompetitors": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Competitors", + "description": "Generates mock competitor objects with realistic competitive intelligence including market position, strengths, and threat levels.", + "operationId": "GetDataverseCompetitors", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of competitor records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock competitor data.", + "schema": { + "type": "object", + "properties": { + "competitors": { + "type": "array", + "description": "Array of generated competitor entities.", + "x-ms-summary": "Competitors", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of competitors returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseInvoices": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Invoices", + "description": "Generates mock invoice objects with realistic billing information including line items, tax calculations, and payment terms.", + "operationId": "GetDataverseInvoices", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of invoice records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock invoice data.", + "schema": { + "type": "object", + "properties": { + "invoices": { + "type": "array", + "description": "Array of generated invoice entities.", + "x-ms-summary": "Invoices", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of invoices returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseActivities": { + "get": { + "tags": [ + "Dataverse", + "Customer Service" + ], + "summary": "Create Dataverse Activities", + "description": "Generates mock activity objects with realistic task and appointment data including schedules, participants, and completion status.", + "operationId": "GetDataverseActivities", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of activity records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock activity data.", + "schema": { + "type": "object", + "properties": { + "activities": { + "type": "array", + "description": "Array of generated activity entities.", + "x-ms-summary": "Activities", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of activities returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseTeams": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Teams", + "description": "Generates mock team objects with realistic organizational structure including team members, roles, and business units.", + "operationId": "GetDataverseTeams", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of team records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock team data.", + "schema": { + "type": "object", + "properties": { + "teams": { + "type": "array", + "description": "Array of generated team entities.", + "x-ms-summary": "Teams", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of teams returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseTerritories": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Territories", + "description": "Generates mock territory objects with realistic sales region data including geographic boundaries and assigned personnel.", + "operationId": "GetDataverseTerritories", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of territory records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock territory data.", + "schema": { + "type": "object", + "properties": { + "territories": { + "type": "array", + "description": "Array of generated territory entities.", + "x-ms-summary": "Territories", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of territories returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseKnowledgeArticles": { + "get": { + "tags": [ + "Dataverse", + "Customer Service" + ], + "summary": "Create Dataverse Knowledge Articles", + "description": "Generates mock knowledge article objects with realistic documentation including topics, content, and approval workflows.", + "operationId": "GetDataverseKnowledgeArticles", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of knowledge article records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock knowledge article data.", + "schema": { + "type": "object", + "properties": { + "knowledgearticles": { + "type": "array", + "description": "Array of generated knowledge article entities.", + "x-ms-summary": "Knowledge Articles", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of knowledge articles returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetDataverseContracts": { + "get": { + "tags": [ + "Dataverse" + ], + "summary": "Create Dataverse Contracts", + "description": "Generates mock contract objects with realistic agreement data including terms, durations, and renewal information.", + "operationId": "GetDataverseContracts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of contract records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock contract data.", + "schema": { + "type": "object", + "properties": { + "contracts": { + "type": "array", + "description": "Array of generated contract entities.", + "x-ms-summary": "Contracts", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of contracts returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralCustomers": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Customers", + "description": "Generates mock customer objects with realistic business information for ERP scenarios including payment terms and credit limits.", + "operationId": "GetBusinessCentralCustomers", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of customer records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock customer data.", + "schema": { + "type": "object", + "properties": { + "customers": { + "type": "array", + "description": "Array of generated customer entities.", + "x-ms-summary": "Customers", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of customers returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralVendors": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Vendors", + "description": "Generates mock vendor objects with realistic supplier information including terms, contact details, and procurement data.", + "operationId": "GetBusinessCentralVendors", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of vendor records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock vendor data.", + "schema": { + "type": "object", + "properties": { + "vendors": { + "type": "array", + "description": "Array of generated vendor entities.", + "x-ms-summary": "Vendors", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of vendors returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralItems": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Items", + "description": "Generates mock item objects with realistic inventory information including pricing, categories, and stock levels.", + "operationId": "GetBusinessCentralItems", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of item records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock item data.", + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "description": "Array of generated item entities.", + "x-ms-summary": "Items", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of items returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralGLAccounts": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central GL Accounts", + "description": "Generates mock general ledger account objects with realistic chart of accounts structure including account types and balances.", + "operationId": "GetBusinessCentralGLAccounts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of GL account records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock GL account data.", + "schema": { + "type": "object", + "properties": { + "glAccounts": { + "type": "array", + "description": "Array of generated GL account entities.", + "x-ms-summary": "GL Accounts", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of GL accounts returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralSalesOrders": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Sales Orders", + "description": "Generates mock sales order objects with realistic transaction data including line items, pricing, and delivery information.", + "operationId": "GetBusinessCentralSalesOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of sales order records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock sales order data.", + "schema": { + "type": "object", + "properties": { + "salesOrders": { + "type": "array", + "description": "Array of generated sales order entities.", + "x-ms-summary": "Sales Orders", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of sales orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralPurchaseOrders": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Purchase Orders", + "description": "Generates mock purchase order objects with realistic procurement data including vendor information, line items, and delivery dates.", + "operationId": "GetBusinessCentralPurchaseOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of purchase order records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock purchase order data.", + "schema": { + "type": "object", + "properties": { + "purchaseOrders": { + "type": "array", + "description": "Array of generated purchase order entities.", + "x-ms-summary": "Purchase Orders", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of purchase orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralSalesInvoices": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Sales Invoices", + "description": "Generates mock sales invoice objects with realistic billing information including tax calculations, payment terms, and line details.", + "operationId": "GetBusinessCentralSalesInvoices", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of sales invoice records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock sales invoice data.", + "schema": { + "type": "object", + "properties": { + "salesInvoices": { + "type": "array", + "description": "Array of generated sales invoice entities.", + "x-ms-summary": "Sales Invoices", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of sales invoices returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralPurchaseInvoices": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Purchase Invoices", + "description": "Generates mock purchase invoice objects with realistic vendor billing including payment processing, line items, and approval workflows.", + "operationId": "GetBusinessCentralPurchaseInvoices", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of purchase invoice records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock purchase invoice data.", + "schema": { + "type": "object", + "properties": { + "purchaseInvoices": { + "type": "array", + "description": "Array of generated purchase invoice entities.", + "x-ms-summary": "Purchase Invoices", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of purchase invoices returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralEmployees": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Employees", + "description": "Generates mock employee objects with realistic workforce information including job titles, departments, and employment details.", + "operationId": "GetBusinessCentralEmployees", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of employee records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock employee data.", + "schema": { + "type": "object", + "properties": { + "employees": { + "type": "array", + "description": "Array of generated employee entities.", + "x-ms-summary": "Employees", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of employees returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralLocations": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Locations", + "description": "Generates mock location objects with realistic warehouse and facility information including addresses and operational details.", + "operationId": "GetBusinessCentralLocations", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of location records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock location data.", + "schema": { + "type": "object", + "properties": { + "locations": { + "type": "array", + "description": "Array of generated location entities.", + "x-ms-summary": "Locations", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of locations returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralJobs": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Jobs", + "description": "Generates mock job objects with realistic project management information including timelines, budgets, and resource allocation.", + "operationId": "GetBusinessCentralJobs", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of job records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock job data.", + "schema": { + "type": "object", + "properties": { + "jobs": { + "type": "array", + "description": "Array of generated job entities.", + "x-ms-summary": "Jobs", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of jobs returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetBusinessCentralDimensions": { + "get": { + "tags": [ + "Business Central" + ], + "summary": "Create Business Central Dimensions", + "description": "Generates mock dimension objects with realistic business intelligence structure including dimension values and hierarchies.", + "operationId": "GetBusinessCentralDimensions", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of dimension records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock dimension data.", + "schema": { + "type": "object", + "properties": { + "dimensions": { + "type": "array", + "description": "Array of generated dimension entities.", + "x-ms-summary": "Dimensions", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of dimensions returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceWorkOrders": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Work Orders", + "description": "Generates mock work order objects with realistic service management data including scheduling, technicians, and service details.", + "operationId": "GetFieldServiceWorkOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of work order records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock work order data.", + "schema": { + "type": "object", + "properties": { + "workOrders": { + "type": "array", + "description": "Array of generated work order entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of work orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceBookableResources": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Bookable Resources", + "description": "Generates mock bookable resource objects with realistic technician and equipment information for scheduling and resource management.", + "operationId": "GetFieldServiceBookableResources", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of bookable resource records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock bookable resource data.", + "schema": { + "type": "object", + "properties": { + "bookableResources": { + "type": "array", + "description": "Array of generated bookable resource entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of bookable resources returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceBookings": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Bookings", + "description": "Generates mock booking objects with realistic appointment scheduling data including time slots, resources, and work orders.", + "operationId": "GetFieldServiceBookings", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of booking records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock booking data.", + "schema": { + "type": "object", + "properties": { + "bookings": { + "type": "array", + "description": "Array of generated booking entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of bookings returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceCustomerAssets": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Customer Assets", + "description": "Generates mock customer asset objects with realistic equipment and device information for maintenance and service tracking.", + "operationId": "GetFieldServiceCustomerAssets", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of customer asset records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock customer asset data.", + "schema": { + "type": "object", + "properties": { + "customerAssets": { + "type": "array", + "description": "Array of generated customer asset entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of customer assets returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceServiceTaskTypes": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Service Task Types", + "description": "Generates mock service task type objects with realistic service procedure templates and standardized task definitions.", + "operationId": "GetFieldServiceServiceTaskTypes", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of service task type records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock service task type data.", + "schema": { + "type": "object", + "properties": { + "serviceTaskTypes": { + "type": "array", + "description": "Array of generated service task type entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of service task types returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceInventoryTransfers": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Inventory Transfers", + "description": "Generates mock inventory transfer objects with realistic parts movement data between warehouses and field technicians.", + "operationId": "GetFieldServiceInventoryTransfers", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of inventory transfer records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock inventory transfer data.", + "schema": { + "type": "object", + "properties": { + "inventoryTransfers": { + "type": "array", + "description": "Array of generated inventory transfer entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of inventory transfers returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceResourceTerritories": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Resource Territories", + "description": "Generates mock resource territory objects with realistic geographic coverage areas and technician assignments.", + "operationId": "GetFieldServiceResourceTerritories", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of resource territory records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock resource territory data.", + "schema": { + "type": "object", + "properties": { + "resourceTerritories": { + "type": "array", + "description": "Array of generated resource territory entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of resource territories returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServicePurchaseOrderProducts": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Purchase Order Products", + "description": "Generates mock purchase order product objects with realistic parts procurement data for field service operations.", + "operationId": "GetFieldServicePurchaseOrderProducts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of purchase order product records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock purchase order product data.", + "schema": { + "type": "object", + "properties": { + "purchaseOrderProducts": { + "type": "array", + "description": "Array of generated purchase order product entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of purchase order products returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceRMAs": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service RMAs", + "description": "Generates mock return merchandise authorization objects with realistic product return and warranty processing information.", + "operationId": "GetFieldServiceRMAs", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of RMA records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock RMA data.", + "schema": { + "type": "object", + "properties": { + "rmas": { + "type": "array", + "description": "Array of generated RMA entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of RMAs returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetFieldServiceTimeOffRequests": { + "get": { + "tags": [ + "Field Service" + ], + "summary": "Create Field Service Time Off Requests", + "description": "Generates mock time off request objects with realistic technician availability and scheduling information.", + "operationId": "GetFieldServiceTimeOffRequests", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of time off request records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock time off request data.", + "schema": { + "type": "object", + "properties": { + "timeOffRequests": { + "type": "array", + "description": "Array of generated time off request entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of time off requests returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsProjects": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Projects", + "description": "Generates mock project objects with realistic project management data including timelines, budgets, and resource requirements.", + "operationId": "GetProjectOperationsProjects", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of project records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock project data.", + "schema": { + "type": "object", + "properties": { + "projects": { + "type": "array", + "description": "Array of generated project entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of projects returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsProjectTasks": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Project Tasks", + "description": "Generates mock project task objects with realistic work breakdown structure and task dependency information.", + "operationId": "GetProjectOperationsProjectTasks", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of project task records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock project task data.", + "schema": { + "type": "object", + "properties": { + "projectTasks": { + "type": "array", + "description": "Array of generated project task entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of project tasks returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsTimeEntries": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Time Entries", + "description": "Generates mock time entry objects with realistic timesheet data for project resource tracking and billing.", + "operationId": "GetProjectOperationsTimeEntries", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of time entry records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock time entry data.", + "schema": { + "type": "object", + "properties": { + "timeEntries": { + "type": "array", + "description": "Array of generated time entry entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of time entries returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsExpenseEntries": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Expense Entries", + "description": "Generates mock expense entry objects with realistic project cost tracking and reimbursement information.", + "operationId": "GetProjectOperationsExpenseEntries", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of expense entry records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock expense entry data.", + "schema": { + "type": "object", + "properties": { + "expenseEntries": { + "type": "array", + "description": "Array of generated expense entry entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of expense entries returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsResourceAssignments": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Resource Assignments", + "description": "Generates mock resource assignment objects with realistic project staffing and allocation information.", + "operationId": "GetProjectOperationsResourceAssignments", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of resource assignment records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock resource assignment data.", + "schema": { + "type": "object", + "properties": { + "resourceAssignments": { + "type": "array", + "description": "Array of generated resource assignment entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of resource assignments returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsProjectContracts": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Project Contracts", + "description": "Generates mock project contract objects with realistic contractual terms and billing arrangements.", + "operationId": "GetProjectOperationsProjectContracts", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of project contract records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock project contract data.", + "schema": { + "type": "object", + "properties": { + "projectContracts": { + "type": "array", + "description": "Array of generated project contract entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of project contracts returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsProjectInvoices": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Project Invoices", + "description": "Generates mock project invoice objects with realistic billing data and invoice line items for project billing.", + "operationId": "GetProjectOperationsProjectInvoices", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of project invoice records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock project invoice data.", + "schema": { + "type": "object", + "properties": { + "projectInvoices": { + "type": "array", + "description": "Array of generated project invoice entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of project invoices returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsResourceRequirements": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Resource Requirements", + "description": "Generates mock resource requirement objects with realistic skill requirements and resource planning information.", + "operationId": "GetProjectOperationsResourceRequirements", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of resource requirement records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock resource requirement data.", + "schema": { + "type": "object", + "properties": { + "resourceRequirements": { + "type": "array", + "description": "Array of generated resource requirement entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of resource requirements returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsProjectTeams": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Project Teams", + "description": "Generates mock project team objects with realistic team composition and role assignment information.", + "operationId": "GetProjectOperationsProjectTeams", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of project team records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock project team data.", + "schema": { + "type": "object", + "properties": { + "projectTeams": { + "type": "array", + "description": "Array of generated project team entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of project teams returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetProjectOperationsProjectEstimates": { + "get": { + "tags": [ + "Project Operations" + ], + "summary": "Create Project Operations Project Estimates", + "description": "Generates mock project estimate objects with realistic cost projections and effort estimation data.", + "operationId": "GetProjectOperationsProjectEstimates", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of project estimate records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock project estimate data.", + "schema": { + "type": "object", + "properties": { + "projectEstimates": { + "type": "array", + "description": "Array of generated project estimate entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of project estimates returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainWarehouses": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Warehouses", + "description": "Generates mock warehouse objects with realistic storage facility data including locations, capacities, and inventory zones.", + "operationId": "GetSupplyChainWarehouses", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of warehouse records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock warehouse data.", + "schema": { + "type": "object", + "properties": { + "warehouses": { + "type": "array", + "description": "Array of generated warehouse entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of warehouses returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainInventoryItems": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Inventory Items", + "description": "Generates mock inventory item objects with realistic product catalog data including SKUs, quantities, and valuation.", + "operationId": "GetSupplyChainInventoryItems", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of inventory item records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock inventory item data.", + "schema": { + "type": "object", + "properties": { + "inventoryItems": { + "type": "array", + "description": "Array of generated inventory item entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of inventory items returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainPurchaseRequisitions": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Purchase Requisitions", + "description": "Generates mock purchase requisition objects with realistic procurement request data including approvals and specifications.", + "operationId": "GetSupplyChainPurchaseRequisitions", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of purchase requisition records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock purchase requisition data.", + "schema": { + "type": "object", + "properties": { + "purchaseRequisitions": { + "type": "array", + "description": "Array of generated purchase requisition entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of purchase requisitions returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainProductionOrders": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Production Orders", + "description": "Generates mock production order objects with realistic manufacturing workflow data including scheduling and resource allocation.", + "operationId": "GetSupplyChainProductionOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of production order records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock production order data.", + "schema": { + "type": "object", + "properties": { + "productionOrders": { + "type": "array", + "description": "Array of generated production order entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of production orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainBillsOfMaterials": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Bills Of Materials", + "description": "Generates mock bill of materials objects with realistic product composition and manufacturing recipe information.", + "operationId": "GetSupplyChainBillsOfMaterials", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of bill of materials records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock bill of materials data.", + "schema": { + "type": "object", + "properties": { + "billsOfMaterials": { + "type": "array", + "description": "Array of generated bill of materials entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of bills of materials returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainInventoryTransactions": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Inventory Transactions", + "description": "Generates mock inventory transaction objects with realistic stock movement data including receipts, issues, and adjustments.", + "operationId": "GetSupplyChainInventoryTransactions", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of inventory transaction records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock inventory transaction data.", + "schema": { + "type": "object", + "properties": { + "inventoryTransactions": { + "type": "array", + "description": "Array of generated inventory transaction entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of inventory transactions returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainQualityOrders": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Quality Orders", + "description": "Generates mock quality order objects with realistic quality control testing and inspection data.", + "operationId": "GetSupplyChainQualityOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of quality order records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock quality order data.", + "schema": { + "type": "object", + "properties": { + "qualityOrders": { + "type": "array", + "description": "Array of generated quality order entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of quality orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainPlannedOrders": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Planned Orders", + "description": "Generates mock planned order objects with realistic demand planning and procurement scheduling information.", + "operationId": "GetSupplyChainPlannedOrders", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of planned order records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock planned order data.", + "schema": { + "type": "object", + "properties": { + "plannedOrders": { + "type": "array", + "description": "Array of generated planned order entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of planned orders returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainVendors": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Vendors", + "description": "Generates mock vendor objects with realistic supplier information including contact details, terms, and performance metrics.", + "operationId": "GetSupplyChainVendors", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of vendor records to generate (between 1 and 100)." + }, + { + "name": "seedValue", + "in": "query", + "required": false, + "type": "integer", + "default": 12345, + "minimum": 1, + "maximum": 999999, + "x-ms-summary": "Data Consistency Key", + "description": "Use the same number (e.g., 12345) across multiple API calls to generate related records that reference each other. Different numbers create different relationship patterns. Recommended ranges: 1-9999 (small datasets), 10000-99999 (medium), 100000-999999 (large)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock vendor data.", + "schema": { + "type": "object", + "properties": { + "vendors": { + "type": "array", + "description": "Array of generated vendor entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of vendors returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetSupplyChainInventoryJournals": { + "get": { + "tags": [ + "Supply Chain" + ], + "summary": "Create Supply Chain Inventory Journals", + "description": "Generates mock inventory journal objects with realistic stock adjustment and audit trail information.", + "operationId": "GetSupplyChainInventoryJournals", + "parameters": [ + { + "name": "count", + "in": "query", + "required": false, + "type": "integer", + "default": 10, + "minimum": 1, + "maximum": 100, + "x-ms-summary": "Record Count", + "description": "Number of inventory journal records to generate (between 1 and 100)." + } + ], + "responses": { + "200": { + "description": "Successfully generated mock inventory journal data.", + "schema": { + "type": "object", + "properties": { + "inventoryJournals": { + "type": "array", + "description": "Array of generated inventory journal entities.", + "items": { + "type": "object" + } + }, + "count": { + "type": "integer", + "description": "Total number of inventory journals returned.", + "x-ms-summary": "Total Count" + } + } + } + } + } + } + }, + "/GetMockDataStatistics": { + "get": { + "tags": [ + "Utilities" + ], + "summary": "Create Mock Data Statistics", + "description": "Generates comprehensive statistics about all available mock data endpoints including operation counts and data type summaries.", + "operationId": "GetMockDataStatistics", + "parameters": [], + "responses": { + "200": { + "description": "Successfully generated mock data statistics.", + "schema": { + "type": "object", + "properties": { + "statistics": { + "type": "object", + "description": "Comprehensive statistics about available mock data operations.", + "x-ms-summary": "Statistics" + } + } + } + } + } + } + } + }, + "definitions": {}, + "parameters": {}, + "responses": {}, + "securityDefinitions": {}, + "security": [], + "tags": [ + { + "name": "Dataverse", + "description": "Microsoft Dataverse entities for customer relationship management and business applications." + }, + { + "name": "Business Central", + "description": "Microsoft Dynamics 365 Business Central entities for enterprise resource planning." + }, + { + "name": "Field Service", + "description": "Microsoft Dynamics 365 Field Service entities for field operations management." + }, + { + "name": "Project Operations", + "description": "Microsoft Dynamics 365 Project Operations entities for project management." + }, + { + "name": "Supply Chain", + "description": "Microsoft Dynamics 365 Supply Chain Management entities for supply chain operations." + } + ], + "x-ms-connector-metadata": [ + { + "propertyName": "Website", + "propertyValue": "https://www.troystaylor.com" + }, + { + "propertyName": "Privacy policy", + "propertyValue": "https://www.troystaylor.com" + }, + { + "propertyName": "Categories", + "propertyValue": "Data;Productivity" + } + ] +} + diff --git a/independent-publisher-connectors/Mock Data Generator/apiProperties.json b/independent-publisher-connectors/Mock Data Generator/apiProperties.json new file mode 100644 index 0000000000..bfe3cbbca5 --- /dev/null +++ b/independent-publisher-connectors/Mock Data Generator/apiProperties.json @@ -0,0 +1,72 @@ +{ + "properties": { + "capabilities": [ + "actions" + ], + "connectionParameters": {}, + "iconBrandColor": "#28a745", + "scriptOperations": [ + "GetDataverseAccounts", + "GetDataverseContacts", + "GetDataverseLeads", + "GetDataverseOpportunities", + "GetDataverseCases", + "GetDataverseProducts", + "GetDataverseQuotes", + "GetDataverseOrders", + "GetDataverseCampaigns", + "GetDataverseCompetitors", + "GetDataverseInvoices", + "GetDataverseActivities", + "GetDataverseTeams", + "GetDataverseTerritories", + "GetDataverseKnowledgeArticles", + "GetDataverseContracts", + "GetBusinessCentralCustomers", + "GetBusinessCentralVendors", + "GetBusinessCentralItems", + "GetBusinessCentralGLAccounts", + "GetBusinessCentralSalesOrders", + "GetBusinessCentralPurchaseOrders", + "GetBusinessCentralSalesInvoices", + "GetBusinessCentralPurchaseInvoices", + "GetBusinessCentralEmployees", + "GetBusinessCentralLocations", + "GetBusinessCentralJobs", + "GetBusinessCentralDimensions", + "GetFieldServiceWorkOrders", + "GetFieldServiceBookableResources", + "GetFieldServiceBookings", + "GetFieldServiceCustomerAssets", + "GetFieldServiceServiceTaskTypes", + "GetFieldServiceInventoryTransfers", + "GetFieldServiceResourceTerritories", + "GetFieldServicePurchaseOrderProducts", + "GetFieldServiceRMAs", + "GetFieldServiceTimeOffRequests", + "GetProjectOperationsProjects", + "GetProjectOperationsProjectTasks", + "GetProjectOperationsTimeEntries", + "GetProjectOperationsExpenseEntries", + "GetProjectOperationsResourceAssignments", + "GetProjectOperationsProjectContracts", + "GetProjectOperationsProjectInvoices", + "GetProjectOperationsResourceRequirements", + "GetProjectOperationsProjectTeams", + "GetProjectOperationsProjectEstimates", + "GetSupplyChainWarehouses", + "GetSupplyChainInventoryItems", + "GetSupplyChainPurchaseRequisitions", + "GetSupplyChainProductionOrders", + "GetSupplyChainBillsOfMaterials", + "GetSupplyChainInventoryTransactions", + "GetSupplyChainQualityOrders", + "GetSupplyChainPlannedOrders", + "GetSupplyChainVendors", + "GetSupplyChainInventoryJournals" + ], + "policyTemplateInstances": [], + "publisher": "Mock Data Solutions", + "stackOwner": "Development Tools" + } +} \ No newline at end of file diff --git a/independent-publisher-connectors/Mock Data Generator/readme.md b/independent-publisher-connectors/Mock Data Generator/readme.md new file mode 100644 index 0000000000..ade73fd68e --- /dev/null +++ b/independent-publisher-connectors/Mock Data Generator/readme.md @@ -0,0 +1,100 @@ +# Mock Data Generator + +Generates realistic mock data for Microsoft business applications including Dataverse, Business Central, Field Service, Project Operations, and Supply Chain Management. + +## Publisher: Troy Taylor + +## Prerequisites +You will need a Microsoft Power Platform plan with custom connector feature. + +## Obtaining Credentials +No external API keys or authentication required. This connector is code-only and does not access an external API. + +## Supported Operations + +### Create Dataverse Accounts +Generate realistic account entities with complete business information including contact details, address information, industry classification, and financial data. Forms the foundation for relationship chains with other entities. + +### Create Dataverse Contacts +Generate realistic contact entities with personal information, business details, communication preferences, and automatic linking to shared Account IDs for consistent relationships. + +### Create Dataverse Leads +Generate realistic lead entities with qualification data, source information, and sales pipeline details for comprehensive prospecting scenarios. + +### Create Dataverse Opportunities +Generate realistic opportunity entities with sales process stages, financial projections, customer relationship data, and automatic Account/Contact associations. + +### Create Dataverse Cases +Generate realistic case entities with customer service tickets, support requests, priority classification, resolution tracking, and linked customer relationships. + +### Create Dataverse Products +Generate realistic product entities with inventory information, pricing data, vendor details, product specifications, and shared product pool for consistent ordering. + +### Create Dataverse Quotes +Generate realistic quote entities with formal pricing proposals, delivery terms, business conditions, and linked Account/Product relationships. + +### Create Dataverse Orders +Generate realistic order entities with sales transactions, fulfillment data, billing/shipping information, and comprehensive relationship dependencies. + +### Create Dataverse Campaigns +Generate realistic campaign entities with marketing budget tracking, response metrics, channel information, and ROI analysis for marketing automation. + +### Create Dataverse Competitors +Generate realistic competitor entities with competitive intelligence, SWOT analysis, financial data, and market positioning for sales enablement. + +### Create Dataverse Invoices +Generate realistic invoice entities with billing records, payment terms, delivery tracking, and financial reconciliation with order relationships. + +### Create Dataverse Activities +Generate realistic activity entities with business communications critical for CRM workflow testing including tasks, appointments, and emails with proper entity associations. + +### Create Dataverse Teams +Generate realistic team entities with sales teams and organizational structure for comprehensive team management testing scenarios. + +### Create Dataverse Territories +Generate realistic territory entities with sales territories and geographic assignments for territory management and resource allocation. + +### Create Dataverse Knowledge Articles +Generate realistic knowledge article entities with content management for customer service and self-service portal testing. + +### Create Dataverse Contracts +Generate realistic contract entities with service contracts and agreements for comprehensive contract lifecycle management testing. + +### Create Business Central Customers +Generate realistic customer entities with complete information including billing/shipping addresses, payment terms, and credit management. + +### Create Business Central Vendors +Generate realistic vendor entities with supplier information, purchase terms, banking details, and procurement data. + +### Create Business Central Items +Generate realistic item entities with inventory management, pricing, units of measure, and product categorization. + +### Create Business Central GL Accounts +Generate realistic General Ledger account entities with chart of accounts structure, account types, and financial categorization. + +### Create Business Central Sales Orders +Generate realistic sales order entities with complete order management including customer details, line items, pricing, and delivery information. + +### Create Business Central Purchase Orders +Generate realistic purchase order entities with procurement workflow including vendor details, requisitions, approvals, and receiving. + +### Create Business Central Sales Invoices +Generate realistic sales invoice entities with billing processes including customer invoicing, payment terms, and revenue recognition. + +### Create Business Central Purchase Invoices +Generate realistic purchase invoice entities with accounts payable including vendor invoicing, approval workflows, and payment processing. + +### Create Business Central Employees +Generate realistic employee entities with HR management including personal information, employment details, and organizational structure. + +### Create Business Central Locations +Generate realistic location entities with warehouse management including inventory locations, shipping points, and logistics coordination. + +### Create Business Central Jobs +Generate realistic job entities with project management including job costing, resource allocation, and project tracking. + +### Create Business Central Dimensions +Generate realistic dimension entities with financial analysis including cost centers, departments, and analytical reporting structures. + +## Known Issues and Limitations +There are no known issues at this time. \ No newline at end of file diff --git a/independent-publisher-connectors/Mock Data Generator/script.csx b/independent-publisher-connectors/Mock Data Generator/script.csx new file mode 100644 index 0000000000..11e612ffdb --- /dev/null +++ b/independent-publisher-connectors/Mock Data Generator/script.csx @@ -0,0 +1,1692 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json; +using System.Text; +using System.Linq; +using System.Globalization; + +public class Script : ScriptBase +{ + // Random instance for data generation + private static readonly Random _random = new Random(); + + // Shared ID pools for relationships (initialized per request with seed) + private static Guid[] _sharedAccountIds; + private static Guid[] _sharedContactIds; + private static Guid[] _sharedProductIds; + private static string[] _sharedAccountNames; + private static string[] _sharedContactNames; + private static string[] _sharedProductNames; + + // ================================================================================================ + // MAIN EXECUTION METHOD + // ================================================================================================ + + public override async Task ExecuteAsync() + { + try + { + var operationId = DecodeOperationId(this.Context.OperationId); + var query = ParseQueryString(this.Context.Request.RequestUri.Query); + var count = GetIntParameter(query, "count", 10, 1, 1000); + var seedValue = GetIntParameter(query, "seedValue", 12345, 1, 999999); + + // Initialize random with seed for consistent relationships + var seededRandom = new Random(seedValue); + + // Generate shared ID pools for relationships (smart defaults based on count) + var accountPoolSize = Math.Max(5, Math.Min(count / 3, 50)); // 3-1 ratio, max 50 accounts + var contactPoolSize = Math.Max(10, Math.Min(count / 2, 100)); // 2-1 ratio, max 100 contacts + var productPoolSize = Math.Max(8, Math.Min(count / 4, 75)); // 4-1 ratio, max 75 products + + InitializeSharedIdPools(seededRandom, accountPoolSize, contactPoolSize, productPoolSize); + + object data; + string entityName; + + switch (operationId.ToLower()) + { + // Dataverse entities + case "getdataverseaccounts": + data = GenerateDataverseAccounts(count, seededRandom); + entityName = "accounts"; + break; + case "getdataversecontacts": + data = GenerateDataverseContacts(count, seededRandom); + entityName = "contacts"; + break; + case "getdataverseleads": + data = GenerateDataverseLeads(count, seededRandom); + entityName = "leads"; + break; + case "getdataverseopportunities": + data = GenerateDataverseOpportunities(count, seededRandom); + entityName = "opportunities"; + break; + case "getdataversecases": + data = GenerateDataverseCases(count, seededRandom); + entityName = "cases"; + break; + case "getdataverseproducts": + data = GenerateDataverseProducts(count, seededRandom); + entityName = "products"; + break; + case "getdataversequotes": + data = GenerateDataverseQuotes(count, seededRandom); + entityName = "quotes"; + break; + case "getdataverseorders": + data = GenerateDataverseOrders(count, seededRandom); + entityName = "orders"; + break; + case "getdataversecampaigns": + data = GenerateDataverseCampaigns(count, seededRandom); + entityName = "campaigns"; + break; + case "getdataversecompetitors": + data = GenerateDataverseCompetitors(count, seededRandom); + entityName = "competitors"; + break; + case "getdataverseinvoices": + data = GenerateDataverseInvoices(count, seededRandom); + entityName = "invoices"; + break; + case "getdataverseactivities": + data = GenerateDataverseActivities(count, seededRandom); + entityName = "activities"; + break; + case "getdataverseteams": + data = GenerateDataverseTeams(count, seededRandom); + entityName = "teams"; + break; + case "getdataverseterritories": + data = GenerateDataverseTerritories(count, seededRandom); + entityName = "territories"; + break; + case "getdataverseknowledgearticles": + data = GenerateDataverseKnowledgeArticles(count, seededRandom); + entityName = "knowledgearticles"; + break; + case "getdataversecontracts": + data = GenerateDataverseContracts(count, seededRandom); + entityName = "contracts"; + break; + + // Business Central entities + case "getbccustomers": + data = GenerateBusinessCentralCustomers(count, seededRandom); + entityName = "customers"; + break; + case "getbcvendors": + data = GenerateBusinessCentralVendors(count, seededRandom); + entityName = "vendors"; + break; + case "getbcitems": + data = GenerateBusinessCentralItems(count, seededRandom); + entityName = "items"; + break; + case "getbcsalesorders": + data = GenerateBusinessCentralSalesOrders(count, seededRandom); + entityName = "salesOrders"; + break; + case "getbcpurchaseorders": + data = GenerateBusinessCentralPurchaseOrders(count, seededRandom); + entityName = "purchaseOrders"; + break; + + // Supply Chain entities + case "getscwarehouses": + data = GenerateSupplyChainWarehouses(count, seededRandom); + entityName = "warehouses"; + break; + case "getscinventoryitems": + data = GenerateSupplyChainInventoryItems(count, seededRandom); + entityName = "inventoryItems"; + break; + case "getscpurchaserequisitions": + data = GenerateSupplyChainPurchaseRequisitions(count, seededRandom); + entityName = "purchaseRequisitions"; + break; + case "getscproductionorders": + data = GenerateSupplyChainProductionOrders(count, seededRandom); + entityName = "productionOrders"; + break; + case "getscbillofmaterials": + data = GenerateSupplyChainBillOfMaterials(count, seededRandom); + entityName = "billOfMaterials"; + break; + case "getscinventorytransactions": + data = GenerateSupplyChainInventoryTransactions(count, seededRandom); + entityName = "inventoryTransactions"; + break; + + // Field Service entities + case "getfsworkorders": + data = GenerateFieldServiceWorkOrders(count, seededRandom); + entityName = "workOrders"; + break; + case "getfsresources": + data = GenerateFieldServiceResources(count, seededRandom); + entityName = "resources"; + break; + case "getfsequipment": + data = GenerateFieldServiceEquipment(count, seededRandom); + entityName = "equipment"; + break; + case "getfsserviceaccounts": + data = GenerateFieldServiceServiceAccounts(count, seededRandom); + entityName = "serviceAccounts"; + break; + case "getfsproducts": + data = GenerateFieldServiceProducts(count, seededRandom); + entityName = "products"; + break; + + default: + return CreateErrorResponse("Unknown operation: " + operationId); + } + + var result = new { value = data }; + return CreateJsonResponse(result); + } + catch (Exception ex) + { + return CreateErrorResponse($"Error executing operation: {ex.Message}"); + } + } + + // ================================================================================================ + // DATA ARRAYS + // ================================================================================================ + + // Names and Demographics + private static readonly string[] FirstNames = { + "James", "Mary", "Robert", "Patricia", "John", "Jennifer", "Michael", "Linda", "David", "Elizabeth", + "William", "Barbara", "Richard", "Susan", "Joseph", "Jessica", "Thomas", "Sarah", "Christopher", "Karen", + "Charles", "Lisa", "Daniel", "Nancy", "Matthew", "Betty", "Anthony", "Helen", "Mark", "Sandra", + "Donald", "Donna", "Steven", "Carol", "Paul", "Ruth", "Andrew", "Sharon", "Joshua", "Michelle", + "Kenneth", "Laura", "Kevin", "Sarah", "Brian", "Kimberly", "George", "Deborah", "Timothy", "Dorothy" + }; + + private static readonly string[] LastNames = { + "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Rodriguez", "Martinez", + "Hernandez", "Lopez", "Gonzalez", "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin", + "Lee", "Perez", "Thompson", "White", "Harris", "Sanchez", "Clark", "Ramirez", "Lewis", "Robinson", + "Walker", "Young", "Allen", "King", "Wright", "Scott", "Torres", "Nguyen", "Hill", "Flores", + "Green", "Adams", "Nelson", "Baker", "Hall", "Rivera", "Campbell", "Mitchell", "Carter", "Roberts" + }; + + private static readonly string[] JobTitles = { + "Software Engineer", "Product Manager", "Sales Representative", "Marketing Specialist", "Data Analyst", + "Project Manager", "Business Analyst", "Customer Service Representative", "Operations Manager", "HR Manager", + "Financial Analyst", "Graphic Designer", "Content Writer", "DevOps Engineer", "Quality Assurance", "System Administrator", + "Account Manager", "Business Development", "Research Analyst", "Technical Writer", "UX Designer", "Database Administrator", + "Network Engineer", "Security Specialist", "Training Coordinator", "Executive Assistant", "Procurement Specialist", + "Supply Chain Manager", "Legal Counsel", "Compliance Officer", "Risk Manager", "Business Intelligence Analyst" + }; + + private static readonly string[] CompanyNames = { + "Acme Corporation", "Global Solutions Inc", "TechFlow Systems", "DataSync Technologies", "NextGen Enterprises", + "Blue Ocean Ventures", "Strategic Innovations", "Digital Dynamics", "Advanced Systems", "Premier Solutions", + "Integrated Technologies", "Synergy Solutions", "Excellence Corp", "Progressive Systems", "Dynamic Enterprises", + "Innovative Solutions", "Peak Performance", "Summit Technologies", "Apex Systems", "Pinnacle Corp" + }; + + private static readonly string[] StreetNames = { + "Main St", "First Ave", "Second St", "Third Ave", "Oak St", "Elm St", "Park Ave", "Broadway", + "Washington St", "Lincoln Ave", "Madison St", "Jefferson Ave", "Franklin St", "Cedar St", + "Maple Ave", "Pine St", "Sunset Blvd", "Rose Ave", "Spring St", "Valley Rd" + }; + + private static readonly string[] Industries = { + "Technology", "Healthcare", "Finance", "Manufacturing", "Retail", "Education", "Real Estate", + "Transportation", "Energy", "Telecommunications", "Agriculture", "Construction", "Entertainment", + "Hospitality", "Insurance", "Consulting", "Media", "Automotive", "Aerospace", "Pharmaceuticals" + }; + + // Business Central specific arrays + private static readonly string[] BCCustomerGroups = { + "DOMESTIC", "FOREIGN", "INTERCOMPANY", "RETAIL", "WHOLESALE", "GOVERNMENT", "NONPROFIT", "EDUCATION" + }; + + private static readonly string[] BCPaymentTerms = { + "NET30", "NET15", "NET10", "COD", "2%10NET30", "1%15NET30", "IMMEDIATE", "NET45", "NET60" + }; + + private static readonly string[] BCCurrencyCodes = { + "USD", "EUR", "GBP", "CAD", "AUD", "JPY", "CHF", "SEK", "NOK", "DKK" + }; + + private static readonly string[] BCItemCategories = { + "FINISHED", "RAW-MAT", "RESALE", "SERVICE", "MISC", "ASSEMBLY", "KIT", "COMPONENT" + }; + + // Supply Chain specific arrays + private static readonly string[] SupplyChainWarehouseTypes = { + "Distribution Center", "Manufacturing Plant", "Cross-Dock", "Cold Storage", "Hazmat Storage", + "Automated Warehouse", "Transit Hub", "Regional Depot", "Consolidation Center", "Fulfillment Center" + }; + + private static readonly string[] SupplyChainItemGroups = { + "Electronics", "Automotive", "Pharmaceutical", "Food & Beverage", "Textiles", "Chemical", + "Industrial Equipment", "Consumer Goods", "Raw Materials", "Packaging" + }; + + private static readonly string[] SupplyChainItemTypes = { + "Finished Good", "Raw Material", "Work in Progress", "Semi-Finished", "Component", "Assembly", + "Spare Part", "Consumable", "Tool", "Equipment" + }; + + private static readonly string[] SupplyChainCategories = { + "Production", "Maintenance", "Office Supplies", "Safety Equipment", "IT Hardware", "Chemicals", + "Packaging Materials", "Tools & Equipment", "Spare Parts", "Consumables" + }; + + private static readonly string[] SupplyChainUnitsOfMeasure = { + "EA", "LB", "KG", "GAL", "L", "FT", "M", "SQ FT", "SQ M", "CASE", "BOX", "PALLET", "ROLL", "SET" + }; + + private static readonly string[] SupplyChainRequisitionPriorities = { + "Low", "Normal", "High", "Critical", "Emergency" + }; + + private static readonly string[] SupplyChainProductionStatuses = { + "Planned", "Released", "Started", "In Progress", "Completed", "On Hold", "Cancelled" + }; + + private static readonly string[] SupplyChainBOMTypes = { + "Production", "Assembly", "Planning", "Service", "Phantom", "Engineering" + }; + + private static readonly string[] SupplyChainTransactionTypes = { + "Receipt", "Issue", "Transfer", "Adjustment", "Count", "Sale", "Purchase", "Production", + "Consumption", "Output", "Scrap", "Rework" + }; + + private static readonly string[] SupplyChainDirections = { "In", "Out" }; + + // Field Service specific arrays + private static readonly string[] FSWorkOrderTypes = { + "Preventive Maintenance", "Corrective Maintenance", "Installation", "Inspection", "Repair", + "Replacement", "Upgrade", "Emergency", "Warranty", "Contract" + }; + + private static readonly string[] FSPriorities = { + "Low", "Normal", "High", "Critical", "Emergency" + }; + + private static readonly string[] FSServiceStatuses = { + "Draft", "Scheduled", "In Progress", "On Hold", "Completed", "Cancelled", "Closed" + }; + + private static readonly string[] FSResourceTypes = { + "Technician", "Engineer", "Specialist", "Supervisor", "Contractor", "Apprentice" + }; + + private static readonly string[] FSSkills = { + "Electrical", "Mechanical", "HVAC", "Plumbing", "Electronics", "Software", "Networking", + "Welding", "Hydraulics", "Pneumatics", "Instrumentation", "Calibration" + }; + + private static readonly string[] FSEquipmentTypes = { + "Generator", "Motor", "Pump", "Compressor", "Transformer", "Switch", "Valve", "Sensor", + "Controller", "Drive", "Panel", "Conveyor", "Robot", "Machine" + }; + + private static readonly string[] FSReasonCodes = { + "Normal Wear", "Manufacturing Defect", "Improper Use", "External Damage", "Age Related", + "Environmental", "Vandalism", "Accident", "Design Flaw", "Installation Error" + }; + + // Dataverse-specific arrays + private static readonly string[] Products = { + "Office 365", "Dynamics 365", "Azure Services", "Power Platform", "SharePoint", "Teams", + "Exchange Online", "Windows Server", "SQL Server", "Visual Studio", "Surface Pro", + "HoloLens", "Azure DevOps", "Power BI", "Power Apps", "Power Automate", "OneDrive", + "Outlook", "Word", "Excel", "PowerPoint", "Project", "Visio", "Access", "Publisher" + }; + + private static readonly string[] OpportunityStages = { + "Qualify", "Develop", "Propose", "Close", "Identify", "Research", "Present", "Negotiate" + }; + + private static readonly string[] CaseTypes = { + "Technical Issue", "Billing Question", "Product Inquiry", "Feature Request", + "Bug Report", "Account Access", "Training Request", "Compliance Question", + "Security Concern", "Performance Issue", "Integration Problem", "Data Migration" + }; + + private static readonly string[] CampaignNames = { + "Spring Launch", "Summer Promotion", "Fall Campaign", "Winter Sale", "New Product Launch", + "Customer Retention", "Lead Generation", "Brand Awareness", "Digital Transformation", + "Innovation Series", "Market Expansion", "Partner Program", "Trade Show Campaign" + }; + + private static readonly string[] ActivityTypes = { + "Phone Call", "Email", "Meeting", "Task", "Appointment", "Follow-up", "Presentation", + "Demo", "Training", "Review", "Planning", "Research", "Documentation", "Support" + }; + + private static readonly string[] StockExchanges = { + "NYSE", "NASDAQ", "LSE", "TSE", "HKSE", "SSE", "Euronext", "TSX", "ASX", "BSE" + }; + + private static readonly string[] KnowledgeTopics = { + "Setup and Configuration", "Troubleshooting", "Best Practices", "Integration Guide", + "Security Configuration", "Performance Optimization", "User Training", "API Documentation", + "Migration Guide", "Backup and Recovery", "Compliance Requirements", "Feature Overview" + }; + + private static readonly string[] Departments = { + "Sales", "Marketing", "IT", "Finance", "HR", "Operations", "Customer Service", + "Research and Development", "Quality Assurance", "Legal", "Procurement", "Manufacturing" + }; + + // Location data - comprehensive US coverage with global cities + private static readonly (string city, string stateOrProvince, string country)[] Locations = { + // United States (255 cities - minimum 5 per state) + // Alabama (5 cities) + ("Birmingham", "AL", "USA"), ("Montgomery", "AL", "USA"), ("Mobile", "AL", "USA"), ("Huntsville", "AL", "USA"), ("Tuscaloosa", "AL", "USA"), + + // Alaska (5 cities) + ("Anchorage", "AK", "USA"), ("Fairbanks", "AK", "USA"), ("Juneau", "AK", "USA"), ("Sitka", "AK", "USA"), ("Ketchikan", "AK", "USA"), + + // Arizona (5 cities) + ("Phoenix", "AZ", "USA"), ("Tucson", "AZ", "USA"), ("Mesa", "AZ", "USA"), ("Chandler", "AZ", "USA"), ("Scottsdale", "AZ", "USA"), + + // Arkansas (5 cities) + ("Little Rock", "AR", "USA"), ("Fort Smith", "AR", "USA"), ("Fayetteville", "AR", "USA"), ("Springdale", "AR", "USA"), ("Jonesboro", "AR", "USA"), + + // California (15 cities) + ("Los Angeles", "CA", "USA"), ("San Diego", "CA", "USA"), ("San Jose", "CA", "USA"), ("San Francisco", "CA", "USA"), + ("Fresno", "CA", "USA"), ("Sacramento", "CA", "USA"), ("Long Beach", "CA", "USA"), ("Oakland", "CA", "USA"), + ("Anaheim", "CA", "USA"), ("Santa Ana", "CA", "USA"), ("Riverside", "CA", "USA"), ("Stockton", "CA", "USA"), + ("Chula Vista", "CA", "USA"), ("Irvine", "CA", "USA"), ("Fremont", "CA", "USA"), + + // Colorado (5 cities) + ("Denver", "CO", "USA"), ("Colorado Springs", "CO", "USA"), ("Aurora", "CO", "USA"), ("Fort Collins", "CO", "USA"), ("Lakewood", "CO", "USA"), + + // Connecticut (5 cities) + ("Bridgeport", "CT", "USA"), ("New Haven", "CT", "USA"), ("Hartford", "CT", "USA"), ("Stamford", "CT", "USA"), ("Waterbury", "CT", "USA"), + + // Delaware (5 cities) + ("Wilmington", "DE", "USA"), ("Dover", "DE", "USA"), ("Newark", "DE", "USA"), ("Middletown", "DE", "USA"), ("Smyrna", "DE", "USA"), + + // Florida (10 cities) + ("Jacksonville", "FL", "USA"), ("Miami", "FL", "USA"), ("Tampa", "FL", "USA"), ("Orlando", "FL", "USA"), + ("St. Petersburg", "FL", "USA"), ("Hialeah", "FL", "USA"), ("Tallahassee", "FL", "USA"), ("Fort Lauderdale", "FL", "USA"), + ("Port St. Lucie", "FL", "USA"), ("Cape Coral", "FL", "USA"), + + // Georgia (5 cities) + ("Atlanta", "GA", "USA"), ("Columbus", "GA", "USA"), ("Augusta", "GA", "USA"), ("Savannah", "GA", "USA"), ("Athens", "GA", "USA"), + + // Hawaii (5 cities) + ("Honolulu", "HI", "USA"), ("Pearl City", "HI", "USA"), ("Hilo", "HI", "USA"), ("Kailua", "HI", "USA"), ("Waipahu", "HI", "USA"), + + // Idaho (5 cities) + ("Boise", "ID", "USA"), ("Meridian", "ID", "USA"), ("Nampa", "ID", "USA"), ("Idaho Falls", "ID", "USA"), ("Pocatello", "ID", "USA"), + + // Illinois (8 cities) + ("Chicago", "IL", "USA"), ("Aurora", "IL", "USA"), ("Rockford", "IL", "USA"), ("Joliet", "IL", "USA"), + ("Naperville", "IL", "USA"), ("Springfield", "IL", "USA"), ("Peoria", "IL", "USA"), ("Elgin", "IL", "USA"), + + // Indiana (5 cities) + ("Indianapolis", "IN", "USA"), ("Fort Wayne", "IN", "USA"), ("Evansville", "IN", "USA"), ("South Bend", "IN", "USA"), ("Carmel", "IN", "USA"), + + // Iowa (5 cities) + ("Des Moines", "IA", "USA"), ("Cedar Rapids", "IA", "USA"), ("Davenport", "IA", "USA"), ("Sioux City", "IA", "USA"), ("Iowa City", "IA", "USA"), + + // Kansas (5 cities) + ("Wichita", "KS", "USA"), ("Overland Park", "KS", "USA"), ("Kansas City", "KS", "USA"), ("Topeka", "KS", "USA"), ("Olathe", "KS", "USA"), + + // Kentucky (5 cities) + ("Louisville", "KY", "USA"), ("Lexington", "KY", "USA"), ("Bowling Green", "KY", "USA"), ("Owensboro", "KY", "USA"), ("Covington", "KY", "USA"), + + // Louisiana (5 cities) + ("New Orleans", "LA", "USA"), ("Baton Rouge", "LA", "USA"), ("Shreveport", "LA", "USA"), ("Lafayette", "LA", "USA"), ("Lake Charles", "LA", "USA"), + + // Maine (5 cities) + ("Portland", "ME", "USA"), ("Lewiston", "ME", "USA"), ("Bangor", "ME", "USA"), ("South Portland", "ME", "USA"), ("Auburn", "ME", "USA"), + + // Maryland (5 cities) + ("Baltimore", "MD", "USA"), ("Frederick", "MD", "USA"), ("Rockville", "MD", "USA"), ("Gaithersburg", "MD", "USA"), ("Bowie", "MD", "USA"), + + // Massachusetts (5 cities) + ("Boston", "MA", "USA"), ("Worcester", "MA", "USA"), ("Springfield", "MA", "USA"), ("Lowell", "MA", "USA"), ("Cambridge", "MA", "USA"), + + // Michigan (5 cities) + ("Detroit", "MI", "USA"), ("Grand Rapids", "MI", "USA"), ("Warren", "MI", "USA"), ("Sterling Heights", "MI", "USA"), ("Lansing", "MI", "USA"), + + // Minnesota (5 cities) + ("Minneapolis", "MN", "USA"), ("St. Paul", "MN", "USA"), ("Rochester", "MN", "USA"), ("Duluth", "MN", "USA"), ("Bloomington", "MN", "USA"), + + // Mississippi (5 cities) + ("Jackson", "MS", "USA"), ("Gulfport", "MS", "USA"), ("Southaven", "MS", "USA"), ("Hattiesburg", "MS", "USA"), ("Biloxi", "MS", "USA"), + + // Missouri (5 cities) + ("Kansas City", "MO", "USA"), ("St. Louis", "MO", "USA"), ("Springfield", "MO", "USA"), ("Columbia", "MO", "USA"), ("Independence", "MO", "USA"), + + // Montana (5 cities) + ("Billings", "MT", "USA"), ("Missoula", "MT", "USA"), ("Great Falls", "MT", "USA"), ("Bozeman", "MT", "USA"), ("Helena", "MT", "USA"), + + // Nebraska (5 cities) + ("Omaha", "NE", "USA"), ("Lincoln", "NE", "USA"), ("Bellevue", "NE", "USA"), ("Grand Island", "NE", "USA"), ("Kearney", "NE", "USA"), + + // Nevada (5 cities) + ("Las Vegas", "NV", "USA"), ("Henderson", "NV", "USA"), ("Reno", "NV", "USA"), ("North Las Vegas", "NV", "USA"), ("Sparks", "NV", "USA"), + + // New Hampshire (5 cities) + ("Manchester", "NH", "USA"), ("Nashua", "NH", "USA"), ("Concord", "NH", "USA"), ("Derry", "NH", "USA"), ("Rochester", "NH", "USA"), + + // New Jersey (5 cities) + ("Newark", "NJ", "USA"), ("Jersey City", "NJ", "USA"), ("Paterson", "NJ", "USA"), ("Elizabeth", "NJ", "USA"), ("Edison", "NJ", "USA"), + + // New Mexico (5 cities) + ("Albuquerque", "NM", "USA"), ("Las Cruces", "NM", "USA"), ("Rio Rancho", "NM", "USA"), ("Santa Fe", "NM", "USA"), ("Roswell", "NM", "USA"), + + // New York (10 cities) + ("New York", "NY", "USA"), ("Buffalo", "NY", "USA"), ("Rochester", "NY", "USA"), ("Yonkers", "NY", "USA"), + ("Syracuse", "NY", "USA"), ("Albany", "NY", "USA"), ("New Rochelle", "NY", "USA"), ("Mount Vernon", "NY", "USA"), + ("Schenectady", "NY", "USA"), ("Utica", "NY", "USA"), + + // North Carolina (5 cities) + ("Charlotte", "NC", "USA"), ("Raleigh", "NC", "USA"), ("Greensboro", "NC", "USA"), ("Durham", "NC", "USA"), ("Winston-Salem", "NC", "USA"), + + // North Dakota (5 cities) + ("Fargo", "ND", "USA"), ("Bismarck", "ND", "USA"), ("Grand Forks", "ND", "USA"), ("Minot", "ND", "USA"), ("West Fargo", "ND", "USA"), + + // Ohio (8 cities) + ("Columbus", "OH", "USA"), ("Cleveland", "OH", "USA"), ("Cincinnati", "OH", "USA"), ("Toledo", "OH", "USA"), + ("Akron", "OH", "USA"), ("Dayton", "OH", "USA"), ("Parma", "OH", "USA"), ("Canton", "OH", "USA"), + + // Oklahoma (5 cities) + ("Oklahoma City", "OK", "USA"), ("Tulsa", "OK", "USA"), ("Norman", "OK", "USA"), ("Broken Arrow", "OK", "USA"), ("Lawton", "OK", "USA"), + + // Oregon (5 cities) + ("Portland", "OR", "USA"), ("Eugene", "OR", "USA"), ("Salem", "OR", "USA"), ("Gresham", "OR", "USA"), ("Hillsboro", "OR", "USA"), + + // Pennsylvania (8 cities) + ("Philadelphia", "PA", "USA"), ("Pittsburgh", "PA", "USA"), ("Allentown", "PA", "USA"), ("Erie", "PA", "USA"), + ("Reading", "PA", "USA"), ("Scranton", "PA", "USA"), ("Bethlehem", "PA", "USA"), ("Lancaster", "PA", "USA"), + + // Rhode Island (5 cities) + ("Providence", "RI", "USA"), ("Warwick", "RI", "USA"), ("Cranston", "RI", "USA"), ("Pawtucket", "RI", "USA"), ("East Providence", "RI", "USA"), + + // South Carolina (5 cities) + ("Columbia", "SC", "USA"), ("Charleston", "SC", "USA"), ("North Charleston", "SC", "USA"), ("Mount Pleasant", "SC", "USA"), ("Rock Hill", "SC", "USA"), + + // South Dakota (5 cities) + ("Sioux Falls", "SD", "USA"), ("Rapid City", "SD", "USA"), ("Aberdeen", "SD", "USA"), ("Brookings", "SD", "USA"), ("Watertown", "SD", "USA"), + + // Tennessee (5 cities) + ("Nashville", "TN", "USA"), ("Memphis", "TN", "USA"), ("Knoxville", "TN", "USA"), ("Chattanooga", "TN", "USA"), ("Clarksville", "TN", "USA"), + + // Texas (15 cities) + ("Houston", "TX", "USA"), ("San Antonio", "TX", "USA"), ("Dallas", "TX", "USA"), ("Austin", "TX", "USA"), + ("Fort Worth", "TX", "USA"), ("El Paso", "TX", "USA"), ("Arlington", "TX", "USA"), ("Corpus Christi", "TX", "USA"), + ("Plano", "TX", "USA"), ("Laredo", "TX", "USA"), ("Lubbock", "TX", "USA"), ("Garland", "TX", "USA"), + ("Irving", "TX", "USA"), ("Amarillo", "TX", "USA"), ("Grand Prairie", "TX", "USA"), + + // Utah (5 cities) + ("Salt Lake City", "UT", "USA"), ("West Valley City", "UT", "USA"), ("Provo", "UT", "USA"), ("West Jordan", "UT", "USA"), ("Orem", "UT", "USA"), + + // Vermont (5 cities) + ("Burlington", "VT", "USA"), ("Essex", "VT", "USA"), ("South Burlington", "VT", "USA"), ("Colchester", "VT", "USA"), ("Rutland", "VT", "USA"), + + // Virginia (8 cities) + ("Virginia Beach", "VA", "USA"), ("Norfolk", "VA", "USA"), ("Chesapeake", "VA", "USA"), ("Richmond", "VA", "USA"), + ("Newport News", "VA", "USA"), ("Alexandria", "VA", "USA"), ("Hampton", "VA", "USA"), ("Portsmouth", "VA", "USA"), + + // Washington (5 cities) + ("Seattle", "WA", "USA"), ("Spokane", "WA", "USA"), ("Tacoma", "WA", "USA"), ("Vancouver", "WA", "USA"), ("Bellevue", "WA", "USA"), + + // West Virginia (5 cities) + ("Charleston", "WV", "USA"), ("Huntington", "WV", "USA"), ("Morgantown", "WV", "USA"), ("Parkersburg", "WV", "USA"), ("Wheeling", "WV", "USA"), + + // Wisconsin (5 cities) + ("Milwaukee", "WI", "USA"), ("Madison", "WI", "USA"), ("Green Bay", "WI", "USA"), ("Kenosha", "WI", "USA"), ("Racine", "WI", "USA"), + + // Wyoming (5 cities) + ("Cheyenne", "WY", "USA"), ("Casper", "WY", "USA"), ("Laramie", "WY", "USA"), ("Gillette", "WY", "USA"), ("Rock Springs", "WY", "USA"), + + // District of Columbia (1 city) + ("Washington", "DC", "USA"), + + // International Cities (245 cities) + // Canada (25 cities) + ("Toronto", "ON", "Canada"), ("Montreal", "QC", "Canada"), ("Calgary", "AB", "Canada"), ("Ottawa", "ON", "Canada"), + ("Edmonton", "AB", "Canada"), ("Mississauga", "ON", "Canada"), ("Winnipeg", "MB", "Canada"), ("Vancouver", "BC", "Canada"), + ("Brampton", "ON", "Canada"), ("Hamilton", "ON", "Canada"), ("Quebec City", "QC", "Canada"), ("Surrey", "BC", "Canada"), + ("Laval", "QC", "Canada"), ("Halifax", "NS", "Canada"), ("London", "ON", "Canada"), ("Markham", "ON", "Canada"), + ("Vaughan", "ON", "Canada"), ("Gatineau", "QC", "Canada"), ("Longueuil", "QC", "Canada"), ("Burnaby", "BC", "Canada"), + ("Saskatoon", "SK", "Canada"), ("Kitchener", "ON", "Canada"), ("Windsor", "ON", "Canada"), ("Regina", "SK", "Canada"), + ("Richmond", "BC", "Canada"), + + // United Kingdom (25 cities) + ("London", "England", "United Kingdom"), ("Birmingham", "England", "United Kingdom"), ("Manchester", "England", "United Kingdom"), ("Liverpool", "England", "United Kingdom"), + ("Sheffield", "England", "United Kingdom"), ("Leeds", "Yorkshire", "United Kingdom"), ("Edinburgh", "Scotland", "United Kingdom"), ("Glasgow", "Scotland", "United Kingdom"), + ("Cardiff", "Wales", "United Kingdom"), ("Belfast", "Northern Ireland", "United Kingdom"), ("Newcastle", "England", "United Kingdom"), ("Nottingham", "England", "United Kingdom"), + ("Bristol", "England", "United Kingdom"), ("Leicester", "England", "United Kingdom"), ("Coventry", "England", "United Kingdom"), ("Hull", "England", "United Kingdom"), + ("Bradford", "Yorkshire", "United Kingdom"), ("Stoke-on-Trent", "England", "United Kingdom"), ("Wolverhampton", "England", "United Kingdom"), ("Plymouth", "England", "United Kingdom"), + ("Derby", "England", "United Kingdom"), ("Southampton", "England", "United Kingdom"), ("Portsmouth", "England", "United Kingdom"), ("Aberdeen", "Scotland", "United Kingdom"), + ("Swansea", "Wales", "United Kingdom"), + + // Germany (25 cities) + ("Berlin", "Berlin", "Germany"), ("Hamburg", "Hamburg", "Germany"), ("Munich", "Bavaria", "Germany"), ("Cologne", "North Rhine-Westphalia", "Germany"), + ("Frankfurt", "Hesse", "Germany"), ("Stuttgart", "Baden-Württemberg", "Germany"), ("Düsseldorf", "North Rhine-Westphalia", "Germany"), ("Dortmund", "North Rhine-Westphalia", "Germany"), + ("Essen", "North Rhine-Westphalia", "Germany"), ("Leipzig", "Saxony", "Germany"), ("Bremen", "Bremen", "Germany"), ("Dresden", "Saxony", "Germany"), + ("Hanover", "Lower Saxony", "Germany"), ("Nuremberg", "Bavaria", "Germany"), ("Duisburg", "North Rhine-Westphalia", "Germany"), ("Bochum", "North Rhine-Westphalia", "Germany"), + ("Wuppertal", "North Rhine-Westphalia", "Germany"), ("Bielefeld", "North Rhine-Westphalia", "Germany"), ("Bonn", "North Rhine-Westphalia", "Germany"), ("Münster", "North Rhine-Westphalia", "Germany"), + ("Karlsruhe", "Baden-Württemberg", "Germany"), ("Mannheim", "Baden-Württemberg", "Germany"), ("Augsburg", "Bavaria", "Germany"), ("Wiesbaden", "Hesse", "Germany"), + ("Mönchengladbach", "North Rhine-Westphalia", "Germany"), + + // France (20 cities) + ("Paris", "Île-de-France", "France"), ("Marseille", "Provence-Alpes-Côte d'Azur", "France"), ("Lyon", "Auvergne-Rhône-Alpes", "France"), ("Toulouse", "Occitanie", "France"), + ("Nice", "Provence-Alpes-Côte d'Azur", "France"), ("Nantes", "Pays de la Loire", "France"), ("Montpellier", "Occitanie", "France"), ("Strasbourg", "Grand Est", "France"), + ("Bordeaux", "Nouvelle-Aquitaine", "France"), ("Lille", "Hauts-de-France", "France"), ("Rennes", "Brittany", "France"), ("Reims", "Grand Est", "France"), + ("Saint-Étienne", "Auvergne-Rhône-Alpes", "France"), ("Le Havre", "Normandy", "France"), ("Toulon", "Provence-Alpes-Côte d'Azur", "France"), ("Grenoble", "Auvergne-Rhône-Alpes", "France"), + ("Dijon", "Burgundy-Franche-Comté", "France"), ("Angers", "Pays de la Loire", "France"), ("Nîmes", "Occitanie", "France"), ("Villeurbanne", "Auvergne-Rhône-Alpes", "France"), + + // Italy (15 cities) + ("Rome", "Lazio", "Italy"), ("Milan", "Lombardy", "Italy"), ("Naples", "Campania", "Italy"), ("Turin", "Piedmont", "Italy"), + ("Palermo", "Sicily", "Italy"), ("Genoa", "Liguria", "Italy"), ("Bologna", "Emilia-Romagna", "Italy"), ("Florence", "Tuscany", "Italy"), + ("Bari", "Apulia", "Italy"), ("Catania", "Sicily", "Italy"), ("Venice", "Veneto", "Italy"), ("Verona", "Veneto", "Italy"), + ("Messina", "Sicily", "Italy"), ("Padua", "Veneto", "Italy"), ("Trieste", "Friuli-Venezia Giulia", "Italy"), + + // Spain (15 cities) + ("Madrid", "Community of Madrid", "Spain"), ("Barcelona", "Catalonia", "Spain"), ("Valencia", "Valencian Community", "Spain"), ("Seville", "Andalusia", "Spain"), + ("Zaragoza", "Aragon", "Spain"), ("Málaga", "Andalusia", "Spain"), ("Murcia", "Region of Murcia", "Spain"), ("Palma", "Balearic Islands", "Spain"), + ("Las Palmas", "Canary Islands", "Spain"), ("Bilbao", "Basque Country", "Spain"), ("Alicante", "Valencian Community", "Spain"), ("Córdoba", "Andalusia", "Spain"), + ("Valladolid", "Castile and León", "Spain"), ("Vigo", "Galicia", "Spain"), ("Gijón", "Asturias", "Spain"), + + // Netherlands (10 cities) + ("Amsterdam", "North Holland", "Netherlands"), ("Rotterdam", "South Holland", "Netherlands"), ("The Hague", "South Holland", "Netherlands"), ("Utrecht", "Utrecht", "Netherlands"), + ("Eindhoven", "North Brabant", "Netherlands"), ("Tilburg", "North Brabant", "Netherlands"), ("Groningen", "Groningen", "Netherlands"), ("Almere", "Flevoland", "Netherlands"), + ("Breda", "North Brabant", "Netherlands"), ("Nijmegen", "Gelderland", "Netherlands"), + + // Australia (10 cities) + ("Sydney", "NSW", "Australia"), ("Melbourne", "VIC", "Australia"), ("Brisbane", "QLD", "Australia"), ("Perth", "WA", "Australia"), + ("Adelaide", "SA", "Australia"), ("Gold Coast", "QLD", "Australia"), ("Newcastle", "NSW", "Australia"), ("Canberra", "ACT", "Australia"), + ("Sunshine Coast", "QLD", "Australia"), ("Wollongong", "NSW", "Australia"), + + // Japan (15 cities) + ("Tokyo", "Tokyo", "Japan"), ("Yokohama", "Kanagawa", "Japan"), ("Osaka", "Osaka", "Japan"), ("Nagoya", "Aichi", "Japan"), + ("Sapporo", "Hokkaido", "Japan"), ("Fukuoka", "Fukuoka", "Japan"), ("Kobe", "Hyogo", "Japan"), ("Kyoto", "Kyoto", "Japan"), + ("Kawasaki", "Kanagawa", "Japan"), ("Saitama", "Saitama", "Japan"), ("Hiroshima", "Hiroshima", "Japan"), ("Sendai", "Miyagi", "Japan"), + ("Kitakyushu", "Fukuoka", "Japan"), ("Chiba", "Chiba", "Japan"), ("Sakai", "Osaka", "Japan"), + + // Brazil (15 cities) + ("São Paulo", "São Paulo", "Brazil"), ("Rio de Janeiro", "Rio de Janeiro", "Brazil"), ("Brasília", "Federal District", "Brazil"), ("Salvador", "Bahia", "Brazil"), + ("Fortaleza", "Ceará", "Brazil"), ("Belo Horizonte", "Minas Gerais", "Brazil"), ("Manaus", "Amazonas", "Brazil"), ("Curitiba", "Paraná", "Brazil"), + ("Recife", "Pernambuco", "Brazil"), ("Goiânia", "Goiás", "Brazil"), ("Belém", "Pará", "Brazil"), ("Porto Alegre", "Rio Grande do Sul", "Brazil"), + ("Guarulhos", "São Paulo", "Brazil"), ("Campinas", "São Paulo", "Brazil"), ("Nova Iguaçu", "Rio de Janeiro", "Brazil"), + + // Mexico (15 cities) + ("Mexico City", "Mexico City", "Mexico"), ("Guadalajara", "Jalisco", "Mexico"), ("Monterrey", "Nuevo León", "Mexico"), ("Puebla", "Puebla", "Mexico"), + ("Tijuana", "Baja California", "Mexico"), ("León", "Guanajuato", "Mexico"), ("Juárez", "Chihuahua", "Mexico"), ("Torreón", "Coahuila", "Mexico"), + ("Querétaro", "Querétaro", "Mexico"), ("San Luis Potosí", "San Luis Potosí", "Mexico"), ("Mérida", "Yucatán", "Mexico"), ("Mexicali", "Baja California", "Mexico"), + ("Aguascalientes", "Aguascalientes", "Mexico"), ("Cuernavaca", "Morelos", "Mexico"), ("Saltillo", "Coahuila", "Mexico"), + + // China (15 cities) + ("Beijing", "Beijing", "China"), ("Shanghai", "Shanghai", "China"), ("Guangzhou", "Guangdong", "China"), ("Shenzhen", "Guangdong", "China"), + ("Tianjin", "Tianjin", "China"), ("Wuhan", "Hubei", "China"), ("Dongguan", "Guangdong", "China"), ("Chengdu", "Sichuan", "China"), + ("Nanjing", "Jiangsu", "China"), ("Chongqing", "Chongqing", "China"), ("Xi'an", "Shaanxi", "China"), ("Shenyang", "Liaoning", "China"), + ("Hangzhou", "Zhejiang", "China"), ("Foshan", "Guangdong", "China"), ("Qingdao", "Shandong", "China"), + + // India (15 cities) + ("Mumbai", "Maharashtra", "India"), ("Delhi", "Delhi", "India"), ("Bangalore", "Karnataka", "India"), ("Hyderabad", "Telangana", "India"), + ("Ahmedabad", "Gujarat", "India"), ("Chennai", "Tamil Nadu", "India"), ("Kolkata", "West Bengal", "India"), ("Surat", "Gujarat", "India"), + ("Pune", "Maharashtra", "India"), ("Jaipur", "Rajasthan", "India"), ("Lucknow", "Uttar Pradesh", "India"), ("Kanpur", "Uttar Pradesh", "India"), + ("Nagpur", "Maharashtra", "India"), ("Indore", "Madhya Pradesh", "India"), ("Thane", "Maharashtra", "India"), + + // South Korea (10 cities) + ("Seoul", "Seoul", "South Korea"), ("Busan", "Busan", "South Korea"), ("Incheon", "Incheon", "South Korea"), ("Daegu", "Daegu", "South Korea"), + ("Daejeon", "Daejeon", "South Korea"), ("Gwangju", "Gwangju", "South Korea"), ("Suwon", "Gyeonggi", "South Korea"), ("Ulsan", "Ulsan", "South Korea"), + ("Changwon", "South Gyeongsang", "South Korea"), ("Goyang", "Gyeonggi", "South Korea"), + + // South Africa (10 cities) + ("Johannesburg", "Gauteng", "South Africa"), ("Cape Town", "Western Cape", "South Africa"), ("Durban", "KwaZulu-Natal", "South Africa"), ("Pretoria", "Gauteng", "South Africa"), + ("Port Elizabeth", "Eastern Cape", "South Africa"), ("Pietermaritzburg", "KwaZulu-Natal", "South Africa"), ("Benoni", "Gauteng", "South Africa"), ("Tembisa", "Gauteng", "South Africa"), + ("East London", "Eastern Cape", "South Africa"), ("Vereeniging", "Gauteng", "South Africa"), + + // Sweden (10 cities) + ("Stockholm", "Stockholm", "Sweden"), ("Gothenburg", "Västra Götaland", "Sweden"), ("Malmö", "Skåne", "Sweden"), ("Uppsala", "Uppsala", "Sweden"), + ("Västerås", "Västmanland", "Sweden"), ("Örebro", "Örebro", "Sweden"), ("Linköping", "Östergötland", "Sweden"), ("Helsingborg", "Skåne", "Sweden"), + ("Jönköping", "Jönköping", "Sweden"), ("Norrköping", "Östergötland", "Sweden"), + + // Norway (5 cities) + ("Oslo", "Oslo", "Norway"), ("Bergen", "Vestland", "Norway"), ("Stavanger", "Rogaland", "Norway"), ("Trondheim", "Trøndelag", "Norway"), + ("Drammen", "Viken", "Norway"), + + // Denmark (5 cities) + ("Copenhagen", "Capital Region", "Denmark"), ("Aarhus", "Central Denmark", "Denmark"), ("Odense", "Southern Denmark", "Denmark"), ("Aalborg", "North Denmark", "Denmark"), + ("Esbjerg", "Southern Denmark", "Denmark"), + + // Belgium (5 cities) + ("Brussels", "Brussels-Capital", "Belgium"), ("Antwerp", "Flanders", "Belgium"), ("Ghent", "Flanders", "Belgium"), ("Charleroi", "Wallonia", "Belgium"), + ("Liège", "Wallonia", "Belgium"), + + // Switzerland (5 cities) + ("Zurich", "Zurich", "Switzerland"), ("Geneva", "Geneva", "Switzerland"), ("Basel", "Basel-Stadt", "Switzerland"), ("Bern", "Bern", "Switzerland"), + ("Lausanne", "Vaud", "Switzerland"), + + // Austria (5 cities) + ("Vienna", "Vienna", "Austria"), ("Graz", "Styria", "Austria"), ("Linz", "Upper Austria", "Austria"), ("Salzburg", "Salzburg", "Austria"), + ("Innsbruck", "Tyrol", "Austria"), + + // Poland (5 cities) + ("Warsaw", "Masovian", "Poland"), ("Kraków", "Lesser Poland", "Poland"), ("Łódź", "Łódź", "Poland"), ("Wrocław", "Lower Silesian", "Poland"), + ("Poznań", "Greater Poland", "Poland") + }; + + // ================================================================================================ + // HELPER METHODS + // ================================================================================================ + + private void InitializeSharedIdPools(Random seededRandom, int accountPoolSize, int contactPoolSize, int productPoolSize) + { + // Generate shared Account ID pool + _sharedAccountIds = new Guid[accountPoolSize]; + _sharedAccountNames = new string[accountPoolSize]; + for (int i = 0; i < accountPoolSize; i++) + { + _sharedAccountIds[i] = Guid.NewGuid(); + _sharedAccountNames[i] = CompanyNames[seededRandom.Next(CompanyNames.Length)]; + } + + // Generate shared Contact ID pool + _sharedContactIds = new Guid[contactPoolSize]; + _sharedContactNames = new string[contactPoolSize]; + for (int i = 0; i < contactPoolSize; i++) + { + _sharedContactIds[i] = Guid.NewGuid(); + var firstName = FirstNames[seededRandom.Next(FirstNames.Length)]; + var lastName = LastNames[seededRandom.Next(LastNames.Length)]; + _sharedContactNames[i] = $"{firstName} {lastName}"; + } + + // Generate shared Product ID pool + _sharedProductIds = new Guid[productPoolSize]; + _sharedProductNames = new string[productPoolSize]; + for (int i = 0; i < productPoolSize; i++) + { + _sharedProductIds[i] = Guid.NewGuid(); + _sharedProductNames[i] = Products[seededRandom.Next(Products.Length)]; + } + } + + private Guid GetRandomSharedAccountId(Random random) + { + return _sharedAccountIds[random.Next(_sharedAccountIds.Length)]; + } + + private Guid GetRandomSharedContactId(Random random) + { + return _sharedContactIds[random.Next(_sharedContactIds.Length)]; + } + + private Guid GetRandomSharedProductId(Random random) + { + return _sharedProductIds[random.Next(_sharedProductIds.Length)]; + } + + private string GetAccountNameById(Guid accountId) + { + var index = Array.IndexOf(_sharedAccountIds, accountId); + return index >= 0 ? _sharedAccountNames[index] : "Unknown Account"; + } + + private string GetContactNameById(Guid contactId) + { + var index = Array.IndexOf(_sharedContactIds, contactId); + return index >= 0 ? _sharedContactNames[index] : "Unknown Contact"; + } + + private string GetProductNameById(Guid productId) + { + var index = Array.IndexOf(_sharedProductIds, productId); + return index >= 0 ? _sharedProductNames[index] : "Unknown Product"; + } + + private Dictionary ParseQueryString(string query) + { + var result = new Dictionary(); + if (string.IsNullOrEmpty(query)) return result; + + query = query.TrimStart('?'); + var pairs = query.Split('&'); + + foreach (var pair in pairs) + { + var parts = pair.Split('='); + if (parts.Length == 2) + { + result[parts[0]] = Uri.UnescapeDataString(parts[1]); + } + } + + return result; + } + + private int GetIntParameter(Dictionary query, string key, int defaultValue, int min, int max) + { + if (query.TryGetValue(key, out string value) && int.TryParse(value, out int result)) + { + return Math.Max(min, Math.Min(max, result)); + } + return defaultValue; + } + + private string DecodeOperationId(string operationId) + { + // Power Platform connectors typically pass operation IDs directly + // If it looks like base64, try to decode it, otherwise return as-is + if (string.IsNullOrEmpty(operationId)) + return operationId; + + // Check if it's a valid operation name pattern + if (operationId.All(c => char.IsLetterOrDigit(c) || c == '_')) + return operationId; + + try + { + byte[] data = Convert.FromBase64String(operationId); + var decoded = Encoding.UTF8.GetString(data); + // Return decoded only if it looks like a valid operation name + if (decoded.All(c => char.IsLetterOrDigit(c) || c == '_')) + return decoded; + } + catch (FormatException) + { + // Not base64, ignore + } + + return operationId; + } + + private HttpResponseMessage CreateJsonResponse(object data) + { + var json = JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented); + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(json, Encoding.UTF8, "application/json") + }; + return response; + } + + private HttpResponseMessage CreateErrorResponse(string message) + { + var error = new { error = new { message = message } }; + var json = JsonConvert.SerializeObject(error); + var response = new HttpResponseMessage(HttpStatusCode.BadRequest) + { + Content = new StringContent(json, Encoding.UTF8, "application/json") + }; + return response; + } + + // ================================================================================================ + // UTILITY METHODS + // ================================================================================================ + + private static string GetRandomItem(T[] array, Random random = null) + { + var rnd = random ?? _random; + return array[rnd.Next(array.Length)].ToString(); + } + + private static DateTime GenerateRandomDate(DateTime start, DateTime end, Random random = null) + { + var rnd = random ?? _random; + var range = end - start; + var randomDays = rnd.Next((int)range.TotalDays); + return start.AddDays(randomDays); + } + + private static (string city, string stateOrProvince, string country) GetRandomLocation(Random random = null) + { + var rnd = random ?? _random; + return Locations[rnd.Next(Locations.Length)]; + } + + private static string GeneratePostalCode(string country, Random random = null) + { + var rnd = random ?? _random; + char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(); + switch (country.ToUpper()) + { + case "USA": + return $"{rnd.Next(10000, 99999)}"; + case "CANADA": + return $"{letters[rnd.Next(letters.Length)]}{rnd.Next(0, 9)}{letters[rnd.Next(letters.Length)]} {rnd.Next(0, 9)}{letters[rnd.Next(letters.Length)]}{rnd.Next(0, 9)}"; + case "UK": + return $"{letters[rnd.Next(letters.Length)]}{letters[rnd.Next(letters.Length)]}{rnd.Next(1, 99)} {rnd.Next(0, 9)}{letters[rnd.Next(letters.Length)]}{letters[rnd.Next(letters.Length)]}"; + case "AUSTRALIA": + return $"{rnd.Next(1000, 9999)}"; + default: + return $"{rnd.Next(10000, 99999)}"; + } + } + + private static string GeneratePhoneNumber(Random random = null) + { + var rnd = random ?? _random; + return $"({rnd.Next(200, 999)}) {rnd.Next(200, 999)}-{rnd.Next(1000, 9999)}"; + } + + private static string GenerateEmail(string firstName, string lastName, string companyName = null) + { + var domain = companyName != null + ? companyName.ToLower().Replace(" ", "").Replace("inc", "").Replace("corp", "").Replace(".", "") + ".com" + : GetRandomItem(new[] { "gmail.com", "outlook.com", "yahoo.com", "company.com", "email.com" }); + + return $"{firstName.ToLower()}.{lastName.ToLower()}@{domain}"; + } + + // ================================================================================================ + // BUSINESS CENTRAL GENERATORS + // ================================================================================================ + + private object[] GenerateBusinessCentralCustomers(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + id = $"C{i:D6}", + displayName = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + type = "Customer", + addressLine1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + city = GetRandomLocation().city, + state = GetRandomLocation().stateOrProvince, + country = GetRandomLocation().country, + postalCode = GeneratePostalCode("USA"), + phoneNumber = GeneratePhoneNumber(), + email = GenerateEmail(GetRandomItem(FirstNames), GetRandomItem(LastNames)), + customerGroup = GetRandomItem(BCCustomerGroups), + paymentTerms = GetRandomItem(BCPaymentTerms), + currencyCode = GetRandomItem(BCCurrencyCodes), + creditLimit = random.Next(1000, 100000), + blocked = random.NextDouble() < 0.05, + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateBusinessCentralVendors(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + id = $"V{i:D6}", + displayName = GetRandomItem(CompanyNames), + addressLine1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + city = GetRandomLocation().city, + state = GetRandomLocation().stateOrProvince, + country = GetRandomLocation().country, + postalCode = GeneratePostalCode("USA"), + phoneNumber = GeneratePhoneNumber(), + email = GenerateEmail("info", "contact", GetRandomItem(CompanyNames)), + paymentTerms = GetRandomItem(BCPaymentTerms), + currencyCode = GetRandomItem(BCCurrencyCodes), + blocked = random.NextDouble() < 0.03, + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateBusinessCentralItems(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + id = $"ITEM{i:D6}", + displayName = $"Product {i}", + type = "Inventory", + itemCategory = GetRandomItem(BCItemCategories), + blocked = random.NextDouble() < 0.02, + unitPrice = Math.Round(random.NextDouble() * 1000 + 10, 2), + unitCost = Math.Round(random.NextDouble() * 500 + 5, 2), + inventory = random.Next(0, 1000), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateBusinessCentralSalesOrders(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + id = $"SO{i:D6}", + number = $"SO{i:D6}", + customerId = $"C{random.Next(1, 1000):D6}", + customerName = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + orderDate = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + requestedDeliveryDate = GenerateRandomDate(DateTime.Now, DateTime.Now.AddDays(30)), + status = GetRandomItem(new[] { "Draft", "Open", "Released", "Pending Approval", "Pending Prepayment" }), + currencyCode = GetRandomItem(BCCurrencyCodes), + totalAmountExcludingTax = Math.Round(random.NextDouble() * 10000 + 100, 2), + totalAmountIncludingTax = Math.Round(random.NextDouble() * 12000 + 120, 2), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 30)) + }).ToArray(); + } + + private object[] GenerateBusinessCentralPurchaseOrders(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + id = $"PO{i:D6}", + number = $"PO{i:D6}", + vendorId = $"V{random.Next(1, 500):D6}", + vendorName = GetRandomItem(CompanyNames), + orderDate = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + expectedReceiptDate = GenerateRandomDate(DateTime.Now, DateTime.Now.AddDays(30)), + status = GetRandomItem(new[] { "Draft", "Open", "Released", "Pending Approval" }), + currencyCode = GetRandomItem(BCCurrencyCodes), + totalAmountExcludingTax = Math.Round(random.NextDouble() * 15000 + 200, 2), + totalAmountIncludingTax = Math.Round(random.NextDouble() * 18000 + 240, 2), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 30)) + }).ToArray(); + } + + // ================================================================================================ + // SUPPLY CHAIN GENERATORS + // ================================================================================================ + + private object[] GenerateSupplyChainWarehouses(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + return new + { + id = $"WH{i:D3}", + name = $"{GetRandomItem(SupplyChainWarehouseTypes)} - {location.city}", + type = GetRandomItem(SupplyChainWarehouseTypes), + address = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + city = location.city, + state = location.stateOrProvince, + country = location.country, + postalCode = GeneratePostalCode(location.country), + manager = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + capacity = random.Next(5000, 100000), + status = GetRandomItem(new[] { "Active", "Inactive", "Maintenance" }), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }; + }).ToArray(); + } + + private object[] GenerateSupplyChainInventoryItems(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + itemNumber = $"ITM{i:D6}", + itemName = $"{GetRandomItem(SupplyChainCategories)} Item {i}", + description = $"High quality item for {GetRandomItem(SupplyChainItemGroups).ToLower()} use", + itemGroup = GetRandomItem(SupplyChainItemGroups), + itemType = GetRandomItem(SupplyChainItemTypes), + unitOfMeasure = GetRandomItem(SupplyChainUnitsOfMeasure), + standardCost = Math.Round(random.NextDouble() * 500 + 10, 2), + listPrice = Math.Round(random.NextDouble() * 800 + 15, 2), + category = GetRandomItem(SupplyChainCategories), + status = GetRandomItem(new[] { "Active", "Inactive", "Discontinued" }), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateSupplyChainPurchaseRequisitions(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + requisitionNumber = $"REQ{i:D6}", + requestor = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + department = GetRandomItem(new[] { "Production", "Maintenance", "IT", "Office", "Quality" }), + requisitionDate = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + requiredDate = GenerateRandomDate(DateTime.Now, DateTime.Now.AddDays(21)), + priority = GetRandomItem(SupplyChainRequisitionPriorities), + totalAmount = Math.Round(random.NextDouble() * 50000 + 1000, 2), + currency = GetRandomItem(BCCurrencyCodes), + status = GetRandomItem(new[] { "Draft", "Submitted", "Approved", "Rejected", "Ordered" }), + approver = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 30)) + }).ToArray(); + } + + private object[] GenerateSupplyChainProductionOrders(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + productionOrderNumber = $"PO{i:D6}", + item = $"ITM{random.Next(100000, 999999)}", + quantity = random.Next(50, 1000), + unitOfMeasure = GetRandomItem(SupplyChainUnitsOfMeasure), + startDate = GenerateRandomDate(DateTime.Now.AddDays(-14), DateTime.Now.AddDays(30)), + endDate = GenerateRandomDate(DateTime.Now, DateTime.Now.AddDays(44)), + priority = GetRandomItem(SupplyChainRequisitionPriorities), + status = GetRandomItem(SupplyChainProductionStatuses), + warehouse = $"WH{random.Next(1, 10):D2}", + productionManager = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + estimatedCost = Math.Round(random.NextDouble() * 25000 + 1000, 2), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 30)) + }).ToArray(); + } + + private object[] GenerateSupplyChainBillOfMaterials(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + bomNumber = $"BOM{i:D6}", + parentItem = $"ITM{random.Next(100000, 999999)}", + componentItem = $"ITM{random.Next(100000, 999999)}", + quantity = Math.Round(random.NextDouble() * 10 + 0.1, 3), + unitOfMeasure = GetRandomItem(SupplyChainUnitsOfMeasure), + bomType = GetRandomItem(SupplyChainBOMTypes), + version = $"V{random.Next(1, 10)}.{random.Next(0, 9)}", + status = GetRandomItem(new[] { "Active", "Inactive", "Under Review", "Approved" }), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateSupplyChainInventoryTransactions(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + transactionNumber = $"TXN{i:D8}", + transactionType = GetRandomItem(SupplyChainTransactionTypes), + item = $"ITM{random.Next(100000, 999999)}", + quantity = random.Next(1, 500), + unitOfMeasure = GetRandomItem(SupplyChainUnitsOfMeasure), + unitCost = Math.Round(random.NextDouble() * 100 + 5, 2), + warehouse = $"WH{random.Next(1, 10):D2}", + direction = GetRandomItem(SupplyChainDirections), + transactionDate = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 30)) + }).ToArray(); + } + + // ================================================================================================ + // FIELD SERVICE GENERATORS + // ================================================================================================ + + private object[] GenerateFieldServiceWorkOrders(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + workOrderNumber = $"WO{i:D6}", + workOrderType = GetRandomItem(FSWorkOrderTypes), + priority = GetRandomItem(FSPriorities), + status = GetRandomItem(FSServiceStatuses), + serviceAccount = GetRandomItem(CompanyNames), + primaryResource = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + scheduledStart = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now.AddDays(14)), + scheduledEnd = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now.AddDays(14)), + address = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + city = GetRandomLocation().city, + estimatedDuration = random.Next(60, 480), // minutes + actualDuration = random.Next(45, 520), // minutes + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 30)) + }).ToArray(); + } + + private object[] GenerateFieldServiceResources(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + resourceId = $"RES{i:D4}", + name = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + resourceType = GetRandomItem(FSResourceTypes), + primarySkill = GetRandomItem(FSSkills), + territory = GetRandomLocation().city, + phoneNumber = GeneratePhoneNumber(), + email = GenerateEmail(GetRandomItem(FirstNames), GetRandomItem(LastNames)), + hourlyRate = Math.Round(random.NextDouble() * 100 + 25, 2), + isActive = random.NextDouble() < 0.9, + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateFieldServiceEquipment(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + equipmentId = $"EQ{i:D6}", + name = $"{GetRandomItem(FSEquipmentTypes)} {i}", + equipmentType = GetRandomItem(FSEquipmentTypes), + serialNumber = $"SN{random.Next(100000, 999999)}", + manufacturer = GetRandomItem(CompanyNames), + model = $"Model-{random.Next(100, 999)}", + installDate = GenerateRandomDate(DateTime.Now.AddDays(-1825), DateTime.Now.AddDays(-30)), + warrantyExpiration = GenerateRandomDate(DateTime.Now.AddDays(-365), DateTime.Now.AddDays(365)), + serviceAccount = GetRandomItem(CompanyNames), + location = GetRandomLocation().city, + status = GetRandomItem(new[] { "Active", "Inactive", "Under Maintenance", "Retired" }), + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + private object[] GenerateFieldServiceServiceAccounts(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + return new + { + accountId = $"SA{i:D6}", + accountName = GetRandomItem(CompanyNames), + primaryContact = $"{GetRandomItem(FirstNames)} {GetRandomItem(LastNames)}", + address = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + city = location.city, + state = location.stateOrProvince, + country = location.country, + postalCode = GeneratePostalCode(location.country), + phoneNumber = GeneratePhoneNumber(), + email = GenerateEmail("contact", "info", GetRandomItem(CompanyNames)), + industry = GetRandomItem(Industries), + serviceTerritory = location.city, + isActive = random.NextDouble() < 0.95, + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }; + }).ToArray(); + } + + private object[] GenerateFieldServiceProducts(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => new + { + productId = $"PROD{i:D6}", + productName = $"Service Product {i}", + productType = GetRandomItem(new[] { "Inventory", "Non-Inventory", "Service" }), + category = GetRandomItem(SupplyChainCategories), + unitOfMeasure = GetRandomItem(SupplyChainUnitsOfMeasure), + listPrice = Math.Round(random.NextDouble() * 500 + 10, 2), + standardCost = Math.Round(random.NextDouble() * 300 + 5, 2), + vendor = GetRandomItem(CompanyNames), + isActive = random.NextDouble() < 0.9, + lastModifiedDateTime = DateTime.Now.AddDays(-random.Next(1, 365)) + }).ToArray(); + } + + // ================================================================================================ + // DATAVERSE GENERATORS + // ================================================================================================ + + private object[] GenerateDataverseAccounts(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(random); + // Use shared Account ID from pool if available, otherwise generate new + var accountId = i <= _sharedAccountIds.Length ? _sharedAccountIds[i - 1] : Guid.NewGuid(); + var companyName = i <= _sharedAccountNames.Length ? _sharedAccountNames[i - 1] : GetRandomItem(CompanyNames, random); + + return new + { + accountid = accountId.ToString(), + name = companyName, + accountnumber = $"ACC{i:D6}", + telephone1 = GeneratePhoneNumber(random), + emailaddress1 = GenerateEmail("info", "contact", companyName), + websiteurl = $"https://www.{companyName.ToLower().Replace(" ", "").Replace("inc", "").Replace("corp", "")}.com", + address1_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames, random)}", + address1_city = location.city, + address1_stateorprovince = location.stateOrProvince, + address1_country = location.country, + address1_postalcode = GeneratePostalCode(location.country, random), + industrycode = random.Next(1, 20), // Industry picklist value + revenue = Math.Round(random.NextDouble() * 10000000 + 100000, 2), + numberofemployees = random.Next(10, 5000), + description = $"Leading {GetRandomItem(Industries, random).ToLower()} company providing innovative solutions", + statecode = 0, // Active + statuscode = 1, // Active status + createdon = GenerateRandomDate(DateTime.Now.AddDays(-365), DateTime.Now, random), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now, random) + }; + }).ToArray(); + } + + private object[] GenerateDataverseContacts(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(random); + var firstName = GetRandomItem(FirstNames, random); + var lastName = GetRandomItem(LastNames, random); + var parentAccountId = GetRandomSharedAccountId(random); + + return new + { + contactid = Guid.NewGuid().ToString(), + firstname = firstName, + lastname = lastName, + fullname = $"{firstName} {lastName}", + emailaddress1 = GenerateEmail(firstName, lastName), + telephone1 = GeneratePhoneNumber(random), + mobilephone = GeneratePhoneNumber(random), + jobtitle = GetRandomItem(JobTitles, random), + department = GetRandomItem(Departments, random), + parentcustomerid = parentAccountId.ToString(), + parentcustomername = GetAccountNameById(parentAccountId), + address1_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames, random)}", + address1_city = location.city, + address1_stateorprovince = location.stateOrProvince, + address1_country = location.country, + address1_postalcode = GeneratePostalCode(location.country, random), + birthdate = GenerateRandomDate(DateTime.Now.AddYears(-65), DateTime.Now.AddYears(-25), random), + gendercode = random.Next(1, 3), + statecode = 0, // Active + statuscode = 1, // Active status + createdon = GenerateRandomDate(DateTime.Now.AddDays(-365), DateTime.Now, random), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now, random) + }; + }).ToArray(); + } + + private object[] GenerateDataverseLeads(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + var firstName = GetRandomItem(FirstNames); + var lastName = GetRandomItem(LastNames); + return new + { + leadid = Guid.NewGuid().ToString(), + firstname = firstName, + lastname = lastName, + fullname = $"{firstName} {lastName}", + emailaddress1 = GenerateEmail(firstName, lastName), + telephone1 = GeneratePhoneNumber(), + mobilephone = GeneratePhoneNumber(), + jobtitle = GetRandomItem(JobTitles), + companyname = GetRandomItem(CompanyNames), + websiteurl = $"https://www.{GetRandomItem(CompanyNames).ToLower().Replace(" ", "")}.com", + address1_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + address1_city = location.city, + address1_stateorprovince = location.stateOrProvince, + address1_country = location.country, + address1_postalcode = GeneratePostalCode(location.country), + revenue = Math.Round(random.NextDouble() * 5000000 + 50000, 2), + numberofemployees = random.Next(1, 1000), + industrycode = random.Next(1, 20), + leadqualitycode = random.Next(1, 4), + leadsourcecode = random.Next(1, 8), + statecode = 0, // Open + statuscode = 1, // New + createdon = GenerateRandomDate(DateTime.Now.AddDays(-180), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseOpportunities(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + opportunityid = Guid.NewGuid().ToString(), + name = $"{GetRandomItem(Products)} Deal - {GetRandomItem(CompanyNames)}", + customerid = Guid.NewGuid().ToString(), + accountid = Guid.NewGuid().ToString(), + contactid = Guid.NewGuid().ToString(), + estimatedvalue = Math.Round(random.NextDouble() * 1000000 + 10000, 2), + actualvalue = Math.Round(random.NextDouble() * 500000 + 5000, 2), + budgetamount = Math.Round(random.NextDouble() * 1200000 + 15000, 2), + estimatedclosedate = GenerateRandomDate(DateTime.Now.AddDays(30), DateTime.Now.AddDays(180)), + actualclosedate = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now.AddDays(60)), + closeprobability = random.Next(10, 95), + salesstage = random.Next(1, 7), + stepname = GetRandomItem(OpportunityStages), + statecode = 0, // Open + statuscode = 1, // In Progress + createdon = GenerateRandomDate(DateTime.Now.AddDays(-365), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseCases(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + incidentid = Guid.NewGuid().ToString(), + ticketnumber = $"CAS-{random.Next(100000, 999999)}", + title = GetRandomItem(CaseTypes), + description = $"Customer reported issue with {GetRandomItem(Products)}. Investigation required.", + customerid = Guid.NewGuid().ToString(), + contactid = Guid.NewGuid().ToString(), + accountid = Guid.NewGuid().ToString(), + caseorigincode = random.Next(1, 6), + casetypecode = random.Next(1, 4), + prioritycode = random.Next(1, 4), + severitycode = random.Next(1, 4), + statecode = 0, // Active + statuscode = 1, // In Progress + escalated = random.Next(0, 2) == 1, + followupby = GenerateRandomDate(DateTime.Now.AddDays(1), DateTime.Now.AddDays(30)), + createdon = GenerateRandomDate(DateTime.Now.AddDays(-90), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseProducts(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + productid = Guid.NewGuid().ToString(), + name = GetRandomItem(Products), + productnumber = $"PRD-{i:D4}", + description = $"High-quality {GetRandomItem(Products)} for enterprise use", + price = Math.Round(random.NextDouble() * 10000 + 100, 2), + standardcost = Math.Round(random.NextDouble() * 5000 + 50, 2), + currentcost = Math.Round(random.NextDouble() * 5500 + 60, 2), + listprice = Math.Round(random.NextDouble() * 12000 + 120, 2), + quantityonhand = random.Next(0, 1000), + quantityallocated = random.Next(0, 100), + productstructure = random.Next(1, 4), + producttypecode = random.Next(1, 5), + vendorname = GetRandomItem(CompanyNames), + vendorpartnumber = $"VPN-{random.Next(10000, 99999)}", + statecode = 0, // Active + statuscode = 1, // Active + createdon = GenerateRandomDate(DateTime.Now.AddDays(-730), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseQuotes(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + quoteid = Guid.NewGuid().ToString(), + quotenumber = $"QUO-{random.Next(100000, 999999)}", + name = $"Quote for {GetRandomItem(CompanyNames)} - {GetRandomItem(Products)}", + customerid = Guid.NewGuid().ToString(), + accountid = Guid.NewGuid().ToString(), + contactid = Guid.NewGuid().ToString(), + opportunityid = Guid.NewGuid().ToString(), + totalamount = Math.Round(random.NextDouble() * 500000 + 10000, 2), + totallineitemamount = Math.Round(random.NextDouble() * 450000 + 9000, 2), + totaltax = Math.Round(random.NextDouble() * 50000 + 1000, 2), + totaldiscountamount = Math.Round(random.NextDouble() * 25000, 2), + freightamount = Math.Round(random.NextDouble() * 5000, 2), + effectivefrom = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + effectiveto = GenerateRandomDate(DateTime.Now.AddDays(30), DateTime.Now.AddDays(90)), + requestdeliveryby = GenerateRandomDate(DateTime.Now.AddDays(45), DateTime.Now.AddDays(120)), + statecode = 0, // Draft + statuscode = 1, // Draft + revisionnumber = random.Next(1, 5), + createdon = GenerateRandomDate(DateTime.Now.AddDays(-60), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseOrders(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + salesorderid = Guid.NewGuid().ToString(), + ordernumber = $"ORD-{random.Next(100000, 999999)}", + name = $"Order for {GetRandomItem(CompanyNames)} - {GetRandomItem(Products)}", + customerid = Guid.NewGuid().ToString(), + accountid = Guid.NewGuid().ToString(), + contactid = Guid.NewGuid().ToString(), + opportunityid = Guid.NewGuid().ToString(), + quoteid = Guid.NewGuid().ToString(), + totalamount = Math.Round(random.NextDouble() * 750000 + 15000, 2), + totallineitemamount = Math.Round(random.NextDouble() * 700000 + 14000, 2), + totaltax = Math.Round(random.NextDouble() * 75000 + 1500, 2), + totaldiscountamount = Math.Round(random.NextDouble() * 37500, 2), + freightamount = Math.Round(random.NextDouble() * 7500, 2), + datedelivered = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now.AddDays(30)), + requestdeliveryby = GenerateRandomDate(DateTime.Now.AddDays(15), DateTime.Now.AddDays(60)), + submitdate = GenerateRandomDate(DateTime.Now.AddDays(-14), DateTime.Now), + statecode = 0, // Active + statuscode = 1, // New + ispricelocked = random.Next(0, 2) == 1, + createdon = GenerateRandomDate(DateTime.Now.AddDays(-90), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseCampaigns(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + campaignid = Guid.NewGuid().ToString(), + name = GetRandomItem(CampaignNames), + codename = $"CAMP-{i:D4}", + description = $"Marketing campaign targeting {GetRandomItem(Departments)} segment", + budgetallocatedamount = Math.Round(random.NextDouble() * 500000 + 10000, 2), + actualcost = Math.Round(random.NextDouble() * 400000 + 8000, 2), + expectedrevenue = Math.Round(random.NextDouble() * 1000000 + 50000, 2), + actualrevenue = Math.Round(random.NextDouble() * 800000 + 40000, 2), + proposedstart = GenerateRandomDate(DateTime.Now.AddDays(-60), DateTime.Now.AddDays(30)), + proposedend = GenerateRandomDate(DateTime.Now.AddDays(30), DateTime.Now.AddDays(180)), + actualstart = GenerateRandomDate(DateTime.Now.AddDays(-45), DateTime.Now.AddDays(15)), + actualend = GenerateRandomDate(DateTime.Now.AddDays(45), DateTime.Now.AddDays(210)), + typecode = random.Next(1, 6), + statecode = 0, // Active + statuscode = 1, // Proposed + expectedresponse = random.Next(5, 25), + otherexpenses = Math.Round(random.NextDouble() * 25000, 2), + promotioncodename = $"PROMO{random.Next(100, 999)}", + createdon = GenerateRandomDate(DateTime.Now.AddDays(-180), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-14), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseCompetitors(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + return new + { + competitorid = Guid.NewGuid().ToString(), + name = GetRandomItem(CompanyNames), + overview = $"Major competitor in the {GetRandomItem(Departments)} market segment", + strengths = "Strong market presence, competitive pricing, good customer service", + weaknesses = "Limited product range, slower innovation cycle", + opportunities = "Expanding into new markets, digital transformation", + threats = "Economic downturn, increased competition, regulatory changes", + keyproduct = GetRandomItem(Products), + websiteurl = $"https://www.{GetRandomItem(CompanyNames).ToLower().Replace(" ", "")}.com", + address1_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + address1_city = location.city, + address1_stateorprovince = location.stateOrProvince, + address1_country = location.country, + address1_postalcode = GeneratePostalCode(location.country), + stockexchange = GetRandomItem(StockExchanges), + tickersymbol = $"{GetRandomItem(CompanyNames).Substring(0, 3).ToUpper()}{random.Next(10, 99)}", + createdon = GenerateRandomDate(DateTime.Now.AddDays(-730), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseInvoices(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + return new + { + invoiceid = Guid.NewGuid().ToString(), + invoicenumber = $"INV-{random.Next(100000, 999999)}", + name = $"Invoice for {GetRandomItem(CompanyNames)} - {GetRandomItem(Products)}", + customerid = Guid.NewGuid().ToString(), + accountid = Guid.NewGuid().ToString(), + contactid = Guid.NewGuid().ToString(), + salesorderid = Guid.NewGuid().ToString(), + totalamount = Math.Round(random.NextDouble() * 1000000 + 20000, 2), + totallineitemamount = Math.Round(random.NextDouble() * 950000 + 19000, 2), + totaltax = Math.Round(random.NextDouble() * 100000 + 2000, 2), + totaldiscountamount = Math.Round(random.NextDouble() * 50000, 2), + freightamount = Math.Round(random.NextDouble() * 10000, 2), + datedelivered = GenerateRandomDate(DateTime.Now.AddDays(-60), DateTime.Now), + duedate = GenerateRandomDate(DateTime.Now.AddDays(15), DateTime.Now.AddDays(45)), + invoicedate = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + statecode = 0, // Active + statuscode = 1, // New + ispricelocked = random.Next(0, 2) == 1, + billto_name = GetRandomItem(CompanyNames), + billto_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + billto_city = location.city, + billto_stateorprovince = location.stateOrProvince, + billto_postalcode = GeneratePostalCode(location.country), + billto_country = location.country, + createdon = GenerateRandomDate(DateTime.Now.AddDays(-90), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseActivities(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + activityid = Guid.NewGuid().ToString(), + subject = GetRandomItem(ActivityTypes), + description = $"Follow up activity regarding {GetRandomItem(Products)} discussion", + regardingobjectid = Guid.NewGuid().ToString(), + ownerid = Guid.NewGuid().ToString(), + actualstart = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now), + actualend = GenerateRandomDate(DateTime.Now.AddDays(-29), DateTime.Now.AddDays(1)), + scheduledstart = GenerateRandomDate(DateTime.Now.AddDays(-35), DateTime.Now.AddDays(-5)), + scheduledend = GenerateRandomDate(DateTime.Now.AddDays(-34), DateTime.Now.AddDays(-4)), + actualdurationminutes = random.Next(15, 240), + scheduleddurationminutes = random.Next(30, 180), + prioritycode = random.Next(0, 3), + statecode = 0, // Open + statuscode = 1, // Open + activitytypecode = GetRandomItem(ActivityTypes), + isbilled = random.Next(0, 2) == 1, + isworkflowcreated = random.Next(0, 2) == 1, + createdon = GenerateRandomDate(DateTime.Now.AddDays(-180), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-7), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseTeams(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + return new + { + teamid = Guid.NewGuid().ToString(), + name = $"{GetRandomItem(Departments)} Team", + description = $"Responsible for {GetRandomItem(Departments)} operations and strategy", + teamtype = random.Next(0, 4), + businessunitid = Guid.NewGuid().ToString(), + administratorid = Guid.NewGuid().ToString(), + emailaddress = GenerateEmail("team", GetRandomItem(Departments)), + regardingobjectid = Guid.NewGuid().ToString(), + isdefault = random.Next(0, 2) == 1, + systemmanaged = random.Next(0, 2) == 1, + queueid = Guid.NewGuid().ToString(), + address1_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + address1_city = location.city, + address1_stateorprovince = location.stateOrProvince, + address1_country = location.country, + address1_postalcode = GeneratePostalCode(location.country), + createdon = GenerateRandomDate(DateTime.Now.AddDays(-1095), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseTerritories(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + territoryid = Guid.NewGuid().ToString(), + name = $"{GetRandomItem(new[] { "North", "South", "East", "West", "Central" })} {GetRandomItem(new[] { "Region", "Territory", "District", "Zone" })}", + description = $"Sales territory covering multiple states and regions", + managerid = Guid.NewGuid().ToString(), + organizationid = Guid.NewGuid().ToString(), + createdon = GenerateRandomDate(DateTime.Now.AddDays(-1095), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-90), DateTime.Now), + createdby = Guid.NewGuid().ToString(), + modifiedby = Guid.NewGuid().ToString(), + versionnumber = random.Next(1000000, 9999999), + importsequencenumber = random.Next(1, 999999), + overriddencreatedon = GenerateRandomDate(DateTime.Now.AddDays(-1100), DateTime.Now.AddDays(-1095)), + timezoneruleversionnumber = random.Next(1, 100), + utcconversiontimezonecode = random.Next(-12, 14) + }; + }).ToArray(); + } + + private object[] GenerateDataverseKnowledgeArticles(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + return new + { + knowledgearticleid = Guid.NewGuid().ToString(), + title = $"How to {GetRandomItem(KnowledgeTopics)}", + articlepublicnumber = $"KB{random.Next(100000, 999999)}", + description = $"Comprehensive guide on {GetRandomItem(KnowledgeTopics)} best practices", + content = $"This article provides detailed information about {GetRandomItem(KnowledgeTopics)}. Follow these steps...", + keywords = $"{GetRandomItem(KnowledgeTopics)}, guide, tutorial, help", + majorversionnumber = random.Next(1, 5), + minorversionnumber = random.Next(0, 10), + languagelocaleid = 1033, // English (United States) + publishedon = GenerateRandomDate(DateTime.Now.AddDays(-365), DateTime.Now), + expirationdate = GenerateRandomDate(DateTime.Now.AddDays(365), DateTime.Now.AddDays(1095)), + statecode = 3, // Published + statuscode = 7, // Published + rating = Math.Round(random.NextDouble() * 4 + 1, 1), + ratingcount = random.Next(0, 100), + ratingsum = random.Next(0, 500), + isinternal = random.Next(0, 2) == 1, + islatestversion = random.Next(0, 2) == 1, + isprimary = random.Next(0, 2) == 1, + isrootarticle = random.Next(0, 2) == 1, + readyforreview = random.Next(0, 2) == 1, + review = random.Next(0, 3), + createdon = GenerateRandomDate(DateTime.Now.AddDays(-730), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } + + private object[] GenerateDataverseContracts(int count, Random random) + { + return Enumerable.Range(1, count).Select(i => { + var location = GetRandomLocation(); + return new + { + contractid = Guid.NewGuid().ToString(), + contractnumber = $"CON-{random.Next(100000, 999999)}", + title = $"Service Contract - {GetRandomItem(CompanyNames)}", + customerid = Guid.NewGuid().ToString(), + accountid = Guid.NewGuid().ToString(), + contactid = Guid.NewGuid().ToString(), + contracttemplateid = Guid.NewGuid().ToString(), + totalvalue = Math.Round(random.NextDouble() * 2000000 + 50000, 2), + totalrevenue = Math.Round(random.NextDouble() * 1800000 + 45000, 2), + netprice = Math.Round(random.NextDouble() * 1500000 + 40000, 2), + activeon = GenerateRandomDate(DateTime.Now.AddDays(-365), DateTime.Now), + expireson = GenerateRandomDate(DateTime.Now.AddDays(365), DateTime.Now.AddDays(1095)), + cancelon = GenerateRandomDate(DateTime.Now.AddDays(400), DateTime.Now.AddDays(1200)), + contractservicelevelcode = random.Next(1, 4), + contracttypecode = random.Next(1, 5), + billingcustomerid = Guid.NewGuid().ToString(), + billingaccountid = Guid.NewGuid().ToString(), + billingcontactid = Guid.NewGuid().ToString(), + billtoaddress_line1 = $"{random.Next(100, 9999)} {GetRandomItem(StreetNames)}", + billtoaddress_city = location.city, + billtoaddress_stateorprovince = location.stateOrProvince, + billtoaddress_country = location.country, + billtoaddress_postalcode = GeneratePostalCode(location.country), + statecode = 0, // Draft + statuscode = 1, // Draft + createdon = GenerateRandomDate(DateTime.Now.AddDays(-400), DateTime.Now), + modifiedon = GenerateRandomDate(DateTime.Now.AddDays(-30), DateTime.Now) + }; + }).ToArray(); + } +} \ No newline at end of file From 2cb956b068243f663e30ce6154bd1e312c8f8460 Mon Sep 17 00:00:00 2001 From: Troy Simeon Taylor <44444967+troystaylor@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:39:23 -0400 Subject: [PATCH 2/2] Add files via upload --- .../Mock Data Generator/ConnectorPackage.zip | Bin 0 -> 32981 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 independent-publisher-connectors/Mock Data Generator/ConnectorPackage.zip diff --git a/independent-publisher-connectors/Mock Data Generator/ConnectorPackage.zip b/independent-publisher-connectors/Mock Data Generator/ConnectorPackage.zip new file mode 100644 index 0000000000000000000000000000000000000000..7d5c35b38003c55510e8875e85356d6bb553d4b1 GIT binary patch literal 32981 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 J(g6)19ssJJ8ax01 literal 0 HcmV?d00001