Скрипт для решения этой задачи. На основе ru.bitel.bgbilling.kernel.contract.limit.server.bean.LimitManager (fernflower). Работает 4 месяца. Может, кому пригодится.
Код:
package ru.XXX.bgbilling.kernel.contract.dyn;
import java.sql.Connection;
import bitel.billing.server.contract.bean.Contract;
import bitel.billing.server.contract.bean.ContractManager;
import ru.bitel.bgbilling.kernel.contract.balance.server.event.PaymentEvent;
import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.sql.ConnectionSet;
import ru.XXX.bgbilling.lib.CustomLimitManager;
/**
* По событию прихода платежа на супердоговор
* восстанавливает временные понижения лимитов
* на всех зависимых дебетовых субдоговорах.
* @param connnection
* @param event - событие о приходе платежа для супердоговора
* @throws BGException
*
*/
public class RestoreSubcontractsLimits
extends EventScriptBase<PaymentEvent>
{
@Override
public void onEvent( PaymentEvent event, Setup setup, ConnectionSet set )
throws Exception
{
// if (event.getContractId() != 17738) // 888888 for test
// return;
Connection con = set.getConnection();
try (ContractManager cm = new ContractManager(con)) {
Contract contract = cm.getContractById(event.getContractId());
if (contract.isSuper() && contract.getBalanceMode() == Contract.DEBET_BALANCE_MODE) {
CustomLimitManager clm = new CustomLimitManager(con, event);
clm.clientPaymentAllSubcontracts();
}
}
}
}
Код:
package ru.XXX.bgbilling.lib;
import java.math.BigDecimal;
import java.sql.*;
import ru.bitel.common.TimeUtils;
import bitel.billing.server.contract.bean.*;
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.kernel.contract.balance.common.bean.Payment;
import ru.bitel.bgbilling.kernel.contract.balance.server.bean.PaymentDao;
import ru.bitel.bgbilling.kernel.contract.balance.server.event.PaymentEvent;
import ru.bitel.bgbilling.kernel.contract.limit.common.bean.ContractLimitLog;
import ru.bitel.bgbilling.kernel.contract.limit.server.bean.ContractLimitLogManager;
import ru.bitel.bgbilling.kernel.contract.limit.server.bean.LimitManager;
import ru.bitel.bgbilling.kernel.module.common.bean.User;
import org.apache.log4j.Logger;
public final class CustomLimitManager
{
public static final int SUB_MODE_DEPEND_BALANCE = 0;
public CustomLimitManager(Connection connection, PaymentEvent event){
this.connection = connection;
this.event = event;
}
private final Connection connection;
private final PaymentEvent event;
private Contract subcontract;
private Contract supercontract;
private int currentLimitStatus;
private int loweringLimitId;
private String existingPayments;
private BigDecimal sum;
private BigDecimal unpaidLimitSumm;
private final static Logger logger = Logger.getLogger( CustomLimitManager.class);
public void clientPaymentAllSubcontracts() throws BGException
{
synchronized (LimitManager.limitMutex) {
BigDecimal rest = event.getPayment().getSum();
try( ContractManager cm = new ContractManager( connection);
PaymentDao paymentDao = new PaymentDao( connection);
)
{
supercontract = cm.getContractById(event.getContractId());
pays:
for (Contract subcon : cm.getSubContracts(event.getContractId(), SUB_MODE_DEPEND_BALANCE)) {
this.subcontract = subcon;
if( subcontract == null)
continue;
if (subcontract.getBalanceMode() != Contract.DEBET_BALANCE_MODE) {
logger.warn(String.format("Subcontract %s is not in debet balance mode. Skip.", subcontract.getTitle()));
continue;
}
try(ResultSet unpayedLimitRs = getUnpayedLimitRs()){
for (boolean isPayIdSaved = false; unpayedLimitRs.next(); rest = sum.subtract(unpaidLimitSumm)) {
currentLimitStatus = unpayedLimitRs.getInt("status");
loweringLimitId = unpayedLimitRs.getInt("id");
existingPayments = unpayedLimitRs.getString("pids");
unpaidLimitSumm = unpayedLimitRs.getBigDecimal("summ");
sum = rest.add(unpayedLimitRs.getBigDecimal("rest"));
sum = sum.add( getPreviousPaymentsSum(paymentDao));
if (!isPayIdSaved) {
savePaymentId();
isPayIdSaved = true;
} else {
saveMoneyRest( rest);
}
if (notEnoughMoney()) {
if (noMoneyAtAll())
setContractLimitStatus( LimitManager.VPAY_NOT_PAYOFFED);
else
setContractLimitStatus( LimitManager.VPAY_PARTIAL_PAYOFFED);
break pays;
}
else {
setContractLimitStatus(LimitManager.VPAY_PAYOFFED);
restoreSubcontractLimit(unpayedLimitRs.getInt("clp_id"), unpaidLimitSumm.negate());
}
}
}
catch (SQLException e) {
throw new BGException(e);
}
}
}
}
}
private void setContractLimitStatus( int newStatus)
throws SQLException
{
if (currentLimitStatus != newStatus) {
if( newStatus == LimitManager.VPAY_PAYOFFED){
String updQuery = "UPDATE contract_limit_manage SET status=?, date2=? WHERE id=?";
try (PreparedStatement ps = connection.prepareStatement(updQuery)) {
ps.setInt(1, newStatus);
ps.setDate(2, TimeUtils.convertDateToSqlDate(event.getPayment().getDate()));
ps.setInt(3, loweringLimitId);
ps.executeUpdate();
logger.info(String.format("subcontract: %s. Limit: %s (Id: %d) payoffed",
subcontract.getTitle(), unpaidLimitSumm.negate().toPlainString(), loweringLimitId));
}
}
else{
String updQuery = "UPDATE contract_limit_manage SET status=? WHERE id=?";
try (PreparedStatement ps = connection.prepareStatement( updQuery)) {
ps.setInt(1, newStatus);
ps.setInt(2, loweringLimitId);
ps.executeUpdate();
logger.info(String.format("subcontract: %s. Limit: %s (Id: %d) NOT payoffed",
subcontract.getTitle(), unpaidLimitSumm.negate().toPlainString(), loweringLimitId));
}
}
}
}
private void restoreSubcontractLimit(int restoreLimitTaskId, BigDecimal unpaidLimitSum) {
// synchronized (LimitManager.limitMutex) {
try{
if (wasUnpayedLimit()) {
String paysIds = getPaysIds(restoreLimitTaskId);
deleteLimitRecoveryTask(restoreLimitTaskId);
recalcLimitSum(unpaidLimitSum);
subcontractLimitRecoveryLogging(paysIds, unpaidLimitSum);
}
} catch (Exception e) {
e.printStackTrace();
}
// }
}
private boolean notEnoughMoney(){
return sum.compareTo(unpaidLimitSumm) < 0;
}
private boolean noMoneyAtAll(){
return sum.compareTo(BigDecimal.ZERO) <= 0;
}
private void saveMoneyRest( BigDecimal rest)
throws SQLException
{
try (PreparedStatement ps = connection.prepareStatement("UPDATE contract_limit_manage SET rest=? WHERE id=?")) {
ps.setBigDecimal(1, rest);
ps.setInt(2, loweringLimitId);
ps.executeUpdate();
}
}
private void savePaymentId()
throws SQLException
{
try (PreparedStatement ps = connection.prepareStatement("UPDATE contract_limit_manage SET pids=? WHERE id=?")) {
ps.setString(1, existingPayments == null ? "" + event.getPayment().getId()
: existingPayments + "," + event.getPayment().getId());
ps.setInt(2, loweringLimitId);
ps.executeUpdate();
}
}
private BigDecimal getPreviousPaymentsSum( PaymentDao pmDao)
throws BGException
{
BigDecimal sum = BigDecimal.ZERO;
for (Payment payment : pmDao.getPaymentsById(existingPayments)) {
if (payment != null) {
sum = sum.add(payment.getSum());
}
}
return sum;
}
private ResultSet getUnpayedLimitRs()
throws SQLException
{
PreparedStatement ps1 = connection.prepareStatement("SELECT * FROM contract_limit_manage WHERE cid=? AND status<?");
ps1.setInt(1, subcontract.getId());
ps1.setInt(2, LimitManager.VPAY_PAYOFFED);
return ps1.executeQuery();
}
private String getPaysIds(int taskId)
throws SQLException {
try( PreparedStatement psSelPids = connection.prepareStatement(
"SELECT pids FROM contract_limit_manage WHERE clp_id = ?");
)
{
psSelPids.setInt(1, taskId);
ResultSet rs1 = psSelPids.executeQuery();
if( rs1.next())
return rs1.getString("pids");
else
return "?";
}
}
private void deleteLimitRecoveryTask( int taskId)
throws SQLException
{
try(PreparedStatement psDeletePeriodLimit = connection.prepareStatement(
"DELETE FROM contract_limit_period WHERE id = ?");
PreparedStatement psUpdateLimitManage = connection.prepareStatement(
"UPDATE contract_limit_manage SET clp_id = NULL WHERE clp_id = ?");
)
{
psDeletePeriodLimit.setInt(1, taskId); // удаляем задание возвращения лимита
psDeletePeriodLimit.executeUpdate();
psUpdateLimitManage.setInt(1, taskId); // удаляем ссылку на задание возвращения лимита
psUpdateLimitManage.executeUpdate();
}
}
private void recalcLimitSum( BigDecimal unpaidLimitSumm)
throws SQLException{
try(PreparedStatement psUpdateLimit = connection.prepareStatement(
"UPDATE contract SET closesumma = closesumma - ? WHERE id = ?");
)
{
psUpdateLimit.setBigDecimal(1, unpaidLimitSumm); // уменьшаем лимит на сумму обещ. платеа
psUpdateLimit.setInt(2, subcontract.getId());
psUpdateLimit.executeUpdate();
}
}
private boolean wasUnpayedLimit(){
return unpaidLimitSumm.compareTo( BigDecimal.ZERO) != 0;
}
private void subcontractLimitRecoveryLogging(String pays, BigDecimal limitValue)
throws BGException{
try(ContractLimitLogManager contractLimitLogManager = new ContractLimitLogManager(connection);)
{
ContractLimitLog contractLimitLog = new ContractLimitLog();
contractLimitLog.setUserId(User.USER_SERVER);
contractLimitLog.setLimitValue(subcontract.getBalanceLimit());
contractLimitLog.setContractId(subcontract.getId());
contractLimitLog.setComment(String.format("Восст. лим. на %s (платеж: %s на договор: %s)",
limitValue.negate().toPlainString(), pays, supercontract.getTitle()));
contractLimitLogManager.addContractLimitLog(contractLimitLog);
}
}
}