Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions logicapp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Logic App SAP to SQL Integration Template

This Bicep template creates an Azure Logic App (Standard) that receives data from an SAP system and moves it to a SQL Database.

## Architecture

The template deploys the following Azure resources:

- **Logic App Standard** - Hosts the workflow that processes SAP data and writes to SQL
- **App Service Plan (WorkflowStandard)** - Provides compute resources for the Logic App
- **Storage Account** - Required for Logic App Standard runtime state and configuration
- **SQL Server** - Database server to store the SAP data
- **SQL Database** - Database to hold the processed SAP data
- **SQL Firewall Rule** - Allows Azure services to access the SQL Server

## Deployment

### Prerequisites

- Azure CLI or Azure PowerShell
- Bicep CLI
- An Azure subscription with appropriate permissions

### Parameters

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `resourceLocation` | string | Azure region for deployment | `swedencentral` |
| `sapConnectionString` | string | Connection string for SAP system | `''` |
| `sqlServerAdminLogin` | string | SQL Server administrator login | `sqladmin` |
| `sqlServerAdminPassword` | securestring | SQL Server administrator password | Required |

### Deploy the template

```bash
# Deploy using Azure CLI
az deployment sub create \
--location swedencentral \
--template-file main.bicep \
--parameters sqlServerAdminPassword='YourSecurePassword123!'

# Deploy with custom parameters
az deployment sub create \
--location swedencentral \
--template-file main.bicep \
--parameters resourceLocation='westeurope' \
sqlServerAdminLogin='myadmin' \
sqlServerAdminPassword='YourSecurePassword123!' \
sapConnectionString='your-sap-connection-string'
```

## Workflow

The Logic App includes a sample workflow (`workflow.json`) that:

1. **Receives SAP Data** - HTTP trigger accepts JSON data from SAP system
2. **Parses Data** - Validates and extracts required fields
3. **Validates Fields** - Ensures required fields are present
4. **Inserts to SQL** - Calls stored procedure to insert data into SQL Database
5. **Returns Response** - Sends success/error response back to SAP system

### Expected SAP Data Format

```json
{
"sapData": {
"documentType": "INVOICE",
"documentNumber": "INV-2024-001",
"customerCode": "CUST001",
"amount": 1500.00,
"currency": "USD",
"date": "2024-08-04T10:30:00Z",
"description": "Product sale invoice"
}
}
```

### SQL Database Setup

Create the following table and stored procedure in your SQL Database:

```sql
-- Create table to store SAP data
CREATE TABLE [dbo].[SAPData] (
[Id] INT IDENTITY(1,1) PRIMARY KEY,
[DocumentType] NVARCHAR(50) NOT NULL,
[DocumentNumber] NVARCHAR(100) NOT NULL UNIQUE,
[CustomerCode] NVARCHAR(50) NOT NULL,
[Amount] DECIMAL(18,2) NOT NULL,
[Currency] NVARCHAR(3) NOT NULL,
[DocumentDate] DATETIME2 NOT NULL,
[Description] NVARCHAR(500),
[ProcessedDate] DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
[CreatedAt] DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);

-- Create stored procedure to insert data
CREATE PROCEDURE [dbo].[InsertSAPData]
@DocumentType NVARCHAR(50),
@DocumentNumber NVARCHAR(100),
@CustomerCode NVARCHAR(50),
@Amount DECIMAL(18,2),
@Currency NVARCHAR(3),
@DocumentDate DATETIME2,
@Description NVARCHAR(500) = NULL,
@ProcessedDate DATETIME2
AS
BEGIN
SET NOCOUNT ON;

INSERT INTO [dbo].[SAPData] (
[DocumentType],
[DocumentNumber],
[CustomerCode],
[Amount],
[Currency],
[DocumentDate],
[Description],
[ProcessedDate]
)
VALUES (
@DocumentType,
@DocumentNumber,
@CustomerCode,
@Amount,
@Currency,
@DocumentDate,
@Description,
@ProcessedDate
);
END
```

## Configuration

After deployment:

1. **Configure SAP Connection** - Update the Logic App's SAP connection settings
2. **Set up SQL Connection** - The SQL connection string is automatically configured
3. **Deploy Workflow** - Upload the `workflow.json` to your Logic App
4. **Test Integration** - Send test data from SAP to verify the flow

## Security Considerations

- The SQL Server is configured to allow Azure services access
- Connection strings are stored as Logic App application settings
- Consider using Azure Key Vault for sensitive configurations
- Enable Azure AD authentication for SQL Server in production

## Monitoring

The Logic App provides built-in monitoring through:
- Run history and status tracking
- Azure Monitor integration
- Application Insights (optional)
- Diagnostic logs

## Customization

You can customize this template by:
- Adding additional data validation
- Implementing error handling and retry logic
- Adding transformation logic for SAP data
- Integrating with additional systems
- Adding authentication mechanisms

