Изменение параметров договора из личного кабинета
Материал из BiTel WiKi
DDPaul (Обсуждение | вклад) |
DDPaul (Обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
<b>Определение нужных параметров.</b> | <b>Определение нужных параметров.</b> | ||
- | + | Сначала нужно создать параметры - в справочнике «Параметры договоров». Для обращения к ним из скриптов и action'а достаточно знать код параметра (pid). Однако, для удобства, решено было использовать мнемонические обозначения параметров, попросту говоря, имена. | |
Связь (map) между кодом параметра и именем задается в конфигурации биллинга. Нам будут нужны следующие map'ы (в скобках - префикс): | Связь (map) между кодом параметра и именем задается в конфигурации биллинга. Нам будут нужны следующие map'ы (в скобках - префикс): | ||
Строка 81: | Строка 81: | ||
</source> | </source> | ||
- | + | 3. Создать обработчик для события "Измененен параметр договора". | |
+ | |||
<source lang="java"> | <source lang="java"> | ||
import ru.bitel.bgbilling.server.util.Setup; | import ru.bitel.bgbilling.server.util.Setup; | ||
Строка 87: | Строка 88: | ||
import bitel.billing.server.util.MailMsg; | import bitel.billing.server.util.MailMsg; | ||
- | // | + | // Получатель email'а |
emailAddr = "my@email.com"; | emailAddr = "my@email.com"; | ||
Строка 99: | Строка 100: | ||
//print( "cid: " + cid + ", pid: " + pid + ", paramValue: " + paramValue + ", paramName: " + paramName ); | //print( "cid: " + cid + ", pid: " + pid + ", paramValue: " + paramValue + ", paramName: " + paramName ); | ||
- | // Если измененный параметр есть в массиве paramNames, то провести процедуру коррекции | + | // Если измененный параметр есть в массиве paramNames, то провести процедуру коррекции и отправить письмо |
- | + | ||
if( paramName != null ) | if( paramName != null ) | ||
{ | { | ||
Строка 130: | Строка 130: | ||
# По результатам выполнения заполнить XML-отчет, который пригодится для отображения результатов в ЛК. | # По результатам выполнения заполнить XML-отчет, который пригодится для отображения результатов в ЛК. | ||
+ | <source lang="java"> | ||
+ | package bitel.billing.server.contract; | ||
+ | |||
+ | import java.sql.SQLException; | ||
+ | import java.util.List; | ||
+ | import java.util.HashMap; | ||
+ | import java.util.Iterator; | ||
+ | import java.security.AccessController; | ||
+ | import javax.security.auth.Subject; | ||
+ | import org.w3c.dom.Element; | ||
+ | import bitel.billing.server.admin.bean.User; | ||
+ | import bitel.billing.server.admin.bgsecure.bean.UserLoginModule.UserPrincipal; | ||
+ | import bitel.billing.server.contract.bean.*; | ||
+ | import bitel.billing.server.script.bean.event.*; | ||
+ | import bitel.billing.server.contract.action.ActionBase; | ||
+ | import ru.bitel.bgbilling.server.util.Setup; | ||
+ | |||
+ | public class WebAction_AdditionalParams extends ActionBase | ||
+ | { | ||
+ | @Override | ||
+ | public void doAction() | ||
+ | throws SQLException | ||
+ | { | ||
+ | // Object request holds all information about HTTP-request | ||
+ | request.getSession(); | ||
+ | |||
+ | // Get customer ID | ||
+ | Subject subject = Subject.getSubject( AccessController.getContext() ); | ||
+ | if( subject != null ) | ||
+ | { | ||
+ | for( UserPrincipal userPrincipal : subject.getPrincipals( UserPrincipal.class ) ) | ||
+ | { | ||
+ | User currentUser = userPrincipal.getUser(); | ||
+ | Integer cid = currentUser.getID(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if( cid != 0 ) | ||
+ | { | ||
+ | Setup setup = Setup.getSetup(); | ||
+ | ContractParameterManager cpm = new ContractParameterManager( con ); | ||
+ | Integer pid = 0; | ||
+ | Integer reportIsNeeded = 0; | ||
+ | Element report = createElement( rootNode, "report" ); | ||
+ | Element element; | ||
+ | |||
+ | // Get parameter IDs and descriptions from BGBilling configuration | ||
+ | HashMap<String,String> pids = (HashMap<String,String>) setup.getHashValuesWithPrefix( "maestro.pid." ); | ||
+ | HashMap<String,String> descriptions = (HashMap<String,String>) setup.getHashValuesWithPrefix( "maestro.desc." ); | ||
+ | |||
+ | // Cycle through parameters set | ||
+ | Iterator iterator = pids.keySet().iterator(); | ||
+ | while( iterator. hasNext() ) | ||
+ | { | ||
+ | String paramName = String.valueOf( iterator.next() ); | ||
+ | String paramDesc = descriptions.get( paramName ); | ||
+ | String paramValue = request.getParameter( paramName ); | ||
+ | String oldParamValue; | ||
+ | String errorBefore = ""; | ||
+ | ContractEmailParamValue emailParam = null; | ||
+ | ContractParamBeforeChangeEvent eventBefore = null; | ||
+ | ContractParamChangedEvent event = null; | ||
+ | |||
+ | // If value from POST-request exists | ||
+ | if( paramValue != null ) | ||
+ | { | ||
+ | pid = Integer.parseInt( pids.get( paramName )); | ||
+ | |||
+ | // Get old value (email parameter needs special handling) | ||
+ | if( paramName.equals( "email" )) { | ||
+ | emailParam = cpm.getEmailParam( cid, pid ); | ||
+ | oldParamValue = emailParam.getEmail(); | ||
+ | } else { | ||
+ | oldParamValue = cpm.getStringParam( cid, pid ); | ||
+ | } | ||
+ | |||
+ | // If value has been changed (from LK) then ... | ||
+ | if( !paramValue.equals( oldParamValue )) | ||
+ | { | ||
+ | // Prepare new value to parameter and set "before change" event (email parameter needs special handling) | ||
+ | if( paramName.equals( "email" )) { | ||
+ | emailParam.setEmail( paramValue ); | ||
+ | emailParam.setEmailId( 1 ); | ||
+ | eventBefore = new ContractParamBeforeChangeEvent( cid, pid, emailParam ); | ||
+ | } else { | ||
+ | eventBefore = new ContractParamBeforeChangeEvent( cid, pid, paramValue ); | ||
+ | } | ||
+ | |||
+ | if( eventBefore != null ) | ||
+ | { | ||
+ | // Create "row" element for XML report | ||
+ | element = createElement( report, "row" ); | ||
+ | element.setAttribute( "parameter", paramDesc ); | ||
+ | |||
+ | // Throw "before change" event to handler (BGBilling server) and get error message | ||
+ | EventProcessor.getProcessor().processEvent( eventBefore ); | ||
+ | errorBefore = eventBefore.getError(); | ||
+ | |||
+ | if( errorBefore == null ) | ||
+ | { | ||
+ | // If handler returns "ok" then set new parameter value and set "parameter changed" event | ||
+ | if( paramName.equals( "email" )) { | ||
+ | cpm.setEmailParam( cid, pid, emailParam, false, 1 ); | ||
+ | event = new ContractParamChangedEvent( cid, pid, emailParam ); | ||
+ | } else { | ||
+ | cpm.setStringParam( cid, pid, paramValue, 1 ); | ||
+ | event = new ContractParamChangedEvent( cid, pid, paramValue ); | ||
+ | } | ||
+ | |||
+ | if( event != null ) | ||
+ | { | ||
+ | // Throw "parameter changed" event and set attributes for XML report | ||
+ | EventProcessor.getProcessor().addEvent( event ); | ||
+ | element.setAttribute( "status", "ok" ); | ||
+ | element.setAttribute( "value", String.valueOf( paramValue )); | ||
+ | reportIsNeeded = 1; | ||
+ | } | ||
+ | } else { | ||
+ | // If handler returns error then set attributes for XML report only | ||
+ | element.setAttribute( "status", "error" ); | ||
+ | element.setAttribute( "value", String.valueOf( errorBefore )); | ||
+ | reportIsNeeded = 1; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Renew XML element with contract parameters and set status variable for Web | ||
+ | if( reportIsNeeded == 1 ) | ||
+ | { | ||
+ | request.getSession().removeAttribute( "contract_data" ); | ||
+ | rootNode.setAttribute("status","ok"); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
- | |||
<b>Шаблон личного кабинета.</b> | <b>Шаблон личного кабинета.</b> | ||
- | Внести необходимые изменения в шаблон ЛК, а именно, | + | Внести необходимые изменения в шаблон ЛК, а именно, common.xsl: |
+ | <source lang="java"> | ||
+ | ... | ||
+ | <!-- Дополнительные параметры договора --> | ||
+ | <xsl:variable name="email" select="/data/contract_data/parameters/parameter[@pid='19']/@value"/> | ||
+ | <xsl:variable name="login" select="/data/contract_data/parameters/parameter[@pid='33']/@value"/> | ||
+ | |||
+ | <!-- Шаблон меню --> | ||
+ | <xsl:template name="standart_menu"> | ||
+ | <tr> | ||
+ | <th><img src="img/strelki.gif"/></th> | ||
+ | <td><a href="?">Новости</a></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <th><img src="img/strelki.gif"/></th> | ||
+ | <td><a href="?action=AdditionalParams&mid=contract">Доп. параметры</a></td> | ||
+ | </tr> | ||
+ | ... | ||
+ | </source> | ||
+ | |||
+ | и main.xsl: | ||
+ | <source lang="java"> | ||
+ | ... | ||
+ | <xsl:template name="title"> | ||
+ | <xsl:choose> | ||
+ | ... | ||
+ | <xsl:when test="data/@action = 'AdditionalParams'">Дополнительные параметры</xsl:when> | ||
+ | ... | ||
+ | <xsl:otherwise>НОВОСТИ</xsl:otherwise> | ||
+ | </xsl:choose> | ||
+ | </xsl:template> | ||
+ | |||
+ | <xsl:template match="/data"> | ||
+ | <xsl:choose> | ||
+ | ... | ||
+ | <xsl:when test="@action = 'AdditionalParams'"> | ||
+ | <xsl:call-template name="AdditionalParams"/> | ||
+ | </xsl:when> | ||
+ | ... | ||
+ | </xsl:choose> | ||
+ | </xsl:template> | ||
+ | |||
+ | <!-- Дополнительные параметры --> | ||
+ | <xsl:template name="AdditionalParams"> | ||
+ | |||
+ | <form method='post' action='{$WEBEXECUTER}'> | ||
+ | <xsl:call-template name="action"/> | ||
+ | <xsl:call-template name="error"/> | ||
+ | <input type="hidden" name="command" value="change"/> | ||
+ | <xsl:if test="@status = 'ok'"> | ||
+ | <div class="infoMessage"> | ||
+ | <xsl:for-each select="/data/report/row"> | ||
+ | <xsl:if test="@status = 'ok'"> | ||
+ | <xsl:value-of select="@parameter" /> изменен на <xsl:value-of select="@value" /><br /> | ||
+ | </xsl:if> | ||
+ | <xsl:if test="@status = 'error'"> | ||
+ | При изменении "<xsl:value-of select="@parameter" />" произошла ошибка: <xsl:value-of select="@value" /><br /> | ||
+ | </xsl:if> | ||
+ | </xsl:for-each> | ||
+ | </div> | ||
+ | </xsl:if> | ||
+ | |||
+ | <div class="report"> | ||
+ | <table cellspacing='1' id="idTableChangePassword"> | ||
+ | <col class="col1"/> | ||
+ | <col class="col2"/> | ||
+ | <tbody> | ||
+ | <tr> | ||
+ | <th>Email:</th> | ||
+ | <td><input type="text" name="email" value="{$email}" size="30" maxlength="100"/></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <th>Логин:</th> | ||
+ | <td><input type="text" name="login" value="{$login}" size="30" maxlength="20"/></td> | ||
+ | </tr> | ||
+ | </tbody> | ||
+ | <tfoot> | ||
+ | <tr><td colspan='2'> | ||
+ | <xsl:call-template name="submit"> | ||
+ | <xsl:with-param name="title" select="'Сохранить'"/> | ||
+ | </xsl:call-template> | ||
+ | </td></tr> | ||
+ | </tfoot> | ||
+ | </table> | ||
+ | </div> | ||
+ | </form> | ||
+ | </xsl:template> | ||
+ | </source> |
Версия 10:52, 16 февраля 2010
Определение нужных параметров.
Сначала нужно создать параметры - в справочнике «Параметры договоров». Для обращения к ним из скриптов и action'а достаточно знать код параметра (pid). Однако, для удобства, решено было использовать мнемонические обозначения параметров, попросту говоря, имена.
Связь (map) между кодом параметра и именем задается в конфигурации биллинга. Нам будут нужны следующие map'ы (в скобках - префикс):
- по имени параметра, полученного из объекта request (т.е. из POST-запроса) определить его код (pid);
- по имени параметра определить его описание, которое будет отображаться в личном кабинете (desc);
- по коду параметра определить его имя - для обработки событий и отсылки сообщения (name).
Для того, чтобы имена наших переменных не пересекались с другими (стандартными) параметрами конфигурации BGBilling, разумно использовать префикс, например, название компании.
# Имя параметра -> ID параметра my.pid.email=19 my.pid.login=33 # # Имя параметра -> Описание параметра my.desc.email=Email my.desc.login=Логин # # ID параметра -> Имя параметра my.name.19=email my.name.33=login
Обработка событий в BGBilling.
Введенные пользователем данные необходимо проверить - провести валидацию. В моем случае - еще и отослать email с уведомлением об изменении. В принципе, эти действия можно выполнить в теле action'а, но грамотнее будет воспользоваться механизмом обработки событий BGBilling'а. В этом случае значения параметров будут проверяться и обрабатываться как при изменении пользователем через личный кабинет, так и администратором/оператором через клиент BGBilling.
- Создать новый скрипт поведения "Параметры".
- Создать обработчик для события "Перед изменением параметра договора" (как в Валидация текстового параметра)
import ru.bitel.bgbilling.server.util.Setup; import bitel.billing.server.contract.bean.*; import java.util.*; // Соответствие ID параметра договора и ключевого слова, обозначающего этот параметр paramNames = Setup.getSetup().getHashValuesWithPrefix( "my.name." ); cid = event.getContractID(); pid = event.getParamId(); paramValue = event.getValue(); paramName = paramNames.get( String.valueOf( pid )); //print( "cid: " + cid + ", pid: " + pid + ", paramValue: " + paramValue + ", paramName: " + paramName ); if( paramName != null ) { // Проверка значения параметра типа Email if( paramName.equals( "email" )) { // Email - http://regexlib.com/REDetails.aspx?regexp_id=21 // Выражение расширено для проверки списка адресов, разделенных ";" и опциональными пробелами REGEX = "^([\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}(\\n|;\\s*|))+$"; paramValue = paramValue.getEmail(); if( !paramValue.matches( REGEX )) { event.setError( "Неверный формат Email" ); return; } } // Проверка значения для телефонного номера if( paramName.equals( "vfaxnumber" )) { // Телефонный номер - (495) 44-2221-1 REGEX1 = "^\\(\\d+\\)\\s*[\\d\\-]+$"; // Телефонный номер - 8-903-44-2221-1 или 890311 REGEX2 = "^\\d[\\d\\-]+$"; // Телефонный номер - +79034422211 REGEX3 = "^\\+\\d+$"; if( !paramValue.matches(REGEX1) && !paramValue.matches(REGEX2) && !paramValue.matches(REGEX3) ) { event.setError( "Неверный формат телефонного номера" ); return; } } }
3. Создать обработчик для события "Измененен параметр договора".
import ru.bitel.bgbilling.server.util.Setup; import bitel.billing.server.contract.bean.*; import bitel.billing.server.util.MailMsg; // Получатель email'а emailAddr = "my@email.com"; // Соответствие ID параметра договора и ключевого слова, обозначающего этот параметр paramNames = Setup.getSetup().getHashValuesWithPrefix( "my.name." ); cid = event.getContractID(); pid = event.getParamId(); paramValue = event.getValue(); paramName = paramNames.get( String.valueOf( pid )); //print( "cid: " + cid + ", pid: " + pid + ", paramValue: " + paramValue + ", paramName: " + paramName ); // Если измененный параметр есть в массиве paramNames, то провести процедуру коррекции и отправить письмо if( paramName != null ) { // Обработка значение параметра типа Email // При изменении через клиент BGBilling'а адреса разделяются "\n" if( paramName.equals( "email" )) { paramValue = paramValue.getEmail(); paramValue = paramValue.replaceAll( "\n", "; "); } // Отправка письма, текст сообщения - "параметр:значение" if( paramValue != null ) { txt = paramName + ":" + paramValue + "\n"; cpm = new ContractParameterManager( con ); recp = emailAddr; new MailMsg( setup ).sendMessage( recp, "Parameters changed", txt ); } }
Action.
Алгоритм работы action'а:
- Определить ID клиента (см. Получение текущего пользователя биллинга).
- Просканировать список всех параметров, и, если, было задано новое значение (через POST-запрос), то:
- Сгенерировать событие ContractParamBeforeChangeEvent - для валидации параметра.
- Если параметр прошел валидацию, то установить новое значение и сгенеририровать событие ContractParamChangedEvent (для выполнения нужных действий с новым значением параметра)
- По результатам выполнения заполнить XML-отчет, который пригодится для отображения результатов в ЛК.
package bitel.billing.server.contract; import java.sql.SQLException; import java.util.List; import java.util.HashMap; import java.util.Iterator; import java.security.AccessController; import javax.security.auth.Subject; import org.w3c.dom.Element; import bitel.billing.server.admin.bean.User; import bitel.billing.server.admin.bgsecure.bean.UserLoginModule.UserPrincipal; import bitel.billing.server.contract.bean.*; import bitel.billing.server.script.bean.event.*; import bitel.billing.server.contract.action.ActionBase; import ru.bitel.bgbilling.server.util.Setup; public class WebAction_AdditionalParams extends ActionBase { @Override public void doAction() throws SQLException { // Object request holds all information about HTTP-request request.getSession(); // Get customer ID Subject subject = Subject.getSubject( AccessController.getContext() ); if( subject != null ) { for( UserPrincipal userPrincipal : subject.getPrincipals( UserPrincipal.class ) ) { User currentUser = userPrincipal.getUser(); Integer cid = currentUser.getID(); } } if( cid != 0 ) { Setup setup = Setup.getSetup(); ContractParameterManager cpm = new ContractParameterManager( con ); Integer pid = 0; Integer reportIsNeeded = 0; Element report = createElement( rootNode, "report" ); Element element; // Get parameter IDs and descriptions from BGBilling configuration HashMap<String,String> pids = (HashMap<String,String>) setup.getHashValuesWithPrefix( "maestro.pid." ); HashMap<String,String> descriptions = (HashMap<String,String>) setup.getHashValuesWithPrefix( "maestro.desc." ); // Cycle through parameters set Iterator iterator = pids.keySet().iterator(); while( iterator. hasNext() ) { String paramName = String.valueOf( iterator.next() ); String paramDesc = descriptions.get( paramName ); String paramValue = request.getParameter( paramName ); String oldParamValue; String errorBefore = ""; ContractEmailParamValue emailParam = null; ContractParamBeforeChangeEvent eventBefore = null; ContractParamChangedEvent event = null; // If value from POST-request exists if( paramValue != null ) { pid = Integer.parseInt( pids.get( paramName )); // Get old value (email parameter needs special handling) if( paramName.equals( "email" )) { emailParam = cpm.getEmailParam( cid, pid ); oldParamValue = emailParam.getEmail(); } else { oldParamValue = cpm.getStringParam( cid, pid ); } // If value has been changed (from LK) then ... if( !paramValue.equals( oldParamValue )) { // Prepare new value to parameter and set "before change" event (email parameter needs special handling) if( paramName.equals( "email" )) { emailParam.setEmail( paramValue ); emailParam.setEmailId( 1 ); eventBefore = new ContractParamBeforeChangeEvent( cid, pid, emailParam ); } else { eventBefore = new ContractParamBeforeChangeEvent( cid, pid, paramValue ); } if( eventBefore != null ) { // Create "row" element for XML report element = createElement( report, "row" ); element.setAttribute( "parameter", paramDesc ); // Throw "before change" event to handler (BGBilling server) and get error message EventProcessor.getProcessor().processEvent( eventBefore ); errorBefore = eventBefore.getError(); if( errorBefore == null ) { // If handler returns "ok" then set new parameter value and set "parameter changed" event if( paramName.equals( "email" )) { cpm.setEmailParam( cid, pid, emailParam, false, 1 ); event = new ContractParamChangedEvent( cid, pid, emailParam ); } else { cpm.setStringParam( cid, pid, paramValue, 1 ); event = new ContractParamChangedEvent( cid, pid, paramValue ); } if( event != null ) { // Throw "parameter changed" event and set attributes for XML report EventProcessor.getProcessor().addEvent( event ); element.setAttribute( "status", "ok" ); element.setAttribute( "value", String.valueOf( paramValue )); reportIsNeeded = 1; } } else { // If handler returns error then set attributes for XML report only element.setAttribute( "status", "error" ); element.setAttribute( "value", String.valueOf( errorBefore )); reportIsNeeded = 1; } } } } } // Renew XML element with contract parameters and set status variable for Web if( reportIsNeeded == 1 ) { request.getSession().removeAttribute( "contract_data" ); rootNode.setAttribute("status","ok"); } } } }
Шаблон личного кабинета.
Внести необходимые изменения в шаблон ЛК, а именно, common.xsl:
... <!-- Дополнительные параметры договора --> <xsl:variable name="email" select="/data/contract_data/parameters/parameter[@pid='19']/@value"/> <xsl:variable name="login" select="/data/contract_data/parameters/parameter[@pid='33']/@value"/> <!-- Шаблон меню --> <xsl:template name="standart_menu"> <tr> <th><img src="img/strelki.gif"/></th> <td><a href="?">Новости</a></td> </tr> <tr> <th><img src="img/strelki.gif"/></th> <td><a href="?action=AdditionalParams&mid=contract">Доп. параметры</a></td> </tr> ...
и main.xsl:
... <xsl:template name="title"> <xsl:choose> ... <xsl:when test="data/@action = 'AdditionalParams'">Дополнительные параметры</xsl:when> ... <xsl:otherwise>НОВОСТИ</xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/data"> <xsl:choose> ... <xsl:when test="@action = 'AdditionalParams'"> <xsl:call-template name="AdditionalParams"/> </xsl:when> ... </xsl:choose> </xsl:template> <!-- Дополнительные параметры --> <xsl:template name="AdditionalParams"> <form method='post' action='{$WEBEXECUTER}'> <xsl:call-template name="action"/> <xsl:call-template name="error"/> <input type="hidden" name="command" value="change"/> <xsl:if test="@status = 'ok'"> <div class="infoMessage"> <xsl:for-each select="/data/report/row"> <xsl:if test="@status = 'ok'"> <xsl:value-of select="@parameter" /> изменен на <xsl:value-of select="@value" /><br /> </xsl:if> <xsl:if test="@status = 'error'"> При изменении "<xsl:value-of select="@parameter" />" произошла ошибка: <xsl:value-of select="@value" /><br /> </xsl:if> </xsl:for-each> </div> </xsl:if> <div class="report"> <table cellspacing='1' id="idTableChangePassword"> <col class="col1"/> <col class="col2"/> <tbody> <tr> <th>Email:</th> <td><input type="text" name="email" value="{$email}" size="30" maxlength="100"/></td> </tr> <tr> <th>Логин:</th> <td><input type="text" name="login" value="{$login}" size="30" maxlength="20"/></td> </tr> </tbody> <tfoot> <tr><td colspan='2'> <xsl:call-template name="submit"> <xsl:with-param name="title" select="'Сохранить'"/> </xsl:call-template> </td></tr> </tfoot> </table> </div> </form> </xsl:template>