Creating a mobile app for stock inventory using 1C:Enterprise platform

1C Developer team

18.11.2019 15 min

Suppose we needed to create a mobile application for conducting an inventory in a warehouse (for recounting goods). For this, the 1C mobile platform is the best suited.

Let’s started.

First, let's decide what functionality we would like to see in this application.

1. The most important thing is barcode scanning. The mobile platform makes it possible to use the phone’s built-in camera as a scanner;
2. We need to store the scan results. For this, documents and catalogs entities are perfectly suitable;
3. If during scanning we found a new product, it would be lovely to enter the details using voice input. The 1C platform takes care of it as well;
4. After all the goods are added, it is necessary to transfer data to an external system. Here we will use http protocol to exchange data with an external system;
5. In the process, the application will give us service messages. We will use voice output to deliver them to the user. 

Create a new 1C configuration. Name it “MobileScanner”. Set property “Use purposes” value to “Mobile platform application”. 

Be sure to fill out the list “Required mobile application permissions” - select “Camera”, “Microphone” and “Audio playback and vibration” permissions.

1C

We will store some settings as constants:

TokenDropBox — String — Dropbox access token (we will store our data there);

We will store other settings (which might change during the workflow) in a catalog. Create a new catalog and name it “Settings”. Add a boolean attribute “Value”.

We will predefine the names of the settings.

You can edit the values on the form, generated automatically for the catalog.

That’s all for the settings.

Let’s create a startup interface (MainForm). 

Similar to the first form, create another common form. Name it “formMain”.

Create three commands (InventoryList, NewInventory) for the form:

Let’s mark that we want use this form as a startup interface:

  1. Add the “fromMain” form in the «Home page work area» dialog:

To store the list of our products - create a catalog “Products” with one attribute “SKU” (String):

Create a new form(ItemForm) for this catalog. 

Add two commands (SaveAndClose, VoiceInput) on the form. Add the form’s attributes as well:

Create a handler for the “SaveAndClose” command:

&AtClient
Procedure SaveAndClose(Command)
    ThisObject.Write();
    ThisForm.Close(Object.SKU);
EndProcedure

Also, create a handler for “VoiceInput”:

&AtClient
Procedure VoiceInput(Command)
  
    voiceIntent = New MobileDeviceApplicationRun;
    voiceIntent.Action = "android.speech.action.RECOGNIZE_SPEECH";

    If voiceIntent.Run(True) = 0 Then
   
    Else
        stringResult = TrimAll(voiceIntent.AdditionalData.Get("query").Value);
        stringResult = Upper(Left(stringResult, 1)) + Mid(stringResult, 2);
        Object.Description = stringResult;
    EndIf;

EndProcedure

Let's go back to the configuration and create the CommonModule “MainModule” with the following program code:

Function Sound() Export
    Return Catalogs.Settings.SoundWhenScanningBarcode.Value
EndFunction

Function Vibration() Export
    Return Catalogs.Settings.VibrationWhenScanningBarcode.Value;
EndFunction

Function UseVoiceInputOfProductDescriptions() Export
    Return Catalogs.Settings.UseVoiceInputOfProductDescriptions.Value;
EndFunction

Function PlayTextMessages() Export
    Return Catalogs.Settings.PlayTextMessages.Value;
EndFunction

Function TokenDropBox() Export
    Return Constants.TokenDropBox.Get();
EndFunction

Create the event handler “OnOpen” for the “ItemFrom” form of the Products catalog:

&AtClient

Procedure OnOpen(Cancel)
    
    If ValueIsFilled(Parameters.parameterSKU) Then
        Object.SKU = Parameters.parameterSKU;
    EndIf;

    ThisForm.Items.VoiceInput.Enabled = MainModule.UseVoiceInputOfProductDescriptions();
EndProcedure

Finally, we finished with all the preparations. 

Create a new document “Inventory”, with a tabular section “Products”. Add to tabular section the next attributes: Product (type — CatalogRef.Products), SKU (type — String), Quantity (type — Number 12.0):




Set “Posting” property to “Disable”:

Create a form for this document. Add two commands (“PostToDropBox” and “ReadBarCode”) on the form, add the required attributes:

Create an event handler “OnOpen”:

&AtClient

Procedure OnOpen(Cancel)
    If Not MultimediaTools.BarcodeScanningSupported() Then
         Message("Barcode scanning not supported");
         Items.buttonReadBarcode.Enabled = False;
    EndIf;
EndProcedure

Create a command handler “ReadBarCode”:

&AtClient

Procedure ReadBarcode(Command)
    ScanningHandler = New NotifyDescription("ScanResult", ThisObject);
    CloseHandler    = New NotifyDescription("ClosingScanWindow", ThisObject);
    MultimediaTools.ShowBarcodeScanning("Point the camera to the barcode",  ScanningHandler, CloseHandler);
EndProcedure

&AtClient

Procedure ScanResult(BarCode, Result, Message, ExtraOptions) Export
    If Result Then
        MultimediaTools.PlaySoundAlert(PlaySoundWhenScanning(), MainModule.Vibration());
        resultFinding = FindOnServer(BarCode);
        If Not resultFinding = False Then
            AddProduct(resultFinding, BarCode);
        Else
            MultimediaTools.CloseBarcodeScanning();
            structureParameters = New Structure;
            structureParameters.Insert("parameterSKU", BarCode);
            formNewProduct = GetForm("Catalog.Products.ObjectForm", structureParameters);
            newSKU = formNewProduct.DoModal();
            If ValueIsFilled(newSKU) Then
                  resultFinding = FindOnServer(newSKU);
                  AddProduct(resultFinding, newSKU);
            EndIf;
        EndIf;
    EndIf;
