New releases of "1C: Trade Management": update without development. Using external COM components (.dll) or any client methods in scheduled server database tasks

On October 23, a new configuration release was released "1C: Trade Management". Once again, the update included changes to VetIS, EGAIS, and the overall functionality of the configuration was almost not affected in any way.

What changed?

Looking at the structure of the changes that are included in the latest configuration release "1C: Trade Management", then more than half is an update on EGAIS, VetIS, and only a few lines in the release description are devoted to expanding functionality software product which are not subject to any legislation.

Sections that have changed:

    v retail sales added support for reading a two-dimensional bar code of excise and federal special stamps of a new sample containing a digital identifier of the EGAIS;

    improved integration with the veterinary control system (VetIS);

    improved exchange with the EGAIS system;

    added new features of the exchange service electronic documents;

    improvements were made in terms of the 1C: Business Network service;

    improved integration with Yandex.Checkout.

In terms of overall functionality, there have been several changes made to the planning and treasury block. And traditionally permanent additions to VAT accounting.

At the same time, the latest actual release of the configuration "1C: Trade Management" is no exception - now the development of a configuration for operational accounting is in progress mainly along the path of closing tasks that arise as a result of legislative regulation in the field of trade. It is logical that support for the requirements of regulators becomes a priority, and, ultimately, determines the direction of development of the software solution as a whole.

Operational accounting becomes regulated?

Traditional configuration "1C: Trade Management" used to automate operational accounting. At the same time, in connection with "1C: Accounting" it was customary to “download” all requirements for modifying typical functionality into "1C: UT", to keep the ability to update the accounting program with minimal effort.

Given the volume of regulatory documents for operational accounting in trade and the reflection of these requirements in a typical configuration, there are reasons to take a more careful approach to making changes to the typical functionality of a trading configuration. For example, problems with the exchange with the Mercury system can, if not paralyze the activities of a number of enterprises, then lead to long downtime, at least.

As one of the solutions, we can consider the use of the extension mechanism, especially since 1C is active in this functionality. Of course, this approach will require additional labor from developers. But this is the best way to support changes in modern configurations.

More radical will be the distribution of functionality between the typical configuration "1C: Trade Management" and some external accounting or analytical systems. Here, on the part of 1C, again, enough has been done to effectively solve such problems at the platform level.

In any case, now when designing corporate accounting systems and distributing functionality between configurations, you need to keep in mind: it is possible that updating "1C: Trade Management" have to if not as often as "1C: Accounting", then definitely not 1-2 times a year, as so many did before.

  • tutorial

Introduction

This article gives an idea of ​​how external components work in the 1C:Enterprise system.
The process of developing an external component for the 1C:Enterprise system version 8.2 running under the Windows operating system with file option work. This option is used in most solutions designed for small businesses. The VC will be implemented in the C++ programming language.

External components "1C: Enterprise"

"1C: Enterprise" is an extensible system. To expand the functionality of the system, external components (VC) are used. From a developer's point of view, a VC is an external object that has properties and methods, and can also generate events for processing by the 1C:Enterprise system.
External components can be used to solve a class of tasks that are difficult or even impossible to implement using the programming language built into 1C: Enterprise. In particular, this class includes tasks that require low-level interaction with the operating system, for example, to work with specific hardware.
The 1C:Enterprise system uses two technologies for creating external components:
  • using Native API
  • using COM technology
Given the restrictions between the two above technologies, the difference is insignificant, so we will consider the development of VK using the Native API. If necessary, the implemented developments can be applied to the development of VC using COM technology, and also, with minor modifications, applied for use in the 1C: Enterprise system with other operating options other than the file mode of operation.
VK structure
The external component of the 1C:Enterprise system is presented as a DLL library. The library code describes the IComponentBase derived class. In the class being created, the methods responsible for implementing the functions of the external component must be defined. The overridden methods will be described in more detail later in the course of the presentation of the material.

Launching the demo VK

