OK. Now let’s talk operators - the most basic low-level commands 1C script engine understands and knows how to execute.
All operators live here - in the Syntax Assistant, right next to the Primitive Types we were looking at in the last Episode.
Let’s grab the most interesting ones from here.
First up: Variables Initialization This includes our old friend Var operator, and a new friend of ours - the New operator.
Next one: Methods declaration, which includes Procedure and Function.
Control flow operators featuring Goto and If.
Loops with For, For Each and While operators.
And some error-handling-related operators, namely Try and Raise.
OK. Starting with the Var operator.
You shouldn’t have forgotten by now that we can declare variables like this. By the way, we can declare more than one variable with the single Var operator. Or we can lose the declaration and initialize a variable like this.
But there are cases when you might need the explicit declaration. Let me show you.
Remember my buddy Kim? He decided to implement the import of legacy Purchase documents from Excel, and this is the test piece of code he came up with.
It creates, fills up and writes one Purchase document. And this is the document he gets as a result. It has no Company specified, but its number is prefixed with IFD because Autonumbering took the last number and incremented it by 1.
What Kim wants is that all imported docs look like this, so that he could tell them from others at a glance.
So, we need to do something about this prefixing functionality.
I would say we need an additional property - some kind of a flag - that belongs to the Purchase document and switches the prefixing between the prefix taken from Company and fixed IMP prefix depending on what is going on - usual UI work or import.
I could add this flag to the object’s attributes like this. But this way it would sit in the database along with other attributes, which does not make a lot of sense. After the posting is done, this info is useless.
So, here is a better way. I can add any properties to the Purchase document here at the top of the object module.
So I’m adding the ImportFlag variable and say that it should be public (that is visible from outside) by adding this Export keyword.
Now, I’m setting its default value to False at the bottom of the module. This part is called the module’s body, and it will be run during the object’s initialization.
Now I’m going to Kim’s import procedure and here is the ImportFlag property that I can now set to True, so the next time the imported Purchase document gets prefixed correctly.
OK. Next up: the New operator.
When we need a new document, we use one of the Document Manager’s object factories, like this. The same applies to all Metadata Objects.
But what do we do when we need to create a system-class object? Array, for example.
There is no such thing as SystemClassManager that could create arrays for us. But there is such thing as a universal object factory called the New operator.
Let’s check if we have already used it in our source code. And the answer is yes, we have.
Here, for example, is how we use the New operator to create a query for checking the Inventory balance.
OK. Moving on. Next: Procedures and Functions declaration.
There are no standalone procedures or functions in the 1C script. All of them have to belong to a specific object. So, before you can run a method, you need its object to exist.
Some of them (like this Sales document manager) are created by the Platform on the application startup, others (like this document object or this array) are created by your source code.
After the object is here, you can call its methods like this. Or this.
For the system classes (like this Array thingy), you can use only what the Platform has in store.
As for the Metadata Objects, we can extend their functionality by adding new procedures and functions to them. Here is an example.
I noticed that working with Purchase documents, I often need to call the supplier to check some details with them. To do so, I need to open the company object form, scroll through the list of the contacts, find the main phone number and then start calling. Too much of a hassle, isn’t it?
Instead, I would like to see the main phone number right here next to the company name. Something like this.
So, let me show you how it’s done.
The phone number lives down here in the Contacts tabular section of the Companies catalog. So it’s only logical to ask the Company object to find and return the main phone number.
So, I added this custom method to the object module. Mind the Export keyword that makes it visible from the outside of the module.
The function browses through the tabular section, checks the contact type against MainPhone predefined item I added to the ContactTypes catalog, and returns the first main phone it finds.
Then I went to the Purchase document form, added the Phone attribute and placed it to the form like this.
And this is how I ask the Company object to give me the main phone number. I’m creating the Company object using its reference’s GetObject method, and then calling the GetPhone method we just saw in the object’s module.
Then I call this function when the form gets created and whenever the Company field is changed.
And by the way. Did you notice that there is no Export keyword in this function declaration?
It means that we can (and we do) call it from inside of the module, but it’s invisible from anywhere outside.
So, this was the methods declaration.
A few more notes on the topic.
Unlike procedures, functions know how to return a single value, so we can use it in the calling procedure like this.
We can also declare and pass to the function or procedure any number of parameters just like this.
The thing about the parameters is that they are passed by reference by default.
So, if we change the parameter value here, it will be changed in the calling procedure as you can see.
You can opt for passing parameters by value using this Val keyword, in which case this variable value in the calling procedure stays unchanged no matter what.
So, this was procedures and functions. Next up: Control flow operators.
Goto makes an unconditional jump, and you don’t want to use it.
No, seriously. It’s considered to be a generally bad practice, and there are good reasons for that.
Although, sometimes it can make some sense, like in this example.
Here we have a loop nested inside of another loop and some exit condition that requires leaving both loops.
First, we need to exit the nested loop, then check the same condition once again and exit the main loop.
Or we can just do this.
You got it? All right. Next up: If operator.
Conditional jump. Very easy, very straightforward, used all over the place.
Moving on. Loops
The For loop.
Increments the counter by 1 from the start value to the end value, executing whatever code is in here.
For Each loop browses through all kinds of collections: arrays, form items, tabular section items, etc. Each item goes to this variable, so you can do whatever you like with it.
And the While loop. This one simply iterates while the condition is true and that’s it.
So, these are our loops. And the last, very important one: error handling.
Remember how we taught the Company object to find and return its main phone number? This piece of code works as long as this MainPhone predefined item is in the ContactTypes catalog.
All right then. LetтАЩs go to the catalog and break it just like this. What happens now?
This is what. I open the Purchase document and get this very confusing message about predefined items and other things I - as a user - am not supposed to know anything about.
And there are many more grim details if I incidentally click this button.
Wouldn’t it be much nicer to get something like this instead? No drama, everything’s under control, keep calm and call a developer.
Let’s see how it’s implemented. This entire loop is now inside of the Try clause. Whatever happens here, the Platform won’t freak a user out with mysterious messages. Instead, it will go to this Except and execute whatever is written here.
This ErrorInfo thingy is a system function that returns the detailed error information that you can use in messages and such.
And, of course, we can raise our own exception like this or this and let whoever is calling this procedure to handle it.
So, these were the operators supported by 1C:Enterprise script engine.