ABACUS Financial
ABACUS Builder
ABACUS Professional
ABACUS WEB
|
Клиенты и представители
Вашему вниманию предлагается еще одна зарисовка по опыту разработки и внедрения корпоративной системы автоматизации учета и управления экономической деятельностью предприятий и холдингов оптовой торговли ПроектИнформ Негоциант™ (ПИН™), созданной с помощью системы разработки корпоративных информационных систем ABACUS Builder™ (AB7™) производства московской фирмы "ОМЕГА". О том, что собой представляет система ПИН™, ее основных возможностях, истории ее создания, а так же об инструменте разработки AB7™ я рассказывал в своей предыдущей статье "ПроектИнформ Негоциант™ или что могут сделать с ABACUS Builder полтора человека за полтора года.
В этой зарисовке речь пойдет о талантах и поклонниках клиентах и их представителях. Коротко о сути проблемы. В группе компаний (для простоты буду называть его холдингом), для которой создавалась система ПИН™, сложилась следующая практика работы с покупателями: все покупатели делились на клиентов и представителей. И клиенты, и их представители - это контрагенты предприятий холдинга (это могут быть как юридические, так и физические лица), вступающие в торговые отношения с предприятиями холдинга. То есть, и клиенты и их представители могут покупать и оплачивать товар. Разница заключается в том, что вся "дебиторская" задолженность ведется по клиенту, в независимости от того, кому был отпущен товар, и от кого пришла оплата. Например, возможны варианты, когда товар был отпущен представителю "А" некоторого клиента, а оплата получена от представителя "Б" того же клиента. При этом, условия работы с контрагентом (максимальная отсрочка платежа, максимальная задолженность, прайс-лист и др.) устанавливаются для клиента. Представители "наследуют" прайс-лист от клиента, но могут иметь и свой прайс-лист по определенным позициям. Менеджеры предприятий холдинга, являющиеся кураторами клиентов, автоматически становятся кураторами их представителей со всеми вытекающими последствиями, включая бонусы с продаж. Возвраты товара могут осуществляться в объемах, не превышающих объемы, отгруженные клиенту и всем его представителям в сумме. Ну и последнее условие: клиент может иметь неограниченное количество представителей, а представитель может быть представителем только одного клиента.
Все эти аспекты взаимоотношений с контрагентами предприятий холдинга и необходимо было отразить в корпоративной системе ПИН™.
Как это было сделано я вам и расскажу. Однако, здесь вам потребуется некоторое представление о модели данных, реализованной в системе разработки корпоративных информационных систем ABACUS Builder™. Эту модель я описывал в своей предыдущей статье. Поэтому, тому, кто ее читал, или тому, кто не обладает достаточной психологической устойчивостью, чтобы справиться со словом "иерархический", советую пропустить врезку.
|
Для остальных же конспективно изложу основные принципы модели данных AB7™. В основе модели данных лежит направленный граф понятий предметной области. Понятия (их еще часть называют "сущности") в приложении к экономическим системам - это предприятие, подразделение предприятия, сотрудник, контрагент, накладная, счет-фактура, платежное поручение и т.д. и т.п.
Каждое из понятий характеризуется определенным набором свойств. Например, предприятие характеризуется наименованием, юридическим адресом, ИНН, КПП, ОКПО, ОГРН и прочими труднопроизносимыми аббревиатурами (тоже, кстати, еще то словечко), которые простому смертному кажутся шаманскими заклинаниями. Отчасти это так и есть. Сотрудник характеризуется фамилией, именем, а большинство в нашей стране даже отчеством, местом проживания, полом (это, понятно не про паркет по месту проживания), паспортными данными и т.д. Все эти понятия находятся друг с другом в иерархической связи. Подразделение "входит" в предприятие, сотрудник "подчиняется" предприятию и подразделению, накладная с одной стороны "принадлежит" предприятию, а с другой контрагенту.
В модели данных AB7™ понятия предметной области принято называть "категориями", свойства понятий "атрибутами категорий" а иерархические связи понятий "связями категорий". Атрибуты могут быть строковыми, числовыми или иметь тип "дата". Связи категорий направлены и имеют "силу" сверху вниз "один ко многим" (предприятие может включать в свой состав несколько подразделений), снизу вверх "один к одному" (подразделение может входить в состав только одного предприятия).
Экземпляр категории называется "объектом". Объект "наследует все свойства категории. То есть, объект может иметь атрибуты, определенные для категории, и направленные связи с объектами других категорий, если между этими категориями определены такие связи. Причем "снизу" может быть привязано любое количество объектов "нижней категории" (связь "один ко многим"), а "сверху" к объекту может быть привязан только один объект другой категории (связь "один к одному"). Обратите внимание, что "сверху" к объекту могут быть привязаны несколько объектов, но только по одному из каждой категории. Для простоты восприятия можно провести аналогию с обычными таблицами базы данных (сразу скажу, что в AB7™ это сделано совсем иначе). "Категория" - это таблица с полями ("атрибуты категории"). "Объект" это запись в таблице с реальными значениями полей ("атрибуты объекта"). "Связи" - это скрытые ключевые поля таблиц.
Встроенный в AB7™ язык запросов к базе данных AQL (ABACUS Query Language) имеет директивы перемещения по "дереву объектов":
- ":КАТЕГОРИЯ" - перемещение вниз на категорию. Возвращает объекты указанной категории, привязанные снизу к объектам, переданным на вход директивы.
- "^КАТЕГОРИЯ" - перемещение вверх на категорию. Возвращает объекты указанной категории, привязанные сверху к объектам, переданным на вход директивы.
Это, пожалуй, все, что необходимо знать для понимания принципов решения проблемы клиентов и представителей.
|
Как же была решена проблема клиентов и представителей?
Первое возможное решение - сделать две категории "Клиенты" и "Представители" и привязать категорию представители снизу к категории клиенты. Второе возможное решение сделать одну категорию "Контрагенты", выделить из них клиентов и представителей и обеспечить привязку представителей к клиенту.
Рассмотрим преимущества и недостатки первого способа.
Преимущества:
- Логичная иерархическая схема данных.
- Простота определения представителей для клиентов и клиента для представителей. В AQL-запросе достаточно, соответственно "спуститься вниз" от объекта клиента на категорию "Представители" или "подняться вверх" от объекта представителя на категорию "Клиенты".
- Поскольку и представители, и клиенты являются контрагентами предприятий холдинга, то есть имеют одну и ту же структуру данных, то необходимо создать две различные категории с абсолютно одинаковым набором категорий и связей. Кстати говоря, категория "Контрагент" имеет 62 атрибута, 11 верхних и 72 нижних связи.
- Поскольку функциональность у этих категорий также одинаковая необходимо для каждой категории создать практически повторяющийся набор экранных форм. В Системе ПИН™ в настоящее время существует 32 экранных формы для категории "Контрагент". На самом деле с точки зрения хранимых данных это не большой объем информации. Главная проблема в другом. В процессе разработки и эксплуатации системы постоянно приходится дорабатывать экранные формы, добавляя в них новый функционал, улучшая представление и т.д. В таком подходе все изменения придется проводить дважды, что в два раза повышает вероятность возникновения ошибки и увеличивает время разработки.
- Во всех документах (накладных, счетах-фактурах, платежных поручениях и т.д. и т.п.) необходимо обеспечить возможность их привязки как к клиентам, так и к представителям.
- Во всех единых справочниках контрагентов необходимо собирать объекты из двух категорий: "Клиенты" и "Представители".
Преимущества и недостатки второго способа прямо противоположны преимуществам и недостаткам первого. Действительно, использование для клиентов и представителей одной категории избавляет от необходимости копировать структуру данных, иметь два набора одинаковых документов, собирать в справочниках объекты из двух категорий и т.д. Но несколько более сложно определить, кто является клиентом, а кто представителем. Естественно, второй способ предпочтительней. На самом деле, он единственно верный.
Какая же должна быть структура данных, чтобы, используя одну и ту же категорию, организовать между объектами этой категории связь "один ко многим" от клиентов к представителям, и связь "один к одному" от представителей к клиенту.
Не буду утомлять вас подробными рассуждениями и приведу сразу окончательную схему данных (Рис. 1)