Task:
  1. Assemble the external component supplied with the ITS subscription and designed to demonstrate the main capabilities of the external component mechanism in 1C
  2. Connect the demo component to the 1C configuration
  3. Make sure that the declared functions work correctly
Compilation
The demo VC is located on the ITS subscription disk in the "/VNCOMP82/example/NativeAPI" directory.
We will use Microsoft Visual Studio 2008 to assemble the demo VK. Other versions of this product do not support the used Visual Studio project format.


Open the AddInNative project. In the project settings, we connect the directory with the header files necessary to build the project. By default, they are located on the ITS disk in the directory /VNCOMP82/include.
The build result is a file /bind/AddInNative.dll. This is the compiled library for connecting to the 1C configuration.
Connecting VK to 1C configuration
Let's create an empty configuration 1C.
Following is the code for the managed application module.
var DemoComp; SystemStartup Procedure() ConnectExternalComponent("...\bind\AddInNative.dll", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); EndProcedure
If no error was reported when starting the 1C configuration, then the VK was successfully connected.
As a result of the execution of the above code, an object appears in the global visibility of the configuration DemoComp An that has properties and methods that are defined in the external bean code.
Demonstration of the embedded functionality
Let's check the performance of the demo VK. To do this, let's try to set and read some properties, call some VK methods, and also receive and process a VK message.
The documentation supplied on the ITS disk states the following functionality of the demo VC:
  1. Component object state management
    Methods: Turn on, Turn off
    Properties: Switched on
  2. Timer control
    Every second, the component sends a message to the 1C: Enterprise system with parameters Component, timer and a system clock counter string.
    Methods: StartTimer, StopTimer
    Properties: There is a timer
  3. Method ShowInStatusLine, which displays in the status bar the text passed to the method as parameters
  4. Method Upload Image. Loads an image from the specified file and transfers it to the 1C:Enterprise system as binary data.
Let's make sure that these functions work. To do this, we will execute the following code:
var DemoComp; SystemStart() Procedure ConnectExternalComponent(...); DemoComp = New("AddIn.DemoVK.AddInNativeExtension"); DemoComp.Disable(); Notify(DemoComp. Enabled); DemoComp.Enable(); Notify(DemoComp. Enabled); DemoComp.StartTimer(); EndProcedure ProcedureExternalEventHandler(Source, Event, Data) Report(Source + " " + Event + " " + Data); EndProcedure
The result of running the configuration is shown in the image


The results of method calls are displayed in the "Messages" panel DemoComp.Disable() and Demo.Comp.Enable(). The subsequent lines on the same panel contain the results of processing messages received from VK - A source, Event and Data respectively.

Arbitrary external component name

Task: Change the name of the external component to an arbitrary one.
The previous section used the identifier AddInNativeExtension, the meaning of which was not explained. In this case AddInNativeExtension is the name of the extension.
The VC code defines a method RegisterExtensionAs, which returns the name to the 1C: Enterprise system, which is necessary for the subsequent registration of the VC in the system. It is recommended to specify an identifier that, to a certain extent, reveals the essence of the external component.
Here is the full code of the method RegisterExtensionAs with the extension name changed:
bool CAddInNative::RegisterExtensionAs(WCHAR_T** wsExtensionName) ( wchar_t *wsExtension = L"SomeName"; int iActualSize = ::wcslen(wsExtension) + 1; WCHAR_T* dest = 0; if (m_iMemory) ( if(m_iMemory->AllocMemory ((void**)wsExtensionName, iActualSize * sizeof(WCHAR_T))) ::convToShortWchar(wsExtensionName, wsExtension, iActualSize); return true; ) return false; )
In the example above, the VK name has been changed to Some Name. Then, when connecting the VK, you must specify a new name:
DemoComp = New("AddIn.DemoVK.SomeName");

Expansion of the list of VK properties

Task:
  1. Study the implementation of VC properties
  2. Add a read-write property of a string type
  3. Add a read/write string type property that stores the data type of the property last set. No action is taken when setting the property value

