Шлюзы к платежным системам интернет-денег.
1. Ваш плательщик может указать там произвольную сумму (а не четко требуемую к поступлению на ваш счет в нужной вам валюте), что может служить источником разногласий.
2. Он может указать непонятную цель платежа, что тоже может быть источником трений и разногласий.
3. Деньги со счета плательщика могут быть списаны, а к вам так и не поступить. Доказывать что-то по анонимному счету как правило бесполезно.
4. Деньги со своего анонимного кошелька вы все равно не сможете обналичить в банкомате (все равно это придется делать через чей-то авторизованный счет).
Указанных недостков лишены авторизованные интернет-кошельки (счета), которые имеют Merchant-интерфейс. Это кнопка, на которую можно кликнуть и, авторизовавшись в своем кошельке, окзаться на сайте интернет-банка уже с заполненной нужной вам суммой, нужным назначением платежа. Вместо цифрового номера вашего счета (куда клиент будет платить) как правило там будет указано символическое имя. А назначение платежа выбирается на вашем собственном сайте и на сайте интернет-банка его уже нельзя изменить.
После выполнения платежа вы мгновенно получите уведомление на свой сайт от интернет-банка и когда ваш пользователь нажмет кнопку "вернутся в магазин" ваш сайт сможет сразу же указать этому пользователю что выбранный им товар оплачен.
В теории все хорошо, вот только к сожалению все существующие интернет-банки имеют свои заморочки. Яндекс-деньги не позволяет использовать merchant-интерфейс физическим лицам, только юридическим - причем взимает за каждую транзакцию баснословные 5%.
Webmoney требует ацской и унизительной процедуры авторизации продавца, которая требует не только ксерокопии паспорта, но и собственноручной обязательной публикации в интернете всех личных данных, вплоть до домашнего адреса владельца предприятия (в отношении юридических лиц не возбуждаются уголовные дела). Ну как бы ваши личные данные невидимы неприоритетным логинам, но там есть десятки тысяч приоритетных логинов. Как мне объяснили в WebMoney в отношении всех остальных граждан (кроме россиян и украинцев) действует банковская тайна. На мой взгляд такая позиция интернет-банка противоречит закону о охране сведений о частной жизни, но кто видел чтобы у нас соблюдались какие-то законы? Банк действует видимо под крышей каких-то чекистов, возможно уклоняется от налогов (зарегистирован в Латвии), а в отношении нас крыша ему гарантирует возможность нарушать любые российские законы. Кроме того, собственноручное заявление об открытии счета с приложением копии паспорта заполяется ровно в той форме, какая требуется для открытия на вас какого-нибудь уголовного дела - фактически вы сами на себя заполняете бланки, которые вам потом покажет ваш следователь. Кроме того, конвертация денег из других платежных систем практически невозможна. Еще одним недостатком является замороченный и тупой сайт WebMoney в котором в самый нужный момент вываливается ошибка - сорри этот сервис недоступен. Кроме того, там еще миллион заморочек странных - например вы не можете открыть себе два счета - почему-то сразу деньги сразу же блокируются (становятся собственностью этого интернет-банка). Для удобства прослушивания они также требуют от вас при регистрации номер вашего мобильника. Чуствуется за этой шайкой крепкая криминально-чекистская крыша, которая позволяет им себя настолько беспредельно вести себя.
Еще более замкнутая платежная система (в плане приема денег из других платежных систем) англо-немецкий банк MoneyBooker. Правда там нет таких явных преступных намерений о сборе ваших личных данных, не нужно заполнять бланки для открытия уголовного дела в отношении себя, не требуется ксерокопия паспорта или номер вашего мобильника. Достаточно просто авторизовать свой почтовый адрес. Вам приходит на ваш домашний (или любой другой) адрес письмо - в нем несколько букв пароля. Вы их вбиваете на сайт и все - счет полностью авторизован. Вы получаете право перечислять по этому счету по $12 тыс. за каждые 90 дней (по $1400 за раз).
Проблемы обычно начинаются позже, когда вы сливаете свои деньги на счета российских чудо-банков, например альфа-банку на карточку Visa-Electron (чтобы снять деньги в банкомате). Альфа-банк видимо кому-то продает ведомости с перечислениями - меня лично трахают после каждого перевода не меньше месяца - звонят на домашний телефон всякие московские банки и предлагают взять у них кредиты. И еще возмущаются, когда я отказываюсь "у нас столько кредитных продуктов предлагается - как такое может быть, что вам не один наш продукт не нравится"? Хотя возможно, утечки происходят не в Альфа-банке. Все управление счетом происходит по SSL, а уведомления о каждом входе по https:// отправляются в Microsoft (как бы в рамках борьбы с фишингом) и вообще легко фильтруются на магистралях даже без этих уведомлений. Так что продавать сведения о платежах могут и все вот эти фельдмаршалы по борьбе с терроризмом, имеющие доступ к интернет-магистралям.
Для приема Яндекс-денег через Merchant-интерфейс физических лиц обычно используется Robokassa. У меня нет пока достаточного опыта общения с этой платежной системой, поэтому я от комментариев воздержусь. Однако относительно всех остальных систем сразу же бросилось в глаза отсутствие нормальной активации логина. Они это делают почему-то вручную по вашей письменной просьбе по электронной почте.
Платежная система для VISA, MasterCard и других пластиковых карточек - Assist. С ней я работал тоже. По логике работы ее мерчант-интерфейс является клоном интерфейса Яндекс-мани и Web-мани. С той небольшой заморочкой, что этот сервис написан на Яве и с ним гиморойно работать с платформы NET. Почему именно - я пояснил тут WCF_CLIENT - клиент Web-сервиса. Шлюз Ассиста является коммерческим know-how, поэтому тут его код опубликован не будет. Однако некоторые мои технологические подходы к программированию этого шлюза вы можете понять из этой моей заметки - Как парсить XML SOAP в MS SQL.
Очень уважаемые мною люди порекомендовали мне израильско-американскую интернет-платежную систему Plimus, который на первый взгляд лишен всех указанных заморочек. Но достаточного личного опыта работы с Плимусом у меня пока нет, поэтому я пока тоже воздержусь от критики.
Документация на Merchant-интерфейсы:
- money.yandex.ru: Инструкция по подключению к ЦПП, Яндекс-деньги. Общие вопросы.
- merchant.webmoney.ru: Webmoney Merchant Interface
- robokassa.ru: ROBOKASSA. Описание интерфейсов
- moneybookers.com: Mertchant services, Moneybookers Payment Gateway, Moneybookers Automated Payments Interface, FAQ
- plimus.com: Plimus Starter Guide, FAQ, Learning center, видеоролики на английском : Настройка Продуктов, Настройка Контрактов, Настройка страниц BuyNow
Теперь перейдем к обсуждению технических аспектов merchant-шлюза в ASP.NET специфике. Все платежные шлюзы устроены совершенно одинаково, собственно даже многие фрагменты кода можно просто копировать из одного шлюза в другой. Процесс начинается с того, то на своем сайте вы формируете итоговую форму (по результатам того, что нащелкал юзер на вашем сайте) и оправляете ее постбеком на сервер платежей. В качестве данных там будет сумма, номер счета назначения, все необходимые комментарии. Вместо цифрового номера счета там будет символичское имя вашего магазина, комментарии и суммы изменить уже будет нельзя. У плимуса страничка, куда попадает ваш клиент после нажатия кнопки "оплатить" на вашем сайте не одинаковая, как в остальных платежных системах (так она выглядит в Яндексе, а вот так в WebMoney), а вы ее конструируете сами (для каждого своего продукта или назначения платежа). В MoneyBooker тоже есть некая настройка странички куда попадет ваш покупатель, но не настолько продвинутая, как в Plimus.
Для выполнения этого первичного постбека с запросом о платеже есть два пути - первый формирование POST на нужный адрес на сервере. Это, конечно, более защищенный путь - относительно отправки первичного реквеста о платеже непосредственно из браузера клиента вашего сайта. Но, увы, это не получается со всеми платежными системами. Так получается работать например с Яндекс-деньгами (пример вы можете посмотреть на rzd.gisis.ru. С WebMoney получается как-то странно - реквесты проходят иногда несколько подряд, иногда через один, иногда каждый второй. Чуствуются какие-то проблемы у этих чекистов. Ну не хочет, видимо, на них работать ни один нормальный программист.
Поэтому для WebMoney (и других) можно работать менее защищенным, но более универсальным способом - отправкой первичного реквеста о платеже непосредственно с клиента. Такой путь я применил, например, на сайте www.asp-net.ru. Фишка, однако, заключается в том, что ASP.NET в приниципе не позволяет отправлять постбеки на другую страничку - те в рамках пиридавой разрекламированной билагейтсвоской чудо-технологии ASP.NET эта простенькая задачка не решаема в принципе. Однако она решается элементарно в рамках простого ASP, где постбек на странички можно отправить куда угодно. Правда тут есть некоторые технические проблемы, например с той же кодировкой.
Итак, если мы хотим сформировать первичный реквест в рамках технологии ASP.NET и более защищенным от всяких атак и подделок способом, то нам надо взять примерно вот такой код, который лежит где-то в библиотеке:
1: 'Запрос странички методом POST (молча, ошибки обрабатываются извне этого кода)
2: Public Function PostRequest(ByVal URL As String, ByVal POST_Data As String) As String
3: '========== System.NotSupportedException The URI prefix is not recognized.
4: Dim request As Net.HttpWebRequest = Net.HttpWebRequest.Create(URL)
5: request.Method = "POST"
6: Dim byteArray As Byte() = System.Text.Encoding.ASCII.GetBytes(POST_Data)
7: request.ContentType = "application/x-www-form-urlencoded"
8: request.ContentLength = byteArray.Length
9: '========== System.Net.WebExceptionStatus.Timeout Unable to connect to the remote server
10: Dim POST_Stream As IO.Stream = request.GetRequestStream()
11: POST_Stream.Write(byteArray, 0, byteArray.Length)
12: POST_Stream.Close()
13: '
14: 'ждем
15: '========== System.Net.WebException.Timeout
16: '========== System.Net.WebException = "The remote server returned an error: (404) Not Found."
17: Dim response As Net.HttpWebResponse = request.GetResponse()
18: Dim GET_Stream As IO.Stream = response.GetResponseStream()
19: Dim reader As IO.StreamReader
20: reader = New IO.StreamReader(GET_Stream, System.Text.ASCIIEncoding.GetEncoding("windows-1251"))
21: Dim HTML As String = reader.ReadToEnd
22: reader.Close()
23: GET_Stream.Close()
24: response.Close()
25: Return HTML
26: End Function
И вызвать его прямо на сервере примерно вот так:
1: 'первый реквест в Яндекс
2: Public Shared Sub YaMoneyFirstRequest(ByVal Summ As String, ByVal CustomerNumber As String)
3: Dim Replay As String = InternetTransfer.PostRequest(System.Configuration.ConfigurationManager.AppSettings("YaMoneyURL"), "scid=1234567&ShopID=" & System.Configuration.ConfigurationManager.AppSettings("ShopID").ToString & "&Sum=" & Summ & "&CustomerNumber=" & CustomerNumber & "&BuyButton=Submit")
4: Replay = Replay.Replace("action=""//demomoney.yandex.ru", "action=""https://demomoney.yandex.ru")
5: Replay = Replay.Replace("action=""/store-request.xml", "action=""https://demomoney.yandex.ru/store-request.xml")
6: Replay = Replay.Replace("action=""http://127.0.0.1:8129/wallet", "action=""https://demomoney.yandex.ru:8129/wallet")
7: HttpContext.Current.Response.Write(Replay)
8: End Sub
Как вы понимаете, это не вполне корректный вызов, скорее напоминающий технологии фишингования. Корректный способ перехода на сервера платежных систем я описал здесь - WCF_CLIENT - клиент Web-сервиса.
Здесь вы видите пример для демо-денег (ибо вам все равно придется отлаживать свой шлюз на них). Параметр ShopID и YaMoneyURL я вынес в конфиг, вам их дадут когда вы зарегистрируетесь в Яндексе.
<add key="ShopID" value="12345678"/> <add key="YaMoneyURL" value="https://demomoney.yandex.ru/eshop.xml"/>
Обратите внимание, что при получении ответа от Яндекса вам придется поменять ссылки на рисунки (ибо они указаны относительными адресами). Параметр CustomerNumber - это тот самый номер заказа, который сформировал ваш сайт. Именно чтобы его сокрыть - выгодно отправлять первичный реквест с сервера, а не с клиента. Это защитит ваш сайт от любых возможных атак. Ведь во всех последующих ответах от яндекса (или от того, кто пытается выдать себя за Яндекс) - нужно будет указывать этот CustomerNumber. А если его и не показывать клиенту изначально (это просто GUID обычно у меня), то тема атак на ваш сервер учета платежей вообще отсутвует. К тому же это решение самое что ни на есть в рамках ASP.NET. Но... как я уже говорил, более глюкавые интернет-банки почему-то принимают такие серверные реквесты через раз.
Поэтому более универсальный, но менее защищенный шлюз должен сформировать этот постбек на клиенте. Для этого придется выйти за рамки ASP.NET. Делается это так:
- вы верстаете обычную ASP.NET страничку в студии (из всех своих контролов и мастер-страниц)
- запускаете ее под девелоперским сервером и созраняете на диск с расширением ASP
- импортируете ее в проект
В итоге у вас получается верстка странички со всеми вашими контролами и мастер-пейджами. Вы можете сразу выбросить из нее все скрипты ASp.NET, но главное:
- Изменить тег FORM на правильный, чтобы постбек уходил в платежную систему
- Добавить параметры, которые уйдут на сайт платежной системы
Для merchant.webmoney.ru это изменение будет выглядеть так:
<form name="aspnetForm" method="post" accept-charset="cp1251" action="https://merchant.webmoney.ru/lmi/payment.asp" id="aspnetForm"> <input type="hidden" id="LMI_PAYMENT_AMOUNT" name="LMI_PAYMENT_AMOUNT" value='<%=Request.Querystring("Sum") %>' /> <input type="hidden" id="LMI_PAYMENT_DESC" name="LMI_PAYMENT_DESC" value='<%=Request.Querystring("Type") %> : <%=Request.Querystring("Comment") %>' /> <input type="hidden" id="LMI_PAYMENT_NO" name="LMI_PAYMENT_NO" value="0" /> <input type="hidden" id="LMI_PAYEE_PURSE" name="LMI_PAYEE_PURSE" value="Z397687856249" /> <input type="hidden" id="LMI_SIM_MODE" name="LMI_SIM_MODE" value="0" />
Как вы поняли, я тут заморачиваться не стал, а вызвал эту ASP-овскую страничку из ASP.NET-овской просто прокинув ей параметры в Реквесте:
1: Protected Sub ImageButton3_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton3.Click
2: Response.Redirect("WM_Payment.asp?Sum=" & txSumm.Text.Replace(",", ".") & "&Type=" & Server.UrlEncode(DropDownList1.SelectedItem.Text) & "&Comment=" & Server.UrlEncode(txComment.Text))
3: Response.End()
4: End Sub
Обратите внимание на кодировку в POST. Здесь все стоит именно так, чтобы в кошельке у вашего покупателя введеный им текст на страничке ASP.NET оказался в руской кодировке. Для этого надо еще задать кодировку самой ASP-вской странички (чтобы она приняла правильно параметры из ASP.NET-овской):
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
В приниципе, сохранение правильной кодировка при переходе из странички ASP.NET на страничку ASP, а затем постбек на страничку платежной системы - это основная заморочка здесь. Комментарий, введенный вашим покупателем на ASP.NET страничке на русском языке - должен отобрадаться в платежной системе тоже на русском языке после прохождения этой цепочки. Никаких других проблем, над которыми тут можно задуматься больше секунды - тут просто нет. Для тестирования кодировок вы можете воспользоваться моим публичным сервисом //www.vb-net.com/PostTest.ashx, отправив для начала постбеки на мой хандлер.
В связи с тем, что я описываю беспредельно простой магазин - для WebMoney тот самый CustomerNumber (номер заказа) здесь имеет имя LMI_PAYMENT_NO и в этом магазине он у меня тупо ноль всегда. LMI_SIM_MODE - это режим тестовый/боевой (в Яндексе применяют вместо этого переключателя префикс к URL - money.yandex.ru или DEMOmoney.yandex.ru)
Аналогичная страничка для отправки первичного постбека формируется и для moneybooker:
<form name="aspnetForm" method="post" accept-charset="cp1251" action="http://www.moneybookers.com/app/test_payment.pl" id="aspnetForm"> <input type="hidden" id="pay_to_email" name="pay_to_email" value="[email protected]" /> <input type="hidden" id="language" name="language" value="RU" /> <input type="hidden" id="transaction_id" name="transaction_id" value="0" /> <input type="hidden" id="amount" name="amount" value='<%=Request.Querystring("Sum") %>' /> <input type="hidden" id="currency" name="currency" value="USD" /> <input type="hidden" id="detail1_description" name="detail1_description" value='<%=Request.Querystring("Type") %>' /> <input type="hidden" id="detail1_text" name="detail1_text" value='<%=Request.Querystring("Comment") %>' /> <input type="hidden" id="status_url" name="status_url" value='//www.vb-net.com/Status3.ashx' />
Совершенно аналогично формируется первичный постбек и для robokassa.ru
<form name="aspnetForm" method="post" accept-charset="cp1251" action="https://merchant.roboxchange.com/Index.aspx" id="aspnetForm"> <input type="hidden" id="MrchLogin" name="MrchLogin" value="asp-net" /> <input type="hidden" id="OutSum" name="OutSum" value='<%=Request.Querystring("Sum") %>' /> <input type="hidden" id="nInvId" name="nInvId" value='0' /> <input type="hidden" id="sInvDesc" name="sInvDesc" value='<%=Request.Querystring("Type") %> : <%=Request.Querystring("Comment") %>' /> <input type="hidden" id="sSignatureValue" name="sSignatureValue" value='<%=Request.Querystring("Hash") %>' /> <input type="hidden" id="sIncCurrLabel" name="sIncCurrLabel" value='PCR' /> <input type="hidden" id="sCulture" name="sCulture" value='ru' /> <input type="hidden" id="sEncoding" name="sEncoding" value='Windows-1251' />
Вот только вызов ее будет сложнее из-за необходимости отправлять MD5-хеш:
1: Protected Sub ImageButton2_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton2.Click, ImageButton7.Click, ImageButton8.Click
2: Dim Signature As New StringBuilder
3: Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvider
4: 'sMrchLogin, sOutSum, nInvId, sMrchPass1
5: Dim MD5Hash() As Byte = MD5.ComputeHash(Encoding.ASCII.GetBytes("тутвыпишитесвойлогин" & ":" & txSumm.Text.Replace(",", ".") & ":" & "0" & ":" & "тутвыпишитесвойпароль"))
6: For Each One As Byte In MD5Hash
7: Signature.AppendFormat("{0:x2}", One)
8: Next
9: Response.Redirect("Robo_Payment.asp?Sum=" & txSumm.Text.Replace(",", ".") & "&Type=" & Server.UrlEncode(DropDownList1.SelectedItem.Text) & "&Comment=" & Server.UrlEncode(txComment.Text) & "&Hash=" & Signature.ToString)
10: Response.End()
11: End Sub
Здесь роль индивидуального номера заказа играет параметр nInvId, так же как CustomerNumber в Яндексе, LMI_PAYMENT_NO в WebMoney, transaction_id в Moneybooker.
Немного иной принцип у plimis.com - вы создаете в конструкторе на сайте плимуса несколько нужных вам настроенных страниц, на которых подробно можете описать все свои продукты, сервисы. Загружаете нужные картинки, программы. Получаете индивидуальный номер созданного описания. И в простейшем случае ставите со своей странички просто линк с номером вашей странички с описанием товара, например такой:
<a href="https://www.plimus.com/jsp/buynow.jsp?contractId=2393616" target="_blank">Payment my product</a>
И ваш покупатель попадает на нужную страничку, на которой вы сформировали описание своего товара или услуги.
Теперь перейдем к следующему этапу. Когда пользователь вашего сайта залогинится и выполнит платеж со своего кошелька в ваш адрес, вам поступит уведомление об оплате. Все интернет-банки имеют некоторые параметры настройки - каким образом удостоверится в корректности параметров платежа, каким образом пеередать вам уведомление об оплате, как вам передать сводный месячный отчет и так далее. Если запрос на выполнение платежа всегда выполняется одинакого, то ответы от интернет-банка зависят от этих настроек. Поэтому я дальше покажу свои любимые настройки в каждом из этих интернет-банков, ибо без них весь дальнейший код совершенно теряет смысл. Например если вы установили режим получения уведомления по почте, то какой смысл будет в хандлере на вашем сайте, который я опишу ниже для приема уведомлений о платеже?
Итак, вы входите в WebMoney и выполняете там настройки своего кошелька. Совершенно аналогичным образом устанавливаются настройки (имена хандлеров на вашем сайте) для Яндекс-кошелька или Робокассы (фактически надстройки над Яндекс-кошельками для физических лиц). Для MoneyBooker видимо имена этих хандлеров тоже можно где-то задать в настройках счета, но я их передаю непосредственно в постбеке параметром status_url. В Яндексе и других магазинах их тоже по идее так же можно передавать. Plimus, насколько я понимаю, делает уведомления об оплате только по E-mail (и я пока не понимаю, как это обрабатывать). Другие платежные системы тоже могут высылать уведомления по Email, но тогда после возврата из платежной системы в ваш магазин вы не узнаете - оплачен ли уже ваш товар. Мыло ведь может и через день дойти. Поэтому, на мой взгляд, есть смысл выбирать уведомления по E-mail только для месячных реестров, а в остальных случаях видеть факт оплаты в онлайне.
Хандлеры, которые мы рассмотрим дальше и являются онлайновыми обработчиками уведомлений об оплате. В каждой платежной системе есть описание, в какой именно форме (обычно это XML) платежные системы вам передают данные об успешной оплате (и от кого зачислены вам деньги).Для Яндекс-денег таких хандлера должно быть четыре - Aviso.ashx, Fail.asxh, Check.asxh, Success.ashx. Fail.ashx вызывается когда ваш покупатель нажал кнопку оплатить товар, залогинился в свой кошелек, что-то тыкал в нем, но платеж в итоге не прошел. Поэтому обрабатывать осмысленно эти ложные тыкания смысла нет.
А вот Check.ashx должен содержать вполне осмысленный код. Этот ханжлер должен сформировать XML, который подтвердит Яндексу, что такой продукт вы продать готовы и деньги за него ваш электронный магазин приять готов. Этот хандлер должен выглядеть так:
1: <%@ WebHandler Language="VB" Class="Check" %>
2: Imports System
3: Imports System.Web
4: Public Class Check : Implements IHttpHandler
5:
6: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
7: Dim InvoiceId As String = ""
8: Dim GisisID As String = Gateway.YaCheckSave
9: If GisisID <> "" Then
10: InvoiceId = Gateway.YaCheck(GisisID)
11: If InvoiceId <> "" Then
12: Dim D As DateTime = Now
13: Dim Performed_S As String '2005-01-21T13:20:07+03:00
14: Performed_S = String.Format("{0:0000}-{1:00}-{2:00}T{3:00}:{4:00}:{5:00}+03:00", D.Year, D.Month, D.Day, D.Hour, D.Minute, D.Second)
15: Dim ResultXmlString As String = "<?xml version=""1.0"" encoding=""windows-1251""?>" & vbCrLf & _
16: "<response performedDatetime=""" & Performed_S & """>" & vbCrLf & _
17: "<result code=""0"" action=""Check"" shopId=""" & System.Configuration.ConfigurationManager.AppSettings("ShopID").ToString & """ invoiceId=""" & InvoiceId & """/>" & vbCrLf & _
18: "</response>"
19: Dim Coder As System.Text.Encoding
20: Coder = System.Text.Encoding.GetEncoding(1251)
21: context.Response.ContentEncoding = Coder
22: context.Response.ContentType = "text/xml"
23: context.Response.BinaryWrite(Coder.GetBytes(ResultXmlString))
24: End If
25: End If
26: End Sub
Хандлер вызывает две функции шлюза. Первая из них просто ведет статистику всех обращений Яндекса за проверками (этого можно и не делать, чтобы не росла база и не требовала лишнего обслуживания) и возвращает CustomerNumber - тот самый номер заказа, который мы отправляли Яндексу в первичном постбеке с запросом платежа.
1: 'Сохранение ответа из Яндекса на запрос платежа
2: Public Shared Function YaCheckSave() As String
3: '
4: Dim CN As System.Data.SqlClient.SqlConnection
5: Dim CMD As Data.SqlClient.SqlCommand
6: '
7: Try
8: CN = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
9: CN.Open()
10: CMD = New Data.SqlClient.SqlCommand("[YaCheckSave]", CN)
11: CMD.CommandType = Data.CommandType.StoredProcedure
12: CMD.Parameters.AddWithValue("requestDatetime", HttpContext.Current.Request.Form("requestDatetime"))
13: CMD.Parameters.AddWithValue("md5", HttpContext.Current.Request.Form("md5"))
14: CMD.Parameters.AddWithValue("shopId", HttpContext.Current.Request.Form("shopId"))
15: CMD.Parameters.AddWithValue("invoiceId", HttpContext.Current.Request.Form("invoiceId"))
16: CMD.Parameters.AddWithValue("customerNumber", HttpContext.Current.Request.Form("customerNumber"))
17: CMD.Parameters.AddWithValue("orderCreatedDatetime", HttpContext.Current.Request.Form("orderCreatedDatetime"))
18: CMD.Parameters.AddWithValue("orderSumAmount", HttpContext.Current.Request.Form("orderSumAmount"))
19: CMD.Parameters.AddWithValue("orderSumCurrencyPaycash", HttpContext.Current.Request.Form("orderSumCurrencyPaycash"))
20: CMD.Parameters.AddWithValue("orderSumBankPaycash", HttpContext.Current.Request.Form("orderSumBankPaycash"))
21: CMD.Parameters.AddWithValue("shopSumAmount", HttpContext.Current.Request.Form("shopSumAmount"))
22: CMD.Parameters.AddWithValue("orderIsPaid", HttpContext.Current.Request.Form("orderIsPaid"))
23: CMD.Parameters.AddWithValue("paymentType", HttpContext.Current.Request.Form("paymentType"))
24: CMD.Parameters.AddWithValue("paymentPayerCode", HttpContext.Current.Request.Form("paymentPayerCode"))
25: CMD.Parameters.AddWithValue("action", HttpContext.Current.Request.Form("action"))
26: CMD.Parameters.AddWithValue("ErrorTemplate", HttpContext.Current.Request.Form("ErrorTemplate"))
27: CMD.Parameters.AddWithValue("shn", HttpContext.Current.Request.Form("shn"))
28: CMD.Parameters.AddWithValue("secureparam2", HttpContext.Current.Request.Form("secureparam2"))
29: CMD.Parameters.AddWithValue("secureparam5", HttpContext.Current.Request.Form("secureparam5"))
30: CMD.Parameters.AddWithValue("BuyButton", HttpContext.Current.Request.Form("BuyButton"))
31: CMD.Parameters.AddWithValue("isViaWeb", HttpContext.Current.Request.Form("isViaWeb"))
32: CMD.Parameters.AddWithValue("SuccessTemplate", HttpContext.Current.Request.Form("SuccessTemplate"))
33: CMD.Parameters.AddWithValue("scid", HttpContext.Current.Request.Form("scid"))
34: CMD.Parameters.AddWithValue("ncrnd", HttpContext.Current.Request.Form("ncrnd"))
35: CMD.Parameters.AddWithValue("WAPaymentPreferences", HttpContext.Current.Request.Form("WAPaymentPreferences"))
36: CMD.ExecuteNonQuery()
37: Catch ex As Exception
38: Dim CN1 As System.Data.SqlClient.SqlConnection
39: Dim CMD1 As Data.SqlClient.SqlCommand
40: CN1 = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
41: CN1.Open()
42: CMD1 = New Data.SqlClient.SqlCommand("INSERT [CheckDump] ([Raw]) VALUES (@Raw)", CN1)
43: CMD1.CommandType = Data.CommandType.Text
44: CMD1.Parameters.AddWithValue("Raw", ex.Message)
45: CMD1.ExecuteNonQuery()
46: Return ""
47: End Try
48: '
49: If CN IsNot Nothing Then
50: If CN.State.Open Then
51: CN.Close()
52: End If
53: End If
54: Return HttpContext.Current.Request.Form("customerNumber")
55: End Function
Вторая функция осуществляет собственно проверку - может ли жлектронный магазин принимать деньги за указанный товар. У меня эта проверка вынесена на уровень SQL и свою проверку я публиковать не буду, ибо в вашем магазине она все равно будет другая.
1: 'Проверка корректности ответа из Яндекса на запрос платежа (возвращает InvoiceId)
2: Public Shared Function YaCheck(ByVal TicketID As String) As String
3: '
4: Dim CN As System.Data.SqlClient.SqlConnection
5: Dim CMD As Data.SqlClient.SqlCommand
6: Dim InvoiceId As String = ""
7: '
8: Try
9: CN = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
10: CN.Open()
11: CMD = New Data.SqlClient.SqlCommand("[YaCheck]", CN)
12: CMD.CommandType = Data.CommandType.StoredProcedure
13: CMD.Parameters.AddWithValue("TicketId", TicketID)
14: Dim RDR1 As Data.SqlClient.SqlDataReader = CMD.ExecuteReader(System.Data.CommandBehavior.SingleRow)
15: If RDR1.Read Then
16: If Not IsDBNull(RDR1("invoiceId")) Then
17: InvoiceId = RDR1("invoiceId")
18: End If
19: End If
20: Catch ex As Exception
21: Dim CN1 As System.Data.SqlClient.SqlConnection
22: Dim CMD1 As Data.SqlClient.SqlCommand
23: CN1 = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
24: CN1.Open()
25: CMD1 = New Data.SqlClient.SqlCommand("INSERT [CheckDump] ([Raw]) VALUES (@Raw)", CN1)
26: CMD1.CommandType = Data.CommandType.Text
27: CMD1.Parameters.AddWithValue("Raw", ex.Message)
28: CMD1.ExecuteNonQuery()
29: Return ""
30: End Try
31: '
32: If CN IsNot Nothing Then
33: If CN.State.Open Then
34: CN.Close()
35: End If
36: End If
37: Return InvoiceId
38: End Function
Вторая функция возвращает invoiceId - номер платежной транзакции Яндекса - он нужен для формирования результирующего XML, который я сформировал прямо в хандлере со всем требуемым Яндексом форматированием.
Хандлер Aviso.ashx вызывает Яндекс, когда происходит платеж. Он тоже не может быть пустым, потому что в ответе надо сформировать XML. Я делаю этот хандлер так:
1: <%@ WebHandler Language="VB" Class="Aviso" %>
2: Imports System
3: Imports System.Web
4: Public Class Aviso : Implements IHttpHandler
5:
6: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
7: Dim InvoiceId As String = gateway.YaSetAviso
8: If InvoiceId<>"" then
9: Dim D As DateTime = Now
10: Dim Performed_S As String '2005-01-21T13:20:07+03:00
11: Performed_S = String.Format("{0:0000}-{1:00}-{2:00}T{3:00}:{4:00}:{5:00}+03:00", D.Year, D.Month, D.Day, D.Hour, D.Minute, D.Second)
12: Dim ResultXmlString As String = "<?xml version=""1.0"" encoding=""windows-1251""?>" & vbCrLf & _
13: "<response performedDatetime=""" & Performed_S & """>" & vbCrLf & _
14: "<result code=""0"" action=""PaymentSuccess"" shopId=""" & System.Configuration.ConfigurationManager.AppSettings("ShopID").ToString & """ invoiceId=""" & InvoiceId & """/>" & vbCrLf & _
15: "</response>"
16: Dim Coder As System.Text.Encoding
17: Coder = System.Text.Encoding.GetEncoding(1251)
18: context.Response.ContentEncoding = Coder
19: context.Response.ContentType = "text/xml"
20: context.Response.BinaryWrite(Coder.GetBytes(ResultXmlString))
21: End If
22: End Sub
23:
24:
25: Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
26: Get
27: Return False
28: End Get
29: End Property
30:
31: End Class
Все осмысленные действия по факту платежа я делаю на уровне SQL и тут публиковать не буду, соответсвенно функция YaSetAviso этого хандлера - это просто вызов процедуры:
1: 'Проверка корректности ответа из Яндекса на запрос платежа (возвращает InvoiceId)
2: Public Shared Function YaSetAviso() As String
3: '
4: Dim CN As System.Data.SqlClient.SqlConnection
5: Dim CMD As Data.SqlClient.SqlCommand
6: Dim InvoiceId As String = ""
7: '
8: Try
9: CN = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
10: CN.Open()
11: CMD = New Data.SqlClient.SqlCommand("[YaSetAviso]", CN)
12: CMD.CommandType = Data.CommandType.StoredProcedure
13: CMD.Parameters.AddWithValue("id", HttpContext.Current.Request.Form("customerNumber"))
14: CMD.Parameters.AddWithValue("Price", HttpContext.Current.Request.Form("orderSumAmount"))
15: CMD.ExecuteNonQuery()
16: InvoiceId = HttpContext.Current.Request.Form("invoiceId")
17: Catch ex As Exception
18: Dim CN1 As System.Data.SqlClient.SqlConnection
19: Dim CMD1 As Data.SqlClient.SqlCommand
20: CN1 = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
21: CN1.Open()
22: CMD1 = New Data.SqlClient.SqlCommand("INSERT [CheckDump] ([Raw]) VALUES (@Raw)", CN1)
23: CMD1.CommandType = Data.CommandType.Text
24: CMD1.Parameters.AddWithValue("Raw", ex.Message)
25: CMD1.ExecuteNonQuery()
26: Return ""
27: End Try
28: '
29: If CN IsNot Nothing Then
30: If CN.State.Open Then
31: CN.Close()
32: End If
33: End If
34: Return InvoiceId
35: End Function
И, наконец, хандлер Success.ashx вызывается Яндексом по кнопке "возврат в магазин". Хдесь вы должны просто сдедать переход на свою страничку, на которой будет установлено, что товар покупателем уже оплачен. Грубо говоря, этот хандлер содержит единственную строку с Response.redirect на список товаров, который отбирал пользователь до нажатия кнопки "оплатить", только в Aviso вы уже изменили статус этого товара на "уже оплачен".
Совершенно аналогично устроен платежный шлюз WebMoney, он состоят из хандлеров Check и Success. Здесь у меня более простой магазин и деньги он принимает без проверки - всегда отвечая "Да".
1: <%@ WebHandler Language="VB" Class="Check1" %>
2: Imports System
3: Imports System.Web
4: Public Class WM_Check : Implements IHttpHandler
5:
6: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
7: If context.Request.Form("LMI_PREREQUEST") IsNot Nothing Then
8: 'это запрос Check - всегда отвечаем YES
9: context.Response.ContentType = "text/plain"
10: context.Response.Write("YES")
11: Else
12: '
13: End If
14: End Sub
15:
16: Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
17: Get
18: Return False
19: End Get
20: End Property
21:
22: End Class
А хандлер Success ведет учет поступивших платежей (фиксируя фозможные ошибки):
1: <%@ WebHandler Language="VB" Class="Success1" %>
2: Imports System
3: Imports System.Web
4: Public Class WM_Success : Implements IHttpHandler
5:
6: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
7: '
8: Dim CN As System.Data.SqlClient.SqlConnection
9: Dim CMD As Data.SqlClient.SqlCommand
10: '
11: Try
12: CN = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
13: CN.Open()
14: CMD = New Data.SqlClient.SqlCommand("AddVmAviso", CN)
15: CMD.CommandType = Data.CommandType.StoredProcedure
16: CMD.Parameters.AddWithValue("PAYEE_PURSE", HttpContext.Current.Request.Form("LMI_PAYEE_PURSE"))
17: CMD.Parameters.AddWithValue("PAYMENT_AMOUNT", HttpContext.Current.Request.Form("LMI_PAYMENT_AMOUNT"))
18: CMD.Parameters.AddWithValue("PAYMENT_NO", HttpContext.Current.Request.Form("LMI_PAYMENT_NO"))
19: CMD.Parameters.AddWithValue("MODE", HttpContext.Current.Request.Form("LMI_MODE"))
20: CMD.Parameters.AddWithValue("SYS_INVS_NO", HttpContext.Current.Request.Form("LMI_SYS_INVS_NO"))
21: CMD.Parameters.AddWithValue("SYS_TRANS_NO", HttpContext.Current.Request.Form("LMI_SYS_TRANS_NO"))
22: CMD.Parameters.AddWithValue("PAYER_PURSE", HttpContext.Current.Request.Form("LMI_PAYER_PURSE"))
23: CMD.Parameters.AddWithValue("PAYER_WM", HttpContext.Current.Request.Form("LMI_PAYER_WM"))
24: CMD.Parameters.AddWithValue("PAYMER_NUMBER", HttpContext.Current.Request.Form("LMI_PAYMER_NUMBER"))
25: CMD.Parameters.AddWithValue("PAYMER_EMAIL", HttpContext.Current.Request.Form("LMI_PAYMER_EMAIL"))
26: CMD.Parameters.AddWithValue("EURONOTE_NUMBER", HttpContext.Current.Request.Form("LMI_EURONOTE_NUMBER"))
27: CMD.Parameters.AddWithValue("EURONOTE_EMAIL", HttpContext.Current.Request.Form("LMI_EURONOTE_EMAIL"))
28: CMD.Parameters.AddWithValue("TELEPAT_PHONENUMBER", HttpContext.Current.Request.Form("LMI_TELEPAT_PHONENUMBER"))
29: CMD.Parameters.AddWithValue("TELEPAT_ORDERID", HttpContext.Current.Request.Form("LMI_TELEPAT_ORDERID"))
30: CMD.Parameters.AddWithValue("PAYMENT_CREDITDAYS", HttpContext.Current.Request.Form("LMI_PAYMENT_CREDITDAYS"))
31: CMD.Parameters.AddWithValue("ATM_WMTRANSID", HttpContext.Current.Request.Form("LMI_ATM_WMTRANSID"))
32: CMD.Parameters.AddWithValue("HASH", HttpContext.Current.Request.Form("LMI_HASH"))
33: CMD.Parameters.AddWithValue("SYS_TRANS_DATE", HttpContext.Current.Request.Form("LMI_SYS_TRANS_DATE"))
34: CMD.Parameters.AddWithValue("SECRET_KEY", HttpContext.Current.Request.Form("LMI_SECRET_KEY"))
35: CMD.Parameters.AddWithValue("Comment", HttpContext.Current.Request.Form("Comment"))
36: CMD.ExecuteNonQuery()
37: Catch ex As Exception
38: Dim CN1 As System.Data.SqlClient.SqlConnection
39: Dim CMD1 As Data.SqlClient.SqlCommand
40: CN1 = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
41: CN1.Open()
42: CMD1 = New Data.SqlClient.SqlCommand("INSERT [WebMoneyAviso]([PAYEE_PURSE], [PAYMENT_AMOUNT]) VALUES (@Raw, @Raw1)", CN1)
43: CMD1.CommandType = Data.CommandType.Text
44: CMD1.Parameters.AddWithValue("Raw", ex.Message)
45: '
46: Dim Buf1(10000) As Byte
47: If HttpContext.Current.Request.InputStream.Length < Buf1.Length Then
48: '
49: Dim ASCII As New System.Text.ASCIIEncoding
50: Dim ASCII_STR1 As String
51: Dim UNIC As New System.Text.UnicodeEncoding
52: Dim UNIC_STR1 As String
53: Dim Raw1 As String
54: '
55: While HttpContext.Current.Request.InputStream.CanRead
56: Dim CountReadingBytes As Integer = HttpContext.Current.Request.InputStream.Read(Buf1, 0, HttpContext.Current.Request.InputStream.Length)
57: If CountReadingBytes = 0 Then Exit While
58: ReDim Preserve Buf1(HttpContext.Current.Request.InputStream.Length)
59: '
60: Raw1 &= ("PostTest" & vbCrLf & vbCrLf)
61: Raw1 &= ("Request.ContentEncoding = " & HttpContext.Current.Request.ContentEncoding.ToString & vbCrLf)
62: Raw1 &= ("Request.ContentType = " & HttpContext.Current.Request.ContentType & vbCrLf)
63: Raw1 &= ("Request.ContentLength = " & HttpContext.Current.Request.ContentLength & vbCrLf & vbCrLf)
64: Raw1 &= ("Request.InputStream = ")
65: For i As Integer = 0 To HttpContext.Current.Request.ContentLength
66: Raw1 &= (String.Format(" {0:X2}", Buf1(i)))
67: Next
68: Raw1 &= (vbCrLf & vbCrLf)
69: '
70: ASCII_STR1 &= ASCII.GetString(Buf1)
71: UNIC_STR1 &= UNIC.GetString(Buf1)
72: '
73: ReDim Buf1(10000)
74: End While
75: Raw1 &= "ASCII = " & ASCII_STR1 & vbCrLf
76: Raw1 &= "UNICODE = " & UNIC_STR1 & vbCrLf
77: '
78: Raw1 &= (vbCrLf & "Request.Params " & vbCrLf & vbCrLf)
79: For i As Integer = 0 To HttpContext.Current.Request.Params.Count - 1
80: Raw1 &= ("(" & i.ToString & ") " & HttpContext.Current.Request.Params.Keys(i) & " = " & HttpContext.Current.Request.Params(HttpContext.Current.Request.Params.Keys(i)) & vbCrLf)
81: Next
82: '
83: CMD1.Parameters.AddWithValue("Raw1", Raw1)
84: End If
85: CMD1.ExecuteNonQuery()
86: End Try
87: '
88: If CN IsNot Nothing Then
89: If CN.State.Open Then
90: CN.Close()
91: End If
92: End If
93: '
94: context.Current.Response.Redirect("Default.aspx")
95: End Sub
96:
97: Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
98: Get
99: Return False
100: End Get
101: End Property
102:
103: End Class
Примерно так же устроен и шлюз робокассы. Там тоже требуется два осмысленных хандлера - Result и Success. Небольшая заморочка заключается в проверке MD5-хеша в хандлере Result. Это я делаю так:
1: <%@ WebHandler Language="VB" Class="Result2" %>
2: Imports System
3: Imports System.Web
4: Public Class Robo_Result : Implements IHttpHandler
5:
6: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
7: 'уведомления об исполнении операции
8: Dim sMrchPass2 As String = "JujWLopJW87%@),762KDXkjwe6"
9: Dim OutSum As String
10: If context.Current.Request.Form("OutSum") IsNot Nothing Then
11: If context.Current.Request.Form("OutSum") <> "" Then
12: OutSum = context.Current.Request.Form("OutSum")
13: End If
14: End If
15: Dim InvId As String
16: If context.Current.Request.Form("InvId") IsNot Nothing Then
17: If context.Current.Request.Form("InvId") <> "" Then
18: InvId = context.Current.Request.Form("InvId")
19: End If
20: End If
21: Dim sCrc As String
22: If context.Current.Request.Form("SignatureValue") IsNot Nothing Then
23: If context.Current.Request.Form("SignatureValue") <> "" Then
24: sCrc = context.Current.Request.Form("SignatureValue")
25: End If
26: End If
27: Dim sCrcBase As String = String.Format("{0}:{1}:{2}", OutSum, InvId, sMrchPass2)
28: '
29: Dim md5 As System.Security.Cryptography.MD5CryptoServiceProvider = New System.Security.Cryptography.MD5CryptoServiceProvider()
30: Dim bSignature() As Byte = md5.ComputeHash(Encoding.ASCII.GetBytes(sCrcBase))
31: '
32: Dim sbSignature = New StringBuilder()
33: For Each One As Byte In bSignature
34: sbSignature.AppendFormat("{0:x2}", One)
35: Next
36: If sbSignature.ToString.ToUpper <> sCrc.ToUpper Then
37: context.Response.ContentType = "text/plain"
38: HttpContext.Current.Response.Write("bad sign")
39: Exit Sub
40: Else
41: context.Response.ContentType = "text/plain"
42: HttpContext.Current.Response.Write(String.Format("OK{0}", InvId))
43: 'писать в базу ничего не будем, запишем в Success
44: End If
45: End Sub
46:
47: Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
48: Get
49: Return False
50: End Get
51: End Property
52:
53: End Class
При успешной оплате робокасса вызывает согласно моим настройкам хандлер Success, который у меня выглядит вот так:
1: <%@ WebHandler Language="VB" Class="Success2" %>
2: Imports System
3: Imports System.Web
4: Public Class Robo_Success : Implements IHttpHandler
5:
6: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
7: 'уведомления об исполнении операции
8: Dim sMrchPass2 As String = "3_4jhs&do$i2kjgMsaW(EghAas"
9: Dim OutSum As String
10: If context.Current.Request.Form("OutSum") IsNot Nothing Then
11: If context.Current.Request.Form("OutSum") <> "" Then
12: OutSum = context.Current.Request.Form("OutSum")
13: End If
14: End If
15: Dim InvId As String
16: If context.Current.Request.Form("InvId") IsNot Nothing Then
17: If context.Current.Request.Form("InvId") <> "" Then
18: InvId = context.Current.Request.Form("InvId")
19: End If
20: End If
21: Dim sCrc As String
22: If context.Current.Request.Form("SignatureValue") IsNot Nothing Then
23: If context.Current.Request.Form("SignatureValue") <> "" Then
24: sCrc = context.Current.Request.Form("SignatureValue")
25: End If
26: End If
27: Dim sCrcBase As String = String.Format("{0}:{1}:{2}", OutSum, InvId, sMrchPass2)
28: '
29: Dim md5 As System.Security.Cryptography.MD5CryptoServiceProvider = New System.Security.Cryptography.MD5CryptoServiceProvider()
30: Dim bSignature() As Byte = md5.ComputeHash(Encoding.ASCII.GetBytes(sCrcBase))
31: '
32: Dim sbSignature = New StringBuilder()
33: For Each One As Byte In bSignature
34: sbSignature.AppendFormat("{0:x2}", One)
35: Next
36: If sbSignature.ToString.ToUpper <> sCrc.ToUpper Then
37: context.Response.ContentType = "text/plain"
38: HttpContext.Current.Response.Write("bad sign")
39: Exit Sub
40: Else
41: context.Response.ContentType = "text/plain"
42: HttpContext.Current.Response.Write("Thank you for using our service")
43: End If
44: '
45: Dim CN As System.Data.SqlClient.SqlConnection
46: Dim CMD As Data.SqlClient.SqlCommand
47: '
48: Try
49: CN = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
50: CN.Open()
51: CMD = New Data.SqlClient.SqlCommand("AddRoboAviso", CN)
52: CMD.CommandType = Data.CommandType.StoredProcedure
53: CMD.Parameters.AddWithValue("Sum", HttpContext.Current.Request.Form("OutSum"))
54: CMD.Parameters.AddWithValue("Id", HttpContext.Current.Request.Form("OutSum"))
55: CMD.Parameters.AddWithValue("Comment", HttpContext.Current.Request.Form("Comment"))
56: CMD.ExecuteNonQuery()
57: Catch ex As Exception
58: Dim CN1 As System.Data.SqlClient.SqlConnection
59: Dim CMD1 As Data.SqlClient.SqlCommand
60: CN1 = New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("SQLServer_ConnectionStrings").ConnectionString)
61: CN1.Open()
62: CMD1 = New Data.SqlClient.SqlCommand("INSERT [RoboAviso]([Sum], [Id], [Comment]) VALUES ('0','0', @Raw)", CN1)
63: CMD1.CommandType = Data.CommandType.Text
64: CMD1.Parameters.AddWithValue("Raw", ex.Message)
65: CMD1.ExecuteNonQuery()
66: End Try
67: '
68: If CN IsNot Nothing Then
69: If CN.State.Open Then
70: CN.Close()
71: End If
72: End If
73: End Sub
74:
75: Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
76: Get
77: Return False
78: End Get
79: End Property
80:
81: End Class
Для MoneyBooker требуется один хандлер - Success. В нем надо формировать XML с ответом - ровно так же, как я показал выше для шлюза с Яндексом.
Что касается Plimus, то на данный момент я к сожалению пока не знаю, как принять онлайновое уведомление о платеже из этой платежной системы. Если Плимус высылает только мыльные сообщения, то для приема оповещений о платежах нужен собственный SMTP-сервер на Web-портале. Для такого SMTP-шлюза придется взять любой хорошо отлаженный исходный код почтового сервера, например LumiSoft Mail Server и прикрутить его к Web-порталу. Но по этому вопросу окончательного мнения у меня пока нет.
Зато я точно знаю как надо организовывать таймаут (для любого из указанных платежных систем). Организация таймаута нужна в тех случаях, когда нельзя держать купленый в онлайне товар бесконечное время забронированным для некоторого покупателя. Обычно логика сайта подразумевает оплату заказанного товара в течении допустим получаса. Если оплата не произошла, то выбранный товар считается разбронированным. Как это делается, я описал здесь - Реализация таймаута на динамически создаваемых SQL JOB, вызывающих SQL CLR сборку.
|