Делаю через dynservice:ru.bitel.bgbilling.kernel.contract.api.ContractService
Я для своих подкрашиваю VIP-клиентов:
Код:
package ru.iks.dyn;
import java.sql.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import javax.jws.WebService;
import javax.xml.ws.Holder;
import java.sql.SQLException;
import org.apache.log4j.Logger;
 
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.common.BGMessageException;
import ru.bitel.bgbilling.kernel.contract.api.common.service.ContractService;
import ru.bitel.common.Utils;
import bitel.billing.common.TimeUtils;
import ru.bitel.common.model.Page;
import bitel.billing.server.contract.bean.*;
import ru.bitel.oss.kernel.entity.common.bean.filter.FilterEntityAttr;
import ru.bitel.bgbilling.kernel.contract.api.common.bean.Contract;
@WebService(endpointInterface = "ru.bitel.bgbilling.kernel.contract.api.common.service.ContractService")
public class myContractServiceImpl
   extends ru.bitel.bgbilling.kernel.contract.api.server.service.ContractServiceImpl
   implements ContractService
{
   private static final Logger logger = Logger.getLogger( myContractServiceImpl.class );
   @Override
   public List<Contract> contractList(String title, String comment, int fc, long groupMask, List<FilterEntityAttr> entityFilter, boolean subContracts, boolean closed, boolean hidden, Holder<Page> pageHolder)
      throws BGException
   {
      List<Contract> list = super.contractList(title, comment, fc, groupMask, entityFilter, subContracts, closed, hidden, pageHolder);
      List<Integer> myCids = new ArrayList<Integer>();
        Page page;
        if(pageHolder == null || (page = (Page)pageHolder.value) == null)
            page = new Page(1, 25);
        StringBuilder sb = new StringBuilder(150);
        StringBuilder where = new StringBuilder("1=1");
        sb.append("select c.id FROM contract c left join contract_parameter_type_1 cpt1 on cpt1.cid=c.id and cpt1.pid=30 ");
        if(groupMask > 0L)
            where.append(" AND c.gr&?=?");
        if(closed)
            where.append(" AND (c.date2 IS NULL OR ?<=c.date2) ");
        if(title != null && title.trim().length() > 0)
            where.append(" AND (UPPER(c.title) REGEXP ? or cpt1.val REGEXP ?) ");
        if(comment != null && comment.trim().length() > 0)
            where.append(" AND UPPER(c.comment) REGEXP ?");
        if(fc == 1 || fc == 0)
            where.append(" AND c.fc=?");
        if(groupMask == 0L && title == null && comment == null && fc == -1)
            where.append(" AND c.gr=0");
        if(!subContracts)
            where.append(" AND c.scid IN ( 0, -1 )");
        if(where.length() > 0) {
            sb.append(" WHERE ");
            sb.append(where);
        }
        sb.append(" ORDER BY c.title");
        if(page.getPageSize() > 0)
            sb.append(" LIMIT ?, ?");
      int i = 1;
        try {
         PreparedStatement ps = (getConnection()).prepareStatement(sb.toString());
         if(groupMask > 0L) {
            ps.setLong(i++, groupMask);
            ps.setLong(i++, groupMask);
         }
         if(closed)
            ps.setDate(i++, TimeUtils.convertDateToSqlDate(new Date()));
         if(title != null && title.trim().length() > 0) {
            ps.setString(i++, title.toUpperCase());
            ps.setString(i++, title.toUpperCase());
         }
         if(comment != null && comment.trim().length() > 0)
            ps.setString(i++, comment.toUpperCase());
         if(fc == 1 || fc == 0)
            ps.setInt(i++, fc);
         if(page.getPageSize() > 0) {
            ps.setInt(i++, page.getPageFirstRecordNumber());
            ps.setInt(i++, page.getPageSize());
         }
         ResultSet rs;
         for( rs = ps.executeQuery(); rs.next(); )
            myCids.add(rs.getInt(1));
         rs.close();
         ps.close();
        }
        catch(SQLException e) {
         throw new BGException(e);
        }
      for( i=0; i<list.size(); i++ ) {
         if( myCids.contains(list.get(i).getId()) )
            myCids.remove((Integer)list.get(i).getId());
      }
      for( i=0; i<myCids.size(); i++ )
         list.add(contractGet(myCids.get(i)));
      for( i=0; i<list.size(); i++ ) {
         if( (list.get(i).getGroups() & Utils.enumToMask("53")) != 0L ) {
            String sTitle = list.get(i).getTitle();
            list.get(i).setTitle("<html><div style='color: red; font-weight: bold'>!!! VIP !!! " + sTitle);
         }
         list.get(i).setComment(list.get(i).getComment()+" {"+(new ContractParameterManager(getConnection())).getStringParam(list.get(i).getId(), 30)+"}");
      }
      return list;
   }
}
Плюс там еще выводится в конце в фигурных скобках значение параметра договора с id=30, это у нас Лицевой счет.
Чтобы раскрашивать внутри договора:
dynaction:contract.ActionContractInfo=ru.iks.dyn.myContractInfo
Код:
package ru.iks.dyn;
import java.sql.*;
import org.w3c.dom.*;
import ru.bitel.common.*;
import java.util.Date;
import java.math.BigDecimal;
import bitel.billing.common.TimeUtils;
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.modules.npay.server.bean.DebetStatusManageConfig;
import ru.bitel.bgbilling.server.util.Setup;
import bitel.billing.server.contract.bean.*;
import bitel.billing.server.npay.bean.ServiceObjectManager;
import bitel.billing.server.contract.bean.*;
public class myContractInfo
    extends bitel.billing.server.contract.action.ActionContractInfo
{
    @Override
    public void doAction()
        throws SQLException, BGException
    {
        super.doAction();
      int NPAY_MID = 3;
      int NO_MONEY_STATUS_ID = 7;
      int W_TARIFF_NO_MONEY_STATUS_ID = 9;
      int F_TARIFF_NO_MONEY_STATUS_ID = 10;
      ContractManager cm = new ContractManager(con);
      Contract c = new Contract();
      Element itemElement = XMLUtils.selectElement( rootNode, (new StringBuilder("/data/info/modules/item[@id=")).append(3).append("]").toString() );
      if( itemElement != null ) {
         String status = itemElement.getAttribute("status");
         if( status.length() == 0 ) {
            DebetStatusManageConfig config = new DebetStatusManageConfig(Setup.getSetup().getModuleSetup(Integer.valueOf(NPAY_MID)));
            if(config.isEnable())
            {
               ContractManager contractManager = new ContractManager(con);
               Contract contract = contractManager.getContractById(super.cid);
               contractManager.recycle();
               if(config.isEnableForContract(contract) && (new ServiceObjectManager(con, NPAY_MID)).getServiceObjectList(cid, null).size() > 0)
               {
                  if( contract.getStatus() == W_TARIFF_NO_MONEY_STATUS_ID || contract.getStatus() == F_TARIFF_NO_MONEY_STATUS_ID ) {
                     contract.setStatus(NO_MONEY_STATUS_ID);
                  }
                  BigDecimal unlockSumm = config.getSummaForUnlock(con, NPAY_MID, contract);
                  if(unlockSumm != null)
                  {
                     itemElement.setAttribute( "status", unlockSumm.toString() );
                  }
               }
            }
         }
      }
      c = cm.getContractById(cid);
      cm.recycle();
      if( (c.getGroups() & Utils.enumToMask("53")) != 0L ) {
         Element itemElementVIPGroup = XMLUtils.selectElement( rootNode, (new StringBuilder("/data/info/groups/item[@id=")).append(53).append("]").toString() );
         if( itemElementVIPGroup != null ) {
            itemElementVIPGroup.setAttribute( "title", "<html><div style='color: red; font-weight: bold'>" + itemElementVIPGroup.getAttribute( "title" ) + "</div/></html>" );
         }
         Element itemElementVIPTitle = XMLUtils.selectElement( rootNode, "/data/contract" );
         if( itemElementVIPTitle != null ) {
            itemElementVIPTitle.setAttribute( "title", "<html><div style='color: red; font-weight: bold'>" + itemElementVIPTitle.getAttribute( "title" ) );
            itemElementVIPTitle.setAttribute( "comment", itemElementVIPTitle.getAttribute( "comment" ) + " ]</div/></html>" );
         }
      }
   }
}
В последнем коде у меня там еще суммы разблокировки для дебет-договоров со статусами 9 и 10 выводятся, я не стал это убирать, как для примера может кому пригодиться.
Код писал для 5.2 и с небольшими изменениями он кочует по всем версиям. Сегодня проверил на 7.0 - работает.