commit 66fe30878986a6accc16712474c699a53e8705bb
parent 5490a93b97307481d72bea3142ba1e6abafced7d
Author: Antoine A <>
Date: Mon, 10 Jun 2024 14:31:39 +0200
bank: support wire transfer fees
Diffstat:
15 files changed, 229 insertions(+), 86 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -6,6 +6,7 @@ testbench/config.json
configure
build/
.gradle
+.kotlin
out
*.sqlite3
*.swp
diff --git a/API_CHANGES.md b/API_CHANGES.md
@@ -56,6 +56,7 @@ This files contains all the API changes for the current release:
- PATCH /accounts/USERNAME: add min_cashout field for the custom minimum cashout amount
- GET /accounts: add min_cashout field for the custom minimum cashout amount
- GET /accounts/USERNAME: add min_cashout field for the custom minimum cashout amount
+- GET /config: new wire_transfer_fees field for transaction fees
## bank cli
diff --git a/bank/conf/test_with_fees.conf b/bank/conf/test_with_fees.conf
@@ -0,0 +1,18 @@
+[libeufin-bank]
+CURRENCY = KUDOS
+WIRE_TYPE = iban
+IBAN_PAYTO_BIC = SANDBOXX
+DEFAULT_DEBT_LIMIT = KUDOS:100
+SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.example.com
+ALLOW_REGISTRATION = yes
+ALLOW_ACCOUNT_DELETION = yes
+ALLOW_EDIT_NAME = yes
+ALLOW_EDIT_CASHOUT_PAYTO_URI = yes
+allow_conversion = YES
+FIAT_CURRENCY = EUR
+tan_sms = libeufin-tan-file.sh
+tan_email = libeufin-tan-file.sh
+wire_transfer_fees = KUDOS:0.1
+
+[libeufin-bankdb-postgres]
+CONFIG = postgresql:///libeufincheck
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Config.kt b/bank/src/main/kotlin/tech/libeufin/bank/Config.kt
@@ -35,7 +35,7 @@ data class BankConfig(
val baseUrl: String?,
val regionalCurrency: String,
val regionalCurrencySpec: CurrencySpecification,
- val wireTransferFees: TalerAmount?,
+ val wireTransferFees: TalerAmount,
val allowRegistration: Boolean,
val allowAccountDeletion: Boolean,
val allowEditName: Boolean,
@@ -127,7 +127,7 @@ fun TalerConfig.loadBankConfig(): BankConfig {
allowConversion = allowConversion,
defaultDebtLimit = amount("libeufin-bank", "default_debt_limit", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
registrationBonus = amount("libeufin-bank", "registration_bonus", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
- wireTransferFees = amount("libeufin-bank", "wire_transfer_fees", regionalCurrency),
+ wireTransferFees = amount("libeufin-bank", "wire_transfer_fees", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
suggestedWithdrawalExchange = lookupString("libeufin-bank", "suggested_withdrawal_exchange"),
spaPath = lookupPath("libeufin-bank", "spa"),
baseUrl = lookupString("libeufin-bank", "base_url"),
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Constants.kt b/bank/src/main/kotlin/tech/libeufin/bank/Constants.kt
@@ -37,6 +37,6 @@ val RESERVED_ACCOUNTS = setOf("admin", "bank")
const val IBAN_ALLOCATION_RETRY_COUNTER: Int = 5
// API version
-const val COREBANK_API_VERSION: String = "4:8:1"
+const val COREBANK_API_VERSION: String = "4:9:1"
const val CONVERSION_API_VERSION: String = "0:1:0"
const val INTEGRATION_API_VERSION: String = "2:0:3"
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
@@ -302,7 +302,8 @@ data class Config(
val allow_edit_cashout_payto_uri: Boolean,
val default_debit_threshold: TalerAmount,
val supported_tan_channels: Set<TanChannel>,
- val wire_type: WireMethod
+ val wire_type: WireMethod,
+ val wire_transfer_fees: TalerAmount
) {
val name: String = "libeufin-bank"
val version: String = COREBANK_API_VERSION
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt
@@ -62,7 +62,8 @@ fun Routing.coreBankApi(db: Database, ctx: BankConfig) {
supported_tan_channels = ctx.tanChannels.keys,
allow_edit_name = ctx.allowEditName,
allow_edit_cashout_payto_uri = ctx.allowEditCashout,
- wire_type = ctx.wireMethod
+ wire_type = ctx.wireMethod,
+ wire_transfer_fees = ctx.wireTransferFees
)
)
}
@@ -455,7 +456,8 @@ private fun Routing.coreBankTransactionsApi(db: Database, ctx: BankConfig) {
amount = amount,
timestamp = Instant.now(),
requestUid = req.request_uid,
- is2fa = challenge != null
+ is2fa = challenge != null,
+ wireTransferFees = ctx.wireTransferFees
)
when (res) {
BankTransactionResult.UnknownDebtor -> throw unknownAccount(username)
@@ -489,9 +491,14 @@ private fun Routing.coreBankWithdrawalApi(db: Database, ctx: BankConfig) {
auth(db, TokenScope.readwrite) {
post("/accounts/{USERNAME}/withdrawals") {
val req = call.receive<BankAccountCreateWithdrawalRequest>()
- // TODO check card_fees
req.amount?.run(ctx::checkRegionalCurrency)
req.suggested_amount?.run(ctx::checkRegionalCurrency)
+ if (req.card_fees != null) {
+ throw conflict(
+ "card_fees differ from wire_transfer_fees",
+ TalerErrorCode.END
+ )
+ }
val opId = UUID.randomUUID()
when (db.withdrawal.create(
username,
@@ -522,7 +529,7 @@ private fun Routing.coreBankWithdrawalApi(db: Database, ctx: BankConfig) {
post("/accounts/{USERNAME}/withdrawals/{withdrawal_id}/confirm") {
val id = call.uuidPath("withdrawal_id")
val challenge = call.checkChallenge(db, Operation.withdrawal)
- when (db.withdrawal.confirm(username, id, Instant.now(), challenge != null)) {
+ when (db.withdrawal.confirm(username, id, ctx.wireTransferFees, Instant.now(), challenge != null)) {
WithdrawalConfirmationResult.UnknownOperation -> throw notFound(
"Withdrawal operation $id not found",
TalerErrorCode.BANK_TRANSACTION_NOT_FOUND
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
@@ -164,7 +164,7 @@ class AccountDAO(private val db: Database) {
if (bonus.value != 0L || bonus.frac != 0) {
conn.prepareStatement("""
SELECT out_balance_insufficient
- FROM bank_transaction(?,'admin','bonus',(?,?)::taler_amount,?,true,NULL)
+ FROM bank_transaction(?,'admin','bonus',(?,?)::taler_amount,?,true,NULL,(0, 0)::taler_amount)
""").run {
setString(1, internalPayto.canonical)
setLong(2, bonus.value)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/TransactionDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/TransactionDAO.kt
@@ -51,6 +51,7 @@ class TransactionDAO(private val db: Database) {
timestamp: Instant,
is2fa: Boolean,
requestUid: ShortHashCode?,
+ wireTransferFees: TalerAmount
): BankTransactionResult = db.serializable { conn ->
val now = timestamp.micros()
conn.transaction {
@@ -70,7 +71,7 @@ class TransactionDAO(private val db: Database) {
,out_debtor_is_exchange
,out_creditor_admin
,out_idempotent
- FROM bank_transaction(?,?,?,(?,?)::taler_amount,?,?,?)
+ FROM bank_transaction(?,?,?,(?,?)::taler_amount,?,?,?,(?,?)::taler_amount)
"""
)
stmt.setString(1, creditAccountPayto.canonical)
@@ -81,6 +82,8 @@ class TransactionDAO(private val db: Database) {
stmt.setLong(6, now)
stmt.setBoolean(7, is2fa)
stmt.setBytes(8, requestUid?.raw)
+ stmt.setLong(9, wireTransferFees.value)
+ stmt.setInt(10, wireTransferFees.frac)
stmt.executeQuery().use {
when {
!it.next() -> throw internalServerError("Bank transaction didn't properly return")
@@ -125,8 +128,7 @@ class TransactionDAO(private val db: Database) {
// No error can happens because an opposite transaction already took place in the same transaction
conn.prepareStatement("""
SELECT bank_wire_transfer(
- ?, ?, ?, (?, ?)::taler_amount, ?,
- NULL, NULL, NULL
+ ?, ?, ?, (?, ?)::taler_amount, ?, (0, 0)::taler_amount
);
"""
).run {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/WithdrawalDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/WithdrawalDAO.kt
@@ -179,6 +179,7 @@ class WithdrawalDAO(private val db: Database) {
suspend fun confirm(
login: String,
uuid: UUID,
+ wireTransferFees: TalerAmount,
now: Instant,
is2fa: Boolean
): WithdrawalConfirmationResult = db.serializable { conn ->
@@ -190,13 +191,15 @@ class WithdrawalDAO(private val db: Database) {
out_not_selected,
out_aborted,
out_tan_required
- FROM confirm_taler_withdrawal(?,?,?,?);
+ FROM confirm_taler_withdrawal(?,?,?,?,(?,?)::taler_amount);
"""
)
stmt.setString(1, login)
stmt.setObject(2, uuid)
stmt.setLong(3, now.micros())
stmt.setBoolean(4, is2fa)
+ stmt.setLong(5, wireTransferFees.value)
+ stmt.setInt(6, wireTransferFees.frac)
stmt.executeQuery().use {
when {
!it.next() ->
diff --git a/bank/src/test/kotlin/AmountTest.kt b/bank/src/test/kotlin/AmountTest.kt
@@ -54,7 +54,8 @@ class AmountTest {
amount = due,
timestamp = Instant.now(),
is2fa = false,
- requestUid = null
+ requestUid = null,
+ wireTransferFees = TalerAmount("KUDOS:0")
)
val txBool = when (txRes) {
BankTransactionResult.BalanceInsufficient -> false
diff --git a/bank/src/test/kotlin/BankIntegrationApiTest.kt b/bank/src/test/kotlin/BankIntegrationApiTest.kt
@@ -58,6 +58,7 @@ class BankIntegrationApiTest {
assert(!it.selection_done)
assert(!it.aborted)
assert(!it.transfer_done)
+ assertEquals(it.card_fees, TalerAmount("KUDOS:0"))
assertEquals(amount, it.amount)
assertEquals(suggested, it.suggested_amount)
assertEquals(listOf("iban"), it.wire_types)
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -1133,6 +1133,49 @@ class CoreBankTransactionsApiTest {
}
}.assertConflict(TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED)
}
+
+ @Test
+ fun createWithFee() = bankSetup(conf = "test_with_fees.conf") {
+ // Init state
+ assertBalance("merchant", "+KUDOS:0")
+ assertBalance("customer", "+KUDOS:0")
+ assertBalance("admin", "+KUDOS:0")
+
+ // Check fee are sent to admin
+ tx("merchant", "KUDOS:3", "customer")
+ assertBalance("merchant", "-KUDOS:3.1")
+ assertBalance("customer", "+KUDOS:3")
+ assertBalance("admin", "+KUDOS:0.1")
+
+ // Check amount with fee are checked
+ for (amount in listOf("KUDOS:7", "KUDOS:6.9")) {
+ println(amount)
+ client.postA("/accounts/merchant/transactions") {
+ json {
+ "payto_uri" to "$customerPayto?message=payout2&amount=$amount"
+ }
+ }.assertConflict(TalerErrorCode.BANK_UNALLOWED_DEBIT)
+ }
+
+ // Check empty account
+ tx("merchant", "KUDOS:6.8", "customer")
+ assertBalance("merchant", "-KUDOS:10")
+ assertBalance("customer", "+KUDOS:9.8")
+ assertBalance("admin", "+KUDOS:0.2")
+
+ // Admin check no fee
+ tx("admin", "KUDOS:0.35", "merchant")
+ assertBalance("merchant", "-KUDOS:9.65")
+ assertBalance("admin", "-KUDOS:0.15")
+
+ // Admin recover from debt
+ tx("customer", "KUDOS:1", "merchant")
+ assertBalance("admin", "-KUDOS:0.05")
+ tx("customer", "KUDOS:1", "merchant")
+ assertBalance("merchant", "-KUDOS:7.65")
+ assertBalance("customer", "+KUDOS:7.6")
+ assertBalance("admin", "+KUDOS:0.05")
+ }
}
class CoreBankWithdrawalApiTest {
diff --git a/bank/src/test/kotlin/GcTest.kt b/bank/src/test/kotlin/GcTest.kt
@@ -105,14 +105,14 @@ class GcTest {
db.withdrawal.setDetails(uuid, exchangePayto, EddsaPublicKey.rand(), null)
)
assertEquals(
- db.withdrawal.confirm(account, uuid, time, false),
+ db.withdrawal.confirm(account, uuid, TalerAmount("KUDOS:0"), time, false),
WithdrawalConfirmationResult.Success
)
assertIs<CashoutCreationResult.Success>(
db.cashout.create(account, ShortHashCode.rand(), from, to, "", time, false),
)
assertIs<BankTransactionResult.Success>(
- db.transaction.create(customerPayto, account, "", from, time, false, ShortHashCode.rand()),
+ db.transaction.create(customerPayto, account, "", from, time, false, ShortHashCode.rand(), TalerAmount("KUDOS:0")),
)
}
for (time in listOf(now, abort, clean, delete)) {
diff --git a/database-versioning/libeufin-bank-procedures.sql b/database-versioning/libeufin-bank-procedures.sql
@@ -320,9 +320,7 @@ SELECT
in_subject,
in_amount,
in_timestamp,
- NULL,
- NULL,
- NULL
+ (0, 0)::taler_amount
) as transfer;
IF out_exchange_balance_insufficient THEN
RETURN;
@@ -398,9 +396,7 @@ SELECT
in_subject,
in_amount,
in_timestamp,
- NULL,
- NULL,
- NULL
+ (0, 0)::taler_amount
) as transfer;
IF out_debitor_balance_insufficient THEN
RETURN;
@@ -418,6 +414,7 @@ CREATE FUNCTION bank_transaction(
IN in_timestamp INT8,
IN in_is_tan BOOLEAN,
IN in_request_uid BYTEA,
+ IN in_wire_transfer_fees taler_amount,
-- Error status
OUT out_creditor_not_found BOOLEAN,
OUT out_debtor_not_found BOOLEAN,
@@ -489,12 +486,11 @@ SELECT
in_subject,
in_amount,
in_timestamp,
- NULL,
- NULL,
- NULL
+ in_wire_transfer_fees
) as transfer;
-
--- TODO wire transfer fees
+IF out_balance_insufficient THEN
+ RETURN;
+END IF;
-- Store operation
IF in_request_uid IS NOT NULL THEN
@@ -653,6 +649,7 @@ CREATE FUNCTION confirm_taler_withdrawal(
IN in_withdrawal_uuid uuid,
IN in_confirmation_date INT8,
IN in_is_tan BOOLEAN,
+ IN in_wire_transfer_fees taler_amount,
OUT out_no_op BOOLEAN,
OUT out_balance_insufficient BOOLEAN,
OUT out_creditor_not_found BOOLEAN,
@@ -719,16 +716,12 @@ FROM bank_wire_transfer(
subject_local,
amount_local,
in_confirmation_date,
- NULL,
- NULL,
- NULL
+ in_wire_transfer_fees
) as transfer;
IF out_balance_insufficient THEN
RETURN;
END IF;
--- TODO wire transfer fees
-
-- Confirm operation
UPDATE taler_withdrawal_operations
SET confirmation_done = true
@@ -749,9 +742,7 @@ CREATE FUNCTION bank_wire_transfer(
IN in_subject TEXT,
IN in_amount taler_amount,
IN in_transaction_date INT8,
- IN in_account_servicer_reference TEXT,
- IN in_payment_information_id TEXT,
- IN in_end_to_end_id TEXT,
+ IN in_fee taler_amount,
-- Error status
OUT out_balance_insufficient BOOLEAN,
-- Success return
@@ -760,6 +751,12 @@ CREATE FUNCTION bank_wire_transfer(
)
LANGUAGE plpgsql AS $$
DECLARE
+amount_with_fee taler_amount;
+admin_account_id INT8;
+admin_has_debt BOOLEAN;
+admin_balance taler_amount;
+admin_payto_uri TEXT;
+admin_name TEXT;
debtor_has_debt BOOLEAN;
debtor_balance taler_amount;
debtor_max_debt taler_amount;
@@ -769,12 +766,7 @@ creditor_has_debt BOOLEAN;
creditor_balance taler_amount;
creditor_payto_uri TEXT;
creditor_name TEXT;
-potential_balance taler_amount;
-new_debtor_balance taler_amount;
-new_debtor_balance_ok BOOLEAN;
-new_creditor_balance taler_amount;
-will_debtor_have_debt BOOLEAN;
-will_creditor_have_debt BOOLEAN;
+tmp_balance taler_amount;
BEGIN
-- Retrieve debtor info
SELECT
@@ -791,7 +783,7 @@ SELECT
JOIN customers ON customer_id=owning_customer_id
WHERE bank_account_id=in_debtor_account_id;
IF NOT FOUND THEN
- RAISE EXCEPTION 'fuck debtor';
+ RAISE EXCEPTION 'Unknown debtor %', in_debtor_account_id;
END IF;
-- Retrieve creditor info
SELECT
@@ -806,7 +798,30 @@ SELECT
JOIN customers ON customer_id=owning_customer_id
WHERE bank_account_id=in_creditor_account_id;
IF NOT FOUND THEN
- RAISE EXCEPTION 'fuck creditor %', in_creditor_account_id;
+ RAISE EXCEPTION 'Unknown creditor %', in_creditor_account_id;
+END IF;
+-- Retrieve admin info
+SELECT
+ bank_account_id, has_debt,
+ (balance).val, (balance).frac,
+ internal_payto_uri, customers.name
+ INTO
+ admin_account_id, admin_has_debt,
+ admin_balance.val, admin_balance.frac,
+ admin_payto_uri, admin_name
+ FROM bank_accounts
+ JOIN customers ON customer_id=owning_customer_id
+ WHERE login = 'admin';
+IF NOT FOUND THEN
+ RAISE EXCEPTION 'No admin';
+END IF;
+
+IF in_fee != (0, 0)::taler_amount AND admin_account_id != in_debtor_account_id THEN
+ SELECT sum.val, sum.frac
+ INTO amount_with_fee.val, amount_with_fee.frac
+ FROM amount_add(in_amount, in_fee) as sum;
+ELSE
+ amount_with_fee = in_amount;
END IF;
-- DEBTOR SIDE
@@ -814,48 +829,44 @@ END IF;
IF debtor_has_debt THEN
-- debt case: simply checking against the max debt allowed.
SELECT sum.val, sum.frac
- INTO potential_balance.val, potential_balance.frac
- FROM amount_add(debtor_balance, in_amount) as sum;
+ INTO debtor_balance.val, debtor_balance.frac
+ FROM amount_add(debtor_balance, amount_with_fee) as sum;
SELECT NOT ok
INTO out_balance_insufficient
FROM amount_left_minus_right(debtor_max_debt,
- potential_balance);
+ debtor_balance);
IF out_balance_insufficient THEN
RETURN;
END IF;
- new_debtor_balance=potential_balance;
- will_debtor_have_debt=TRUE;
ELSE -- not a debt account
SELECT
NOT ok,
(diff).val, (diff).frac
INTO
out_balance_insufficient,
- potential_balance.val,
- potential_balance.frac
+ tmp_balance.val,
+ tmp_balance.frac
FROM amount_left_minus_right(debtor_balance,
- in_amount);
+ amount_with_fee);
IF NOT out_balance_insufficient THEN -- debtor has enough funds in the (positive) balance.
- new_debtor_balance=potential_balance;
- will_debtor_have_debt=FALSE;
+ debtor_balance=tmp_balance;
ELSE -- debtor will switch to debt: determine their new negative balance.
SELECT
(diff).val, (diff).frac
INTO
- new_debtor_balance.val, new_debtor_balance.frac
- FROM amount_left_minus_right(in_amount,
+ debtor_balance.val, debtor_balance.frac
+ FROM amount_left_minus_right(amount_with_fee,
debtor_balance);
- will_debtor_have_debt=TRUE;
+ debtor_has_debt=TRUE;
SELECT NOT ok
INTO out_balance_insufficient
FROM amount_left_minus_right(debtor_max_debt,
- new_debtor_balance);
+ debtor_balance);
IF out_balance_insufficient THEN
RETURN;
END IF;
END IF;
END IF;
-out_balance_insufficient=FALSE;
-- CREDITOR SIDE.
-- Here we figure out whether the creditor would switch
@@ -863,29 +874,57 @@ out_balance_insufficient=FALSE;
-- accordingly.
IF NOT creditor_has_debt THEN -- easy case.
SELECT sum.val, sum.frac
- INTO new_creditor_balance.val, new_creditor_balance.frac
+ INTO creditor_balance.val, creditor_balance.frac
FROM amount_add(creditor_balance, in_amount) as sum;
- will_creditor_have_debt=FALSE;
ELSE -- creditor had debit but MIGHT switch to credit.
SELECT
(diff).val, (diff).frac,
NOT ok
INTO
- new_creditor_balance.val, new_creditor_balance.frac,
- will_creditor_have_debt
+ tmp_balance.val, tmp_balance.frac,
+ creditor_has_debt
FROM amount_left_minus_right(in_amount,
creditor_balance);
- IF will_creditor_have_debt THEN
+ IF NOT creditor_has_debt THEN
+ creditor_balance=tmp_balance;
+ ELSE
-- the amount is not enough to bring the receiver
-- to a credit state, switch operators to calculate the new balance.
SELECT
(diff).val, (diff).frac
- INTO new_creditor_balance.val, new_creditor_balance.frac
+ INTO creditor_balance.val, creditor_balance.frac
FROM amount_left_minus_right(creditor_balance,
in_amount);
END IF;
END IF;
+-- ADMIN SIDE.
+-- Here we figure out whether the administrator would switch
+-- from debit to a credit situation, and adjust the balance
+-- accordingly.
+IF amount_with_fee != in_amount THEN
+ IF NOT admin_has_debt THEN -- easy case.
+ SELECT sum.val, sum.frac
+ INTO admin_balance.val, admin_balance.frac
+ FROM amount_add(admin_balance, in_fee) as sum;
+ ELSE -- creditor had debit but MIGHT switch to credit.
+ SELECT (diff).val, (diff).frac, NOT ok
+ INTO
+ tmp_balance.val, tmp_balance.frac,
+ admin_has_debt
+ FROM amount_left_minus_right(in_fee, admin_balance);
+ IF NOT admin_has_debt THEN
+ admin_balance=tmp_balance;
+ ELSE
+ -- the amount is not enough to bring the receiver
+ -- to a credit state, switch operators to calculate the new balance.
+ SELECT (diff).val, (diff).frac
+ INTO admin_balance.val, admin_balance.frac
+ FROM amount_left_minus_right(admin_balance, in_fee);
+ END IF;
+ END IF;
+END IF;
+
-- now actually create the bank transaction.
-- debtor side:
INSERT INTO bank_account_transactions (
@@ -896,9 +935,6 @@ INSERT INTO bank_account_transactions (
,subject
,amount
,transaction_date
- ,account_servicer_reference
- ,payment_information_id
- ,end_to_end_id
,direction
,bank_account_id
)
@@ -910,9 +946,6 @@ VALUES (
in_subject,
in_amount,
in_transaction_date,
- in_account_servicer_reference,
- in_payment_information_id,
- in_end_to_end_id,
'debit',
in_debtor_account_id
) RETURNING bank_transaction_id INTO out_debit_row_id;
@@ -926,9 +959,6 @@ INSERT INTO bank_account_transactions (
,subject
,amount
,transaction_date
- ,account_servicer_reference
- ,payment_information_id
- ,end_to_end_id
,direction
,bank_account_id
)
@@ -940,9 +970,6 @@ VALUES (
in_subject,
in_amount,
in_transaction_date,
- in_account_servicer_reference,
- in_payment_information_id,
- in_end_to_end_id, -- does this interest the receiving party?
'credit',
in_creditor_account_id
) RETURNING bank_transaction_id INTO out_credit_row_id;
@@ -950,16 +977,58 @@ VALUES (
-- checks and balances set up, now update bank accounts.
UPDATE bank_accounts
SET
- balance=new_debtor_balance,
- has_debt=will_debtor_have_debt
+ balance=debtor_balance,
+ has_debt=debtor_has_debt
WHERE bank_account_id=in_debtor_account_id;
UPDATE bank_accounts
SET
- balance=new_creditor_balance,
- has_debt=will_creditor_have_debt
+ balance=creditor_balance,
+ has_debt=creditor_has_debt
WHERE bank_account_id=in_creditor_account_id;
+-- Fee part
+IF amount_with_fee != in_amount THEN
+ INSERT INTO bank_account_transactions (
+ creditor_payto_uri
+ ,creditor_name
+ ,debtor_payto_uri
+ ,debtor_name
+ ,subject
+ ,amount
+ ,transaction_date
+ ,direction
+ ,bank_account_id
+ )
+ VALUES (
+ admin_payto_uri,
+ admin_name,
+ debtor_payto_uri,
+ debtor_name,
+ 'transaction fee of ' || out_debit_row_id,
+ in_fee,
+ in_transaction_date,
+ 'debit',
+ in_debtor_account_id
+ ), (
+ admin_payto_uri,
+ admin_name,
+ debtor_payto_uri,
+ debtor_name,
+ 'transaction fee of ' || out_debit_row_id,
+ in_amount,
+ in_transaction_date,
+ 'credit',
+ admin_account_id
+ );
+
+ UPDATE bank_accounts
+ SET
+ balance=admin_balance,
+ has_debt=admin_has_debt
+ WHERE bank_account_id=admin_account_id;
+END IF;
+
-- notify new transaction
PERFORM pg_notify('bank_tx', in_debtor_account_id || ' ' || in_creditor_account_id || ' ' || out_debit_row_id || ' ' || out_credit_row_id);
END $$;
@@ -1025,9 +1094,7 @@ SELECT
in_subject,
converted_amount,
in_now_date,
- NULL,
- NULL,
- NULL
+ (0, 0)::taler_amount
) as transfer;
IF out_balance_insufficient THEN
RETURN;
@@ -1130,9 +1197,7 @@ FROM bank_wire_transfer(
in_subject,
in_amount_debit,
in_now_date,
- NULL,
- NULL,
- NULL
+ (0, 0)::taler_amount
) as transfer;
IF out_balance_insufficient THEN
RETURN;