Marking custom module regions

 


You finally finished editing the Posting() procedure in the Services document module. It is the only procedure in the module but it is quite long, especially from the novice developer perspective, and it does not fit a single screen, which makes it hard to read, understand, and debug.

The module editor provides a handy feature for marking custom text regions in modules. Then you can group and collapse these regions just like you collapse loops, conditions, procedures, and functions. You can name the regions to mark the module parts that have specific purposes.

For example, you can split your posting procedure into three logical parts: the first part generates the temporary table for storing the document materials, the second part calculates the material cost, and the third part performs the check for negative balances if the document is posted in real-time mode.

Mark these parts in the procedure text using the preprocessor instructions #Region <region name> and #EndRegion, as shown in listing 14.42.

Listing 14.42. Posting() procedure

Procedure Posting(Cancel, Mode)

    RegisterRecords.BalanceOfMaterials.Write = True;
    RegisterRecords.CostOfMaterials.Write = True;
    RegisterRecords.Sales.Write = True;

    // Creating temporary tables manager
    TTManager = New TempTablesManager;

    #Region DocumentMaterialsAndServices
    Query = New Query;
 
    // Specifying the temporary tables manager used by the query
    Query.TempTablesManager = TTManager;

    Query.Text = 
        "SELECT
        |    ServicesMaterialsAndServices.MaterialOrService,
        |    ServicesMaterialsAndServices.MaterialOrService.MaterialServiceType AS MaterialServiceType,
        |    SUM(ServicesMaterialsAndServices.Quantity) AS QuantityInDocument,
        |    SUM(ServicesMaterialsAndServices.Total) AS TotalInDocument
        |INTO DocumentMaterialsAndServices
        |FROM
        |    Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices
        |WHERE
        |    ServicesMaterialsAndServices.Ref = &Ref
        |GROUP BY
        |    ServicesMaterialsAndServices.MaterialOrService,
        |    ServicesMaterialsAndServices.MaterialOrService.MaterialServiceType";
    
    Query.SetParameter("Ref", Ref);
    
    QueryResult = Query.Execute();
    #EndRegion
    
    #Region RegisterRecords
    Query2 = New Query;
    Query2.TempTablesManager = TTManager;
 
    Query2.Text = "SELECT
        |    DocumentMaterialsAndServices.MaterialOrService,
        |    DocumentMaterialsAndServices.MaterialServiceType,
        |    DocumentMaterialsAndServices.QuantityInDocument,
        |    DocumentMaterialsAndServices.TotalInDocument,
        |    ISNULL(CostOfMaterialsBalance.CostBalance, 0) AS Cost,
        |    ISNULL(BalanceOfMaterialsBalance.QuantityBalance, 0) AS Quantity
        |FROM
        |    DocumentMaterialsAndServices AS DocumentMaterialsAndServices
        |        LEFT JOIN AccumulationRegister.CostOfMaterials.Balance( , Material IN (
        |            SELECT
        |                DocumentMaterialsAndServices.MaterialOrService
        |            FROM
        |                DocumentMaterialsAndServices)) AS CostOfMaterialsBalance
        |        ON DocumentMaterialsAndServices.MaterialOrService = CostOfMaterialsBalance.Material
        |        LEFT JOIN AccumulationRegister.BalanceOfMaterials.Balance( , Material IN (
        |            SELECT
        |                DocumentMaterialsAndServices.MaterialOrService
        |            FROM
        |                DocumentMaterialsAndServices)) AS BalanceOfMaterialsBalance
        |        ON DocumentMaterialsAndServices.MaterialOrService = BalanceOfMaterialsBalance.Material";
    
    // Writing empty record sets to read balances without the data added by this document
    RegisterRecords.CostOfMaterials.Write();
    RegisterRecords.BalanceOfMaterials.Write();
    
    QueryResult = Query2.Execute();
    
    // VT = QueryResult.Unload();
    
    SelectionDetailRecords = QueryResult.Select();
    
    While SelectionDetailRecords.Next() Do

        If SelectionDetailRecords.Quantity = 0 Then
            MaterialCost = 0;
        Else
            MaterialCost = SelectionDetailRecords.Cost / SelectionDetailRecords.Quantity;
        EndIf;

        If SelectionDetailRecords.MaterialServiceType = Enums.MaterialServiceTypes.Material Then
        
            // register BalanceOfMaterials Expense
            Record = RegisterRecords.BalanceOfMaterials.Add();
            Record.RecordType = AccumulationRecordType.Expense;
            Record.Period = Date;
            Record.Material = SelectionDetailRecords.MaterialOrService;
            Record.Warehouse = Warehouse;
            Record.Quantity = SelectionDetailRecords.QuantityInDocument;
 
            // register CostOfMaterials Expense
            Record = RegisterRecords.CostOfMaterials.Add();
            Record.RecordType = AccumulationRecordType.Expense;
            Record.Period = Date;
            Record.Material = SelectionDetailRecords.MaterialOrService;
            Record.Cost = SelectionDetailRecords.QuantityInDocument * MaterialCost;
 
        EndIf;
 
        // register Sales
        Record = RegisterRecords.Sales.Add();
        Record.Period = Date;
        Record.MaterialOrService = SelectionDetailRecords.MaterialOrService;
        Record.Customer = Customer;
        Record.Technician = Technician;
        Record.Quantity = SelectionDetailRecords.QuantityInDocument;
        Record.Revenue = SelectionDetailRecords.TotalInDocument;
        Record.Cost = SelectionDetailRecords.QuantityInDocument * MaterialCost;
 
    EndDo;
 
    RegisterRecords.Write();
    #EndRegion
 
    #Region BalanceCheck
    If Mode = DocumentPostingMode.RealTime Then
        // Checking for negative balances
        Query3 = New Query;
        Query3.TempTablesManager = TTManager;
        Query3.Text = "SELECT
            |    BalanceOfMaterialsBalance.Material,
            |    BalanceOfMaterialsBalance.QuantityBalance
            |FROM
            |    AccumulationRegister.BalanceOfMaterials.Balance( , Material IN (
            |        SELECT
            |            DocumentMaterialsAndServices.MaterialOrService
            |        FROM
            |            DocumentMaterialsAndServices)
            |        AND Warehouse = &Warehouse) AS BalanceOfMaterialsBalance
            |WHERE
            |    BalanceOfMaterialsBalance.QuantityBalance < 0";

        Query3.SetParameter("Warehouse", Warehouse);

        QueryResult = Query3.Execute();
        SelectionDetailRecords = QueryResult.Select();
 
        While SelectionDetailRecords.Next() Do
            Message = New UserMessage();

            Message.Text = String(- SelectionDetailRecords.QuantityBalance) + " units shortage for """
                + SelectionDetailRecords.Material + """ with """ + SelectionDetailRecords.PropertySet
                + """ property set.";
            Message.Message();
 
            Cancel = True;

        EndDo;
 
    EndIf;
    #EndRegion
 
EndProcedure

Now you can collapse the marked regions (fig. 14.32).

 
Fig. 14.32. Marked regions in a module

Then you can expand only the region you are working with. This makes the procedure text compact and easier to read.

In this example you split a procedure into three logical parts. But you might often want to do the contrary: when a module contains many procedures, you can group similar procedures. For example, you can name the procedure groups API, EventHandlers, and InternalProceduresAndFunctions, where each name clearly describes the group purpose.

You can create nested regions or include regions into other collapsible structures. When marking regions, ensure that they do not overlap each other or other collapsible structures because overlapping regions cannot be grouped.


Comments
0
Add comment