Направление связи между категориями "Клиенты" и "Контрагенты" здесь совершенно не принципиально. Категории "Клиенты" и "Представители" являются промежуточными и пустыми (содержат никаких атрибутов). Они служат только для определения направления связи. Объект категории "Контрагент", привязанный к объекту категории "Клиент", является клиентом, а объект категории "Контрагент", привязанный к объекту категории "Представитель", является догадайтесь сами кем. "Дерево объектов" для клиента "Контрагент 1" и трех его представителей: "Контрагент 2", "Контрагент 3" и "Контрагент 4" (Рис. 2). Обращаю ваше внимание, что для каждого клиента, имеющего представителей должна существовать пара объектов "Клиенты" и "Представители".
|
Соответственно, в AQL-запросах для получения списка представителей клиента теперь необходимо написать:
НЕКОТОРЫЙ_КОНТРАГЕНТ ^ КАТЕГОРИЯ_КЛИЕНТЫ : КАТЕГОРИЯ_ПРЕДСТАВИТЕЛИ : КАТЕГОРИЯ_КОНТАГЕНТЫ
Для определения клиента представителя необходимо написать:
НЕКОТОРЫЙ_КОНТРАГЕНТ ^ КАТЕГОРИЯ_ПРЕДСТАВИТЕЛИ ^ КАТЕГОРИЯ_КЛИЕНТЫ : КАТЕГОРИЯ_КОНТАГЕНТЫ
|

