Дерево страниц

Сравнение версий

Ключ

  • Эта строка добавлена.
  • Эта строка удалена.
  • Изменено форматирование.

...

Scroll Ignore

Оглавление
printablefalse

Отображение дочерних

Обновление личного кабинета

Для обновления личного кабинета запустите скрипт mybgbilling-update.sh:

Блок кода
languageruby
/opt/wildfly/standalone/deployments/MyBGBilling.war/WEB-INF/script/update_libs.sh

При обновлении файлы, рядом с которыми есть файл с таким же именем плюс суффикс(расширение) .orig, не будут перезаписаны файлом из сборки, вместо них обновяться .orig-файлы (см. Кастомизация личного кабинета). Также при обновлении полностью удаляется и перезаписывается директория MyBGBilling.war/WEB-INF/classes/ru/bitel.

Путь к контексту ЛК

Путь к контексту личного кабинета можно изменить в файле wildfly/standalone/deployments/MyBGBilling.war/WEB-INF/jboss-web.xml:

Блок кода
languagexml
<!-- https://provider.ru/my -->
<context-root>/my</context-root>

Например, чтобы ЛК открывался от корня:

Блок кода
languagexml
<!-- https://my.provider.ru/ -->
<context-root>/</context-root>
Примечание

При использовании NGINX необходимо, чтобы путь к контексту был одинаковым в NGINX и в самом ЛК.

Восстановление пароля

При нажатии кнопки восстановления пароля через email пользователю в письме приходит ссылка, которая настраивается параметром конфигурации contract.password.forgot.link. Укажите в нем правильный путь до страницы index.xhml (вместо webexecuter):

Блок кода
contract.password.forgot.link=http://provider.ru/my/index.xhtml?action=ChangePassword&mid=contract

Описание синтаксиса файлов конфигурации groovy

Группы параметров в конфиге разделяются не точкой, а с помощью вложенных блоков. Значение параметра должно быть правильным Groovy/Java-объектом - в простом случае строкой, заключенной в одинарные или двойные кавычки, или числом, например:

...

  • isCustomer() или isUserInRole('customer') - возвращает true, если в режиме аутентификации, которым воспользовался абонент, не указан параметр role = 'unauthCustomer';
  • contractInGroup( contract, groupIds ) - возвращает true, если переданный в первый аргумент объект-contract содержит в себе одну из групп, указанных списке второго аргумента, например: contractInGroup( contract, [2, 3, 8, 13] ).

Основная конфигурация (mybgbilling-conf.groovy)

Основная конфигурация личного кабинета состоит из нескольких блоков:

  • bgbilling - конфигурация подключения к BGBillingServer,
  • authentication - параметры аутентификации абонента,
  • mail - параметры почтовой подсистемы (чтобы ЛК мог отправлять письма при необходимости),
  • content - параметры содержимого страниц.

Конфигурация подключения к BGBillingServer

Блок кода
languagescala
// Параметры подключения к BGBillingServer.
// ЛК является пользователем биллинга, общается с ним также, как BGBillingClient
bgbilling {
    // URL доступа к BGBilling
    url = 'http://127.0.0.1:8080/bgbilling/executer'
    // Логин
    user = 'customer'
    // Пароль
    password = '123456'
}

Параметры идентификации HTTP-соединения

Личному кабинету в некоторых случаях требуется знать базовый URL, по которому абоненты получают доступ к нему. Личный кабинет биллинга может получить это значение из запроса, однако при использовании NGINX значение из запроса может быть не правильным. Поэтому базовый URL следует указать в конфигурации в параметре baseUrl.

Также личному кабинету требуется знать IP-адрес абонента, который пользуется им в текущий момент (например, для авторизации по IP-адресу или блокировке при переборе логинов/паролей). Поэтому при использовании NGINX требуется указать HTTP-заголовок в параметре context.hostHttpRequestHeader, из которого получать реальный IP-адрес вместо физического IP-адреса HTTP-соединения.

Блок кода
languagescala
context {
	
    // Базовый адрес сервера (через который абоненты получают доступ к ЛК). По умолчанию используется значение из запроса
    //baseUrl = 'https://provider.ru/selfcare'
    baseUrl = 'https://my.provider.ru'
    
    // Идентификатор хоста по HTTP-заголовку, например, X-Real-IP. По умолчанию используется IP-адрес хоста
    hostHttpRequestHeader = 'X-Real-IP'
}

Параметры аутентификации абонента

Блок кода
languagescala
// Параметры аутентификации абонента
authentication {
    // Кол-во ошибок аутентификации, после которого будет отображаться captcha для этого логина
    captchaLoginErrorCount = 5
    // Кол-во ошибок аутентификации, после которого будет отображаться captcha для хоста
    captchaHostErrorCount = 20
    // Кол-во ошибок аутентификации, после которых будут заблокированы попытки этого хоста
    blockHostErrorCount = 30
    
    // Режимы аутентификации для входа в ЛК
    modes = [
		// аутентификация по номеру договора
    	authenticationMode {
 			mode = 'contract'
    	}
 	]
}

Режимов аутентификации может быть несколько - в этом случае в окне логина можно выбрать необходимый. На данный момент поддерживаются 6 режимов аутентификации:

  • по номеру договора:

    Блок кода
    languagescala
    authenticationMode {
    	mode = 'contract'
    }
  • по логину модуля Inet:

    Блок кода
    languagescala
    authenticationMode {
    	module = 'inet'
    	mode = 'login'
    	// ID модуля
    	moduleId = 1
    }
  • по IP-адресу сессии модуля Inet (вход без пароля):

    Блок кода
    languagescala
    authenticationMode {
    	module = 'inet'
    	mode = 'ip'
    	// ID модуля
    	moduleId = 1
    	// ограниченный доступ
    	role = 'unauthCustomer'
    }
  • по параметру договора "телефон":

    Блок кода
    languagescala
    authenticationMode {
    	module = 'kernel'
    	mode = 'phoneParam'
    	// ID параметра
    	parameterId = 1
    	// преобразование введенного номера договора
    	username = { s -> s.replaceAll( /^8(.+)$/,'7$1' ) }
    }
  • по параметру договора "Email":

    Блок кода
    languagescala
    authenticationMode {
    	module = 'kernel'
    	mode = 'emailParam'
    	// ID параметра
    	parameterId = 2
    	// преобразование введенного номера телефона
    	username = { s -> s.replaceAll( /^8(.+)$/,'7$1' ) }
    }
  • по текстовому параметру договора:

    Блок кода
    languagescala
    authenticationMode {
    	module = 'kernel'
    	mode = 'textParam'
    	// ID параметра
    	parameterId = 3
    }

При аутентификации по параметру договора в качестве пароля используется пароль к личному кабинету (как и при аутентификации номеру договора). При аутентификации по номеру телефона идет поиск только по введенным цифрам, при этом можно задать преобразование введенного номера в другой вид с помощью параметра username; если параметр username не указан, то по умолчанию 8 в начале строки заменяется на 7.

Для режима аутентификации можно назначить, чтобы доступ после аутентификации через него был ограничен. Для этого указывается параметр role = 'unauthCustomer'. В этом случае, вызов isUserInRole( "customer" ) будет возвращать false. Ограниченный доступ может быть указан, например, для режима аутентификации по IP-адресу модуля Inet.

Можно разрешить аутентификацию только для определенных групп договоров, указав условие в параметре filter:

Блок кода
languagescala
authenticationMode {
	module = 'inet'
	mode = 'ip'
	//ID модуля
	moduleId = 1
	// ограниченный доступ
	role = 'unauthCustomer'
    // фильтр по группам договоров
	filter = { contract -> contractInGroup( contract, [1, 2, 3, 4, 20] ) }
}

Или наоборот, запретить для определенных групп договоров:

Блок кода
languagescala
	filter = { contract -> !contractInGroup( contract, [1, 2, 3, 4, 20] ) }

Или разрешить по номеру договора:

Блок кода
languagescala
	filter = { contract -> contract.title.startsWith( "NK" ) }

Или использовать регулярное выражение:

Блок кода
languagescala
	filter = { contract -> contract.title.matches( "NK.*" ) }

Параметры почтовой подсистемы

Блок кода
languagescala
// Параметры SMTP, чтобы ЛК мог отправлять письма
mail {
	smtp {
		host = 'smtp.provider.ru'
	}
	
	from {
		email = 'support@provider.ru'
		name = 'BGBilling'
	}
}

Параметры содержимого страниц

Разрешенные фрагменты

Данный блок конфигурации позволяет настраивать, какие фрагменты страницы или какие действия доступны абонентам или группам абонентов. Например, в коде страницы статусов договора есть фрагмент смены статуса:

Блок кода
languagexml
<ui:fragment rendered="#{configuration.get('content.kernel.status.statusChange', true)}">
	...
</ui:fragment>

Соответственно можно в конфигурации запретить всем менять статус договора из личного кабинета:

Блок кода
languagescala
content {
	kernel {
		...
	
		// status.xhtml
		status {
			// возможность изменения статуса договора
			statusChange = false
		}
		
		...
	}
	
	...
}

Можно разрешить только тем, кто был аутентифицирован по логину/паролю (в конфигурации по умолчанию установлен этот вариант):

Блок кода
languagescala
statusChange = { isUserInRole( "customer" ) }

Разрешить только аутентифицированным по логину/паролю физ. лицам:

Блок кода
languagescala
statusChange = { contract -> isUserInRole( "customer" ) && contract.getPersonType() == 0 }

Или разрешить только аутентифицированным по логину/паролю определенным группам договоров:

Блок кода
languagescala
statusChange = { contract -> isUserInRole( "customer" ) && contractInGroup( contract, [1, 2, 3, 4, 20] ) }

Название контрагента в верхней части страницы

По умолчанию в шапке страницы название или имя контрагента не отображается. За отображение названия (или имени) отвечает параметр content.kernel.customerTitle. В конфигурации можно указать, чтобы отображался комментарий договора:

