setKeckReceipt method

Future setKeckReceipt(
  1. KasseneckReceipt receipt, {
  2. QrPrintMode qrMode = QrPrintMode.imageRaster,
})

Implementation

Future setKeckReceipt(KasseneckReceipt receipt, {QrPrintMode qrMode = QrPrintMode.imageRaster}) async {
  reset();

  if (receipt.logo != null) {
    Image image = decodeImage(receipt.logo!)!;
    Image resized = copyResize(image, width: paperSize.imageWidth);

    addImage(resized);
    addFeed();
  }

  addText(receipt.companyName, styles: PosStyles(align: PosAlign.center, bold: true));
  addText(receipt.street, styles: PosStyles(align: PosAlign.center));
  addText('${receipt.zip} ${receipt.city}', styles: PosStyles(align: PosAlign.center));
  addText(receipt.taxInfo, styles: PosStyles(align: PosAlign.center));
  addText(receipt.phone, styles: PosStyles(align: PosAlign.center));

  if (receipt.customerDetails.isNotEmpty) {
    addFeed();

    for (int i = 0; i < receipt.customerDetails.length; i++) {
      if (i == 0) {
        addDoubleText('Kunde:', receipt.customerDetails[i], leftWidth: 5, rightWidth: 7);
      } else {
        addDoubleText('', receipt.customerDetails[i], leftWidth: 1, rightWidth: 11);
      }
    }
  }

  addFeed();
  addDoubleText('Datum:', receipt.readableTime, leftWidth: 4, rightWidth: 8);
  addDoubleText('Kassen-ID:', receipt.cashregisterId);
  addDoubleText('Beleg-ID:', receipt.receiptId);
  addFeed();

  Map<VatRate, List<KasseneckItem>> itemsByVat = {};
  for (KasseneckItem item in receipt.items) {
    if (itemsByVat[item.vat] == null) {
      itemsByVat[item.vat] = [];
    }
    itemsByVat[item.vat]!.add(item);
    String amount = item.quantity.toString().padRight(2);
    if (item.quantity
        .toString()
        .length > 2) {
      amount += ' x';
    } else {
      amount += ' x ';
    }
    addDoubleText('$amount${item.name.check()}${item.quantity > 1 ? ' je ${formatAmount(item.singlePrice)}' : ''}', '${formatAmount(item.singlePrice * item.quantity)} ${item.vat.category}', leftWidth: 7, rightWidth: 5);
  }

  double totalPromoVoucherValue = 0;
  for (KeckVoucher voucher in receipt.vouchers??[]) {

    if (voucher.isValid && voucher.action == VoucherAction.sell) {
      itemsByVat[VatRate.vat0] ??= [];
      itemsByVat[VatRate.vat0]!.add(KasseneckItem(
        name: voucher.receiptText,
        quantity: 1,
        singlePrice: voucher.value ?? 0,
        vat: VatRate.vat0
      ));
    }
    if (voucher.action == VoucherAction.sell && voucher.type == VoucherType.value) {
      String amount = '1  x ';
      addDoubleText('$amount${voucher.receiptText}', '${formatAmount(voucher.value??0)} ${VatRate.vat0.category}', leftWidth: 7, rightWidth: 5);
    }
    if (voucher.action == VoucherAction.redeem && voucher.type == VoucherType.promo) {
      totalPromoVoucherValue += voucher.value ?? 0;
      addDoubleText(voucher.receiptText, '-${formatAmount(voucher.value??0)} EUR', leftWidth: 7, rightWidth: 5);
    }
  }

  final Map<VatRate, int> vatTableBruttoByVatCents = {
    for (final VatRate key in itemsByVat.keys) key: 0,
  };

  itemsByVat.forEach((key, value) {
    int bruttoCents = 0;
    for (final KasseneckItem element in value) {
      bruttoCents += euroToCent(element.singlePrice * element.quantity);
    }
    vatTableBruttoByVatCents[key] = bruttoCents;
  });

  final int totalPromoVoucherValueCents = euroToCent(totalPromoVoucherValue);
  final int totalAmountCents = vatTableBruttoByVatCents.values.fold(0, (sum, value) => sum + value);
  final int usablePromoVoucherValueCents =
      totalPromoVoucherValueCents > totalAmountCents ? totalAmountCents : totalPromoVoucherValueCents;

  if (usablePromoVoucherValueCents > 0 && totalAmountCents > 0) {
    final Map<VatRate, int> promoByVatCents = {
      for (final VatRate key in vatTableBruttoByVatCents.keys) key: 0,
    };

    int usedPromoCents = 0;
    vatTableBruttoByVatCents.forEach((key, bruttoCents) {
      final int proportionalCents = (usablePromoVoucherValueCents * bruttoCents) ~/ totalAmountCents;
      promoByVatCents[key] = proportionalCents;
      usedPromoCents += proportionalCents;
    });

    final int remainingPromoCents = usablePromoVoucherValueCents - usedPromoCents;
    if (remainingPromoCents > 0) {
      final List<MapEntry<VatRate, int>> sortedGroups = vatTableBruttoByVatCents.entries.toList()
        ..sort((a, b) => b.value.compareTo(a.value));

      if (sortedGroups.isNotEmpty && sortedGroups.first.value > 0) {
        promoByVatCents[sortedGroups.first.key] =
            (promoByVatCents[sortedGroups.first.key] ?? 0) + remainingPromoCents;
      }
    }

    promoByVatCents.forEach((key, promoCents) {
      vatTableBruttoByVatCents[key] = (vatTableBruttoByVatCents[key] ?? 0) - promoCents;
    });
  }

  addFeed();

  _addTable('MwSt%', 'MwSt', 'Netto', 'Brutto');

  vatTableBruttoByVatCents.forEach((key, bruttoCents) {
    final double brutto = centToEuro(bruttoCents);
    final num mwstSatz = key.rate;
    final double netto = brutto / (1 + (mwstSatz / 100));
    final double mwst = brutto - netto;

    _addTable('${key.category} ${key.rate.toString().replaceAll('.', ',')}%', formatAmount(mwst), formatAmount(netto), formatAmount(brutto));
  });

  addFullHorizontalLine();

  if (receipt.sum != receipt.subSum) {
    addDoubleText('Zwischensumme', '${formatAmount(receipt.subSum)} EUR');

    for (KeckVoucher voucher in receipt.vouchers??[]) {
      if (voucher.action == VoucherAction.redeem && voucher.type == VoucherType.value) {
        addDoubleText(voucher.receiptText, '-${formatAmount(voucher.value??0)} EUR');
      }
    }

    addFullHorizontalLine();
  }
  addDoubleText('Gesamt:', '${formatAmount(receipt.sum)} EUR');

  addFeed();

  if (receipt.legalMessage.isNotEmpty) {
    for (String line in receipt.legalMessage) {
      addText(line, styles: PosStyles(align: PosAlign.center));
    }
    addFeed();
  }
  if (receipt.isSigFailed) {
    addText(RKSVService.signatureDeviceDamagedKey, styles: PosStyles(align: PosAlign.center));
    addFeed();
  }


  switch (qrMode) {
    case QrPrintMode.imageRaster:
      await addQrCodeAsImage(receipt.qr, raster: true);
      break;
    case QrPrintMode.imageBitImage:
      await addQrCodeAsImage(receipt.qr, raster: false);
      break;
    case QrPrintMode.native:
      addQrCode(receipt.qr);
      break;
  }

  addFeed();

  if (receipt.cardPaymentData != null && receipt.creditCardProvider != null) {
    try {
      switch (receipt.creditCardProvider!) {
        case CreditCardProvider.gpTomAndroid:
        case CreditCardProvider.gpTomIos:
          _gpTom(receipt.cardPaymentData!);
          break;
        case CreditCardProvider.hobexCloudApi:
          _hobexApi(receipt.cardPaymentData!);
          break;
        case CreditCardProvider.hobexHps:
          _hobexHps(receipt.cardPaymentData!);
          break;
        case CreditCardProvider.sumup:
          _sumup(receipt.cardPaymentData!);
          break;
        case CreditCardProvider.custom:
          break;
        case CreditCardProvider.myposPro:
          _mypos(receipt.cardPaymentData!);
          break;
      }
      addFeed();
    } catch (_) {
      // Fehlerhafte cardPaymentData darf den Beleg-Druck nicht abbrechen
    }
  }

  if (receipt.thanksMessage.isNotEmpty) {
    addFeed();
    for (String message in receipt.thanksMessage) {
      addText(message, styles: PosStyles(align: PosAlign.center));
    }
  }

  addText(receipt.footer1, styles: PosStyles(align: PosAlign.center));
  addText(receipt.footer2, styles: PosStyles(align: PosAlign.center));
  if (receipt.footer3 != null) {
    addText(receipt.footer3!, styles: PosStyles(align: PosAlign.center));
  }
  if (receipt.footer4 != null) {
    addText(receipt.footer4!, styles: PosStyles(align: PosAlign.center));
  }
  addCut();
}