## Support

This template provides a foundation for SAP to SQL integration. Customize based on your specific SAP system configuration and data requirements.
159 changes: 159 additions & 0 deletions logicapp/logicapp.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
param resourceLocation string = 'swedencentral'
param sapConnectionString string = ''
param sqlServerAdminLogin string = 'sqladmin'
@secure()
param sqlServerAdminPassword string

// Generate unique names for resources
var uniqueSuffix = uniqueString(resourceGroup().id)
var storageAccountName = 'st${uniqueSuffix}'
var logicAppName = 'logic-sap-sql-${uniqueSuffix}'
var sqlServerName = 'sql-${uniqueSuffix}'
var sqlDatabaseName = 'db-sap-data'
var servicePlanName = 'asp-${uniqueSuffix}'

// Storage Account for Logic App Standard
module storageAccount 'br/public:avm/res/storage/storage-account:0.6.7' = {
name: '${uniqueString(deployment().name, resourceLocation)}-storage'
params: {
// Required parameters
name: storageAccountName
// Non-required parameters
location: resourceLocation
skuName: 'Standard_LRS'
kind: 'StorageV2'
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
supportsHttpsTrafficOnly: true
networkAcls: {
defaultAction: 'Allow'
}
}
}

// App Service Plan for Logic App Standard
module servicePlan 'br/public:avm/res/web/serverfarm:0.4.1' = {
name: '${uniqueString(deployment().name, resourceLocation)}-serverfarm'
params: {
// Required parameters
name: servicePlanName
// Non-required parameters
location: resourceLocation
skuName: 'WS1'
skuTier: 'WorkflowStandard'
kind: 'elastic'
elasticScaleEnabled: true
maximumElasticWorkerCount: 20
}
}

// SQL Server
resource sqlServer 'Microsoft.Sql/servers@2023-05-01-preview' = {
name: sqlServerName
location: resourceLocation
properties: {
administratorLogin: sqlServerAdminLogin
administratorLoginPassword: sqlServerAdminPassword
version: '12.0'
minimalTlsVersion: '1.2'
publicNetworkAccess: 'Enabled'
}
}

// SQL Server Firewall Rule to allow Azure services
resource sqlFirewallRule 'Microsoft.Sql/servers/firewallRules@2023-05-01-preview' = {
parent: sqlServer
name: 'AllowAllWindowsAzureIps'
properties: {
startIpAddress: '0.0.0.0'
endIpAddress: '0.0.0.0'
}
}

// SQL Database
resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-05-01-preview' = {
parent: sqlServer
name: sqlDatabaseName
location: resourceLocation
properties: {
collation: 'SQL_Latin1_General_CP1_CI_AS'
maxSizeBytes: 2147483648 // 2GB
}
sku: {
name: 'Basic'
tier: 'Basic'
}
}

// Logic App Standard
module logicApp 'br/public:avm/res/web/site:0.11.0' = {
name: '${uniqueString(deployment().name, resourceLocation)}-logicapp'
params: {
// Required parameters
kind: 'functionapp,workflowapp'
name: logicAppName
serverFarmResourceId: servicePlan.outputs.resourceId
// Non-required parameters
location: resourceLocation
httpsOnly: true
siteConfig: {
netFrameworkVersion: 'v6.0'
use32BitWorkerProcess: false
ftpsState: 'Disabled'
minTlsVersion: '1.2'
appSettings: [
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.outputs.name};AccountKey=${storageAccount.outputs.primaryAccessKey};EndpointSuffix=core.windows.net'
}
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.outputs.name};AccountKey=${storageAccount.outputs.primaryAccessKey};EndpointSuffix=core.windows.net'
}
{
name: 'WEBSITE_CONTENTSHARE'
value: toLower(logicAppName)
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'node'
}
{
name: 'WEBSITE_NODE_DEFAULT_VERSION'
value: '~18'
}
{
name: 'AzureFunctionsJobHost__extensionBundle__id'
value: 'Microsoft.Azure.Functions.ExtensionBundle.Workflows'
}
{
name: 'AzureFunctionsJobHost__extensionBundle__version'
value: '[1.*, 2.0.0)'
}
{
name: 'APP_KIND'
value: 'workflowApp'
}
{
name: 'SAP_CONNECTION_STRING'
value: sapConnectionString
}
{
name: 'SQL_CONNECTION_STRING'
value: 'Server=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Initial Catalog=${sqlDatabaseName};Persist Security Info=False;User ID=${sqlServerAdminLogin};Password=${sqlServerAdminPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'
}
]
}
}
}

// Outputs
output logicAppName string = logicApp.outputs.name
output logicAppId string = logicApp.outputs.resourceId
output sqlServerName string = sqlServer.name
output sqlDatabaseName string = sqlDatabase.name
output storageAccountName string = storageAccount.outputs.name
Loading