Skip to content

opxw/sapb1-diapi-helper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SAP BusinessOne Data Interface API Helper

NuGet version (SAPB1.DIAPI.Helper)

A Wrapper of DIAPI with more extras such as UDF field mapping, easy access to UDO, SQL query, and more.

Requirements

DIAPI must be installed on machine (tested on DIAPI 9 & 10 SAP HANA & SQL Server version) & Add COM reference into your C# project.

Defining Connection

var provider = new SboProvider(new SboConfiguration()
{
    ServerType = SboServerType.SapMsSql2019,
    Server = "SERVER",
    CompanyDatabase = "ACME_DB",
    LicenseServer = "SERVER:30000",
    User = "johndoe",
    Password = "password"
});
var connected = provider.Connect();

Accessing Business Object

// get business partner master data
var businessPartner = provider.GetBusinessObject<BusinessPartners>
    (BoObjectTypes.oBusinessPartners);

// get goods receipt
var goodsReceipt = provider.GetBusinessObject<Documents>
    (BoObjectTypes.oInventoryGenEntry);

UDF Field Mapping

Assign(IUdf source);

This method is applied to UserFields data type.

Example of case :

udf-marketing-document

Marketing Document in SAP B1 is any document relating to the planning, pricing, coordination, promotion, purchase, sale, or distribution of goods or services. So the UDF will be placed on related transaction interfaces e.g. SalesOrder, GoodsReceipt, Inventory Transfer, Goods Issue or Receipt, etc.

Now, we will manage those fields from Marketing Documents UDF into POCO class like this:

public class MarketingDocumentUdf : IUdf
{
    [SboField("U_AnotherDate")]
    public DateTime? AnotherDate { get; set; }

    [SboField("U_AnotherNumber")]
    public int? AnotherNumber { get; set; }

    [SboField("U_AnotherText")]
    public string? AnotherText { get; set; }
}

public class MarketingDocumentRowUdf : IUdf
{
    [SboField("U_TestRow1")]
    public string? TestRow { get; set; }
}

And below is how we implement those fields into the transaction

var docUdf = new MarketingDocumentUdf()
{
    AnotherDate = DateTime.Today.AddDays(1),
    AnotherNumber = 1000,
    AnotherText = "test",
};

var goodsIssue = provider.GetBusinessObject<Documents>
    (BoObjectTypes.oInventoryGenExit);
goodsIssue.UserFields.Assign(docUdf);

var goodsReceipt = provider.GetBusinessObject<Documents>
    (BoObjectTypes.oInventoryGenEntry);
goodsReceipt.UserFields.Assign(docUdf);
goodsReceipt.Lines.UserFields.Assign(new MarketingDocumentRowUdf()
{
    TestRow = "value"
});

As we can see, the variabledocUdf is reusable and we can use into another document transaction.

Now, let's compare with native (origin) from DIAPI SDK:

var goodsIssue = (Documents)
company.GetBusinessObject(BoObjectTypes.oInventoryGenEntry);
goodsIssue.UserFields.Fields.Item("U_AnotherDate").Value = DateTime.Today.AddDays(1);
goodsIssue.UserFields.Fields.Item("U_AnotherNumber").Value = 1000;
goodsIssue.UserFields.Fields.Item("U_AnotherText").Value = "test";

var goodsReceipt = (Documents)
company.GetBusinessObject(BoObjectTypes.oInventoryGenEntry);
goodsReceipt.UserFields.Fields.Item("U_AnotherDate").Value = DateTime.Today.AddDays(1);
goodsReceipt.UserFields.Fields.Item("U_AnotherNumber").Value = 1000;
goodsReceipt.UserFields.Fields.Item("U_AnotherText").Value = "test";
goodsReceipt.Lines.UserFields.Fields.Item("U_TestRow1").Value = "row value";

// we need more effort to save GoodsIssue & Receipt documents at same time
// it's just about setting up the value of fields

You must set all property data type (has getter & setter) as Nullable.

In .NET Framework : public Nullable<int> Value { get; set; }

In .NET Core, simply put ? sign after data type.

NULL value of the property will be ignored, so we can insert/update data partially.

UDO PROVIDER

Calling or Get UDO

var udo = provider.GetUDO("REGISTERED_OBJECT_NAME");

Read Information Of UDO

UdoProperties properties = udo.Properties;

// here's the UdoProperties structure
class UdoProperties
{
    public string Code { get; set; }
    public string Name { get; set; }
    public string TableName { get; set; }
    public string LogTable { get; set; }
    // UDO type, 1 = Master Data otherwise Document
    public string Type { get; set; }
}

Child Tables

List<UdoChildTable> childs = udo.ChildTables;
  • Accessing The Child Table Object
    var table1 = childs.Item(0);
    or
    var table1 = childs.Item("NAME_OF_CHILD_TABLE");
  • Accessing Values
    List<T> GetValues<T>() where T : GeneralDataRowField
    
    var values = table1.GetValues<YourCustomType>(); 
  • Modify, Add or Delete Item on Child
    //add to existing GeneralDataCollection
    void AddList<T>(List<T> values) where T : GeneralDataRowField
    void Add<T>(T value) where T : GeneralDataRowField
    
    //update existing GeneralData in GeneralDataCollection
    UpdateList<T>(List<T> values) where T : GeneralDataRowField
    void Update<T>(T value) where T : GeneralDataRowField
    
    //remove existing GeneralData in GeneralDataCollection
    void RemoveAtLine(int lineId)
    void RemoveAll()

Insert/Update/Cancel/Close/Delete

// it will returning DocEntry if UDO type is Document otherwise Code if Master Data
object Insert();

public void Update();

// cancel & close only available if UDO type is Document
public void Cancel();
public void Close();

public void Delete();

Let's try it on available User Table Item Sale & has been registered as UDO named ITM_SALE

user-table

The first step, define those fields into POCO class:

public class ItemSale : GeneralDataField
{
    // this is system field & defined as key
    [SboField("Code"), SboPrimaryKey]
    public string? Code { get; set; }

    [SboField("U_ItemCode")]
    public string? ItemCode { get; set; }

    [SboField("U_Notes")]
    public string? Notes { get; set; }
}

public class ItemSaleDiscount : GeneralDataRowField
{
    [SboField("U_FromDate")]
    public DateTime? StartDate { get; set; }

    [SboField("U_Days")]
    public int? AvailableDays { get; set; }

    [SboField("U_Disc")]
    public double? Discount { get; set; }

    public ItemSaleDiscount(DateTime? startDate, 
        int? availableDays, 
        double? discount,
        int? lineId = null)
    {
        StartDate = startDate;
        AvailableDays = availableDays;
        Discount = discount;
        LineId = lineId;
    }
}

Insert

object Insert();

It will returning the new inserted DocEntry if UDO type is Document, otherwise the new inserted Code if UDO type is Master Data.

 // header
udo.Values = new ItemSale()
{
    Code = "MyCode",
    ItemCode = "123",
    Notes = "test"
 };

var discTable = udo.ChildTables.Item("ITM_SALE_DISC");

// add multiple values
discTable.AddList(new List<ItemSaleDiscount>()
{
    new ItemSaleDiscount(DateTime.Now, 2, 35),
    new ItemSaleDiscount(DateTime.Now.AddDays(1), 2, 30),
    new ItemSaleDiscount(DateTime.Now.AddDays(1), 2, 20),
});

// add single value
discTable.Add(new ItemSaleDiscount(DateTime.Now, 2, 35));

udo.Insert();

Update

udo.GetByParams<ItemSale>(new ItemSale()
{
    Code = "MyCode"
});
var discTable = udo.ChildTables.Item("ITM_SALE_DISC");

// update multiple values in line 1 & 3
discTable.UpdateList(new List<ItemSaleDiscount>()
{
    new ItemSaleDiscount(null, null, 25, 1),
    new ItemSaleDiscount(null, null, 25, 3)
});

// update value in line 1
discTable.Update(new ItemSaleDiscount(null, null, 25, 1));

udo.Update();

Read

udo.GetByParams<ItemSale>(new ItemSale()
{
    Code = "MyCode"
}, SboRecordsetFillParam.FillIntoValues);

SQL Query

Examples :

With manual field mapping (using attribute) :

public class BusinessPartner
{
    [SboField("CardCode")]
    public string Code { get; set; }

    [SboField("CardName")]
    public string Name { get; set; }
}

var sql = "SELECT CardCode, CardName from OCRD";
var result = provider.SqlQuery<BusinessPartner>(sql, true);

// it will return List<BusinessPartner>

or, using automatic field mapping:

public class BusinessPartner
{
    public string Code { get; set; }
    public string Name { get; set; }
}

var sql = "SELECT CardCode AS Code, CardName from OCRD AS Name";
var result = provider.SqlQuery<BusinessPartner>(sql);

About

SAP Business One (SAP B1) DIAPI Helper

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages