WebAction CustomSuspend

Материал из BiTel WiKi

Перейти к: навигация, поиск

Ниже приведён код вебэкшена, представляющего собой модификацию стандартной логики приостановления - экшена WebAction_ContractStatus

Реализация очень специфична и для конкретного провайдера скорее всего потребует изменений.


Содержание

Логика

Приостановление доступно:

  • Физ.лицам
  • Не более x дней в течение y дней
  • Приостановить договор можно только с завтрашнего дня
  • Активировать можно либо с сегодняшнего, либо с завтрашнего дня
  • Возможно взимание расхода за каждое приостановление. Если приостановление отменяется полностью, расход удаляется.
  • Баланс должен быть >0 с учетом расхода за приостановление.

Скрины

Файл:Activate.jpg Файл:Suspend.jpg

Требования

Настройки

В настройках сервера (Сервис -> настройка) добавляем строки:

#Параметры для WebAction_CustomSuspend
#Максимальное количество дней приостановления в течение custom.suspend.suspened.check.period
custom.suspend.max.suspened.in.period=60
#Период, в течение которого клиент не может быть приостановлен более, чем custom.suspend.max.suspened.in.period дней
custom.suspend.suspened.check.period=90
#Тип расхода для приостановления через Web
custom.suspend.charge.type=14
#Стоимость приостановления
custom.suspend.charge.summa=20

Код java

5.1

package bitel.billing.server.contract.action.web;
 
import bitel.billing.common.BGException;
import bitel.billing.server.contract.action.base.ActionBase;
import bitel.billing.common.TimeUtils;
import bitel.billing.server.contract.bean.BalanceUtils;
import bitel.billing.server.contract.bean.Charge;
import bitel.billing.server.contract.bean.ChargeManager;
import bitel.billing.server.contract.bean.Contract;
import bitel.billing.server.contract.bean.ContractManager;
import bitel.billing.server.contract.bean.ContractStatus;
import bitel.billing.server.contract.bean.ContractStatusManager;
import bitel.billing.server.script.bean.event.ChargeEvent;
import bitel.billing.server.rscm.bean.ContractServiceManager;
import bitel.billing.server.rscm.bean.ContractService;
import bitel.billing.server.rscm.bean.event.RSCMContractServiceUpdateEvent;
import bitel.billing.server.script.bean.event.EventProcessor;
//import bitel.billing.server.util.Utils;
import ru.bitel.bgbilling.server.util.ServerUtils;
//import bitel.billing.server.script.bean.event.EventProcessor;
//import bitel.billing.server.script.bean.event.GetContractStatusChangeDatesEvent;
 
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
//import java.util.List;
import org.w3c.dom.Element;
 
//import ru.bitel.bgbilling.common.BGIllegalArgumentException;
 
/**
 * web params:
 * 
 * action=CustomSuspend
 * command=
 * 		Suspend ({to_date|(to_day,to_month,to_year)})
 * 		Activate ([from=tomorrow])
 *
 */
public class ActionCustomSuspend extends ActionBase {
 
 
	private static final int CANCHANGE_DISABLED = 1;
	private static final int CANCHANGE_DISABLED_BADSTATUS = 2;
	private static final int CANCHANGE_DO = 3;
	private static final int CANCHANGE_CANCEL_ALLOW = 4;
//	private static final int CANCHANGE_CANCEL_DENY = 5;
	private static final int CANCHANGE_CANCEL_ALLOW_ONLY_TODAY = 6;
	private static final int CANCHANGE_DISABLED_LOW_ACCOUNT = 7;
 
	private int maxDays;	//Максимальное количество дней приостановления в течение checkDays
							//Параметр глобального конфига:
							//custom.suspend.max.suspened.in.period
	private int checkDays;	//Период, в течение которого клиент не может быть приостановлен более, чем maxDays дней
							//Параметр глобального конфига:
							//custom.suspend.suspened.check.period
	private int chargeType; //Берем расход за приостановление
							//Параметр глобального конфига:
							//custom.suspend.charge.type
	private float chargeSumm;//Сумма расхода за приостановление
	private int chargeAsRSCMsid = 0;//Снимаем деньги в виде RSCM услуги вместо расхода
 