EndProcedure

&AtServer

Function FindOnServer(BarCode)
    Query = New Query;
    Query.Text = "SELECT
              |    Products.Ref AS Ref
              |FROM
              |    Catalog.Products AS Products
              |WHERE
              |    Products.SKU = &SKU";
    
    Query.SetParameter("SKU", TrimAll(BarCode));
    resultQuery = Query.Execute().Select();
    If resultQuery.Next() Then
        Return resultQuery.Ref;
    Else
        Return False;
    EndIf;
EndFunction

&AtClient

Procedure AddProduct(Product, SKU)
    SearchOptions = New Structure;
    SearchOptions.Insert("SKU", SKU);
    FoundLines = Object.Products.FindRows(SearchOptions);
    If FoundLines.Count() = 0 Then
        NewLine = Object.Products.Add();
        NewLine.Product   = Product;
        NewLine.SKU    = SKU;
        NewLine.Quantity     = 1;
    Else
        FoundLine = FoundLines[5];
        FoundLine.Quantity = FoundLine.Quantity + 1;
    EndIf;
    ThisObject.Write();
EndProcedure

&AtClient

Function PlaySoundWhenScanning()
    If MainModule.Sound() Then
        Return SoundAlert.Default;
    Else
        Return SoundAlert.None;
    EndIf;
EndFunction

&AtClient

Procedure ClosingScanWindow(ExtraOptions) Export
    //
EndProcedure

Also create a command handler “PostToDropBox”:

&AtClient

Procedure PostToDropBox(Command)
    If Object.Products.Count() = 0 Then
        ReportStatus("No data for send");
        Return;
    EndIf;
    structureResult = PostToDropBoxAtServer();
    If structureResult.Status Then
        ReportStatus("File uploaded successfully");
    Else
        ReportStatus(structureResult.Description);
    EndIf;
EndProcedure


&AtServer

Function PostToDropBoxAtServer()
    newSpreadsheetDocument = New SpreadsheetDocument;
    Section = newSpreadsheetDocument.GetArea("R1");
    Section.Area("R1"+"C1").Text = "Number";
    Section.Area("R1"+"C2").Text = "Product";
    Section.Area("R1"+"C3").Text = "SKU";
    Section.Area("R1"+"C4").Text = "Quantity";
    counter = 1;

    For Each curProduct In Object.Products Do
        counter = counter + 1;
        Section.Area("R" + String(counter) + "C1").Text = counter - 1;
        Section.Area("R" + String(counter) + "C2").Text = curProduct.Product;
        Section.Area("R" + String(counter) + "C3").Text = curProduct.SKU;
        Section.Area("R" + String(counter) + "C4").Text = curProduct.Quantity;
    EndDo;

    ShortTempFileName     = String(Object.Number) + ".pdf";
    FullTempFileName     = TempFilesDir() + String(Object.Number) + ".pdf";
    newSpreadsheetDocument.Put(Section);
    newSpreadsheetDocument.Write(FullTempFileName, SpreadsheetDocumentFileType.PDF);
    tokenDropBox = MainModule.TokenDropBox();
    ServerName = "content.dropboxapi.com";
    URL = "/2/files/upload";
    ShortTempFileName = "/" + ShortTempFileName;
    Headers = New Map;
    DropBoxAPIArg = "{""path"": " + """" + ShortTempFileName + """" + ",""mode"": ""overwrite""}";
    Headers.Insert("Dropbox-API-Arg", DropBoxAPIArg);
    Headers.Insert("Authorization", "Bearer " + tokenDropBox);
    Headers.Insert("Content-Type", "application/octet-stream");
    Headers.Insert("Accept", "application/octet-stream");
    HttpQuery = New HTTPRequest(URL, Headers);
    HttpQuery.SetBodyFileName(FullTempFileName);
    HttpConnection = New HTTPConnection(ServerName, 443,,,,, New OpenSSLSecureConnection);
    HttpAnswer = HttpConnection.Post(HttpQuery, "");
    BodyAnswer = HttpAnswer.GetBodyAsString(TextEncoding.UTF8);
    structureResult = New Structure;
    structureResult.Insert("Status");
    structureResult.Insert("Description");
    
    If (HttpAnswer.StatusCode < 200) Or (HttpAnswer.StatusCode >= 300) Then
        ErrorDescription = "An error occurred while uploading!" + Chars.LF;
        ErrorDescription = ErrorDescription + "Status code: " + HttpAnswer.StatusCode + Chars.LF;
        ErrorDescription = ErrorDescription + "Body answer: " + BodyAnswer;
        structureResult.Status = False;
        structureResult.Description = ErrorDescription;
    Else
        structureResult.Status = True;
    EndIf;
        
    Return structureResult;

EndFunction

&AtClient

Procedure  ReportStatus(TextMessage)
    If MultimediaTools.TextPlaybackSupported() And MainModule.PlayTextMessages() Then
        MultimediaTools.PlayText(TextMessage);
    Else
        Message(TextMessage);
    EndIf;
EndProcedure

That's basically it! Now you can publish your application on a web server, then install it on your mobile device and start using it. As you can see - using the 1C platform, we created a fully functional mobile application that can be used in real business just in half an hour.

You can download this app for the Android device or use project to develop your own application.

Please, supplement your suggestions for the development of demo applications in our forum.

Next time we will create a server part and implement a data exchange.

Stay tuned!

Be the first to know tips & tricks on business application development!

A confirmation e-mail has been sent to the e-mail address you provided .

Click the link in the e-mail to confirm and activate the subscription.