Создание счетов на предоплату
Материал из BiTel WiKi
(Различия между версиями)
Artur (Обсуждение | вклад) |
Skyb (Обсуждение | вклад) |
||
Строка 159: | Строка 159: | ||
} | } | ||
} | } | ||
+ | </source> | ||
+ | |||
+ | Выставление по каждой услуги на договоре отдельно | ||
+ | <source lang="java"> | ||
+ | package ru.skyb.scripts.global; | ||
+ | |||
+ | |||
+ | import bitel.billing.common.TimeUtils; | ||
+ | import ru.bitel.bgbilling.kernel.script.server.dev.GlobalScriptBase; | ||
+ | import ru.bitel.bgbilling.server.util.ModuleSetup; | ||
+ | import ru.bitel.bgbilling.server.util.Setup; | ||
+ | import ru.bitel.common.sql.ConnectionSet; | ||
+ | import ru.bitel.common.Utils; | ||
+ | import ru.bitel.common.XMLUtils; | ||
+ | import ru.bitel.bgbilling.modules.npay.server.Calculator; | ||
+ | import bitel.billing.server.bill.bean.*; | ||
+ | import bitel.billing.server.contract.bean.*; | ||
+ | |||
+ | import java.io.ByteArrayInputStream; | ||
+ | import java.io.ByteArrayOutputStream; | ||
+ | import java.io.InputStream; | ||
+ | import java.math.*; | ||
+ | import java.sql.*; | ||
+ | import java.util.*; | ||
+ | import java.util.Date; | ||
+ | |||
+ | import org.w3c.dom.Document; | ||
+ | import org.w3c.dom.Element; | ||
+ | |||
+ | import javax.xml.parsers.DocumentBuilder; | ||
+ | import javax.xml.parsers.DocumentBuilderFactory; | ||
+ | |||
+ | import org.apache.log4j.Logger; | ||
+ | |||
+ | public class BillGen | ||
+ | extends GlobalScriptBase | ||
+ | { | ||
+ | private static final Logger logger = Logger.getLogger( BillGen.class ); | ||
+ | |||
+ | @Override | ||
+ | public void execute( Setup setup1, ConnectionSet connectionSet2 ) | ||
+ | throws Exception | ||
+ | { | ||
+ | log( "Инициализация" ); | ||
+ | //переменные | ||
+ | int npayMid = 8; //код модуля Npay | ||
+ | String groups = "6"; //коды групп договоров через запятую | ||
+ | Connection con = connectionSet2.getConnection(); //соединение с БД | ||
+ | int billMid = 9; // код модуля Бухгалтерии | ||
+ | int accountId = 1; // код счета банка | ||
+ | String docType = "1"; // ID типа выставляемого документа | ||
+ | int userId = 0; // ID пользователя, от имени которого выставляется счет | ||
+ | //получаем список договоров, для которых будем выставлять счета | ||
+ | log( "Получение списка договоров" ); | ||
+ | StringBuilder cids = new StringBuilder(); | ||
+ | StringBuilder query = new StringBuilder( "SELECT id FROM contract" ); | ||
+ | long groupMask = Utils.enumToMask( groups ); | ||
+ | if( groupMask > 0 ) | ||
+ | { | ||
+ | query.append( " WHERE gr&?>0" ); | ||
+ | } | ||
+ | PreparedStatement ps = con.prepareStatement( query.toString() ); | ||
+ | if( groupMask > 0 ) | ||
+ | { | ||
+ | ps.setLong( 1, groupMask ); | ||
+ | } | ||
+ | ResultSet rs = ps.executeQuery(); | ||
+ | while( rs.next() ) | ||
+ | { | ||
+ | cids.append( rs.getInt( "id" ) + "," ); | ||
+ | } | ||
+ | rs.close(); | ||
+ | ps.close(); | ||
+ | cids.deleteCharAt( cids.lastIndexOf( "," ) ); | ||
+ | log( "Получено " + cids.toString().split( "," ).length + " договоров, которым необходимо выставить авансовые счета" ); | ||
+ | //запускаем калькулятор по всем договорам, полученным выше | ||
+ | log( "Запуск предначисления наработки для выбранных договоров" ); | ||
+ | Calendar dt = new GregorianCalendar(); | ||
+ | dt.add( Calendar.MONTH, 1 ); //нам нужно, чтобы считался будущий месяц | ||
+ | dt.set( Calendar.DAY_OF_MONTH, dt.getActualMaximum( Calendar.DAY_OF_MONTH ) ); //выставляем последнее число будущего месяца | ||
+ | |||
+ | Calculator calculator = new Calculator(); | ||
+ | calculator.setExecutingTime( dt ); | ||
+ | calculator.setPreCalc(); | ||
+ | calculator.initTask( setup1, 0, "mid=" + npayMid ); //здесь можно прописывать только конкретные услуги через service.set=<наборы через запятую> | ||
+ | calculator.setCids( cids.toString() ); | ||
+ | calculator.startTask(); | ||
+ | //после обсчета получаем список наработок с разбивкой по договорам | ||
+ | Map<Integer, BigDecimal> planAccountMap = new HashMap<Integer, BigDecimal>(); | ||
+ | if( !calculator.isCalcErrors() ) | ||
+ | { | ||
+ | planAccountMap = calculator.getCostCache().getContractAccounts(); | ||
+ | print("planAccountMap " + planAccountMap); | ||
+ | } | ||
+ | Collection<CostSum> costSumList = calculator.getCostCache().getAmounts(); | ||
+ | log( "Подсчет наработки закончен. Формирование документов" ); | ||
+ | //for( CostSum costSum : calculator.getCostCache().getAmounts() ) | ||
+ | //{ | ||
+ | // log ("CostSum " +costSum.cost.abs()); | ||
+ | //} | ||
+ | //ок, теперь нужно формировать документы | ||
+ | //dt.add( Calendar.MONTH, -1 ); | ||
+ | int mm = dt.get(Calendar.MONTH); | ||
+ | int yy = dt.get(Calendar.YEAR); | ||
+ | log("Дата формирования счетов: " + TimeUtils.format( new Date(), TimeUtils.DATE_FORMAT_PATTERN_DDMMYYYY_HHMMSS ) ); | ||
+ | log("Старт генерации документов за год=" + yy + "; месяц=" + mm + "; группы договоров=" + groups); | ||
+ | |||
+ | BalanceUtils bu = new BalanceUtils( con ); | ||
+ | ModuleSetup moduleSetup = setup1.getModuleSetup( billMid ); | ||
+ | TemplateBillManager man = new TemplateBillManager( moduleSetup, con, billMid, false ); | ||
+ | List<TemplateBill> templateBillList = man.getTemplatePayBillList( moduleSetup, yy, mm, groups, null, docType, null, false ); | ||
+ | log("Число сгенерированных документов = " + templateBillList.size()); | ||
+ | DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); | ||
+ | DocumentBuilder docBuilder = dFactory.newDocumentBuilder(); | ||
+ | Document doc = docBuilder.newDocument(); | ||
+ | Element bills = doc.createElement("bills"); | ||
+ | for( TemplateBill templateBill : templateBillList ) | ||
+ | { | ||
+ | //if(templateBill.getContractId() == costSum.cid) | ||
+ | //{ | ||
+ | Element row = XMLUtils.createElement(bills, "bill"); | ||
+ | row.setAttribute( "rest", Utils.formatBigDecimalSumm( bu.getBalance( dt.getTime(), templateBill.getContractId() ) ) ); | ||
+ | row.setAttribute( "account_id",String.valueOf(accountId )); | ||
+ | log("Получаем наработку за будущий месяц по договору, если она есть"); | ||
+ | BigDecimal summ = Utils.maskNull( planAccountMap.get( templateBill.getContractId() ) ); | ||
+ | fillBillData( row, templateBill, summ, costSumList, con ); | ||
+ | //} | ||
+ | } | ||
+ | doc.appendChild(bills); | ||
+ | ByteArrayOutputStream sos = new ByteArrayOutputStream(); | ||
+ | XMLUtils.serialize(bills, sos, "UTF-8"); | ||
+ | String xml = sos.toString(); | ||
+ | log("Полученная сгенерированная xml со счетами: " + xml ); | ||
+ | InputStream is = new ByteArrayInputStream( xml.getBytes( "cp1251" ) ); | ||
+ | BillManager pbm = new BillManager( setup1, con, billMid, moduleSetup ); | ||
+ | pbm.addBillDocs( userId, is, yy, mm, dt.getTime(), false ); | ||
+ | //} | ||
+ | } | ||
+ | |||
+ | private void fillBillData( Element row, TemplateBill templateBill, BigDecimal billSumm, Collection<CostSum> costSumList, Connection con ) throws SQLException | ||
+ | { | ||
+ | List<PositionValue> valList = new ArrayList<PositionValue>(); | ||
+ | BigDecimal totalSum = BigDecimal.ZERO; | ||
+ | for( CostSum costSum : costSumList ) | ||
+ | { | ||
+ | if(templateBill.getContractId() == costSum.cid) | ||
+ | { | ||
+ | row.setAttribute( "id", String.valueOf( templateBill.getContractDocTypeId() ) ); | ||
+ | row.setAttribute( "type", String.valueOf( templateBill.getDocTypeId() ) ); | ||
+ | //row.setAttribute( "cid", String.valueOf( templateBill.getContractId() ) ); | ||
+ | row.setAttribute( "cid", String.valueOf( costSum.cid ) ); | ||
+ | |||
+ | row.setAttribute( "contract", templateBill.getContractTitle() ); | ||
+ | row.setAttribute( "contract_comment", templateBill.getContractComment() ); | ||
+ | |||
+ | String query = " select title from service where id = " + costSum.sid ; | ||
+ | PreparedStatement contractPs = con.prepareStatement( query ); | ||
+ | ResultSet contractRs = contractPs.executeQuery(); | ||
+ | while ( contractRs.next() ) | ||
+ | { | ||
+ | String title = contractRs.getString( 1 ); | ||
+ | log("title " + title + " costSum.cid " + costSum.cid ); | ||
+ | PositionValue value = new PositionValue(); | ||
+ | value.setSumma( costSum.cost.abs() ); | ||
+ | value.setSumScaled( costSum.cost.abs() ); | ||
+ | value.setSumUnscaled( costSum.cost.abs() ); | ||
+ | value.setName(title); | ||
+ | totalSum = totalSum.add( costSum.cost ); | ||
+ | Element posEl = XMLUtils.createElement( row, "pos" ); | ||
+ | value.toElement( posEl ); | ||
+ | } | ||
+ | contractRs.close(); | ||
+ | contractPs.close(); | ||
+ | } | ||
+ | templateBill.setPositionList(valList); | ||
+ | row.setAttribute( "summ", Utils.formatBigDecimalSumm( totalSum.abs() ) ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Вывод сообщений и в лог-файл и в клиентский лог. | ||
+ | * @param msg текст сообщения. | ||
+ | */ | ||
+ | private void log( String msg ) | ||
+ | { | ||
+ | print( msg ); | ||
+ | logger.info( msg ); | ||
+ | } | ||
+ | } | ||
+ | |||
</source> | </source> |
Текущая версия на 21:38, 25 ноября 2014
Основная проблема выставления счетов в будущем - отсутствие данных по наработке и начислениям. Именно поэтому в клиенте биллинга можно выставлять счета только за текущий или предыдущий периоды. Для выставления счетов в будущем можно воспользоваться API биллинга. Ниже представлен пример формирования счета, установки суммы позиций, которые вычисляются с помощью "виртуального" начисления абонплат. Код представляет собой глобальный скрипт на динамическом коде, который можно запускать по планировщику в нужное время.
package ru.stk; import bitel.billing.common.TimeUtils; import ru.bitel.bgbilling.kernel.script.server.dev.GlobalScriptBase; import ru.bitel.bgbilling.server.util.ModuleSetup; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.sql.ConnectionSet; import ru.bitel.common.Utils; import ru.bitel.common.XMLUtils; import ru.bitel.bgbilling.modules.npay.server.Calculator; import bitel.billing.server.bill.bean.*; import bitel.billing.server.contract.bean.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.math.*; import java.sql.*; import java.util.*; import java.util.Date; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.log4j.Logger; public class BillGen extends GlobalScriptBase { private static final Logger logger = Logger.getLogger( BillGen.class ); @Override public void execute( Setup setup1, ConnectionSet connectionSet2 ) throws Exception { log( "Инициализация" ); //переменные int npayMid = 66; //код модуля Npay String groups = "60"; //коды групп договоров через запятую Connection con = connectionSet2.getConnection(); //соединение с БД int billMid = 65; // код модуля Бухгалтерии int accountId = 1; // код счета банка String docType = "10"; // ID типа выставляемого документа int userId = 46; // ID пользователя, от имени которого выставляется счет //получаем список договоров, для которых будем выставлять счета log( "Получение списка договоров" ); StringBuilder cids = new StringBuilder(); StringBuilder query = new StringBuilder( "SELECT id FROM contract" ); long groupMask = Utils.enumToMask( groups ); if( groupMask > 0 ) { query.append( " WHERE gr&?>0" ); } PreparedStatement ps = con.prepareStatement( query.toString() ); if( groupMask > 0 ) { ps.setLong( 1, groupMask ); } ResultSet rs = ps.executeQuery(); while( rs.next() ) { cids.append( rs.getInt( "id" ) + "," ); } rs.close(); ps.close(); cids.deleteCharAt( cids.lastIndexOf( "," ) ); log( "Получено " + cids.toString().split( "," ).length + " договоров, которым необходимо выставить авансовые счета" ); //запускаем калькулятор по всем договорам, полученным выше log( "Запуск предначисления наработки для выбранных договоров" ); Calendar dt = new GregorianCalendar(); dt.add( Calendar.MONTH, 1 ); //нам нужно, чтобы считался будущий месяц dt.set( Calendar.DAY_OF_MONTH, dt.getActualMaximum( Calendar.DAY_OF_MONTH ) ); //выставляем последнее число будущего месяца Calculator calculator = new Calculator(); calculator.setExecutingTime( dt ); calculator.setPreCalc(); calculator.initTask( setup1, 0, "mid=" + npayMid ); //здесь можно прописывать только конкретные услуги через service.set=<наборы через запятую> calculator.setCids( cids.toString() ); calculator.startTask(); //после обсчета получаем список наработок с разбивкой по договорам Map<Integer, BigDecimal> planAccountMap = new HashMap<Integer, BigDecimal>(); if( !calculator.isCalcErrors() ) { planAccountMap = calculator.getCostCache().getContractAccounts(); } log( "Подсчет наработки закончен. Формирование документов" ); //ок, теперь нужно формировать документы int mm = dt.get(Calendar.MONTH); int yy = dt.get(Calendar.YEAR); log("Дата формирования счетов: " + TimeUtils.format( new Date(), TimeUtils.DATE_FORMAT_PATTERN_DDMMYYYY_HHMMSS ) ); log("Старт генерации документов за год=" + yy + "; месяц=" + mm + "; группы договоров=" + groups); BalanceUtils bu = new BalanceUtils( con ); ModuleSetup moduleSetup = setup1.getModuleSetup( billMid ); TemplateBillManager man = new TemplateBillManager( moduleSetup, con, billMid, false ); List<TemplateBill> templateBillList = man.getTemplatePayBillList( moduleSetup, yy, mm, groups, null, docType, null, false ); log("Число сгенерированных документов = " + templateBillList.size()); DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element bills = doc.createElement("bills"); for( TemplateBill templateBill : templateBillList ) { Element row = XMLUtils.createElement(bills, "bill"); row.setAttribute( "rest", Utils.formatBigDecimalSumm( bu.getBalance( dt.getTime(), templateBill.getContractId() ) ) ); row.setAttribute( "account_id",String.valueOf(accountId )); //Получаем наработку за будущий месяц по договору, если она есть BigDecimal summ = Utils.maskNull( planAccountMap.get( templateBill.getContractId() ) ); fillBillData( row, templateBill, summ ); } doc.appendChild(bills); ByteArrayOutputStream sos = new ByteArrayOutputStream(); XMLUtils.serialize(bills, sos, "UTF-8"); String xml = sos.toString(); log("Полученная сгенерированная xml со счетами: " + xml ); InputStream is = new ByteArrayInputStream( xml.getBytes( "cp1251" ) ); BillManager pbm = new BillManager( setup1, con, billMid, moduleSetup ); pbm.addBillDocs( userId, is, yy, mm, dt.getTime(), false ); } private void fillBillData( Element row, TemplateBill templateBill, BigDecimal billSumm ) { row.setAttribute( "id", String.valueOf( templateBill.getContractDocTypeId() ) ); row.setAttribute( "type", String.valueOf( templateBill.getDocTypeId() ) ); row.setAttribute( "cid", String.valueOf( templateBill.getContractId() ) ); row.setAttribute( "contract", templateBill.getContractTitle() ); row.setAttribute( "contract_comment", templateBill.getContractComment() ); for( PositionValue value : templateBill.getPositionList() ) { value.setSumma( billSumm ); value.setSumScaled( billSumm ); value.setSumUnscaled( billSumm ); Element posEl = XMLUtils.createElement( row, "pos" ); value.toElement( posEl ); Position pos = value.getPosition(); posEl.setAttribute( "insum", Utils.booleanToStringInt( pos.isInSum() ) ); posEl.setAttribute( "awlz", Utils.booleanToStringInt( pos.isAddWhenLessZero() ) ); } //предполагается, что на догоовре одна абонка. в итоге получим лишь одну позицию row.setAttribute( "summ", Utils.formatBigDecimalSumm( billSumm ) ); } /** * Вывод сообщений и в лог-файл и в клиентский лог. * @param msg текст сообщения. */ private void log( String msg ) { print( msg ); logger.info( msg ); } }
Выставление по каждой услуги на договоре отдельно
package ru.skyb.scripts.global; import bitel.billing.common.TimeUtils; import ru.bitel.bgbilling.kernel.script.server.dev.GlobalScriptBase; import ru.bitel.bgbilling.server.util.ModuleSetup; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.sql.ConnectionSet; import ru.bitel.common.Utils; import ru.bitel.common.XMLUtils; import ru.bitel.bgbilling.modules.npay.server.Calculator; import bitel.billing.server.bill.bean.*; import bitel.billing.server.contract.bean.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.math.*; import java.sql.*; import java.util.*; import java.util.Date; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.log4j.Logger; public class BillGen extends GlobalScriptBase { private static final Logger logger = Logger.getLogger( BillGen.class ); @Override public void execute( Setup setup1, ConnectionSet connectionSet2 ) throws Exception { log( "Инициализация" ); //переменные int npayMid = 8; //код модуля Npay String groups = "6"; //коды групп договоров через запятую Connection con = connectionSet2.getConnection(); //соединение с БД int billMid = 9; // код модуля Бухгалтерии int accountId = 1; // код счета банка String docType = "1"; // ID типа выставляемого документа int userId = 0; // ID пользователя, от имени которого выставляется счет //получаем список договоров, для которых будем выставлять счета log( "Получение списка договоров" ); StringBuilder cids = new StringBuilder(); StringBuilder query = new StringBuilder( "SELECT id FROM contract" ); long groupMask = Utils.enumToMask( groups ); if( groupMask > 0 ) { query.append( " WHERE gr&?>0" ); } PreparedStatement ps = con.prepareStatement( query.toString() ); if( groupMask > 0 ) { ps.setLong( 1, groupMask ); } ResultSet rs = ps.executeQuery(); while( rs.next() ) { cids.append( rs.getInt( "id" ) + "," ); } rs.close(); ps.close(); cids.deleteCharAt( cids.lastIndexOf( "," ) ); log( "Получено " + cids.toString().split( "," ).length + " договоров, которым необходимо выставить авансовые счета" ); //запускаем калькулятор по всем договорам, полученным выше log( "Запуск предначисления наработки для выбранных договоров" ); Calendar dt = new GregorianCalendar(); dt.add( Calendar.MONTH, 1 ); //нам нужно, чтобы считался будущий месяц dt.set( Calendar.DAY_OF_MONTH, dt.getActualMaximum( Calendar.DAY_OF_MONTH ) ); //выставляем последнее число будущего месяца Calculator calculator = new Calculator(); calculator.setExecutingTime( dt ); calculator.setPreCalc(); calculator.initTask( setup1, 0, "mid=" + npayMid ); //здесь можно прописывать только конкретные услуги через service.set=<наборы через запятую> calculator.setCids( cids.toString() ); calculator.startTask(); //после обсчета получаем список наработок с разбивкой по договорам Map<Integer, BigDecimal> planAccountMap = new HashMap<Integer, BigDecimal>(); if( !calculator.isCalcErrors() ) { planAccountMap = calculator.getCostCache().getContractAccounts(); print("planAccountMap " + planAccountMap); } Collection<CostSum> costSumList = calculator.getCostCache().getAmounts(); log( "Подсчет наработки закончен. Формирование документов" ); //for( CostSum costSum : calculator.getCostCache().getAmounts() ) //{ // log ("CostSum " +costSum.cost.abs()); //} //ок, теперь нужно формировать документы //dt.add( Calendar.MONTH, -1 ); int mm = dt.get(Calendar.MONTH); int yy = dt.get(Calendar.YEAR); log("Дата формирования счетов: " + TimeUtils.format( new Date(), TimeUtils.DATE_FORMAT_PATTERN_DDMMYYYY_HHMMSS ) ); log("Старт генерации документов за год=" + yy + "; месяц=" + mm + "; группы договоров=" + groups); BalanceUtils bu = new BalanceUtils( con ); ModuleSetup moduleSetup = setup1.getModuleSetup( billMid ); TemplateBillManager man = new TemplateBillManager( moduleSetup, con, billMid, false ); List<TemplateBill> templateBillList = man.getTemplatePayBillList( moduleSetup, yy, mm, groups, null, docType, null, false ); log("Число сгенерированных документов = " + templateBillList.size()); DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element bills = doc.createElement("bills"); for( TemplateBill templateBill : templateBillList ) { //if(templateBill.getContractId() == costSum.cid) //{ Element row = XMLUtils.createElement(bills, "bill"); row.setAttribute( "rest", Utils.formatBigDecimalSumm( bu.getBalance( dt.getTime(), templateBill.getContractId() ) ) ); row.setAttribute( "account_id",String.valueOf(accountId )); log("Получаем наработку за будущий месяц по договору, если она есть"); BigDecimal summ = Utils.maskNull( planAccountMap.get( templateBill.getContractId() ) ); fillBillData( row, templateBill, summ, costSumList, con ); //} } doc.appendChild(bills); ByteArrayOutputStream sos = new ByteArrayOutputStream(); XMLUtils.serialize(bills, sos, "UTF-8"); String xml = sos.toString(); log("Полученная сгенерированная xml со счетами: " + xml ); InputStream is = new ByteArrayInputStream( xml.getBytes( "cp1251" ) ); BillManager pbm = new BillManager( setup1, con, billMid, moduleSetup ); pbm.addBillDocs( userId, is, yy, mm, dt.getTime(), false ); //} } private void fillBillData( Element row, TemplateBill templateBill, BigDecimal billSumm, Collection<CostSum> costSumList, Connection con ) throws SQLException { List<PositionValue> valList = new ArrayList<PositionValue>(); BigDecimal totalSum = BigDecimal.ZERO; for( CostSum costSum : costSumList ) { if(templateBill.getContractId() == costSum.cid) { row.setAttribute( "id", String.valueOf( templateBill.getContractDocTypeId() ) ); row.setAttribute( "type", String.valueOf( templateBill.getDocTypeId() ) ); //row.setAttribute( "cid", String.valueOf( templateBill.getContractId() ) ); row.setAttribute( "cid", String.valueOf( costSum.cid ) ); row.setAttribute( "contract", templateBill.getContractTitle() ); row.setAttribute( "contract_comment", templateBill.getContractComment() ); String query = " select title from service where id = " + costSum.sid ; PreparedStatement contractPs = con.prepareStatement( query ); ResultSet contractRs = contractPs.executeQuery(); while ( contractRs.next() ) { String title = contractRs.getString( 1 ); log("title " + title + " costSum.cid " + costSum.cid ); PositionValue value = new PositionValue(); value.setSumma( costSum.cost.abs() ); value.setSumScaled( costSum.cost.abs() ); value.setSumUnscaled( costSum.cost.abs() ); value.setName(title); totalSum = totalSum.add( costSum.cost ); Element posEl = XMLUtils.createElement( row, "pos" ); value.toElement( posEl ); } contractRs.close(); contractPs.close(); } templateBill.setPositionList(valList); row.setAttribute( "summ", Utils.formatBigDecimalSumm( totalSum.abs() ) ); } } /** * Вывод сообщений и в лог-файл и в клиентский лог. * @param msg текст сообщения. */ private void log( String msg ) { print( msg ); logger.info( msg ); } }