
com.aoindustries.aoserv.master.BillingTransactionHandler Maven / Gradle / Ivy
/*
* aoserv-master - Master server for the AOServ Platform.
* Copyright (C) 2001-2013, 2015, 2017, 2018, 2019, 2020 AO Industries, Inc.
* [email protected]
* 7262 Bull Pen Cir
* Mobile, AL 36695
*
* This file is part of aoserv-master.
*
* aoserv-master is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aoserv-master is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with aoserv-master. If not, see .
*/
package com.aoindustries.aoserv.master;
import com.aoindustries.aoserv.client.account.Account;
import com.aoindustries.aoserv.client.billing.Currency;
import com.aoindustries.aoserv.client.billing.Transaction;
import com.aoindustries.aoserv.client.billing.TransactionSearchCriteria;
import com.aoindustries.aoserv.client.master.User;
import com.aoindustries.aoserv.client.master.UserHost;
import com.aoindustries.aoserv.client.schema.AoservProtocol;
import com.aoindustries.aoserv.client.schema.Table;
import com.aoindustries.dbc.DatabaseConnection;
import com.aoindustries.io.stream.StreamableOutput;
import com.aoindustries.lang.Strings;
import com.aoindustries.util.i18n.Money;
import com.aoindustries.util.i18n.Monies;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The TransactionHandler
handles all the accesses to the transaction tables.
*
* @author AO Industries, Inc.
*/
final public class BillingTransactionHandler {
private BillingTransactionHandler() {
}
public static boolean canAccessTransaction(DatabaseConnection conn, RequestSource source, int transaction) throws IOException, SQLException {
return AccountHandler.canAccessAccount(conn, source, getAccountForTransaction(conn, transaction));
}
public static void checkAccessTransaction(DatabaseConnection conn, RequestSource source, String action, int transaction) throws IOException, SQLException {
AccountHandler.checkAccessAccount(conn, source, action, getAccountForTransaction(conn, transaction));
}
/**
* Adds a transaction.
*/
public static int addTransaction(
DatabaseConnection conn,
RequestSource source,
InvalidateList invalidateList,
char timeType,
Timestamp time,
Account.Name account,
Account.Name sourceAccount,
com.aoindustries.aoserv.client.account.User.Name administrator,
String type,
String description,
int quantity,
Money rate,
String paymentType,
String paymentInfo,
String processor,
byte payment_confirmed
) throws IOException, SQLException {
BankAccountHandler.checkIsAccounting(conn, source, "addTransaction");
AccountHandler.checkAccessAccount(conn, source, "addTransaction", account);
AccountHandler.checkAccessAccount(conn, source, "addTransaction", sourceAccount);
AccountUserHandler.checkAccessUser(conn, source, "addTransaction", administrator);
if(administrator.equals(com.aoindustries.aoserv.client.linux.User.MAIL)) throw new SQLException("Not allowed to add Transaction for user '"+com.aoindustries.aoserv.client.linux.User.MAIL+'\'');
return addTransaction(
conn,
invalidateList,
timeType,
time,
account,
sourceAccount,
administrator,
type,
description,
BigDecimal.valueOf(quantity, 3),
rate,
paymentType,
paymentInfo,
processor,
payment_confirmed
);
}
/**
* Adds a transaction.
*/
public static int addTransaction(
DatabaseConnection conn,
InvalidateList invalidateList,
char timeType,
Timestamp time,
Account.Name account,
Account.Name sourceAccount,
com.aoindustries.aoserv.client.account.User.Name administrator,
String type,
String description,
BigDecimal quantity,
Money rate,
String paymentType,
String paymentInfo,
String processor,
byte payment_confirmed
) throws IOException, SQLException {
if(administrator.equals(com.aoindustries.aoserv.client.linux.User.MAIL)) throw new SQLException("Not allowed to add Transaction for user '"+com.aoindustries.aoserv.client.linux.User.MAIL+'\'');
int transaction;
if(time == null) {
String function;
if(timeType == 'D') {
function = "CURRENT_DATE";
} else if(timeType == 'T') {
function = "NOW()";
} else {
throw new IllegalArgumentException("Unexpected value for timeType: " + timeType);
}
transaction = conn.executeIntUpdate(
"INSERT INTO billing.\"Transaction\" VALUES (" + function + ",default,?,?,?,?,?,?,?,?,?,?,?,null,?) RETURNING transid",
account,
sourceAccount,
administrator,
type,
description,
quantity,
rate.getCurrency().getCurrencyCode(),
rate.getValue(),
paymentType,
paymentInfo,
processor,
payment_confirmed==Transaction.CONFIRMED?"Y":payment_confirmed==Transaction.NOT_CONFIRMED?"N":"W"
);
} else {
String cast;
if(timeType == 'D') {
cast = "::date";
} else if(timeType == 'T') {
cast = "";
} else {
throw new IllegalArgumentException("Unexpected value for timeType: " + timeType);
}
transaction = conn.executeIntUpdate(
"INSERT INTO billing.\"Transaction\" VALUES (?" + cast + ",default,?,?,?,?,?,?,?,?,?,?,?,null,?) RETURNING transid",
time,
account,
sourceAccount,
administrator,
type,
description,
quantity,
rate.getCurrency().getCurrencyCode(),
rate.getValue(),
paymentType,
paymentInfo,
processor,
payment_confirmed==Transaction.CONFIRMED?"Y":payment_confirmed==Transaction.NOT_CONFIRMED?"N":"W"
);
}
// Notify all clients of the updates
invalidateList.addTable(conn, Table.TableID.TRANSACTIONS, account, AccountHandler.getHostsForAccount(conn, account), false);
return transaction;
}
/**
* Gets the balance for one account.
*/
public static void getAccountBalance(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
Account.Name account
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
// TODO: release conn before writing to out
MasterServer.writePenniesCheckBusiness(
conn,
source,
"getAccountBalance",
account,
out,
"SELECT coalesce(sum(cast((quantity * \"rate.value\") as numeric(9,2))), 0)\n"
+ "FROM billing.\"Transaction\"\n"
+ "WHERE accounting=? AND \"rate.currency\"=? AND payment_confirmed!='N'",
account.toString(),
Currency.USD.getCurrencyCode()
);
} else {
throw new IOException("getAccountBalance only supported for protocol < " + AoservProtocol.Version.VERSION_1_83_0);
}
}
/**
* Gets the balance for one account.
*/
public static void getAccountBalanceBefore(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
Account.Name account,
long before
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
// TODO: release conn before writing to out
MasterServer.writePenniesCheckBusiness(
conn,
source,
"getAccountBalanceBefore",
account,
out,
"SELECT coalesce(sum(cast((quantity * \"rate.value\") as numeric(9,2))), 0)\n"
+ "FROM billing.\"Transaction\"\n"
+ "WHERE accounting=? AND \"rate.currency\"=? and \"time\" AND payment_confirmed!='N'",
account.toString(),
Currency.USD.getCurrencyCode(),
new Timestamp(before)
);
} else {
throw new IOException("getAccountBalanceBefore only supported for protocol < " + AoservProtocol.Version.VERSION_1_83_0);
}
}
/**
* Gets the confirmed balance for one account.
*/
public static void getConfirmedAccountBalance(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
Account.Name account
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
// TODO: release conn before writing to out
MasterServer.writePenniesCheckBusiness(
conn,
source,
"getConfirmedAccountBalance",
account,
out,
"SELECT coalesce(sum(cast((quantity * \"rate.value\") as numeric(9,2))), 0)\n"
+ "FROM billing.\"Transaction\"\n"
+ "WHERE accounting=? AND \"rate.currency\"=? AND payment_confirmed='Y'",
account.toString(),
Currency.USD.getCurrencyCode()
);
} else {
throw new IOException("getConfirmedAccountBalance only supported for protocol < " + AoservProtocol.Version.VERSION_1_83_0);
}
}
/**
* Gets the confirmed balance for one account.
*/
public static Monies getConfirmedAccountBalance(
DatabaseConnection conn,
Account.Name account
) throws IOException, SQLException {
return Monies.of(
conn.executeObjectCollectionQuery(
new ArrayList<>(),
ObjectFactories.moneyFactory,
"SELECT\n"
+ " t.\"rate.currency\"\n"
+ " sum(\n"
+ " round(\n"
+ " t.quantity * t.\"rate.value\",\n"
+ " c.\"fractionDigits\"\n"
+ " )\n"
+ " )\n"
+ "FROM\n"
+ " billing.\"Transaction\" t\n"
+ " INNER JOIN billing.\"Currency\" c ON t.\"rate.currency\" = c.\"currencyCode\"\n"
+ "WHERE\n"
+ " t.accounting=?\n"
+ " AND t.payment_confirmed='Y'\n"
+ "GROUP BY t.\"rate.currency\"",
account.toString()
)
);
}
/**
* Gets the confirmed balance for one account.
*/
public static void getConfirmedAccountBalanceBefore(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
Account.Name account,
long before
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
// TODO: release conn before writing to out
MasterServer.writePenniesCheckBusiness(
conn,
source,
"getConfirmedAccountBalanceBefore",
account,
out,
"SELECT coalesce(sum(cast((quantity * \"rate.value\") as numeric(9,2))), 0)\n"
+ "FROM billing.\"Transaction\"\n"
+ "WHERE accounting=? AND \"rate.currency\"=? and \"time\" AND payment_confirmed='Y'",
account.toString(),
Currency.USD.getCurrencyCode(),
new Timestamp(before)
);
} else {
throw new IOException("getConfirmedAccountBalanceBefore only supported for protocol < " + AoservProtocol.Version.VERSION_1_83_0);
}
}
/**
* Gets all billing.Transaction for one business.
*/
public static void getTransactionsForAccount(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
boolean provideProgress,
Account.Name account
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
com.aoindustries.aoserv.client.account.User.Name currentAdministrator = source.getCurrentAdministrator();
User masterUser=MasterServer.getUser(conn, currentAdministrator);
UserHost[] masterServers=masterUser==null?null:MasterServer.getUserHosts(conn, currentAdministrator);
if(masterUser!=null) {
if(masterServers.length==0) {
// TODO: release conn before writing to out
MasterServer.writeObjects(
conn,
source,
out,
provideProgress,
CursorMode.AUTO,
new Transaction(),
"SELECT * FROM billing.\"Transaction\" WHERE accounting=? AND \"rate.currency\"=?",
account,
Currency.USD.getCurrencyCode()
);
}else {
conn.releaseConnection();
MasterServer.writeObjects(source, out, provideProgress, Collections.emptyList());
}
} else {
// TODO: release conn before writing to out
MasterServer.writeObjects(
conn,
source,
out,
provideProgress,
CursorMode.AUTO,
new Transaction(),
"SELECT\n"
+ " tr.*\n"
+ "FROM\n"
+ " account.\"User\" un1,\n"
+ " billing.\"Package\" pk1,\n"
+ TableHandler.BU1_PARENTS_JOIN
+ " billing.\"Transaction\" tr\n"
+ "WHERE\n"
+ " un1.username=?\n"
+ " AND un1.package=pk1.name\n"
+ " AND (\n"
+ TableHandler.PK1_BU1_PARENTS_WHERE
+ " )\n"
+ " AND bu1.accounting=tr.accounting\n"
+ " AND tr.accounting=?\n"
+ " AND tr.\"rate.currency\"=?",
currentAdministrator,
account,
Currency.USD.getCurrencyCode()
);
}
} else {
throw new IOException("getTransactionsForAccount only supported for protocol < " + AoservProtocol.Version.VERSION_1_83_0);
}
}
/**
* Gets all billing.Transaction for one business administrator.
*/
public static void getTransactionsForAdministrator(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
boolean provideProgress,
com.aoindustries.aoserv.client.account.User.Name administrator
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
AccountUserHandler.checkAccessUser(conn, source, "getTransactionsForAdministrator", source.getCurrentAdministrator());
// TODO: release conn before writing to out
MasterServer.writeObjects(
conn,
source,
out,
provideProgress,
CursorMode.FETCH,
new Transaction(),
"SELECT * FROM billing.\"Transaction\" WHERE username=? AND \"rate.currency\"=?",
administrator,
Currency.USD.getCurrencyCode()
);
} else {
throw new IOException("getTransactionsForAdministrator only supported for protocol < " + AoservProtocol.Version.VERSION_1_83_0);
}
}
public static void getTransactionsSearch(
DatabaseConnection conn,
RequestSource source,
StreamableOutput out,
boolean provideProgress,
TransactionSearchCriteria criteria
) throws IOException, SQLException {
if(source.getProtocolVersion().compareTo(AoservProtocol.Version.VERSION_1_83_0) < 0) {
com.aoindustries.aoserv.client.account.User.Name currentAdministrator = source.getCurrentAdministrator();
User masterUser=MasterServer.getUser(conn, currentAdministrator);
UserHost[] masterServers=masterUser==null?null:MasterServer.getUserHosts(conn, currentAdministrator);
StringBuilder sql;
final List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy