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.
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:
-
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!