Skip to main content

kasseneck_api 10.4.0 copy "kasseneck_api: ^10.4.0" to clipboard
kasseneck_api: ^10.4.0 copied to clipboard

Austrian fiscal cash register (RKSV, Registrierkasse) for Flutter: signed receipts, cancellations, hobex and Stripe card payments, ESC/POS receipt printing.

example/example.dart

// ignore_for_file: avoid_print
//
// Example usage of the kasseneck_api package.
//
// You need an API key and a cashregister token from Kreiseck to operate a
// register. Request yours at office@kreiseck.com (https://kreiseck.com).

import 'package:kasseneck_api/kasseneck_api.dart';
import 'package:kasseneck_api/enums/keck_payment_method.dart';
import 'package:kasseneck_api/enums/vat_rate.dart';
import 'package:kasseneck_api/models/kasseneck_item.dart';

// Local Hobex terminal (HPS), see cardSale() below.
import 'package:kasseneck_api/hobex_hps.dart';

Future<void> main() async {
  final kasseneck = KasseneckApi(
    apiKey: 'YOUR_API_KEY',
    cashregisterToken: 'YOUR_CASHREGISTER_TOKEN',
  );

  // 1) A simple cash sale with two items.
  // The payments must add up to the amount due (receiptDueCents): 2 x 3.20 + 2.40.
  final receipt = await kasseneck.sellReceipt(
    payments: const [KeckPaymentInput(method: KeckPaymentMethod.cash, amountCents: 880)],
    customerDetails: ['Max Mustermann'],
    items: [
      // Prices in cents (320 = EUR 3.20); alternatively KasseneckItem.euro(singlePrice: 3.20)
      KasseneckItem(name: 'Coffee', quantity: 2, vat: VatRate.vat20, priceCents: 320),
      KasseneckItem(name: 'Bread', quantity: 1, vat: VatRate.vat4_9, priceCents: 240),
    ],
  );
  print('Receipt ${receipt?.receiptId}, signed: ${receipt?.signatureSuccess}');

  // 2) Print it via a Bluetooth ESC/POS printer.
  await kasseneck.initBluetoothPrinter(printerAddress: 'AA:BB:CC:DD:EE:FF');
  await receipt?.printReceiptBluetooth();

  // 3) Cancel it again: a new signed cancellation receipt that references the
  //    original. Leave out `items` to cancel everything that is left.
  if (receipt != null) {
    final cancellation = await kasseneck.cancelReceipt(
      cashregisterId: receipt.cashregisterId,
      originalReceiptId: receipt.receiptId,
      reason: 'input_error', // key from cancellationReasons
    );
    print('Cancellation ${cancellation.receipt.receiptId}, remaining: ${cancellation.remaining}');
  }
}

/// Charges a card on a local Hobex terminal (HPS) and turns the result into a
/// signed Kasseneck receipt. Any other terminal works the same way, or use
/// `CreditCardProvider.custom` to pass your own card data.
///
/// Use [HpsPayments], not [HpsClient.payment] directly. Two reasons, both paid
/// for in real money on 2026-08-24:
///
///  * It fixes the transaction id **before** the first request goes out. Let
///    the client generate it and you only learn it from the response, so if
///    the response never arrives, you cannot query or void the transaction,
///    and every retry is a second, independent charge.
///  * It answers the only question a caller has (may I retry?) with three
///    values instead of a boolean. `!isApproved` lumps "declined" together
///    with "still running" and with "no idea".
Future<void> cardSale(KasseneckApi kasseneck) async {
  final payments = HpsPayments(
    HpsClient(tid: '3600335'), // TID without leading zero
  );

  // Fix the id first; persist it if you want to survive an app restart.
  final txId = HpsClient.newTransactionId();
  final res = await payments.pay(amount: 12.50, transactionId: txId);

  switch (res.outcome) {
    case CardPaymentOutcome.declined:
      // Proven: nothing was charged. Retrying is safe.
      //
      // Print the last clarification step, not res.response?.responseCode:
      // when the proof came from a successful abort, that response is the
      // ABORT's, and its code is '0', which means "approved" everywhere
      // else.
      print('Declined: ${res.steps.last}; safe to retry');
      return;
    case CardPaymentOutcome.unresolved:
      // NOT the same as declined. The card may well have been charged.
      // Never retry silently: warn, and keep res.transactionId. It is the
      // only handle left for transactionStatus() or cancel().
      print('Outcome unknown for ${res.transactionId}; do NOT charge again');
      print(res.steps.join('\n'));
      return;
    case CardPaymentOutcome.approved:
      break;
  }

  final card = HobexReceipt.fromHps(res.response!);
  await kasseneck.sellReceipt(
    // The card details belong to the payment itself.
    payments: [
      KeckPaymentInput(
        method: KeckPaymentMethod.creditCard,
        amountCents: 1250,
        provider: card.creditCardProvider,
        providerPaymentId: card.transactionId,
        providerData: card.toCardPaymentData(),
      ),
    ],
    items: [KasseneckItem(name: 'Lunch', quantity: 1, vat: VatRate.vat10, priceCents: 1250)],
  );
}
0
likes
0
points
2.96k
downloads

Publisher

verified publisherkreiseck.com

Weekly Downloads

Austrian fiscal cash register (RKSV, Registrierkasse) for Flutter: signed receipts, cancellations, hobex and Stripe card payments, ESC/POS receipt printing.

Repository (GitHub)
View/report issues

Topics

#pos #payments #receipt #thermal-printer #austria

License

unknown (license)

Dependencies

crypto, flutter, flutter_blue_plus, http, kreiseck_design, my_pos, path_provider, qr, qr_flutter, sumup

More

Packages that depend on kasseneck_api