Merge pull request #53 from metacube2/codex/create-c#-console-app-for-sap-hana-export
Add Trafag SAP HANA → Excel → SharePoint exporter (.NET 8 console)
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
namespace TrafagSalesExporter.Models;
|
||||||
|
|
||||||
|
public class SalesRecord
|
||||||
|
{
|
||||||
|
public DateTime ExtractionDate { get; set; }
|
||||||
|
public string Tsc { get; set; } = string.Empty;
|
||||||
|
public string InvoiceNumber { get; set; } = string.Empty;
|
||||||
|
public int PositionOnInvoice { get; set; }
|
||||||
|
public string Material { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string ProductGroup { get; set; } = string.Empty;
|
||||||
|
public decimal Quantity { get; set; }
|
||||||
|
public string SupplierNumber { get; set; } = string.Empty;
|
||||||
|
public string SupplierName { get; set; } = string.Empty;
|
||||||
|
public string SupplierCountry { get; set; } = string.Empty;
|
||||||
|
public string CustomerNumber { get; set; } = string.Empty;
|
||||||
|
public string CustomerName { get; set; } = string.Empty;
|
||||||
|
public string CustomerCountry { get; set; } = string.Empty;
|
||||||
|
public string CustomerIndustry { get; set; } = string.Empty;
|
||||||
|
public decimal StandardCost { get; set; }
|
||||||
|
public string StandardCostCurrency { get; set; } = string.Empty;
|
||||||
|
public string PurchaseOrderNumber { get; set; } = string.Empty;
|
||||||
|
public decimal SalesPriceValue { get; set; }
|
||||||
|
public string SalesCurrency { get; set; } = string.Empty;
|
||||||
|
public string Incoterms2020 { get; set; } = string.Empty;
|
||||||
|
public string SalesResponsibleEmployee { get; set; } = string.Empty;
|
||||||
|
public DateTime? InvoiceDate { get; set; }
|
||||||
|
public DateTime? OrderDate { get; set; }
|
||||||
|
public string Land { get; set; } = string.Empty;
|
||||||
|
public string DocumentType { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using TrafagSalesExporter.Services;
|
||||||
|
|
||||||
|
namespace TrafagSalesExporter;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
private static async Task Main()
|
||||||
|
{
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(AppContext.BaseDirectory)
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var appConfig = config.Get<AppConfig>() ?? throw new InvalidOperationException("Konfiguration konnte nicht geladen werden.");
|
||||||
|
|
||||||
|
var hanaService = new HanaQueryService();
|
||||||
|
var excelService = new ExcelExportService();
|
||||||
|
var sharePointService = new SharePointUploadService(
|
||||||
|
appConfig.SharePoint.TenantId,
|
||||||
|
appConfig.SharePoint.ClientId,
|
||||||
|
appConfig.SharePoint.ClientSecret,
|
||||||
|
appConfig.SharePoint.SiteUrl,
|
||||||
|
appConfig.SharePoint.ExportFolder);
|
||||||
|
|
||||||
|
var outputDir = Path.Combine(AppContext.BaseDirectory, "output");
|
||||||
|
|
||||||
|
foreach (var site in appConfig.Sites)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log($"Starte Standort: {site.Land} ({site.Schema})");
|
||||||
|
|
||||||
|
if (!appConfig.HanaServers.TryGetValue(site.Server, out var serverConfig))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"HANA Server-Konfiguration '{site.Server}' nicht gefunden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var records = hanaService.GetSalesRecords(
|
||||||
|
serverConfig.Host,
|
||||||
|
serverConfig.Port,
|
||||||
|
serverConfig.Username,
|
||||||
|
serverConfig.Password,
|
||||||
|
site.Schema,
|
||||||
|
site.TSC,
|
||||||
|
site.Land);
|
||||||
|
|
||||||
|
var filePath = excelService.CreateExcelFile(outputDir, site.TSC, DateTime.UtcNow.Date, records);
|
||||||
|
Log($"Excel erzeugt: {filePath}");
|
||||||
|
|
||||||
|
await sharePointService.UploadAsync(site.Land, filePath);
|
||||||
|
Log($"Upload abgeschlossen: {site.Land}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log($"Fehler bei Standort {site.Land}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("Export beendet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Log(string message)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AppConfig
|
||||||
|
{
|
||||||
|
public Dictionary<string, HanaServerConfig> HanaServers { get; set; } = new();
|
||||||
|
public List<SiteConfig> Sites { get; set; } = new();
|
||||||
|
public SharePointConfig SharePoint { get; set; } = new();
|
||||||
|
public string DateFilter { get; set; } = "2025-01-01";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HanaServerConfig
|
||||||
|
{
|
||||||
|
public string Host { get; set; } = string.Empty;
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public string Password { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SiteConfig
|
||||||
|
{
|
||||||
|
public string Schema { get; set; } = string.Empty;
|
||||||
|
public string Server { get; set; } = string.Empty;
|
||||||
|
public string TSC { get; set; } = string.Empty;
|
||||||
|
public string Land { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SharePointConfig
|
||||||
|
{
|
||||||
|
public string SiteUrl { get; set; } = string.Empty;
|
||||||
|
public string ExportFolder { get; set; } = string.Empty;
|
||||||
|
public string TenantId { get; set; } = string.Empty;
|
||||||
|
public string ClientId { get; set; } = string.Empty;
|
||||||
|
public string ClientSecret { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using ClosedXML.Excel;
|
||||||
|
using TrafagSalesExporter.Models;
|
||||||
|
|
||||||
|
namespace TrafagSalesExporter.Services;
|
||||||
|
|
||||||
|
public class ExcelExportService
|
||||||
|
{
|
||||||
|
public string CreateExcelFile(string outputDirectory, string tsc, DateTime fileDate, List<SalesRecord> records)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(outputDirectory);
|
||||||
|
var fileName = $"Sales_{tsc}_{fileDate:yyyy-MM-dd}.xlsx";
|
||||||
|
var fullPath = Path.Combine(outputDirectory, fileName);
|
||||||
|
|
||||||
|
using var workbook = new XLWorkbook();
|
||||||
|
var ws = workbook.Worksheets.Add("Sales");
|
||||||
|
|
||||||
|
var headers = new[]
|
||||||
|
{
|
||||||
|
"extraction date",
|
||||||
|
"TSC",
|
||||||
|
"Invoice Number",
|
||||||
|
"Position on invoice",
|
||||||
|
"Material",
|
||||||
|
"Name",
|
||||||
|
"Product Group",
|
||||||
|
"Quantity",
|
||||||
|
"Supplier number",
|
||||||
|
"Supplier name",
|
||||||
|
"Supplier country",
|
||||||
|
"Customer number",
|
||||||
|
"Customer name",
|
||||||
|
"Customer country",
|
||||||
|
"Customer Industry",
|
||||||
|
"Standard cost",
|
||||||
|
"Standard Cost Currency",
|
||||||
|
"Purchase Order number",
|
||||||
|
"Sales Price/Value",
|
||||||
|
"Sales Currency",
|
||||||
|
"Incoterms 2020",
|
||||||
|
"Sales responsible employee",
|
||||||
|
"invoice date",
|
||||||
|
"order date",
|
||||||
|
"Land",
|
||||||
|
"Document Type"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < headers.Length; i++)
|
||||||
|
{
|
||||||
|
ws.Cell(1, i + 1).Value = headers[i];
|
||||||
|
ws.Cell(1, i + 1).Style.Font.Bold = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var row = 2;
|
||||||
|
foreach (var record in records)
|
||||||
|
{
|
||||||
|
ws.Cell(row, 1).Value = record.ExtractionDate.ToString("dd.MM.yyyy HH:mm:ss");
|
||||||
|
ws.Cell(row, 2).Value = record.Tsc;
|
||||||
|
ws.Cell(row, 3).Value = record.InvoiceNumber;
|
||||||
|
ws.Cell(row, 4).Value = record.PositionOnInvoice;
|
||||||
|
ws.Cell(row, 5).Value = record.Material;
|
||||||
|
ws.Cell(row, 6).Value = record.Name;
|
||||||
|
ws.Cell(row, 7).Value = record.ProductGroup;
|
||||||
|
ws.Cell(row, 8).Value = record.Quantity;
|
||||||
|
ws.Cell(row, 9).Value = record.SupplierNumber;
|
||||||
|
ws.Cell(row, 10).Value = record.SupplierName;
|
||||||
|
ws.Cell(row, 11).Value = record.SupplierCountry;
|
||||||
|
ws.Cell(row, 12).Value = record.CustomerNumber;
|
||||||
|
ws.Cell(row, 13).Value = record.CustomerName;
|
||||||
|
ws.Cell(row, 14).Value = record.CustomerCountry;
|
||||||
|
ws.Cell(row, 15).Value = record.CustomerIndustry;
|
||||||
|
ws.Cell(row, 16).Value = record.StandardCost;
|
||||||
|
ws.Cell(row, 17).Value = record.StandardCostCurrency;
|
||||||
|
ws.Cell(row, 18).Value = record.PurchaseOrderNumber;
|
||||||
|
ws.Cell(row, 19).Value = record.SalesPriceValue;
|
||||||
|
ws.Cell(row, 20).Value = record.SalesCurrency;
|
||||||
|
ws.Cell(row, 21).Value = record.Incoterms2020;
|
||||||
|
ws.Cell(row, 22).Value = record.SalesResponsibleEmployee;
|
||||||
|
ws.Cell(row, 23).Value = record.InvoiceDate?.ToString("dd.MM.yyyy") ?? string.Empty;
|
||||||
|
ws.Cell(row, 24).Value = record.OrderDate?.ToString("dd.MM.yyyy") ?? string.Empty;
|
||||||
|
ws.Cell(row, 25).Value = record.Land;
|
||||||
|
ws.Cell(row, 26).Value = record.DocumentType;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.Columns().AdjustToContents();
|
||||||
|
workbook.SaveAs(fullPath);
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
using Sap.Data.Hana;
|
||||||
|
using TrafagSalesExporter.Models;
|
||||||
|
|
||||||
|
namespace TrafagSalesExporter.Services;
|
||||||
|
|
||||||
|
public class HanaQueryService
|
||||||
|
{
|
||||||
|
public List<SalesRecord> GetSalesRecords(string host, int port, string username, string password, string schema, string tsc, string land)
|
||||||
|
{
|
||||||
|
var connectionString = $"ServerNode={host}:{port};UserName={username};Password={password}";
|
||||||
|
var result = new List<SalesRecord>();
|
||||||
|
|
||||||
|
using var connection = new HanaConnection(connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
var invoiceQuery = GetInvoiceQuery(schema, tsc);
|
||||||
|
var creditNoteQuery = GetCreditNoteQuery(schema, tsc);
|
||||||
|
|
||||||
|
result.AddRange(ReadRecords(connection, invoiceQuery, land));
|
||||||
|
result.AddRange(ReadRecords(connection, creditNoteQuery, land));
|
||||||
|
|
||||||
|
foreach (var record in result)
|
||||||
|
{
|
||||||
|
if (record.Material.Contains('/'))
|
||||||
|
{
|
||||||
|
var parts = record.Material.Split('/');
|
||||||
|
record.Material = parts[^1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<SalesRecord> ReadRecords(HanaConnection connection, string query, string land)
|
||||||
|
{
|
||||||
|
var records = new List<SalesRecord>();
|
||||||
|
|
||||||
|
using var command = new HanaCommand(query, connection);
|
||||||
|
using var reader = command.ExecuteReader();
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
records.Add(new SalesRecord
|
||||||
|
{
|
||||||
|
ExtractionDate = reader.GetDateTime(reader.GetOrdinal("extraction_date")),
|
||||||
|
Tsc = reader.GetString(reader.GetOrdinal("tsc")),
|
||||||
|
InvoiceNumber = reader["invoice_number"]?.ToString() ?? string.Empty,
|
||||||
|
PositionOnInvoice = Convert.ToInt32(reader["invoice_position"]),
|
||||||
|
InvoiceDate = reader.IsDBNull(reader.GetOrdinal("invoice_date")) ? null : reader.GetDateTime(reader.GetOrdinal("invoice_date")),
|
||||||
|
Material = reader["material"]?.ToString() ?? string.Empty,
|
||||||
|
Name = reader["material_name"]?.ToString() ?? string.Empty,
|
||||||
|
ProductGroup = reader["product_group"]?.ToString() ?? string.Empty,
|
||||||
|
Quantity = Convert.ToDecimal(reader["quantity"]),
|
||||||
|
SupplierNumber = reader["supplier_number"]?.ToString() ?? string.Empty,
|
||||||
|
SupplierName = reader["supplier_name"]?.ToString() ?? string.Empty,
|
||||||
|
SupplierCountry = reader["supplier_country"]?.ToString() ?? string.Empty,
|
||||||
|
CustomerNumber = reader["customer_number"]?.ToString() ?? string.Empty,
|
||||||
|
CustomerName = reader["customer_name"]?.ToString() ?? string.Empty,
|
||||||
|
CustomerCountry = reader["customer_country"]?.ToString() ?? string.Empty,
|
||||||
|
CustomerIndustry = reader["customer_industry"]?.ToString() ?? string.Empty,
|
||||||
|
StandardCost = Convert.ToDecimal(reader["standard_cost"]),
|
||||||
|
StandardCostCurrency = reader["standard_cost_currency"]?.ToString() ?? string.Empty,
|
||||||
|
PurchaseOrderNumber = reader["purchase_order_number"]?.ToString() ?? string.Empty,
|
||||||
|
SalesPriceValue = Convert.ToDecimal(reader["sales_value"]),
|
||||||
|
SalesCurrency = reader["sales_currency"]?.ToString() ?? string.Empty,
|
||||||
|
Incoterms2020 = reader["incoterms_2020"]?.ToString() ?? string.Empty,
|
||||||
|
SalesResponsibleEmployee = reader["sales_responsible"]?.ToString() ?? string.Empty,
|
||||||
|
OrderDate = reader.IsDBNull(reader.GetOrdinal("order_date")) ? null : reader.GetDateTime(reader.GetOrdinal("order_date")),
|
||||||
|
Land = land,
|
||||||
|
DocumentType = reader["doc_type"]?.ToString() ?? string.Empty
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetInvoiceQuery(string schema, string tsc) => $@"
|
||||||
|
SELECT
|
||||||
|
CURRENT_TIMESTAMP AS extraction_date,
|
||||||
|
'{tsc}' AS tsc,
|
||||||
|
h.""DocNum"" AS invoice_number,
|
||||||
|
p.""LineNum"" AS invoice_position,
|
||||||
|
h.""DocDate"" AS invoice_date,
|
||||||
|
p.""ItemCode"" AS material,
|
||||||
|
p.""Dscription"" AS material_name,
|
||||||
|
COALESCE(grp.""ItmsGrpNam"", '') AS product_group,
|
||||||
|
p.""Quantity"" AS quantity,
|
||||||
|
COALESCE(itm.""CardCode"", '') AS supplier_number,
|
||||||
|
COALESCE(sup.""CardName"", '') AS supplier_name,
|
||||||
|
COALESCE(sup_adr.""Country"", '') AS supplier_country,
|
||||||
|
h.""CardCode"" AS customer_number,
|
||||||
|
h.""CardName"" AS customer_name,
|
||||||
|
COALESCE(cust_adr.""Country"", '') AS customer_country,
|
||||||
|
COALESCE(ind.""IndName"", '') AS customer_industry,
|
||||||
|
p.""StockPrice"" AS standard_cost,
|
||||||
|
COALESCE(p.""Currency"", h.""DocCur"") AS standard_cost_currency,
|
||||||
|
CASE WHEN p.""BaseType"" = 22
|
||||||
|
THEN CAST(p.""BaseRef"" AS NVARCHAR(20))
|
||||||
|
ELSE '' END AS purchase_order_number,
|
||||||
|
p.""LineTotal"" AS sales_value,
|
||||||
|
COALESCE(p.""Currency"", h.""DocCur"") AS sales_currency,
|
||||||
|
'' AS incoterms_2020,
|
||||||
|
COALESCE(emp.""SlpName"", '') AS sales_responsible,
|
||||||
|
CASE WHEN p.""BaseType"" = 17
|
||||||
|
THEN (SELECT o.""DocDate"" FROM {schema}.""ORDR"" o
|
||||||
|
WHERE o.""DocEntry"" = p.""BaseEntry"")
|
||||||
|
ELSE NULL END AS order_date,
|
||||||
|
'INV' AS doc_type
|
||||||
|
FROM {schema}.""OINV"" h
|
||||||
|
INNER JOIN {schema}.""INV1"" p ON h.""DocEntry"" = p.""DocEntry""
|
||||||
|
LEFT JOIN {schema}.""OITM"" itm ON p.""ItemCode"" = itm.""ItemCode""
|
||||||
|
LEFT JOIN {schema}.""OITB"" grp ON itm.""ItmsGrpCod"" = grp.""ItmsGrpCod""
|
||||||
|
LEFT JOIN {schema}.""OCRD"" cust ON h.""CardCode"" = cust.""CardCode""
|
||||||
|
LEFT JOIN {schema}.""CRD1"" cust_adr ON h.""CardCode"" = cust_adr.""CardCode""
|
||||||
|
AND cust_adr.""AdresType"" = 'B' AND cust_adr.""Address"" = h.""PayToCode""
|
||||||
|
LEFT JOIN {schema}.""OOND"" ind ON cust.""IndustryC"" = ind.""IndCode""
|
||||||
|
LEFT JOIN {schema}.""OCRD"" sup ON itm.""CardCode"" = sup.""CardCode""
|
||||||
|
AND sup.""CardType"" = 'S'
|
||||||
|
LEFT JOIN {schema}.""CRD1"" sup_adr ON itm.""CardCode"" = sup_adr.""CardCode""
|
||||||
|
AND sup_adr.""AdresType"" = 'B'
|
||||||
|
LEFT JOIN {schema}.""OSLP"" emp ON h.""SlpCode"" = emp.""SlpCode""
|
||||||
|
WHERE h.""CANCELED"" = 'N' AND h.""DocDate"" >= '2025-01-01'
|
||||||
|
ORDER BY h.""DocDate"" DESC, h.""DocNum"", p.""LineNum""";
|
||||||
|
|
||||||
|
private static string GetCreditNoteQuery(string schema, string tsc) => $@"
|
||||||
|
SELECT
|
||||||
|
CURRENT_TIMESTAMP AS extraction_date,
|
||||||
|
'{tsc}' AS tsc,
|
||||||
|
h.""DocNum"" AS invoice_number,
|
||||||
|
p.""LineNum"" AS invoice_position,
|
||||||
|
h.""DocDate"" AS invoice_date,
|
||||||
|
p.""ItemCode"" AS material,
|
||||||
|
p.""Dscription"" AS material_name,
|
||||||
|
COALESCE(grp.""ItmsGrpNam"", '') AS product_group,
|
||||||
|
p.""Quantity"" * -1 AS quantity,
|
||||||
|
COALESCE(itm.""CardCode"", '') AS supplier_number,
|
||||||
|
COALESCE(sup.""CardName"", '') AS supplier_name,
|
||||||
|
COALESCE(sup_adr.""Country"", '') AS supplier_country,
|
||||||
|
h.""CardCode"" AS customer_number,
|
||||||
|
h.""CardName"" AS customer_name,
|
||||||
|
COALESCE(cust_adr.""Country"", '') AS customer_country,
|
||||||
|
COALESCE(ind.""IndName"", '') AS customer_industry,
|
||||||
|
p.""StockPrice"" AS standard_cost,
|
||||||
|
COALESCE(p.""Currency"", h.""DocCur"") AS standard_cost_currency,
|
||||||
|
'' AS purchase_order_number,
|
||||||
|
p.""LineTotal"" * -1 AS sales_value,
|
||||||
|
COALESCE(p.""Currency"", h.""DocCur"") AS sales_currency,
|
||||||
|
'' AS incoterms_2020,
|
||||||
|
COALESCE(emp.""SlpName"", '') AS sales_responsible,
|
||||||
|
NULL AS order_date,
|
||||||
|
'CRN' AS doc_type
|
||||||
|
FROM {schema}.""ORIN"" h
|
||||||
|
INNER JOIN {schema}.""RIN1"" p ON h.""DocEntry"" = p.""DocEntry""
|
||||||
|
LEFT JOIN {schema}.""OITM"" itm ON p.""ItemCode"" = itm.""ItemCode""
|
||||||
|
LEFT JOIN {schema}.""OITB"" grp ON itm.""ItmsGrpCod"" = grp.""ItmsGrpCod""
|
||||||
|
LEFT JOIN {schema}.""OCRD"" cust ON h.""CardCode"" = cust.""CardCode""
|
||||||
|
LEFT JOIN {schema}.""CRD1"" cust_adr ON h.""CardCode"" = cust_adr.""CardCode""
|
||||||
|
AND cust_adr.""AdresType"" = 'B' AND cust_adr.""Address"" = h.""PayToCode""
|
||||||
|
LEFT JOIN {schema}.""OOND"" ind ON cust.""IndustryC"" = ind.""IndCode""
|
||||||
|
LEFT JOIN {schema}.""OCRD"" sup ON itm.""CardCode"" = sup.""CardCode""
|
||||||
|
AND sup.""CardType"" = 'S'
|
||||||
|
LEFT JOIN {schema}.""CRD1"" sup_adr ON itm.""CardCode"" = sup_adr.""CardCode""
|
||||||
|
AND sup_adr.""AdresType"" = 'B'
|
||||||
|
LEFT JOIN {schema}.""OSLP"" emp ON h.""SlpCode"" = emp.""SlpCode""
|
||||||
|
WHERE h.""CANCELED"" = 'N' AND h.""DocDate"" >= '2025-01-01'
|
||||||
|
ORDER BY h.""DocDate"" DESC, h.""DocNum"", p.""LineNum""";
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Graph;
|
||||||
|
|
||||||
|
namespace TrafagSalesExporter.Services;
|
||||||
|
|
||||||
|
public class SharePointUploadService
|
||||||
|
{
|
||||||
|
private readonly GraphServiceClient _graphClient;
|
||||||
|
private readonly string _siteUrl;
|
||||||
|
private readonly string _exportFolder;
|
||||||
|
|
||||||
|
public SharePointUploadService(string tenantId, string clientId, string clientSecret, string siteUrl, string exportFolder)
|
||||||
|
{
|
||||||
|
var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||||
|
_graphClient = new GraphServiceClient(credential, ["https://graph.microsoft.com/.default"]);
|
||||||
|
_siteUrl = siteUrl;
|
||||||
|
_exportFolder = exportFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UploadAsync(string land, string localFilePath)
|
||||||
|
{
|
||||||
|
var uri = new Uri(_siteUrl);
|
||||||
|
var sitePath = uri.AbsolutePath;
|
||||||
|
var site = await _graphClient.Sites[$"{uri.Host}:{sitePath}"].GetAsync();
|
||||||
|
|
||||||
|
if (site?.Id is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("SharePoint Site konnte nicht gefunden werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var drive = await _graphClient.Sites[site.Id].Drive.GetAsync();
|
||||||
|
if (drive?.Id is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("SharePoint Dokumentenbibliothek konnte nicht gefunden werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = Path.GetFileName(localFilePath);
|
||||||
|
var folderPath = $"{_exportFolder.Trim('/').Trim()}";
|
||||||
|
var remotePath = $"{folderPath}/{land}/{fileName}";
|
||||||
|
|
||||||
|
await using var stream = File.OpenRead(localFilePath);
|
||||||
|
await _graphClient.Drives[drive.Id].Root.ItemWithPath(remotePath).Content.PutAsync(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ClosedXML" Version="0.104.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Graph" Version="5.80.0" />
|
||||||
|
<PackageReference Include="Azure.Identity" Version="1.13.1" />
|
||||||
|
<PackageReference Include="Sap.Data.Hana.v2" Version="2.22.26" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"HanaServers": {
|
||||||
|
"Internal": {
|
||||||
|
"Host": "travtrp0",
|
||||||
|
"Port": 30015,
|
||||||
|
"Username": "",
|
||||||
|
"Password": ""
|
||||||
|
},
|
||||||
|
"India": {
|
||||||
|
"Host": "20.197.20.60",
|
||||||
|
"Port": 30015,
|
||||||
|
"Username": "",
|
||||||
|
"Password": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Sites": [
|
||||||
|
{ "Schema": "fr01_p", "Server": "Internal", "TSC": "TRFR", "Land": "Frankreich" },
|
||||||
|
{ "Schema": "it01_p", "Server": "Internal", "TSC": "TRIT", "Land": "Italien" },
|
||||||
|
{ "Schema": "us01_p", "Server": "Internal", "TSC": "TRUS", "Land": "USA" },
|
||||||
|
{ "Schema": "TRAFAG_LIVE", "Server": "India", "TSC": "TRIN", "Land": "Indien" }
|
||||||
|
],
|
||||||
|
"SharePoint": {
|
||||||
|
"SiteUrl": "https://trafagag.sharepoint.com/sites/WorldwideBIPlatform",
|
||||||
|
"ExportFolder": "/Shared Documents/Exports/",
|
||||||
|
"TenantId": "",
|
||||||
|
"ClientId": "",
|
||||||
|
"ClientSecret": ""
|
||||||
|
},
|
||||||
|
"DateFilter": "2025-01-01"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user