Альтернативный интерфейс для тяжелых форм

Обсуждение технических вопросов работы с системами управления базами данных (СУБД), работе с языком SQL и скриптовыми языками.
Ответить
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

Юрий, Disillusioned если вы еще в теме, посоветуйте...
мы уже скоро как год без подписки, привели весь базовый функционал в порядок, и в виду отсутствия перспектив на развитие внутри - выходим за рамки
короче тема такая
мы начинаем переписывать ключевые диалоги (уже отработанные на скриптах Лоции на 90%) на Visual Studio Express 2010 (на шарпе или на бейсике не важно)
как это лучше организовать для администрирования?
1. Все чтение мы делаем сами нормально - тут вопросов нет
2. Всю запись мы хотим оставить Лоции ...
на текущий момент планируем выгружать инфу, для записи в базу, в виде xml с последующим запуском api действия Лоции в котором, в скрипте, разбирать что пришло и записывать в базу (прямую запись атрибута/ов, из своего софта, через API лоции - делать не хотим)
в общем если есть время - можете привести здесь пример? (мастер класс) на тему:
- вызов действия Лоции с передачей ему параметров из внешней среды
(тут наверно без API лоции не обойтись - но хотелось по минимуму - только для действий)

и еще момент
как внешний софт лучше оформить для установки по клиентам, может можно к Лоции свои dll подключать - у них же там есть что-то типа "Внешний модуль" в настройках меню... правда не знаю что имеется в виду под этими словами
или как? это вообще делается?
просто вызов *.exe из действия? или...

если время будет - ...было бы круто посмотреть

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Юрий
Активный участник
Сообщения: 239
Зарегистрирован: 13 янв 2005, 14:30
Используемое ПО: Lotsia PDM PLUS LT
Откуда: Украина, Донецк
Контактная информация:

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Юрий »

Внешний модуль предназначен только для работы с интерфейсом Лоции
он вам не поможет.

Проще всего сделать запуск действия на С отдельный EXE
который будет вызывать ваша программа на С#, а в командной строке передавать ид действия.

Код: Выделить всё

WORD PartyOperationRun(
  HWND hWndParent,
  DWORD dwOperID,
  LPPtOperationArgs lpArgs);

typedef struct PtOperationArgs_ {
  DWORD dwSize;
  DWORD dwFlags;
  WORD wVarsInCnt;
  LPCPtOperationVarValue lpVarsIn;
  WORD wVarsOutCnt;
  LPPtOperationVarValue lpVarsOut;
} PtOperationArgs, *LPPtOperationArgs;

typedef struct PtOperationVarValue_ {
  DWORD dwSize;
  char szVarName[51];
  PtValue pvValue;
} PtOperationVarValue, *LPPtOperationVarValue;

typedef struct PtValue_ {
  char cDataType;
  char szValueS[256];
  double dblValueN;
  PtDateTime dtValueT;
} PtValue, *LPPtValue;

typedef struct PtDateTime_ {
  WORD Year;
  BYTE Month;
  BYTE Day;
  BYTE Hour;
  BYTE Min;
  BYTE Sec;
  DWORD MilSec;
} PtDateTime, *LPPtDateTime;


Как видишь описание параметров действия довольно сложная структура
поэтому напрямую из С# вызов запуска действия процесс затруднительный.
Я написал переходник - библиотеку со смешанным кодом на С++ в которой я использую
структуры С и заполняю их данными из управляемого кода.
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

Юрий - спасибо за совет
Слушай а мы можем как нибудь продолжить обсуждение в данном направлении?
на предмет
ты можешь например на C++ показать основной кусок по подключению API лоции и вызова действия?
а то что-то мне подсказывает что с места я без помощи '...Hello World' не сдвинусь :wink:

ps
хотел на н.г. на каникулах уже замутить что нибудь такое по этой теме :wink:

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Юрий
Активный участник
Сообщения: 239
Зарегистрирован: 13 янв 2005, 14:30
Используемое ПО: Lotsia PDM PLUS LT
Откуда: Украина, Донецк
Контактная информация:

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Юрий »

У лоции есть набор примеров по API http://www.lotsia.com/support/lotsiapdm ... api420.exe
Там есть куча примеров. Есть и на 440.
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

Юрий привет!
слушай - я уже достаточно далеко отошел от Лоции теперь только чистое программирование на visual studio express 2010 ;-). Посмотрел я примеры по api Лоции - и ничего не понял - я к 'си' как то не проникся за все время разработок - на всем остальном сколько угодно но не на си
тем не менее вопросец
ты не можешь сюда на форум бросить самый простой проектик на C# или на чем еще - запуск действия с параметрами - например - форма, кнопка - и параметр в textbox'e - на кнопку нажали - действие в Лоции запустилось с целью изучения этого проекта - типа чтобы он работал и я у тебя мог че нибудь спросить

выручай... - больше не к кому обратиться

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

собственно пока не совсем понятно как правильно получить данные из api лоции (vbnet express 2010)
например вот это - получить инфу о коннекте - ничего не возвращает в структуру..., хотя ошибок нет на выходе

Код: Выделить всё

Imports System
Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Sequential)> Public Structure PtConnectInfo
    Public dwSize As Int32
    <MarshalAs(UnmanagedType.LPStr)> Public lpszLoginName As String
    <MarshalAs(UnmanagedType.LPStr)> Public lpszPassword As String
    Public wDBMSType As Int32
    <MarshalAs(UnmanagedType.LPStr)> Public lpszServer As String
    <MarshalAs(UnmanagedType.LPStr)> Public lpszDataBase As String
End Structure

Module Example
    Private Declare Function PartyInit Lib "PartyApi" (ByVal Wnd As Int32) As Int32
    Private Declare Function PartyConnectInfo Lib "PartyApi" (ByRef lpCnInfo As PtConnectInfo) As Int32

    Sub Main1()
        PartyInit(0)

        Dim p As PtConnectInfo
        p.lpszLoginName = "test"
        Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(p))

        Try
            Dim nRc As Int32 = PartyConnectInfo(p)

            Marshal.StructureToPtr(p, pnt, False)
            Dim anotherP As PtConnectInfo = CType(Marshal.PtrToStructure(pnt, GetType(PtConnectInfo)), PtConnectInfo)
            MsgBox(anotherP.lpszLoginName.ToString)

        Finally
            Marshal.FreeHGlobal(pnt)
        End Try

    End Sub
End Module
где тут может быть ошибка? где-то с памятью не попадаю...

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

... посмотрев проект под C# http://lsapi.googlecode.com/svn/trunk/
получился тот самый первый шаг к API Лоции для vb net 2010 - прочитать параметры соединения

Код: Выделить всё

Imports System.Runtime.InteropServices
Imports IntPtr = System.IntPtr

Public Class Form1
    <DllImport("PartyAPI.dll", CharSet:=CharSet.Ansi)> _
    Public Shared Function PartyInit(ByVal mainWindow As IntPtr) As Int16
    End Function

    <DllImport("PartyAPI.dll", CharSet:=CharSet.Ansi)> _
    Public Shared Function PartyConnectInfo(ByRef connectionInfo As IntPtr) As Int16
    End Function

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> Public Structure PtConnectInfo
        Public Size As Int32
        <MarshalAs(UnmanagedType.LPStr)> Public LoginName As String
        <MarshalAs(UnmanagedType.LPStr)> Public Password As String
        Public DBMSType As Int16
        <MarshalAs(UnmanagedType.LPStr)> Public Server As String
        <MarshalAs(UnmanagedType.LPStr)> Public DataBase As String
    End Structure

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        PartyInit(0)
        Dim ConnectInfo As PtConnectInfo = GetConnectInfo()
        MsgBox(ConnectInfo.Server)
    End Sub

    Public Function GetConnectInfo() As PtConnectInfo
        Dim ptrConInfo As IntPtr
        Dim ret As Integer = PartyConnectInfo(ptrConInfo)
        Try
            Return Marshal.PtrToStructure(ptrConInfo, GetType(PtConnectInfo))
        Finally
            Marshal.FreeHGlobal(ptrConInfo)
        End Try
    End Function

End Class
теперь можно и на действия уходить
ps
вообще конечно все это ужасно ...
и я бы например работал напрямую с базой через обновляемые источники данных для существующих значений...
но Лоция... лицензии, права, ключи... все это так неудобно...
и так тормозит прогресс... :wink: :wink: скоро 2012 а тут такие заморочки.. :wink: :wink:
но вроде как...

