Реализация
Опишем некоторые детали реализации.
· Данные хранимые в специальных таблицах-словарях базы данных будем загружать один раз при старте приложения:
void Application_Start(object sender, EventArgs e)
{
Web.Environment.Procedures.Init();
Web.Environment.Words.Init();
Web.Environment.Elements.Init();
}
· Система будет поддерживать несколько языков, соответственно для идентификации текста будем использовать числовые идентификаторы. При получении строки будем пользоваться классом Words:
public class Words
{
private static Dictionary> wordsDictionary;
public static Dictionary> WordsDictionary
{
get { return Words.wordsDictionary; }
}
private static bool valid;
public static bool Valid
{
get { return Words.valid; }
}
public static void Init()
{
wordsDictionary = Procedures.WordsSelect();
valid = true;
}
public static string GetWord(int languageId, int wordId, params object[] args)
{
string wordText = null;
wordsDictionary[languageId].TryGetValue(wordId, out wordText);
if (string.IsNullOrEmpty(wordText))
{
wordsDictionary[languageId].TryGetValue(NO_NAME, out wordText);
if (string.IsNullOrEmpty(wordText))
{
return "No name";
}
return GetParametrizedWords(wordText, args);
}
else
{
return GetParametrizedWords(wordText, args);
}
}
private static string GetParametrizedWords(string wordText, params object[] args)
{
if (args == null)
{
return wordText;
}
StringBuilder wordTextBuild = new StringBuilder();
wordTextBuild.AppendFormat(wordText, args);
return wordTextBuild.ToString();
}
public static string GetWord(int languageId, int wordId)
{
return GetWord(languageId, wordId, null);
}
}
· При занесении в систему пользовательских данных, способ хранения описанный выше не подходит из-за возможных конфликтов в идентификаторах фраз. Разработка системы ведется на отдельной базе – копии настоящей, идентификаторы новых фраз жестко используются в интерфейсах. Если бы пользователи могли собственноручно заносить новые фразы, это привело бы к коллизиям при переносе фраз созданные в отдельной базе. Поэтому пользовательские фразы будут храниться в XML, и обеспечивать работу с этими данными будет класс:
public class MultilangString
{
public MultilangString()
{
foreach (Currencies currency in Enum.GetValues(typeof(Currencies)).Cast())
{
if (currency == Currencies.NONE)
{
continue;
}
items.Add(currency, string.Empty);
}
}
public MultilangString(string xml) : this()
{
StringReader reder = new StringReader(xml);
foreach (XElement str in XElement.Load(reder).Descendants("string"))
{
Currencies cur = (Currencies)Enum.Parse(typeof(Currencies), str.Attribute("Language").Value);
items[cur] = str.Attribute("Value").Value;
}
}
private Dictionary items = new Dictionary();
public string this[short curId]
{
get
{
Currencies cur = (Currencies)curId;
return this[cur];
}
set
{
Currencies cur = (Currencies)curId;
this[cur] = value;
}
}
public string this[Currencies cur]
{
get
{
if (items.ContainsKey(cur))
{
return items[cur];
}
return string.Empty;
}
set
{
if (items.ContainsKey(cur))
{
items[cur] = value;
}
}
}
public List> ToList()
{
return items.ToList();
}
public string ToXml()
{
XElement strings = new XElement("Strings");
foreach (var pair in items.Where(p => !string.IsNullOrEmpty(p.Value)))
{
strings.Add(
new XElement("string",
new XAttribute("Language", pair.Key),
new XAttribute("Value", pair.Value)));
}
return strings.ToString();
}
}
Основные типы данных
1. Компонент. Единица товара, изготавливаемая на производстве. Каждый компонент наделен уникальным десятизначным номером. Материалы, необходимые для производства компонента зависят от спецификации.
Рис 10. Структура продукта
2. Материал. Закупаемая единица используется при производстве компонентов. Материал характеризуется ценой и классом.
Рис 11. Структура материала
3. Спецификация. Содержит набор материалов необходимых для производства компонента. Спецификация идентифицируется уникальным номером.
Рис 12. Структура спецификации
4. Менеджер. Выполняет роль куратора заказа.
5. Аналоги. Содержит материалы, которые можно взаимозаменить при производстве компонента.
6. Остатки. Материалы, хранимые на производстве.
Рис 13. Структура остатков
7. Заказ. Описывает заказ на компоненты. Может находиться в одной из пяти стадий: прогноз, план, заказ, производство, закрыт.
Рис 14. Структура заказа.
Уровень бизнес-логики
Бизнес-объекты используемые в системе делятся на два вида.
Первые - объекты содержащие информацию принятую из базы данных. Эти объекты часто выстроены в иерархию, для того, чтобы в разных вариантах использования, использовалась только необходимая часть данных, что уменьшает нагрузку на сервер.
public class ComponentItemBaseInformation
{
protected int componentId;
public int ComponentId
{
get { return componentId; }
set { componentId = value; }
}
protected int componentTypeId;
public int ComponentTypeId
{
get { return componentTypeId; }
set { componentTypeId = value; }
}
protected string custPartNumber;
public string CustPartNumber
{
get { return custPartNumber; }
set { custPartNumber = value; }
}
protected string description;
public string Description
{
get { return description; }
set { description = value; }
}
public string DescriptionView
{
get
{
return description;
}
}
private int producerId;
public int ProducerId
{
get { return producerId; }
set { producerId = value; }
}
}
Рис 15. Отношения классов
Второй – объекты-менеджеры предоставляющие возможность управлять объектами описанными выше:
Рис 16. Классы-менеджеры
Уровень доступа к данным
Доступ к базе данных осуществляется с помощью хранимых процедур:
using (SqlDataReader rd = cmd.ExecuteReader())
{
ComponentItemGeneral tmpComponentItem;
while (rd.Read())
{
tmpComponentItem = new ComponentItem();
tmpComponentItem.ComponentId = (Int32)rd["ComponentID"];
tmpComponentItem.ComponentTypeId = (Int32)rd["ComponentTypeID"];
tmpComponentItem.CustPartNumber = rd["CustPartNumber"].ToString();
tmpComponentItem.Description = Convert.ToString(rd["Description"]);
tmpComponentItem.DescriptionRussian = Convert.ToString(rd["DescriptionRussian"]);
tmpComponentItem.IsActive = Convert.ToBoolean(rd["IsActive"]);
tmpComponentItem.ManufacturerId = Convert.ToInt32(rd["ManufacturerID"]);
tmpComponentItem.RevisionDate = Convert.ToDateTime(rd["RevisionDate"]);
tmpComponentItem.ComponentPrice = Convert.ToDouble(rd["ComponentPrice"]);
tmpComponentItem.CurrencyID = (Currencies) Convert.ToInt16(rd["CurrencyID"]);
tmpComponentItem.Tags = Convert.ToString(rd["Tags"]);
tmpComponentItem.ProducerId = Convert.ToInt32(rd["ProducerID"]);
collection.Add(tmpComponentItem);
}
}
Все хранимые процедуры начинаются с проверки пользователя:
EXEC p_Logon_Check @intGroupId = @intGroupId OUT,
@strGuid = @strGuid,
@intUserId = @intUserId OUT
IF @intUserId IS NULL
BEGIN
RETURN
END
IF @intGroupId is null
BEGIN
RETURN
END
Сами же процедуры представляют собой обычные SQL-запросы
SELECT
b.[ComponentID]
,[ComponentGroupID]
,b.[ComponentTypeID]
,[CustPartNumber]
,[Description]
,CASE @DescriptionRussianConcat
WHEN 1 THEN [DescriptionRussian] + ' ' + [Description]
ELSE [DescriptionRussian] END AS [DescriptionRussian]
,[PricesPerUnit]
,[ManufacturerID]
,[IsActive]
,[RevisionDate]
,[PcsPerPackage]
,[WeightNetPackage]
,[WeightBruttoPackage]
,[DimX]
,[DimY]
,[DimZ]
,[ComponentPrice]
,[CurrencyID]
,[PriceDate]
,[MinStock]
,[MarginForLoss]
,[Picture]
,b.Tags
,b.ProducerID
FROM dbo.List_BOM b
INNER JOIN Component_Prices cp ON cp.PriceID = b.PriceID
INNER JOIN Ref_Maker m ON m.MakerID = b.ManufacturerID
INNER JOIN List_ComponentTypes ct ON ct.ComponentTypeID = b.ComponentTypeID
WHERE b.[ComponentID] in (select [ComponentID] FROM @TempComponents)
ORDER BY
CASE @SortingType
WHEN 0 THEN CustPartNumber
WHEN 1 THEN ct.ComponentDescription
WHEN 2 THEN Description
WHEN 3 THEN m.TitleName
WHEN 5 THEN DescriptionRussian
END,
CASE @SortingType
WHEN 6 THEN cp.[ComponentPrice]
WHEN 7 THEN [CurrencyID]
END,
CASE @SortingType
WHEN 4 THEN RevisionDate
END DESC
Уровень представления
Отображение данных на страницах производится с использованием модели «поставщики данных». Эта модель включает специальные объекты – DataSource, предоставляющие данные:
<asp:ObjectDataSource ID="odsAnalogs" runat="server"
OnObjectCreating="odsAnalogs_ObjectCreating"
OnSelecting="odsAnalogs_Selecting"
SelectMethod="AnalogElementsSelect"
TypeName="GS.MConvoy.Web.Tables.ComponentItems"
OnUpdated="odsAnalogs_Updated"
OnUpdating="odsAnalogs_Updating"
UpdateMethod="AnalogComponentsUpdate"
DeleteMethod="AnalogComponentDelete"
OnDeleted="odsAnalogs_Deleted"
OnDeleting="odsAnalogs_Deleting">
SelectParameters>
asp:ObjectDataSource>
Эти объекты взаимодействуют с объектами-менеджерами с бизнес-уровня, для получения информации из базы данных. Для отображения используются другие объекты. Будучи подключенными к источнику данных, они отображают данные по заданному шаблону:
SkinID="ComponentPage"
AllowPaging="True"
PageSize="13" AutoGenerateColumns="False"
DataSourceID="odsAnalogs"
OnDataBound="grvAnalogs_DataBound"
DataKeyNames="ComponentId"
OnRowDeleting="grvAnalogs_RowDeleting">
Position="TopAndBottom" />
ShowDeleteButton="True" />
ID="lnkCustPartNumber"
Text='<%# Eval("CustPartNumber")%>'
NavigateUrl='<%#Eval("ComponentLink")%>'>
HeaderText="Description" ReadOnly="true"
SortExpression="Description" />
HeaderText="ComponentPrice" ReadOnly="true"
SortExpression="ComponentPrice" />
HeaderText="CurrencyName" ReadOnly="true"
SortExpression="CurrencyName" />
HeaderText="ManufacturerIdView" ReadOnly="true"
SortExpression="ManufacturerIdView" />
HeaderText="RevisionDateView" ReadOnly="true"
SortExpression="RevisionDateView" />
Columns>
asp:GridView
Выводы
В ходе работы был разработан модуль для автоматизации бизнес-процессов при работе с заказами на производственной фирме. Модуль включает в себя подсистему управления данными о продукте, подсистему управления остатками, подсистему управления заказами.
В ходе данной работы были достигнуты следующие результаты:
· Изучены существующие решения в сфере автоматизации производства
· Изучена платформа .Net, созданная для разработки приложений
· Разработано техническое задание и спецификация системы
· Разработана архитектура системы
· Реализовано приложение, отвечающее заданным требованиям
· Приложение протестировано. Найденные ошибки устранены.
Комментариев нет:
Отправить комментарий