Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
[1] Оглавление [2] Характеристика объекта автоматизации [3] Краткое техническое задание на разработку автоматизированной системы [4] Функциональная модель системы обработки заявок [5] Модель базы данных системы обработки заявок [6] Проектирование интерфейса [7] Разработка системы. Выбор средств реализации. [8] Реализация [9] Листинг основных классов программы [10] Глоссарий [11] Заключение [12] Список использованных источников |
Причин, по которым руководство остается недовольным качеством корпоративных информационных технологий (ИТ), много. Часть из них находится в области управления проектами внедрения ИТ. Далеко не всегда проекты завершаются в заданный срок и в рамках выделенных бюджетов. Но даже тогда, когда проекты заканчиваются, становятся актуальными ежедневные вопросы, связанные с использованием ИТ, которые во многом формируют мнение о качестве работы ИТ:
И так далее.
Решение вопросов через руководителей далеко не самый эффективный путь. Необходимо налаживание горизонтальных связей, позволяющих построить взаимодействие сотрудников на всех уровнях. Необходим структурированный подход, позволяющий сделать работу департамента ИТ эффективной и рациональной. Этот подход стал стандартом де-факто в мире для формирования ИТ-службы как современного бизнес-подразделения, то есть департамента, постоянно ориентированного на потребности своих пользователей, нацеленного на решение изменяющихся задач при сохранении прозрачности для руководства с точки зрения достигнутого уровня качества и используемых ресурсов. Опыт показывает, что рассматриваемые принципы организации деятельности актуальны как для небольших, так и для крупных компаний и не зависят от того, передается ли сопровождение ИТ на аутсорсинг или организуется внутренними силами. Качественно работающий ИТ-департамент это задача, ставшая актуальной для многих современных российских компаний.
С ростом зависимости бизнес-процессов от информационных технологий растёт и ущерб, наносимый бизнесу простоями и некорректной работой ИТ-услуг. Процесс управления заявками пользователей призван обеспечить скорейшее восстановление предоставления ИТ-услуг на должном уровне. Для решения этой задачи в рамках процесса выполняется контролируемая регистрация заявок, точное оперативное назначение специалистам (инженерам), диагностика и ремонт компонентов ИТ-инфраструктуры.
Информация о заявках часто поступает к поставщику услуг от пользователей, столкнувшихся с трудностями при выполнении бизнес-операций. Для обеспечения эффективных коммуникаций между пользователями и поставщиком ИТ-услуг организуется служба поддержки пользователей Service Desk.
По данным зарубежных ИТ-аналитиков, 45% происходящих на рабочих местах пользователей инцидентов требуют выхода инженера на место инцидента для сбора информации об имуществе, его конфигурации, подключениях к сети, установленном ПО и т.п. Если эта информация будет доступна инженеру со своего рабочего места, то затраты на разрешение инцидента сокращаются в среднем на 25%.
Предположим:
Штат ИТ-службы компании
30 человек
Средняя заработная плата ИТ-специалиста
21 000 рублей
Количество пользовательских рабочих мест в компании
1500
Среднее количество заявок по инцидентам
760
Среднее время, затрачиваемое инженером на закрытие одного инцидента - 4 часа
Тогда:
Стоимость обслуживания 1 рабочего места в месяц:
(30х21000)/1500=420 рублей
Количество заявок, требующих выхода на место инцидента:
760х0,45=342
Экономия времени при внедрении Service Desk на решение одного инцидента:
4х0,25=1 час
Экономия времени по всем инцидентам за месяц:
342х1=342 часа
Час работы специалиста стоит:
21000/22/8=120 рублей
Экономия времени
за месяц 120*342=41 040 рублей, за год 41 040х12=492 480 рублей.
С другой стороны, сокращается время простоев пользователей. При средней заработной плате сотрудников компании 15 000 рублей 342 часа экономии в месяц на простоях выражаются суммой в (15000/22/8)х342х12=349 773 рубля в год.
Суммарный эффект 842 253 рубля в год
Данный расчёт весьма грубый, принимающий за основу лишь заработную плату и не учитывающий множества других факторов, заметно повышающих выведенную цифру.
В частности, полномасштабный запуск системы создаёт постоянно накапливаемую информационную основу для совершенствования регламентов и методик, применяемых для повышения качества предоставляемых пользователям услуг (базу знаний по возникающим решениям). Такое совершенствование также значительно снижает время обработки инцидентов и простоев по их вине. По данным известного независимого аналитического агентства Giga Information Group время разрешения инцидентов на рабочих местах сокращается при этом на 30-40%
В соответствии с ГОСТ 34.601-90, настоящий стандарт распространяется на автоматизированные системы (АС), используемые в различных видах деятельности (исследование, проектирование, управление и т.п.), включая их сочетания, создаваемые в организациях, объединениях и на предприятиях (далее - организациях).
Стандарт устанавливает стадии и этапы создания АС.
Стадии и этапы создания АС выделяются как части процесса создания по соображениям рационального планирования и организации работ, заканчивающихся заданным результатом. Работы по развитию АС осуществляют по стадиям и этапам, применяемым для создания АС. Состав и правила выполнения работ на установленных настоящим стандартом стадиях и этапах определяют в соответствующей документации организаций, участвующих в создании конкретных видов АС.
Назначение и цели создания системы:
Целью создания автоматизированной системы заявок пользователей является обеспечение наиболее эффективного и скорейшего разрешения всех возникающих проблем и трудностей у пользователей, учет качества и объема работы специалистов (инженеров) группы технической поддержки, а также технических специалистов, занимающихся решением заявок пользователей.
Требования к функциям системы:
Система должна автоматизировано накапливать заявки пользователей в IT-отдел, автоматически сортировать их по проектам и исполнителям.
Данные о поступивших заявках должны отображаться у инженеров (исполнителей), в порядке их приоритета и времени поступления, должна существовать возможность сортировки заявок, аналитика времени их поступления и решения для учета скорости решения заявок руководителями (координаторами).
Система должна хранить данные о поступающих заявках, их статусах исполнения, комментариях, добавленных в процессе работы над заявками, с возможностью формирования отчётов по работе инженеров как в отдельности, так и всего отдела за необходимый период.
Система должна информировать инженера о поступившей заявке, а также его руководителя (координатора), оператора, о том, что его заявка принята на исполнение или решена, а также о всех движениях заявки.
Требования к видам обеспечения информационному, техническому, программному, организационному:
Система должна работать при минимальных требованиях к аппаратному и программному обеспечению клиента, с любого узла корпоративной сети (компьютер, терминал, планшет, кпк, сотовый телефон). Система должна иметь интуитивно понятный интерфейс с возможностью максимального исключения возможных ошибок ввода (выбор из готовых списков, подбор варианта выбора за пользователя по контексту и т.д.)
Требования к персоналу:
Минимальные требования к знанию интерфейса Windows, умение пользоваться браузером, начальные навыки обращения с ПК.
Состав и содержание работ по созданию системы:
Порядок контроля и приемки системы:
Система должна работать согласно технического задания, то есть позволять создавать, заявки, просматривать их аналитику, контролировать выполнение.
Рис.1 Модель IDEF0 системы обработки заявок
Рис.2 Процесс обработки заявок пользователей (разделение на АРМы)
Рис. 3 ER-диаграмма базы данных для системы обработки заявок
Когда говорят о научных основах проектирования пользовательских интерфейсов, в первую очередь упоминают термин HCI. HCI это аббревиатура английского Human-Computer Interaction, что переводится как "взаимодействие человека и компьютера". На Западе HCI это целая профессия, ей обучают в университетах, выдавая дипломы "Специалист по HCI". Издается много журналов по этой теме, существует большое количество Web-сайтов. В России, к сожалению, эта наука не пользуется особой популярностью, например, у нас настоящих специалистов по HCI можно буквально пересчитать по пальцам одной руки.
Как легко догадаться по названию, составными частями HCI являются:
Пользовательский интерфейс (англ. user interface, UI) является своеобразным коммуникационным каналом, по которому осуществляется взаимодействие пользователя и компьютера.
Лучший пользовательский интерфейс это такой интерфейс, которому пользователь не должен уделять много внимания, почти не замечать его. Пользователь просто работает, вместо того, чтобы размышлять, какую кнопку нажать или где щелкнуть мышью. Такой интерфейс называют прозрачным пользователь как бы смотрит сквозь него на свою работу.
Чтобы создать эффективный интерфейс, который делал бы работу с программой приятной, нужно понимать, какие задачи будут решать пользователи с помощью данной программы и какие требования к интерфейсу могут возникнуть у пользователей. Это сделать гораздо легче, если вы используете свою программу для собственных нужд, ведь в данном случае вы являетесь не только разработчиком, но и пользователем программы, смотрите на нее глазами ее аудитории.
Огромную роль играет интуиция если разработчик сам терпеть не может некрасивые и неудобные интерфейсы, то при создании собственной программы он будет чувствовать, где и какой именно элемент нужно убрать или добавить. Необходимо иметь художественный вкус, чтобы понимать, что именно придаст интерфейсу красоту и привлекательность.
Западные исследователи в области HCI сформулировали основные принципы проектирования пользовательских интерфейсов компьютерных программ. Как и в любой другой науке, существует довольно много различных методик и классификаций, которые можно найти в книгах по HCI, выпушенных за рубежом, а также на иностранных Web-сайтах.
На рис 4 приведен схематичный план основного интерфейса программы.
ASP.NET MVC это платформа для разработки веб-приложений от Microsoft, которая сочетает в себе эффективность и аккуратность архитектуры «модель-представление-контроллер», новейшие идеи и приемы гибкой разработки, а также все лучшее из существующей платформы ASP.NET. Она представляет собой полномасштабную альтернативу традиционной технологии ASP.NET Web Forms, предоставляя существенные преимущества для всех проектов веб-разработки, кроме наиболее тривиальных. Новая платформа ASP.NET MVC обеспечила радикальный сдвиг в разработке веб приложений на платформе Microsoft. В ней делается упор на ясную архитектуру, шаблоны проектирования и тестируемость, и не предпринимается попыток сокрытия того, как работает веб-среда.
Термин модель представление контроллер (model view controller) используется с конца 70-х гг. прошлого столетия. Эта модель явилась результатом проекта Smalltalk в компании Xerox, где она была задумана как способ организации некоторых из ранних приложений графического пользовательского интерфейса. Некоторые из нюансов первоначальной модели MVC были связаны с концепциями, специфичными для Smalltalk, такими как экраны и инструменты, но более глобальные понятия все еще применимы к приложениям, и особенно хорошо они подходят для веб-приложений [5, с. 63].
Если оперировать понятиями высокого уровня, архитектурный шаблон MVC означает, что приложение MVC будет разделено, по крайней мере, на три части (рисунок 5).
Рисунок 5 Структурные части архитектурного шаблона MVC
Модели, содержащие или представляющие данные, с которыми работают пользователи. Они могут быть простыми моделями представлений, которые только представляют данные, передаваемые между представлениями и контроллерами; или же они могут быть моделями предметной области, которые содержат бизнес данные, а также операции, преобразования и правила для манипулирования этими данными.
Представления, применяемые для визуализации некоторой части модели в виде пользовательского интерфейса.
Контроллеры, которые обрабатывают поступающие запросы, выполняют операции с моделью и выбирают представления для визуализации пользователю.
В MVC контроллеры являются классами, обычно производными от класса System. Web. Mvc. Controller. Каждый метод public в классе, унаследованном от класса Controller, называется методом действия и посредством системы маршрутизации ASP.NET связан с конфигурируемым URL. Когда запрос отправляется URL, связанному с методом действия, операторы в классе контроллера выполняются, чтобы провести некоторую операцию по отношению к модели предметной области и затем выбрать представление для отображения клиенту. Взаимодействия между контроллером, моделью и представлением показаны на рисунке 6
Рисунок 6 Взаимодействия между контроллером, моделью и представлением
Для разработки программного продукта была выбрана технология ASP.NET MVC 3 и язык C#, являющийся самым популярным языком для написания бизнес логики на платформе.NET, основные преимущества технологии ASP.NET MVC 3:
Использование встроенного архитектурного шаблона MVC.
Расширяемость, так как платформа MVC построена в виде серии независимых компонентов реализующих интерфейс.NET или построенных на основе абстрактного базового класса, можно легко заменить систему маршрутизации, механизм визуализации, фабрику контроллеров или прочие компоненты платформы другими, с собственной специальной реализацией.
Жесткий контроль над HTML и HTTP. В платформе ASP.NET MVC учтена важность генерации ясного и соответствующего стандартам кода разметки. Ее встроенные вспомогательные методы HTML создают соответствующий стандартам вывод, но в ней реализовано и гораздо более значимое философское изменение по сравнению с Web Forms. Вместо громадного объема, трудно поддающегося управлению HTML-кода, платформа MVC стимулирует создание простых и элегантных, стилизованных с помощью CSS компонентов.
Тестируемость. Естественное разнесение различных задач приложения по разным, независимым друг от друга частям программного обеспечения, поддерживаемое архитектурой MVC. позволяет изначально строить легко сопровождаемые и тестируемые приложения. Однако проектировщики ASP.NET MVC на этом не остановились. Для каждого фрагмента компонентно-ориентированного дизайна платформы они обеспечили структурированность, необходимую для выполнения требований модульного тестирования и средств макетирования.
В качестве IDE была выбрана Visual Studio 2010 это интегрированная среда разработки Microsoft (IDE), являющейся самой функциональной IDE для разработки на платформе.NET.
Для модульного тестирования была выбрана встроенная поддержка в Visual Studio 2010 так как в настоящий момент функциональность встроенной поддержки ничуть не хуже, чем у конкурентов, а тесная интеграция с IDE ставит её на первое место.
Для хранения данных был выбрана СУБД SQL Server 2008 R2 от Microsoft. Из наиболее распространенных СУБД для создания базы данных выбрана СУБД MS SQL Server, так как она обладает всеми необходимыми средствами для создания и обеспечения работоспособности базы данных, поддерживает визуальную технологию создания объектов базы данных, стандарт языка SQL.
Рис. 7 Основной интерфейс программы
Рис. 8 Форма для подачи заявки
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Timers;
using PlanningService.DataClasses;
using System.Diagnostics;
namespace PlanningService
{
public class RequestComparer : IComparer<Request>
{
public int Compare(Request x, Request y)
{
if(x.CurrentStatus < y.CurrentStatus)
{
return -1;
}
else if (x.CurrentStatus > y.CurrentStatus)
{
return 1;
}
else
{
if (x.CurrentStatus == Status.WaitingOpen_StatusCode && y.CurrentStatus == Status.WaitingOpen_StatusCode && x.Type == y.Type && x.PlanningTime < 10 && y.PlanningTime < 10)
{
return 0;
}
else
{
if (y.Priority==1)
{
return 1;
}
else if (x.Priority==1)
{
return -1;
}
else
{
if (x.PlanningOnDate < y.PlanningOnDate)
{
return -1;
}
else if (x.PlanningOnDate > y.PlanningOnDate)
{
return 1;
}
else
{
return 0;
}
}
}
}
}
}
public class UserRequestComparer : IEqualityComparer<Request>
{
#region IEqualityComparer<Request> Members
public bool Equals(Request x, Request y)
{
if (x.ReqID == y.ReqID)
{
if (x.CurrentStatus == y.CurrentStatus && x.ExecutorID == y.ExecutorID && x.PlanningOnDate == y.PlanningOnDate && x.PlanningCompleteDate==y.PlanningCompleteDate)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
public int GetHashCode(Request obj)
{
return obj.GetHashCode();
}
#endregion
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class PlanningService : IService1
{
private ServiceResponse Response =null;
private List<UserContainer> UserList = null;
private static linqDataContext dc = null;
private static ViolationsDataContext vdc= null;
private RequestComparer ReqComparer = null;
public PlanningService()
{
Response = new ServiceResponse(false, "");
UserList = new List<UserContainer>();
dc = new linqDataContext();
vdc = new ViolationsDataContext();
ReqComparer = new RequestComparer();
SOTRUD user = null;
foreach (Sessions session in dc.Sessions)
{
user = dc.SOTRUD.SingleOrDefault(s => s.ID == session.EmployeeID);
if (user != null)
{
if (user.ID_SOTRUD_DOLG.HasValue)
{
SetWorkDay(user.ID, user.ID_SOTRUD_DOLG.Value, false, session.DuringTime);
}
}
}
}
private static UsersList ContainerToUser(UserContainer uc)
{
SOTRUD CurrentSotr = dc.SOTRUD.Single(s=>s.ID==uc.UserID);
return new UsersList { ID = CurrentSotr.ID, name = CurrentSotr.FIO, position = CurrentSotr.SOTRUD_DOLG.SOTRUD_DOLG1, BeginTime = uc.ComeTime.ToString(@"hh\:mm\:ss") };
}
private void AddViolation(Guid ReqID, string Type)
{
Violations V = new Violations{ Data=DateTime.Now, Request=ReqID, Type=Type };
vdc.Violations.InsertOnSubmit(V);
vdc.SubmitChanges();
}
public bool SetWorkDay(int id, int posID,bool itIsEnd, int minutes = 0)
{
if (!itIsEnd)
{
UserContainer CurrentContainer = UserList.SingleOrDefault(s => s.UserID == id);
if (CurrentContainer == null)
{
UserContainer NewContainer = new UserContainer(id, posID, dc);
NewContainer.ComeTime = NewContainer.ComeTime.Subtract(new TimeSpan(0, minutes, 0));
try
{
foreach (Request r in NewContainer.ReqList.FindAll(r=>r.CurrentStatus>Status.Opened_StatusCode && r.PlanningOnDate.Date<=DateTime.Now.Date && !r.PlannedRequest))
{
int ind = NewContainer.ReqList.IndexOf(r);
if (ind == 0)
{
r.PlanningOnDate = DateTime.Parse(GetPlanningTime(r.CreatorID, r.IsCycle, r.Type,r.Executor.LocationID.Value ,false, r.ExecutorID));
}
else
{
r.PlanningOnDate = NewContainer.ReqList[ind - 1].PlanningCompleteDate.Value.AddMinutes(5);
}
r.PlanningCompleteDate = r.PlanningOnDate.AddMinutes(r.PlanningTime);
}
dc.SubmitChanges();
UserList.Capacity++;
UserList.Add(NewContainer);
CheckForCyclicRequests();
return true;
}
catch
{
return false;
}
}
else
{
return false;
}
}
else
{
UserContainer Current = UserList.Single(s=>s.UserID==id);
int DepID = dc.SOTRUD.Single(s=>s.ID==id).ID_OTD;
Current.ReqList.ForEach(ListRequestHandlers.SetMinutesLeft);
dc.SubmitChanges();
List<Request> lreq = dc.Request.Where(r=>r.PlanningOnDate.Date==DateTime.Now.Date && r.ExecutorID==Current.UserID).ToList();
TimeSpan WorkedTime = DateTime.Now.TimeOfDay.Subtract(Current.ComeTime);
int RequestsPlanning = lreq.Count;
int RequestsExecuted = lreq.Where(r=>r.CurrentStatus>=Status.Completed_StatusCode).Count();
List<Request> forgrade = lreq.Where(r=>r.grade.HasValue).ToList();
int ViolCount = vdc.Violations.Where(r => r.Re.PlanningOnDate.Date == DateTime.Now.Date && r.Re.ExecutorID == Current.UserID).Count();
double AvgGrade = 0;
if (forgrade.Count > 0)
{
AvgGrade = forgrade.Average(a => a.grade.Value);
}
Tabel tab = new Tabel
{
BeginWorkTime = DateTime.Now.Subtract(WorkedTime),
EndWorkTime = DateTime.Now,
ExecutorID = Current.UserID,
TimeOnBreak = Current.TimeInBreak,
RequestsAssigned = RequestsPlanning,
RequestsExecuted = RequestsExecuted,
AverageGrade = Convert.ToDecimal(AvgGrade),
ViolationsCount = ViolCount,
ViolationsPercent = RequestsExecuted != 0 ? ViolCount / RequestsExecuted : 0,
DepID= DepID
};
vdc.Tabel.InsertOnSubmit(tab);
vdc.SubmitChanges();
bool Deleted = UserList.Remove(Current);
return false;
}
}
private void DeleteSession(int uid)
{
try
{
Sessions session = dc.Sessions.SingleOrDefault(s => s.EmployeeID == uid);
if (session != null)
{
dc.Sessions.DeleteOnSubmit(session);
dc.SubmitChanges();
}
}
catch
{
}
}
private void WriteSession(int uid, int minutes)
{
try
{
Sessions session = dc.Sessions.SingleOrDefault(s => s.EmployeeID == uid);
if (session == null)
{
session = new Sessions { DuringTime = minutes, ID = Guid.NewGuid(), EmployeeID = uid };
dc.Sessions.InsertOnSubmit(session);
}
else
{
session.DuringTime = minutes;
}
dc.SubmitChanges();
}
catch
{
}
}
public bool ToggleBreak(int UID)
{
UserContainer Current = UserList.SingleOrDefault(s => s.UserID == UID);
if (Current != null)
{
int index = UserList.IndexOf(Current);
UserList[index].IsOnBreak = !Current.IsOnBreak;
if (UserList[index].IsOnBreak)
{
UserList[index].TimeInLastBreak = 0;
UserList[index].BreakTimer.Start();
UserList[index].PauseTimer.Stop();
}
else
{
UserList[index].BreakTimer.Stop();
UserList[index].MovePlanningCompleteTime(0, Convert.ToDouble(UserList[index].TimeInLastBreak));
}
}
return true;
}
public Request GetRequest(int userID, string reqID)
{
Guid outGID;
Request req = null;
if (Guid.TryParse(reqID, out outGID))
{
req = dc.Request.SingleOrDefault(r => r.ReqID == outGID);
}
return req;
}
public void ResetReplannedFlag(int id)
{
UserContainer uc = GetUserContainer(id);
if(uc!=null)UserList[UserList.IndexOf(uc)].IsReplanned=false;
}
public void SetPlannedFlag(Guid RID, bool value)
{
Request r = dc.Request.SingleOrDefault(s => s.ReqID == RID);
if (r != null)
{
UserContainer ul = UserList.SingleOrDefault(a => a.UserID == r.ExecutorID);
if (ul != null) ul.IsReplanned = true;
r.PlannedRequest = value;
dc.SubmitChanges();
}
}
public void SetPlanningTime(Guid RID, DateTime On, DateTime Complete)
{
Request r = dc.Request.SingleOrDefault(s => s.ReqID == RID);
if (r != null)
{
UserContainer ul = UserList.SingleOrDefault(a => a.UserID == r.ExecutorID);
if (ul != null) ul.IsReplanned = true;
r.PlanningOnDate = On;
r.PlanningCompleteDate = Complete;
dc.SubmitChanges();
}
}
public bool CheckForListEquality(IEnumerable<Request> OldList, int UID)
{
IEnumerable<Request> newList = GetUserRequests(UID);
return OldList.SequenceEqual(newList,new UserRequestComparer());
}
private void AddCommentToRequest(Guid RID, int CommentType, string comment, int CreatorID)
{
if(comment.Trim()!=string.Empty)
{
if (comment.Length > 998)
{
comment = "Комментарий, который хотел добавить пользователь был слишком большим по объему";
}
try
{
ReqComment rc = new ReqComment { CommentID = Guid.NewGuid(), UID = CreatorID, EnterDate = DateTime.Now, CommentType = CommentType, Comment = comment, ReqID = RID };
dc.ReqComment.InsertOnSubmit(rc);
dc.SubmitChanges();
}
catch(Exception ex)
{
Trace.Write("Ошибка в функции AddCommentToRequest " + ex.Message);
}
}
}
private ServiceResponse SetErrorMessage(string message)
{
Response.IsError = true;
Response.ErrorMessage = message;
return Response;
}
public ServiceResponse CreateRequest(string intCreatorUID, string gidReqType, string dtmPlanningOnDate, string strcomment, string intCount, string LocationID, bool Cyclic, bool HighestPriority, string HostName, bool NeedReconcile, int? ExecutorID)
{
byte StatusID = NeedReconcile ? Status.Reconciling_StatusCode : Status.WaitingOpen_StatusCode;
return this.CreateRequestWithCurrentStatus(intCreatorUID, gidReqType, dtmPlanningOnDate, strcomment, intCount, LocationID, Cyclic, HighestPriority, HostName, StatusID, ExecutorID);
}
public ServiceResponse CreateRequestWithCurrentStatus(string intCreatorUID, string gidReqType, string dtmPlanningOnDate, string strcomment, string intCount, string LocationID, bool Cyclic, bool HighestPriority, string HostName, byte StatusID, int? ExecutorID)
{
int CreatorUID;
if (!int.TryParse(intCreatorUID, out CreatorUID))
{
return SetErrorMessage("Ошибка Не получен ID инициатора");
}
int locationID;
if (!int.TryParse(LocationID, out locationID))
{
locationID = GetLocID(CreatorUID);
}
Guid ReqType;
if (!Guid.TryParse(gidReqType, out ReqType))
{
return SetErrorMessage("Ошибка Не получен тип заявки");
}
DateTime PlanningOnDate;
if (!DateTime.TryParse(dtmPlanningOnDate, out PlanningOnDate))
{
return SetErrorMessage("Ошибка Не получена дата начала действия заявки, формат даты должен соответствовать: дд мм гггг чч:мм");
}
int Count;
if (!int.TryParse(intCount, out Count))
{
return SetErrorMessage("Ошибка Не получено количество заявок");
}
//Если планнинг день не сегодня тогда пишем заявку в базу, и не пишем в юзерлист
if (PlanningOnDate.DayOfYear < DateTime.Now.DayOfYear)
{
return SetErrorMessage("Ошибка Планируемая дата заявки меньше сегодняшней");
}
try
{
WorkClassificator wclass = dc.WorkClassificator.SingleOrDefault(s => s.ID == ReqType);
if (wclass != null) dc.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, wclass);
}
catch
{
Trace.TraceWarning("An error in function CreateRequest, workcls refresh");
}
UserContainer ExecutorContainer = null;
if (ExecutorID.HasValue)
{
ExecutorContainer = UserList.SingleOrDefault(s => s.UserID == ExecutorID.Value);
}
else
{
ExecutorContainer = FindUser(ReqType, CreatorUID, locationID);
ExecutorID = ExecutorContainer != null ? ExecutorContainer.UserID : FindExecutorByReqType(ReqType, CreatorUID, locationID);
}
if (ExecutorID < 0 || !ExecutorID.HasValue)
{
return SetErrorMessage("Ошибка Не удалось найти ни одного исполнителя");
}
Request NewReq = new Request { ReqID = Guid.NewGuid(), CreationDate = DateTime.Now, PlanningOnDate = PlanningOnDate, CreatorID = CreatorUID, ExecutorID = ExecutorID.Value, CurrentStatus = StatusID, Type = ReqType, IsCycle = Cyclic };
if (HostName is string)
{
if (HostName.Length > 1) NewReq.HostName = HostName;
}
NewReq.Priorities = SetRequestPriority(NewReq.IsCycle, CreatorUID, HighestPriority);
try
{
dc.Request.InsertOnSubmit(NewReq);
dc.SubmitChanges();
}
catch (Exception ex)
{
return SetErrorMessage("Ошибка при записи заявки " + ex.Message);
}
NewReq.PlanningTime = NewReq.WorkClassificator.PlanningTime.HasValue ? NewReq.WorkClassificator.PlanningTime.Value * Count : 0;
NewReq.PlanningCompleteDate = NewReq.PlanningOnDate.AddMinutes(Convert.ToDouble(NewReq.PlanningTime));
dc.SubmitChanges();
AddCommentToRequest(NewReq.ReqID, ReqCommentTypes.Open_CommentType, strcomment, CreatorUID);
if (ExecutorContainer != null && NewReq.PlanningOnDate.Date >= DateTime.Now.Date && NewReq.PlanningOnDate.Date <= DateTime.Now.Date.AddDays(5) && StatusID != Status.Reconciling_StatusCode)
{
int indexContainer = UserList.IndexOf(ExecutorContainer);
UserList[indexContainer].IsReplanned = true;
UserList[indexContainer].ReqList.Add(NewReq);
UserList[indexContainer].ReqList.Sort(ReqComparer);
double minInterval = NewReq.PlanningOnDate.Subtract(DateTime.Now).TotalMinutes;
if (UserList[indexContainer].ReqList.Count == 1 && minInterval < 10) UserList[indexContainer].StartRequest();
}
if (StatusID != Status.Reconciling_StatusCode)
{
OTD Department = dc.OTD.SingleOrDefault(s => s.ID == NewReq.WorkClassificator.DepartmentID);
long? AccEmailId = null;
if (Department != null)
{
AccEmailId = Department.ID_EmailAccount;
}
UserContainer.NotificateUser(ExecutorID.Value, CreatorUID, "Оповещение о регистрации заявки", "Ваша заявка " + NewReq.WorkClassificator.TitleRow + " зарегистрирована. Ваш исполнитель " + NewReq.Executor.FIO + ". Планируемое время закрытия - " + NewReq.PlanningCompleteDate.Value.ToString(), AccEmailId);
UserContainer.NotificateUser(ExecutorID.Value, ExecutorID.Value, "Оповещение о новой заявке", "Вам назначена новая заявка: " + NewReq.WorkClassificator.TitleRow + " от пользователя " + NewReq.Creator.FIO, AccEmailId);
}
Response.IsError = false;
Response.ReturnObject = NewReq.ReqID.ToString();
return Response;
}
public int GetCurrentRequestTime(UserContainer Container)
{
Request CurrentReq = Container.ReqList.FirstOrDefault(s => s.CurrentStatus == Status.Opened_StatusCode);
int CurrentRequestRemaining = 0;
if (CurrentReq != null)
{
CurrentRequestRemaining = Convert.ToInt32(CurrentReq.PlanningCompleteDate.Value.Subtract(DateTime.Now).TotalMinutes);
}
return CurrentRequestRemaining;
}
public void CreateGroupRequest(string intCreatorUID, string gidReqType, string dtmPlanningOnDate, string strcomment, string intCount, string LocationID, bool Cyclic, bool Highest, int? ExecutorID)
{
int countReq = int.Parse(intCount);
for (int i = 0; i < countReq; i++)
{
string planDate = GetPlanningTime(int.Parse(intCreatorUID),false,Guid.Parse(gidReqType),int.Parse(LocationID), Highest,null);
CreateRequest(intCreatorUID, gidReqType, planDate, strcomment, "1",LocationID, false, Highest, null,false, ExecutorID);
}
}
public string GetPlanningTime(int CreatorID, bool ReqIsCycle, Guid ReqType, int LocationID, bool HighestPriority, int? ExecutorID)
{
Priorities PriorityEntity = SetRequestPriority(ReqIsCycle, CreatorID, HighestPriority);
int Priority = PriorityEntity.ID;
dc.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, dc.WorkClassificator);
WorkClassificator Class = dc.WorkClassificator.Single(s => s.ID == ReqType);
int pause = 5;
int CurrentExecutor;
int TimeNeedToRequest = Class.PlanningTime.Value + (pause * 2);
UserContainer ExecutorContainer = !ExecutorID.HasValue ? FindUser(ReqType, CreatorID, LocationID) : UserList.SingleOrDefault(s => s.UserID == ExecutorID.Value);
List<Request> reversed;
if (ExecutorContainer != null)
{
reversed = ExecutorContainer.ReqList.Where(r=>r.Priority<=Priority && r.CurrentStatus<Status.Excluded_StatusCode && r.PlanningOnDate.Date==DateTime.Now.Date).OrderBy(r => r.PlanningOnDate).ToList();
CurrentExecutor = ExecutorContainer.UserID;
}
else
{
int OfflineExecutor = !ExecutorID.HasValue ? FindExecutorByReqType(ReqType, CreatorID, LocationID) : ExecutorID.Value;
reversed = (from r in dc.Request where r.PlanningOnDate.Date == DateTime.Now.Date && r.ExecutorID == OfflineExecutor && r.Priority <= Priority && r.CurrentStatus < Status.Excluded_StatusCode orderby r.PlanningOnDate select r).ToList();
CurrentExecutor = OfflineExecutor;
}
int currentIndex=-1;
Request Next;
foreach (Request req in reversed)
{
currentIndex = reversed.IndexOf(req);
Next = reversed.ElementAtOrDefault(currentIndex + 1);
if (Next != null)
{
if (Next.PlanningOnDate.TimeOfDay.Subtract(req.PlanningCompleteDate.Value.TimeOfDay).TotalMinutes >= TimeNeedToRequest)
{
//если нашли окно то втыкаем сюда.
if (DateTime.Now.CompareTo(req.PlanningCompleteDate.Value) > 0) continue;
return req.PlanningCompleteDate.Value.AddMinutes(Convert.ToDouble(pause)).ToString("dd MM yyyy HH:mm:ss");
}
}
else
{
if (DateTime.Now.CompareTo(req.PlanningCompleteDate.Value) > 0)
{
return DateTime.Now.ToString("dd MM yyyy HH:mm:ss");
}
else
{
return req.PlanningCompleteDate.Value.AddMinutes(Convert.ToDouble(pause)).ToString("dd MM yyyy HH:mm:ss");
}
}
}
Request LastOpenedReq = dc.Request.Where(r => r.CurrentStatus <= Status.Opened_StatusCode && r.PlanningCompleteDate.HasValue && r.ExecutorID==CurrentExecutor).OrderByDescending(r=>r.PlanningCompleteDate).FirstOrDefault();
if (LastOpenedReq != null && DateTime.Now.CompareTo(LastOpenedReq.PlanningCompleteDate.Value) < 0)
{
return LastOpenedReq.PlanningCompleteDate.Value.AddMinutes(Convert.ToDouble(pause)).ToString("dd MM yyyy HH:mm:ss");
}
else
{
return DateTime.Now.ToString("dd MM yyyy HH:mm:ss");
}
}
//Этот блок инициирует пользователь, поэтому нужно искать в листе, потом, если не найдено - в базе
public bool ReopenRequest(int UID, Guid ReqID, string comment)
{
UserContainer Current = UserList.SingleOrDefault(s => s.UserID == UID);
Request ReqObj = dc.Request.Single(s => s.ReqID == ReqID);
ReqObj.Status = dc.Status.Single(s => s.ID == Status.WaitForResponse_StatusCode);
if(Current!=null)
{
ReqObj.PlanningOnDate = DateTime.Parse(GetPlanningTime(UID, ReqObj.IsCycle, ReqObj.Type, ReqObj.Executor.LocationID.Value, false, ReqObj.ExecutorID));
ReqObj.PlanningCompleteDate = ReqObj.PlanningOnDate.AddMinutes(Convert.ToDouble(ReqObj.PlanningTime));
int index = UserList.IndexOf(Current);
UserList[index].ReqList.Sort(new RequestComparer());
UserList[index].IsReplanned= true;
}
try
{
dc.SubmitChanges();
AddCommentToRequest(ReqID, ReqCommentTypes.Reopen_CommentType, comment, ReqObj.CreatorID);
return true;
}
catch
{
return false;
}
}
public bool CloseRequest(int UID, Guid ReqID, string comment="", int grade=0)
{
UserContainer Current = UserList.SingleOrDefault(s => s.UserID == UID);
Request ReqObj = dc.Request.Single(s => s.ReqID == ReqID);
ReqObj.CloseDate = DateTime.Now;
ReqObj.Status = dc.Status.Single(s => s.ID == Status.Closed_StatusCode);
ReqObj.grade = grade;
if (grade > 0 && grade < 3)
{
AddViolation(ReqObj.ReqID, Violations.BadGradeViolation);
}
try
{
dc.SubmitChanges();
if (Current != null)
{
int currindex = UserList.IndexOf(Current);
UserList[currindex].IsReplanned = true;
UserList[currindex].ReqList.Remove(ReqObj);
}
if (!string.IsNullOrEmpty(comment))
{
this.AddCommentToRequest(ReqObj.ReqID, ReqCommentTypes.UserClose_CommentType, comment, ReqObj.ExecutorID);
}
return true;
}
catch
{
return false;
}
}
public bool CancelRequest(int UID, Guid ReqID, string comment = "", int grade = 0)
{
UserContainer Current = UserList.SingleOrDefault(s => s.UserID == UID);
Request ReqObj = dc.Request.Single(s => s.ReqID == ReqID);
ReqObj.CloseDate = DateTime.Now;
ReqObj.Status = dc.Status.Single(s => s.ID == Status.Cancelled_StatusCode);
ReqObj.grade = grade;
if (grade > 0 && grade < 3)
{
AddViolation(ReqObj.ReqID, Violations.BadGradeViolation);
}
try
{
dc.SubmitChanges();
if (Current != null)
{
int currindex = UserList.IndexOf(Current);
UserList[currindex].IsReplanned = true;
UserList[currindex].ReqList.Remove(ReqObj);
}
if (!string.IsNullOrEmpty(comment))
{
this.AddCommentToRequest(ReqObj.ReqID, ReqCommentTypes.UserClose_CommentType, comment, ReqObj.ExecutorID);
}
return true;
}
catch
{
return false;
}
}
private void CheckForCyclicRequests()
{
DateTime Now = DateTime.Now;
IEnumerable<CyclicRequests> CRList = (from creq in dc.CyclicRequests
join req in dc.Request
on new { creq.CreatorID, creq.Type }
equals
new { req.CreatorID, req.Type }
where creq.BeginDateTime <= Now
&& creq.EndDate > Now
&& creq.BeginDateTime.TimeOfDay <= Now.TimeOfDay
&& creq.isActive==true
&& req.IsCycle==true
&& req.PlanningOnDate.Date == Now.Date
select creq);
List<CyclicRequests> CycleList = (from c in dc.CyclicRequests where c.BeginDateTime <= Now && c.EndDate > Now && c.isActive == true select c).ToList();
CycleList.RemoveAll(c => CRList.Contains(c));
bool AddToRequests;
string CombinedTime;
foreach (CyclicRequests CycleReq in CycleList)
{
AddToRequests=false;
switch (CycleReq.ScheduleType)
{
case Schedule.DailyScheduleType:
AddToRequests = true;
break;
case Schedule.WeeklyScheduleType:
if (CycleReq.RunDays.Contains(DateTime.Now.DayOfWeek.ToString()))
{
AddToRequests = true;
}
break;
case Schedule.MonthlyScheduleType:
if (CycleReq.RunWeeks.Contains(Service.GetWeekOfMonth(DateTime.Now).ToString()) && CycleReq.RunDays.Contains(DateTime.Now.DayOfWeek.ToString()))
{
AddToRequests = true;
}
break;
}
if (AddToRequests)
{
string LocID = GetLocID(CycleReq.CreatorID).ToString();
CombinedTime = DateTime.Now.ToString("dd MM yyyy ")+CycleReq.Time;
CreateRequest(CycleReq.CreatorID.ToString(), CycleReq.Type.ToString(), CombinedTime, CycleReq.comment, "1", LocID, true, false, null, false,null);
}
}
return;
}
public string Validate(string[] str)
{
return "";
}
public string CreateCycleRequest(string dtBeginDT, string dtEndDT, string intCrID, string comment, string gdType, string SchedType, string ReqTime, string RunDays=null, string RunWeeks=null)
{
int CreatorUID;
if (!int.TryParse(intCrID, out CreatorUID))
{
return "Ошибка Не получен ID инициатора";
}
Guid ReqType;
if (!Guid.TryParse(gdType, out ReqType))
{
return "Ошибка Не получен тип заявки";
}
if (ReqTime.Trim() == String.Empty)
{
return "Ошибка Время должно быть заполнено";
}
DateTime BeginDate;
if (!DateTime.TryParse(dtBeginDT, out BeginDate))
{
return "Ошибка Не получена дата начала действия заявки, формат даты должен соответствовать: дд мм гггг чч:мм";
}
DateTime EndDate;
if (!DateTime.TryParse(dtEndDT, out EndDate))
{
return "Ошибка Не получена дата окончания действия заявки, формат даты должен соответствовать: дд мм гггг чч:мм";
}
CyclicRequests CReq = new CyclicRequests { BeginDateTime = BeginDate, EndDate = EndDate, ID = Guid.NewGuid(), isActive = true, CreatorID = CreatorUID, RunDays = RunDays, Type = ReqType, comment = comment, Time=ReqTime, ScheduleType=SchedType, RunWeeks=RunWeeks };
try
{
dc.CyclicRequests.InsertOnSubmit(CReq);
dc.SubmitChanges();
return "";
}
catch(Exception ex)
{
return "Ошибка не удалось записать заявку "+ex.Message ;
}
}
public bool SetRequestCompleted(int Uid, Guid ReqID)
{
UserContainer Current = UserList.SingleOrDefault(c => c.UserID == Uid);
if (Current != null)
{
int CurrIndex = UserList.IndexOf(Current);
Request RObj = dc.Request.SingleOrDefault(c => c.ReqID == ReqID);
if (RObj != null)
{
RObj.Status = dc.Status.First(s => s.ID == Status.Completed_StatusCode);
RObj.CompleteDate = DateTime.Now;
if (RObj.PlanningCompleteDate.Value.CompareTo(RObj.CompleteDate) < 0)
{
AddViolation(RObj.ReqID, Violations.BreakTimeViolation);
}
try
{
dc.SubmitChanges();//При закрытии заявки удалять ее из листа и записывать в базу(сначала в базу потом удалять)
UserList[CurrIndex].IsReplanned = true;
UserList[CurrIndex].PauseTimer.Start();
CheckForCyclicRequests();
UserList[CurrIndex].ReqList.Sort(ReqComparer);
OTD Department = dc.OTD.SingleOrDefault(s => s.ID == RObj.WorkClassificator.DepartmentID);
long? AccEmailId = null;
if (Department != null)
{
AccEmailId = Department.ID_EmailAccount;
}
UserContainer.NotificateUser(RObj.ExecutorID, RObj.CreatorID, "Оповещение о закрытии заявки", "Ваша заявка " + RObj.WorkClassificator.TitleRow + " завершена исполнителем " + RObj.Executor.FIO + ". Подтвердите ее завершение в интерфейсе пользователя", AccEmailId);
UserList[CurrIndex].ReqList.Remove(RObj);
return true;
}
catch
{
return false;
}
}
}
return false;
}
public void StartFirst(int id)
{
UserContainer Current = UserList.SingleOrDefault(c => c.UserID == id);
if (Current != null)
{
int CurrIndex = UserList.IndexOf(Current);
UserList[CurrIndex].PauseTimer.Stop();
UserList[CurrIndex].StartRequest();
}
}
public IEnumerable<Request> GetUserRequests(int CreatorID)
{
List<Request> IReq = (from cr in dc.Request where cr.CreatorID == CreatorID && cr.CurrentStatus != Status.Closed_StatusCode select cr).ToList();
IReq.Sort(new RequestComparer());
return IReq.AsEnumerable();
}
private Priorities SetRequestPriority(bool isCycle, int CreatorID, bool HighestPriority)
{
if (!HighestPriority)
{
SOTRUD Creator = dc.SOTRUD.Single(s => s.ID == CreatorID);
dc.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, Creator);
return Creator.Priorities;
}
else
{
return dc.Priorities.Single(e => e.ID == 1);
}
}
public void TransmitRequest(string RID, int FromUID, int ToUID, string comment, bool isOffline)
{
Request Current = dc.Request.SingleOrDefault(s => s.ReqID == Guid.Parse(RID));
if (Current != null)
{
if (this.UserIsHere(FromUID))
{
int indexFrom = UserList.IndexOf(UserList.Single(u => u.UserID == FromUID));
UserContainer uc = UserList[indexFrom];
if (Current != null && uc.ReqList.Contains(Current))
{
UserList[indexFrom].ReqList.Remove(Current);
UserList[indexFrom].ReqList.Sort(new RequestComparer());
UserList[indexFrom].IsReplanned = true;
}
}
AddCommentToRequest(Guid.Parse(RID), ReqCommentTypes.Redirect_CommentType, comment, FromUID);
if (Current.CurrentStatus != Status.onRegistration_StatusCode)
{
Current.Status = dc.Status.Single(i => i.ID == Status.WaitingOpen_StatusCode);
}
Current.Executor = dc.SOTRUD.Single(s => s.ID == ToUID);
Current.PlanningOnDate = DateTime.Parse(GetPlanningTime(Current.CreatorID, Current.IsCycle, Current.Type, Current.Executor.LocationID.Value, false, ToUID));
dc.SubmitChanges();
OTD Department = dc.OTD.SingleOrDefault(s => s.ID == Current.WorkClassificator.DepartmentID);
long? AccEmailId = null;
if (Department != null)
{
AccEmailId = Department.ID_EmailAccount;
}
UserContainer.NotificateUser(Current.ExecutorID, Current.CreatorID, "Оповещение о передаче заявки", "Ваша заявка " + Current.WorkClassificator.TitleRow + " передана другому исполнителю. Ваш новый исполнитель " + Current.Executor.FIO + ". Планируемое время закрытия - " + Current.PlanningCompleteDate.Value.ToString(),AccEmailId);
UserContainer.NotificateUser(Current.CreatorID, Current.ExecutorID, "Оповещение о передаче заявки", "Вам была передана заявка " + Current.WorkClassificator.TitleRow + ". Инициатор заявки " + Current.Creator.FIO + ". Планируемое время закрытия - " + Current.PlanningCompleteDate.Value.ToString(),AccEmailId);
if (!isOffline)
{
int indexTo = UserList.IndexOf(UserList.Single(u => u.UserID == ToUID));
UserList[indexTo].ReqList.Add(Current);
UserList[indexTo].ReqList.Sort(new RequestComparer());
UserList[indexTo].IsReplanned = true;
}
}
}
public void EditPlanningTime(string RID, int UID, string NewTime, string comment)
{
int index = UserList.IndexOf(UserList.Single(u => u.UserID == UID));
DateTime NewT = DateTime.Parse(NewTime);
double MinutesToMove=0;
Request Current = UserList[index].ReqList.Single(r => r.ReqID == Guid.Parse(RID));
int ReqIndex = UserList[index].ReqList.IndexOf(Current);
AddCommentToRequest(Guid.Parse(RID), ReqCommentTypes.ChangeData_CommentType, comment, UID);
if(NewT.Date==DateTime.Now.Date)
{
MinutesToMove= NewT.Subtract(UserList[index].ReqList[ReqIndex].PlanningCompleteDate.Value).TotalMinutes;
}
UserList[index].ReqList[ReqIndex].PlanningCompleteDate = NewT;
UserList[index].ReqList[ReqIndex].PlanningOnDate = UserList[index].ReqList[ReqIndex].PlanningCompleteDate.Value.Subtract(new TimeSpan(0, Current.PlanningTime, 0));
//}
if(UserList[index].ReqList[ReqIndex].CurrentStatus<=Status.Opened_StatusCode)
{
UserList[index].ReqList[ReqIndex].Status = dc.Status.Single(s => s.ID == Status.WaitingOpen_StatusCode);
}
UserList[index].ReqList.Sort(new RequestComparer());
dc.SubmitChanges();
ReqIndex = UserList[index].ReqList.IndexOf(Current);
UserList[index].MovePlanningCompleteTime(ReqIndex, MinutesToMove);
UserList[index].IsReplanned = true;
AddViolation(Current.ReqID, Violations.ChangeTimeViolation);
}
private UserContainer FindUser(Guid TypeReq, int creatorID, int CreatorLocationID)
{
/*Если юзер не найден - найти заместителя, если заместитель не найден идем на уровень выше по классификтору
Если никто не найден = возврат -1*/
WorkClassificator ClassObj = dc.WorkClassificator.SingleOrDefault(r => r.ID == TypeReq && r.responsibleDolgID.HasValue);
UserContainer User = UserList.Find(r => (r.PositionID == ClassObj.responsibleDolgID.Value || ClassObj.SOTRUD_DOLG.MainPost.Count(a=>a.ID==r.PositionID)>0) && GetLocID(r.UserID)==CreatorLocationID);
if (User != null)
{
return User;
}
else
{
User = UserList.Find(r => (r.PositionID == ClassObj.AssistantDolgID.Value || ClassObj.SOTRUD_DOLG1.MainPost.Count(a => a.ID == r.PositionID) > 0) && GetLocID(r.UserID) == CreatorLocationID);
}
if (User != null)
{
return User;
}
else
{
if(ClassObj.ParentUID.HasValue)
{
FindUser(ClassObj.ParentUID.Value, creatorID, CreatorLocationID);
}
}
if (User == null)
{
return UserList.SingleOrDefault(s => s.UserID == 104);
}
return User;
}
private int GetLocID(int id)
{
SOTRUD sotr = dc.SOTRUD.Single(s => s.ID == id);
if (sotr.LocationID.HasValue)
{
return sotr.LocationID.Value;
}
else
{
return 1;
}
}
public int FindExecutorByReqType(Guid TypeReq, int CreatorID, int CreatorLocationID)
{
WorkClassificator ClassObj = dc.WorkClassificator.Single(r => r.ID == TypeReq);
SOTRUD User = dc.SOTRUD.FirstOrDefault(r => (r.SOTRUD_DOLG.ID == ClassObj.responsibleDolgID.Value || ClassObj.SOTRUD_DOLG.MainPost.Contains(r.SOTRUD_DOLG)) && r.LocationID == CreatorLocationID && r.DATA_YVOL.HasValue == false);
if (User == null)
{
User = dc.SOTRUD.FirstOrDefault(r => (r.SOTRUD_DOLG.ID == ClassObj.AssistantDolgID.Value || ClassObj.SOTRUD_DOLG1.MainPost.Contains(r.SOTRUD_DOLG)) && r.LocationID == CreatorLocationID && r.DATA_YVOL.HasValue == false);
if (User == null)
{
return ClassObj.ParentUID.HasValue== true ? FindExecutorByReqType(ClassObj.ParentUID.Value,CreatorID,CreatorLocationID) : 104;
}
}
return User.ID;
}
public UserContainer GetUserContainer(int id)
{
UserContainer uc = UserList.SingleOrDefault(u => u.UserID == id);
if (uc != null)
{
uc.ReqList.Sort(ReqComparer);
}
return uc;
}
public bool UserIsHere(int id)
{
return (UserList.Find(f => f.UserID == id) != null);
}
public List<UsersList> GetActiveUsers()
{
try
{
List<UsersList> ul = UserList.ConvertAll(new Converter<UserContainer, UsersList>(ContainerToUser));
return ul;
}
catch
{
List<UsersList> ul = UserList.ConvertAll(new Converter<UserContainer, UsersList>(ContainerToUser));
return ul;
}
}
private void SetHighestPriority(Request Req,UserContainer user)
{
//Установить высший приоритет == 1
if(user.ReqList.Contains(Req) && !Req.PlannedRequest)
{
Req.Priorities = dc.Priorities.SingleOrDefault(p => p.ID == 1);
Request LastOpen = user.ReqList.FindLast(e=>e.CurrentStatus==Status.Opened_StatusCode);
if (LastOpen != null)
{
Req.PlanningOnDate = LastOpen.PlanningCompleteDate.Value;
}
else
{
Req.PlanningOnDate = DateTime.Now;
}
Req.PlanningCompleteDate = Req.PlanningOnDate.AddMinutes(Req.PlanningTime);
dc.SubmitChanges();
user.ReqList.Sort(ReqComparer);
user.ReplanAll(user.ReqList.IndexOf(Req) + 1, Req.PlanningCompleteDate.Value);
}
//Перепланировать время в соответствии с приоритетом
}
private void MoveUp(Request Req, UserContainer user)
{
if(user.ReqList.Contains(Req) && !Req.PlannedRequest)
{
int CurrentIndex = user.ReqList.IndexOf(Req);
if (CurrentIndex > 0)
{
Req.PlanningOnDate = user.ReqList[CurrentIndex - 1].PlanningOnDate;
Req.PlanningCompleteDate = Req.PlanningOnDate.AddMinutes(Req.PlanningTime);
user.ReqList[CurrentIndex - 1].PlanningOnDate = Req.PlanningCompleteDate.Value.AddMinutes(5);
user.ReqList[CurrentIndex - 1].PlanningCompleteDate=user.ReqList[CurrentIndex - 1].PlanningOnDate.AddMinutes(user.ReqList[CurrentIndex - 1].PlanningTime);
}
}
}
private void MoveDown(Request Req, UserContainer user)
{
if (user.ReqList.Contains(Req) && !Req.PlannedRequest)
{
int CurrentIndex = user.ReqList.IndexOf(Req);
if (CurrentIndex < user.ReqList.Count-1)
{
Req.PlanningOnDate = user.ReqList[CurrentIndex + 1].PlanningOnDate;
Req.PlanningCompleteDate = Req.PlanningOnDate.AddMinutes(Req.PlanningTime);
user.ReqList[CurrentIndex + 1].PlanningCompleteDate = Req.PlanningOnDate.AddMinutes(-5);
user.ReqList[CurrentIndex + 1].PlanningOnDate = user.ReqList[CurrentIndex + 1].PlanningCompleteDate.Value.AddMinutes(user.ReqList[CurrentIndex + 1].PlanningTime * -1);
}
}
}
public void ManagerContextAction(string ActCode, string ReqID)
{
Guid gReqID;
if (Guid.TryParse(ReqID, out gReqID))
{
Request Req = dc.Request.SingleOrDefault(s => s.ReqID == gReqID);
if (Req != null)
{
UserContainer container = UserList.SingleOrDefault(s => s.UserID == Req.ExecutorID);
if ((Req.CurrentStatus < Status.Completed_StatusCode) && container!=null)
{
switch (ActCode)
{
case ContextAction.SetHighestPriority:
SetHighestPriority(Req,container);
break;
case ContextAction.MoveUp:
MoveUp(Req, container);
break;
case ContextAction.MoveDown:
MoveDown(Req, container);
break;
case ContextAction.IncludeToQueue:
IncludeToQueue(Req, container);
break;
case ContextAction.ExcludeFromQueue:
ExcludeFromQueue(Req, container);
break;
case ContextAction.CloseRequest:
SetRequestCompleted(container.UserID, Req.ReqID);
break;
default:
break;
}
try
{
dc.SubmitChanges();
container.IsReplanned = true;
container.ReqList.Sort(ReqComparer);
}
catch
{
}
}
}
}
}
private void ExcludeFromQueue(Request Req, UserContainer container)
{
Req.Status = dc.Status.Single(s => s.ID == Status.Excluded_StatusCode);
}
private void IncludeToQueue(Request Req, UserContainer container)
{
if (Req.CurrentStatus == Status.Excluded_StatusCode)
{
Req.Status = dc.Status.Single(s => s.ID == Status.WaitingOpen_StatusCode);
Req.PlanningOnDate = DateTime.Parse(GetPlanningTime(Req.CreatorID, Req.IsCycle, Req.Type, Req.Executor.LocationID.Value, false, Req.ExecutorID));
Req.PlanningCompleteDate = Req.PlanningOnDate.AddMinutes(Req.PlanningTime);
}
}
public bool SetWorkDay(int id, int posID, bool itIsEnd)
{
return this.SetWorkDay(id, posID, itIsEnd, 0);
}
}
}
Инцидент заявка, поданная оператором в системе регистрации заявок
Оператор лицо (пользователь системы), создающее заявку (инцидент) в службу ИТ, для решения.
Служба ИТ отдел информационных технологий или отдел автоматизации на предприятии.
Координатор непосредственный руководитель лица, занимающегося решением заявок (инженера).
Инженер лицо, которое непосредственно занимается решением заявок (инцидентов).
АРМ автоматизированное рабочее место инженера, оператора, координатора.
Инцидент заявка, поданная пользователем (оператором) через систему Service Desk.
ПО программное обеспечение, установленное на компьютере.
ЖЦ жизненный цикл (время от создания инцидента до его разрешения).
В данной курсовой достигнуты все поставленные задачи и цели, а именно было разработано программное обеспечение с продуманным и простым интерфейсом, реализующее основные функции системы подачи заявок. Были рассчитаны экономические показатели, и можно сказать, что внедрение программного продукта будет выгодно для большинства предприятий.
В ходе выполнения работы была изучена технология ASP.NET MVC 3, усовершенствованы навыки Web разработки, работы .NET Framework.
Учитывая экономическую эффективность программного продукта, современность и перспективность выбранных технологий и подходов при разработки программного продукта можно с уверенностью сказать, что данный продукт будет, не только экономически обоснован и перспективен, но и прост и удобен в поддержке.
В результате данной работы была разработана система обработки заявок, позволяющая автоматизировать поступающие от пользователей заявки в области ИТ-инфраструктуры, минимизировать время, на их решение, а также производить аналитику работы отдела инженеров службы ИТ.
Разбив участки работы на АРМы (автоматизированные рабочие места), можно увеличить производительность работы, убрав ненужную информацию, упорядочив необходимую информацию и разграничив доступ.
Основная цель системы заявок - минимизировать неблагоприятное воздействие на работу предприятия, вызванное инцидентами и проблемами, связанными с ошибками в работе ИТ-инфраструктуры. Цели работы достигнуты, процесс полностью соответствует стандартам, данный программный продукт можно рассматривать как базовую систему Service desk, в которой также присутствуют функции системы управления проблемами.
1. Программа Ramus Educational Version: 1.1.1 Copyright © 2005 - 2009 Oleksiy Chizhevskiy, Vitaliy Yakovchuk. All rights reserved. e-mail: support@ramussoftware.com http://ramussoftware.com/
2. М.Б. Букреев, А.Е. Заславский, «Управление ИТ-сервисами информационно-телекоммуникационных систем (ИТС)», Москва, РУСЭЛПРОМ, 2007г.
3. СовiТ 4.1. Москва, Аудит и контроль информационных систем 2008.
4. С. Жарков Shareware: профессиональная разработка и продвижение программ. Издательство БХВ-Петербург, 2002
5. Фримен, A. ASP.NET МVС 3 для профессионалов /А. Фримен, С. Сандерсон. Москва: Вильямс, 2012. 680 с.: ил.
6. http://www.osp.ru/cio/2005/01/173763/ Статья «Как организовать управление проблемами» 27 января 2005 г.
7. http://masu-inform.ru:8888/index.php/Управление_проблемами.
8. www.allITIL.ru.
9. http://ru.wikipedia.org/wiki/ITSM.
10. http://www.itexpert.ru/rus/biblio/itmanagement/.
11.http://www.pcweek.ru/themes/detail.php?ID=81984 Статья «Управление инцидентами и проблемами: как распределить ресурсы» PCWeeK № 562 13 февраля 2007 г.
12.http://msdn.microsoft.com/ru-ru/library/gg416651(v=vs.98).aspx Справочная информация по Microsoft MVC 3.0