To define the properties of the component being created, the developer needs to implement the following methods in the code of the AddInNative.cpp library:
GetNProps
Returns the number of properties for this extension, 0 if there are no properties
FindProp
Returns the ordinal number of the property whose name is passed in the parameters
GetPropName
Returns the name of the property by its ordinal and by the passed language ID
GetPropVal
Returns the value of the property with the specified ordinal
SetPropVal
Sets the value of the property with the specified ordinal
IsPropReadable
Returns the readability flag of the property with the specified ordinal
IsPropWritable
Returns the property writability flag with the specified sequence number


Consider the implementation of the above class methods CAddInNative.
The demo VC defines 2 properties: Switched on and There is a timer (IsEnabled and IsTimerPresent).
Two arrays are defined in the global scope of the library code:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent"); static wchar_t *g_PropNamesRu = (L"Enabled", L"There is a Timer");
which store the Russian and English names of the properties. In header file AddInNative.h an enum is defined:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropLast // Always last );
ePropIsEnabled and ePropIsTimerPresent, respectively having the values ​​0 and 1, are used to replace the ordinal numbers of properties with meaningful identifiers. ePropLast, which has a value of 2, is used to get the number of properties (using the GetNProps method). These names are only used inside the component's code and are not accessible from outside.
The FindProp and GetPropName methods search through arrays g_PropNames and g_PropNames.
To store the value of the fields in the library module, the CAddInNative class has properties that store the value of the component's properties. Methods GetPropVal and SetPropVal respectively return and set the value of these properties.
Methods IsPropReadable and IsPropWritable and return true or false, depending on the passed ordinal of the property according to the application logic.
To add a custom property:

  1. Add the name of the property to be added to arrays g_PropNames and g_PropNames(file AddInNative.cpp)
  2. To enumeration props(file AddInNative.h) front ePropLast add a name that uniquely identifies the property to be added
  3. Organize memory for storing property values ​​(create component module fields that store the corresponding values)
  4. Make changes to methods GetPropVal and SetPropVal to interact with the memory allocated in the previous step
  5. In accordance with the application logic, make changes to the methods IsPropReadable and IsPropWritable
