Filling prices in documents upon selecting materials or services
Let us proceed to the next goal. The material and service prices are stored in an information register. When a user creates a Services document or modifies a list of services within a Services document, it is good to have the service price added or updated automatically based on the information register record that matches the document date.
This includes two steps. First, write a function that returns the current material or service price. Second, call the function when a service is added to the document and fill the price field with the returned value.
This feature will hardly be used exclusively in this document. You might need it for the development of other documents that contain materials and services in their tabular sections. So let us store the function to a place that can be accessed from any applied solution part: a common module.
In Designer mode
In 1C:Enterprise mode
Let us test the document.
- Start 1C:Enterprise in the debug mode.
- Open the Prices information register.
- Add another price with a different date for the Philips transistor (fig. 9.11).
Fig. 9.11. Prices information register
- Open the Service document #1.
As you remember, this document records the expense of one Philips transistor.
- Leave the document date unchanged and reselect the transistor in the Material or service column of the document tabular section.
The platform fills the Price field with the price value effective as of 7/1/2014. This is the latest price value for the document date (fig. 9.12).
Fig. 9.12. Filling the Services document
- Change the document date to 9/17/2014 and reselect the transistor.
The platform fills the Price field with the price value effective as of 9/17/2014 (fig. 9.13).
Fig. 9.13. Filling the Services document
So you can see that the Price field is automatically filled with the price effective on the document creation date.
Creating a function that returns material or service price
First, let us create the RetailPrice() function that returns the current material or service retail price, and let us store it to a common module.
- In Designer, in the configuration object tree, in the Common / Common modules branch, add a Common module configuration object and name it CatalogProcessing.
In the module property palette the Server check box is selected by default. This means that the module instances are only compiled on the server.
- Select the Server call check box.
This allows calling export procedures and functions of the module from the client (fig. 9.9).
Fig. 9.9. Common module properties
- Add the following script to the module (listing 9.1).
Listing 9.1. Function RetailPrice()
Function RetailPrice(EffectiveDate, MaterialOrServiceItem) Export //Creating auxiliary Filter object Filter = New Structure("MaterialOrService", MaterialOrServiceItem); //Getting effective register resource values ResourceValues = InformationRegisters.Prices.GetLast(EffectiveDate, Filter); Return ResourceValues.Price; EndFunction
Now let us examine this script.
The function has two parameters:
- EffectiveDate, type: Date. The point on the time axis for which you want to know the retail price.
- MaterialOrServiceItem, type: reference to an item of the MaterialsAndServices catalog. The item whose price you want to know.
The first line in the function body creates the auxiliary Filter object.
It is a structure that contains a filter by register dimensions. It includes the register records where the MaterialOrService register dimension is equal to the catalog item reference passed to the function.
The structure key name MaterialOrService must be identical to the register dimension name that you specified in Designer. The structure item value MaterialOrServiceItems is the value filtered by the specified dimension.
The second line calls the manager of the Prices information register (InformationRegisters.Prices) and executes its method GetLast(), which returns the resource values for the latest register record that corresponds to the date passed to the function (EffectiveDate) and for the specified register dimension values (Filter).
The GetLast method retrieves a structure that contains the resource values. This structure is stored to the ResourceValues variable. In general a register can have multiple resources. The Prices register has a single resource, so the method retrieves a structure with a single element.
This is why in the next line you can get the required retail price by specifying the register resource name after a dot (ResourceValues.Price). The function returns this value.
Now let us have this function called at some point in document processing algorithms.
Calling the function upon material or service selection for filling the price
Your next task is implementing automatic filling of the Price field once a user selects a service in the Services document. And the service price must be based on the document date.
- In Designer, find the Services document and open its DocumentForm.
- Double-click the MaterialsAndServicesMaterialOrService form item.
Right-click the MaterialsAndServicesMaterialOrService form item and then click Properties.
This opens the property palette of that item.
- Scroll down the property palette to find the OnChange event.
This event occurs when the field value is changed.
- In the OnChange field, click the Open button .
- In the window that prompts you to select the handler type, keep the default Create on client option (fig. 9.10).
This option indicates that you are creating a client handler of an event that is triggered by interactive user actions.
Fig. 9.10. Selecting handler type for a form event
The platform generates a handler procedure template for this event in the form module and opens the Module tab of the form editor.
- Add the following script to the handler procedure body (listing 9.2).
Listing 9.2. Procedure MaterialsAndServicesMaterialOrServiceOnChange()
// Getting current tabular section row TabularSectionRow = Items.MaterialsAndServices.CurrentData; // Setting price TabularSectionRow.Price = CatalogProcessing.RetailPrice(Object.Date, TabularSectionRow.MaterialOrService); //Recalculating row total DocumentProcessing.CalculateTotal(TabularSectionRow);
Now let us examine this script.
You are already familiar with the first line of the handler after the MaterialsAndServicesQuantityOnChange and MaterialsAndServicesPriceOnChange procedures. It gets the current tabular section row of the document and stores it to the TabularSectionRow variable for future use.
The next line calls the RetailPrice() function from the CatalogProcessing common module.
The first function parameter is the document date, which is used to retrieve the price. The date is taken from the Object.Date default form attribute.
The second parameter is a reference to an item of the MaterialsAndServices catalog that is stored in the current tabular section row (TabularSectionRow.MaterialOrService).
The function returns the latest price value, which is assigned to the Price field of the current tabular section row (TabularSectionRow.Price).
The next line calls the CalculateTotal procedure from the DocumentProcessing common module. It is the procedure that you created earlier for recalculating the document row total when the quantity or price is changed.
Note that the MaterialsAndServicesMaterialOrServiceOnChange procedure execution starts in the form module on the client because it is a handler of an interactive form event. During the generation of the procedure template the platform added the &AtClient compilation directive before the procedure description.
Then the RetailPrice() function is called. Since this function is not found on the client, the execution is passed to the CatalogProcessing common module that is executed on the server. Once the function execution is completed, the script execution continues on the client.
So why do we need this trick? Why is it necessary to pass the script execution to the server?
It is because all database operations (reading or writing data) can only be performed on the server. Here you need to read the latest data for some material or service from the information register.
This action can only be performed on the server, and if you check the description of the GetLast() method of an information register in the Syntax Assistant, you will see that this method is only available on the server, in the thick client, and in external connections.
Thick client and external connection are client applications of the previous platform version that are supported for compatibility with legacy applied solutions.
But you are developing a new applied solution that uses the thin client or the web client. So in order to get some data from the database you need to pass the script execution to the server, get the required data there, and return the data to the client. And this is exactly what the handler does.