# C# Integration

Before the integration can begin, artifactory must be added as source so that the NuGet packages can be installed. Instructions on how to do this can be found here.

# Required Packages

The following packages must be installed:

  • anybill.POS.Client
  • anybill.POS.Client.Abstractions

Optional Packages:

  • anybill.POS.Client.Microsoft.Extensions.DependencyInjection
  • anybill.POS.Client.Newtonsoft

Download the full documentation here

# Initialization

After all required packages are installed, you can continue with the initialization of the AnybillClientFactory and the creation of the AnybillClient. For this the following parameters are necessary:

  • Username
  • Password
  • ClientId
var clientFactory = new AnybillClientFactory();
var anybillClient = clientFactory.Create(x => x.WithUsername(username).WithPassword(password).WithClientId(clientId), AnybillEnvironment.Staging);

The environment can be optionally added when creating the AnybillClient. By default, Production is stored here.

# Authentication

After the AnybillClient exists, the authentication can be executed in a second step. An AccessToken is requested and stored internally.

await anybillClient.Authentication.EnsureAsync();

# Register new bill

If you want to display a QR code already during the checkout process and before the purchase is completed, you can request a new BillId using the RegisterIdAsync method.

var registerBillId = new RegisterBillId
{
    StoreId = storeId
};

var registerBillIdResponse = await anybillClient.Bill.RegisterIdAsync(registerBillId);

switch (registerBillIdResponse)
{
    case IRegisterBillIdUrlResponse registerBillIdUrlResponse:
        // do something
        break;
    case IRegisterBillIdExternalIdResponse registerBillIdExternalResponse:
        // do something
        break;
}

The result is an interface of type IRegisterBillIdUrlResponse or IRegisterBillIdExternalIdResponse. The difference between the 2 interfaces is that the IRegisterBillIdExternalIdResponse only contains the BillId, while the IRegisterBillIdUrlResponse additionally contains the Url to display the QR code. Since IRegisterBillIdExternalIdResponse has already been assigned to a user, it is no longer necessary to display the QR code here.

# Add Bill

Adding the bill is composed of the bill itself and the associated billOptions. As a result one of the following interfaces is returned:

  • IExternalIdResponse
  • ILoyaltyCardResponse
  • IMatchedBillResponse
  • IUrlBillResponse
  • IUserIdResponse
var billResponse = await anybillClient.Bill.CreateAsync(bill, billOptions);

switch (billResponse)
{
    case IExternalIdResponse externalIdResponse:
        // do something
        break;
    case ILoyaltyCardResponse loyaltyCardResponse:
        // do something
        break;
    case IMatchedBillResponse matchedBillResponse:
        // do something
        break;
    case IUrlBillResponse urlBillResponse:
        // do something
        break;
    case IUserIdResponse userIdResponse:
        // do something
        break;
}

# Get Categories

To get all existing bill-categories GetAllCategoriesAsync can be used.

var categories = await anybillClient.Category.GetAllCategoriesAsync();

A specific category can be fetched by GetCategoryByIdAsync.

var category = await anybillClient.Category.GetCategoryByIdAsync(categoryId);

# Check the Activation-Status of a Customer

To find out whether a Customer finished the Onboarding process and is allowed to use other VendorAPI endpoints or not, IsActivatedAsync can be used.

var customerActivated = await anybillClient.Customer.IsActivatedAsync();
if(customerActivated.Type == "activated")
    // Allowed to call other endpoints

# Onboarding

To do the automatic Onboarding of a vendor customer, OnboardingAsync can be used.

var onboardingCreateVendorCustomer = new OnboardingCreateVendorCustomer()
{
    Address = new Address()
    {
        // ...
    },
    Email = "<e-mail address>",
    BillingAddress = new BillingAddress()
    {
        // ...
    },
    CompanyName = "<name of company>",
    InvoicingEmail = "<invoicing email>",
    DistributorCustomerId = <optional guid of distributor>
};
var onboarding = new Onboarding()
{
    PosSoftwareCustomerId = <posSoftwareCustomerId>,
    Stores = new List<OnboardingCreateStore>()
    {
        // ...
    },
    VendorCustomer = onboardingCreateVendorCustomer
};
var onboardingResponse = await anybillClient.Onboarding.OnboardingAsync(onboarding);

# Stores

Multiple functions exist to manage stores. To get all stores GetStoresAsync can be used.

var skip = 0;
var take = 100;
var stores = await anybillClient.Store.GetStoresAsync(skip, take);

If you want to get a specific store you can use GetStoreByIdAsync.

var store = await anybillClient.Store.GetStoreByIdAsync(storeId);

To find out how the information about a store was changed over time, GetStoreHistoryAsync can be used.

var storeHistory = await anybillClient.Store.GetStoreHistoryAsync(storeId);

To delete an existing store by id, DeleteStoreAsync can be used. The flag IsSuccess in the response of the call indicated if the store was deleted or not.

var deleteStoreResponse = await anybillClient.Store.DeleteStoreAsync(storeId);
if(deleteStoreResponse.IsSuccess)
    // Store was deleted successfully

To create a new store or to update the information of an existing store the method UpSertStoreAsync exists.

var newStore = new UpSertStore()
{
    // Add store information here 
};
var storeResponse = await anybillClient.Store.UpSertStoreAsync(newStore);

# User

To identify a user by its User-Id, Loyalty-Card-Barcode or external Id, you can use IdentifyAsync. The UserIdentification object can hold the three values UserId, LoyaltyCardBarcode and ExternalId. The user will be identified by one of those. If more values are set, the UserId has the highest priority, then the LoyaltyCardBarcode and finally the ExternalId with lowest priority.

var userIdentificationResponse = await anybillClient.User.IdentifyAsync(userIdentificationObject, cancellationToken);
var userId = userIdentificationResponse.UserId;

# Exception Handling

The following list describe all exceptions which can occur in case of an error.

  • AuthenticationException: Occurs when authentication fails, e.g. when no username is specified.
  • BadRequestException: Occurs when the request fails. For example due to a validation error.
  • ForbiddenException: Occurs when the user does not have the necessary rights to access this endpoint.
  • NotFoundException: Occurs when the endpoint could not be found.
  • UnauthorizedException: Occurs when the user is not authenticated.
  • UnhandledException: Occurs if an unexpected error occurs.

# Example

The following example shows the simplest implementation of the C# SDK and should serve as a help.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using anybill.POS.Client.Exceptions;
using anybill.POS.Client.Factories;
using anybill.POS.Client.Models.Bill;
using anybill.POS.Client.Models.Bill.CashRegister;
using anybill.POS.Client.Models.Bill.Data;
using anybill.POS.Client.Models.Bill.Data.VatAmount;
using anybill.POS.Client.Models.Bill.Head;
using anybill.POS.Client.Models.Bill.Misc;
using anybill.POS.Client.Models.Bill.Misc.Extension;
using anybill.POS.Client.Models.Bill.Response;
using anybill.POS.Client.Models.Bill.Security;
using anybill.POS.Client.Models.Bill.Security.Extension;
using anybill.POS.Client.Options;