короче когда действие научусь запускать через ихнее API- скину сюда проектик
безвозмездно :wink: :wink:

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Старик Крупский
Активный участник
Сообщения: 803
Зарегистрирован: 27 июл 2006, 22:17
Откуда: Москва

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Старик Крупский »

Лоция... лицензии, права, ключи... все это так неудобно..
Интересная фраза... Как будто кто-то заставляет :roll:
"Лучше меньше, да лучше" (C)
Юрий
Активный участник
Сообщения: 239
Зарегистрирован: 13 янв 2005, 14:30
Используемое ПО: Lotsia PDM PLUS LT
Откуда: Украина, Донецк
Контактная информация:

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Юрий »

Вот демонстрационная библиотека для .net

https://docs.google.com/leaf?id=0Bx5yiW ... y=CPjV_IoN
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

спасибо!
но у меня не качается, может прав нет - при download открывается пустая страница...
не можешь посмотреть что там не так

ps
попутный вопрос по теме
а ты пользовался C# оберткой LotsiaAPI - http://lsapi.googlecode.com/svn/trunk/ ?
я поначалу стал переписывать ее под vb - но в маршалинге для действий утонул :wink:
скомпилировал их dll - стал через него - но не смог запустить действие через

Public Sub Run(ByVal varsIn As System.Collections.Generic.IEnumerable(Of Lotsia.PDM.LsOperationVar), ByVal varsOut As System.Collections.Generic.IEnumerable(Of Lotsia.PDM.LsOperationVar))
является членом: Lotsia.PDM.API.LsOperation

...пока еще не въехал как (не понятно где id подставлять и с параметрами... у них примера вызова нет...)

собственно вопрос - этот проект актуален для 4.40? просто версию API он показывает -> 4.30..

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Юрий
Активный участник
Сообщения: 239
Зарегистрирован: 13 янв 2005, 14:30
Используемое ПО: Lotsia PDM PLUS LT
Откуда: Украина, Донецк
Контактная информация:

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Юрий »

Попробуй отсюда http://files.mail.ru/DETED9

Это моя собственная обертка.
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

скачал - ок, спасибо
единственная проблема - под framework 4 не стартовала (надо где-то в конфигурации проекта ставить совместимость) - короче проект под framework 2 - все проглотил :wink:

Действие ЗАПУСТИЛОСЬ!! о чудо!!! :wink: :wink: :wink: :wink:

Код: Выделить всё

        Dim cParty = New PartyApiFDN.Party(Me.Handle)
        Dim res = New PartyApiFDN.PMConnectInfo
        Dim ret As Integer = cParty.ConnectInfo(res)
        Dim inValue = New ArrayList
        Dim outValue = New ArrayList
        ret = cParty.OperationRun(12, PartyApiFDN.PMOperRunFlag.MPPARTY_OPERRUN_OUTVARS, inValue, outValue)
Юрий - Спасибо еще раз, осталось только понять (мне) как параметры туда-сюда гонять в действии
:wink: :wink: :wink: :wink:

ps
и если не секрет - но покажешь кусочек обертки где ты запускаешь действие (PartyOperationRun) - интересует алгоритм маршаллинга для этого случая - просто интересно - я у себя дошел до того что - адрес структуры параметров действия (PtOperationInfo) получаю - все ок - а что с ним дальше делать не пойму - синтаксически, - там же массив значений (PtOperationVars)... то что адрес нужно двигать - по массиву это ясно - а вот как это в коде выглядит - уже сутки въехать не могу :wink:
если не в коде - то на словах - не объяснишь последовательность обработки этих структур?

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Юрий
Активный участник
Сообщения: 239
Зарегистрирован: 13 янв 2005, 14:30
Используемое ПО: Lotsia PDM PLUS LT
Откуда: Украина, Донецк
Контактная информация:

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Юрий »

В демоверсии вывод параметров зарезан. :)
А передавать параметры это список объектов PMPtValue.

Код: Выделить всё