	@Override
	public void doAction() throws SQLException, BGException 
	{
		int cid= this.cid;
 
	    if (cid <= 0)
	    {
	      //setParamsError();
	      setWebParamsError();
	      return;
	    }
 
//		this.maxDays = this.setup.getIntValue("custom.suspend.max.suspened.in.period", 60);
//		this.checkDays = this.setup.getIntValue("custom.suspend.suspened.check.period", 90);
//		this.chargeType = this.setup.getIntValue("custom.suspend.charge.type", -1);
//		this.chargeSumm = this.setup.getFloatValue("custom.suspend.charge.summa", 0);
//		this.chargeAsRSCMsid = this.setup.getIntValue("custom.suspend.charge.as.rscm.sid", 0);
		this.maxDays = this.setup.getInt("custom.suspend.max.suspened.in.period", 60);
		this.checkDays = this.setup.getInt("custom.suspend.suspened.check.period", 90);
		this.chargeType = this.setup.getInt("custom.suspend.charge.type", -1);
		this.chargeSumm = this.setup.getFloat("custom.suspend.charge.summa", 0);
		this.chargeAsRSCMsid = this.setup.getInt("custom.suspend.charge.as.rscm.sid", 0);
 
		//Выполняем действия
 
	    if ("Suspend".equals(getParameter("command")))
	    {
	    	ActionCustomSuspendSuspend(cid);
	    	if(!rootNode.getAttribute("status").equals("error")){
	    		try {
	    			this.response.sendRedirect("webexecuter?action=CustomSuspend");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
	    }
 
		if ("Activate".equals(getParameter("command")))
	    {
			ActionCustomSuspendActivate(cid);
			if(!rootNode.getAttribute("status").equals("error")){
				try {
					this.response.sendRedirect("webexecuter?action=CustomSuspend");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
	    }
 
		//Строим список статусов
 
		ContractStatusManager statusManager = new ContractStatusManager(this.con);
		Element table = createElement(this.rootNode, "statuses");
 
		//Проверяем наличие в будущем статусов, отличных от 0 и 4
	    boolean isManualFutureStatuses = false;
	    Integer canchange = null;
	    for (ContractStatus status : statusManager.getStatusList(cid))
	    {
	      Element row = createElement(table, "status");
	      //row.setAttribute("period", TimeUtils.formatPeriod(status.getDate1(), status.getDate2()));
	      row.setAttribute("date1",  TimeUtils.format(status.getDateFrom(), "dd.MM.yyyy"));
	      row.setAttribute("date2",  TimeUtils.format(status.getDateTo(), "dd.MM.yyyy"));
	      row.setAttribute("status", ContractStatus.statusToString(status.getStatus()));
	      row.setAttribute("statusint", String.valueOf(status.getStatus()));
	      //row.setAttribute("comment", status.getComment());
 
	      if(status.getDateTo()==null){
	    	  row.setAttribute("future", "2");//Текущий период
	      }else{
	    	  if (TimeUtils.dateBeforeOrEq(new Date(), status.getDateTo())) {
	    		  row.setAttribute("future", "2");//Текущий период
	    	  }
	      }
	      if(status.getDateFrom()==null){continue;}
	      if (!TimeUtils.dateBefore(new Date(), status.getDateFrom())) {
	        continue;
	      }
	      row.setAttribute("future", "1");
 
	      if ((status.getStatus() != 0) && (status.getStatus() != 4))
	      {
	    	  isManualFutureStatuses = true;
	      }
 
	      if(status.getStatus() == 4)
	      {
	    	  canchange = CANCHANGE_CANCEL_ALLOW; //Есть что отменять
	      }
	    }
 
 
	    //Пишем текущий статус
	    ContractManager contractManager = new ContractManager(this.con);
	    Contract contract = contractManager.getContractByID(cid);
	    int statusint = contract.getStatus();
	    if((isManualFutureStatuses==false)&&(statusint==4))//Если в будущем нет статусов кроме 0 и 4, но текущий статус - приостановлен, то ...
	    {
	    	canchange = CANCHANGE_CANCEL_ALLOW; //... можно его отменить
 
	    	//При этом, если завтрашний статус != "приостановлен", то отменять можно только сегодня
	    	Calendar tomorrow = Calendar.getInstance();
	    	tomorrow.add(Calendar.DATE, 1);
	    	if(statusManager.getStatus(cid, TimeUtils.convertCalendarToDate(tomorrow)).getStatus()!=4){
	    		canchange = CANCHANGE_CANCEL_ALLOW_ONLY_TODAY;
	    	}
	    }
 
	    this.rootNode.setAttribute("statusstr", ContractStatus.statusToString(statusint));
 
	    this.rootNode.setAttribute("statusint", String.valueOf(statusint));
 
	    //Запишем в xml сумму расхода за приостановление, если есть
	    if(this.chargeSumm>0){
	    	this.rootNode.setAttribute("suspendChargeSumm", String.valueOf(this.chargeSumm));
	    }	    
 
		if ((statusint != 0) && (statusint != 4))
	    {
	      canchange = Integer.valueOf(CANCHANGE_DISABLED_BADSTATUS);
	    }
 
		if(contract.getFc()==1) //Для юрлиц - нельзя
		{
			canchange = CANCHANGE_DISABLED;
		}
 
		//Дата, с которой можно менять статус (date1 для активации, деактивация всегда с завтрашнего числа)
	    Element date1 = createElement(this.rootNode, "mindate");
	    Calendar now = Calendar.getInstance();
	    if (statusint == 0)
	    {
	      now.add(5, 1);
	    }
	    date1.setAttribute("day", String.valueOf(now.get(5)));
	    date1.setAttribute("month", String.valueOf(now.get(2) + 1));
	    date1.setAttribute("year", String.valueOf(now.get(1)));
 
	    if (statusint == 0){
		    //<--рекомендуемая максимальная дата для приостановления (date2)
		    //Этот адовый кусок кода нужен только для того, чтобы показать пользователю максимальную дату,
	    	//до которой он может приостановить договор
	    	//..не спрашивайте, как это работает ;)
		    Element date2 = createElement(this.rootNode, "date");
 
		    //Сначала устанавливаем эту дату для рассчетного периода от (now-checkDays) до собстна upperbound
		    Calendar upperbound = Calendar.getInstance();
		    upperbound.add(Calendar.DATE, this.maxDays-this.SuspendedDays(cid) );
 
		    //lowerbound = upperbound - checkDays, определяем "нормальный" период проверки
		    Calendar lowerbound = (Calendar)upperbound.clone();
		    lowerbound.add(Calendar.DATE, - this.checkDays);
 
		    //lowestbound = now - checkDays
		    Calendar lowestbound = Calendar.getInstance();
		    lowestbound.add(Calendar.DATE, - this.checkDays);
 
		    //Теперь upperbound можно нарастить на количество дней приостановки между lowestbound и lowerbound
		    upperbound.add(Calendar.DATE, this.SuspendedDays(lowestbound, lowerbound, cid));
 
		    //Это и есть максимальная дата, до которой можно приостановить наш конкретный договор
		    date2.setAttribute("day", String.valueOf(upperbound.get(5)));
		    date2.setAttribute("month", String.valueOf(upperbound.get(2) + 1));
		    date2.setAttribute("year", String.valueOf(upperbound.get(1)));
		    //--/>
	    }
 
	    if (canchange == null)
	    {
	    	//Проверяем текущий баланс
			BalanceUtils bu =  new BalanceUtils(this.con);
			if(bu.getBalance(new Date(), cid).floatValue()-this.chargeSumm<0){
				canchange = CANCHANGE_DISABLED_LOW_ACCOUNT;
			}else{
				canchange = CANCHANGE_DO;//Всё ок
			}
	    }
 
 
 
	    this.rootNode.setAttribute("canchange", String.valueOf(canchange));
	  }
 
	private int SuspendedDays(Calendar date1, Calendar date2, int cid)
	throws SQLException
	{
	    PreparedStatement ps = this.con.prepareStatement("select sum(1+datediff(LEAST(date2,date(now())),GREATEST(?,date1))) from contract_status where cid=? and status=4 and date2>=? and date1<=?");
		ps.setDate(1, TimeUtils.convertCalendarToSqlDate(date1));
		ps.setInt(2, cid);
		ps.setDate(3, TimeUtils.convertCalendarToSqlDate(date1));
		ps.setDate(4, TimeUtils.convertCalendarToSqlDate(date2));
		ResultSet rs = ps.executeQuery();
		if(rs.next())
		{
			return rs.getInt(1);
		}else
		{
			return 0;
		}
	}
 
	//Количество приостановленных дней от текущего времени
	private int SuspendedDays(int cid)
		throws SQLException
	{
			Calendar date2 = Calendar.getInstance();
			Calendar date1 = (Calendar)date2.clone();
			date1.add(5, -this.checkDays);
			return SuspendedDays(date1, date2, cid);
	}
 
	//Приостанавливаем
	public void ActionCustomSuspendSuspend(int cid)
	    throws SQLException, BGException
	{
	    int newStatus = 4;
	    String comment = "Изменено пользователем";
 
	    Date date1 = null;
	    //Приостанавливаем только с завтрашнего числа
    	Calendar tomorrow = Calendar.getInstance();
    	tomorrow.add(5, 1);
    	date1 = tomorrow.getTime();
 
    	//По какое число приостанавливаем
    	Date date2 = getDateParameter("to_date");
	    if (date2 == null)
	    {
	      int day = getIntParameter("to_day", 0);
	      int month = getIntParameter("to_month", 0);
	      int year = getIntParameter("to_year", 0);
	      if ((day > 0) && (month > 0) && (year > 0))
	      {
	        Calendar dateCal = Calendar.getInstance();
	        dateCal.set(year, month - 1, day);
	        date2 = dateCal.getTime();
	      }
	    }
 
	    if (cid <= 0)
	    {
	    	//setParamsError();
	    	setWebParamsError();
	    	return;
	    }
 
	    //Проверяем текущий баланс
		BalanceUtils bu =  new BalanceUtils(this.con);
		if(bu.getBalance(new Date(), cid).floatValue()-this.chargeSumm<0){
			//setErrorStatus("Недостаточно средств для приостановления");
			setWebErrorMessage("Недостаточно средств для приостановления");
			return;
		}
 
	    if (date2 == null)
	    {
	    	//setErrorStatus("не задана дата");
	    	setWebErrorMessage("не задана дата");
	    	return;
	    }	    
 
	    if (!checkPeriod(date1, date2))
	    {
	    	return;
	    }
 
	    ContractManager contractManager = new ContractManager(this.con);
	    Contract contract = contractManager.getContractByID(cid);
 
	    if ((((contract.getStatus() != 0) || (newStatus != 4))) && ((
	      (contract.getStatus() != 4) || (newStatus != 0))))
	    {
	      //setErrorStatus("нельзя менять статус кроме 'активен' <-> 'приостановлен'");
	      setWebErrorMessage("нельзя менять статус кроме 'активен' <-> 'приостановлен'");
	      return;
	    }
 
	    /*
	    if ((newStatus == 4) && (TimeUtils.dateBeforeOrEq(date1, new Date())))
	    {
	      setErrorStatus("можно приостанавливать договор не раньше завтрашнего числа");
	      return;
	    }
 
	    if ((newStatus == 0) && (TimeUtils.dateBefore(date1, new Date())))
	    {
	    	setErrorStatus("нельзя активировать раньше, чем сегодня");
	    	return;
	    }*/
 
	    //Проверка на suspend abuse
	    Calendar tmp = TimeUtils.convertDateToCalendar(date2);
	    tmp.add(Calendar.DATE, -this.checkDays);
	    int expectedSuspendedDays = this.SuspendedDays(tmp, Calendar.getInstance(), cid)+TimeUtils.daysDelta(TimeUtils.convertDateToCalendar(date1), TimeUtils.convertDateToCalendar(date2))+1;
	    if(expectedSuspendedDays>this.maxDays){
	    	setWebErrorMessage("Договор не может быть приостановлен дольше "+this.maxDays +" дней в течение "+ this.checkDays+". Сократите период на "+(expectedSuspendedDays-this.maxDays) + " дн.");
	    	return;	    	
	    }
 
	    ContractStatus status = new ContractStatus();
	    status.setContractId(cid);
	    status.setStatus(newStatus);
	    //status.setDate1(TimeUtils.convertDateToCalendar(date1));
	    //status.setDate2(TimeUtils.convertDateToCalendar(date2));
	    status.setDateFrom(date1);
	    status.setDateTo(date2);
	    status.setComment(comment);
	    if ((isDateCheckingEnabled("ActionContractStatus")) && ((
	      (!checkDatesByClosedDate(null, date1)) || (!checkDatesByClosedDate(null, date2)))))
	    {
	    	setWebErrorMessage("Устанавливаемый статус пересекается с закрытым периодом!");
	    	return;
	    }
 
	    //Приостанавливаем
	    ContractStatusManager statusManager = new ContractStatusManager(this.con);
	    //statusManager.changeStatus(status.clone(), this.userID, true, true);
	    statusManager.changeStatus(status.clone(), Integer.valueOf(-1), true);
	    //Вносим расход, если нужно
	    if(this.chargeAsRSCMsid>0)
	    	//Снимаем расход как RSCM-услугу
	    {
	    	//определяем mid модуля rscm
	    	int rscmMid=0;
			PreparedStatement ps = con.prepareStatement("select mid from service where id=?");
			ps.setInt(1, this.chargeAsRSCMsid);
			ResultSet rs = ps.executeQuery();
			if(rs.next()){
				rscmMid = rs.getInt(1);
			}
			ContractServiceManager rscmManager = new ContractServiceManager(this.con,rscmMid);
			ContractService rscmService = new ContractService();
			rscmService.setServiceId(this.chargeAsRSCMsid);
			rscmService.setComment("Приостановление через Web");
			rscmService.setAmount(1);
			rscmService.setContractId(this.cid);
			rscmService.setDate(TimeUtils.convertDateToCalendar(date1));
			rscmManager.updateContractService(rscmService);
			//EventProcessor.getProcessor().addEvent(new RSCMContractServiceUpdateEvent(rscmMid, cid, rscmService));
			EventProcessor.getProcessor().addEvent(new RSCMContractServiceUpdateEvent(Integer.valueOf(-1), rscmMid, cid, rscmService));
			//Обновляем баланс в предыдущем месяце
			bu.updateBalance(date1, cid);
			//Обновляем баланс в личном кабинете - сбрасываем кэш contract_data, в котором хранятся данные о балансе
			this.request.getSession().setAttribute("contract_data", null);
	    }else{
	    	//Снимаем расход как расход
		    if(this.chargeType>=0)
		    {
		    	ChargeManager chargeManager = new ChargeManager(con);
		    	Charge charge = new Charge();
				charge.setChargeDate(date1);
				charge.setChargeTypeID(this.chargeType);
				charge.setComment("Приостановление через Web");
				charge.setContractID(cid);
				charge.setID(-1);
				charge.setSumma(new BigDecimal(this.chargeSumm));
				charge.setUserID(0);
				chargeManager.updateCharge(charge);
				EventProcessor.getProcessor().addEvent(new ChargeEvent(Integer.valueOf(-1), charge));
				//Обновляем баланс в предыдущем месяце
				bu.updateBalance(date1, cid);
				//Обновляем баланс в личном кабинете - сбрасываем кэш contract_data, в котором хранятся данные о балансе
				this.request.getSession().setAttribute("contract_data", null);
		    }
	    }
	}
 
	public void ActionCustomSuspendActivate(int cid)
	    throws SQLException, BGException
	{
		//Дата, с которой будем активироваться: сегодня или завтра
		Calendar dt = Calendar.getInstance();
 
		if("tomorrow".equals(getParameter("from")))
		{//Включаемся завтра
			dt.add(Calendar.DATE, 1);
		}
		Date date1 = TimeUtils.convertCalendarToDate(dt);
		Date date2 = null;
 
		//Есть ли вообще что отменять в будущем?
		boolean futureSuspendExists=false;
		ContractStatusManager statusManager = new ContractStatusManager(this.con);
		//Перебираем будущие статусы: если есть статусы, отличные от 4 и 0, то отменять приостановление нельзя
		for (ContractStatus status : statusManager.getStatusList(cid))
		{
		  if (!TimeUtils.dateBefore(new Date(), status.getDateFrom())) {
		    continue;
		  }
 
		  if ((status.getStatus() != 0) && (status.getStatus() != 4))
		  {
			  //setErrorStatus("запланировано изменение статуса на что-либо отличное от 'активен' или 'приостановлен'");
			  setWebErrorMessage("запланировано изменение статуса на что-либо отличное от 'активен' или 'приостановлен'");
			  return;
		  }
		  if (status.getStatus() == 4)
		  {
			  futureSuspendExists=true;
		  }
 
		}
 
		ContractManager contractManager = new ContractManager(this.con);
		Contract contract = contractManager.getContractByID(cid);
 
		if(contract.getFc()==1){
			setWebErrorMessage("управление статусом недоступно");
			return;
		}
 
		if ((contract.getStatus() != 4) && (contract.getStatus() != 0))
		{
			setWebErrorMessage("нельзя менять статус кроме 'активен' <-> 'приостановлен'");
			return;
		}
 
		if (!futureSuspendExists && contract.getStatus() != 4)
		{
			setWebErrorMessage("нет периодов приостановления");
			return;
		}
 
		String comment = "Изменено пользователем (отмена смены статуса)";
 
		ContractStatus status = new ContractStatus();
		status.setContractId(cid);
		status.setStatus(0);
		//status.setDate1(TimeUtils.convertDateToCalendar(date1));
		//status.setDate2(TimeUtils.convertDateToCalendar(date2));
		status.setDateFrom(date1);
		status.setDateTo(date2);
		status.setComment(comment);
		if ((isDateCheckingEnabled("ActionContractStatus")) && ((
		  (!checkDatesByClosedDate(null, date1)) || (!checkDatesByClosedDate(null, date2)))))
		{
			setWebErrorMessage("Устанавливаемый статус пересекается с закрытым периодом!");
			return;
		}
		//Устанавливаем статус
		//statusManager.changeStatus(status.clone(), this.userID, true, true);
		statusManager.changeStatus(status.clone(), Integer.valueOf(-1), true);
		BalanceUtils bu =  new BalanceUtils(this.con);
		//Удаляем расходы с даты date1 до бесконечности
	    if(this.chargeAsRSCMsid>0)
	    	//Удаляем все RSCM-услуги заданного типа
	    {
	    	//определяем mid модуля rscm
	    	int rscmMid=0;
			PreparedStatement ps = this.con.prepareStatement("select mid from service where id=?");
			ps.setInt(1, this.chargeAsRSCMsid);
			ResultSet rs = ps.executeQuery();
			if(rs.next()){
				rscmMid = rs.getInt(1);
			}
			rs.close();
 
			ContractServiceManager rscmManager = new ContractServiceManager(this.con,rscmMid);
			//Определяем таблицы, в которых будем искать rscm-услуги для удаления
			Calendar mon = Calendar.getInstance();
			//Не паримся и удаляем RSCM-услуги приостановления за текущий и следующий месяц только
			for(int i=0;i<=1;i++){
				String table_name = ServerUtils.getModuleMonthTableName("rscm_service_account", TimeUtils.convertCalendarToDate(mon), rscmMid); 
				if(ServerUtils.tableExists(this.con, table_name)){
					ps = this.con.prepareStatement("select id, date from "+table_name+" where cid=? and sid=? and date>=?");
					ps.setInt(1, cid);
					ps.setInt(2, this.chargeAsRSCMsid);
					ps.setDate(3, TimeUtils.convertDateToSqlDate(date1));
					rs = ps.executeQuery();
//					log.info("service_account count to delete: "+rs.getFetchSize());
					while(rs.next()){
//						log.info("service_account to delete: "+rs.getInt(1));
						rscmManager.deleteContractService(rs.getInt(1),cid,mon);
					}
					bu.updateBalance(TimeUtils.convertCalendarToDate(mon), cid);
				}
				mon.add(Calendar.MONTH,1);
			}
	    }
		//Удаляем расходы с даты date1 до бесконечности
		if(this.chargeType>=0)
	    {
			ChargeManager chargeManager = new ChargeManager(con);
 
			PreparedStatement ps = con.prepareStatement("select id, dt from contract_charge where cid=? and pt=? and dt>=?");
			ps.setInt(1, cid);
			ps.setInt(2, this.chargeType);
			ps.setDate(3, TimeUtils.convertDateToSqlDate(date1));
 
			ResultSet rs = ps.executeQuery();
			while(rs.next()){
				chargeManager.deleteCharge(rs.getInt(1));
				bu.updateBalance(TimeUtils.convertSqlDateToDate(rs.getDate(2)), cid);
			}
			//Обновляем баланс в личном кабинете - сбрасываем кэш contract_data, в котором хранятся данные о балансе
			this.request.getSession().setAttribute("contract_data", null);
 
	    }
	  }
 
}

5.0

/**
 * 
 */
package bitel.billing.server.contract;
 
import bitel.billing.common.BGException;
import bitel.billing.server.ActionBase;
import bitel.billing.common.TimeUtils;
import bitel.billing.server.contract.bean.BalanceUtils;
import bitel.billing.server.contract.bean.Charge;
import bitel.billing.server.contract.bean.ChargeManager;
import bitel.billing.server.contract.bean.Contract;
import bitel.billing.server.contract.bean.ContractManager;
import bitel.billing.server.contract.bean.ContractStatus;
import bitel.billing.server.contract.bean.ContractStatusManager;
import bitel.billing.server.script.bean.event.ChargeEvent;
import bitel.billing.server.script.bean.event.EventProcessor;
//import bitel.billing.server.script.bean.event.EventProcessor;
//import bitel.billing.server.script.bean.event.GetContractStatusChangeDatesEvent;
 
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
//import java.util.List;
import org.w3c.dom.Element;
 
//import ru.bitel.bgbilling.common.BGIllegalArgumentException;
 
/**
 * web params:
 * 
 * action=CustomSuspend
 * command=
 * 		Suspend ({to_date|(to_day,to_month,to_year)})
 * 		Activate ([from=tomorrow])
 */
public class WebAction_CustomSuspend extends ActionBase {
 
 
	private static final int CANCHANGE_DISABLED = 1;
	private static final int CANCHANGE_DISABLED_BADSTATUS = 2;
	private static final int CANCHANGE_DO = 3;
	private static final int CANCHANGE_CANCEL_ALLOW = 4;
//	private static final int CANCHANGE_CANCEL_DENY = 5;
	private static final int CANCHANGE_CANCEL_ALLOW_ONLY_TODAY = 6;
	private static final int CANCHANGE_DISABLED_LOW_ACCOUNT = 7;
 
	private int maxDays;	//Максимальное количество дней приостановления в течение checkDays
							//Параметр глобального конфига:
							//custom.suspend.max.suspened.in.period
	private int checkDays;	//Период, в течение которого клиент не может быть приостановлен более, чем maxDays дней
							//Параметр глобального конфига:
							//custom.suspend.suspened.check.period
	private int chargeType; //Берем расход за приостановление
							//Параметр глобального конфига:
							//custom.suspend.charge.type
	private float chargeSumm;//Сумма расхода за приостановление
 
	@Override
	public void doAction() throws SQLException, BGException 
	{
		int cid= this.cid;
 
	    if (cid <= 0)
	    {
	      setParamsError();
	      return;
	    }
 
		this.maxDays = this.setup.getIntValue("custom.suspend.max.suspened.in.period", 60);
		this.checkDays = this.setup.getIntValue("custom.suspend.suspened.check.period", 90);
		this.chargeType = this.setup.getIntValue("custom.suspend.charge.type", -1);
		this.chargeSumm = this.setup.getFloatValue("custom.suspend.charge.summa", 0);
 
		//Выполняем действия
 
	    if ("Suspend".equals(getParameter("command")))
	    {
	    	ActionCustomSuspendSuspend(cid);
	    	if(!rootNode.getAttribute("status").equals("error")){
	    		try {
	    			this.response.sendRedirect("webexecuter?action=CustomSuspend");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
	    }
 
		if ("Activate".equals(getParameter("command")))
	    {
			ActionCustomSuspendActivate(cid);
			if(!rootNode.getAttribute("status").equals("error")){
				try {
					this.response.sendRedirect("webexecuter?action=CustomSuspend");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
	    }
 
		//Строим список статусов
 
		ContractStatusManager statusManager = new ContractStatusManager(this.con);
		Element table = createElement(this.rootNode, "statuses");
 
		//Проверяем наличие в будущем статусов, отличных от 0 и 4
	    boolean isManualFutureStatuses = false;
	    Integer canchange = null;
	    for (ContractStatus status : statusManager.getStatusList(cid))
	    {
	      Element row = createElement(table, "status");
	      //row.setAttribute("period", TimeUtils.formatPeriod(status.getDate1(), status.getDate2()));
	      row.setAttribute("date1",  TimeUtils.format(status.getDate1(), "dd.MM.yyyy"));
	      row.setAttribute("date2",  TimeUtils.format(status.getDate2(), "dd.MM.yyyy"));
	      row.setAttribute("status", ContractStatus.statusToString(status.getStatus()));
	      row.setAttribute("statusint", String.valueOf(status.getStatus()));
	      //row.setAttribute("comment", status.getComment());
 
	      if(status.getDate2()==null){
	    	  row.setAttribute("future", "2");//Текущий период
	      }else{
	    	  if (TimeUtils.dateBeforeOrEq(new Date(), TimeUtils.convertCalendarToDate(status.getDate2()))) {
	    		  row.setAttribute("future", "2");//Текущий период
	    	  }
	      }
	      if(status.getDate1()==null){continue;}
	      if (!TimeUtils.dateBefore(new Date(), TimeUtils.convertCalendarToDate(status.getDate1()))) {
	        continue;
	      }
	      row.setAttribute("future", "1");
 
	      if ((status.getStatus() != 0) && (status.getStatus() != 4))
	      {
	    	  isManualFutureStatuses = true;
	      }
 
	      if(status.getStatus() == 4)
	      {
	    	  canchange = CANCHANGE_CANCEL_ALLOW; //Есть что отменять
	      }
	    }
 
 
	    //Пишем текущий статус
	    ContractManager contractManager = new ContractManager(this.con);
	    Contract contract = contractManager.getContractByID(cid);
	    int statusint = contract.getStatus();
	    if((isManualFutureStatuses==false)&&(statusint==4))//Если в будущем нет статусов кроме 0 и 4, но текущий статус - приостановлен, то ...
	    {
	    	canchange = CANCHANGE_CANCEL_ALLOW; //... можно его отменить
 
	    	//При этом, если завтрашний статус != "приостановлен", то отменять можно только сегодня
	    	Calendar tomorrow = Calendar.getInstance();
	    	tomorrow.add(Calendar.DATE, 1);
	    	if(statusManager.getStatus(cid, tomorrow).getStatus()!=4){
	    		canchange = CANCHANGE_CANCEL_ALLOW_ONLY_TODAY;
	    	}
	    }
 
	    this.rootNode.setAttribute("statusstr", ContractStatus.statusToString(statusint));
 
	    this.rootNode.setAttribute("statusint", String.valueOf(statusint));
 
	    //Запишем в xml сумму расхода за приостановление, если есть
	    if(this.chargeSumm>0){
	    	this.rootNode.setAttribute("suspendChargeSumm", String.valueOf(this.chargeSumm));
	    }	    
 
		if ((statusint != 0) && (statusint != 4))
	    {
	      canchange = Integer.valueOf(CANCHANGE_DISABLED_BADSTATUS);
	    }
 
		if(contract.getFc()==1) //Для юрлиц - нельзя
		{
			canchange = CANCHANGE_DISABLED;
		}
 
		//Дата, с которой можно менять статус (date1 для активации, деактивация всегда с завтрашнего числа)
	    Element date1 = createElement(this.rootNode, "mindate");
	    Calendar now = Calendar.getInstance();
	    if (statusint == 0)
	    {
	      now.add(5, 1);
	    }
	    date1.setAttribute("day", String.valueOf(now.get(5)));
	    date1.setAttribute("month", String.valueOf(now.get(2) + 1));
	    date1.setAttribute("year", String.valueOf(now.get(1)));
 
	    if (statusint == 0){
		    //<--рекомендуемая максимальная дата для приостановления (date2)
		    //Этот адовый кусок кода нужен только для того, чтобы показать пользователю максимальную дату,
	    	//до которой он может приостановить договор
	    	//..не спрашивайте, как это работает ;)
		    Element date2 = createElement(this.rootNode, "date");
 
		    //Сначала устанавливаем эту дату для рассчетного периода от (now-checkDays) до собстна upperbound
		    Calendar upperbound = Calendar.getInstance();
		    upperbound.add(Calendar.DATE, this.maxDays-this.SuspendedDays(cid) );
 
		    //lowerbound = upperbound - checkDays, определяем "нормальный" период проверки
		    Calendar lowerbound = (Calendar)upperbound.clone();
		    lowerbound.add(Calendar.DATE, - this.checkDays);
 
		    //lowestbound = now - checkDays
		    Calendar lowestbound = Calendar.getInstance();
		    lowestbound.add(Calendar.DATE, - this.checkDays);
 
		    //Теперь upperbound можно нарастить на количество дней приостановки между lowestbound и lowerbound
		    upperbound.add(Calendar.DATE, this.SuspendedDays(lowestbound, lowerbound, cid));
 
		    //Это и есть максимальная дата, до которой можно приостановить наш конкретный договор
		    date2.setAttribute("day", String.valueOf(upperbound.get(5)));
		    date2.setAttribute("month", String.valueOf(upperbound.get(2) + 1));
		    date2.setAttribute("year", String.valueOf(upperbound.get(1)));
		    //--/>
	    }
 
	    if (canchange == null)
	    {
	    	//Проверяем текущий баланс
			BalanceUtils bu =  new BalanceUtils(this.con);
			if(bu.getBalance(new Date(), cid).floatValue()-this.chargeSumm<0){
				canchange = CANCHANGE_DISABLED_LOW_ACCOUNT;
			}else{
				canchange = CANCHANGE_DO;//Всё ок
			}
	    }
 
 
 
	    this.rootNode.setAttribute("canchange", String.valueOf(canchange));
	  }
 
	private int SuspendedDays(Calendar date1, Calendar date2, int cid)
	throws SQLException
	{
	    PreparedStatement ps = this.con.prepareStatement("select sum(1+datediff(LEAST(date2,date(now())),GREATEST(?,date1))) from contract_status where cid=? and status=4 and date2>=? and date1<=?");
		ps.setDate(1, TimeUtils.convertCalendarToSqlDate(date1));
		ps.setInt(2, cid);
		ps.setDate(3, TimeUtils.convertCalendarToSqlDate(date1));
		ps.setDate(4, TimeUtils.convertCalendarToSqlDate(date2));
		ResultSet rs = ps.executeQuery();
		if(rs.next())
		{
			return rs.getInt(1);
		}else
		{
			return 0;
		}
	}
 
	//Количество приостановленных дней от текущего времени
	private int SuspendedDays(int cid)
		throws SQLException
	{
			Calendar date2 = Calendar.getInstance();
			Calendar date1 = (Calendar)date2.clone();
			date1.add(5, -this.checkDays);
			return SuspendedDays(date1, date2, cid);
	}
 
	//Приостанавливаем
	public void ActionCustomSuspendSuspend(int cid)
	    throws SQLException, BGException
	{
	    int newStatus = 4;
	    String comment = "Изменено пользователем";
 
	    Date date1 = null;
	    //Приостанавливаем только с завтрашнего числа
    	Calendar tomorrow = Calendar.getInstance();
    	tomorrow.add(5, 1);
    	date1 = tomorrow.getTime();
 
    	//По какое число приостанавливаем
    	Date date2 = getDateParameter("to_date");
	    if (date2 == null)
	    {
	      int day = getIntParameter("to_day", 0);
	      int month = getIntParameter("to_month", 0);
	      int year = getIntParameter("to_year", 0);
	      if ((day > 0) && (month > 0) && (year > 0))
	      {
	        Calendar dateCal = Calendar.getInstance();
	        dateCal.set(year, month - 1, day);
	        date2 = dateCal.getTime();
	      }
	    }
 
	    if (cid <= 0)
	    {
	    	setParamsError();
	    	return;
	    }
 
	    //Проверяем текущий баланс
		BalanceUtils bu =  new BalanceUtils(this.con);
		if(bu.getBalance(new Date(), cid).floatValue()-this.chargeSumm<0){
			setErrorStatus("Недостаточно средств для приостановления");
			return;
		}
 
	    if (date2 == null)
	    {
	    	setErrorStatus("не задана дата");
	    	return;
	    }	    
 
	    if (!checkPeriod(date1, date2))
	    {
	    	return;
	    }
 
	    ContractManager contractManager = new ContractManager(this.con);
	    Contract contract = contractManager.getContractByID(cid);
 
	    if ((((contract.getStatus() != 0) || (newStatus != 4))) && ((
	      (contract.getStatus() != 4) || (newStatus != 0))))
	    {
	      setErrorStatus("нельзя менять статус кроме 'активен' <-> 'приостановлен'");
	      return;
	    }
 
	    /*
	    if ((newStatus == 4) && (TimeUtils.dateBeforeOrEq(date1, new Date())))
	    {
	      setErrorStatus("можно приостанавливать договор не раньше завтрашнего числа");
	      return;
	    }*/
 
	    /*if ((newStatus == 0) && (TimeUtils.dateBefore(date1, new Date())))
	    {
	    	setErrorStatus("нельзя активировать раньше, чем сегодня");
	    	return;
	    }*/
 
	    //Проверка на suspend abuse
	    Calendar tmp = TimeUtils.convertDateToCalendar(date2);
	    tmp.add(Calendar.DATE, -this.checkDays);
	    int expectedSuspendedDays = this.SuspendedDays(tmp, Calendar.getInstance(), cid)+TimeUtils.daysDelta(TimeUtils.convertDateToCalendar(date1), TimeUtils.convertDateToCalendar(date2))+1;
	    if(expectedSuspendedDays>this.maxDays){
	    	setErrorStatus("Договор не может быть приостановлен дольше "+this.maxDays +" дней в течение "+ this.checkDays+". Сократите период на "+(expectedSuspendedDays-this.maxDays) + " дн.");
	    	return;	    	
	    }
 
	    ContractStatus status = new ContractStatus();
	    status.setContractId(cid);
	    status.setStatus(newStatus);
	    status.setDate1(TimeUtils.convertDateToCalendar(date1));
	    status.setDate2(TimeUtils.convertDateToCalendar(date2));
	    status.setComment(comment);
	    if ((isDateCheckingEnabled("ActionContractStatus")) && ((
	      (!checkDatesByClosedDate(null, date1)) || (!checkDatesByClosedDate(null, date2)))))
	    {
	    	setErrorStatus("Устанавливаемый статус пересекается с закрытым периодом!");
	    	return;
	    }
 
	    //Приостанавливаем
	    ContractStatusManager statusManager = new ContractStatusManager(this.con);
	    statusManager.changeStatus(status.clone(), this.userID, true, true);
	    //Вносим расход, если нужно
	    if(this.chargeType>=0)
	    {
	    	ChargeManager chargeManager = new ChargeManager(con);
	    	Charge charge = new Charge();
			charge.setChargeDate(date1);
			charge.setChargeTypeID(this.chargeType);
			charge.setComment("Приостановление через Web");
			charge.setContractID(cid);
			charge.setID(-1);
			charge.setSumma(new BigDecimal(this.chargeSumm));
			charge.setUserID(0);
			chargeManager.updateCharge(charge);
			EventProcessor.getProcessor().addEvent(new ChargeEvent(charge));
			//Обновляем баланс в предыдущем месяце
			bu.updateBalance(date1, cid);
			//Обновляем баланс в личном кабинете - сбрасываем кэш contract_data, в котором хранятся данные о балансе
			this.request.getSession().setAttribute("contract_data", null);
	    }
	}
 
	public void ActionCustomSuspendActivate(int cid)
	    throws SQLException, BGException
	{
		//Дата, с которой будем активироваться: сегодня или завтра
		Calendar dt = Calendar.getInstance();
 
		if("tomorrow".equals(getParameter("from")))
		{//Включаемся завтра
			dt.add(Calendar.DATE, 1);
		}
		Date date1 = TimeUtils.convertCalendarToDate(dt);
		Date date2 = null;
 
		//Есть ли вообще что отменять в будущем?
		boolean futureSuspendExists=false;
		ContractStatusManager statusManager = new ContractStatusManager(this.con);
		//Перебираем будущие статусы: если есть статусы, отличные от 4 и 0, то отменять приостановление нельзя
		for (ContractStatus status : statusManager.getStatusList(cid))
		{
		  if (!TimeUtils.dateBefore(Calendar.getInstance(), status.getDate1())) {
		    continue;
		  }
 
		  if ((status.getStatus() != 0) && (status.getStatus() != 4))
		  {
			  setErrorStatus("запланировано изменение статуса на что-либо отличное от 'активен' или 'приостановлен'");
			  return;
		  }
		  if (status.getStatus() == 4)
		  {
			  futureSuspendExists=true;
		  }
 
		}
 
		ContractManager contractManager = new ContractManager(this.con);
		Contract contract = contractManager.getContractByID(cid);
 
		if(contract.getFc()==1){
			setErrorStatus("управление статусом недоступно");
			return;
		}
 
		if ((contract.getStatus() != 4) && (contract.getStatus() != 0))
		{
			setErrorStatus("нельзя менять статус кроме 'активен' <-> 'приостановлен'");
			return;
		}
 
		if (!futureSuspendExists && contract.getStatus() != 4)
		{
			setErrorStatus("нет периодов приостановления");
			return;
		}
 
		String comment = "Изменено пользователем (отмена смены статуса)";
 
		ContractStatus status = new ContractStatus();
		status.setContractId(cid);
		status.setStatus(0);
		status.setDate1(TimeUtils.convertDateToCalendar(date1));
		status.setDate2(TimeUtils.convertDateToCalendar(date2));
		status.setComment(comment);
		if ((isDateCheckingEnabled("ActionContractStatus")) && ((
		  (!checkDatesByClosedDate(null, date1)) || (!checkDatesByClosedDate(null, date2)))))
		{
			setErrorStatus("Устанавливаемый статус пересекается с закрытым периодом!");
			return;
		}
 
		//Устанавливаем статус
		statusManager.changeStatus(status.clone(), this.userID, true, true);
		//Удаляем расходы с даты date1 до бесконечности
		if(this.chargeType>=0)
	    {
			ChargeManager chargeManager = new ChargeManager(con);
	    	BalanceUtils bu =  new BalanceUtils(this.con);
 
			PreparedStatement ps = con.prepareStatement("select id, dt from contract_charge where cid=? and pt=? and dt>=?");
			ps.setInt(1, cid);
			ps.setInt(2, this.chargeType);
			ps.setDate(3, TimeUtils.convertDateToSqlDate(date1));
 
			ResultSet rs = ps.executeQuery();
			while(rs.next()){
				chargeManager.deleteCharge(rs.getInt(1));
				bu.updateBalance(TimeUtils.convertSqlDateToDate(rs.getDate(2)), cid);
			}
			//Обновляем баланс в личном кабинете - сбрасываем кэш contract_data, в котором хранятся данные о балансе
			this.request.getSession().setAttribute("contract_data", null);
 
	    }
	  }
 
}

XSL template

<xsl:template name="CustomSuspend">
	<xsl:call-template name="error"/>
 
	<!-- canchange:
			CANCHANGE_DISABLED = 1
			CANCHANGE_DISABLED_BADSTATUS = 2
			CANCHANGE_DO = 3
			CANCHANGE_CANCEL_ALLOW = 4
			CANCHANGE_CANCEL_ALLOW_ONLY_TODAY = 6
			CANCHANGE_DISABLED_LOW_ACCOUNT = 7
	-->
	<xsl:choose>
		<!-- если canchange=1 -->
		<xsl:when test="/data/@canchange=1">
			Вы не можете менять статус
		</xsl:when>
		<xsl:when test="/data/@canchange=2">
			Ваш текущий или будущий статус не позволяет воспользоваться приостановлением услуг
		</xsl:when>
		<xsl:when test="/data/@canchange=3">
			<!-- Можно приостановить -->
			<form method="post" action="{$WEBEXECUTER}">
			<xsl:call-template name="module"/>
			<input type="hidden" name="action" value="CustomSuspend" />
			<input type="hidden" name="command" value="Suspend" />
			<table cellspacing="0" class="filter" style="font-size:12px">
			<tr>
				<td>
					Приостановить услуги
				</td>
				<td>с
					<xsl:if test="/data/mindate">
					<b>
					<xsl:value-of select="/data/mindate/@day"/>.<xsl:value-of select="/data/mindate/@month"/>.<xsl:value-of select="/data/mindate/@year"/>
					</b>
					</xsl:if>
					<xsl:if test="not(/data/mindate)">
					<b>завтрашнего числа</b>
					</xsl:if>
				</td>
				<td>
					по
					<select name="to_day">
						<option value='0'><xsl:if test="/data/date/@day = '0'"><xsl:attribute name="selected">1</xsl:attribute></xsl:if>--</option>
						<xsl:call-template name="day_list"/>
					</select>
				</td>
				<td>
					<select name="to_month">
						<xsl:call-template name="month_list"/>
					</select>
				</td>
				<td>
					<select name="to_year">
						<xsl:if test="/data/mindate/@year != /data/date/@year">
							<option value="{/data/mindate/@year}"><xsl:value-of select="/data/mindate/@year"/></option>
						</xsl:if>
						<option value="{/data/date/@year}" selected="1"><xsl:value-of select="/data/date/@year"/></option>
					</select>
				</td>
				<xsl:if test="/data/@suspendChargeSumm">
				<td>за <b><font color="red"><xsl:value-of select="/data/@suspendChargeSumm"/>р.</font></b> единовременно</td>
				</xsl:if>
				<td>
				<xsl:call-template name="submit">
					<xsl:with-param name="title" select="'Выполнить'"/>
					<xsl:with-param name="guid" select="'_set'"/>
				</xsl:call-template>
				</td>
			</tr>
			</table>
			</form>
		</xsl:when>
		<xsl:when test="/data/@canchange=4">
			<!-- Можно активировать договор -->
			<!--
			Вы можете активировать договор <b>
<a href="{$WEBEXECUTER}?action=CustomSuspend&amp;command=Activate">сегодня</a></b> или <b><a href="{$WEBEXECUTER}?action=CustomSuspend&amp;command=Activate&amp;from=tomorrow">завтра</a></b>
			-->
			<table style="font-size: 12px;">
			<tr>
			<td>Вы можете <b>активировать</b> договор</td>
			<td>
				<xsl:call-template name="button">
					<xsl:with-param name="align" select="'left'"/>
					<xsl:with-param name="onclick">location.href='<xsl:value-of select="$WEBEXECUTER"/>?action=CustomSuspend&amp;command=Activate'</xsl:with-param>
					<xsl:with-param name="title" select="'Сегодня'"/>
				</xsl:call-template>
			</td>
			<td>или</td>
			<td>
				<xsl:call-template name="button">
					<xsl:with-param name="align" select="'left'"/>
					<xsl:with-param name="onclick">location.href='<xsl:value-of select="$WEBEXECUTER"/>?action=CustomSuspend&amp;command=Activate&amp;from=tomorrow'</xsl:with-param>
					<xsl:with-param name="title" select="'Завтра'"/>
				</xsl:call-template>
			</td>
			</tr>
			</table>
		</xsl:when>
		<xsl:when test="/data/@canchange=6">
			<!-- Можно активировать договор только сегодня -->
			<!--
			Вы можете активировать договор <b>
<a href="{$WEBEXECUTER}?action=CustomSuspend&amp;command=Activate">сегодня</a></b>
			-->
			<table style="font-size: 12px;">
			<tr>
			<td>Вы можете <b>активировать</b> договор</td> 
			<td>
				<xsl:call-template name="button">
					<xsl:with-param name="align" select="'left'"/>
					<xsl:with-param name="onclick">location.href='<xsl:value-of select="$WEBEXECUTER"/>?action=CustomSuspend&amp;command=Activate'</xsl:with-param>
					<xsl:with-param name="title" select="'Сегодня'"/>
				</xsl:call-template>
			</td>
			</tr>
			</table>
		</xsl:when>
		<xsl:when test="/data/@canchange=7">
			<!-- Низкий остаток на балансе -->
			<p>Недостаточно средств для приостановления услуг. Баланс должен быть не меньше <xsl:if test="/data/@suspendChargeSumm"><b><xsl:value-of select="/data/@suspendChargeSumm"/>р</b></xsl:if><xsl:if test="not(/data/@suspendChargeSumm)"><b>0</b></xsl:if>. <xsl:if test="/data/contract_data/contract/@balance_rest"> Ваш текущий баланс = <b><xsl:value-of select="/data/contract_data/contract/@balance_rest"/>р</b>.</xsl:if></p>
                        <!-- Если у провайдера используется обещанный платеж, то нужно указать об этом-->
			<p>Обещанный платеж не влияет на текущий баланс.</p>
                        <!-- Если у провайдера используется логика дебетовых абонплат, то нужно указать об этом-->
			<xsl:if test="/data/@balance_mode='1'"><p>При отсутствии средств на счету услуги приостанавливаются автоматически раз в сутки статусом "<font color="red">закрыт</font>".</p></xsl:if>
		</xsl:when>		
		<xsl:otherwise>
			Вы не можете менять статус.
		</xsl:otherwise>
	</xsl:choose>
	<br/>
    <b>Текущий статус: 
		<font>
			<xsl:if test="/data/@statusint='0'"><xsl:attribute name="color">green</xsl:attribute></xsl:if>
			<xsl:if test="/data/@statusint='3'"><xsl:attribute name="color">red</xsl:attribute></xsl:if>
			<xsl:value-of select="/data/@statusstr"/>
		</font>
	</b>
	<br/>
	<br/>
	<b>История изменения статусов:</b>
	<br/>
	<br/>
 
		<div class="report">
			<table cellspacing="1" width="400px">
			<thead>
			  <tr>
				<td>С даты</td>
				<td>По дату</td>
				<td>Статус</td>
			  </tr>
			</thead>
			<tbody>
			  <xsl:for-each select="statuses/status">
				<xsl:sort select="position()" data-type="number" order="descending"/>
				<tr>
					<xsl:if test="@future=2"><xsl:attribute name="style">font-weight:bold;</xsl:attribute></xsl:if>
					<td><xsl:value-of select="@date1"/></td>
					<td><xsl:value-of select="@date2"/></td>
					<td>
						<xsl:if test="@statusint='0'"><xsl:attribute name="style">color:green;</xsl:attribute></xsl:if>
						<xsl:if test="@statusint='3'"><xsl:attribute name="style">color:red;</xsl:attribute></xsl:if>
						<xsl:value-of select="@status"/>
					</td>		
				</tr>		
			  </xsl:for-each>
			</tbody>
			</table>
		</div>
 
</xsl:template>

--Cromeshnic 04:31, 22 июля 2010 (UTC)

Личные инструменты