namespace POSLibraryTestProject
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // necessary login data + storeId
            const string username = "";
            const string password = "";
            const string clientId = "";
            const string storeId = "";
            
            // bill object with billOptions
            var bill = new AddBill
            {
                StoreId = storeId,
                Bill = new Bill()
                {
                    CashRegister = new CashRegister()
                    {
                      SerialNumber  = "1234",
                    },
                    Head = new Head()
                    {
                        Date = DateTimeOffset.Now
                    },
                    Data = new Data()
                    {
                        Currency = "EUR",
                        VatAmounts = new List<DataVatAmount>()
                        {
                            new()
                            {
                                Percentage = 7,
                                Vat = (decimal)1.00,
                                ExclVat = (decimal)12.00,
                                InclVat = (decimal)13.00
                            }
                        }
                    },
                    Security = new Security()
                    {
                        Extension = new AnybillSecurityExtension()
                        {
                            TseFailure = true,
                            TseRequired = false
                        }
                    },
                    Misc = new Misc()
                    {
                        Extension = new AnybillMiscExtension()
                        {
                            IsExample = true,
                            IsInvoice = false
                        }
                    }
                }
            };
            var billOptions = new AddBillOptions();

            // registerBillId object
            var registerBillId = new RegisterBillId
            {
                StoreId = storeId
            };

            // create clientFactory and anybillClient
            var clientFactory = new AnybillClientFactory();
            var anybillClient = clientFactory.Create(x => x.WithUsername(username).WithPassword(password).WithClientId(clientId), AnybillEnvironment.Staging);

            try
            {
                // 1. create authentication token
                await anybillClient.Authentication.EnsureAsync();

                // 2. create preGenerated billID (if necessary)
                var registerBillIdResponse = await anybillClient.Bill.RegisterIdAsync(registerBillId);
                switch (registerBillIdResponse)
                {
                    case IRegisterBillIdUrlResponse registerBillIdUrlResponse:
                        Console.WriteLine("BillID: " + registerBillIdUrlResponse.BillId);
                        Console.WriteLine("GetMy website: " + registerBillIdUrlResponse.Url);
                        break;
                    case IRegisterBillIdExternalIdResponse registerBillIdExternalResponse:
                        Console.WriteLine("BillID: " + registerBillIdExternalResponse.BillId);
                        break;
                }

                // 3. add Bill
                var billResponse = await anybillClient.Bill.CreateAsync(bill, billOptions);
                switch (billResponse)
                {
                    case IExternalIdResponse externalIdResponse:
                        Console.WriteLine("IsAssigned: " + externalIdResponse.IsAssigned);
                        break;
                    case ILoyaltyCardResponse loyaltyCardResponse:
                        Console.WriteLine("IsAssigned: " + loyaltyCardResponse.IsAssigned);
                        break;
                    case IMatchedBillResponse matchedBillResponse:
                        Console.WriteLine("IsAssigned: " + matchedBillResponse.IsAssigned);
                        break;
                    case IUrlBillResponse urlBillResponse:
                        Console.WriteLine("GetMy website: " + urlBillResponse.Url);
                        break;
                    case IUserIdResponse userIdResponse:
                        Console.WriteLine("IsAssigned: " + userIdResponse.IsAssigned);
                        break;
                }
            }
            catch (AuthenticationException authenticationException)
            {
                // Authentication failed because username, password or clientId is wrong.
                Console.WriteLine(authenticationException);
            }
            catch (BadRequestException badRequestException)
            {
                // Request failed. e.g. validation error.
                Console.WriteLine(badRequestException.Body);
            }
            catch (ForbiddenException forbiddenException)
            {
                // Request failed because user is not allowed to use the called endpoint.
                Console.WriteLine(forbiddenException);
            }
            catch (NotFoundException notFoundException)
            {
                // Request failed because called endpoint does not exists.
                Console.WriteLine(notFoundException);
            }
            catch (UnauthorizedException unauthorizedException)
            {
                // Request failed because user is not authorized.
                Console.WriteLine(unauthorizedException);
            }
            catch (UnhandledException unhandledException)
            {
                // Request failed for some reason.
                Console.WriteLine(unhandledException);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }
    }
}

# Changelog

# 2023-11-20 (Version 3.0.0.34)

  • added customQuantityMeasure to bill.data.lines.item.extension:anybill
  • made quantityMeasure in bill.data.lines.item optional (if customQuantityMeasure is set)
  • added EmailAddress and SendReceiptByMail to bill.head.buyer to allow custom email solutions
  • FIX: Changes type of remainingAmount in bill.data.paymentTypeInformation.extension:anybill from decimal to double

