libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

List.kt (6190B)


      1 /*
      2  * This file is part of LibEuFin.
      3  * Copyright (C) 2025, 2026 Taler Systems S.A.
      4 
      5  * LibEuFin is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU Affero General Public License as
      7  * published by the Free Software Foundation; either version 3, or
      8  * (at your option) any later version.
      9 
     10  * LibEuFin is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
     13  * Public License for more details.
     14 
     15  * You should have received a copy of the GNU Affero General Public
     16  * License along with LibEuFin; see the file COPYING.  If not, see
     17  * <http://www.gnu.org/licenses/>
     18  */
     19 
     20 package tech.libeufin.nexus.cli
     21 
     22 import com.github.ajalt.clikt.core.CliktCommand
     23 import com.github.ajalt.clikt.core.Context
     24 import com.github.ajalt.clikt.core.subcommands
     25 import com.github.ajalt.clikt.parameters.arguments.*
     26 import com.github.ajalt.clikt.parameters.groups.provideDelegate
     27 import com.github.ajalt.clikt.parameters.options.convert
     28 import com.github.ajalt.clikt.parameters.options.default
     29 import com.github.ajalt.clikt.parameters.options.flag
     30 import com.github.ajalt.clikt.parameters.options.option
     31 import com.github.ajalt.clikt.parameters.types.*
     32 import com.github.ajalt.mordant.terminal.*
     33 import tech.libeufin.common.*
     34 import tech.libeufin.nexus.*
     35 import tech.libeufin.nexus.iso20022.*
     36 import java.util.zip.*
     37 import java.time.Instant
     38 import java.io.*
     39 
     40 private fun fmtPayto(payto: String): String {
     41     try {
     42         val parsed = Payto.parse(payto).expectIban()
     43         return buildString {
     44             append(parsed.iban.toString())
     45             if (parsed.bic != null) append(" ${parsed.bic}")
     46             if (parsed.receiverName != null) append(" ${parsed.receiverName}")
     47         }
     48     } catch (e: Exception) {
     49         return payto.removePrefix("payto://")
     50     }
     51 }
     52 
     53 
     54 class ListIncoming: TalerCmd("incoming") {
     55     override fun help(context: Context) = "List incoming transactions"
     56 
     57     private val incomplete by option(
     58         "--incomplete",
     59         help = "Only list transactions that are incomplete",
     60     ).flag()
     61 
     62 
     63     override fun run() = cliCmd(logger) {
     64         nexusConfig(config).withDb { db, cfg ->
     65             val txs = db.list.incoming(incomplete)
     66             for (tx in txs) {
     67                 println(buildString{
     68                     if (tx.creditFee.isZero()) {
     69                         append("${tx.date} ${tx.id} ${tx.amount}\n")
     70                     } else {
     71                         append("${tx.date} ${tx.id} ${tx.amount}-${tx.creditFee}\n")
     72                     }
     73                     if (tx.debtor != null) {
     74                         append("  debtor: ${fmtPayto(tx.debtor)}\n")
     75                     }
     76                     if (tx.subject != null) {
     77                         append("  subject: ${tx.subject}\n")
     78                     }
     79                     if (tx.talerable != null) {
     80                         append("  talerable: ${tx.talerable}\n")
     81                     }
     82                     if (tx.bounced != null) {
     83                         append("  bounced: ${tx.bounced}\n")
     84                     }
     85                 })
     86             }
     87         }
     88     }
     89 }
     90 
     91 class ListOutgoing: TalerCmd("outgoing") {
     92     override fun help(context: Context) = "List outgoing transactions"
     93 
     94     override fun run() = cliCmd(logger) {
     95         nexusConfig(config).withDb { db, cfg ->
     96             val txs = db.list.outgoing()
     97             for (tx in txs) {
     98                 println(buildString{
     99                     append("${tx.date} ${tx.id} ${tx.amount}\n")
    100                     if (tx.creditor != null) {
    101                         append("  creditor: ${fmtPayto(tx.creditor)}\n")
    102                     }
    103                     append("  subject: ${tx.subject}\n")
    104                     if (tx.wtid != null) {
    105                         append("  talerable: ${tx.wtid} ${tx.exchangeBaseUrl}\n")
    106                     }
    107                 })
    108             }
    109         }
    110     }
    111 }
    112 
    113 class ListInitiated: TalerCmd("initiated") {
    114     override fun help(context: Context) = "List initiated transactions"
    115 
    116     private val awaitingAck by option(
    117         "--ack", "--awaiting-ack",
    118         help = "Only list transactions awaiting manual acknowledgement",
    119     ).flag()
    120 
    121     override fun run() = cliCmd(logger) {
    122         nexusConfig(config).withDb { db, cfg ->
    123             if (awaitingAck) {
    124                 val txs = db.list.initiatedAck()
    125                 for (tx in txs) {
    126                     println(buildString{
    127                         append("${tx.date} ${tx.id} ${tx.amount}\n")
    128                         append("  creditor: ${fmtPayto(tx.creditor)}\n")
    129                         append("  subject: ${tx.subject}\n")
    130                         append("  ack: ${tx.dbId}")
    131                         append('\n')
    132                     })
    133                 }
    134             } else {
    135                 val txs = db.list.initiated()
    136                 for (tx in txs) {
    137                     println(buildString{
    138                         append("${tx.date} ${tx.id} ${tx.amount}\n")
    139                         append("  creditor: ${fmtPayto(tx.creditor)}\n")
    140                         append("  subject: ${tx.subject}\n")
    141                         if (tx.batch != null) {
    142                             append("  batch: ${tx.batch}")
    143                             if (tx.batchOrder != null)
    144                             append(" ${tx.batchOrder}")
    145                             append('\n')
    146                         }
    147                         if (tx.submissionCounter > 0) {
    148                             append("  submission: ${tx.submissionTime} ${tx.submissionCounter}\n")
    149                         }
    150                         append("  status: ${tx.status}")
    151                         if (tx.msg != null) {
    152                             append(" ${tx.msg}")
    153                         }
    154                         append('\n')
    155                     })
    156                 }
    157             }  
    158         }
    159     }
    160 }
    161 
    162 
    163 class ListCmd: CliktCommand("list") {
    164     override fun help(context: Context) = "List nexus transactions"
    165 
    166     init {
    167         subcommands(ListIncoming(), ListOutgoing(), ListInitiated())
    168     }
    169 
    170     override fun run() = Unit
    171 }