Items 1, 2, 5 need no explanation. Details of the implementation of these steps can be found in the appendix to the article.
Let's name the test properties Test and Type Check respectively. Then, as a result of paragraph 1, we have:
static wchar_t *g_PropNames = (L"IsEnabled", L"IsTimerPresent", L"Test", L"TestType"); static wchar_t *g_PropNamesRu = (L"Enabled", L"HasTimer", L"Test", L"CheckType");
Enumeration props will look like:
enum Props ( ePropIsEnabled = 0, ePropIsTimerPresent, ePropTest1, ePropTest2, ePropLast // Always last );
To significantly simplify the code, we will use STL C++. In particular, for working with strings WCHAR, connect the library wstring.
To store the value of a method Test, define in the class CAddInNative in scope private field:
string test1;
To transfer string parameters between 1C:Enterprise and an external component, the 1C:Enterprise memory manager is used. Let's take a closer look at his work. To allocate and free memory, respectively, use the functions AllocMemory and FreeMemory, defined in the file MemoryManager.h. If it is necessary to pass a string parameter to the 1C: Enterprise system, the external component must allocate memory for it by calling the function AllocMemory. Its prototype looks like this:
virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
where pMemory- the address of the pointer in which the address of the allocated memory will be placed,
ulCountByte- the size of the allocated memory area.
An example of allocating memory for a string:
WCHAR_T *t1 = NULL, *test = L"TEST_STRING"; int iActualSize = wcslen(test1)+1; m_iMemory->AllocMemory((void**)&t1, iActualSize * sizeof(WCHAR_T)); ::convToShortWchar(&t1, test1, iActualSize);
For the convenience of working with string data types, we describe the function wstring_to_p. It takes a wstring string as a parameter. The result of the function is a filled structure tVariant. Function code:
bool CAddInNative::wstring_to_p(std::wstring str, tVariant* val) ( char* t1; TV_VT(val) = VTYPE_PWSTR; m_iMemory->AllocMemory((void**)&t1, (str.length()+1) * sizeof(WCHAR_T)); memcpy(t1, str.c_str(), (str.length()+1) * sizeof(WCHAR_T)); val -> pstrVal = t1; val -> strLen = str.length(); return true; )
Then the corresponding case section of the switch statement of the method GetPropVal will take the form:
case ePropTest1: wstring_to_p(test1, pvarPropVal); break;
method SetPropVal:
case ePropTest1: if (TV_VT(varPropVal) != VTYPE_PWSTR) return false; test1 = std::wstring((wchar_t*)(varPropVal -> pstrVal)); break;
To implement the second property, we define a class field CaddInNative
uint8_t last_type;
in which we will store the type of the last passed value. To do this, add the following command to the CaddInNative::SetPropVal method:
last_type = TV_VT(varPropVal);
Now, when requesting to read the value of the second property, we will return the value last_type, which is required by the designated task.
Let's check the performance of the changes made.
For this, we present appearance configuration 1C to the view:
var DemoComp; SystemStartup Procedure() ConnectExternalComponent("...", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.CheckType = 1; Report(String(DemoComp.TypeCheck)); DemoComp.Test = "Vasya"; Report(String(DemoComp.Test)); DemoComp.Test = "Petya"; Report(String(DemoComp.Test)); Report(String(DemoComp.TypeCheck)); EndProcedure
As a result of the launch, we get a sequence of messages:
3
Vasya
Peter
22

The second and third messages are the result of reading the property set in the previous step. The first and second messages contain the type code of the last property set. 3 corresponds to an integer value, 22 - to a string value. The correspondence of types and their codes is established in the file types.h, which is located on the ITS disk.

Expanding the list of methods

Task:
  1. Extend the functionality of the external component with the following functionality:
  2. Learn how to implement external component methods
  3. Add method-function Function1, which takes two strings ("Parameter1" and "Parameter2") as a parameter. As a result, a string of the form is returned: “Check. Parameter1, Parameter2"
  4. Verify that the changes made are working.

To define the methods of the component being created, the developer needs to implement the following methods in the code of the AddInNative library:
GetNMethods, FindMethod, GetMethodName
Designed to obtain, respectively, the number of methods, search for the number and name of the method. Similar to the corresponding methods for properties
GetNParams
Returns the number of method parameters with the specified sequence number; if there is no method with this number or has no parameters, returns 0
GetParamDefValue
Returns the default value of the specified parameter of the specified method
HasRetVal
Returns a flag that the method with the specified return value ordinal has: true for methods with a return value and false otherwise
CallAsProc
false, a run-time error occurs and the execution of the 1C: Enterprise module stops. Memory for the array of parameters is allocated and released by 1C: Enterprise.
CallAsFunc
Executes the method with the specified ordinal. If the method returns false, a run-time error occurs and the execution of the 1C: Enterprise module stops. Memory for the array of parameters is allocated by 1C: Enterprise. If the return value is of type string or binary data, the component allocates memory with the function AllocMemory memory manager, writes data there and stores this address in the corresponding field of the structure. 1С: The enterprise will release this memory by calling FreeMemory.
A complete description of the methods, including a list of parameters, is described in detail in the documentation supplied on the ITS disk.
Consider the implementation of the methods described above.
In the component code, two arrays are defined:
static wchar_t *g_MethodNames = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture"); static wchar_t *g_MethodNamesRu = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage");
and enum:
enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethLast // Always last );
They are used in functions GetNMethods, FindMethod and GetMethodName, by analogy with the description of properties.
Methods GetNParams, GetParamDefValue, HasRetVal implement switch, depending on the passed parameters and application logic, return the required value. Method HasRetVal in its code has a list of only methods that can return a result. For them it returns true. For all steel methods returns false.
Methods CallAsProc and CallAsFunc contain directly executable method code.
To add a method that can only be called as a function, you need to make the following changes in the source code of the external component:
  1. Add method name to arrays g_MethodNames and g_MethodNames(file AddInNative.cpp)
  2. Add a meaningful method identifier to the Methods enum (file AddInNative.h)
  3. Make changes to the function code GetNParams according to program logic
  4. If necessary, make changes to the code of the method GetParamDefValue if you want to use the default values ​​of the method parameters.
  5. Make changes to a function HasRetVal
  6. Make changes to the logic of the functions CallAsProc or CallAsFunc, by placing the directly executable code of the method there
Let's bring arrays g_MethodNames and g_MethodNames, as well as enumeration methods to the view:
static wchar_t *g_MethodNames = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadPicture", L"Test"); static wchar_t *g_MethodNamesRu = (L"Enable", L"Disable", L"ShowInStatusLine", L"StartTimer", L"StopTimer", L"LoadImage", L"Test");

Enum Methods ( eMethEnable = 0, eMethDisable, eMethShowInStatusLine, eMethStartTimer, eMethStopTimer, eMethLoadPicture, eMethTest, eMethLast // Always last );
Let's edit the function GetNProps so that it returns the number of parameters of the "Test" method:
long CAddInNative::GetNParams(const long lMethodNum) ( switch(lMethodNum) ( case eMethShowInStatusLine: return 1; case eMethLoadPicture: return 1; case eMethTest: return 2; default: return 0; ) return 0; )
Let's make changes to the function:
bool CAddInNative::GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) ( ​​TV_VT(pvarParamDefValue)= VTYPE_EMPTY; switch(lMethodNum) ( case eMethEnable: case eMethDisable: case eMethShowInStatusLine: case eMethStartTimer: case eMethStopTimer: case eMethTest: case / There are no parameter values ​​by default break; default: return false; ) return false; )
Thanks to the added line
case eMethTest:
in the absence of one or more arguments, the corresponding parameters will have an empty value ( VTYPE_EMPTY). If you need a default value for a parameter, you must specify it in the section eMethTest function switch statement CAddInNative::GetParamDefValue.
Since the "Test" method can return a value, you need to make changes to the function code HasRetVal:
bool CAddInNative::HasRetVal(const long lMethodNum) ( switch(lMethodNum) ( case eMethLoadPicture: case eMethTest: return true; default: return false; ) return false; )
And add the executable code of the method to the function CallAsFunc:
bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) ( ... std::wstring s1, s2; switch(lMethodNum) ( case eMethLoadPicture: ... break; case eMethTest: if (!lSizeArray || !paParams) return false; s1 = (paParams) -> pwstrVal; s2 = (paParams+1) -> pwstrVal; wstring_to_p(std::wstring(s1+s2), pvarRetValue); ret = true ; break; ) return ret; )
Let's compile the component and bring the configuration code to the form:
var DemoComp; SystemStartup Procedure() ConnectExternalComponent("...", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.SomeName"); lane = DemoComp.Test("Hi, ", "World!"); Notify(per); EndProcedure
After starting the configuration, we will receive a message: “Hello, World!”, Which indicates that the method has worked successfully.

Timer

Task:
  1. Study the implementation of the timer in the demo VK
  2. Modify the "StartTimer" method by adding the ability to pass in the parameters the timer interval (in milliseconds)
  3. Verify that the changes made are working.

In WinAPI, to work with time, you can use the message WM_TIMER. This message will be sent to your program at the time interval you specify when creating the timer.
To create a timer use the function SetTimer:
UINT SetTimer(HWND hWnd, // window handle UINT nIDevent, // timer ID (number) UINT nElapse, // delay TIMERPROC lpTimerFunc); // function pointer
The operating system will send a message WM_TIMER to the program with the interval specified in the argument nElapse(in milliseconds). In the last parameter, you can specify a function that will be executed every time the timer fires. The header of this function should look like this (the name can be anything):
void __stdcall TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Consider the implementation of the timer in the demo VK.
Since we are considering the process of developing an external component for the OS of the Windows family, we will not consider the implementation of the timer in other operating systems. For GNU/Linux OS, in particular, the implementation will differ in the syntax of the function SetTimer and TimerProc.
The method is called in the executable code SetTimer, to which the function is passed MyTimerProc:
m_uiTimer = ::SetTimer(NULL,0,100,(TIMERPROC)MyTimerProc);
The ID of the created timer is placed in a variable m_uiTimer so that you can turn it off later.
Function MyTimerProc as follows:
VOID CALLBACK MyTimerProc(HWND hwnd, // handle of window for timer messages UINT uMsg, // WM_TIMER message UINT idEvent, // timer identifier DWORD dwTime // current system time) ( if (!pAsyncEvent) return; wchar_t *who = L "ComponentNative", *what = L"Timer"; wchar_t *wstime = new wchar_t; if (wstime) ( wmemset(wstime, 0, TIME_LEN); ::_ultow(dwTime, wstime, 10); pAsyncEvent->ExternalEvent(who , what, wstime); delete wstime; ) )
The essence of the function is that the method is called ExternalEvent, which sends a message to the 1C: Enterprise system.
To expand the functionality of the method StartTimer let's do the following:
Modifying the method code GetNParams so that it is for the method eMethStartTimer returned value 1:
case eMethStartTimer: return 1;
Here is the method code CallAsProc to the view:
case eMethStartTimer: if (!lSizeArray || TV_VT(paParams) != VTYPE_I4 || TV_I4(paParams)<= 0) return false; pAsyncEvent = m_iConnect; #ifndef __linux__ m_uiTimer = ::SetTimer(NULL,0,TV_I4(paParams),(TIMERPROC)MyTimerProc); #else // код для GNU/Linux #endif break;
Now let's check the functionality. To do this, in the module of the managed application of the configuration, we will write the code:
var DemoComp; SystemStartup Procedure() ConnectExternalComponent("...", "DemoVK", ExternalComponentType.Native); DemoComp = New("AddIn.DemoVK.SomeName"); DemoComp.StartTimer(2000); EndProcedure
After starting the configuration, the program will receive messages with an interval of 2 seconds, which indicates the correct operation of the timer.

Interaction with the 1C: Enterprise system

To interact between the external component and the 1C:Enterprise system, methods of the IAddInDefBase class described in the file AddInDefBase.h. We list the most commonly used:
Error message generation
virtual bool ADDIN_API AddError(unsigned short wcode, const WCHAR_T* source, const WCHAR_T* descr, long scode)
wcode, code- error codes (a list of error codes with a description can be found on the ITS disk)
source- error source
descr- error description
Sending a message to the 1C: Enterprise system
virtual bool ADDIN_API ExternalEvent(WCHAR_T* wszSource, WCHAR_T* wszMessage, WCHAR_T* wszData) = 0;
wszSource- message source
wszMessage- Message text
wszData- transmitted data
The interception of the message is carried out by the procedure HandlingExternalEvent
Registration of an external component in the 1C:Enterprise system
virtual bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName)
wszProfileName- component name.
These methods are sufficient for the full interaction of VK and 1C. To receive data by an external component from the 1C:Enterprise system and vice versa, the external component sends a special message, which, in turn, is intercepted by the 1C system and, if necessary, calls the methods of the external component to send back data.

tVariant data type

When exchanging data between an external component and the 1C:Enterprise system, the tVariant data type is used. It is described in the types.h file, which can be found on the ITS disk:
struct _tVariant (_ANONYMOUS_UNION union (int8_t i8Val; int16_t shortVal; int32_t lVal; int intVal; unsigned int uintVal; int64_t llVal; uint8_t ui8Val; uint16_t ushortVal; uint32_t ulVal; uint64_t ullVal; int32_t errCode; long hRes; float fltVal; double dblVal; bool bVal; char chVal; wchar_t wchVal; DATE date; IID IDVal; struct _tVariant *pvarVal; struct tm tmVal; _ANONYMOUS_STRUCT struct ( void* pInterfaceVal; IID InterfaceID; ) __VARIANT_NAME_2/*iface*/; _ANONYMOUS_STRUCT struct ( char* pstr2_t Lint3 ; //count of bytes ) __VARIANT_NAME_3/*str*/; _ANONYMOUS_STRUCT struct ( WCHAR_T* pwstrVal; uint32_t wstrLen; //count of symbol ) __VARIANT_NAME_4/*wstr*/; ) __VARIANT_NAME_1; uint32_t cbElements; //Dimension for an one- dimensional array in pvarVal TYPEVAR vt; );
A type tVariant is a structure that includes:
  • mixture (union) intended directly for data storage
  • data type identifier
In general, working with variables of type tVariant occurs according to the following algorithm:
  1. Determining the type of data currently stored in a variable
  2. Access to the corresponding field of the mixture, for direct access to data
Type usage tVariant greatly simplifies the interaction of the 1C: Enterprise system and an external component

Appendix

The "examples" directory contains examples for the article
examples/1 - run the demo component
examples/2 - property list extension demo
examples/3 - demonstration of method list extension
Each directory contains a VS 2008 project and a prebuilt 1C configuration.

For example, it will not be possible to rewrite a component if you are not its author and there are simply no source codes. Or if the simplest types supported by Native API technology (number, string, boolean, date) are not enough for its operation.

There are no special problems when working with the file base. The scheduled task is called in the background process of a normal user. Therefore, client calls are available to him. There is no client context in the server database when a scheduled task is started, so the call ConnectExternalComponent() not available.

In this case, you can call the component on the client. To do this, it is enough to launch another 1C session from the scheduled task on the server in which to perform the necessary actions on the client. Well, do not forget to end the running session later.

Let's say that in our scheduled task, we generate and save a report that uses the external COM component NameDeclension.dll to decline the full name. On the file base, such a scheduled task will work correctly, but it will not work on the server component.

To fix the problem, let's add a procedure to the scheduled task module that will launch another session in server mode and in it will execute a report generation call on the client from external processing.

#If Client Then Procedure ExecuteFormationAndSavingReport() Export If ConnectExternalComponent("CommonLayout.NAMEDECL","Cl",ExternalComponentType.COM) Then Component = New ("AddIn.Cl.NameDeclension"); //Here is the code for generating and saving the report. ElseJoinRegisterLog("RegistTask", LevelJoinLog.Error, "Failed to connect the external component on the client"); EndIf; End of Procedure #Otherwise Procedure ExecuteFormationAndSavingReport() Export ExecuteOperationOnClient("RegularTasks.ExecuteFormationAndSavingReport()"); EndProcedure Procedure PerformOperationOnClient(ParameterToExecute) ExportUserName = ""; UserPassword = ""; PathToExternalProcessing = "c:/temp/Autostart.epf"; Quote = """"; DirectoryBIN = DirectoryProgram(); PathToConfiguration = InfoBase ConnectionString(); ConfigurationPath = StrReplace(ConfigurationPath, Quote, Quote + Quote); StartString = Quote + Bin Directory + "1cv8.exe" + Quote + " ENTERPRISE" + " /IBConnectionString " + Quote + ConfigurationPath + Quote + " /N " + Quote + Username + Quote + " /P " + Quote + UserPassword + Quote + " /Execute " + Quote + PathToExternalProcessing + Quote + " /C " + Quote + ParameterToExecute + Quote; StartApplication(StartString); EndProcedure #EndIf

External processing code that will simply cause the client context to print the required report from the scheduled jobs module and end the session after the report is generated.

Attempt to Execute(StartupParameter); Exception EndTry; ShutdownSystem(False);

The convenience of the solution is that when setting up scheduled tasks, it does not matter in what mode the task will be launched. If the database is a file one, then the necessary procedure will immediately start. If the database is server-side and there is no client context at startup, then a new session will be initialized and the procedure will work correctly in the client context.

Code for a typical application. Theoretically, it will work in a completely similar way in a managed one.

p.s. Also, this approach can be used to execute any client procedures in scheduled jobs.

The mobile application allows you to carry out warehouse operations (inventory of goods and fixed assets, movement of goods) in 1C Accounting 3.+. The application is developed natively on Android. For full-fledged work when exchanging through a file, only external processing is required. This application does not require intermediate databases and any additional software. The application can work in the complete absence of communication.

Functionality:
. Inventory of goods;
. Inventory of fixed assets;
. Movement of goods;

Download link.

Version history.

Android version support.

Android 4.4 and above.

Configuration support.

1C: Accounting 3.+

Support for barcode scanners and TSD.

  • GS-M100BT is supported in SPP mode;
  • TSD CARIBE PL 50L
  • Any scanners in HID mode connected via OTG are supported.

Functional.

Inventory of goods.

To conduct an inventory of goods, it is necessary to prepare a document Inventory of goods without the actual quantity in 1C. Next, you need to go to the application in the Inventory of goods section. If you have set up an online exchange with 1C, then click on the Download menu. This will load all the Goods Inventory documents, the edited documents will not be overwritten.

tabular part

The barcode match is searched in the device memory, if not found, it is searched in the 1C database, if not found, then it is searched in the 1C database in fixed assets. If the nomenclature is found as a result of the search, then a search will be performed in the tabular part of the document. If the object is found in the tabular section, then the number 1 + the amount found in the tabular section will be added to this line. If the object is not found in the tabular section, then it will be added to the tabular section of the document with the actual quantity 1 and the accounting quantity 0. If the search results in a fixed asset, the program will offer to add it to the OS Inventory document.

Uploading documents in 1C

Inventory of fixed assets.

To conduct an inventory of fixed assets (hereinafter referred to as OS), it is necessary to prepare a document Inventory of OS in 1C without actual availability. Next, you need to go to the application in the OS Inventory section. If you have set up an online exchange with 1C, then click on the Download menu. This will load all OS Inventory documents, edited documents will not be overwritten.

If your application works offline, then you can load documents from a file. The file is unloaded from 1C using processing.

Documents can be deleted all at once by clicking on Delete All or one by one by swiping left or right.

tabular part

By clicking on the desired document, a tabular part will open by analogy with 1C. The tabular part allows you to add/change/delete rows, edit the quantity.

Scanning and processing barcodes

Barcodes can be scanned with a camera, handheld scanner, GS-M100BT scanner, Carible PL 50L RTD, or entered manually.

The barcode search algorithm is as follows:

The barcode match is searched in the device's memory, if not found, then it is searched in the 1C database. If it is found as a result of the search, then a search will be performed in the tabular part of the document. If the object is found in the tabular part, then the actual presence will be set in this line. If the object is not found in the tabular section, then it will be added to the tabular section of the document with the actual presence.

Uploading documents in 1C

Completed documents are uploaded to 1C from the menu of the tabular section.

By analogy with uploading, documents can be uploaded online in 1C or through a file.

Assignment and printing of item barcodes.

To install a barcode and print labels, you need to connect an external printing form in the Items card and click Print barcode. If this nomenclature does not have a barcode, then the barcode will be automatically generated and a label will be printed. The label will be printed in 60X30 size.

Assignment and printing of fixed asset labels.

The OS directory code is used as the barcode for the OS. To print, you need to connect an external printing form and click Print barcode in the OS card. The label will be printed in 60X30 size.

Settings.

Description of settings.

Setting up the bluetooth scanner GS-M100BT.

On the Setup screen, you can set up the bluetooth barcode scanner GS-M100BT. For the first setup, you must first open "Bluetooth", a standard interface for pairing devices will open (it will look different on different devices).

Fast start

  • Install app
  • Publish OData interface in 1C
  • Customize the composition of the OData interface
  • Upload all directories, barcodes and documents from 1C to the application, either online or via a file.
  • Carry out warehouse operations
  • Upload processed data to 1C

 

It might be useful to read: