Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Проектирование реализации операций бизнес-процесса «Складской учёт» ( Аналитическая часть )

Содержание:

ВВЕДЕНИЕ

Развитие информационных технологий дало широкий спектр возможностей для автоматизации совершенно любых задачи бизнеса. ИТ занимает лидирующие позиции в рейтинге востребованных профессий и в рейтинге услуг, необходимых бизнесу. Автоматизация добавляет бизнесу такие возможности как сокращение затрат, сокращение персонала, а также упрощение рабочей деятельности.

Однако, не смотря на бурное развитие информационных технологий и повсеместное их внедрение, всегда остаются небольшие участки производственного процесса, которые либо плохо автоматизированы, либо не автоматизированы вовсе. Такие слабо автоматизированные участки имеют более низкую производительность труда, что отрицательно сказывается на общей производительности труда на предприятии.

Цель курсовой работы – проектирование информационной системы для реализации бизнес-процесса «Складской учет» на примере компании ООО «Атлетика».

Для достижения поставленной цели необходимо решить следующие задачи:

  • Охарактеризовать существующие бизнес-процессы и выявить необходимость их автоматизации;
  • Обосновать проектные решения по информционному и программному обеспечению;
  • Составить информционную модель, дерево функций и сценарий диалога;
  • Разработать базу данных и программные модули ИС;
  • Описать контрольный пример реализации проекта.

1 Глава. Аналитическая часть

1.1. Выбор комплекса задач автоматизации

Общество с ограниченной ответственностью «Атлетика» владеет сетью оружейных магазинов в г. Москва более 10 лет. Основным видом деятельности предприятия является розничная и мелкооптовая торговля товарами для охоты и активного отдыха.

Деятельность предприятия осуществляется на основании Федерального закона «Об оружии» от 13.12.1996 № 150-ФЗ Российской Федерации и на основании договоров с другими юридическими и физическими лицами, заключаемых согласно действующему законодательству. Предприятие полностью отвечает за результаты своей деятельности и выполняет обязательства перед потребителями и поставщиками.

ООО «Атлетика» является коммерческой организацией. Общество является собственником принадлежащего ему имущества и денежных средств и отвечает по своим обязательствам собственным имуществом.

Целями деятельности Общества являются расширение рынка товаров и услуг, а также извлечение прибыли.

Предметами деятельности предприятия являются:

  • торговля пневматическим оружием и аксессуарами;
  • торговля товарами и аксессуарами для охоты;
  • торговля средствами самообороны;
  • торговля сувенирной продукцией и многое другое.

Номенклатура включаемых товаров составляет несколько тысяч наименований и постоянно возрастает. Основными потребителями услуг является население и предприятия города Москва.

В рамках данной работы будет рассмотрена деятельность склада компании, а именно – складской учет поступлений и отгрузок товарно-материальных ценностей (ТМЦ).

1.2. Характеристика существующих бизнес-процессов

Для более полного изучения текущей организации процессов учета ТМЦ на складе компании был использован метод структурно-функционального моделирования.

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

Стандарт IDEF0 регламентирует с помощью входа (первый тип входных данных) показывать объекты, которые преобразуются в данном бизнес-процессе, это могут быть информационные и материальные потоки. С помощью управления (второй тип) показывают объекты, которые управляют выполнением бизнес-процесса. С помощью механизмов (третий тип) необходимо показывать объекты, которые непосредственно осуществляют данный бизнес-процесс: сотрудники, технические средства, информационные системы. На выходе бизнес-процесса показывают результат его выполнения.

На первом этапе построения IDEF0-модели моделируемая деятельность представляется как единое целое. Основная цель данного этапа – выявить входные и выходные данные, а также механизмы и правила для данной деятельности. Диаграмма данного этапа называется контекстной, она изображена на рисунке 1.

Рисунок 1. Контекстная диаграмма

В качестве входных данных для моделируемой деятельности выступают товары от поставщиков, счет-фактуры и заказы покупателей. Выходные данные – это отчеты по инвентаризации, отгружаемые товары, акты прием и передачи ТМЦ.

Вся деятельность ведется в соответствии с регламентом складского учета и выполняется работниками склада.

Следующий этап построения структурно-функциональной модели – декомпозиция контекстной диаграммы. Диаграмма декомпозиции изображена на рисунке 4.

Рисунок 2. Диаграмма декомпозиции

Исследуемая деятельность состоит из четырех основных процессов:

  • прием товаров от поставщиков;
  • отгрузка товаров клиентам;
  • формирование отчет по остаткам;
  • проведение инвентаризации;

1.3. Характеристика документооборота, возникающего при решении задачи

В настоящее время складской учет в компании ведется с помощью нескольких инструментов:

  • книга инвентаризаций;
  • таблицы оперативного учета движения товаров;
  • архив документов на поступление и выдачу товаров (актов приема и выдачи).

В книгу инвентаризаций вносятся результаты инвентаризации, которая проводится периодически на складе (обычно – один раз в квартал). В книге указывается дата проведения инвентаризации и количество товара, которое должно быть в наличии и имеется по факту.

В таблицах оперативного учета движения товаров по каждой товарной позиции ведется учет поступлений и отгрузок при их выполнении. Данные таблицы хранятся на общем сервере компании в формате электронных таблиц Excel. Перед проведением инвентаризации выполняется подсчет остатков товаров, которые должны быть в наличии (формируется отчет по остаткам). Стоит отметить, что в данных таблицах имеются инструменты для быстрого формирования данных отчетов и суммарных показателей, реализованные с помощью Visual Basic for Application (VBA). Однако, хранение данных в нескольких файлах очень неудобно и замедляет работы с информацией. Кроме того, при расширении номенклатуры товаров увеличивается и количество хранимых данных, поэтому необходимо автоматизировать процессы складского учета.

Архив документов представляет собой упорядоченные папки, в которых хранятся бумажные копии документов (счет-фактуры, акты приема-передачи и пр.)

Схема документооборота приведена на рисунке 3.

Рисунок 3. Схема документооборота

Основным недостатком является не слишком удобное хранение данных о движении товаров в виде таблиц Excel. И хотя в этих таблицах учета имеются примитивные инструменты для автоматизации рутинных действий, по мере разрастания номенклатурной базы работа с таблицами замедляется и становится менее удобной.

1.4. Обоснование проектных решений по информационному обеспечению

Информационное обеспечение комплекса задач, которые поставлены перед данным проектом организовано в виде реляционной базы данных, в которой хранится вся информация, необходимая для автоматизации складского учета.

Существуют определенные правила создания и проектировании базы данных для нужд какой-либо организации:

  • база данных должна содержать в себе все необходимые для работы организации данные, хранимая информация должна быть в актуальном состоянии;
  • база данных должна обеспечивать доступ ко всей информации за приемлемое время, то есть отвечать заданным требованиям производительности;
  • база данных должна удовлетворять выявленным и вновь возникающим требованиям конечных пользователей;
  • база данных должна иметь возможности расширения, на случай расширения сферы деятельности организации;
  • база данных должна легко изменяться при изменении программной и аппаратной среды;
  • данные, которые загружаются в базу данных, должны быть корректными, поэтому при добавлении данных должна проводиться проверка вводимых данных;
  • доступ к информации, хранимой в БД должны иметь только лица и сотрудники организации, имеющие на это соответствующие полномочия и должностные обязанности;
  • работа с базой данных не должны вызывать трудностей у пользователей, для этого обязательно нужен дружественных интерфейс.

Реляционная модель базы данных – это такая модель, где БД – совокупность отношений, содержащих всю информацию, которая должна храниться в БД. Однако пользователи могут воспринимать такую базу данных как совокупность таблиц.

Входными данными для проектируемой информационной системы выступают данные о поступающих и отгружаемых товарах.

Всего в информационной системе используется четыре справочника:

  • сотрудники (они же пользователи ИС);
  • товары;
  • категории товаров;
  • единица измерения;
  • роль пользователя.

Выходными данными информационной системы выступают сформированные отчет по остаткам и отчет по движению товаров.

Для каждого поступления, отгрузки, товара, категории товара и сотрудника, используются классификаторы, предназначенные для идентификации каждой записи в таблице БД.

Описание используемых классификаторов приведено в таблице 1.

Таблица 1

Используемые идентификаторы

№ пп

Наименование кодируемого множества объектов

Значность кода

Мощность кода

Система кодирования

1

Идентификационный номер пользователя

4

9999

Порядковая

2

Идентификационный номер роли пользователя

4

9999

Порядковая

3

Идентификационный номер товара

4

9999

Порядковая

4

Идентификационный номер единицы измерения

4

9999

Порядковая

5

Идентификационный номер категории товаров

4

9999

Порядковая

6

Идентификационный номер поступления

4

9999

Порядковая

7

Идентификационный номер отгрузки

4

9999

Порядковая

1.5. Обоснование проектных решений по программному обеспечению

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

В состав программного обеспечения входят общесистемные и специальные программные продукты, в том числе: операционная система, системы программирования, инструментальные средства программиста, тестовые и диагностические программы, программные средства телекоммуникации, защиты информации, функциональное программное обеспечение (автоматизированные рабочие места, системы управления базами данных и т. п.).

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

В качестве языка программирования был выбран язык php.

PHP (PersonalHomePageTools – «Инструмент для создания персональных веб-страниц») – является скриптовым языком программирования общего пользования, используемый для создания Web-приложений. В данный момент времени поддерживают подавляющие большинство хостинг-провайдеров и стал одним из ведущих языком программирования, использующих для разработки динамических Web-сайтов.

Популярность языка в создании web-сайтов определяется наличием большого набора средств предназначенных на разработку web-приложений. Основные из них:

  • автоматически извлекаемые GET и POST -параметров, а также переменных окружения веб-сервера в предопределённые массивы;
  • взаимодействует с очень большим количеством разныхСУБД (MySQL, SQLite,MySQLi, Oracle (OCI8), PostgreSQL, Microsoft SQL Server и пр.);
  • автоматическая отправка HTTP-заголовков;
  • работает с HTTP-авторизацией;
  • работает с сессиями и cookies;
  • работает с удалёнными и локальными файлами, сокетами;
  • обрабатывает файлы, загруженные на сервер;

В качестве системы управления базой данных была выбрана СУБД MySQL.

MySQL – разработка шведской компании MySQL AB. СУБД MySQL является программным обеспечением с открытым исходным кодом, распространяемым по лицензии GNU (GPL) и коммерческой лицензии для ситуаций, не подпадающих под действие лицензии GPL.

MySQL поддерживает реляционную модель данных, т. е. представляет собой реляционную СУБД.

Основные достоинства СУБД MySQL:

  • Высокое качество – MySQL характеризуется устойчивой работой.
  • Наряду с Oracle, MySQL считается одной из самых быстрых СУБД в мире.
  • Открытый код доступен для просмотра и модернизации, что позволяет постоянно улучшать программный продукт.
  • СУБД MySQL, разработанная с использованием языков C/C++, протестирована на многих платформах, среди которых Windows, Linux, FreeBSD, Mac OS X, OS/2, Solaris и др.
  • MySQL поддерживает API (Application Programming Interface, программный интерфейс приложения) для С, C++, Eiffel, Java, Perl, PHP, Python, Ruby и Tcl. MySQL можно успешно применять как для построения Web-страниц с использованием Perl, PHP и Java, так и для работы прикладной программы, созданной с использованием Delphi, Builder C++ или платформы .NET.4
  • СУБД MySQL предоставляет широкий выбор типов таблиц, в том числе и сторонних разработчиков, что позволяет реализовать оптимальную для решаемой задачи производительность и функциональность.
  • Локализация в MySQL выполнена корректно. У пользователя, как правило, не возникает проблем при обработке русского содержимого БД

2 Глава. Проектная часть

2.1. Информационная модель и её описание

Информационной моделью называют схему движения входной, промежуточной и результативной информации и функций предметной области. Также с помощью информационной модели объясняется с помощью каких входных данных (документов) и какой нормативно-справочной информации происходит выполнение основных функций. Информационная модель проектируемой ИС представлена на рисунке 4.

Рисунок 4. Информационная модель

Согласно данной модели пользователю системы доступны функции по управления справочниками, добавления поступлений и отгрузок, формирования отчетов. Выполнение функций системы выполняется с помощью специальных форм пользовательского интерфейса.

2.2. Характеристика нормативно-справочной, входной и оперативной информации

В информационной системе используются пять справочников, характеристики которых приведены в таблице 2.

Таблица 2

Справочники информационной системы

№ пп

Название справочника

Ответственный за ведение

Средний объём справочника в записях

Среднюю частоту актуализации

Средний объем актуализации, %

1

Пользователи

Администратор

5

1 раз в месяц

20

2

Роль

-

2

-

-

3

Единица измерения

Администратор

4

1 раз в год

25

4

Товар

Администратор

1500

1 раз в месяц

2

5

Категория товаров

Администратор

10

1 раз в месяц

10

Справочник ролей пользователей носит нормативный характер, поэтому его актуализация не требуется. Остальные справочники время от времени необходимо актуализировать.

Реквизитный состав каждого справочника представлен в виде таблицы 3.

Таблица 3

Реквизитный состав справочников информационной системы

№ пп

Название справочника

Перечень реквизитов

1

Пользователи

ФИО

логин

пароль

электронная почта

телефон

2

Роль

наименование

3

Единица измерения

наименование

4

Товар

наименование

штрихкод

артикул

остаток

цена закупки

цена продажи

5

Категория товаров

наименование

Редактирование и ввод новых записей во все справочники осуществляется с помощью специальных форм.

На рисунке 5 изображена форма для работы с записями справочника «Товар».

Рисунок 5. Форма Товар

Формы для работы с записями других справочников имеют аналогичный вид.

В качестве входных данных для информационной системы выступают и данные о поступлениях и отгрузках товаров. Эти данные вводятся в ИС с помощью специальных форм. На рисунке 6 приведена форма для добавления поступления.

Рисунок 6. Форма для добавления поступления

Форма для добавления отгрузки имеет аналогичный вид.

Данные, введенные в формы, которые приведены выше, сохраняются в базе данных и используются для формирования выходных данных.

2.3. Характеристика результатной информации

В качестве выходных данных выступают заказ поставщику и отчет о деятельности сотрудников отдела закупок.

Подробное описание выходных данных представлено в таблице 4.

Таблица 4

Описание результатной информации

Наименование

Отчет по отгрузкам

Отчет по поступлениям

Реквизиты

Дата формирования

Категория

Наименование товара

Артикул

Единица измерения

Дата формирования

Категория

Наименование товара

Артикул

Единица измерения

Количество поступило

Количество выдано

Итоговый остаток

Таблицы, на основе которых формируется

Товары

Категории

Единицы измерения

Товары

Категории

Единицы измерения

Поступления

Выдачи

Частота формирования

По мере необходимости

По мере необходимости

Способ доставки

Файл в формате *.CSV

Файл в формате *.CSV

2.4. Общие положения (дерево функций и сценарий диалога)

Базовый набор функций разработанной информационной системы можно изобразить в виде дерева, изображенного на рисунке 7.

Рисунок 7. Дерево функций

Функции ИС можно разделить на основные и служебные. К служебным относятся управление профилем пользователя, авторизация и проверка вводимых данных. К основным функциям системы относятся все функции, которые необходимы для автоматизации исследуемого процесса: от управления справочными данными до работы с поступлениями и отгрузками, а также формирование отчетов.

Выполнение функций разработанной информационной системы осуществляется с помощью ведения диалога с пользователем. То есть пользователь информационной системы выполняет какие-то действия, а программа соответствующим образом на них реагирует. Сценарий диалога с пользователем представлен на рисунке 8.

Рисунок 8. Сценарий диалога

После открытия ИС пользователю необходимо пройти авторизацию с помощью логина и пароля.

После авторизации на сайте пользователь переходит по разделам сайта с помощью навигационного меню. В зависимости от выбранного пункта в меню ему отображается содержимое соответствующего раздела.

2.5. Характеристика базы данных

В качестве системы управления базой данный для разрабатываемой информационной системы была выбрана СУБД Mysql.

Для хранения всех необходимых данных была спроектирована и создана база данных, состоящая из 9 таблиц. ER-модель спроектированной базы данных представлена на рисунке 9.

Рисунок 9. ER-модель базы данных

Описание всех таблиц базы данных представлено в таблицах 5-13.

Таблица 5

Описание таблицы User (пользователи)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

FIO

varchar

Фамилия Имя и Отчество пользователя

Да

password

varchar

Пароль (в зашифрованном виде)

Да

email

varchar

Адрес электронной почты

Да

role_id

integer

FK

Роль пользователя (связь с таблицей Role)

Да

login

varchar

Логин пользователя

Да

Таблица 6

Описание таблицы Role (Роль пользователя)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

caption

varchar

Наименование роли

Да

Таблица 7

Описание таблицы Category (Категория товаров)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

caption

varchar

Наименование категории

Да

Таблица 8

Описание таблицы Measure (Единица измерения)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

caption

varchar

Наименование единицы измерения

Да

Таблица 9

Описание таблицы Product (Товар)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

caption

varchar

Наименование товара

Да

price_zakup

decimal

Цена закупки

Да

price_cell

decimal

Цена продажи

Да

quantity

decimal

Остаток на складе

Да

category_id

integer

FK

Код категории

Да

measure_id

integer

FK

Код единицы измерения

Да

artikul

varchar

Артикул товара

Нет

code

varchar

Шрихкод товара

Нет

Таблица 10

Описание таблицы Otgruz (Отгрузки)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

createdAt

datetime

Дата и время создания

Да

status

boolean

Статус (проведено или нет)

Да

comment

decimal

Комментарий

Нет

total

decimal

Общая сумма

Да

user_id

integer

FK

Код пользователя

Да

Таблица 11

Описание таблицы ProductOtgruz (Товары в отгрузках)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

price

decimal

Дата и время создания

Да

comment

decimal

Комментарий

Нет

quantity

decimal

Количество товара

Да

product_id

integer

FK

Код товара

Да

otgruz_id

integer

FK

Код отгрузки

Да

Таблица 12

Описание таблицы Postup (Поступления)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

createdAt

datetime

Дата и время создания

Да

status

boolean

Статус (проведено или нет)

Да

comment

decimal

Комментарий

Нет

total

decimal

Общая сумма

Да

user_id

integer

FK

Код пользователя

Да

Таблица 13

Описание таблицы ProductPostup (Товары в поступлениях)

Поле

Тип данных

Ключ

Описание

Обязательное

id

integer

PK

Первичный ключ таблицы

Да

price

decimal

Дата и время создания

Да

comment

decimal

Комментарий

Нет

quantity

decimal

Количество товара

Да

product_id

integer

FK

Код товара

Да

postup_id

integer

FK

Код отгрузки

Да

2.6. Структурная схема пакета (дерево вызова программных модулей)

Популярность языка php обусловила появление большого числа фреймворков, основанных на нем. Фреймворк – программная платформа, определяющая структуру программной системы; программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта.

Для написания информационной системы использовался фреймворк языка php Symfony 2.

Symfony 2 – самый популярный PHP-фреймворк в мире. Он включает в себя весь набор инструментов, используемый для быстрой разработки веб-приложений, и при этом абсолютно ничего не навязывает создаваемому приложению. Разработчик может быстро начать работу, используя дистрибутив Symfony2.

Данный фреймворк работает с подходом к программированию, называемый Model-view-controller (MVC, «модель-представление-контроллер», «модель-вид-контроллер»).

Основная идея данного подхода заключается в разделении данных, их представлениях и обработку действий пользователей на три больших группы:

  • Модель (англ. Model). Модель предоставляет знания: данные и методы работы с этими данными, реагирует на запросы, изменяя своё состояние. Объекты данной группы не содержат информации, как эти знания можно визуализировать.
  • Представление, вид (англ. View). Отвечает за отображение информации (визуализацию). Часто в качестве представления выступает форма (окно) с графическими элементами. Главная задача – представить информацию, хранимой в модели в виде, воспринимаемым пользователем.
  • Контроллер (англ. Controller). Обеспечивает связь между пользователем и системой: контролирует ввод данных пользователем и использует модель и представление для реализации необходимой реакции.

В таблице 14 приведен список разработанных программных модулей-контроллеров, в таблице 15 – модели, в таблице 16 – представления.

Таблица 14

Программные модули Controller

Название

Описание

ReportContoller.php

Класс контроллера, для формирования отчетов

InitializableController.php

Родительский класс контроллера, содержащий методы для отображения данных и форм, обработки отправленных форм

SecurityController.php

Класс контроллера, содержащий методы и функции, необходимые для реализации функций авторизации, выхода из сайта, управления профилем пользователя

PostupController.php

Класс контроллера, содержащий методы для реализации работы с поступлениями товаров

OtgruzController.php

Класс контроллера, содержащий методы для реализации работы с отгрузками товаров

SpravController.php

Класс контроллера, содержащий методы для реализации работы с записями справочников

Таблица 15

Программные модули Model

Название

Описание

AbstractEntity.php

Родительский класс модели, содержащий базовые методы и свойства для реализации классов модели

User.php

Класс модели, содержащий атрибуты и методы для работы с объектом пользователя

Product.php

Класс модели, содержащий атрибуты и методы для работы с объектом товара

Category.php

Класс модели, содержащий атрибуты и методы для работы с объектом категории товара

Measure.php

Класс модели, содержащий атрибуты и методы для работы с объектом единицы измерения

Postup.php

Класс модели, содержащий атрибуты и методы для работы с объектом поступления

ProductPostup.php

Класс модели, содержащий атрибуты и методы для работы с объектом товара в поступлении

Otgruz.php

Класс модели, содержащий атрибуты и методы для работы с объектом отгрузки

ProductOtgruz.php

Класс модели, содержащий атрибуты и методы для работы с объектом товара в отгрузке

Role.php

Класс модели, содержащий атрибуты и методы для работы с объектом роли пользователя

Таблица 16

Программные модули View

Название

Описание

AbstractFormType.php

Класс формы управления данными

LoginFormType.php

Класс формы авторизации

FilterFormType.php

Класс формы для реализации фильтров

UserFormType.php

Класс формы для реализации работы с данными пользователя

PostupFormType.php

Класс формы для реализации работы с данными поступления

OtguzFormType.php

Класс формы для реализации работы с записью отгрузки

MeasureFormType.php

Класс формы для реализации работы с единицами измерения

ProductFormType.php

Класс формы для реализации работы с товарами

CategoryFormType.php

Класс формы для реализации работы с категориями товаров

Структурная схема пакета (дерево вызова программных модулей) приведена на рисунке 10.

Рисунок 10. Структурная схема пакета

Исходный код программных модулей представлен в приложении.

2.8. Контрольный пример реализации проекта и его описание

При открытии сайта информационной системы открывается форма авторизации (Рисунок 11).

Рисунок 11. Форма авторизации

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

Рисунок 12. Раздел работы с поступлениями

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

При нажатии на кнопку «Добавить поступление» открывается форма создания поступления. На ней нужно указать товары, которые поступают. Для каждого товара указывается цена (по молчанию подставляется закупочная цена товара из справочника товаров) и количество (Рисунок 13).

Рисунок 13. Форма создания поступления товаров

Стоит отметить, что при сохранении нового поступления автоматически фиксируется пользователь, который его создал и время создания. После нажатия на кнопку «Сохранить» страница обновляется (Рисунок 14), поступлению присваивается статус «Черновик».

Рисунок 14. Поступление после сохранения

Чтобы поступившие товары добавились к остаткам необходимо нажать кнопку «Провести» после сохранения поступления. Перед проведением система запрашивает подтверждение пользователя (Рисунок 15).

Рисунок 15. Запрос подтверждения проведения поступления

После того, как поступление будет проведено, система добавить указанные в нем товары на баланс. Также поменяется и внешний вид поступления (Рисунок 16). Стоит отметить, что кнопка «Отменить проведение» доступна только пользователям с ролью «Администратор».

Рисунок 16. Форма просмотра данных поступления

Формы для работы с отгрузками имеют аналогичный вид.

При переходе в раздел справочника открывается список записей справочника. На рисунке 17 приведен скриншот формы просмотра записей справочника товаров.

Рисунок 17. Форма просмотра справочника товаров

Над таблицей с записями справочника отображается фильтра для поиска нужного товара. При добавлении кнопки «Добавить» отображается форма добавления нового товара (Рисунок 18).

Рисунок 18. Форма добавления нового товара

На форме работы с данными товара добавляются дополнительные вкладки для просмотра поступлений и отгрузок данного товара со склада (Рисунок 17).

Рисунок 19. Вкладка просмотра поступлений товара

Формы работы с другими справочниками имеют более простой вид (Рисунок 20-22).

Рисунок 20. Форма работы со справочником «Категория товаров»

Рисунок 21. Форма работы со справочником «Единица измерения»

Рисунок 22. Форма работы со справочником «Пользователь»

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

Для формирования отчета о движении товаров нужно указать интервал дат, за который следует выбрать данные (Рисунок 23).

Рисунок 23. Форма ввода интервала дат для формирования отчета

Сформированный отчет выгружается в формате CSV. Данный файл открывается с помощью редактора электронных таблиц Microsoft Excel иди OpenOffice Calc. Пример сформированного отчета приведен на рисунке 24.

Рисунок 24. Сформированный отчет о движении товаров

Для формирования отчета по остаткам товаров никаких параметров не требуется, за исключением того, что можно выбрать категории товаров, для которых нужно формировать отчет. Если ни одна категория не выбрана, то отчет сформируется сразу для всех (Рисунок 25).

Рисунок 25. Форма для выбора категорий

Сформированный отчет также выгружается в виде файла в формате CSV (Рисунок 26).

Рисунок 26. Сформированный отчет об остатках

ЗАКЛЮЧЕНИЕ

В ходе проделанной работы были решены следующие задачи:

  • была проанализирована текущая организация бизнес-процесса складского учета в компании ООО «Атлетика», были выделены основные этапы выполнения бизнес-процесса, изучен возникающий документооборот;
  • были выбраны проектные решения по информационному обеспечению и программному, в качестве языка программирования был выбран php, а в качестве СУБД – Mysql;
  • была составлена информационная модель информационной системы, которая отражает пути преобразования входной информации в выходную;
  • была разработана база данных и программные модули, реализующие работу ИС.
  • был описан контрольный пример реализации проекта.

Таким образом, все задачи, поставленные перед данным курсовым проектом выполнены, а значит и основная цель достигнута.

СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ

1. ГОСТ 2.105 – 95. Общие требования к текстовым документам.

2. ГОСТ 7.32 – 2001. Отчет по научно-исследовательской работе. Структура и правила оформления.

3. ГОСТ 7.82-2001. Библиографическое описание электронных ресурсов.

4. ГОСТ 24.702-85 Эффективность автоматизированных систем управления.

5. ГОСТ Р 7.0.5-2008. Библиографическая запись. Библиографическое описание.

6. Алистер Коберн, Современные методы описания функциональных требований к системам, М.: издательство "Лори", 2017. – 288 с

9. Дунаев В. HTML, скрипты и стили / В. Дунаев. – Спб. : БХВ-Петербург, 2015. – 816 с.

10. Жадеев А. PHP для начинающих / А. Жадеев. – Спб.: «Питер», 2014. – 592 c.

11. Колисниченко Д. PHP и MySQL. Разработка WEB-приложений / Д. Колисниченков – Спб: БХВ-Петербург, 2013. – 560 с.

12. Конналли Т. Базы данных. Проектирование, реализация и сопровождение. Теория и практика / Т. Коналли, К. Бегг. – М.: Издательский дом «Вильямс», 2013. – 1093 c.

13. Лобова Г. Моделирование и анализ бизнес-процессов SADT. – М.: LAP Lambert Academic Publishing, 2014. – 352 c.

14. Макдональд, М. Созданиец Web-сайта. Недостающее руководство / М. Макдональд. – Спб. : БХВ-Петербург, 2013. – 624 с.

17. Маклаков С.В. BPwin и Erwin. CASE-средства разработки информационных систем / С.В. Маклаков. – М. : ДИАЛОГ–МИФИ, 2014. – 369 c.

18. Тельнов, Ю.Ф. Информационные системы и технологии. Information System and Technologies: науч. издание под ред. Тельнова Ю. Ф. – М: Юнити-Дана, 2012 – 303 с.

19. Флэнаган, Д. Javascript. Подробное руководство / Д. Флэнаган : пер с англ. – М. : Символ-Плюс, 2013. – 1080 с.

ПРИЛОЖЕНИЯ

<?php

namespace AppBundle\Controller;

use AppBundle\Entity\Client;

use AppBundle\Entity\Notification;

use AppBundle\Entity\Postup;

use AppBundle\Entity\PostupComment;

use AppBundle\Entity\PostupProduct;

use AppBundle\Entity\User;

use AppBundle\Form\Type\PostupFilterFormType;

use AppBundle\Form\Type\PostupFormType;

use AppBundle\Form\Type\PostupProductFormType;

use Doctrine\ORM\Query;

use Sensio\Bundle\FrameworkExtraBundle\Configuration as Config;

use Symfony\Component\HttpFoundation\JsonResponse;

use Symfony\Component\HttpFoundation\RedirectResponse;

use Symfony\Component\HttpFoundation\Response;

class PostupController extends InitializableController

{

/**

* @return RedirectResponse|Response

* @Config\Route("/postups/index/{pagenum}", name = "site_postups_index", defaults={ "pagenum": "1"})

*/

public function indexAction($pagenum=1)

{

$form=$this->createForm(new PostupFilterFormType());

$caption = null;

$form->handleRequest($this->request);

$postupsquery = $this->getRepository('Postup')->createQueryBuilder('o')

->where('o.deleted = 0')

->addPostupBy('o.status', 'ASC')

->addPostupBy('o.createdAt', 'ASC');

$postupsquerycount = $this->getRepository('Postup')->createQueryBuilder('o')

->select('COUNT(DISTINCT o.id)')

->where('o.deleted = 0');

if ($form->isSubmitted() && $form->isValid()) {

$id = $form->get('id')->getData();

$status=$form->get('status')->getData();

$user=$form->get('user')->getData();

}

if (!empty($id)) {

$postupsquery->andWhere('o.id = :id')->setParameter('id', $id);

$postupsquerycount->andWhere('o.id = :id')->setParameter('id', $id);

}

if (!empty($status)) {

$postupsquery->andWhere('o.status = :status')->setParameter('status', $status);

$postupsquerycount->andWhere('o.status = :status')->setParameter('status', $status);

}

if (!empty($user)) {

$postupsquery->andWhere('o.user = :user')->setParameter('user', $user);

$postupsquerycount->andWhere('o.user = :user')->setParameter('user', $user);

}

$count=$postupsquerycount->getQuery()->getSingleScalarResult();

$pages = floor($count / 20) + ($count % 20 > 0 ? 1 : 0);

if ($pages < 1) $pages = 1;

if ($pagenum > $pages) $pagenum = $pages;

$postups = $postupsquery->setFirstResult(($pagenum - 1) * 20)

->setMaxResults(20)

->getQuery()->getResult();

$this->view['postups'] = $postups;

$this->view['form'] = $form->createView();

$this->view['page']=$pagenum;

$this->view['pages']=$pages;

$this->navigation = array('active' => 'postups');

return $this->render('AppBundle:Postups:index.html.twig');

}

/**

* @return RedirectResponse|Response

* @Config\Route("/postups/add", name = "site_postups_add")

*/

public function addAction()

{

$postup = new Postup();

$client_id=$this->request->get('client_id');

if (!(empty($client_id))) {

/** @var Client $client */

$client=$this->getRepository('Client')->findOneBy(array('id'=>$client_id));

$postup->setClient($client);

}

$form = $this->createForm(new PostupFormType(), $postup);

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var PostupStatus $newstatus**/

$newstatus = $this->getRepository('PostupStatus')->findOneBy(array('id'=>1));

$postup->setStatus($newstatus);

$postup->setUser($this->user);

$this->manager->persist($postup);

$this->manager->flush();

$this->addNotice('success',

'postups.html.twig',

array('notice' => 'added', 'caption' => $postup->getId())

);

return $this->redirectToRoute('site_postups_edit',array('postup' => $postup->getId(), 'step' => 1));

}

$this->view['postup'] = null;

$this->forms['postup'] = $form->createView();

$this->navigation = array('active' => 'postups');

return $this->render('AppBundle:Postups:postup1.html.twig');

}

/**

* @param Postup $postup

* @return RedirectResponse|Response

* @Config\Route("/postups/{postup}/edit/{step}", name = "site_postups_edit")

* @Config\ParamConverter("postup", options = {"mapping": {"postup": "id"}})

*/

public function editAction(Postup $postup, $step)

{

if ($step > 4) {

$step = 4;

}

switch ($step) {

//общие данные

case 1:

$form = $this->createForm(new PostupFormType(), $postup);

if ($this->request->isMethod('POST')) {

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

$postup->setUser($this->user);

$this->manager->persist($postup);

$this->manager->flush();

$this->addNotice('success',

'postups.html.twig',

array('notice' => 'changed', 'caption' => $postup->getId())

);

return $this->redirectToRoute(

'site_postups_edit',

array('postup' => $postup->getId(), 'step' => 1)

);

}

}

$this->view['postup'] = $postup;

$this->forms['postup'] = $form->createView();

break;

//список товаров

case 2:

$form = $this->createForm(new PostupProductFormType());

$products=$this->getRepository('PostupProduct')->createQueryBuilder('op')

->leftJoin('op.product','p')

->where('p.deleted <> 1')

->andWhere('op.postup = :postup')

->setParameters(array('postup'=>$postup))

->postupBy('p.category')->getQuery()->getResult();

if ($this->request->isXmlHttpRequest() && $this->request->isMethod('POST')) {

return $this->handleProductsAjaxRequest();

}

if ($this->request->isMethod('POST')) {

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var PostupProduct $postupproduct */

$postupproduct = $form->getData();

$postupproduct->setPostup($postup);

$postupproduct->setPrice($postupproduct->getProduct()->getPrice());

$this->manager->persist($postupproduct);

$this->manager->flush();

$postup->refreshCurrency();

$this->manager->persist($postup);

$this->manager->flush();

return $this->redirectToRoute(

'site_postups_edit',

array('postup' => $postup->getId(), 'step' => 2)

);

}

}

$this->view['postup'] = $postup;

$this->view['products'] = $products;

$this->forms['postupproduct'] = $form->createView();

$this->navigation = array('active' => 'postups');

return $this->render('AppBundle:Postups:postup2.html.twig');

break;

//список услуг

case 3:

$form = $this->createForm(new PostupServiceFormType());

$services=$this->getRepository('PostupService')->createQueryBuilder('os')

->leftJoin('os.service','s')

->where('s.deleted <> 1')

->andWhere('os.postup = :postup')

->setParameters(array('postup'=>$postup))

->postupBy('s.caption')->getQuery()->getResult();

if ($this->request->isMethod('POST')) {

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var PostupService $postupservice */

$postupservice = $form->getData();

$postupservice->setPostup($postup);

$postupservice->setPrice($postupservice->getService()->getPrice());

$this->manager->persist($postupservice);

$this->manager->flush();

$postup->refreshCurrency();

$this->manager->persist($postup);

$this->manager->flush();

return $this->redirectToRoute(

'site_postups_edit',

array('postup' => $postup->getId(), 'step' => 3)

);

}

}

$this->view['postup'] = $postup;

$this->view['services'] = $services;

$this->forms['postupservice'] = $form->createView();

$this->navigation = array('active' => 'postups');

return $this->render('AppBundle:Postups:postup3.html.twig');

break;

//доки

case 4:

$this->view['postup'] = $postup;

$this->navigation = array('active' => 'postups');

return $this->render('AppBundle:Postups:postup4.html.twig');

break;

}

$this->navigation = array('active' => 'postups');

return $this->render('AppBundle:Postups:postup'.$step.'.html.twig');

}

protected function handleProductsAjaxRequest()

{

$category = $this->request->get('category', null);

if (is_null($category)) return new JsonResponse();

$products=$this->getRepository('Product')->createQueryBuilder('p')

->select('p.id as id')

->where('p.category = :category')

->andWhere('p.deleted=0')

->setParameters(array('category'=> $category))

->getQuery()->getResult(Query::HYDRATE_ARRAY);

return new JsonResponse($products);

}

/**

* @param Postup $postup

* @return Response

* @Config\Route("/postups/{postup}/remove", name = "site_postups_remove")

* @Config\ParamConverter("postup", options = {"mapping": {"postup": "id"}})

*/

public function removeAction(Postup $postup)

{

$postup->setDeleted(true);

$this->manager->persist($postup);

$this->manager->flush();

return $this->redirectToRoute('site_postups_index');

}

/**

* @param Postup $postup

* @return Response

* @Config\Route("/postups/{postup}/changestatus/{status}", name = "site_postups_changestatus")

* @Config\ParamConverter("postup", options = {"mapping": {"postup": "id"}})

*/

public function changestatusAction(Postup $postup, $status)

{

$oldstatus=$postup->getStatus()->getId();

/** @var PostupStatus $newstatus**/

$newstatus = $this->getRepository('PostupStatus')->findOneBy(array('id'=>$status));

$postup->setStatus($newstatus);

//отправляем уведомление пользователю

$descriptiontext='';

$notifusers=$postup->getSpecs();

switch ($status) {

case 2:

$descriptiontext="Вам был назначен новый заказ № ".$postup->getId().". Не забудьте подтвердить принятие в работу. <a href='".$this->generateUrl('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>1))."'>Подробнее</a> ";

break;

case 3:

//если перед этим был статус "Ждет подтверждения"

if ($oldstatus==4) {

$descriptiontext="Заказ № ".$postup->getId()." был вернут в работу. <a href='".$this->generateUrl('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>1))."'>Подробнее</a> ";

//отменяем выбор поставщика

foreach ($postup->getPostupproviders() as $postupprovider) {

$postupprovider->setSelected(false);

$this->manager->persist($postupprovider);

$this->manager->flush();

}

}

//иначе увеомление админу

else {

$descriptiontext="Пользователь ".$this->getUser()->getUserfio()." принял заказ № ".$postup->getId()." в работу. <a href='".$this->generateUrl('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>1))."'>Подробнее</a> ";

$notifusers=array();

/** @var User $notifuser**/

$notifuser = $this->getRepository('User')->findOneBy(array('username'=>'admin'));

array_push($notifusers,$notifuser );

}

break;

case 5: $descriptiontext="Выбор поставщика в заказе №".$postup->getId()." был утвержден. <a href='".$this->generateUrl('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>1))."'>Подробнее</a>";

break;

case 6: $descriptiontext="Заказ №".$postup->getId()." был отменен. <a href='".$this->generateUrl('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>1))."'>Подробнее</a>";

break;

}

foreach ( $notifusers as $notifuser) {

$this->addNotification($notifuser,$descriptiontext);

}

$this->manager->persist($postup);

$this->manager->flush();

$this->addNotice('success',

'postups.html.twig',

array('notice' => 'postup_changestatus', 'caption' => $postup->getId())

);

return $this->redirectToRoute('site_postups_edit', array('postup' => $postup->getId(), 'step' => 1));

}

/**

* @param PostupProduct $postupproduct

* @param Postup $postup

* @return Response

* @Config\Route("/postups/{postup}/postupproducts/{postupproduct}/remove", name = "site_postupproducts_remove")

* @Config\ParamConverter("postupproduct", options = {"mapping": {"postupproduct": "id"}})

* @Config\ParamConverter("postup", options = {"mapping": {"postup": "id"}})

*/

public function removeproductAction(PostupProduct $postupproduct, Postup $postup)

{

$this->manager->remove($postupproduct);

$this->manager->flush();

$postup->refreshCurrency();

$this->manager->persist($postup);

$this->manager->flush();

return $this->redirectToRoute('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>2));

}

/**

* @param PostupService $postupservice

* @param Postup $postup

* @return Response

* @Config\Route("/postups/{postup}/postupservices/{postupservice}/remove", name = "site_postupservices_remove")

* @Config\ParamConverter("postupservice", options = {"mapping": {"postupservice": "id"}})

* @Config\ParamConverter("postup", options = {"mapping": {"postup": "id"}})

*/

public function removeserviceAction(PostupService $postupservice, Postup $postup)

{

$this->manager->remove($postupservice);

$this->manager->flush();

$postup->refreshCurrency();

$this->manager->persist($postup);

$this->manager->flush();

return $this->redirectToRoute('site_postups_edit', array('postup'=>$postup->getId(), 'step'=>3));

}

public function addNotification (User $user, $description) {

$notification = new Notification();

$notification->setUser($user);

$notification->setDescription($description);

$this->manager->persist($notification);

$this->manager->flush();

}

}

<?php

namespace AppBundle\Controller;

use AppBundle\Entity\Client;

use AppBundle\Entity\Notification;

use AppBundle\Entity\Otgruz;

use AppBundle\Entity\OtgruzProduct;

use AppBundle\Entity\OtgruzStatus;

use AppBundle\Entity\ProviderProduct;

use AppBundle\Entity\User;

use AppBundle\Form\Type\OtgruzCommentFormType;

use AppBundle\Form\Type\OtgruzEndFormType;

use AppBundle\Form\Type\OtgruzFilterFormType;

use AppBundle\Form\Type\OtgruzFormType;

use AppBundle\Form\Type\OtgruzProductFormType;

use Doctrine\ORM\Query;

use Sensio\Bundle\FrameworkExtraBundle\Configuration as Config;

use Symfony\Component\HttpFoundation\JsonResponse;

use Symfony\Component\HttpFoundation\RedirectResponse;

use Symfony\Component\HttpFoundation\Response;

class OtgruzController extends InitializableController

{

/**

* @return RedirectResponse|Response

* @Config\Route("/otgruzs/index/{pagenum}", name = "site_otgruzs_index", defaults={ "pagenum": "1"})

*/

public function indexAction($pagenum=1)

{

$form=$this->createForm(new OtgruzFilterFormType());

$caption = null;

$form->handleRequest($this->request);

$otgruzsquery = $this->getRepository('Otgruz')->createQueryBuilder('o')

->where('o.deleted = 0')

->addOtgruzBy('o.status', 'ASC')

->addOtgruzBy('o.createdAt', 'ASC');

$otgruzsquerycount = $this->getRepository('Otgruz')->createQueryBuilder('o')

->select('COUNT(DISTINCT o.id)')

->where('o.deleted = 0');

if ($form->isSubmitted() && $form->isValid()) {

$id = $form->get('id')->getData();

$status=$form->get('status')->getData();

$user=$form->get('user')->getData();

}

if (!empty($id)) {

$otgruzsquery->andWhere('o.id = :id')->setParameter('id', $id);

$otgruzsquerycount->andWhere('o.id = :id')->setParameter('id', $id);

}

if (!empty($status)) {

$otgruzsquery->andWhere('o.status = :status')->setParameter('status', $status);

$otgruzsquerycount->andWhere('o.status = :status')->setParameter('status', $status);

}

if (!empty($user)) {

$otgruzsquery->andWhere('o.user = :user')->setParameter('user', $user);

$otgruzsquerycount->andWhere('o.user = :user')->setParameter('user', $user);

}

$count=$otgruzsquerycount->getQuery()->getSingleScalarResult();

$pages = floor($count / 20) + ($count % 20 > 0 ? 1 : 0);

if ($pages < 1) $pages = 1;

if ($pagenum > $pages) $pagenum = $pages;

$otgruzs = $otgruzsquery->setFirstResult(($pagenum - 1) * 20)

->setMaxResults(20)

->getQuery()->getResult();

$this->view['otgruzs'] = $otgruzs;

$this->view['form'] = $form->createView();

$this->view['page']=$pagenum;

$this->view['pages']=$pages;

$this->navigation = array('active' => 'otgruzs');

return $this->render('AppBundle:Otgruzs:index.html.twig');

}

/**

* @return RedirectResponse|Response

* @Config\Route("/otgruzs/add", name = "site_otgruzs_add")

*/

public function addAction()

{

$otgruz = new Otgruz();

$client_id=$this->request->get('client_id');

if (!(empty($client_id))) {

/** @var Client $client */

$client=$this->getRepository('Client')->findOneBy(array('id'=>$client_id));

$otgruz->setClient($client);

}

$form = $this->createForm(new OtgruzFormType(), $otgruz);

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var OtgruzStatus $newstatus**/

$newstatus = $this->getRepository('OtgruzStatus')->findOneBy(array('id'=>1));

$otgruz->setStatus($newstatus);

$otgruz->setUser($this->user);

$this->manager->persist($otgruz);

$this->manager->flush();

$this->addNotice('success',

'otgruzs.html.twig',

array('notice' => 'added', 'caption' => $otgruz->getId())

);

return $this->redirectToRoute('site_otgruzs_edit',array('otgruz' => $otgruz->getId(), 'step' => 1));

}

$this->view['otgruz'] = null;

$this->forms['otgruz'] = $form->createView();

$this->navigation = array('active' => 'otgruzs');

return $this->render('AppBundle:Otgruzs:otgruz1.html.twig');

}

/**

* @param Otgruz $otgruz

* @return RedirectResponse|Response

* @Config\Route("/otgruzs/{otgruz}/edit/{step}", name = "site_otgruzs_edit")

* @Config\ParamConverter("otgruz", options = {"mapping": {"otgruz": "id"}})

*/

public function editAction(Otgruz $otgruz, $step)

{

if ($step > 4) {

$step = 4;

}

switch ($step) {

//общие данные

case 1:

$form = $this->createForm(new OtgruzFormType(), $otgruz);

if ($this->request->isMethod('POST')) {

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

$otgruz->setUser($this->user);

$this->manager->persist($otgruz);

$this->manager->flush();

$this->addNotice('success',

'otgruzs.html.twig',

array('notice' => 'changed', 'caption' => $otgruz->getId())

);

return $this->redirectToRoute(

'site_otgruzs_edit',

array('otgruz' => $otgruz->getId(), 'step' => 1)

);

}

}

$this->view['otgruz'] = $otgruz;

$this->forms['otgruz'] = $form->createView();

break;

//список товаров

case 2:

$form = $this->createForm(new OtgruzProductFormType());

$products=$this->getRepository('OtgruzProduct')->createQueryBuilder('op')

->leftJoin('op.product','p')

->where('p.deleted <> 1')

->andWhere('op.otgruz = :otgruz')

->setParameters(array('otgruz'=>$otgruz))

->otgruzBy('p.category')->getQuery()->getResult();

if ($this->request->isXmlHttpRequest() && $this->request->isMethod('POST')) {

return $this->handleProductsAjaxRequest();

}

if ($this->request->isMethod('POST')) {

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var OtgruzProduct $otgruzproduct */

$otgruzproduct = $form->getData();

$otgruzproduct->setOtgruz($otgruz);

$otgruzproduct->setPrice($otgruzproduct->getProduct()->getPrice());

$this->manager->persist($otgruzproduct);

$this->manager->flush();

$otgruz->refreshCurrency();

$this->manager->persist($otgruz);

$this->manager->flush();

return $this->redirectToRoute(

'site_otgruzs_edit',

array('otgruz' => $otgruz->getId(), 'step' => 2)

);

}

}

$this->view['otgruz'] = $otgruz;

$this->view['products'] = $products;

$this->forms['otgruzproduct'] = $form->createView();

$this->navigation = array('active' => 'otgruzs');

return $this->render('AppBundle:Otgruzs:otgruz2.html.twig');

break;

//список услуг

case 3:

$form = $this->createForm(new OtgruzServiceFormType());

$services=$this->getRepository('OtgruzService')->createQueryBuilder('os')

->leftJoin('os.service','s')

->where('s.deleted <> 1')

->andWhere('os.otgruz = :otgruz')

->setParameters(array('otgruz'=>$otgruz))

->otgruzBy('s.caption')->getQuery()->getResult();

if ($this->request->isMethod('POST')) {

$form->handleRequest($this->request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var OtgruzService $otgruzservice */

$otgruzservice = $form->getData();

$otgruzservice->setOtgruz($otgruz);

$otgruzservice->setPrice($otgruzservice->getService()->getPrice());

$this->manager->persist($otgruzservice);

$this->manager->flush();

$otgruz->refreshCurrency();

$this->manager->persist($otgruz);

$this->manager->flush();

return $this->redirectToRoute(

'site_otgruzs_edit',

array('otgruz' => $otgruz->getId(), 'step' => 3)

);

}

}

$this->view['otgruz'] = $otgruz;

$this->view['services'] = $services;

$this->forms['otgruzservice'] = $form->createView();

$this->navigation = array('active' => 'otgruzs');

return $this->render('AppBundle:Otgruzs:otgruz3.html.twig');

break;

//доки

case 4:

$this->view['otgruz'] = $otgruz;

$this->navigation = array('active' => 'otgruzs');

return $this->render('AppBundle:Otgruzs:otgruz4.html.twig');

break;

}

$this->navigation = array('active' => 'otgruzs');

return $this->render('AppBundle:Otgruzs:otgruz'.$step.'.html.twig');

}

protected function handleProductsAjaxRequest()

{

$category = $this->request->get('category', null);

if (is_null($category)) return new JsonResponse();

$products=$this->getRepository('Product')->createQueryBuilder('p')

->select('p.id as id')

->where('p.category = :category')

->andWhere('p.deleted=0')

->setParameters(array('category'=> $category))

->getQuery()->getResult(Query::HYDRATE_ARRAY);

return new JsonResponse($products);

}

/**

* @param Otgruz $otgruz

* @return Response

* @Config\Route("/otgruzs/{otgruz}/remove", name = "site_otgruzs_remove")

* @Config\ParamConverter("otgruz", options = {"mapping": {"otgruz": "id"}})

*/

public function removeAction(Otgruz $otgruz)

{

$otgruz->setDeleted(true);

$this->manager->persist($otgruz);

$this->manager->flush();

return $this->redirectToRoute('site_otgruzs_index');

}

/**

* @param Otgruz $otgruz

* @return Response

* @Config\Route("/otgruzs/{otgruz}/changestatus/{status}", name = "site_otgruzs_changestatus")

* @Config\ParamConverter("otgruz", options = {"mapping": {"otgruz": "id"}})

*/

public function changestatusAction(Otgruz $otgruz, $status)

{

$oldstatus=$otgruz->getStatus()->getId();

/** @var OtgruzStatus $newstatus**/

$newstatus = $this->getRepository('OtgruzStatus')->findOneBy(array('id'=>$status));

$otgruz->setStatus($newstatus);

//отправляем уведомление пользователю

$descriptiontext='';

$notifusers=$otgruz->getSpecs();

switch ($status) {

case 2:

$descriptiontext="Вам был назначен новый заказ № ".$otgruz->getId().". Не забудьте подтвердить принятие в работу. <a href='".$this->generateUrl('site_otgruzs_edit', array('otgruz'=>$otgruz->getId(), 'step'=>1))."'>Подробнее</a> ";

break;

case 3:

//если перед этим был статус "Ждет подтверждения"

if ($oldstatus==4) {

$descriptiontext="Заказ № ".$otgruz->getId()." был вернут в работу. <a href='".$this->generateUrl('site_otgruzs_edit', array('otgruz'=>$otgruz->getId(), 'step'=>1))."'>Подробнее</a> ";

//отменяем выбор поставщика

foreach ($otgruz->getOtgruzproviders() as $otgruzprovider) {

$otgruzprovider->setSelected(false);

$this->manager->persist($otgruzprovider);

$this->manager->flush();

}

}

//иначе увеомление админу

else {

$descriptiontext="Пользователь ".$this->getUser()->getUserfio()." принял заказ № ".$otgruz->getId()." в работу. <a href='".$this->generateUrl('site_otgruzs_edit', array('otgruz'=>$otgruz->getId(), 'step'=>1))."'>Подробнее</a> ";

$notifusers=array();

/** @var User $notifuser**/

$notifuser = $this->getRepository('User')->findOneBy(array('username'=>'admin'));

array_push($notifusers,$notifuser );

}

break;

case 5: $descriptiontext="Выбор поставщика в заказе №".$otgruz->getId()." был утвержден. <a href='".$this->generateUrl('site_otgruzs_edit', array('otgruz'=>$otgruz->getId(), 'step'=>1))."'>Подробнее</a>";

break;

case 6: $descriptiontext="Заказ №".$otgruz->getId()." был отменен. <a href='".$this->generateUrl('site_otgruzs_edit', array('otgruz'=>$otgruz->getId(), 'step'=>1))."'>Подробнее</a>";

break;

}

foreach ( $notifusers as $notifuser) {

$this->addNotification($notifuser,$descriptiontext);

}

$this->manager->persist($otgruz);

$this->manager->flush();

$this->addNotice('success',

'otgruzs.html.twig',

array('notice' => 'otgruz_changestatus', 'caption' => $otgruz->getId())

);

return $this->redirectToRoute('site_otgruzs_edit', array('otgruz' => $otgruz->getId(), 'step' => 1));

}

/**

* @param OtgruzProduct $otgruzproduct

* @param Otgruz $otgruz

* @return Response

* @Config\Route("/otgruzs/{otgruz}/otgruzproducts/{otgruzproduct}/remove", name = "site_otgruzproducts_remove")

* @Config\ParamConverter("otgruzproduct", options = {"mapping": {"otgruzproduct": "id"}})

* @Config\ParamConverter("otgruz", options = {"mapping": {"otgruz": "id"}})

*/

public function removeproductAction(OtgruzProduct $otgruzproduct, Otgruz $otgruz)

{

$this->manager->remove($otgruzproduct);

$this->manager->flush();

$otgruz->refreshCurrency();

$this->manager->persist($otgruz);

$this->manager->flush();

return $this->redirectToRoute('site_otgruzs_edit', array('otgruz'=>$otgruz->getId(), 'step'=>2));

}