Курс валют на сайте
Практически на всех сайтах сегодня надо показывать курс валют. В сущности, в стране, которую чекистская военная хунта сделала сырьевым придатком мировой экономики - ничего кроме сырья (и уголовных дел) не производится воовсе. И как всегда, в очередном моем сайте - все расчеты завязаны на курсе валют.
У меня появился свободный часок и решил показать всем махонький кусочек живого кода этого проекта - небольшой рецептик на сто кликов мышкой - как я обычно учитываю курс валют в своих сайтах на билогетсовской платформе.
ШАГ1. Для начала создадим вот такую табличку и индекс к ней:
1: CREATE TABLE [dbo].[Curs](
2: [i] [int] IDENTITY(1,1) NOT NULL,
3: [CrDate] [datetime] NOT NULL,
4: [SetDate] [datetime] NOT NULL,
5: [Vname] [nvarchar](100) NOT NULL,
6: [Vnom] [int] NOT NULL,
7: [Vcurs] [money] NOT NULL,
8: [Vcode] [int] NOT NULL,
9: [VchCode] [nvarchar](3) NOT NULL
10: ) ON [PRIMARY]
11:
12: GO
13:
14: CREATE NONCLUSTERED INDEX [IX_Curs] ON [dbo].[Curs]
15: (
16: [i] ASC
17: )
18: WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
19: ON [PRIMARY]
20:
21: GO
Как вы понимаете, это биголейтсовский SQL-сервер. В данном сайте применение этого сервера вызвано не моей глубокой любовью к Биллу Гейтсу или неумением использовать SQLite, PostgreSQL, MySQL и другие сервера, а требованиями заказчика к сайту.
Итак, создадим процедурку для записи курса в табличку. Здесь может быть две политики - накапливть курс по дням и не накапливать. Люди, которые ничего не понимают в практическом удобстве эксплуатации сайтов - создают накопительную табличку с курсами по дням. Но этот детский сад давно прошел - и в моих сайтах таблички не разрастаются со временем. Поэтому вот такая процедура прогоняется ровно один раз:
1: ALTER procedure [dbo].[SetCurs]
2: @SetDate datetime,
3: @Vname nvarchar(100),
4: @Vnom money,
5: @Vcurs money,
6: @Vcode integer,
7: @VchCode nvarchar(3)
8: as
9: INSERT INTO [FlySeason].[dbo].[Curs]
10: ([CrDate]
11: ,[SetDate]
12: ,[Vname]
13: ,[Vnom]
14: ,[Vcurs]
15: ,[Vcode]
16: ,[VchCode])
17: VALUES
18: (GETDATE()
19: ,@SetDate
20: ,@Vname
21: ,cast(@Vnom as integer)
22: ,@Vcurs
23: ,@Vcode
24: ,@VchCode)
25: GO
А после первого прогона эта процедура становится вот такой:
1: ALTER procedure [dbo].[SetCurs]
2: @SetDate datetime,
3: @Vname nvarchar(100),
4: @Vnom money,
5: @Vcurs money,
6: @Vcode integer,
7: @VchCode nvarchar(3)
8: as
9: --INSERT INTO [FlySeason].[dbo].[Curs]
10: -- ([CrDate]
11: -- ,[SetDate]
12: -- ,[Vname]
13: -- ,[Vnom]
14: -- ,[Vcurs]
15: -- ,[Vcode]
16: -- ,[VchCode])
17: -- VALUES
18: -- (GETDATE()
19: -- ,@SetDate
20: -- ,@Vname
21: -- ,cast(@Vnom as integer)
22: -- ,@Vcurs
23: -- ,@Vcode
24: -- ,@VchCode)
25: UPDATE [FlySeason].[dbo].[Curs]
26: SET [CrDate] = GETDATE()
27: ,[SetDate] = @SetDate
28: ,[Vcurs] = @Vcurs
29: WHERE [VchCode] = @VchCode
30: GO
Теперь нам потребуется сделать процедурку для отбора курса по коду валюты, потому что валют, как вы понимаете, существует много:
1: CREATE procedure [dbo].[GetCurs]
2: @Code nvarchar(3)
3: as
4: select top(1) * from [dbo].[Curs]
5: where VchCode=@Code
6: order by i desc
Это все что нам нужно на уровне SQL. Там у нас будут данные, которые вы видите на табличке ниже и мы можем их читать процедурой GetCurs и обновлять процедурой SetCurs.
ШАГ2.Теперь нужно выбрать метд доступа к базе. Ну в принципе я практикую множество методов, самый на мой взгляд полезный - моя собственная универсальная обвязка, позволяющая обращаться к любому SQL-серверу, минуя сервисы, предоставляемые Биллом Гейтсом - вот она для MySQL. Впрочем я иногда пользуюсь LINQ и другими чудо-сервисами, написанными индусами по заказу Билла Гейтса. В этом проекте я уже начал все делать на LINQ TO SQL.
Итак, делаю два клика мышкой и перетаскиваю обе процы (GetCurs и SetCurs) на панель Linq to sql. Студия вычитывает типы параметров этих процедур и создает враппер, который будет мне давать в подсказке точные типы параметров для вызова этих процедур.
ШАГ3.Теперь создадим клиента к любому web-сервису, который транслирует в интернет курс валют. О клиентах к веб-сервисам у меня на сайте много написано, есть и мой собственный альтернативный микрософтовскому клиент. У меня на сайте немало написано и как самому создать такой же web-сервис, какой работает на сервере центробанка. Но в данном случае - это простейший коммерческий сайт и задача состоит в том, чтобы решить всю эту проблему за минимальное количество кликов мышкой. Получится за сто кликов - отлично. А если за пятьдесят - еще лучше.
Поэтому тыкаем в студии добавление ссылки на Web-сервис центробанка РФ.
И делаем тестик в одну строку.
Упс, все работает. Теперь ШАГ4. - делаем наш основной метод на 10 строчек, который будет сохранять курс в базу.
1: Public Class ReadCurs
2: Public Sub GO()
3: Dim DB2 As New FlySeasonDataContext
4: Try
5: Dim Curs As New CursValut.DailyInfoSoapClient
6: Dim LatestDateTime As Date = Curs.GetLatestDateTime
7: Dim X As Data.DataSet = Curs.GetCursOnDate(Now)
8: Dim DB1 As New FlySeasonDataContext
9: For Each One As Data.DataRow In X.Tables(0).Rows
10: DB1.SetCurs(LatestDateTime, One(0).ToString.TrimEnd, One(1), One(2), One(3), One(4).ToString.TrimEnd)
11: Next
12: Catch ex As Exception
13: DB2.SaveLoadError("Curs " & ex.Message)
14: End Try
15: End Sub
16: End Class
ШАГ5. Теперь надо вызывать обновление курса валют периодически (не реже одного раза в сутки - лучше раз в час). Как делаются периодические задачки - я описывал на своем сайте множество раз, например вот так Реализация таймаута на динамически создаваемых SQL JOB, вызывающих SQL CLR сборку. Но в этом сайте заморачиваться нет необходимости - создаем периодическую задачу в самом найпростейшем варианте. Добавляем к проекту Global.ASAX и вносим в него вот такой копеечный код на 10 строчек:
1: <%@ Application Language="VB" %>
2:
3: <script runat="server">
4:
5: Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
6: ' Code that runs on application startup
7: Dim GetCursThread As System.Threading.Thread = New System.Threading.Thread(AddressOf GetCursSub)
8: GetCursThread.Name = "GetCursThread (Started " & Now.ToString & ")"
9: Application("GetCursThread") = GetCursThread
10: Application("GetCursInterval") = System.Configuration.ConfigurationManager.AppSettings("GetCursInterval")
11: If System.Configuration.ConfigurationManager.AppSettings("GetCursThread") Then GetCursThread.Start()
12: End Sub
13:
14: Sub GetCursSub()
15: Dim X As New ReadCurs
16: Dim DB1 As New FlySeasonDataContext
17: While True
18: System.Threading.Thread.Sleep(CInt(Application("GetCursInterval")) * 3600000)
19: 'диагностика фонового процесса
20: Dim ClearJobThread As System.Threading.Thread = CType(Application("GetCursThread"), System.Threading.Thread)
21: DB1.SaveLoadError(ClearJobThread.Name & " started at " & Now.ToString)
22: X.GO()
23: End While
24: End Sub
25:
26: </script>
В конфиге поведением этого потока управляет два параметра:
1: <configuration>
2: <appSettings>
3: <!-- Чтение курса валют -->
4: <add key="GetCursThread" value="True"/>
5: <!-- интервал перезапуска задачи чтение курса валют 1час -->
6: <add key="GetCursInterval" value="1"/>
7: ...
Вот протокол почасового считывания курса:
И наконец, последний ШАГ6 - используем данные о курсе валют. Понятно, что само по себе использование курса валют в разнообразных платежных шлюзах, да и вообще в банковских операциях - это тема совершенно необьятная. Поэтому я покажу самое минимально возможное использование полученного курса - просто отображение его на форме.
Для этого находим нужный контрол и вносим в него вот такой копеечный код на три строчки:
1: Partial Class Kurs
2: Inherits System.Web.UI.UserControl
3:
4: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not IsPostBack Then
6: Dim DB1 As New FlySeasonDataContext
7: Dim EUR As Decimal = DB1.GetCurs("EUR")(0).Vcurs
8: Dim USD As Decimal = DB1.GetCurs("USD")(0).Vcurs
9: l_EUR.Text = EUR.ToString("N2")
10: l_USD.Text = USD.ToString("N2")
11: End If
12: End Sub
13: End Class
Ну вот собственно и все. Похоже в этом рецепте, как и во многих других своих других рецептах - уложился в сто кликов мышкой.
|