bill

Version: 2.1.5

Contains functionalities to receive the receipts from the POS.

Having problems? Contact us at <dev@anybill.de>

Release History

  • 2.1.5

    • Add new model RKSV and enum TSEType.

    • BREAKING:

      • Change type of NoScanBill.security.tse to an abstract class TSEBase. TSEBase can be one of its subclasses TSE or RKSV determined by it's parameter type.

  • 2.1.4

    • Add AnybillURLUtils which can be used to check URLs/Strings for existing bill id. (E.g. after scanning a POS QR Code)

    • Change Return of addBillByID/addBillByURl to BillAddedResponse which contains the added id and a flag which determines if the bill is a "Pregenerated" Bill. Further information to Pregenerated Bills can be found here.

  • 2.1.3

    • Made values of UpsertBillDTO editable.

      • Bills should now be updated by filling the UpsertBillDTO with the bill's previous values. New changes should then be applied on the UpsertBillDTO afterwards.

  • 2.1.2

    • Remove deprecated parameter id from all PaymentDetails-types

  • 2.1.1

    • Extend Bill Model with values:

      • Misc.isHospitalityBill, Misc.hospitalityBillInformation, Misk.customSections, Misk.contentAreaId

      • Head.creditorId

      • Data.fullAmountInclVatBeforeDiscounts,Data.tip

      • See documentation for detailed description of usage

    • Add method to update NoScanBills. Use Billprovider.updateBill() with an UpsertBillDTO.

  • 2.1.0

    • Upgrade to Gradle 7 and Java 11

    • Improve caching algorithm by changing Room queries

    • Add CurrencyUtils object including helper functions for currency Strings

  • 2.0.2

    • Improve internal logging

  • 2.0.1

    • Upgrade dependencies

  • 2.0.0

    • Refactor bill model to new anybill API Version

      • More detailed model for Bills based on the DFKA (v1.0.0)

      • Improve serialization of bill models by extending null safety

  • 1.1.3

    • Made parameter name in LineItem nullable

  • 1.1.2

    • Replaced deprecated LocalBroadcastManager

  • 1.1.1

    • Extend Warranty model with notification flag

  • 1.1.0

    • Reset version number on Artifactory Move

Resolving the artifact using gradle:

Add this to your project's build.gradle with:

allprojects {
repositories {
maven {
url "https://anybill.jfrog.io/artifactory/anybill_android_sdk"
credentials {
username = {username}
password = {password}
}
}
}
}

Add this to your module's build.gradle:

dependencies {
implementation 'de.anybill.anybill_android_sdk:bill:{latest version}'
}

Resolving the artifact using maven:

Add this to your settings.xml:

<?xml version="1.0" encoding="UTF-8"?>
<settings
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"
xmlns="http://maven.apache.org/SETTINGS/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<servers>
<server>
<username>${security.getCurrentUsername()}</username>
<password>${security.getEscapedEncryptedPassword()!"*** Insert encrypted password here ***"}</password>
<id>central</id>
</server>
<server>
<username>${security.getCurrentUsername()}</username>
<password>${security.getEscapedEncryptedPassword()!"*** Insert encrypted password here ***"}</password>
<id>snapshots</id>
</server>
</servers>
<profiles>
<profile>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>maven-release</name>
<url>https://anybill.jfrog.io/artifactory/maven-release</url>
</repository>
<repository>
<snapshots />
<id>snapshots</id>
<name>maven-release</name>
<url>https://anybill.jfrog.io/artifactory/maven-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>maven-release</name>
<url>https://anybill.jfrog.io/artifactory/maven-release</url>
</pluginRepository>
<pluginRepository>
<snapshots />
<id>snapshots</id>
<name>maven-release</name>
<url>https://anybill.jfrog.io/artifactory/maven-release</url>
</pluginRepository>
</pluginRepositories>
<id>artifactory</id>
</profile>
</profiles>
<activeProfiles>
<activeProfile>artifactory</activeProfile>
</activeProfiles>
</settings>

Add this dependency:

<dependency>
<groupId>de.anybill.anybill_android_sdk</groupId>
<artifactId>bill</artifactId>
<version>{latest version}</version>
<type>pom</type>
</dependency>

Required modules

The bill module depends on the following anybill SDK modules and can't be used without them:

:core
:auth

The bill module is part of the SDK's core functions which consists of the following SDK modules:

:core
:bill
:auth
:category
:log

Please add the corresponding dependencies to your module's build.gradle.

Coming soon: Single dependency for the SDK's core functions.

Usage

Error Handling

The anybill sdk uses a custom error handling model. All methods return a type of the sealed class ApiResult, including the return object on success and/or information about the error which occurred. Detailed description of the possible error codes can be found in the corresponding documentation of the methods

sealed class ApiResult<out T> {

/**
* Success\
* Used when Api Call and serialization was successful\
*
* @param T Type [T] of the object which should be returned if Api call and JSON Serialization was successful
* @property value Object of type [T] holding the serialized result of the api call
*/

data class Success<out T>(val value: T) : ApiResult<T>()

/**
* Generic error\
* Used if a generic error occurs during execution of the api call or serialization of the received data\
* Possible GenericError's of each operation are listed in the method documentation
*
* @property code Nullable [Int] with the Error Code of the exception
* @property error Nullable [ErrorResponse] object with further exception information
*/

data class GenericError(val code: Int? = null, val error: ErrorResponse? = null) : ApiResult<Nothing>()

/**
* Empty success\
* Used if the execution of the api call and the serialization of the result was successful without a need of a result object (e.g. token operations)\
*
*/

object EmptySuccess : ApiResult<Nothing>()

/**
* Network error\
* Used if a network error occurs during execution of the api call (e.g. timeout, no network)
*/

object NetworkError : ApiResult<Nothing>()
}

Example usage of the error model based on the loginCall of the AuthProvider.

fun loginUser(email: String, password: String) {
viewModelScope.launch {
when (val loginTask = AuthProvider.loginUser(email = email, password = password)) {
is NetworkError -> //Error Handling
is GenericError -> {
when(loginTask.code){
INVALID_DATA -> //Error Handling
SERVER_ERROR -> //Error Handling
REFRESH_ERROR -> //Error Handling
}
}
is EmptySuccess -> //Success
}
}
}

Example usage of the public provider and models:

Providers

BillProvider

Singleton provider granting access to the anybill bill functions. Most functions of the BillProvider are suspend functions and have to be called in a coroutine scope.

Retrieving user's bills

With its caching technique the anybill sdk stores the user's bills in a local database and updates them using the anybill backend when needed. The anybill sdk provides a LiveData object bills representing a list of bills which can be observed in your app. By calling BillProvider's updateBills() method the LiveData object gets filled with the locally cached bills first and updated with the newly modified/added bills as soon as the API operation completed.

Sample-Code for your ViewModel:

    //This LiveData can be observed in your View
val billList : LiveData<List<Bill>> = BillProvider.bills

//Call this to initialize/fill/update the LiveData object
fun updateBills(){
viewModelScope.launch{
BillProvider.updateBills()
}
}

To receive all of the user's bills without the caching process the anybill sdk provides the getBills() (includes parameters for pagination) method.

    val billList: MutableLiveData<Bill> = MutableLiveData<Bill>()

fun getAllBills(){
viewModelScope.launch {
when (val billCall = BillProvider.getBills()) {
is NetworkError -> //Error Handling
is GenericError -> //Error Handling
is Success -> {
billList.postValue(billCall.value)
}
}
}
}

To get all Bills by Category (see Category module) use 'getBillsFromCategory(categoryId: String)'.

Adding bills

The anybill SDK provides several ways to add a Bill to the users account.

QR-Code on POS-Terminal

To add a bill from the QR-Code on the POS-Terminal use a common QR-Code Reader and extract the information of the shown QR Code. The data includes an URL with the ID of the Bill which should be added to the users account. Add the bill by calling on of the listed Methods with your preferred parameter type.

  //Depending on the QR Code Scanner you are going to receive a String or URL object.
//
//Format:
// https://getmy.anybill.de/#/bill/b45f4b77-9c3c-454a-8b87-08d8bbd02f7e
//
//You can choose to parse and validate the URL before using the sdk or call one of the following methods:

BillProvider.addBillByID(billID: String)

BillProvider.addBillByURL(url: URL)

BillProvider.addBillByString(url: String)

QR-Code on Mobile-Screen

To add a bill with a QR-Code on the user's phone screen use AuthProviders QR-Code Data method. (See auth module documentation)

Exporting bills

PDF

To share or save a bill as PDF exportBillAsPDF(bill: Bill) returns an URI of a PDF file in the cached directory of the app. The Uri can then be shared using an intent or saved on the user's device. (Generation of the PDF file takes up to 30 sec)

Share PDF in other apps:

    fun exportBillToPDF(bill: Bill) {
viewModelScope.launch {
when (val exportCall = billProvider.exportBillAsPDF(bill)) {
is ApiResult.Success -> startIntent(exportCall.value)
is ApiResult.GenericError -> //Error Handling
is ApiResult.NetworkError -> //Error Handling
}
}
}
private fun startIntent(uri: Uri) {
val intent = Intent()
intent.action = Intent.ACTION_SEND
intent.type = "application/pdf"
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(share)
}

ZIP

If the user wants to get hold of all his bills as PDF files, the anybill SDK provides an endpoint to generate a .zip file containing the user's bills and send it to his email address.

    fun exportAllBills() {
viewModelScope.launch {
when(val exportCall = billProvider.exportBills()){
is ApiResult.EmptySuccess -> //Success
is ApiResult.GenericError -> //Error Handling
is ApiResult.NetworkError -> //Error Handling
}
}
}

Deleting bills

Deleting a bill is irreversible. After deleting a bill with BillProvider.deleteBill(bill: Bill) the LiveData object should be updated using updateBills().

Models

Bill

Bill

Bill is an abstract class and represents both ScanBill and NoScanBill which are distinguish through the type parameter.

ScanBill

Bills of type ScanBill represent all bills created or added by the user. Either manually or with the OCR scan (OCR module). It's not mandatory for ScanBills to have a OCR scan or images.

NoScanBill

Bills of type NoScanBill are solely created by the anybill API (e.g. the POS-Terminal).

Detailed description of the structure and function of models/variables can be found in the code or provided KDoc.

Packages