Oracle Fusion Cloud
This guide walks you through the steps required to connect Docflo.ai to your Oracle Fusion Cloud system, enabling seamless document integration and automated invoice processing.
- Oracle Fusion Cloud instance with REST API access
- Visual Studio or development environment for .NET
- Docflo.ai account with API access
- Oracle Fusion user with appropriate privileges
- SSL certificate management capabilities
π Integration Stepsβ
Follow these steps to establish a secure connection between Docflo.ai and your Oracle Fusion system:
Step 1: Import SSL Certificate Chainβ
- Download our SSL certificate chain (link)
- Import the certificate to the Windows Certificate Store on your integration server
- Add the certificate to Trusted Root Certification Authorities
- Ensure the certificate is properly validated for HTTPS connections
Step 2: Configure Oracle Fusion REST API Accessβ
- Enable REST API services in your Oracle Fusion instance
- Create integration user with appropriate roles and privileges
- Configure authentication (Basic Authentication or OAuth 2.0)
- Test API connectivity using tools like Postman
Step 3: Generate API Credentialsβ
- Go to the "Integrations" section in your Docflo.ai platform
- Create an API key for Oracle Fusion integration
- Copy the API key and store it securely
- Copy the tenant ID as well - you'll need both for the integration
Step 4: Create Oracle Fusion Integration Serviceβ
Create a Windows Service or scheduled application using REST API calls. Here's a sample C# implementation:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http.Headers;
namespace DocfloOracleFusionIntegration
{
public class DocfloFusionIntegrationService
{
private readonly string _docfloApiUrl;
private readonly string _tenantId;
private readonly string _apiKey;
private readonly string _fusionBaseUrl;
private readonly string _fusionUsername;
private readonly string _fusionPassword;
private readonly HttpClient _httpClient;
private readonly HttpClient _fusionClient;
public DocfloFusionIntegrationService(string docfloApiUrl, string tenantId, string apiKey,
string fusionBaseUrl, string fusionUsername, string fusionPassword)
{
_docfloApiUrl = docfloApiUrl;
_tenantId = tenantId;
_apiKey = apiKey;
_fusionBaseUrl = fusionBaseUrl;
_fusionUsername = fusionUsername;
_fusionPassword = fusionPassword;
// Initialize Docflo HTTP client
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("x-tenant-id", _tenantId);
_httpClient.DefaultRequestHeaders.Add("apiKey", _apiKey);
// Initialize Fusion HTTP client with basic authentication
_fusionClient = new HttpClient();
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_fusionUsername}:{_fusionPassword}"));
_fusionClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);
_fusionClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<List<DocfloDocument>> GetDocfloDocuments(string documentType, bool includeResults = true)
{
try
{
string url = $"{_docfloApiUrl}/docs/v1/document?type={documentType}&includeResults={includeResults}";
HttpResponseMessage response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
string jsonContent = await response.Content.ReadAsStringAsync();
var docfloResponse = JsonConvert.DeserializeObject<DocfloResponse>(jsonContent);
return docfloResponse.Data;
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching Docflo documents: {ex.Message}");
return new List<DocfloDocument>();
}
}
public async Task<bool> CreateSupplierInvoice(DocfloDocument document)
{
try
{
// Extract data from Docflo document results
var extractedData = ExtractInvoiceData(document);
// Create supplier invoice payload
var invoicePayload = new
{
InvoiceNumber = extractedData.InvoiceNumber,
InvoiceDate = extractedData.InvoiceDate?.ToString("yyyy-MM-dd") ?? DateTime.Now.ToString("yyyy-MM-dd"),
Supplier = extractedData.SupplierNumber,
SupplierSite = extractedData.SupplierSite ?? "DEFAULT",
InvoiceAmount = extractedData.Total,
InvoiceCurrencyCode = extractedData.CurrencyCode ?? "USD",
PaymentTerms = extractedData.PaymentTerms ?? "NET30",
Description = $"Invoice processed from Docflo document {document.Id}",
InvoiceLines = extractedData.LineItems.Select(line => new
{
LineNumber = line.LineNumber,
LineAmount = line.LineTotal,
Description = line.Description,
DistributionCombination = line.AccountCombination ?? "01-000-1000-0000-000",
TaxClassificationCode = line.TaxCode
}).ToArray(),
// Custom attribute for Docflo tracking
AttributeCategory = "DOCFLO",
Attribute1 = document.Id
};
string jsonPayload = JsonConvert.SerializeObject(invoicePayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string fusionUrl = $"{_fusionBaseUrl}/fscmRestApi/resources/11.13.18.05/invoices";
HttpResponseMessage response = await _fusionClient.PostAsync(fusionUrl, content);
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Supplier Invoice created successfully for document {document.Id}");
Console.WriteLine($"Response: {responseContent}");
return true;
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating Supplier Invoice: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception creating Supplier Invoice: {ex.Message}");
return false;
}
}
public async Task<bool> CreateCustomerInvoice(DocfloDocument document)
{
try
{
// Extract data from Docflo document results
var extractedData = ExtractInvoiceData(document);
// Create customer invoice payload
var invoicePayload = new
{
TransactionNumber = extractedData.InvoiceNumber,
TransactionDate = extractedData.InvoiceDate?.ToString("yyyy-MM-dd") ?? DateTime.Now.ToString("yyyy-MM-dd"),
TransactionType = "Invoice",
BillToCustomerNumber = extractedData.CustomerNumber,
BillToSite = extractedData.CustomerSite ?? "DEFAULT",
TransactionCurrencyCode = extractedData.CurrencyCode ?? "USD",
PaymentTerms = extractedData.PaymentTerms ?? "NET30",
Comments = $"Invoice processed from Docflo document {document.Id}",
TransactionLines = extractedData.LineItems.Select((line, index) => new
{
LineNumber = index + 1,
LineType = "LINE",
Description = line.Description,
Quantity = line.Quantity,
UnitSellingPrice = line.UnitPrice,
MemoLineType = "LINE"
}).ToArray(),
// Custom attribute for Docflo tracking
AttributeCategory = "DOCFLO",
Attribute1 = document.Id
};
string jsonPayload = JsonConvert.SerializeObject(invoicePayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string fusionUrl = $"{_fusionBaseUrl}/fscmRestApi/resources/11.13.18.05/receivablesInvoices";
HttpResponseMessage response = await _fusionClient.PostAsync(fusionUrl, content);
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Customer Invoice created successfully for document {document.Id}");
Console.WriteLine($"Response: {responseContent}");
return true;
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating Customer Invoice: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception creating Customer Invoice: {ex.Message}");
return false;
}
}
private FusionInvoiceData ExtractInvoiceData(DocfloDocument document)
{
var data = new FusionInvoiceData();
data.LineItems = new List<FusionInvoiceLineItem>();
// Extract data from Docflo results
if (document.DocfloResults?.ModelFields?.Items?.Value != null)
{
foreach (var item in document.DocfloResults.ModelFields.Items.Value)
{
var description = item.ValueObject?.Description;
if (description != null)
{
switch (description.Type?.ToLower())
{
case "supplier_number":
case "vendor_number":
data.SupplierNumber = description.ValueString;
break;
case "customer_number":
data.CustomerNumber = description.ValueString;
break;
case "supplier_site":
case "vendor_site":
data.SupplierSite = description.ValueString;
break;
case "customer_site":
data.CustomerSite = description.ValueString;
break;
case "invoice_number":
case "document_number":
data.InvoiceNumber = description.ValueString;
break;
case "invoice_date":
case "document_date":
if (DateTime.TryParse(description.ValueString, out DateTime invoiceDate))
{
data.InvoiceDate = invoiceDate;
}
break;
case "currency_code":
case "currency":
data.CurrencyCode = description.ValueString;
break;
case "payment_terms":
data.PaymentTerms = description.ValueString;
break;
case "total":
case "total_amount":
case "gross_amount":
if (double.TryParse(description.ValueString, out double total))
{
data.Total = total;
}
break;
case "item_description":
case "product_description":
case "line_description":
// Create new line item
var lineItem = new FusionInvoiceLineItem
{
LineNumber = data.LineItems.Count + 1,
Description = description.ValueString,
Quantity = 1, // Default quantity
UnitPrice = 0, // Default price
LineTotal = 0 // Default total
};
data.LineItems.Add(lineItem);
break;
case "quantity":
// Update last line item quantity
if (data.LineItems.Count > 0 && double.TryParse(description.ValueString, out double quantity))
{
data.LineItems[data.LineItems.Count - 1].Quantity = quantity;
}
break;
case "unit_price":
case "price":
// Update last line item price
if (data.LineItems.Count > 0 && double.TryParse(description.ValueString, out double unitPrice))
{
data.LineItems[data.LineItems.Count - 1].UnitPrice = unitPrice;
}
break;
case "line_total":
case "amount":
// Update last line item total
if (data.LineItems.Count > 0 && double.TryParse(description.ValueString, out double lineTotal))
{
data.LineItems[data.LineItems.Count - 1].LineTotal = lineTotal;
}
break;
case "account_combination":
case "gl_account":
// Update last line item account
if (data.LineItems.Count > 0)
{
data.LineItems[data.LineItems.Count - 1].AccountCombination = description.ValueString;
}
break;
case "tax_code":
case "vat_code":
// Update last line item tax code
if (data.LineItems.Count > 0)
{
data.LineItems[data.LineItems.Count - 1].TaxCode = description.ValueString;
}
break;
}
}
}
}
return data;
}
public void Dispose()
{
_httpClient?.Dispose();
_fusionClient?.Dispose();
}
}
// Data models
public class DocfloResponse
{
[JsonProperty("data")]
public List<DocfloDocument> Data { get; set; }
}
public class DocfloDocument
{
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("sourceId")]
public string SourceId { get; set; }
[JsonProperty("sourceDesc")]
public string SourceDesc { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("numOfPages")]
public string NumOfPages { get; set; }
[JsonProperty("createdAt")]
public string CreatedAt { get; set; }
[JsonProperty("docflo_results")]
public DocfloResults DocfloResults { get; set; }
}
public class DocfloResults
{
[JsonProperty("modelFields")]
public ModelFields ModelFields { get; set; }
}
public class ModelFields
{
[JsonProperty("Items")]
public ItemsField Items { get; set; }
}
public class ItemsField
{
[JsonProperty("value")]
public List<Item> Value { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
public class Item
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("valueObject")]
public ValueObject ValueObject { get; set; }
}
public class ValueObject
{
[JsonProperty("Description")]
public Description Description { get; set; }
}
public class Description
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("valueString")]
public string ValueString { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
}
public class FusionInvoiceData
{
public string SupplierNumber { get; set; }
public string CustomerNumber { get; set; }
public string SupplierSite { get; set; }
public string CustomerSite { get; set; }
public string InvoiceNumber { get; set; }
public DateTime? InvoiceDate { get; set; }
public string CurrencyCode { get; set; }
public string PaymentTerms { get; set; }
public double Total { get; set; }
public List<FusionInvoiceLineItem> LineItems { get; set; }
}
public class FusionInvoiceLineItem
{
public int LineNumber { get; set; }
public string Description { get; set; }
public double Quantity { get; set; }
public double UnitPrice { get; set; }
public double LineTotal { get; set; }
public string AccountCombination { get; set; }
public string TaxCode { get; set; }
}
// Main program example
class Program
{
static async Task Main(string[] args)
{
var service = new DocfloFusionIntegrationService(
"https://api.docflo.ai", // Replace with actual Docflo API URL
"your-tenant-id", // Replace with your tenant ID
"your-api-key", // Replace with your API key
"https://your-fusion-instance.oraclecloud.com", // Replace with your Fusion URL
"fusion-username", // Replace with Fusion username
"fusion-password" // Replace with Fusion password
);
try
{
// Get documents from Docflo
var documents = await service.GetDocfloDocuments("invoice", true);
foreach (var document in documents)
{
// Process each document based on type
if (document.Status == "APPROVED")
{
// Create Supplier Invoice for vendor invoices
bool supplierResult = await service.CreateSupplierInvoice(document);
// Or create Customer Invoice for customer invoices
// bool customerResult = await service.CreateCustomerInvoice(document);
if (supplierResult)
{
Console.WriteLine($"Successfully processed document {document.Id}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in main process: {ex.Message}");
}
finally
{
service.Dispose();
}
}
}
}
π§ Configuration Requirementsβ
NuGet Packages Requiredβ
Add these NuGet packages to your project:
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
Oracle Fusion User Privilegesβ
Ensure your integration user has the following roles and privileges:
- Payables Invoice Entry - For creating supplier invoices
- Receivables Invoice Entry - For creating customer invoices
- REST API Access - For API connectivity
- Integration Specialist - For system integration tasks
Application Configurationβ
Create an app.config file with your settings:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="DocfloApiUrl" value="https://api.docflo.ai" />
<add key="TenantId" value="your-tenant-id" />
<add key="ApiKey" value="your-api-key" />
<add key="FusionBaseUrl" value="https://your-fusion-instance.oraclecloud.com" />
<add key="FusionUsername" value="your-fusion-username" />
<add key="FusionPassword" value="your-fusion-password" />
</appSettings>
</configuration>
π Deployment Optionsβ
Option 1: Windows Serviceβ
Deploy as a Windows Service for continuous processing:
- Install the service using
sc createor InstallUtil - Configure service account with appropriate permissions
- Set up logging for monitoring and troubleshooting
- Schedule regular document polling
Option 2: Azure Functionβ
Deploy as an Azure Function for cloud-based processing:
- Create Azure Function App
- Configure timer trigger for scheduled execution
- Set application settings for configuration values
- Monitor execution through Azure portal
Option 3: Scheduled Taskβ
Use Windows Task Scheduler for periodic execution:
- Create a scheduled task to run the application
- Set appropriate triggers (hourly, daily, etc.)
- Configure security context for Oracle Fusion access
- Monitor execution logs
π Monitoring and Loggingβ
Implement comprehensive logging using NLog or Serilog:
// Add to your service class
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public void LogIntegrationActivity(string message, Exception ex = null)
{
if (ex == null)
{
logger.Info(message);
}
else
{
logger.Error(ex, message);
}
}
π Integration Complete! Your Oracle Fusion system is now connected to Docflo.ai and can automatically process invoice documents, creating both supplier and customer invoices based on extracted document data.
π Troubleshootingβ
Common Issuesβ
-
REST API Authentication Errors:
- Verify username and password credentials
- Check user roles and privileges in Fusion
- Ensure API endpoints are accessible
-
SSL Certificate Issues:
- Verify certificate installation in Windows Certificate Store
- Check certificate chain completeness
- Ensure proper certificate binding
-
API Rate Limiting:
- Implement retry logic with exponential backoff
- Monitor API usage limits
- Consider batch processing for large volumes
-
Data Mapping Issues:
- Validate extracted data from Docflo documents
- Check required fields for Fusion invoice creation
- Ensure proper data type conversions
π Supportβ
For technical assistance with the Oracle Fusion integration:
- Contact Docflo.ai support team
- Consult Oracle Fusion Cloud documentation
- Review Oracle REST API guides
- Contact your Oracle implementation partner