Ну и в заключение приведу пример работы с такой структурой данных. Как получить отчет по продажам для предприятия холдинга по клиентам за определенны период времени?
|
Пишем запрос:
select # ^ КАТЕГОРИЯ_КОНТРАГЕНТЫ.НАЗВАНИЕ, #.СУММА_НАКЛАДНОЙ from ПРЕДПРИЯТИЕ_ХОЛДИНГА : КАТЕГОРИЯ_НАКЛАДНЫЕ range_val(ДАТА_НАКЛАДНОЙ, ДАТА_НАЧАЛА ПЕРИОДА,ДАТА_ОКОНЧАНИЯ_ПЕРИОДА)
|
То есть, (идем от конструкции "from") для некоторого предприятия холдинга получаем все накладные (: КАТЕГОРИЯ_НАКЛАДНЫЕ) за период (range_val(…)), и для каждой накладной получаем контрагента (конструкция ".НАЗВАНИЕ" означает, что необходимо получит название контрагента) и сумму накладной. В результате выполнения запроса получаем таблицу, в первой колонке которой представлены контрагенты по накладным, а во второй суммы накладных. Далее, проходя по каждой строке таблицы, получаем уже известным нам запросом клиента для контрагента и заменяем в первой колонке представителя (если контрагент является представителем) клиентом. Теперь достаточно сгруппировать таблицу по первому столбцу с суммированием второго столбца, и мы получает таблицу, в первой колонке которой представлены клиенты, а во второй для каждого клиента представлены суммы всех накладных по клиентам вместе с их представителями.
У этого способа существует один, но довольно существенный недостаток. Он заключается в том, что для каждой строки необходимо отдельным запросом к базе данных получить клиента для контрагента. Это весьма существенно увеличивает время получения нашего отчета, особенно при большом количестве накладных за период. Решить эту проблему просто. Надо в первом запросе сразу же получить клиента для представителя. Для этого добавим вторую строку в запрос:
|
Пишем запрос:
select # ^ КАТЕГОРИЯ_КОНТРАГЕНТЫ.НАЗВАНИЕ, # ^ КАТЕГОРИЯ_КОНТРАГЕНТЫ ^ КАТЕГОРИЯ_ ПРЕДСТАВИТЕЛИ ^ КАТЕГОРИЯ_КЛИЕНТЫ : КАТЕГОРИЯ_КОНТРАГЕНТЫ.НАЗВАНИЕ, #.СУММА_НАКЛАДНОЙ from ПРЕДПРИЯТИЕ_ХОЛДИНГА : КАТЕГОРИЯ_НАКЛАДНЫЕ range_val(ДАТА_НАКЛАДНОЙ,ДАТА _НАЧАЛА ПЕРИОДА,ДАТА_ОКОНЧАНИЯ_ПЕРИОДА)
|
В полученной таблице в первом столбце будут представлены контрагенты по накладной, во втором клиенты для контрагентов по накладной и в третьем суммы накладных. Теперь "проходим" по каждой строке таблицы и копируем клиента, если он есть, в первый столбец. Удаляем второй столбец и группируем по первому с суммированием по второму. Получаем тот же результат, но только с одним обращением к базе данных.
Таким образом решена проблема клиентов и представителей в корпоративной системе автоматизации учета и управления экономической деятельностью предприятий и холдингов оптовой торговли ПроектИнформ Негоциант™.
Владимир Русецкий
ПроектИнформ
(495)775-61-41
torus@p-inform.ru
| Первый кассовый аппарат был сконструирован американцем Джеймсом Ритти в 1876 г. Прибор показывал сумму денег, полученную за каждую покупку, и хранил информацию обо всех, сделанных за день, операциях. Возможность ошибок и мелкого жульничества практически перестала существовать, и была достигнута исключительная точность записи всех торговых операций". |
 |
|
|