
# 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](./configuration).

## Required Packages
The following packages must be installed:
- anybill.POS.Client
- anybill.POS.Client.Abstractions

Optional Package:
- anybill.POS.Client.Microsoft.Extensions.DependencyInjection

Download the full documentation <a href="https://developer.anybill.de/documents/docs.zip" download>here</a>

## 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

```csharp
var clientFactory = new AnybillClientFactory();
var anybillClient = clientFactory.Create(
        new AnybillAuthenticationOptions(username, password, clientId),
        AnybillEnvironment.Test);
```

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.

```csharp
await anybillClient.Authentication.EnsureAsync();
```

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

```csharp
var registerReceiptId = new RegisterReceiptId
{
    StoreId = storeId
};

var registerReceiptIdResponse = await anybillClient.Receipt.RegisterIdAsync(registerReceiptId);

if (registerReceiptIdResponse is IRegisterBillIdUrlResponse registerReceiptIdUrlResponse)
{
    // do something
}
```

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

## Add Receipt
Adding the receipt is composed of the `receipt` itself and the associated `receiptOptions`. As a result one of the following interfaces is returned:
- IExternalIdResponse
- ILoyaltyCardResponse
- IMatchedReceiptResponse
- IUrlReceiptResponse
- IUserIdResponse

```csharp
var receiptResponse = await anybillClient.Receipt.CreateAsync(receipt, receiptOptions);

if (receiptResponse is IExternalIdResponse externalIdResponse)
{
    // do something
}
else if (receiptResponse is IUrlReceiptResponse urlReceiptResponse)
{
    // do something
}
```

## Printed Receipt
You can mark a receipt as printed with the `PrintedReceiptAsync`method. 

```csharp
var printedReceiptResponse = await anybillClient.Receipt.PrintedReceiptAsync(receiptId);

if (printedReceiptResponse is IPrintedReceiptResponse printedResponse)
{
    // use printedResponse here
}
```

## 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.

```csharp
try {
    await anybillClient.Authentication.EnsureAsync();

    var registerReceiptIdResponse = await anybillClient.Receipt.RegisterIdAsync(registerReceiptId);

    ...
}
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);
}

```

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

```csharp
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.Receipt;
using anybill.POS.Client.Models.Receipt.CashRegister;
using anybill.POS.Client.Models.Receipt.Data;
using anybill.POS.Client.Models.Receipt.Data.VatAmount;
using anybill.POS.Client.Models.Receipt.Head;
using anybill.POS.Client.Models.Receipt.Misc;
using anybill.POS.Client.Models.Receipt.Misc.Extension;
using anybill.POS.Client.Models.Receipt.Response;
using anybill.POS.Client.Models.Receipt.Security;
using anybill.POS.Client.Models.Receipt.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 = "";
            
            // receipt object with receiptOptions
            var receipt = new AddReceipt
            {
                StoreId = storeId,
                Receipt = new Receipt()
                {
                    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()
                        {
                            Failure = true,
                            Required = false
                        }
                    },
                    Misc = new Misc()
                    {
                        Extension = new AnybillMiscExtension()
                        {
                            IsExample = true,
                            IsInvoice = false
                        }
                    }
                }
            };
            var receiptOptions = new AddReceiptOptions();

            // registerReceiptId object
            var registerReceiptId = new RegisterReceiptId
            {
                StoreId = storeId
            };

            // create clientFactory and anybillClient
            var clientFactory = new AnybillClientFactory();
            var anybillClient = clientFactory.Create(
                new AnybillAuthenticationOptions(username, password, clientId),
                AnybillEnvironment.Test);

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

                // 2. create preGenerated receiptID (if necessary)
                var registerReceiptIdResponse = await anybillClient.Receipt.RegisterIdAsync(registerReceiptId);
              

                if (registerReceiptIdResponse is IRegisterBillIdUrlResponse registerReceiptIdUrlResponse)
                {
                    Console.WriteLine("ReceiptID: " + registerReceiptIdUrlResponse.ReceiptId);
                    Console.WriteLine("GetMy website: " + registerBillIdUrlResponse.Url);
                }

                // 3. add Receipt
                var receiptResponse = await anybillClient.Receipt.CreateAsync(receipt, receiptOptions);
                switch (receiptResponse)
                {
                    case IExternalIdResponse externalIdResponse:
                        Console.WriteLine("IsAssigned: " + externalIdResponse.IsAssigned);
                        break;
                    case ILoyaltyCardResponse loyaltyCardResponse:
                        Console.WriteLine("IsAssigned: " + loyaltyCardResponse.IsAssigned);
                        break;
                    case IMatchedReceiptResponse matchedReceiptResponse:
                        Console.WriteLine("IsAssigned: " + matchedReceiptResponse.IsAssigned);
                        break;
                    case IUrlReceiptResponse urlReceiptResponse:
                        Console.WriteLine("GetMy website: " + urlReceiptResponse.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);
            }
        }
    }
}
```

## Additional Resources

### 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.
```csharp
var customerActivated = await anybillClient.Customer.IsActivatedAsync();
if(customerActivated.Type == "activated")
    // Allowed to call other endpoints
```

### Stores
Multiple functions exist to manage stores. To get all stores `GetStoresAsync` can be used.
```csharp
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`.
```csharp
var store = await anybillClient.Store.GetStoreByIdAsync(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.
```csharp
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.
```csharp
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.
```csharp
var userIdentificationResponse = await anybillClient.User.IdentifyAsync(userIdentificationObject, cancellationToken);
var userId = userIdentificationResponse.UserId;
```