# 2023-08-21 (Version 3.0.0.33)

  • added remainingAmount to bill.data.paymentTypeInformation.extension:anybill

# 2023-06-07 (Version 3.0.0.31)

  • added publicKey to bill.security.extension:anybill

# 2023-04-26 (Version 3.0.0.30)

  • added isVisible to VatAmountsDto and exclude a vat group from the list overview

# 2023-03-27 (Version 3.0.0.29)

  • Added group taxing to the vat amounts
  • Added countryCode to the UpSertStoreDto

# 2023-03-06 (Version 3.0.0.28)

  • simplify LineItems Object
  • added EquivalentValue to BillDiscount Object
  • added Number to cashRegister Object
  • added PositionCount to Data Object
  • added EquivalentValue to DefaultLineDiscount and mark FullAmountInclVat nullable
  • mark FullAmountInclVat nullable
  • added VatId to Seller Object
  • added Language to UpSertStore Object
  • added PrintedBill Endpoint

# 2022-12-13 (Version 3.0.0.27)

  • Internal changes

# 2022-11-28 (Version 3.0.0.26)

  • Added new BarcodeType to BarcodeCustomSectionData

# 2022-11-25 (Version 3.0.0.25)

  • Added Version to CashRegister
  • Added EquivalentValueName and FullEquivalentValue to AnybillDataExtension
  • Added EquivalentValue and IsReturn to AnybillDefaultLineExtension
  • Added EquivalentValue to AnybillPaymentTypeInformationExtension
  • Added VendorAdditionalReceipt to AdditionalReceipt
  • Added CountrySpecificAttributes to extension:anybill at misc
  • Added ReceiptTransactionType to extension:anybill at misc
  • Added BoiTva to Tse at Security

# 2022-10-17 (Version 3.0.0.24)

  • removed phoneNumber and creditorId from head.extension:anybill
  • Added new additionalHeaderInformation to head.extension:anybill

# 2022-10-04 (Version 3.0.0.23)

  • Adding the new endpoint to cancel a bill
  • Fixed bug in the TSE and RKSV object when TseFailure = true and empty TSE object is transmitted

# 2022-09-28 (Version 3.0.0.22)

  • Removed AdditionalTerminalText and PaymentReceipt in the CardPaymentDetails.

# 2022-09-27 (Version 3.0.0.21)

  • Added new attribue DisableVatAmountsValidation to AnybillDataExtension. With this attribute its possible to disable VatAmounts validation

# 2022-09-26 (Version 3.0.0.20)

  • Added new type KilowattHour to QuantityMeasure
  • Added documentation to PaymentType and QuantityMeasure

# 2022-09-12 (Version 3.0.0.19)

  • Added new barcode types Code128ABarcode, Code128BBarcode, Code128CBarcode to the returnBarcodeType

# 2022-08-31 (Version 3.0.0.18)

  • Internal code refactoring

# 2022-08-30 (Version 3.0.0.17)

  • Added Example code snippets for endpoints

# 2022-07-26 (Version 3.0.0.16)

  • Added onboarding endpoint to the SDK

# 2022-07-22 (Version 3.0.0.15)

  • Added store endpoints to the SDK

# 2022-06-20 (Version 3.0.0.14)

  • Added Ean128 to the AfterSalesCouponType in the AfterSalesCouponsDto

# 2022-05-29 (Version 3.0.0.13)

  • Added isPrintBuffer to the SDK

# 2022-05-02 (Version 3.0.0.12)

  • Added user endpoints to the SDK
  • added customer endpoints to the SDK

# 2022-04-28 (Version 3.0.0.11)

  • Added phoneNumber to head.extension:anybill
  • Added new type Barcode to the ReturnBarcodeType

# 2022-03-15

  • Added new optional attribute alignment in textCustomSectionData to align the text on the PDF receipt.
  • Adjusted user not found object when user couldn't find using the userIdentification object.