int OperationRun(int OpId, int flag, ArrayList^ ArgIn, ArrayList^ ArgOut)
		{
			int j=0;
			char str1[256];
			LPPtOperationArgs lpArgs=(LPPtOperationArgs)LocalAlloc(LPTR, sizeof(PtOperationArgs));
			lpArgs->dwSize=sizeof(PtOperationArgs);
			lpArgs->dwFlags=flag;
			lpArgs->wVarsInCnt=ArgIn->Count;
			lpArgs->wVarsOutCnt=0;
			LPPtOperationVarValue ValIn = 
				(LPPtOperationVarValue)LocalAlloc(LPTR, sizeof(PtOperationVarValue)* ArgIn->Count);
			for(int i=0;i<ArgIn->Count;i++)
			{
				ValIn[i].dwSize=sizeof(PtOperationVarValue);
				StrToChr(((PMPtValue^)ArgIn[i])->szDescription,str1);
				strcpy_s(ValIn[i].szVarName,str1);
				StrToChr(((PMPtValue^)ArgIn[i])->cDataType->ToString(),str1);
				ValIn[i].pvValue.cDataType=str1[0];
				if (ValIn[i].pvValue.cDataType=='S' || ValIn[i].pvValue.cDataType=='I')
				{
					StrToChr(((PMPtValue^)ArgIn[i])->szValueS,str1);
					strcpy_s(ValIn[i].pvValue.szValueS,str1);
				}
				if (ValIn[i].pvValue.cDataType=='T' || ValIn[i].pvValue.cDataType=='D')
				{
					ValIn[i].pvValue.dtValueT.Year=((PMPtValue^)ArgIn[i])->szValueT->Year;
					ValIn[i].pvValue.dtValueT.Month=((PMPtValue^)ArgIn[i])->szValueT->Month;
					ValIn[i].pvValue.dtValueT.Day=((PMPtValue^)ArgIn[i])->szValueT->Day;
					ValIn[i].pvValue.dtValueT.Hour=((PMPtValue^)ArgIn[i])->szValueT->Hour;
					ValIn[i].pvValue.dtValueT.Min=((PMPtValue^)ArgIn[i])->szValueT->Minute;
					ValIn[i].pvValue.dtValueT.Sec=((PMPtValue^)ArgIn[i])->szValueT->Second;
					ValIn[i].pvValue.dtValueT.MilSec=((PMPtValue^)ArgIn[i])->szValueT->Millisecond;
				}
				if (ValIn[i].pvValue.cDataType=='N')
				{
					ValIn[i].pvValue.dblValueN=((PMPtValue^)ArgIn[i])->dblValueN;
				}
			}
			lpArgs->lpVarsIn=ValIn;
			j=PartyOperationRun(NULL, (DWORD)OpId, lpArgs);
			if(j!=0) 
			{
				PtError(j);
				LocalFree(lpArgs);
				LocalFree(ValIn);
				return j;
			}
			ArgOut->Clear();
			LPPtOperationVarValue ValOut = lpArgs->lpVarsOut;
			for(int i=0;i<lpArgs->wVarsOutCnt;i++)
			{
				PMPtValue^ val1 = gcnew PMPtValue();
				val1->cDataType=gcnew Char(ValOut[i].pvValue.cDataType);
				val1->szDescription=gcnew String((char*)ValOut[i].szVarName);
				if (ValOut[i].pvValue.cDataType=='S' || ValOut[i].pvValue.cDataType=='I')
				{
					val1->szValueS=gcnew String((char*)ValOut[i].pvValue.szValueS);
				}
				if (ValOut[i].pvValue.cDataType=='T')
				{
					val1->szValueT=gcnew DateTime(ValOut[i].pvValue.dtValueT.Year,
						ValOut[i].pvValue.dtValueT.Month,
						ValOut[i].pvValue.dtValueT.Day,
						ValOut[i].pvValue.dtValueT.Hour,
						ValOut[i].pvValue.dtValueT.Min,
						ValOut[i].pvValue.dtValueT.Sec,
						ValOut[i].pvValue.dtValueT.MilSec);
				}
				if (ValOut[i].pvValue.cDataType=='N')
				{
					val1->dblValueN=ValOut[i].pvValue.dblValueN;
				}
				ArgOut->Add(val1);
			}
			LocalFree(ValIn);
			LocalFree(lpArgs);
			return j;
		}
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

Юрий - спасибо за пример - пытаюсь реализоваться в vb net (их обертка под 4й framework открыта и написана конечно очень красиво - но для меня, сложно... - мне так круто не нужно, твоя под 2й - супер но язык 'не мой' мне понятней на vb) :wink: :wink: :wink:
...
не поможешь разобраться в структуре - я где-то в передаче параметров в действие застрял

Код: Выделить всё

        'создать параметр
      Dim id As UInt32 = 463
      Dim varValue As New LsNative.PtOperationVarValue
        varValue.Size = CType(Marshal.SizeOf(GetType(LsNative.PtOperationVarValue)), UInt32)
        varValue.Name = "In"
        varValue.Value.ValueS = "Test"
        'добавить параметр в массив параметров
      Dim aVars() As LsNative.PtOperationVarValue = {varValue}

        'создать экземпляр класса аргументов
      Dim Args = New LsNative.PtOperationArgs()
        Args.Size = CType(Marshal.SizeOf(GetType(LsNative.PtOperationArgs)), UInt32)
        Args.VarsIn = Nothing 'aVars    -если здесь nothing и в количестве поременнох 0 - дествие стартует ....
        Args.VarsInCnt = 0 '1
        Args.VarsOut = Nothing
        Args.VarsOutCnt = 0

        'выполнить действие
        ret = LsNative.LsOperation.PartyOperationRun(0, id, Args)
все структуры для действия взял из открытой обертки - т.е. вроде там все правильно
проблема в том - что если вместо in и out структуры передаю пустые значения Nothing - действие стартует и все ок, а если пытаюсь передать один параметр на вход (Args.VarsIn) (на выходе ничего не жду (Args.VarsOut) - Nothing) - то типа исключение на аргументах

Код: Выделить всё

Параметр задан неверно. (Исключение из HRESULT: 0x80070057 (E_INVALIDARG)) - т.е. какая то проблема передачи между управляемым и неуправляемым кодом
хотя в отладчике структура Args.VarsIn - перед передачей в действие заполнена нормально
debug01.gif
debug01.gif (19.64 КБ) 49516 просмотров
не подскажешь - в какую сторону смотреть - передача по ссылке/значению или все-таки структура аргументов получается некорректной?

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Re: Альтернативный интерфейс для тяжелых форм

Сообщение Александр »

...чтобы прикрыть тему
вызов действия с параметрами получился только благодаря библиотеке Юрия
(своими силами в .Net 4 C# напрямую для Lotsia API v3.5 ничего не получилось - залез в маршалинг и утонул там :wink: )

Код: Выделить всё

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Lotsia=PartyApiFDN;

namespace Ric
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int ret = 0;
            Lotsia.Party cParty = new Lotsia.Party((int)this.Handle);
            ret = cParty.UIActivate();
            Lotsia.PMConnectInfo cInfo = new Lotsia.PMConnectInfo();
            ret = cParty.ConnectInfo(cInfo);

            Lotsia.PMPtValue InValStr = new Lotsia.PMPtValue();
            InValStr.cDataType = 'S';
            InValStr.szDescription = "str";
            InValStr.szValueS = "Тест";

            Lotsia.PMPtValue InValInt = new Lotsia.PMPtValue();
            InValInt.cDataType = 'N';
            InValInt.szDescription = "int";
            InValInt.dblValueN = 12345;

            Lotsia.PMPtValue InValDate = new Lotsia.PMPtValue();
            InValDate.cDataType = 'T';
            InValDate.szDescription = "dt";
            InValDate.szValueT = System.DateTime.Now;

            ArrayList inValue = new ArrayList();
            inValue.Add(InValStr);
            inValue.Add(InValInt);
            inValue.Add(InValDate);

            ArrayList outValue = new ArrayList();

            ret = cParty.OperationRun(463,
                                      PartyApiFDN.PMOperRunFlag.MPPARTY_OPERRUN_OUTVARS,
                                      inValue,
                                      outValue); 
        }
    }
}
Pic 06.gif
Pic 06.gif (31.93 КБ) 48974 просмотра

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Ответить