Блок кода
languagescala
content {
	kernel {
 
	// название контрагента, отображаемое на странице
	customerTitle = { contract, contractParameterMap -> contract.comment }
 
	...
}

Или же отобразить параметр договора, в зависимости от типа лица договора (физ. лицо или юр. лицо):

Блок кода
languagescala
content {
	kernel {

		// название контрагента, отображаемое на странице
		customerTitle = { contract, contractParameterMap ->

			// ID параметров договоров названия физ. лиц (для customerTitle)
			def individualCustomerTitleParamIds = [33, 0, 0, 0, 0];
			// ID параметров договоров названия юр. лиц (для customerTitle)
			def corporationCustomerParamIds = [10, 0, 0, 0, 0];

			def paramIds = contract.personType == 1 ? corporationCustomerParamIds : individualCustomerTitleParamIds;

			String result = contractParameterMap.values().stream()
				.filter{ v -> paramIds.contains( v.entitySpecAttrId ) && notBlankString( v.toString() ) }
				.findFirst()
				.map{ v -> v.toString() }
				.orElse( null );

			return result;
		}
 
		...
	}
	
	...
}

Группировка субдоговоров в меню

Если субдоговоров у данного договора меньше 10 - они отображаются прямо в меню. В этом случае можно сортировать и группировать список субдоговоров:

Блок кода
languagescala
content {
	kernel {

		// группировка субдоговоров (для меню)
		subContractGroup = { subContractList ->
		
			subContractList
			.stream()
			.sorted({ a,b -> a.title.compareTo(b.title) })
			.collect( Collectors.groupingBy{ contract ->

				// можно группировать субдоговора по группам договоров
				if( contractInGroup( contract, [1, 2, 3, 4, 20] ) ) {
					return "contract.sub.group.01.internet";
				}else if( contractInGroup( contract, [5, 6, 7, 8, 9] ) ) {
					return "contract.sub.group.02.phone";
				} else {
					return "contract.sub.group.99.other";
				}

				// если всем возвращать пустую строку - то группировки не будет
				return "";
			})
			.entrySet()
			.stream()
			.sorted({ a,b -> a.key.compareTo(b.key) })
			.collect( Collectors.toList() );
		}
 
		...
	}
 
	...
}

В примере при группировке используются строки вида "contract.sub.group.01.internet". Число в данном случае используется для сортировки групп, а само название группы должно быть прописано в Locale_ru_RU.properties по ключу:

Блок кода
languagescala
contract.sub.group.01.internet=Интернет
contract.sub.group.02.phone=Телефония
contract.sub.group.99.other=Другое

Конфигурация меню (mybgbilling-menu.groovy)

Данный файл конфигурации возвращает дерево пунктов меню для договора. Выглядит конфигурация, например, так:

Блок кода
languagescala
menu {
	// список пунктов верхнего уровня
	children = [
	
		// Новости
		menu( page: "kernel/news", icon: "fa-newspaper-o", title: "menu.news" ),
		
		// Уведомления + Рассылки
		menu( page: "kernel/notificationsEx", subPage: "notifications", icon: "fa-envelope-o", 
						title: "menu.notifications", badge: "#{notificationBean.getUnreadCount()}", badgeUpdate: "#{notificationBean.populate()}",
						show: isCustomer() ),
	
		// Уведомления (отдельно от рассылок)
		menu( page: "kernel/notifications", icon: "fa-envelope-o", title: "menu.notifications",
						show: !isCustomer() ),
							
		// Баланс
		menu( page: "kernel/balance", icon: "fa-rub", title: "menu.balance" ),
	
		// Лимит
		menu( page: "kernel/limit", icon: "fa-umbrella", title: "menu.limit" ),
		
		// Тарифные опции
		menu( page: "kernel/tariffOptions", icon: "fa-cogs", title: "menu.tariffOptions", show: isCustomer() ),

		// Договор
		menu( icon: "fa-briefcase", title: "menu.contract" ) {
				children = [
					// Статус
					menu( page: "kernel/status", title: "menu.status" ),
					// Тарифы
					menu( page: "kernel/tariffs", title: "menu.tariffs", show: isCustomer() ),
					// Действия
					menu( page: "kernel/additionalActions", title: "menu.additionalActions", show: isCustomer() ),
					// Документы
					menu( page: "kernel/documents", title: "menu.documents", show: isCustomer() ),
					// Документы (включены в предыдущий пункт)
					//menu( page: "plugins/documents/documents", title: "menu.documents" ),
					// Бухгалтерия
					menu( module: "bill", page: "modules/bill/bill", title: "menu.bill", show: isCustomer() ),
					// Примечания
					menu( page: "kernel/notes", title: "menu.notes", show: isCustomer() ),
					// Смена пароля
					menu( page: "kernel/password", title: "menu.password", show: isCustomer() )
				]
			},

		// Интернет
		menu( module:"inet", icon:"fa-globe", title:"menu.inet" ) {
				children = [
					// Сессии
					menu( page: "modules/inet/sessions", title: "menu.inet.sessions" ),
					// Трафик
					menu( page: "modules/inet/traffics", title: "menu.inet.traffics" ),
					// Смена пароля
					menu( page: "modules/inet/password", title: "menu.inet.password", show: isCustomer() )
				]
			},
			
		// ТВ
		menu( module:"tv", page:"modules/tv/tv", icon:"fa-tv", title:"menu.tv" ),
	
		// Поддержка
		menu( page: "plugins/helpdesk/helpdesk", icon: "fa-wrench", title: "menu.helpdesk",
							badge: "#{helpdeskBean.getUnreadTopicCount()}", badgeUpdate: "#{helpdeskBean.populateTopics()}",
							show: isCustomer() )
	
	]
}

У каждого объекта-пункта меню есть набор параметров:

  • module - модуль, если данный пункт относится к модулю, наследуется дочерними пунктами;
  • moduleId - ID модуля (необязательно, если указан module, то подставляется автоматически), наследуется дочерними пунктами. Можно использовать, если одинаковые модули нужно показывать по разному;
  • page - страница, без .xhtml;
  • subPage - подстраница;
  • icon - иконка;
  • title - название пункта меню (ключ для Locale.properties);
  • badge - счетчик, указывается JSF-вызов метода, который вернет число;
  • badgeUpdate - JSF-вызов метода, который нужно произвести для обновления счетчика
  • show - показывать пункт или нет (если не указан, то показывать)
  • children - список дочерних пунктов меню

Используя параметр show, можно ограничивать использование пунктов меню для групп договоров:

Блок кода
languagescala
 menu( moduleId: 210, page: "modules/tv/tv", icon: "fa-tv", title: "menu.tv",
							show: contractInGroup( contract, [1, 2, 3, 4, 20] ) )

При необходимости список дочерних пунктов меню можно определить как переменную и добавлять пункты в этот список, используя условия:

Блок кода
languagescala
 
menu {
	// список пунктов верхнего уровня
	def firstLevel = [];
	children = firstLevel;
	
	// Новости
	firstLevel << menu( page: "kernel/news", icon: "fa-newspaper-o", title: "menu.news" )
	
	// если авторизован по логину/паролю
	if( isCustomer() ) {
	
		// Уведомления + Рассылки
		firstLevel << menu( page: "kernel/notificationsEx", subPage: "notifications", icon: "fa-envelope-o", 
							title: "menu.notifications", badge: "#{notificationBean.getUnreadCount()}", badgeUpdate: "#{notificationBean.populate()}" )
	
	} else {
	
		// Уведомления
		firstLevel << menu( page: "kernel/notifications", subPage: "", icon: "fa-envelope-o", title: "menu.notifications" )
	
	}
	// Баланс
	firstLevel << menu( page: "kernel/balance", icon: "fa-rub", title: "menu.balance" )
	
	// если авторизован по логину/паролю
	if( isCustomer() ) {
	
		// Лимит
		firstLevel << menu( page: "kernel/limit", icon: "fa-umbrella", title: "menu.limit" )
		
		// Тарифные опции
		firstLevel << menu( page: "kernel/tariffOptions", icon: "fa-cogs", title: "menu.tariffOptions" )
 
...

Конфигурация приема платежей (mybgbilling-payment.groovy)

В файле mybgbilling-payment.groovy настраивается, какие платежные системы будут присутствовать при проведении оплаты из личного кабинета. Часто значения по умолчанию не требуют изменений. ЛК сам создаст список провайдеров из платежных модулей и при проведении оплаты отобразит те из них, модули которых подключены к данному договору.

Блок кода
languagescala
paymentConfig {

	/* Если true - то используются только провайдеры/модули, которые указаны в providers. */
    replaceProviders = false
    /* Показывать оплату через модуль Card */
    showCard = false
    /* Нужно ли указывать email/телефон при оплате */
    needReceiptContacts = true

    providers = [
    
    ]

	/* Список возможных способов пополнения можно указать вручную, но также нужно учитывать, что если модуль отсутствует на договоре - 
		то пункт с соответствующим модулем будет исключен из списка.  */
    payments = [

    ]
}

Если вы хотите, чтобы дополнительно отображался вариант с активацией карты оплаты модуля Card, укажите в конфигурации showCard=true

Блок кода
languagescala
paymentConfig {

	...

    /* Показывать оплату через модуль Card */
    showCard = true

    ...
}

При необходимости к текущим платежным системам вы можете добавить кнопку-ссылку:

Блок кода
languagescala
paymentConfig {

	/* Если true - то используются только провайдеры/модули, которые указаны в providers. */
    replaceProviders = false
    /* Показывать оплату через модуль Card */
    showCard = false
    /* Нужно ли указывать email/телефон при оплате */
    needReceiptContacts = true

    providers = [

    	// внешняя ссылка
		provider {
        	id = "externalLinkQiwi"
        	title = "Qiwi"
        	image = 'static/images/logos/qiwi.png'
			config = config {
				url = 'https://qiwi.com/payment/form.action?provider=297'
			}
    	}
    ]

    payments = [

    ]
}
Информация
Обратите внимание на параметр replaceProviders. Если он указан true, то не будет автоматической подгрузки провайдеров из платежных модулей - будут только те провайдеры, которые указаны в providers. Т.е. если его установить в true в конфигурации, что представлена выше, то при проведении платежа будет доступна только эта внешняя ссылка, даже если к договору подключены какие-то платежные модули.

Также для некоторых случаев с помощью providers можно переопределить конфигурацию провайдера, например, указать для Яндекс.Денег, какие именно типы платежей можно принимать:

Блок кода
languagescala
paymentConfig {

	/* Если true - то используются только провайдеры/модули, которые указаны в providers. */
    replaceProviders = false
    /* Показывать оплату через модуль Card */
    showCard = false
    /* Нужно ли указывать email/телефон при оплате */
    needReceiptContacts = true

    providers = [
    
    	// для Яндекс.Деньги возможно нужно указать типы платежей
        provider {
        	// код модуля Яндекс.Деньги
			moduleId = кодмодуля
			config = config {
				//Список доступных типов оплаты (Из в ЦПП). Пример: PC:Оплата со счета Яндекс.Денег;AC:Оплата с банковской карты;MC:Платеж со счета мобильного телефона;GP:Оплата наличными через кассы и терминалы;WM:Оплата с кошелька в системе WebMoney;SB:Оплата через Сбербанк Онлайн
				//paymentTypes = 'PC:payment.yamoney.PC;AC:payment.yamoney.AC;MC:payment.yamoney.MC;GP:payment.yamoney.GP;WM:payment.yamoney.WM;SB:payment.yamoney.SB'
				paymentTypes = 'PC:payment.yamoney.PC'
			}
    	}
    ]

    payments = [

    ]
}

Параметр payments предназначен для указания режимов оплаты и их порядка на странице вручную. Если в этом параметре указаны какие-то режимы, то при проведении платежа будут доступны только они (при дополнительном условии, что соответствующий модуль подключен к договору):

Блок кода
languagescala
paymentConfig {

	/* Если true - то используются только провайдеры/модули, которые указаны в providers. */
    replaceProviders = false
    /* Показывать оплату через модуль Card */
    showCard = false
    /* Нужно ли указывать email/телефон при оплате */
    needReceiptContacts = true

    providers = [

    ]

    payments = [

        payment {
            title = 'payment.bankCard'
            image = 'static/images/logos/visa_mastercard.png'
            providerId = 'yamoney'
            type = 'bankCard'
            config = config {
                paymentTypes = 'AC:payment.yamoney.AC'
            }
        },


        payment {
            title = 'payment.yamoney'
            image = 'static/images/logos/yamoney.png'
            providerId = 'yamoney'
            type = 'bankCard'
            config = config {
                paymentTypes = 'PC:payment.yamoney.PC'
            }
        }, 


        payment {
            title = 'payment.card'
            image = 'static/images/logos/card.png'
            providerId = 'card'
        }
    ]
}

Еще один пример:

Блок кода
languagescala
paymentConfig {

	/* Если true - то используются только провайдеры/модули, которые указаны в providers. */
    replaceProviders = false
    /* Показывать оплату через модуль Card */
    showCard = false
    /* Нужно ли указывать email/телефон при оплате */
    needReceiptContacts = true

    providers = [

        provider {
             id = "externalLinkQiwi"
             title = "Qiwi"
             image = 'static/images/logos/qiwi.png'
             config = config {
                 url = 'https://qiwi.com/payment/form.action?provider=297'
             }
        }
    ]

    payments = [

        payment {
            title = 'payment.bankCard'
            image = 'static/images/logos/visa_mastercard.png'
            providerId = 'yamoney'
            type = 'bankCard'
            config = config {
                paymentTypes = 'AC:payment.yamoney.AC'
            }
        },


        payment {
            title = 'payment.yamoney'
            image = 'static/images/logos/yamoney.png'
            providerId = 'yamoney'
            type = 'bankCard'
            config = config {
                paymentTypes = 'PC:payment.yamoney.PC'
            }
        }, 


        payment {
            providerId = ’externalLinkQiwi’
        }
    ]
}

Параметр needReceiptContacts указывает, нужно ли абоненту указывать email или телефон перед проведением оплаты (введенную информацию далее можно использовать при создании электронного чека).

Обновление личного кабинета

Для обновления личного кабинета запустите скрипт mybgbilling-update.sh:

Блок кода
languageruby
/opt/wildfly/bin/mybgbilling-update.sh

При обновлении файлы, рядом с которыми есть файл с таким же именем плюс суффикс(расширение) .orig, не будут перезаписаны файлом из сборки, вместо них обновяться .orig-файлы (см. Кастомизация нового личного кабинета). Также при обновлении полностью удаляется и перезаписывается директория MyBGBilling.war/WEB-INF/classes/ru/bitel.