# Covasant SAP OData Connector
A powerful, production-ready Python library for connecting to SAP OData services with advanced features like parallel processing, intelligent batching, and comprehensive error handling.
## Features
- π **High Performance**: Parallel processing with configurable workers
- π **Smart Batching**: Automatic pagination and batch size optimization
- π **Retry Logic**: Built-in resilience with exponential backoff
- π― **Query Builder**: Support for $filter, $select, $expand, $orderby, and more
- πΎ **Multiple Storage**: Local files, Google BigQuery, and Cloud Storage
- π **Metadata Discovery**: Automatic schema detection and relationship mapping
- β
**OData V2 & V4 Support**: Full support for both OData V2 (SAP) and V4 (modern services)
## Installation
```bash
pip install covasant_sap_odata_connector
```
# SAP OData Connector - Complete Configuration & Filtering Guide
## π Table of Contents
1. [Configuration Options](#configuration-options)
2. [Connection Methods](#connection-methods)
3. [SAP Module Mapping](#sap-module-mapping)
4. [Filtering Guide](#filtering-guide)
5. [Query Options](#query-options)
6. [Advanced Examples](#advanced-examples)
---
## π§ Configuration Options
### Complete ClientConfig Parameters
```python
from covasant_odata.config.models import ClientConfig
config = ClientConfig(
# ========== CONNECTION METHOD 1: Using SAP Module (Recommended) ==========
sap_server="sapes5.sapdevcenter.com", # SAP server hostname/IP
sap_port=443, # Port (default: 8000, HTTPS: 443)
sap_module="ES5", # SAP module name (auto-maps to service)
use_https=True, # Use HTTPS (default: True)
# ========== CONNECTION METHOD 2: Using Service Name Directly ==========
# sap_server="sapes5.sapdevcenter.com",
# sap_port=443,
# service_name="EPM_REF_APPS_SHOP_SRV", # Direct OData service name
# use_https=True,
# ========== CONNECTION METHOD 3: Using Full URL (Legacy) ==========
# service_url="https://sapes5.sapdevcenter.com/sap/opu/odata/sap/EPM_REF_APPS_SHOP_SRV/",
# ========== AUTHENTICATION (Required) ==========
username="your_username", # SAP username
password="your_password", # SAP password
# ========== AUTHENTICATION - OAuth (Alternative) ==========
# client_id="your_client_id", # OAuth client ID
# client_secret="your_client_secret", # OAuth client secret
# ========== SAP-SPECIFIC PARAMETERS (Optional) ==========
sap_client="100", # SAP client number (e.g., '100', '800')
system_id="ES5", # SAP system ID
# ========== OUTPUT SETTINGS ==========
output_directory="./output", # Where to save results
# ========== ENTITY SELECTION (Optional) ==========
selected_modules=["Products", "Orders"], # Specific entities to process
# ========== PROCESSING LIMITS (Optional) ==========
total_records_limit=10000, # Global record limit (None = unlimited)
)
```
---
## π Connection Methods
### Method 1: Using SAP Module (Recommended) β
**Best for**: Standard SAP modules with automatic service mapping
```python
config = ClientConfig(
sap_server="sapes5.sapdevcenter.com",
sap_port=443,
sap_module="ES5", # Automatically maps to EPM_REF_APPS_SHOP_SRV
username="user",
password="pass"
)
```
**Advantages:**
- β
Simple and clean
- β
Automatic service name mapping
- β
Supports 50+ SAP modules
- β
Easy to remember module names
**Supported Modules:** See [SAP Module Mapping](#sap-module-mapping) section
---
### Method 2: Using Service Name Directly
**Best for**: Custom OData services or when you know the exact service name
```python
config = ClientConfig(
sap_server="mycompany-sap.com",
sap_port=8000,
service_name="ZMY_CUSTOM_SERVICE_SRV", # Your custom service
username="user",
password="pass"
)
```
**Advantages:**
- β
Works with any OData service
- β
Custom services supported
- β
Full control over service name
---
### Method 3: Using Full URL (Legacy)
**Best for**: Backward compatibility or complex URL structures
```python
config = ClientConfig(
service_url="https://server.com/sap/opu/odata/sap/MY_SERVICE_SRV/",
username="user",
password="pass"
)
```
**Advantages:**
- β
Backward compatible
- β
Works with any URL structure
- β
No URL construction needed
---
## πΊοΈ SAP Module Mapping
The connector supports automatic mapping from module names to OData service names:
### Finance & Controlling (FI/CO)
```python
sap_module="FI" # β Financial Accounting services
sap_module="CO" # β Controlling services
sap_module="TR" # β Treasury services
sap_module="AA" # β Asset Accounting services
```
### Materials Management (MM)
```python
sap_module="MM" # β Materials Management services
sap_module="IM" # β Inventory Management services
sap_module="WM" # β Warehouse Management services
```
### Sales & Distribution (SD)
```python
sap_module="SD" # β Sales & Distribution services
sap_module="LE" # β Logistics Execution services
```
### Production Planning (PP)
```python
sap_module="PP" # β Production Planning services
sap_module="QM" # β Quality Management services
sap_module="PM" # β Plant Maintenance services
```
### Human Resources (HR)
```python
sap_module="HR" # β Human Resources services
sap_module="PA" # β Personnel Administration services
sap_module="PY" # β Payroll services
```
### Cloud Solutions
```python
sap_module="ARIBA" # β SAP Ariba services
sap_module="CONCUR" # β SAP Concur services
sap_module="SUCCESSFACTORS" # β SuccessFactors services
sap_module="FIELDGLASS" # β SAP Fieldglass services
```
### Demo/Test Systems
```python
sap_module="ES5" # β EPM_REF_APPS_SHOP_SRV (Demo system)
sap_module="NORTHWIND" # β Northwind OData service
```
### Check Available Modules
```python
from covasant_odata.config.sap_module_mapping import SAPModuleMapping
# Get all available modules
modules = SAPModuleMapping.get_all_modules()
print(f"Available modules: {modules}")
# Get service name for a module
service = SAPModuleMapping.get_service_name("ES5")
print(f"ES5 maps to: {service}")
# Get module information
info = SAPModuleMapping.get_module_info("FI")
print(f"FI module info: {info}")
```
---
## π Filtering Guide
### Basic Filter Syntax
OData filters use a specific syntax. Here's the complete guide:
### 1. Comparison Operators
#### Equal (`eq`)
```python
filter_condition="Status eq 'Active'"
filter_condition="Price eq 100"
filter_condition="IsDeleted eq false"
```
#### Not Equal (`ne`)
```python
filter_condition="Status ne 'Deleted'"
filter_condition="Category ne 'Obsolete'"
```
#### Greater Than (`gt`)
```python
filter_condition="Price gt 100"
filter_condition="Quantity gt 0"
```
#### Greater or Equal (`ge`)
```python
filter_condition="Price ge 100"
filter_condition="Stock ge 10"
```
#### Less Than (`lt`)
```python
filter_condition="Price lt 1000"
filter_condition="Stock lt 5"
```
#### Less or Equal (`le`)
```python
filter_condition="Discount le 20"
filter_condition="Quantity le 100"
```
---
### 2. Logical Operators
#### AND
```python
filter_condition="Price gt 100 and Stock lt 10"
filter_condition="Category eq 'Electronics' and Price le 500"
filter_condition="Status eq 'Active' and Quantity gt 0 and Price lt 1000"
```
#### OR
```python
filter_condition="Category eq 'Electronics' or Category eq 'Computers'"
filter_condition="Status eq 'Pending' or Status eq 'Processing'"
```
#### NOT
```python
filter_condition="not (Status eq 'Deleted')"
filter_condition="not (Price gt 1000)"
```
#### Complex Combinations
```python
filter_condition="(Category eq 'A' or Category eq 'B') and Price gt 100"
filter_condition="Status eq 'Active' and (Stock lt 5 or Reorder eq true)"
```
---
### 3. String Functions
#### contains() - Check if string contains substring
```python
filter_condition="contains(Name, 'SAP')"
filter_condition="contains(Description, 'premium')"
filter_condition="contains(Email, '@company.com')"
```
#### startswith() - Check if string starts with
```python
filter_condition="startswith(ProductCode, 'PRD')"
filter_condition="startswith(CustomerID, 'C')"
filter_condition="startswith(Name, 'SAP')"
```
#### endswith() - Check if string ends with
```python
filter_condition="endswith(Email, '@gmail.com')"
filter_condition="endswith(FileName, '.pdf')"
```
#### tolower() / toupper() - Case conversion
```python
filter_condition="tolower(Name) eq 'product a'"
filter_condition="toupper(Status) eq 'ACTIVE'"
```
#### length() - String length
```python
filter_condition="length(ProductCode) eq 10"
filter_condition="length(Name) gt 5"
```
#### substring() - Extract substring
```python
filter_condition="substring(ProductCode, 0, 3) eq 'PRD'"
```
---
### 4. Date and Time Functions
#### Date Comparison
```python
# Using datetime literal
filter_condition="OrderDate ge datetime'2024-01-01T00:00:00'"
filter_condition="CreatedDate lt datetime'2024-12-31T23:59:59'"
```
#### Date Functions
```python
# Year
filter_condition="year(OrderDate) eq 2024"
# Month
filter_condition="month(OrderDate) eq 10"
# Day
filter_condition="day(OrderDate) eq 15"
# Hour, Minute, Second
filter_condition="hour(CreatedTime) ge 9"
filter_condition="minute(CreatedTime) lt 30"
```
#### Dynamic Date Filtering (Python)
```python
from datetime import datetime, timedelta
# Last 30 days
thirty_days_ago = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%dT%H:%M:%S')
filter_condition = f"OrderDate ge datetime'{thirty_days_ago}'"
# Last 6 months
six_months_ago = (datetime.now() - timedelta(days=180)).strftime('%Y-%m-%dT%H:%M:%S')
filter_condition = f"ModifiedDate ge datetime'{six_months_ago}'"
# This year
year_start = datetime.now().replace(month=1, day=1).strftime('%Y-%m-%dT00:00:00')
filter_condition = f"OrderDate ge datetime'{year_start}'"
# This month
month_start = datetime.now().replace(day=1).strftime('%Y-%m-%dT00:00:00')
filter_condition = f"OrderDate ge datetime'{month_start}'"
```
---
### 5. Arithmetic Functions
```python
# Add
filter_condition="Price add Tax gt 100"
# Subtract
filter_condition="Stock sub Reserved gt 10"
# Multiply
filter_condition="Quantity mul Price gt 1000"
# Divide
filter_condition="TotalAmount div Quantity lt 50"
# Modulo
filter_condition="OrderNumber mod 2 eq 0" # Even order numbers
```
---
### 6. Null Checks
```python
# Check if field is null
filter_condition="Email eq null"
filter_condition="DeletedDate eq null"
# Check if field is not null
filter_condition="Email ne null"
filter_condition="ApprovedDate ne null"
```
---
### 7. Collection Functions
#### any() - Check if any item in collection matches
```python
filter_condition="OrderDetails/any(d: d/Quantity gt 10)"
filter_condition="Tags/any(t: t eq 'Premium')"
```
#### all() - Check if all items in collection match
```python
filter_condition="OrderDetails/all(d: d/Status eq 'Shipped')"
```
---
## π Query Options
### Complete get_data() Parameters
```python
result = await connector.get_data(
# ========== REQUIRED ==========
entity_name="Products", # Entity to query
# ========== FILTERING ==========
filter_condition="Price gt 100", # OData filter expression
# ========== FIELD SELECTION ==========
select_fields="Id,Name,Price", # Comma-separated fields
# ========== RELATIONSHIP EXPANSION (JOINs) ==========
expand_relations="Supplier,Category", # Comma-separated relations
# ========== SORTING ==========
order_by="Price desc", # Field and direction (asc/desc)
# ========== SEARCH ==========
search_query="electronics", # Full-text search
# ========== LIMITING ==========
record_limit=100, # Maximum records to fetch
# ========== COUNT ==========
include_count=True, # Include total count
# ========== CUSTOM PARAMETERS ==========
custom_query_params={ # Custom OData parameters
"$skip": "10",
"$format": "json"
}
)
```
---
## π― Advanced Examples
### Example 1: Complex Business Query
```python
# Get high-value orders from last quarter with customer details
from datetime import datetime, timedelta
quarter_start = (datetime.now() - timedelta(days=90)).strftime('%Y-%m-%dT00:00:00')
result = await connector.get_data(
entity_name="Orders",
filter_condition=f"OrderDate ge datetime'{quarter_start}' and TotalAmount gt 10000 and Status eq 'Completed'",
select_fields="Id,OrderDate,TotalAmount,CustomerName,Status",
expand_relations="Customer,OrderDetails/Product",
order_by="TotalAmount desc",
record_limit=100
)
```
### Example 2: Inventory Management Query
```python
# Find low-stock products that need reordering
result = await connector.get_data(
entity_name="Products",
filter_condition="Stock lt ReorderLevel and Active eq true and not (Category eq 'Discontinued')",
select_fields="Id,Name,Stock,ReorderLevel,Category,SupplierName",
expand_relations="Supplier",
order_by="Stock asc"
)
```
### Example 3: Customer Analysis Query
```python
# Get premium customers from specific region
result = await connector.get_data(
entity_name="Customers",
filter_condition="Country eq 'USA' and (CustomerType eq 'Premium' or TotalPurchases gt 50000) and Active eq true",
select_fields="Id,CompanyName,Country,TotalPurchases,CustomerType,Email",
expand_relations="Orders,ContactPersons",
order_by="TotalPurchases desc",
record_limit=50
)
```
### Example 4: Date Range with Multiple Conditions
```python
# Get orders from specific date range with specific criteria
from datetime import datetime
start_date = "2024-01-01T00:00:00"
end_date = "2024-12-31T23:59:59"
result = await connector.get_data(
entity_name="Orders",
filter_condition=f"OrderDate ge datetime'{start_date}' and OrderDate le datetime'{end_date}' and (Status eq 'Shipped' or Status eq 'Delivered') and TotalAmount gt 100",
select_fields="Id,OrderDate,Status,TotalAmount,CustomerName",
expand_relations="Customer,ShippingAddress",
order_by="OrderDate desc"
)
```
### Example 5: String Search with Multiple Conditions
```python
# Find products with specific keywords in name or description
result = await connector.get_data(
entity_name="Products",
filter_condition="(contains(Name, 'laptop') or contains(Description, 'laptop')) and Price ge 500 and Price le 2000 and Stock gt 0",
select_fields="Id,Name,Description,Price,Stock",
expand_relations="Category,Supplier",
order_by="Price asc"
)
```
### Example 6: Nested Expansion
```python
# Get orders with full hierarchy: Order β OrderDetails β Product β Supplier
result = await connector.get_data(
entity_name="Orders",
filter_condition="Status eq 'Processing'",
expand_relations="Customer,OrderDetails/Product/Supplier,ShippingAddress",
order_by="OrderDate desc"
)
```
### Example 7: Using Multiple Modules
```python
# Query different SAP modules
config_fi = ClientConfig(
sap_server="server.com",
sap_port=443,
sap_module="FI", # Financial Accounting
username="user",
password="pass"
)
config_mm = ClientConfig(
sap_server="server.com",
sap_port=443,
sap_module="MM", # Materials Management
username="user",
password="pass"
)
# Query FI module
connector_fi = SAPODataConnector(config_fi)
await connector_fi.initialize()
gl_accounts = await connector_fi.get_data(entity_name="GLAccounts")
# Query MM module
connector_mm = SAPODataConnector(config_mm)
await connector_mm.initialize()
materials = await connector_mm.get_data(entity_name="Materials")
```
---
## π Filter Operators Quick Reference
| Operator | Description | Example |
|----------|-------------|---------|
| `eq` | Equal | `Status eq 'Active'` |
| `ne` | Not equal | `Status ne 'Deleted'` |
| `gt` | Greater than | `Price gt 100` |
| `ge` | Greater or equal | `Quantity ge 10` |
| `lt` | Less than | `Stock lt 5` |
| `le` | Less or equal | `Discount le 20` |
| `and` | Logical AND | `Price gt 100 and Stock lt 10` |
| `or` | Logical OR | `Category eq 'A' or Category eq 'B'` |
| `not` | Logical NOT | `not (Status eq 'Deleted')` |
| `contains()` | String contains | `contains(Name, 'SAP')` |
| `startswith()` | String starts with | `startswith(Code, 'PRD')` |
| `endswith()` | String ends with | `endswith(Email, '@company.com')` |
| `tolower()` | Convert to lowercase | `tolower(Name) eq 'product'` |
| `toupper()` | Convert to uppercase | `toupper(Status) eq 'ACTIVE'` |
| `length()` | String length | `length(Code) eq 10` |
| `year()` | Extract year | `year(OrderDate) eq 2024` |
| `month()` | Extract month | `month(OrderDate) eq 10` |
| `day()` | Extract day | `day(OrderDate) eq 15` |
| `add` | Addition | `Price add Tax gt 100` |
| `sub` | Subtraction | `Stock sub Reserved gt 10` |
| `mul` | Multiplication | `Quantity mul Price gt 1000` |
| `div` | Division | `Total div Quantity lt 50` |
| `mod` | Modulo | `OrderNumber mod 2 eq 0` |
---
## π‘ Best Practices
### 1. Use Specific Filters
```python
# β
Good - filter on server
result = await connector.get_data(
entity_name="Products",
filter_condition="Price gt 100"
)
# β Bad - fetch all then filter in Python
all_products = await connector.get_data(entity_name="Products")
filtered = [p for p in all_products if p['Price'] > 100]
```
### 2. Select Only Needed Fields
```python
# β
Good - select specific fields
result = await connector.get_data(
entity_name="Products",
select_fields="Id,Name,Price"
)
# β Bad - fetch all fields
result = await connector.get_data(entity_name="Products")
```
### 3. Use Expansion for Related Data
```python
# β
Good - one query with expansion
result = await connector.get_data(
entity_name="Products",
expand_relations="Supplier,Category"
)
# β Bad - multiple queries
products = await connector.get_data(entity_name="Products")
for product in products:
supplier = await connector.get_data(entity_name="Suppliers", ...)
```
### 4. Test Filters with Limits
```python
# β
Good - test with small limit first
test = await connector.get_data(
entity_name="Products",
filter_condition="Price gt 100",
record_limit=5
)
# Verify results, then fetch all
full = await connector.get_data(
entity_name="Products",
filter_condition="Price gt 100"
)
```
---
## π Troubleshooting
### Invalid Filter Syntax
```python
# β Wrong
filter_condition="Price > 100" # Use 'gt' not '>'
# β
Correct
filter_condition="Price gt 100"
```
### Date Format Issues
```python
# β Wrong
filter_condition="OrderDate ge '2024-01-01'"
# β
Correct
filter_condition="OrderDate ge datetime'2024-01-01T00:00:00'"
```
### String Comparison
```python
# β Wrong
filter_condition="Status eq Active" # Missing quotes
# β
Correct
filter_condition="Status eq 'Active'"
```
---
## π Additional Resources
- **OData Protocol**: https://www.odata.org/documentation/
- **OData Query Options**: https://www.odata.org/getting-started/basic-tutorial/#queryData
- **SAP OData Documentation**: https://help.sap.com/docs/odata
---
**Package**: `covasant_sap_odata_connector` | **Version**: 1.0.3 | **OData**: V2 & V4 Support
Raw data
{
"_id": null,
"home_page": null,
"name": "covasant-sap-odata-connector",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "sap, odata, connector, api, rest, data, integration, etl",
"author": "Covasant Technologies",
"author_email": "Covasant Technologies <info@covasant.com>",
"download_url": "https://files.pythonhosted.org/packages/45/b3/3ee370b98652719d9b1aa9b1e35b2c8c2c9b1831685591d9b264251e8f4a/covasant_sap_odata_connector-1.0.3.tar.gz",
"platform": null,
"description": "# Covasant SAP OData Connector\r\n\r\nA powerful, production-ready Python library for connecting to SAP OData services with advanced features like parallel processing, intelligent batching, and comprehensive error handling.\r\n\r\n## Features\r\n\r\n- \ud83d\ude80 **High Performance**: Parallel processing with configurable workers\r\n- \ud83d\udcca **Smart Batching**: Automatic pagination and batch size optimization\r\n- \ud83d\udd04 **Retry Logic**: Built-in resilience with exponential backoff\r\n- \ud83c\udfaf **Query Builder**: Support for $filter, $select, $expand, $orderby, and more\r\n- \ud83d\udcbe **Multiple Storage**: Local files, Google BigQuery, and Cloud Storage\r\n- \ud83d\udd0d **Metadata Discovery**: Automatic schema detection and relationship mapping\r\n- \u2705 **OData V2 & V4 Support**: Full support for both OData V2 (SAP) and V4 (modern services)\r\n\r\n## Installation\r\n\r\n```bash\r\npip install covasant_sap_odata_connector\r\n```\r\n# SAP OData Connector - Complete Configuration & Filtering Guide\r\n\r\n## \ud83d\udccb Table of Contents\r\n1. [Configuration Options](#configuration-options)\r\n2. [Connection Methods](#connection-methods)\r\n3. [SAP Module Mapping](#sap-module-mapping)\r\n4. [Filtering Guide](#filtering-guide)\r\n5. [Query Options](#query-options)\r\n6. [Advanced Examples](#advanced-examples)\r\n\r\n---\r\n\r\n## \ud83d\udd27 Configuration Options\r\n\r\n### Complete ClientConfig Parameters\r\n\r\n```python\r\nfrom covasant_odata.config.models import ClientConfig\r\n\r\nconfig = ClientConfig(\r\n # ========== CONNECTION METHOD 1: Using SAP Module (Recommended) ==========\r\n sap_server=\"sapes5.sapdevcenter.com\", # SAP server hostname/IP\r\n sap_port=443, # Port (default: 8000, HTTPS: 443)\r\n sap_module=\"ES5\", # SAP module name (auto-maps to service)\r\n use_https=True, # Use HTTPS (default: True)\r\n \r\n # ========== CONNECTION METHOD 2: Using Service Name Directly ==========\r\n # sap_server=\"sapes5.sapdevcenter.com\",\r\n # sap_port=443,\r\n # service_name=\"EPM_REF_APPS_SHOP_SRV\", # Direct OData service name\r\n # use_https=True,\r\n \r\n # ========== CONNECTION METHOD 3: Using Full URL (Legacy) ==========\r\n # service_url=\"https://sapes5.sapdevcenter.com/sap/opu/odata/sap/EPM_REF_APPS_SHOP_SRV/\",\r\n \r\n # ========== AUTHENTICATION (Required) ==========\r\n username=\"your_username\", # SAP username\r\n password=\"your_password\", # SAP password\r\n \r\n # ========== AUTHENTICATION - OAuth (Alternative) ==========\r\n # client_id=\"your_client_id\", # OAuth client ID\r\n # client_secret=\"your_client_secret\", # OAuth client secret\r\n \r\n # ========== SAP-SPECIFIC PARAMETERS (Optional) ==========\r\n sap_client=\"100\", # SAP client number (e.g., '100', '800')\r\n system_id=\"ES5\", # SAP system ID\r\n \r\n # ========== OUTPUT SETTINGS ==========\r\n output_directory=\"./output\", # Where to save results\r\n \r\n # ========== ENTITY SELECTION (Optional) ==========\r\n selected_modules=[\"Products\", \"Orders\"], # Specific entities to process\r\n \r\n # ========== PROCESSING LIMITS (Optional) ==========\r\n total_records_limit=10000, # Global record limit (None = unlimited)\r\n)\r\n```\r\n\r\n---\r\n\r\n## \ud83c\udf10 Connection Methods\r\n\r\n### Method 1: Using SAP Module (Recommended) \u2b50\r\n\r\n**Best for**: Standard SAP modules with automatic service mapping\r\n\r\n```python\r\nconfig = ClientConfig(\r\n sap_server=\"sapes5.sapdevcenter.com\",\r\n sap_port=443,\r\n sap_module=\"ES5\", # Automatically maps to EPM_REF_APPS_SHOP_SRV\r\n username=\"user\",\r\n password=\"pass\"\r\n)\r\n```\r\n\r\n**Advantages:**\r\n- \u2705 Simple and clean\r\n- \u2705 Automatic service name mapping\r\n- \u2705 Supports 50+ SAP modules\r\n- \u2705 Easy to remember module names\r\n\r\n**Supported Modules:** See [SAP Module Mapping](#sap-module-mapping) section\r\n\r\n---\r\n\r\n### Method 2: Using Service Name Directly\r\n\r\n**Best for**: Custom OData services or when you know the exact service name\r\n\r\n```python\r\nconfig = ClientConfig(\r\n sap_server=\"mycompany-sap.com\",\r\n sap_port=8000,\r\n service_name=\"ZMY_CUSTOM_SERVICE_SRV\", # Your custom service\r\n username=\"user\",\r\n password=\"pass\"\r\n)\r\n```\r\n\r\n**Advantages:**\r\n- \u2705 Works with any OData service\r\n- \u2705 Custom services supported\r\n- \u2705 Full control over service name\r\n\r\n---\r\n\r\n### Method 3: Using Full URL (Legacy)\r\n\r\n**Best for**: Backward compatibility or complex URL structures\r\n\r\n```python\r\nconfig = ClientConfig(\r\n service_url=\"https://server.com/sap/opu/odata/sap/MY_SERVICE_SRV/\",\r\n username=\"user\",\r\n password=\"pass\"\r\n)\r\n```\r\n\r\n**Advantages:**\r\n- \u2705 Backward compatible\r\n- \u2705 Works with any URL structure\r\n- \u2705 No URL construction needed\r\n\r\n---\r\n\r\n## \ud83d\uddfa\ufe0f SAP Module Mapping\r\n\r\nThe connector supports automatic mapping from module names to OData service names:\r\n\r\n### Finance & Controlling (FI/CO)\r\n```python\r\nsap_module=\"FI\" # \u2192 Financial Accounting services\r\nsap_module=\"CO\" # \u2192 Controlling services\r\nsap_module=\"TR\" # \u2192 Treasury services\r\nsap_module=\"AA\" # \u2192 Asset Accounting services\r\n```\r\n\r\n### Materials Management (MM)\r\n```python\r\nsap_module=\"MM\" # \u2192 Materials Management services\r\nsap_module=\"IM\" # \u2192 Inventory Management services\r\nsap_module=\"WM\" # \u2192 Warehouse Management services\r\n```\r\n\r\n### Sales & Distribution (SD)\r\n```python\r\nsap_module=\"SD\" # \u2192 Sales & Distribution services\r\nsap_module=\"LE\" # \u2192 Logistics Execution services\r\n```\r\n\r\n### Production Planning (PP)\r\n```python\r\nsap_module=\"PP\" # \u2192 Production Planning services\r\nsap_module=\"QM\" # \u2192 Quality Management services\r\nsap_module=\"PM\" # \u2192 Plant Maintenance services\r\n```\r\n\r\n### Human Resources (HR)\r\n```python\r\nsap_module=\"HR\" # \u2192 Human Resources services\r\nsap_module=\"PA\" # \u2192 Personnel Administration services\r\nsap_module=\"PY\" # \u2192 Payroll services\r\n```\r\n\r\n### Cloud Solutions\r\n```python\r\nsap_module=\"ARIBA\" # \u2192 SAP Ariba services\r\nsap_module=\"CONCUR\" # \u2192 SAP Concur services\r\nsap_module=\"SUCCESSFACTORS\" # \u2192 SuccessFactors services\r\nsap_module=\"FIELDGLASS\" # \u2192 SAP Fieldglass services\r\n```\r\n\r\n### Demo/Test Systems\r\n```python\r\nsap_module=\"ES5\" # \u2192 EPM_REF_APPS_SHOP_SRV (Demo system)\r\nsap_module=\"NORTHWIND\" # \u2192 Northwind OData service\r\n```\r\n\r\n### Check Available Modules\r\n\r\n```python\r\nfrom covasant_odata.config.sap_module_mapping import SAPModuleMapping\r\n\r\n# Get all available modules\r\nmodules = SAPModuleMapping.get_all_modules()\r\nprint(f\"Available modules: {modules}\")\r\n\r\n# Get service name for a module\r\nservice = SAPModuleMapping.get_service_name(\"ES5\")\r\nprint(f\"ES5 maps to: {service}\")\r\n\r\n# Get module information\r\ninfo = SAPModuleMapping.get_module_info(\"FI\")\r\nprint(f\"FI module info: {info}\")\r\n```\r\n\r\n---\r\n\r\n## \ud83d\udd0d Filtering Guide\r\n\r\n### Basic Filter Syntax\r\n\r\nOData filters use a specific syntax. Here's the complete guide:\r\n\r\n### 1. Comparison Operators\r\n\r\n#### Equal (`eq`)\r\n```python\r\nfilter_condition=\"Status eq 'Active'\"\r\nfilter_condition=\"Price eq 100\"\r\nfilter_condition=\"IsDeleted eq false\"\r\n```\r\n\r\n#### Not Equal (`ne`)\r\n```python\r\nfilter_condition=\"Status ne 'Deleted'\"\r\nfilter_condition=\"Category ne 'Obsolete'\"\r\n```\r\n\r\n#### Greater Than (`gt`)\r\n```python\r\nfilter_condition=\"Price gt 100\"\r\nfilter_condition=\"Quantity gt 0\"\r\n```\r\n\r\n#### Greater or Equal (`ge`)\r\n```python\r\nfilter_condition=\"Price ge 100\"\r\nfilter_condition=\"Stock ge 10\"\r\n```\r\n\r\n#### Less Than (`lt`)\r\n```python\r\nfilter_condition=\"Price lt 1000\"\r\nfilter_condition=\"Stock lt 5\"\r\n```\r\n\r\n#### Less or Equal (`le`)\r\n```python\r\nfilter_condition=\"Discount le 20\"\r\nfilter_condition=\"Quantity le 100\"\r\n```\r\n\r\n---\r\n\r\n### 2. Logical Operators\r\n\r\n#### AND\r\n```python\r\nfilter_condition=\"Price gt 100 and Stock lt 10\"\r\nfilter_condition=\"Category eq 'Electronics' and Price le 500\"\r\nfilter_condition=\"Status eq 'Active' and Quantity gt 0 and Price lt 1000\"\r\n```\r\n\r\n#### OR\r\n```python\r\nfilter_condition=\"Category eq 'Electronics' or Category eq 'Computers'\"\r\nfilter_condition=\"Status eq 'Pending' or Status eq 'Processing'\"\r\n```\r\n\r\n#### NOT\r\n```python\r\nfilter_condition=\"not (Status eq 'Deleted')\"\r\nfilter_condition=\"not (Price gt 1000)\"\r\n```\r\n\r\n#### Complex Combinations\r\n```python\r\nfilter_condition=\"(Category eq 'A' or Category eq 'B') and Price gt 100\"\r\nfilter_condition=\"Status eq 'Active' and (Stock lt 5 or Reorder eq true)\"\r\n```\r\n\r\n---\r\n\r\n### 3. String Functions\r\n\r\n#### contains() - Check if string contains substring\r\n```python\r\nfilter_condition=\"contains(Name, 'SAP')\"\r\nfilter_condition=\"contains(Description, 'premium')\"\r\nfilter_condition=\"contains(Email, '@company.com')\"\r\n```\r\n\r\n#### startswith() - Check if string starts with\r\n```python\r\nfilter_condition=\"startswith(ProductCode, 'PRD')\"\r\nfilter_condition=\"startswith(CustomerID, 'C')\"\r\nfilter_condition=\"startswith(Name, 'SAP')\"\r\n```\r\n\r\n#### endswith() - Check if string ends with\r\n```python\r\nfilter_condition=\"endswith(Email, '@gmail.com')\"\r\nfilter_condition=\"endswith(FileName, '.pdf')\"\r\n```\r\n\r\n#### tolower() / toupper() - Case conversion\r\n```python\r\nfilter_condition=\"tolower(Name) eq 'product a'\"\r\nfilter_condition=\"toupper(Status) eq 'ACTIVE'\"\r\n```\r\n\r\n#### length() - String length\r\n```python\r\nfilter_condition=\"length(ProductCode) eq 10\"\r\nfilter_condition=\"length(Name) gt 5\"\r\n```\r\n\r\n#### substring() - Extract substring\r\n```python\r\nfilter_condition=\"substring(ProductCode, 0, 3) eq 'PRD'\"\r\n```\r\n\r\n---\r\n\r\n### 4. Date and Time Functions\r\n\r\n#### Date Comparison\r\n```python\r\n# Using datetime literal\r\nfilter_condition=\"OrderDate ge datetime'2024-01-01T00:00:00'\"\r\nfilter_condition=\"CreatedDate lt datetime'2024-12-31T23:59:59'\"\r\n```\r\n\r\n#### Date Functions\r\n```python\r\n# Year\r\nfilter_condition=\"year(OrderDate) eq 2024\"\r\n\r\n# Month\r\nfilter_condition=\"month(OrderDate) eq 10\"\r\n\r\n# Day\r\nfilter_condition=\"day(OrderDate) eq 15\"\r\n\r\n# Hour, Minute, Second\r\nfilter_condition=\"hour(CreatedTime) ge 9\"\r\nfilter_condition=\"minute(CreatedTime) lt 30\"\r\n```\r\n\r\n#### Dynamic Date Filtering (Python)\r\n```python\r\nfrom datetime import datetime, timedelta\r\n\r\n# Last 30 days\r\nthirty_days_ago = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%dT%H:%M:%S')\r\nfilter_condition = f\"OrderDate ge datetime'{thirty_days_ago}'\"\r\n\r\n# Last 6 months\r\nsix_months_ago = (datetime.now() - timedelta(days=180)).strftime('%Y-%m-%dT%H:%M:%S')\r\nfilter_condition = f\"ModifiedDate ge datetime'{six_months_ago}'\"\r\n\r\n# This year\r\nyear_start = datetime.now().replace(month=1, day=1).strftime('%Y-%m-%dT00:00:00')\r\nfilter_condition = f\"OrderDate ge datetime'{year_start}'\"\r\n\r\n# This month\r\nmonth_start = datetime.now().replace(day=1).strftime('%Y-%m-%dT00:00:00')\r\nfilter_condition = f\"OrderDate ge datetime'{month_start}'\"\r\n```\r\n\r\n---\r\n\r\n### 5. Arithmetic Functions\r\n\r\n```python\r\n# Add\r\nfilter_condition=\"Price add Tax gt 100\"\r\n\r\n# Subtract\r\nfilter_condition=\"Stock sub Reserved gt 10\"\r\n\r\n# Multiply\r\nfilter_condition=\"Quantity mul Price gt 1000\"\r\n\r\n# Divide\r\nfilter_condition=\"TotalAmount div Quantity lt 50\"\r\n\r\n# Modulo\r\nfilter_condition=\"OrderNumber mod 2 eq 0\" # Even order numbers\r\n```\r\n\r\n---\r\n\r\n### 6. Null Checks\r\n\r\n```python\r\n# Check if field is null\r\nfilter_condition=\"Email eq null\"\r\nfilter_condition=\"DeletedDate eq null\"\r\n\r\n# Check if field is not null\r\nfilter_condition=\"Email ne null\"\r\nfilter_condition=\"ApprovedDate ne null\"\r\n```\r\n\r\n---\r\n\r\n### 7. Collection Functions\r\n\r\n#### any() - Check if any item in collection matches\r\n```python\r\nfilter_condition=\"OrderDetails/any(d: d/Quantity gt 10)\"\r\nfilter_condition=\"Tags/any(t: t eq 'Premium')\"\r\n```\r\n\r\n#### all() - Check if all items in collection match\r\n```python\r\nfilter_condition=\"OrderDetails/all(d: d/Status eq 'Shipped')\"\r\n```\r\n\r\n---\r\n\r\n## \ud83d\udcdd Query Options\r\n\r\n### Complete get_data() Parameters\r\n\r\n```python\r\nresult = await connector.get_data(\r\n # ========== REQUIRED ==========\r\n entity_name=\"Products\", # Entity to query\r\n \r\n # ========== FILTERING ==========\r\n filter_condition=\"Price gt 100\", # OData filter expression\r\n \r\n # ========== FIELD SELECTION ==========\r\n select_fields=\"Id,Name,Price\", # Comma-separated fields\r\n \r\n # ========== RELATIONSHIP EXPANSION (JOINs) ==========\r\n expand_relations=\"Supplier,Category\", # Comma-separated relations\r\n \r\n # ========== SORTING ==========\r\n order_by=\"Price desc\", # Field and direction (asc/desc)\r\n \r\n # ========== SEARCH ==========\r\n search_query=\"electronics\", # Full-text search\r\n \r\n # ========== LIMITING ==========\r\n record_limit=100, # Maximum records to fetch\r\n \r\n # ========== COUNT ==========\r\n include_count=True, # Include total count\r\n \r\n # ========== CUSTOM PARAMETERS ==========\r\n custom_query_params={ # Custom OData parameters\r\n \"$skip\": \"10\",\r\n \"$format\": \"json\"\r\n }\r\n)\r\n```\r\n\r\n---\r\n\r\n## \ud83c\udfaf Advanced Examples\r\n\r\n### Example 1: Complex Business Query\r\n```python\r\n# Get high-value orders from last quarter with customer details\r\nfrom datetime import datetime, timedelta\r\n\r\nquarter_start = (datetime.now() - timedelta(days=90)).strftime('%Y-%m-%dT00:00:00')\r\n\r\nresult = await connector.get_data(\r\n entity_name=\"Orders\",\r\n filter_condition=f\"OrderDate ge datetime'{quarter_start}' and TotalAmount gt 10000 and Status eq 'Completed'\",\r\n select_fields=\"Id,OrderDate,TotalAmount,CustomerName,Status\",\r\n expand_relations=\"Customer,OrderDetails/Product\",\r\n order_by=\"TotalAmount desc\",\r\n record_limit=100\r\n)\r\n```\r\n\r\n### Example 2: Inventory Management Query\r\n```python\r\n# Find low-stock products that need reordering\r\nresult = await connector.get_data(\r\n entity_name=\"Products\",\r\n filter_condition=\"Stock lt ReorderLevel and Active eq true and not (Category eq 'Discontinued')\",\r\n select_fields=\"Id,Name,Stock,ReorderLevel,Category,SupplierName\",\r\n expand_relations=\"Supplier\",\r\n order_by=\"Stock asc\"\r\n)\r\n```\r\n\r\n### Example 3: Customer Analysis Query\r\n```python\r\n# Get premium customers from specific region\r\nresult = await connector.get_data(\r\n entity_name=\"Customers\",\r\n filter_condition=\"Country eq 'USA' and (CustomerType eq 'Premium' or TotalPurchases gt 50000) and Active eq true\",\r\n select_fields=\"Id,CompanyName,Country,TotalPurchases,CustomerType,Email\",\r\n expand_relations=\"Orders,ContactPersons\",\r\n order_by=\"TotalPurchases desc\",\r\n record_limit=50\r\n)\r\n```\r\n\r\n### Example 4: Date Range with Multiple Conditions\r\n```python\r\n# Get orders from specific date range with specific criteria\r\nfrom datetime import datetime\r\n\r\nstart_date = \"2024-01-01T00:00:00\"\r\nend_date = \"2024-12-31T23:59:59\"\r\n\r\nresult = await connector.get_data(\r\n entity_name=\"Orders\",\r\n filter_condition=f\"OrderDate ge datetime'{start_date}' and OrderDate le datetime'{end_date}' and (Status eq 'Shipped' or Status eq 'Delivered') and TotalAmount gt 100\",\r\n select_fields=\"Id,OrderDate,Status,TotalAmount,CustomerName\",\r\n expand_relations=\"Customer,ShippingAddress\",\r\n order_by=\"OrderDate desc\"\r\n)\r\n```\r\n\r\n### Example 5: String Search with Multiple Conditions\r\n```python\r\n# Find products with specific keywords in name or description\r\nresult = await connector.get_data(\r\n entity_name=\"Products\",\r\n filter_condition=\"(contains(Name, 'laptop') or contains(Description, 'laptop')) and Price ge 500 and Price le 2000 and Stock gt 0\",\r\n select_fields=\"Id,Name,Description,Price,Stock\",\r\n expand_relations=\"Category,Supplier\",\r\n order_by=\"Price asc\"\r\n)\r\n```\r\n\r\n### Example 6: Nested Expansion\r\n```python\r\n# Get orders with full hierarchy: Order \u2192 OrderDetails \u2192 Product \u2192 Supplier\r\nresult = await connector.get_data(\r\n entity_name=\"Orders\",\r\n filter_condition=\"Status eq 'Processing'\",\r\n expand_relations=\"Customer,OrderDetails/Product/Supplier,ShippingAddress\",\r\n order_by=\"OrderDate desc\"\r\n)\r\n```\r\n\r\n### Example 7: Using Multiple Modules\r\n```python\r\n# Query different SAP modules\r\nconfig_fi = ClientConfig(\r\n sap_server=\"server.com\",\r\n sap_port=443,\r\n sap_module=\"FI\", # Financial Accounting\r\n username=\"user\",\r\n password=\"pass\"\r\n)\r\n\r\nconfig_mm = ClientConfig(\r\n sap_server=\"server.com\",\r\n sap_port=443,\r\n sap_module=\"MM\", # Materials Management\r\n username=\"user\",\r\n password=\"pass\"\r\n)\r\n\r\n# Query FI module\r\nconnector_fi = SAPODataConnector(config_fi)\r\nawait connector_fi.initialize()\r\ngl_accounts = await connector_fi.get_data(entity_name=\"GLAccounts\")\r\n\r\n# Query MM module\r\nconnector_mm = SAPODataConnector(config_mm)\r\nawait connector_mm.initialize()\r\nmaterials = await connector_mm.get_data(entity_name=\"Materials\")\r\n```\r\n\r\n---\r\n\r\n## \ud83d\udcca Filter Operators Quick Reference\r\n\r\n| Operator | Description | Example |\r\n|----------|-------------|---------|\r\n| `eq` | Equal | `Status eq 'Active'` |\r\n| `ne` | Not equal | `Status ne 'Deleted'` |\r\n| `gt` | Greater than | `Price gt 100` |\r\n| `ge` | Greater or equal | `Quantity ge 10` |\r\n| `lt` | Less than | `Stock lt 5` |\r\n| `le` | Less or equal | `Discount le 20` |\r\n| `and` | Logical AND | `Price gt 100 and Stock lt 10` |\r\n| `or` | Logical OR | `Category eq 'A' or Category eq 'B'` |\r\n| `not` | Logical NOT | `not (Status eq 'Deleted')` |\r\n| `contains()` | String contains | `contains(Name, 'SAP')` |\r\n| `startswith()` | String starts with | `startswith(Code, 'PRD')` |\r\n| `endswith()` | String ends with | `endswith(Email, '@company.com')` |\r\n| `tolower()` | Convert to lowercase | `tolower(Name) eq 'product'` |\r\n| `toupper()` | Convert to uppercase | `toupper(Status) eq 'ACTIVE'` |\r\n| `length()` | String length | `length(Code) eq 10` |\r\n| `year()` | Extract year | `year(OrderDate) eq 2024` |\r\n| `month()` | Extract month | `month(OrderDate) eq 10` |\r\n| `day()` | Extract day | `day(OrderDate) eq 15` |\r\n| `add` | Addition | `Price add Tax gt 100` |\r\n| `sub` | Subtraction | `Stock sub Reserved gt 10` |\r\n| `mul` | Multiplication | `Quantity mul Price gt 1000` |\r\n| `div` | Division | `Total div Quantity lt 50` |\r\n| `mod` | Modulo | `OrderNumber mod 2 eq 0` |\r\n\r\n---\r\n\r\n## \ud83d\udca1 Best Practices\r\n\r\n### 1. Use Specific Filters\r\n```python\r\n# \u2705 Good - filter on server\r\nresult = await connector.get_data(\r\n entity_name=\"Products\",\r\n filter_condition=\"Price gt 100\"\r\n)\r\n\r\n# \u274c Bad - fetch all then filter in Python\r\nall_products = await connector.get_data(entity_name=\"Products\")\r\nfiltered = [p for p in all_products if p['Price'] > 100]\r\n```\r\n\r\n### 2. Select Only Needed Fields\r\n```python\r\n# \u2705 Good - select specific fields\r\nresult = await connector.get_data(\r\n entity_name=\"Products\",\r\n select_fields=\"Id,Name,Price\"\r\n)\r\n\r\n# \u274c Bad - fetch all fields\r\nresult = await connector.get_data(entity_name=\"Products\")\r\n```\r\n\r\n### 3. Use Expansion for Related Data\r\n```python\r\n# \u2705 Good - one query with expansion\r\nresult = await connector.get_data(\r\n entity_name=\"Products\",\r\n expand_relations=\"Supplier,Category\"\r\n)\r\n\r\n# \u274c Bad - multiple queries\r\nproducts = await connector.get_data(entity_name=\"Products\")\r\nfor product in products:\r\n supplier = await connector.get_data(entity_name=\"Suppliers\", ...)\r\n```\r\n\r\n### 4. Test Filters with Limits\r\n```python\r\n# \u2705 Good - test with small limit first\r\ntest = await connector.get_data(\r\n entity_name=\"Products\",\r\n filter_condition=\"Price gt 100\",\r\n record_limit=5\r\n)\r\n# Verify results, then fetch all\r\nfull = await connector.get_data(\r\n entity_name=\"Products\",\r\n filter_condition=\"Price gt 100\"\r\n)\r\n```\r\n\r\n---\r\n\r\n## \ud83c\udd98 Troubleshooting\r\n\r\n### Invalid Filter Syntax\r\n```python\r\n# \u274c Wrong\r\nfilter_condition=\"Price > 100\" # Use 'gt' not '>'\r\n\r\n# \u2705 Correct\r\nfilter_condition=\"Price gt 100\"\r\n```\r\n\r\n### Date Format Issues\r\n```python\r\n# \u274c Wrong\r\nfilter_condition=\"OrderDate ge '2024-01-01'\"\r\n\r\n# \u2705 Correct\r\nfilter_condition=\"OrderDate ge datetime'2024-01-01T00:00:00'\"\r\n```\r\n\r\n### String Comparison\r\n```python\r\n# \u274c Wrong\r\nfilter_condition=\"Status eq Active\" # Missing quotes\r\n\r\n# \u2705 Correct\r\nfilter_condition=\"Status eq 'Active'\"\r\n```\r\n\r\n---\r\n\r\n## \ud83d\udcda Additional Resources\r\n\r\n- **OData Protocol**: https://www.odata.org/documentation/\r\n- **OData Query Options**: https://www.odata.org/getting-started/basic-tutorial/#queryData\r\n- **SAP OData Documentation**: https://help.sap.com/docs/odata\r\n\r\n---\r\n\r\n**Package**: `covasant_sap_odata_connector` | **Version**: 1.0.3 | **OData**: V2 & V4 Support\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A powerful Python library for connecting to SAP OData services with OData V2 and V4 support",
"version": "1.0.3",
"project_urls": null,
"split_keywords": [
"sap",
" odata",
" connector",
" api",
" rest",
" data",
" integration",
" etl"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "51aeebf692b18d7049517030d92500882d78c0ce22dd9b55f276da65a6ecac8b",
"md5": "6b970215a9794918ae40129296774523",
"sha256": "7a24d24d1dffdac7c21a8f83b944dff45c268099be29860360eb6f93adbfe5fd"
},
"downloads": -1,
"filename": "covasant_sap_odata_connector-1.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6b970215a9794918ae40129296774523",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 101459,
"upload_time": "2025-10-09T07:06:39",
"upload_time_iso_8601": "2025-10-09T07:06:39.434958Z",
"url": "https://files.pythonhosted.org/packages/51/ae/ebf692b18d7049517030d92500882d78c0ce22dd9b55f276da65a6ecac8b/covasant_sap_odata_connector-1.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "45b33ee370b98652719d9b1aa9b1e35b2c8c2c9b1831685591d9b264251e8f4a",
"md5": "2adb95e1c6c99eed861bfb06c69320eb",
"sha256": "eebe11f39bf352599c0330ea8b94c37dc37046e52bcb4432ba4181ab6b14a28c"
},
"downloads": -1,
"filename": "covasant_sap_odata_connector-1.0.3.tar.gz",
"has_sig": false,
"md5_digest": "2adb95e1c6c99eed861bfb06c69320eb",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 127738,
"upload_time": "2025-10-09T07:06:40",
"upload_time_iso_8601": "2025-10-09T07:06:40.959598Z",
"url": "https://files.pythonhosted.org/packages/45/b3/3ee370b98652719d9b1aa9b1e35b2c8c2c9b1831685591d9b264251e8f4a/covasant_sap_odata_connector-1.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-09 07:06:40",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "covasant-sap-odata-connector"
}