VERSION 5.00
Begin VB.UserControl DC_InvoiceItemMtnc 
   ClientHeight    =   7380
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   16020
   ScaleHeight     =   7380
   ScaleWidth      =   16020
   Begin VB.Frame frm_detail 
      Height          =   4350
      Left            =   0
      TabIndex        =   0
      Tag             =   "CUS"
      Top             =   0
      Width           =   15000
      Begin Project1.A_calocx cal_InvoiceDate 
         Height          =   360
         Left            =   8850
         TabIndex        =   1
         Top             =   915
         Width           =   1860
         _ExtentX        =   3281
         _ExtentY        =   635
      End
      Begin VB.Frame frm_itemHeader 
         Height          =   1500
         Left            =   7515
         TabIndex        =   11
         Top             =   180
         Width           =   6675
         Begin VB.TextBox txt_DCI_Code 
            Height          =   315
            Left            =   4845
            MaxLength       =   10
            TabIndex        =   13
            Text            =   "Text1"
            Top             =   165
            Width           =   1695
         End
         Begin VB.TextBox txt_DCI_Number 
            Height          =   315
            Left            =   1860
            MaxLength       =   16
            TabIndex        =   12
            Text            =   "Text1"
            Top             =   165
            Width           =   1695
         End
         Begin Project1.ArmCombobox cbo_CARRIER_Code 
            Height          =   345
            Left            =   4425
            TabIndex        =   15
            Tag             =   "CARRIER_Code"
            Top             =   600
            Width           =   2115
            _ExtentX        =   3731
            _ExtentY        =   609
         End
         Begin Project1.ArmCombobox cbo_CURR_Code 
            Height          =   345
            Left            =   5145
            TabIndex        =   16
            Tag             =   "CUST_FC_Currency"
            Top             =   1035
            Width           =   1395
            _ExtentX        =   2461
            _ExtentY        =   609
         End
         Begin Project1.ArmCombobox cbo_DC_Code 
            Height          =   345
            Left            =   1440
            TabIndex        =   24
            Tag             =   "DC_Code"
            Top             =   600
            Width           =   2115
            _ExtentX        =   3731
            _ExtentY        =   609
         End
         Begin VB.Label lbl_labels 
            Alignment       =   1  'Right Justify
            Caption         =   "#Invoice currency"
            Height          =   255
            Index           =   14
            Left            =   3270
            TabIndex        =   22
            Tag             =   "lbl_currency"
            Top             =   1095
            Width           =   1770
         End
         Begin VB.Label lbl_labels 
            Alignment       =   1  'Right Justify
            Caption         =   "#Invoice key"
            Height          =   255
            Index           =   11
            Left            =   3600
            TabIndex        =   21
            Tag             =   "lbl_invoiceKey"
            Top             =   210
            Width           =   1080
         End
         Begin VB.Label lbl_labels 
            Caption         =   "#Invoice number"
            Height          =   255
            Index           =   9
            Left            =   165
            TabIndex        =   20
            Tag             =   "lbl_invoiceNb"
            Top             =   210
            Width           =   1455
         End
         Begin VB.Label lbl_labels 
            Caption         =   "#Date"
            Height          =   255
            Index           =   8
            Left            =   540
            TabIndex        =   19
            Tag             =   "lbl_date"
            Top             =   1095
            Width           =   780
         End
         Begin VB.Label lbl_labels 
            Caption         =   "#Distr. centre"
            Height          =   255
            Index           =   7
            Left            =   180
            TabIndex        =   18
            Tag             =   "lbl_DC_Code"
            Top             =   660
            Width           =   1005
         End
         Begin VB.Label lbl_labels 
            Alignment       =   1  'Right Justify
            Caption         =   "#Carrier"
            Height          =   255
            Index           =   6
            Left            =   3480
            TabIndex        =   17
            Tag             =   "lbl_carrier"
            Top             =   660
            Width           =   840
         End
      End
      Begin VB.Frame frm_itemDetail 
         Height          =   1710
         Left            =   7410
         TabIndex        =   2
         Top             =   2295
         Width           =   6675
         Begin Project1.ArmCombobox cbo_TRANS_Code 
            Height          =   345
            Left            =   1305
            TabIndex        =   6
            Tag             =   "Master_TRANS_Code"
            Top             =   1155
            Width           =   5220
            _ExtentX        =   9208
            _ExtentY        =   609
         End
         Begin VB.TextBox txt_DCII_Code 
            Height          =   315
            Left            =   4830
            TabIndex        =   5
            Text            =   "Text1"
            Top             =   210
            Width           =   1695
         End
         Begin VB.TextBox txt_DCII_Number 
            Height          =   315
            Left            =   1335
            MaxLength       =   3
            TabIndex        =   4
            Text            =   "Text1"
            Top             =   210
            Width           =   615
         End
         Begin VB.TextBox txt_DCII_Amount 
            Height          =   315
            Left            =   1305
            TabIndex        =   3
            Text            =   "Text1"
            Top             =   645
            Width           =   1695
         End
         Begin VB.Label lbl_labels 
            Caption         =   "#Item key"
            Height          =   255
            Index           =   10
            Left            =   3615
            TabIndex        =   10
            Tag             =   "lbl_itemKey"
            Top             =   255
            Width           =   1140
         End
         Begin VB.Label lbl_labels 
            Caption         =   "#Item number"
            Height          =   255
            Index           =   12
            Left            =   90
            TabIndex        =   9
            Tag             =   "lbl_itemNb"
            Top             =   255
            Width           =   1230
         End
         Begin VB.Label lbl_labels 
            Caption         =   "#Item amount"
            Height          =   255
            Index           =   13
            Left            =   90
            TabIndex        =   8
            Tag             =   "lbl_itemAmount"
            Top             =   690
            Width           =   1230
         End
         Begin VB.Label lbl_masterTran 
            Caption         =   "#Transaction"
            Height          =   255
            Left            =   90
            TabIndex        =   7
            Tag             =   "lbl_itemTran"
            Top             =   1200
            Width           =   1155
         End
      End
      Begin Project1.ArmGrid grd_items 
         Height          =   1800
         Left            =   195
         TabIndex        =   23
         Tag             =   "grd_items"
         Top             =   1170
         Width           =   6900
         _ExtentX        =   12171
         _ExtentY        =   1826
      End
      Begin Project1.ToolbarControl tlb_item 
         Height          =   690
         Left            =   7410
         TabIndex        =   14
         Top             =   1560
         Width           =   6075
         _ExtentX        =   10716
         _ExtentY        =   1217
      End
   End
End
Attribute VB_Name = "DC_InvoiceItemMtnc"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

Private Const SCREEN_NAME As String = "DCInvoiceItemManager"


Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwnd As Long) As Long

Const C_REQ_CARRIER As String = "EXEC DC_Carrier_lst $DC_CODE$,0"

Private Const C_TOOLBAR_ID As Long = 2998
Private Const C_ITEM_TOOLBAR_ID As Long = 2999

Dim ms_MsgInfo As Variant

Private Const SEP = "®©"
Private Const SEP1 As String = "®"
Private Const SEP2 As String = "©"
Private Const CL_COLOR_ENABLED As Long = &H80000005
Private Const CL_COLOR_DISABLED As Long = &H8000000F

Private Const VALUE_FORMAT As String = "###0.00"
Private Const MONEY_FORMAT As String = "###0.00"
Private Const COLOR_PARENT As Long = ColorConstants.vbWhite
Private Const COLOR_CHILD As Long = ColorConstants.vbCyan

Private Const C_TOOLBARFACE_LINE_LST As String = "0"
Private Const C_TOOLBARFACE_LINE_UPD As String = "1"
Private Const C_TOOLBARFACE_LINE_DEL As String = "2"
Private Const C_TOOLBARFACE_LINE_LST2 As String = "3"

Private mb_eventRunning As Boolean
Private mb_Initialized As Boolean
Private ms_inTranName As String
Private mo_Db As ArmDb
Private ms_Language_Code As String
Dim mu_ActiveMode As ArmScreenMode
Dim mu_Item_ActiveMode As ArmScreenMode
Private ml_U_Code As Long
Private ms_LoginName As String
Private ml_iConcurrency As Long                   ' iconcurrency

Private ms_DC_Code As String
Private ms_Carrier_Code As String

Private Enum ArmErr
    DBCnxFailed = C_ERRORRAISE + 1             ' Unable to connect to the database
    CPTAlreadyInitialized = C_ERRORRAISE + 2   ' We try to initialize a component that is already initialized
    CPTNotInitialized = C_ERRORRAISE + 3       ' We try to use or free that is not initialized yet
    InvalidArgument = C_ERRORRAISE + 4
    PropertyNotSet = C_ERRORRAISE + 5
    SQLFailure = C_ERRORRAISE + 6               ' A SQL runtime error has occured : syntax wrong....
    SQLBadRowAffectedCount = C_ERRORRAISE + 7   ' A SQL request has not affected the expected rowcount (ex: one Update do nothing)
    SQLBadRowExpectedCount = C_ERRORRAISE + 8   ' A SQL request does not return the expected rowcount : select an item return nothing...
    DrivingError = C_ERRORRAISE + 9
    CompFncFailed = C_ERRORRAISE + 10           ' when component function fail
    GridLoadFailed = C_ERRORRAISE + 11          ' load function failed ... bad sql
    InvalidValue = C_ERRORRAISE + 12          ' load function failed ... bad sql
    SQLTableReferenceConstraint = C_ERRORRAISE + 13 ' A SQL request cannot be executed : Table reference constraint
    DuplicityDetected = vbObjectError + 2301     ' detected row with same unique id
End Enum

Public Event RowAdded(ByVal al_DCI_Code As Long, ByVal ad_invDate As Date, ByVal as_invNumber As String, ByVal as_CURR_Code As String)
Public Event RowUpdated(ByVal al_DCI_Code As Long, ByVal ad_invDate As Date, ByVal as_invNumber As String, ByVal as_CURR_Code As String)
Public Event RowDeleted(ByVal al_DCI_Code As Long)

Public Event ItemRowAdded(ByVal al_TRANS_Code As Long, ByVal al_DCII_Code As Long, ByVal ad_amount As Double, ByVal as_invItemNumber As String)
Public Event ItemRowUpdated(ByVal al_DCII_Code As Long, ByVal ad_amount As Double, ByVal as_invItemNumber As String)
Public Event ItemRowDeleted(ByVal al_TRANS_Code As Long, ByVal al_DCII_Code As Long)

Private Enum ArmScreenMode
    smNone
    smMain
    smAdd
    smUpdate
    smDelete
    smView
End Enum

Public Property Get Initialized() As Boolean
    Initialized = mb_Initialized
End Property


Public Property Let Visible(ByVal aVisible As Boolean)
    UserControl.Extender.Visible = aVisible
End Property
Public Property Get Visible() As Boolean
    Visible = UserControl.Extender.Visible
End Property

Public Sub Move(ByVal aLeft As Single, ByVal aTop As Single, ByVal aWidth As Single, ByVal aHeight As Single)
    Call UserControl.Extender.Move(aLeft, aTop, aWidth, aHeight)
    Call Resize
End Sub

Property Let Language_Code(AString As String)
On Error GoTo errhandler

  ms_Language_Code = AString
  Exit Property
errhandler:
  Call ErrorMessage("Language_Code.Let")
End Property

Property Let U_Code(ByVal al_U_Code As Long)
On Error GoTo errhandler

  ml_U_Code = al_U_Code
  Exit Property
errhandler:
  Call ErrorMessage("U_Code.Let")
End Property

Public Property Let LoginName(ByVal as_loginName As String)
On Error GoTo errhandler
    
    ms_LoginName = as_loginName
    Exit Property
errhandler:
    Call ErrorMessage(Extender.Name & ".LoginName(Let)")
End Property

Public Property Let Tag(ByVal as_Value As String)
    Extender.Tag = as_Value
End Property

Public Property Get Tag() As String
    Tag = Extender.Tag
End Property

Public Property Set ArmDb(ByRef lo_Db As Object)
On Error GoTo errhandler
  
  Set mo_Db = lo_Db
  Exit Property
errhandler:
  Call ErrorHandler("ArmDb.Set")
End Property

Public Property Let MasterScreenMode(ByVal as_screenMode As String)
    Select Case as_screenMode
        Case "Main"
            mu_ActiveMode = ArmScreenMode.smMain
        Case "View"
            mu_ActiveMode = ArmScreenMode.smView
        Case "Add"
            mu_ActiveMode = ArmScreenMode.smAdd
        Case "Update"
            mu_ActiveMode = ArmScreenMode.smUpdate
        Case "Delete"
            mu_ActiveMode = ArmScreenMode.smDelete
        Case Else
            mu_ActiveMode = ArmScreenMode.smNone
    End Select
End Property

Public Property Let Enabled(ByVal ab_Enabled As Boolean)
    frm_detail.Enabled = ab_Enabled
End Property

Public Sub Load_A_COM()
    
On Error GoTo errhandler

    If mb_Initialized Then Exit Sub
    
    mb_Initialized = True
    
    mb_eventRunning = True
    
    ms_inTranName = ""
    
    Dim lo_Control As Object
    Dim lo_ToolTip As Object
    
      For Each lo_Control In Controls
        Select Case UCase(TypeName(lo_Control))
        Case "ARMCOMBOBOX"
          Set lo_Control.ArmDb = mo_Db
          Call lo_Control.Load_A_COM
        Case "ARMPICKER"
          Set lo_Control.ArmDb = mo_Db
          Call lo_Control.Load_A_COM
        Case "TOOLBARCONTROL"
          lo_Control.Language = ms_Language_Code
'          Set lo_Control.ArmDb = mo_Db
          Call lo_Control.Load_A_COM
        Case "ARMGRID"
          Set lo_Control.ArmDb = mo_Db
          Call lo_Control.Load_A_COM
        Case "ARMTREEVIEW"
          Set lo_Control.ArmDb = mo_Db
          lo_Control.Language = ms_Language_Code
          Call lo_Control.Load_A_COM
        Case "ARMCHECKVIEW"
          Set lo_Control.ArmDb = mo_Db
          Call lo_Control.Load_A_COM
        Case "A_CALOCX"
          lo_Control.Language = ms_Language_Code
          Call lo_Control.reinit_cal
        Case "TOOLBR"
          Set lo_Control.ArmDb = mo_Db
          Call lo_Control.Load_A_COM
        End Select
      Next

    ' init toolbar
    Dim ll_Cursor As Long
    
    ll_Cursor = OpenSQLSafe(mo_Db, "exec Toolbar_sel 'DC Load Plan'")

    If mo_Db.Find(ll_Cursor, "Id", C_ITEM_TOOLBAR_ID) < 0 Then
        Err.Raise ArmErr.InvalidValue, tlb_item.Name, "Toolbar not found in toolbars_definitions ID:" & C_TOOLBAR_ID
    End If

    Dim ls_ToolbarInfo  As String
    ls_ToolbarInfo = mo_Db.GetFields(ll_Cursor, "info")
    
    Call tlb_item.SetToolbarInfoStringParameters(ls_ToolbarInfo, Left(ls_ToolbarInfo, 3))
    
    Call mo_Db.Close(ll_Cursor)
    ll_Cursor = 0

    
    ' INIT COMBOBOXES
    cbo_DC_Code.FirstBlankItem = False
    cbo_DC_Code.Request = "EXEC DC_cbo"
    
    cbo_CARRIER_Code.FirstBlankItem = False
    
    cbo_CURR_Code.FirstBlankItem = False
    cbo_CURR_Code.Request = "EXEC DC_currencies_cbo '" & ms_Language_Code & "'"

    ' init grid
    grd_items.AllowExcelExport = True
    grd_items.Title = "#Invoice item lines"
    grd_items.MultiSelect = False
    
    If Not grd_items.SetColumns(Array( _
                Join(Array("DCII_Code", 0, 1, "DCII_Code", "#DCII_Code", "String"), SEP) _
                , Join(Array("DCII_Number", 900, 0, "DCII_Number", "#DCII_Number", "String"), SEP) _
                , Join(Array("TRANS_Code", 0, 0, "TRANS_Code", "#TRANS_Code"), SEP) _
                , Join(Array("TRANS_Name", 3000, 0, "TRANS_Name", "#TRANS_Name", "String"), SEP) _
                , Join(Array("DCII_Amount", 1100, 0, "DCII_Amount", "#DCII_Amount", "Float", MONEY_FORMAT_PRECISE, "Right"), SEP) _
                , Join(Array("CARRIER_Name", 1200, 0, "CARRIER_Name", "#CARRIER_Name", "STRING"), SEP) _
                , Join(Array("Shipping_Date", 1200, 0, "Shipping_Date", "#Shipping_Date", "DATE"), SEP) _
                , Join(Array("CUSTN1", 1100, 0, "CUSTN1", "#ShipToPartnerName", "String"), SEP) _
                , Join(Array("Ship_To_Zip_Code", 300, 0, "Ship_To_Zip_Code", "#Ship_To_Zip_Code", "STRING"), SEP) _
                , Join(Array("Ship_To_CT_Code", 300, 0, "Ship_To_CT_Code", "#Ship_To_CT_Code", "STRING"), SEP) _
                , Join(Array("Ship_To_Address", 2300, 0, "Ship_To_Address", "#Ship_To_Address", "STRING"), SEP) _
                , Join(Array("Quantity", 1000, 0, "Quantity", "#Quantity"), SEP), Join(Array("UOM_Code", 800, 0, "UOM_Code", "#UOM", "STRING"), SEP) _
                , Join(Array("iConcurrency", 0, 0, "iConcurrency", "#iConcurrency", "INT"), SEP) _
                , Join(Array("Action", 0, 0, "", "Action", "String"), SEP) _
            )) Then
        MsgBox ("Grid not initialized!")
    End If
    
    Call LoadLabels(UserControl.Controls, SCREEN_NAME, ms_Language_Code)
    Call ChangeCharset(UserControl.Controls, GetCodePageFromLanguage(mo_Db, ms_Language_Code))

    mb_eventRunning = False
    
    Exit Sub
    
errhandler:
    
    Call ErrorHandler("Load_A_COM")
    
End Sub

Private Sub Item_UpdateUI(ByVal au_LineMode As ArmScreenMode)
On Error GoTo errhandler
    mu_Item_ActiveMode = au_LineMode
    tlb_item.Redraw = False
    
    frm_itemDetail.Visible = False
    frm_itemHeader.Visible = True

    frm_itemDetail.Enabled = True
    
    Select Case mu_Item_ActiveMode
        Case ArmScreenMode.smNone
            frm_detail.Visible = False
        Case ArmScreenMode.smMain
            Call EnableControl(grd_items, True)
            Call SetEnabled(GetContainedControlsChain(frm_itemHeader), mu_ActiveMode = smAdd Or mu_ActiveMode = smUpdate)
            Call EnableControl(cal_InvoiceDate, mu_ActiveMode = smAdd Or mu_ActiveMode = smUpdate)
            Call EnableControl(txt_DCI_Code, False)
            
            Call SetEnabled(GetContainedControlsChain(frm_itemDetail), False)
    
            Call tlb_item.DisplayFace(IIf(mu_ActiveMode = smAdd Or mu_ActiveMode = smUpdate, C_TOOLBARFACE_LINE_LST, C_TOOLBARFACE_LINE_LST2))
            
            grd_items.Visible = True
            tlb_item.Visible = True
        Case ArmScreenMode.smUpdate
            ' we are in Update section
            Call EnableControl(grd_items, False)
            Call SetEnabled(GetContainedControlsChain(frm_itemHeader), False)
            Call EnableControl(cal_InvoiceDate, False)
            Call EnableControl(txt_DCI_Code, False)
            
            Call SetEnabled(GetContainedControlsChain(frm_itemDetail), True)
            Call EnableControl(txt_DCII_Code, False)
            
            Call tlb_item.DisplayFace(C_TOOLBARFACE_LINE_UPD)
        
            frm_itemDetail.Visible = True
            grd_items.Visible = True
            tlb_item.Visible = True
        Case ArmScreenMode.smAdd
            ' we are in Update section
            Call EnableControl(grd_items, False)
            Call SetEnabled(GetContainedControlsChain(frm_itemHeader), False)
            Call EnableControl(cal_InvoiceDate, False)
            Call EnableControl(txt_DCI_Code, False)
            
            Call SetEnabled(GetContainedControlsChain(frm_itemDetail), True)
            Call EnableControl(txt_DCII_Code, False)
            
            Call tlb_item.DisplayFace(C_TOOLBARFACE_LINE_UPD)
            
            grd_items.Visible = True
            tlb_item.Visible = True
            frm_itemDetail.Visible = True
       Case ArmScreenMode.smView
            ' we are in PreView section
            Call EnableControl(grd_items, True)
            Call SetEnabled(GetContainedControlsChain(frm_itemHeader), mu_ActiveMode = smAdd Or mu_ActiveMode = smUpdate)
            Call EnableControl(cal_InvoiceDate, mu_ActiveMode = smAdd Or mu_ActiveMode = smUpdate)
            Call EnableControl(txt_DCI_Code, False)

            Call SetEnabled(GetContainedControlsChain(frm_itemDetail), False)
            
            Call tlb_item.DisplayFace(IIf(mu_ActiveMode = smAdd Or mu_ActiveMode = smUpdate, C_TOOLBARFACE_LINE_LST, C_TOOLBARFACE_LINE_LST2))
            
            frm_itemDetail.Visible = True
            grd_items.Visible = True
            tlb_item.Visible = True
            
        Case ArmScreenMode.smDelete
            ' we are in PreView section
            Call EnableControl(grd_items, False)
            Call SetEnabled(GetContainedControlsChain(frm_itemDetail), False)
            
            Call tlb_item.DisplayFace(C_TOOLBARFACE_LINE_DEL)
            
            frm_itemDetail.Visible = True
            grd_items.Visible = True
            tlb_item.Visible = True
        Case Else
            Debug.Assert (False)
    End Select
    
    ' to display face immidiatelly
    tlb_item.Redraw = True

    Exit Sub
errhandler:
    Call ErrorHandler("Item_UpdateUI()")
End Sub

Public Sub Unload_A_COM()
    
On Error GoTo errhandler
    mb_Initialized = False
    
    Dim lo_Control As Object

    For Each lo_Control In Controls
      Select Case UCase(TypeName(lo_Control))
      Case "ARMCOMBOBOX"
        Call lo_Control.Unload_A_COM
      Case "ARMPICKER"
        Call lo_Control.Unload_A_COM
      Case "TOOLBARCONTROL"
        Call lo_Control.Unload_A_COM
      Case "ARMGRID"
        Call lo_Control.Unload_A_COM
      Case "ARMTREEVIEW"
        Call lo_Control.Unload_A_COM
      Case "ARMCHECKVIEW"
        Call lo_Control.Unload_A_COM
      Case "TOOLBR"
        Call lo_Control.Unload_A_COM
      End Select
    Next
    Exit Sub
    
errhandler:
    
    Call ErrorHandler("UnLoad_A_Com")
    
End Sub

Public Sub Resize()
    Call InitCtrlSize
End Sub

Private Sub InitCtrlSize()
On Error GoTo errhandler
    If UserControl.Extender.Width < 11910 Then
        Exit Sub
    End If
    
    If UserControl.Extender.Height < 5500 Then
        Exit Sub
    End If
    
    Const SPACE As Long = 60
        
    Call frm_detail.Move(0, 0, UserControl.Extender.Width, UserControl.Extender.Height)
    
    Call grd_items.Move(SPACE, 220, frm_detail.Width - frm_itemDetail.Width - 3 * SPACE, frm_detail.Height - grd_items.Top - SPACE)
    
    
    Call frm_itemHeader.Move(grd_items.Left + grd_items.Width + SPACE, grd_items.Top - 90)
    Call cal_InvoiceDate.Move(frm_itemHeader.Left + 1335, frm_itemHeader.Top + 990)
    
    Call tlb_item.Move(frm_itemHeader.Left, frm_itemHeader.Top + frm_itemHeader.Height + SPACE, frm_itemHeader.Width)
    
    Call frm_itemDetail.Move(tlb_item.Left, tlb_item.Top + tlb_item.Height + SPACE)
    
    Exit Sub
errhandler:
    Call ErrorHandler("InitCtrlSize")
End Sub

' Standard error handler
Private Sub ErrorHandler(ByVal as_Fct As String)
    Err.Raise Err.Number, UserControl.Name & "." & UserControl.Ambient.DisplayName & "::" & as_Fct & SEP1 & Err.Source, Err.Description
End Sub



Private Function GetContainedControlsChain(ByVal ao_parent As Object) As Collection
On Error GoTo errhandler
    Dim lo_retCollection As New Collection
    Dim lo_Control As Object
    
    For Each lo_Control In Controls
        If Not TypeOf lo_Control.Container Is DC_InvoiceItemMtnc Then
            If ao_parent.hwnd = lo_Control.Container.hwnd Then
                If TypeOf lo_Control Is Frame Then
                    Dim lo_aux_collection As New Collection
                    Dim ll_i As Long
                    Set lo_aux_collection = GetContainedControlsChain(lo_Control)
                    For ll_i = 1 To lo_aux_collection.Count
                        lo_retCollection.Add (lo_aux_collection.Item(ll_i))
                    Next
                Else
                    Call lo_retCollection.Add(lo_Control)
                End If
            End If
        End If
    Next
    Set GetContainedControlsChain = lo_retCollection
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".GetContainedControlsChain()")
End Function

Private Function UpdateGridAfterAction(ByVal ao_grid As ArmGrid, ByVal as_Action As String, ByVal av_Key As Variant, Optional ByVal as_no_upd_Action As String = "") As Boolean
On Error GoTo errhandler
    Dim ll_Index As Long
    Dim lo_Column As ArmColumn
    
    UpdateGridAfterAction = False
    
    Select Case as_Action
    Case "Add"
        ' insert row at the end of grid
        Debug.Assert (ao_grid.Cols > 0)
        Dim lsa_newRow() As String
        'MS REDIMM
        Call SafeRedimPreserve(lsa_newRow, ao_grid.Cols - 1)
        Dim ll_KeyIndex As Long
        ll_KeyIndex = 0
        
        For ll_Index = 0 To ao_grid.Cols - 1
            Set lo_Column = ao_grid.Columns(ll_Index)
            If lo_Column.Key Then
                Debug.Assert (UBound(av_Key) >= ll_KeyIndex)
                lsa_newRow(ll_Index) = av_Key(ll_KeyIndex)
                ll_KeyIndex = ll_KeyIndex + 1
            ElseIf lo_Column.Name = "Action" Then
                lsa_newRow(ll_Index) = "A"
            ElseIf lo_Column.Name = "iConcurrency" Then
                lsa_newRow(ll_Index) = 0
            Else
                lsa_newRow(ll_Index) = GetDataSrcForGrid(lo_Column)
            End If
        Next
        Call ao_grid.AddLine(lsa_newRow)
        ao_grid.LineColor(ao_grid.Row) = vbGreen
    Case "Upd"
        ' search and update row in the grid
        Debug.Assert (ao_grid.Cols > 0)
        
        If Not EqualKeys(ao_grid.SelectedKey(0), av_Key) Then
            If Not ao_grid.SearchKey(True, av_Key) Then
                Exit Function
            End If
        End If
        
        Dim ls_newData As String
        Dim lb_updated As Boolean
        lb_updated = False
        
        For ll_Index = 0 To ao_grid.Cols - 1
            Set lo_Column = ao_grid.Columns(ll_Index)
            If Not lo_Column.Key Then
                If lo_Column.Name = "Action" Then
                    If (lo_Column.GetData(ao_grid.Row) = "" And lb_updated) Or lo_Column.GetData(ao_grid.Row) = "D" Then
                        Call lo_Column.SetData(ao_grid.Row, "U")
                        ao_grid.LineColor(ao_grid.Row) = vbCyan
                    ElseIf lo_Column.GetData(ao_grid.Row) = "" And Not lb_updated Then
                        Call lo_Column.SetData(ao_grid.Row, as_no_upd_Action)
                    End If
                ElseIf lo_Column.Name <> "iConcurrency" Then
                    ls_newData = GetDataSrcForGrid(lo_Column)
                    If ls_newData <> lo_Column.GetData(ao_grid.Row) Then
                        If Not lo_Column.SetData(ao_grid.Row, ls_newData) Then
                            Call Err.Raise(1, "lo_Column.SetData", "Cannot update grid.")
                        End If
                        lb_updated = True
                    End If
                End If
            End If
        Next

    Case "Del"
        Debug.Assert (ao_grid.Cols > 0)
        
        If Not EqualKeys(ao_grid.SelectedKey(0), av_Key) Then
            If Not ao_grid.SearchKey(True, av_Key) Then
                Exit Function
            End If
        End If
        
        Call ao_grid.DeleteSelectedLines
    
    Case "Del2"         ' mark as to be deleted
        Debug.Assert (ao_grid.Cols > 0)
        
        If Not EqualKeys(ao_grid.SelectedKey(0), av_Key) Then
            If Not ao_grid.SearchKey(True, av_Key) Then
                Exit Function
            End If
        End If
        
        If ao_grid.Data(ao_grid.Row, "Action") = "A" Then
            Call ao_grid.DeleteSelectedLines
        Else
            ao_grid.Data(ao_grid.Row, "Action") = "D"
            ao_grid.LineColor(ao_grid.Row) = vbRed
            
            Call ao_grid.DeselectRow
        End If
        
    Case Else
        Debug.Assert (False)
    End Select
    UpdateGridAfterAction = True
    Exit Function
errhandler:
     Call ErrorHandler("UpdateGridAfterAction()")
End Function

' when updating main grid from detail
Private Function GetDataSrcForGrid(ByVal ao_Column As ArmColumn) As String
On Error GoTo errhandler
    Select Case ao_Column.FieldName
        Case "DCII_Code", "iConcurrency", "Action"
            Debug.Assert (False) ' must be handled in levele above
        Case "DCII_Number"
            GetDataSrcForGrid = txt_DCII_Number.Text
        Case "DCII_Amount"
            GetDataSrcForGrid = txt_DCII_Amount.Text
        Case "TRANS_Code"
            GetDataSrcForGrid = GetCboKey(cbo_TRANS_Code)
        Case "TRANS_Name"
            GetDataSrcForGrid = GetCboText(cbo_TRANS_Code)
        Case "CARRIER_Name"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "CARRIER_Name")
        Case "Shipping_Date"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "Shipping_Date")
        Case "CUSTN1"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "CUSTN1")
        Case "Ship_To_Zip_Code"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "Ship_To_Zip_Code")
        Case "Ship_To_CT_Code"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "Ship_To_CT_Code")
        Case "Ship_To_Address"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "Ship_To_Address")
        Case "Quantity"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "Quantity")
        Case "UOM_Code"
            GetDataSrcForGrid = GetCboValue(cbo_TRANS_Code, "UOM_Code")
    End Select
    
    Exit Function
errhandler:
     Call ErrorHandler("GetDataSrcForGrid()")
End Function


Private Sub Item_LoadGrid()
On Error GoTo errhandler
    
Const C_REQ As String = "EXEC DC_InvoiceItem_lst $DCI_Code$"
    Dim ls_req As String
    
    If txt_DCI_Code.Text <> "NEW" Then
    
        ls_req = Item_ReplacePlaceholders(C_REQ)
    
        If Not grd_items.Load(ls_req, True) Then
            MsgBox ("Grid not loaded!")
        End If
    Else
        Call grd_items.ClearGrid
        grd_items.Requests = ""
    End If
    
    Exit Sub
errhandler:
     Call ErrorHandler("Item_LoadGrid()")
End Sub

Private Sub Item_Clear()
On Error GoTo errhandler
    
    txt_DCI_Number.Text = ""
    
    txt_DCI_Code.Text = ""
    
    Set cbo_DC_Code.SelectedItem = Nothing
    
    Call cbo_CARRIER_Code.Clear
    Set cbo_CARRIER_Code.SelectedItem = Nothing
    
    Set cbo_CURR_Code.SelectedItem = Nothing
    
    Call cal_InvoiceDate.reinit_cal
    
    Call grd_items.ClearGrid
    
    Exit Sub
errhandler:
    Call ErrorHandler("Item_Clear()")
End Sub

Private Sub ItemLine_Clear()
On Error GoTo errhandler
    
    txt_DCII_Number.Text = ""
    
    txt_DCII_Code.Text = ""
    
    txt_DCII_Amount.Text = ""
    
    Call cbo_TRANS_Code.Clear
    Set cbo_TRANS_Code.SelectedItem = Nothing
    
    Exit Sub
errhandler:
    Call ErrorHandler("ItemLine_Clear()")
End Sub


Public Sub ViewInit(ByVal al_DCII_Code As Long)
On Error GoTo errhandler
    
    Call Item_Clear
    
    ' loading values
    Call Item_LoadValues(al_DCII_Code)
    
    Call Item_UpdateUI(ArmScreenMode.smMain)
    
    If grd_items.SearchKey(True, Array(al_DCII_Code)) Then
        Call grd_items_SelChange
    End If
    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".ViewInit")
End Sub

Public Sub UpdateInit(ByVal al_DCII_Code As Long)
On Error GoTo errhandler
    
    Call Item_Clear
    
    ' loading values
    Call Item_LoadValues(al_DCII_Code)
    
    Call Item_UpdateUI(ArmScreenMode.smMain)
    
    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".UpdateInit")
End Sub

Public Sub UpdateInit2(ByVal al_DCII_Code As Long, ByVal al_TRANS_Code As Long)
On Error GoTo errhandler
    
    mb_eventRunning = True
    
    Call UpdateInit(al_DCII_Code)
    
    ' navigate to add item mode
    Call ItemLine_AddInit
    
    If Not SetCboKey(cbo_TRANS_Code, al_TRANS_Code) Then
        ' cancel the init
        
        ' inconsistent data!!!
        ReDim ms_MsgInfo(0, 1)
        ms_MsgInfo(0, 0) = "$TRANS_Code$"
        ms_MsgInfo(0, 1) = al_TRANS_Code
        
        Call MsgBox(MsgText(5180, ms_Language_Code, "#Skipping inconsistent line for TRANS_Code=$TRANS_Code$", ms_MsgInfo), vbOKOnly)
        
        Call Item_UpdateUI(ArmScreenMode.smMain)
    Else
        txt_DCII_Amount.Text = GetCboValue(cbo_TRANS_Code, "DC_Cost")
        Call SetTextBoxFocus(txt_DCII_Amount)
    End If

    mb_eventRunning = False
    Exit Sub
errhandler:
    mb_eventRunning = False
    Call ErrorHandler(Extender.Name & ".UpdateInit2")
End Sub

Public Sub UpdateInit2_sel(ByRef ao_grid As ArmGrid, ByVal al_DCII_Code As Long)
On Error GoTo errhandler
    
    mb_eventRunning = True
    
    Call UpdateInit(al_DCII_Code)
    
    Dim ls_DC_Code As String
    Dim ls_CARRIER_Code As String
    Dim ls_CURR_Code As String
    
    ls_DC_Code = GetCboKey(cbo_DC_Code)
    ls_CARRIER_Code = GetCboKey(cbo_CARRIER_Code)
    ls_CURR_Code = GetCboKey(cbo_CURR_Code)
    
    Dim ll_i As Long
    
    For ll_i = 0 To ao_grid.SelectedCount - 1
    
        If ao_grid.SelectedLine(ll_i, "DCII_Code") = 0 Then
    
            If ls_DC_Code <> ao_grid.SelectedLine(ll_i, "DC_Code") Or _
                ls_CARRIER_Code <> ao_grid.SelectedLine(ll_i, "CARRIER_Code") Or _
                ls_CURR_Code <> ao_grid.SelectedLine(ll_i, "CURR_Code") Then
                
                ' inconsistent data!!!
                ReDim ms_MsgInfo(2, 1)
                ms_MsgInfo(0, 0) = "$DC_Code$"
                ms_MsgInfo(0, 1) = ao_grid.SelectedLine(ll_i, "DC_Code")
                ms_MsgInfo(1, 0) = "$CARRIER_Code$"
                ms_MsgInfo(1, 1) = ao_grid.SelectedLine(ll_i, "CARRIER_Code")
                ms_MsgInfo(2, 0) = "$CURR_Code$"
                ms_MsgInfo(2, 1) = ao_grid.SelectedLine(ll_i, "CURR_Code")
                
                Call MsgBox(MsgText(5190, ms_Language_Code, "#Skipping inconsistent line for DC=$DC_Code$, Carrier=$CARRIER_Code$, Currency=$CURR_Code$", ms_MsgInfo), vbOKOnly)
            Else
            
                Call ItemLine_AddInit
                
                Call SetCboKey(cbo_TRANS_Code, ao_grid.SelectedLine(ll_i, "TRANS_Code"))
                
                txt_DCII_Amount.Text = ao_grid.SelectedLine(ll_i, "DC_Cost")
                
                Call ItemLine_Add
            
            End If
        End If
    Next

    Call Item_UpdateUI(ArmScreenMode.smMain)
    
    Call grd_items.DeselectRow
    
    mb_eventRunning = False
    Exit Sub
errhandler:
    mb_eventRunning = False
    Call ErrorHandler(Extender.Name & ".UpdateInit2_sel")
End Sub

Public Sub AddInit2_sel(ByRef ao_grid As ArmGrid)
On Error GoTo errhandler
    
    mb_eventRunning = True
    
    Dim ls_DC_Code As String
    Dim ls_CARRIER_Code As String
    Dim ls_CURR_Code As String
    
    ls_DC_Code = ao_grid.SelectedLine(0, "DC_Code")
    ls_CARRIER_Code = ao_grid.SelectedLine(0, "CARRIER_Code")
    ls_CURR_Code = ao_grid.SelectedLine(0, "CURR_Code")
    
    Call AddInit(ls_DC_Code, ls_CARRIER_Code)
    
    'fill some data

    Call SetCboKey(cbo_CURR_Code, ls_CURR_Code)
    
    Dim ll_i As Long
    
    For ll_i = 0 To ao_grid.SelectedCount - 1
        
        If ao_grid.SelectedLine(ll_i, "DCII_Code") = 0 Then
        
            If ls_DC_Code <> ao_grid.SelectedLine(ll_i, "DC_Code") Or _
                ls_CARRIER_Code <> ao_grid.SelectedLine(ll_i, "CARRIER_Code") Or _
                ls_CURR_Code <> ao_grid.SelectedLine(ll_i, "CURR_Code") Then
                
                ' inconsistent data!!!
                ReDim ms_MsgInfo(2, 1)
                ms_MsgInfo(0, 0) = "$DC_Code$"
                ms_MsgInfo(0, 1) = ao_grid.SelectedLine(ll_i, "DC_Code")
                ms_MsgInfo(1, 0) = "$CARRIER_Code$"
                ms_MsgInfo(1, 1) = ao_grid.SelectedLine(ll_i, "CARRIER_Code")
                ms_MsgInfo(2, 0) = "$CURR_Code$"
                ms_MsgInfo(2, 1) = ao_grid.SelectedLine(ll_i, "CURR_Code")
                
                Call MsgBox(MsgText(5190, ms_Language_Code, "#Skipping inconsistent line for DC=$DC_Code$, Carrier=$CARRIER_Code$, Currency=$CURR_Code$", ms_MsgInfo), vbOKOnly)
            Else
                ' navigate to add item mode
                Call ItemLine_AddInit
                
                Call SetCboKey(cbo_TRANS_Code, ao_grid.SelectedLine(ll_i, "TRANS_Code"))
                
                txt_DCII_Amount.Text = ao_grid.SelectedLine(ll_i, "DC_Cost")
                
                Call ItemLine_Add
                
            End If
            
        End If
        
    Next

    Call Item_UpdateUI(ArmScreenMode.smMain)
    
    Call grd_items.DeselectRow
    
    Call SetTextBoxFocus(txt_DCI_Number)
    
    mb_eventRunning = False
    Exit Sub
errhandler:
    mb_eventRunning = False
    Call ErrorHandler(Extender.Name & ".AddInit2_sel")
End Sub

Public Sub UpdateInit3(ByVal al_DCII_Code As Long)
On Error GoTo errhandler
    
    Call UpdateInit(al_DCII_Code)
    
    If grd_items.SearchKey(True, Array(al_DCII_Code)) Then
        Call grd_items_SelChange
    End If
    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".UpdateInit3")
End Sub

Public Sub DeleteInit(ByVal al_DCII_Code As Long)
On Error GoTo errhandler
    
    Call Item_Clear
    
    ' loading values
    Call Item_LoadValues(al_DCII_Code)
    
    Call Item_UpdateUI(ArmScreenMode.smMain)
    
    If grd_items.SearchKey(True, Array(al_DCII_Code)) Then
        Call grd_items_SelChange
    End If
    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".DeleteInit")
End Sub

Private Function Item_Check() As Boolean
On Error GoTo errhandler
    Item_Check = False
    
    If GetCboKey(cbo_DC_Code) = "" Then
        Call MsgBox(Replace(MsgText(8300, ms_Language_Code, "The field is mandatory."), "$FIELD_NAME$", lbl_labels(7).Caption, , , vbTextCompare), vbInformation)
        Call cbo_DC_Code.SetFocus
        Exit Function
    End If
    
    If GetCboKey(cbo_CARRIER_Code) = "" Then
        Call MsgBox(Replace(MsgText(8300, ms_Language_Code, "The field is mandatory."), "$FIELD_NAME$", lbl_labels(6).Caption, , , vbTextCompare), vbInformation)
        Call cbo_CARRIER_Code.SetFocus
        Exit Function
    End If
    
    If cal_InvoiceDate.date_dt() = 0 Then
        Call MsgBox(Replace(MsgText(8300, ms_Language_Code, "The field is mandatory."), "$FIELD_NAME$", lbl_labels(8).Caption, , , vbTextCompare), vbInformation)
        Call cal_InvoiceDate.SetFocus
        Exit Function
    End If
    
    If Trim(txt_DCI_Number) = "" Then
        Call MsgBox(Replace(MsgText(8300, ms_Language_Code, "The field is mandatory."), "$FIELD_NAME$", lbl_labels(9).Caption, , , vbTextCompare), vbInformation)
        Call txt_DCI_Number.SetFocus
        Exit Function
    End If
    
    If GetCboKey(cbo_CURR_Code) = "" Then
        Call MsgBox(Replace(MsgText(8300, ms_Language_Code, "The field is mandatory."), "$FIELD_NAME$", lbl_labels(14).Caption, , , vbTextCompare), vbInformation)
        Call cbo_CURR_Code.SetFocus
        Exit Function
    End If
    
    Item_Check = True
    
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Item_Check")
End Function

Private Function ItemLine_Check() As Boolean
On Error GoTo errhandler
    ItemLine_Check = False

    If (Trim(txt_DCII_Number.Text) = "") Then
        Call MsgBox("Missing Invoice Item number!")
        Call SetTextBoxFocus(txt_DCII_Number)
        Exit Function
    End If
    
    
    If (Trim(txt_DCII_Amount.Text) <> "") And Not isNumeric(txt_DCII_Amount.Text) Then
        Call MsgBox("Wrong Amount number!")
        Call SetTextBoxFocus(txt_DCII_Amount)
        Exit Function
    End If
    
    ' check if reccord with the same ItemNb exists
    Dim ll_i As Long
    For ll_i = 0 To grd_items.Rows - 1
        If txt_DCII_Number.Text = grd_items.Data(ll_i, "DCII_Number") Then
            If txt_DCII_Code.Text <> grd_items.Data(ll_i, "DCII_Code") Then
                Call MsgBox("Item with the same item number already exists!")
                Call SetTextBoxFocus(txt_DCII_Number)
                Exit Function
            End If
        End If
    Next
    
    ItemLine_Check = True
    Exit Function
errhandler:
    Call ErrorMessage("ItemLine_Check")
End Function

Private Sub SetTextBoxFocus(ByRef ao_tb As TextBox)
On Error GoTo errhandler
    
    ao_tb.SelStart = 0
    ao_tb.SelLength = Len(ao_tb.Text)
    If ao_tb.Visible Then
        Call ao_tb.SetFocus
    End If

    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".SetTextBoxFocus")
End Sub


Public Function Add() As Boolean
On Error GoTo errhandler
    Add = False
    If Not Item_Check Then
        Exit Function
    End If

    Dim ll_DCI_Code As Long
    ll_DCI_Code = Item_AddDB
    
    RaiseEvent RowAdded(ll_DCI_Code, cal_InvoiceDate.date_dt, txt_DCI_Number.Text, GetCboKey(cbo_CURR_Code))
    
    Add = True
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Add")
End Function

Public Function Update() As Boolean
On Error GoTo errhandler

    Update = False
    If Not Item_Check Then
        Exit Function
    End If
    
    If Item_UpdateDB Then
        RaiseEvent RowUpdated(Val(txt_DCI_Code.Text), cal_InvoiceDate.date_dt, txt_DCI_Number.Text, GetCboKey(cbo_CURR_Code))
    Else
        RaiseEvent RowDeleted(Val(txt_DCI_Code.Text))
    End If
    
    Update = True
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Update")
End Function

Public Function Delete() As Boolean
On Error GoTo errhandler
    Delete = False
    
    If MsgBox("Do you want to delete the record?", vbYesNo) <> vbYes Then
        Exit Function
    End If
        
    Call Item_DeleteDB
    
    RaiseEvent RowDeleted(Val(txt_DCI_Code.Text))
    
    Delete = True
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Delete")
End Function

Public Function Line_AddDB(ByVal al_DCI_Code As Long, ByVal as_DCII_Number As String, al_TRANS_Code As Long, ad_DCII_Amount As Double) As Long
On Error GoTo errhandler
    Line_AddDB = 0
    
Const CREQ_AV = "EXEC DC_InvoiceItem_ins $DCII_Code$, $DCI_Code$, $DCII_Number$, $Trans_code$, $DCII_Amount$, $Z_Creator$"

    Dim ls_req As String
    
    Dim ll_DCII_Code As Long
    
    ll_DCII_Code = CLng(GetNextRecordID("DCII_Code"))
    
    ls_req = Replace(CREQ_AV, "$DCII_Code$", SQLNum(ll_DCII_Code), , , vbTextCompare)
    ls_req = Replace(ls_req, "$DCI_Code$", SQLNum(al_DCI_Code), , , vbTextCompare)
    ls_req = Replace(ls_req, "$DCII_Number$", SqlStr(as_DCII_Number, 3), , , vbTextCompare)
    ls_req = Replace(ls_req, "$Trans_code$", SQLNum(al_TRANS_Code, True), , , vbTextCompare)
    ls_req = Replace(ls_req, "$DCII_Amount$", SQLNum(ad_DCII_Amount), , , vbTextCompare)
    ls_req = Replace(ls_req, "$Z_Creator$", SqlStr(ms_LoginName, 15), , , vbTextCompare)
    
    Call ExecuteSQLSafe(mo_Db, ls_req, 1)

    Line_AddDB = ll_DCII_Code
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Line_AddDB")
End Function

Public Function Line_DeleteDB(ByVal al_DCII_Code As Long, ByVal al_iConcurrency As Long) As Boolean
On Error GoTo errhandler
    Line_DeleteDB = False
Const CREQ_DV = "EXEC DC_InvoiceItem_del $DCII_Code$, $Z_Creator$, $iConcurrency$"
Const CREQ_DINV = "EXEC DC_Invoice_del2 $DCII_Code$, $Z_Creator$"
    
    Dim ls_req As String
    
    ls_req = Replace(CREQ_DV, "$DCII_Code$", SQLNum(al_DCII_Code), , , vbTextCompare)
    ls_req = Replace(ls_req, "$iConcurrency$", SQLNum(al_iConcurrency), , , vbTextCompare)
    ls_req = Replace(ls_req, "$Z_Creator$", SqlStr(ms_LoginName, 15), , , vbTextCompare)
    
    Call ExecuteSQLSafe(mo_Db, ls_req, 1)

    ls_req = Replace(CREQ_DINV, "$DCII_Code$", SQLNum(al_DCII_Code), , , vbTextCompare)
    ls_req = Replace(ls_req, "$Z_Creator$", SqlStr(ms_LoginName, 15), , , vbTextCompare)
    
    Call ExecuteSQLSafe(mo_Db, ls_req)

    Line_DeleteDB = True
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Line_DeleteDB")
End Function

Public Function Line_UpdateDB(ByVal al_valueIndex As Long) As Long
On Error GoTo errhandler
    Dim ls_req As String
    
    Line_UpdateDB = 0

Const CREQ_AV = "EXEC DC_InvoiceItem_ins $DCII_Code$, $DCI_Code$, $DCII_Number$, $Trans_code$, $DCII_Amount$, $Z_Creator$"
Const CREQ_UV = "EXEC DC_InvoiceItem_upd $DCII_Code$, $DCII_Number$, $Trans_code$, $DCII_Amount$, $Z_Creator$, $iConcurrency$"
Const CREQ_DV = "EXEC DC_InvoiceItem_del $DCII_Code$, $Z_Creator$, $iConcurrency$"
    
    ls_req = ""
    Select Case grd_items.Data(al_valueIndex, "Action")
        Case "A"
            If grd_items.Data(al_valueIndex, "DCII_Code") = "NEW" Then
                
                grd_items.Data(al_valueIndex, "DCII_Code") = CLng(GetNextRecordID("DCII_Code"))
                
                Line_UpdateDB = CLng(grd_items.Data(al_valueIndex, "DCII_Code"))
                
                ls_req = Replace(CREQ_AV, "$DCI_Code$", SQLNum(txt_DCI_Code.Text), , , vbTextCompare)
            End If
        Case "U"
            ls_req = CREQ_UV
        Case "D"
            ls_req = CREQ_DV
    End Select
    
    If ls_req = "" Then
        Exit Function
    End If
    
    ls_req = Replace(ls_req, "$DCII_Code$", SQLNum(grd_items.Data(al_valueIndex, "DCII_Code")), , , vbTextCompare)
    ls_req = ItemLine_ReplacePlaceholders(ls_req, al_valueIndex)
    
    Call ExecuteSQLSafe(mo_Db, ls_req, 1)
    
    ' raise events
    Select Case grd_items.Data(al_valueIndex, "Action")
        Case "A"
            RaiseEvent ItemRowAdded(Val(grd_items.Data(al_valueIndex, "TRANS_Code")), CLng(grd_items.Data(al_valueIndex, "DCII_Code")), Val(grd_items.Data(al_valueIndex, "DCII_Amount")), grd_items.Data(al_valueIndex, "DCII_Number"))
        Case "U"
            RaiseEvent ItemRowUpdated(CLng(grd_items.Data(al_valueIndex, "DCII_Code")), Val(grd_items.Data(al_valueIndex, "DCII_Amount")), grd_items.Data(al_valueIndex, "DCII_Number"))
        Case "D"
            RaiseEvent ItemRowDeleted(Val(grd_items.Data(al_valueIndex, "TRANS_Code")), CLng(grd_items.Data(al_valueIndex, "DCII_Code")))
    End Select
    
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Line_UpdateDB")
End Function

Private Function Item_AddDB() As Long
On Error GoTo errhandler
    Item_AddDB = 0
    Dim ls_req As String

Const CREQ = "EXEC DC_Invoice_ins $DCI_Code$, $DC_CARRIER_Code$, $DCI_Number$, $DCI_Date$, $CURR_Code$, $Z_Creator$"
    
    Dim ll_record_ID As Long
    
    ll_record_ID = CLng(GetNextRecordID("DCI_Code"))
    
    txt_DCI_Code.Text = ll_record_ID
    
    ' common placeholders
    ls_req = Replace(CREQ, "$DCI_Code$", ll_record_ID, , , vbTextCompare)
    ls_req = Item_ReplacePlaceholders(ls_req)
    
    Call BeginTran("DC_INVOICE")
    
    Call ExecuteSQLSafe(mo_Db, ls_req, 1)
    
    ' update invoice items
    Dim ll_i As Long
    
    'step 1 .... generate DC_InvoiceItem records
    
    For ll_i = 0 To grd_items.Rows - 1
        
        Call Line_UpdateDB(ll_i)
        
    Next
    
    Call CommitTran("DC_INVOICE")
    Item_AddDB = ll_record_ID
    Exit Function
errhandler:
    Call RollbackTran("DC_INVOICE")
    Call ErrorHandler(Extender.Name & ".Item_AddDB")
End Function

Public Function AddDB2(ByVal ls_DC_CARRIER_Code As String, ByVal as_DCI_Number As String, ByVal ad_DCI_Date As Date, ByVal as_CURR_Code As String) As Long
On Error GoTo errhandler
    Dim ls_req As String
    
    AddDB2 = 0

Const CREQ = "EXEC DC_Invoice_ins $DCI_Code$, $DC_CARRIER_Code$, $DCI_Number$, $DCI_Date$, $CURR_Code$, $Z_Creator$"
    
    Dim ll_record_ID As Long
    
    ll_record_ID = CLng(GetNextRecordID("DCI_Code"))
    
    ' common placeholders
    ls_req = Replace(CREQ, "$DCI_Code$", SQLNum(ll_record_ID), , , vbTextCompare)
    ls_req = Replace(ls_req, "$DC_CARRIER_Code$", SqlStr(ls_DC_CARRIER_Code, 10), , , vbTextCompare)
    ls_req = Replace(ls_req, "$DCI_Number$", SqlStr(as_DCI_Number, 10), , , vbTextCompare)
    ls_req = Replace(ls_req, "$DCI_Date$", SqlDate(ad_DCI_Date), , , vbTextCompare)
    ls_req = Replace(ls_req, "$CURR_Code$", SqlStr(as_CURR_Code, 5), , , vbTextCompare)
    ls_req = Replace(ls_req, "$Z_Creator$", SqlStr(ms_LoginName, 15), , , vbTextCompare)
    
    Call ExecuteSQLSafe(mo_Db, ls_req, 1)
    
    AddDB2 = ll_record_ID
    
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".AddDB2")
End Function


Private Function Item_UpdateDB() As Boolean
On Error GoTo errhandler
Const C_REQ = "EXEC DC_Invoice_upd $DCI_Code$, $DC_CARRIER_Code$, $DCI_Number$, $DCI_Date$, $CURR_Code$, $Z_Creator$, $iConcurrency$"
Const C_REQ_DEL = "EXEC DC_Invoice_del $DCI_Code$, $Z_Creator$, $iConcurrency$"

    Item_UpdateDB = False
    Call BeginTran("DC_INVOICE")
    
    Call ExecuteSQLSafe(mo_Db, Item_ReplacePlaceholders(C_REQ), 1)
    ml_iConcurrency = ml_iConcurrency + 1
        
    ' update invoice items
    Dim ll_i As Long
    
    Dim ll_deletedCounter As Long
    ll_deletedCounter = 0
    
    'step 1 .... generate DC_InvoiceItem records
    
    For ll_i = 0 To grd_items.Rows - 1
        
        If grd_items.Data(ll_i, "Action") = "D" Then
            ll_deletedCounter = ll_deletedCounter + 1
        End If
        
        Call Line_UpdateDB(ll_i)
        
    Next
    
    ' if we have removed all the lines => we remove also the invoice
    If ll_deletedCounter = grd_items.Rows Then
        Call ExecuteSQLSafe(mo_Db, Item_ReplacePlaceholders(C_REQ_DEL), 1)
    Else
        Item_UpdateDB = True
    End If
    
    Call CommitTran("DC_INVOICE")
    Exit Function
errhandler:
    Call RollbackTran("DC_INVOICE")
    Call ErrorHandler(Extender.Name & ".Item_UpdateDB")
End Function

Private Sub Item_DeleteDB()
On Error GoTo errhandler
Const C_REQ = "EXEC DC_Invoice_del $DCI_Code$, $Z_Creator$, $iConcurrency$"
    
    Call BeginTran("DC_INVOICE")
    
    Dim ll_i As Long
    
    For ll_i = 0 To grd_items.Rows - 1
        grd_items.Data(ll_i, "Action") = "D"
        
        Call Line_UpdateDB(ll_i)
    Next
        
    Call ExecuteSQLSafe(mo_Db, Item_ReplacePlaceholders(C_REQ), 1)
    
    Call CommitTran("DC_INVOICE")
    Exit Sub
errhandler:
    Call RollbackTran("DC_INVOICE")
    Call ErrorHandler(Extender.Name & ".Item_DeleteDB")
End Sub

Private Function Item_ReplacePlaceholders(ByVal as_req As String) As String
On Error GoTo errhandler

    as_req = Replace(as_req, "$DCI_Code$", SQLNum(txt_DCI_Code.Text), , , vbTextCompare)
    as_req = Replace(as_req, "$DCI_Number$", SqlStr(txt_DCI_Number.Text, 16), , , vbTextCompare)
    as_req = Replace(as_req, "$DC_CARRIER_Code$", SQLNum(GetCboValue(cbo_CARRIER_Code, "DC_CARRIER_Code")), , , vbTextCompare)
    as_req = Replace(as_req, "$DCI_Date$", SqlDate(cal_InvoiceDate.date_dt), , , vbTextCompare)
    as_req = Replace(as_req, "$CURR_Code$", SqlStr(GetCboKey(cbo_CURR_Code), 5), , , vbTextCompare)
    as_req = Replace(as_req, "$Z_Creator$", SqlStr(ms_LoginName, 15), , , vbTextCompare)
    as_req = Replace(as_req, "$iConcurrency$", SQLNum(ml_iConcurrency), , , vbTextCompare)
    as_req = Replace(as_req, "$TT_Code$", SqlStr(Tag, 1), , , vbTextCompare)

    Item_ReplacePlaceholders = as_req
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".Item_ReplacePlaceholders")
End Function

Private Function ItemLine_ReplacePlaceholders(ByVal as_req As String, ByVal al_Row As Long) As String
On Error GoTo errhandler
    
    as_req = Replace(as_req, "$DCII_Code$", SQLNum(grd_items.Data(al_Row, "DCII_Code")), , , vbTextCompare)
    as_req = Replace(as_req, "$DCII_Number$", SqlStr(grd_items.Data(al_Row, "DCII_Number"), 10), , , vbTextCompare)
    as_req = Replace(as_req, "$DCII_Amount$", SQLNum(grd_items.Data(al_Row, "DCII_Amount")), , , vbTextCompare)
    as_req = Replace(as_req, "$TRANS_Code$", SQLNum(grd_items.Data(al_Row, "TRANS_Code"), True), , , vbTextCompare)
    as_req = Replace(as_req, "$iConcurrency$", SQLNum(grd_items.Data(al_Row, "iConcurrency")), , , vbTextCompare)
    as_req = Replace(as_req, "$Z_Creator$", SqlStr(ms_LoginName, 15), , , vbTextCompare)

    ItemLine_ReplacePlaceholders = as_req
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".ItemLine_ReplacePlaceholders")
End Function

Public Sub AddInit(ByVal as_DC_Code As String, ByVal as_CARRIER_Code As String)
On Error GoTo errhandler
    
    ms_DC_Code = as_DC_Code
    
    ms_Carrier_Code = as_CARRIER_Code
    
    Call Item_Clear
    
    ' loading values
    Call Item_LoadValues(0)
    
    Call Item_UpdateUI(ArmScreenMode.smMain)
    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".AddInit")
End Sub

Public Sub AddInit2(ByVal as_DC_Code As String, ByVal as_CARRIER_Code As String, al_TRANS_Code As Long, ByVal as_CURR_Code As String)
On Error GoTo errhandler

    mb_eventRunning = True

    Call AddInit(as_DC_Code, as_CARRIER_Code)
    
    Call SetCboKey(cbo_CURR_Code, as_CURR_Code)
    
    ' navigate to add item mode
    Call ItemLine_AddInit
    
    If Not SetCboKey(cbo_TRANS_Code, al_TRANS_Code) Then
        ' cancel the init
        
        ' inconsistent data!!!
        ReDim ms_MsgInfo(0, 1)
        ms_MsgInfo(0, 0) = "$TRANS_Code$"
        ms_MsgInfo(0, 1) = al_TRANS_Code
        
        Call MsgBox(MsgText(5180, ms_Language_Code, "#Skipping inconsistent line for TRANS_Code=$TRANS_Code$", ms_MsgInfo), vbOKOnly)
        
        Call Item_UpdateUI(ArmScreenMode.smMain)
    Else
        txt_DCII_Amount.Text = GetCboValue(cbo_TRANS_Code, "DC_Cost")
        Call SetTextBoxFocus(txt_DCII_Amount)
    End If
    
    mb_eventRunning = False
    Exit Sub
errhandler:
    mb_eventRunning = False
    Call ErrorHandler(Extender.Name & ".AddInit2")
End Sub

Private Sub ItemLine_AddInit()
On Error GoTo errhandler
    
    ' check if DC_CARRIER_Code is selected
    If GetCboValue(cbo_CARRIER_Code, "DC_CARRIER_Code") = "" Then
        Call MsgBox(Replace(MsgText(8300, ms_Language_Code, "The field is mandatory."), "$FIELD_NAME$", lbl_labels(6).Caption, , , vbTextCompare), vbInformation)
        Call cbo_CARRIER_Code.SetFocus
        Exit Sub
    End If

    Call ItemLine_Clear
    
    Call Item_UpdateUI(ArmScreenMode.smAdd)
    
    Call ItemLine_LoadValues(Empty)
    
    Call SetTextBoxFocus(txt_DCII_Amount)
    
    Exit Sub
errhandler:
    Call ErrorMessage("ItemLine_AddInit")
End Sub

Private Sub ItemLine_UpdateInit(ByVal av_Key As Variant)
On Error GoTo errhandler
    
    Call ItemLine_Clear
    
    If Not EqualKeys(grd_items.SelectedKey(0), av_Key) Then
        If Not grd_items.SearchKey(True, av_Key) Then
            MsgBox ("Record not found!")
            Exit Sub
        End If
    End If
    
    Call ItemLine_LoadValues(av_Key)
    
    Call Item_UpdateUI(ArmScreenMode.smUpdate)
    
    Exit Sub
errhandler:
    Call ErrorMessage("ItemLine_UpdateInit")
End Sub

Private Sub ItemLine_ViewInit(ByVal av_Key As Variant)
On Error GoTo errhandler
    
    Call ItemLine_Clear
    
    If Not EqualKeys(grd_items.SelectedKey(0), av_Key) Then
        If Not grd_items.SearchKey(True, av_Key) Then
            MsgBox ("Record not found!")
            Exit Sub
        End If
    End If
    
    Call ItemLine_LoadValues(av_Key)
    
    Call Item_UpdateUI(ArmScreenMode.smView)
    
    Exit Sub
errhandler:
    Call ErrorMessage("ItemLine_ViewInit")
End Sub

Private Sub ItemLine_DeleteInit(ByVal av_Key As Variant)
On Error GoTo errhandler
    
    Call ItemLine_Clear
    
    If Not EqualKeys(grd_items.SelectedKey(0), av_Key) Then
        If Not grd_items.SearchKey(True, av_Key) Then
            MsgBox ("Record not found!")
            Exit Sub
        End If
    End If
    
    Call ItemLine_LoadValues(av_Key)
    
    Call Item_UpdateUI(ArmScreenMode.smDelete)
    
    Exit Sub
errhandler:
    Call ErrorMessage("ItemLine_DeleteInit")
End Sub

Private Function ItemLine_Add() As Boolean
On Error GoTo errhandler
    ItemLine_Add = False
    If Not ItemLine_Check() Then
        Exit Function
    End If
    
    Call UpdateGridAfterAction(grd_items, "Add", Array(txt_DCII_Code.Text))
    
    ItemLine_Add = True
    Exit Function
errhandler:
    Call ErrorMessage("ItemLine_Add")
End Function

Private Function ItemLine_Update(Optional ByVal as_noUpdAction As String = "") As Boolean
On Error GoTo errhandler
    ItemLine_Update = False
    If Not ItemLine_Check() Then
        Exit Function
    End If
    
    If Not UpdateGridAfterAction(grd_items, "Upd", Array(txt_DCII_Code.Text), as_noUpdAction) Then
        Call MsgBox("Record not found for current filters! (" & txt_DCII_Code.Text & ")")
    End If
    
    ItemLine_Update = True
    Exit Function
errhandler:
    Call ErrorMessage("ItemLine_Update")
End Function

Private Function ItemLine_Delete() As Boolean
On Error GoTo errhandler
    ItemLine_Delete = False
    If MsgBox("Do you want to delete the record?", vbYesNo) <> vbYes Then
        Exit Function
    End If
    
    Call UpdateGridAfterAction(grd_items, "Del2", Array(txt_DCII_Code.Text))
    
    ItemLine_Delete = True
    Exit Function
errhandler:
    Call ErrorMessage("ItemLine_Delete")
End Function

Private Function EqualKeys(ByRef av_Key1 As Variant, av_Key2 As Variant) As Boolean
On Error GoTo errhandler
    Debug.Assert (IsArray(av_Key1))
    Debug.Assert (IsArray(av_Key2))
    
    EqualKeys = False
    If LBound(av_Key1) <> LBound(av_Key2) Then Exit Function
    If UBound(av_Key1) <> UBound(av_Key2) Then Exit Function
    
    Dim ll_i As Long
    For ll_i = LBound(av_Key1) To UBound(av_Key1)
        If av_Key1(ll_i) <> av_Key2(ll_i) Then Exit Function
    Next
    
    EqualKeys = True
    Exit Function
errhandler:
    Call ErrorHandler("EqualKeys")
End Function

Private Sub ItemLine_LoadValues(ByVal av_Key As Variant)
On Error GoTo errhandler

    If Not IsEmpty(av_Key) Then
        Debug.Assert (IsArray(av_Key))
        If grd_items.SelectedKey(0)(0) <> av_Key(0) Then
            If Not grd_items.SearchKey(True, av_Key) Then
                Exit Sub
            End If
        End If
        
        If Not SetCboKey(cbo_TRANS_Code, grd_items.SelectedLine(0, "TRANS_Code")) Then
            Call cbo_TRANS_Code.AddItem(Array(grd_items.SelectedLine(0, "TRANS_Code"), grd_items.SelectedLine(0, "TRANS_Name"), grd_items.SelectedLine(0, "DCII_Amount"), _
                                                grd_items.SelectedLine(0, "CARRIER_Name"), grd_items.SelectedLine(0, "Shipping_Date"), grd_items.SelectedLine(0, "CUSTN1"), _
                                                grd_items.SelectedLine(0, "Ship_To_Zip_Code"), grd_items.SelectedLine(0, "Ship_To_CT_Code"), grd_items.SelectedLine(0, "Ship_To_Address"), _
                                                grd_items.SelectedLine(0, "Quantity"), grd_items.SelectedLine(0, "UOM_code")), True)
        End If
        
        txt_DCII_Number.Text = grd_items.SelectedLine(0, "DCII_Number")
        txt_DCII_Code.Text = grd_items.SelectedLine(0, "DCII_Code")
        txt_DCII_Amount.Text = grd_items.SelectedLine(0, "DCII_Amount")
    
    Else
        ' load default values
        txt_DCII_Code.Text = "NEW"
        txt_DCII_Amount.Text = "0"
        
        ' calculate next item number based on data in the grid
        Dim ll_i As Long
        Dim ll_max_itemNb As Long
        Dim ll_akt_ItemNb  As Long
        
        ll_max_itemNb = 0
        For ll_i = 0 To grd_items.Rows - 1
            If isNumeric(grd_items.Data(ll_i, "DCII_Number")) Then
                ll_akt_ItemNb = grd_items.Data(ll_i, "DCII_Number")
                If ll_akt_ItemNb > ll_max_itemNb Then
                    ll_max_itemNb = ll_akt_ItemNb
                End If
            End If
        Next
        
        txt_DCII_Number.Text = Format(Int((ll_max_itemNb / 10)) + 1, "#00") + "0"
        
        
    End If
    
    Exit Sub
errhandler:
    Call ErrorHandler(Extender.Name & ".ItemLine_LoadValues")
End Sub

Private Sub Item_LoadValues(ByVal al_DCII_Code As Long)
On Error GoTo errhandler

Const C_REQ As String = "EXEC DC_Invoice_sel2 $DCII_Code$"

    If al_DCII_Code <> 0 Then

        Dim ll_Cursor As Long
        Dim ls_req As String
        
        ls_req = Replace(C_REQ, "$DCII_Code$", SQLNum(al_DCII_Code), , , vbTextCompare)
        
        ll_Cursor = OpenSQLSafe(mo_Db, ls_req, 1)
        
        txt_DCI_Code.Text = mo_Db.GetFields(ll_Cursor, "DCI_Code")
        txt_DCI_Number.Text = mo_Db.GetFields(ll_Cursor, "DCI_Number")
        Call SetCboKey(cbo_DC_Code, mo_Db.GetFields(ll_Cursor, "DC_Code"))
        Call SetCboKey(cbo_CARRIER_Code, mo_Db.GetFields(ll_Cursor, "CARRIER_Code"))
        Call SetCboKey(cbo_CURR_Code, mo_Db.GetFields(ll_Cursor, "CURR_Code"))
        
        cal_InvoiceDate.date_courte = Format(mo_Db.GetFields(ll_Cursor, "DCI_Date"), "dd\/mm\/yyyy")
        
        ml_iConcurrency = mo_Db.GetFields(ll_Cursor, "iConcurrency")
        
        Call mo_Db.Close(ll_Cursor)
        ll_Cursor = 0
    Else
        ' put default values for add
        txt_DCI_Code.Text = "NEW"
        ml_iConcurrency = 0
        
        cal_InvoiceDate.date_courte = Format(Now, "dd\/mm\/yyyy")
        
        If SetCboKey(cbo_DC_Code, ms_DC_Code) Then
            Call SetCboKey(cbo_CARRIER_Code, ms_Carrier_Code)
        End If
        
        
    End If

    Call Item_LoadGrid

    Exit Sub
errhandler:
    If ll_Cursor > 0 Then
        Call mo_Db.Close(ll_Cursor)
        ll_Cursor = 0
    End If
    Call ErrorHandler(Extender.Name & ".Item_LoadValues")
End Sub


'*********************************** support functions ******************************************
' display standard error message
Private Sub ErrorMessage(ByVal as_Fct As String)
    Dim ls_ErrSource As String
    Dim ls_errDescription As String
    Dim ls_Message As String
    
    ls_ErrSource = as_Fct & SEP1 & Err.Source
    ls_errDescription = Err.Description
    ls_Message = SCREEN_NAME & " exception. Nr:" & Err.Number & ",Desc: " & ls_errDescription & ",Src:" & ls_ErrSource & "@"
'    Call mo_Tools.LogMessage(mo_Db, ml_U_Code, SCREEN_NAME, ls_Message, "E")
    Call MsgBox("Error occured, please contact IT. Application will now shutdown." & vbCrLf & ls_ErrSource & vbCrLf & "Description: " & ls_errDescription, vbCritical, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
    End
End Sub

Private Sub EnableControl(ByVal ao_Control As Control, ByVal ab_Enabled As Boolean)
On Error GoTo errhandler

    Select Case UCase(TypeName(ao_Control))
        Case "FRAME", "LABEL", "MSFLEXGRID", "SHAPE", "ARMGRID", "ARMCHECKVIEW", "TABSTRIP"
            ao_Control.Enabled = ab_Enabled
            ' Do nothing !
        Case "LISTVIEW"
            ' Do nothing !
        Case "TEXTBOX"
            ao_Control.Locked = Not ab_Enabled
            ao_Control.BackColor = IIf(ab_Enabled, CL_COLOR_ENABLED, CL_COLOR_DISABLED)
            ao_Control.TabStop = ab_Enabled
        Case "OPTIONBUTTON"
            ao_Control.Enabled = ab_Enabled
        Case "ARMCOMBOBOX", "A_CALOCX", "OPTIONBUTTON", "ARMTREEVIEW", "LISTBOX", "PICTUREBOX", "CHECKBOX", "COMMANDBUTTON", "TOOLBARCONTROL"
            ao_Control.Enabled = ab_Enabled
            ao_Control.TabStop = ab_Enabled
        Case Else
          Debug.Print ao_Control.Name
    End Select
  Exit Sub
errhandler:
  Call ErrorHandler("EnableControl")
End Sub

Private Sub SetEnabled(ByVal ao_srcCtrl As Object, ByVal ab_Value As Boolean)
On Error GoTo errhandler
    Dim lo_ctrl As Object
    For Each lo_ctrl In ao_srcCtrl
        Call EnableControl(lo_ctrl, ab_Value)
    Next
    Exit Sub
errhandler:
     Call ErrorHandler("SetEnabled()")
End Sub


' translate string to sql format
' Params:
' as_Value (String)
' ab_EmptyNULL (Boolean = False)
Private Function SqlStr(ByVal as_Value As String, Optional ByVal al_MaxLen As Long = 8000, Optional ByVal ab_EmptyNULL As Boolean = False) As String
    If as_Value = "" And ab_EmptyNULL Then
        SqlStr = "NULL"
    Else
        SqlStr = "'" & Replace(Left(as_Value, IIf(Len(as_Value) <= al_MaxLen, Len(as_Value), al_MaxLen)), "'", "''") & "'"
    End If
End Function

Private Function SqlDate(ByVal av_Data As String) As String
On Error GoTo errhandler

    SqlDate = "NULL"
    If IsNull(av_Data) Then av_Data = ""
    If (Trim(CStr(av_Data)) <> "") And (CStr(av_Data) <> "0") Then
        SqlDate = "'" & Format(av_Data, "yyyy-mm-dd") & "'"
    End If
    Exit Function
errhandler:
End Function


Private Function SQLNum(ByVal as_str As String, Optional ByVal ab_zeroIsNULL As Boolean = False) As String
    If ab_zeroIsNULL And Val(as_str) = 0 Then
        SQLNum = "NULL"
    Else
        SQLNum = Replace(as_str, ",", ".")
    End If
End Function

Private Function GetCboKey(ByRef ao_cbo As ArmCombobox) As String
On Error GoTo errhandler
    GetCboKey = ""
    If Not ao_cbo.SelectedItem Is Nothing Then
        GetCboKey = ao_cbo.SelectedItem.Key
    End If
    Exit Function
errhandler:
     Call ErrorHandler("GetCboKey()")
End Function

Private Function GetCboText(ByRef ao_cbo As ArmCombobox) As String
On Error GoTo errhandler
    GetCboText = ""
    If Not ao_cbo.SelectedItem Is Nothing Then
        GetCboText = ao_cbo.SelectedItem.DisplayText
    End If
    Exit Function
errhandler:
     Call ErrorHandler("GetCboText()")
End Function

Private Function GetCboValue(ByRef ao_cbo As ArmCombobox, ByVal av_field As Variant) As String
On Error GoTo errhandler
    GetCboValue = ""
    If Not ao_cbo.SelectedItem Is Nothing Then
        GetCboValue = ao_cbo.GetItemData(ao_cbo.SelectedItem.Key, av_field)
    End If
    Exit Function
errhandler:
     Call ErrorHandler("GetCboValue()")
End Function

Private Function SetCboKey(ByRef ao_cbo As ArmCombobox, ByVal as_Key As String) As Boolean
On Error GoTo ErrorHandler
    SetCboKey = True
    If Not ao_cbo.SearchItem(as_Key) Then
        Call ao_cbo.Load
        SetCboKey = ao_cbo.SearchItem(as_Key)
    End If
    Exit Function
ErrorHandler:
    Call ErrorHandler(Extender.Name & ".SetCboKey")
End Function
' Sets combobox selected item
' Params:
' ao_ComboBox (ArmCombobox)
' as_Key (String)
' as_Desc (String)
Private Sub SetComboBoxText(ByRef ao_Combobox As ArmCombobox, ByVal as_Key As String, ByVal as_desc As String)
On Error GoTo errhandler
    If Not ao_Combobox.SearchItem(as_Key) Then
        ' key not found ... set value from parameter
        If as_Key = "" Or as_Key = "0" Then     ' zero or empty string is not valid key
            Set ao_Combobox.SelectedItem = Nothing
        Else
            Call ao_Combobox.AddItem(Array(as_Key, as_desc), True)
            ' to make vb raise event
            Call ao_Combobox.SearchItem(as_Key)
        End If
    End If
    Exit Sub
errhandler:
    Call ErrorHandler("SetComboBoxText")
End Sub

Private Sub LockScreen(ByVal ab_lock As Boolean)

    Dim ll_errNumber As Long, ls_ErrSrc As String, ls_ErrDesc As String
    ll_errNumber = Err.Number
    ls_ErrSrc = Err.Source
    ls_ErrDesc = Err.Description

On Error GoTo errhandler
    Static ll_Count As Long
    Static ll_Mousepointer As Long
    Static lb_Locked As Boolean
      
      
    ll_Count = ll_Count + IIf(ab_lock, 1, -1)
    Debug.Assert (ll_Count >= 0)
    
    ' First lock
    If Not lb_Locked And ab_lock Then
        ll_Mousepointer = Screen.MousePointer
        Screen.MousePointer = vbHourglass
        LockWindowUpdate UserControl.hwnd
        lb_Locked = True
    End If
    
    ' Unlock
    If ll_Count = 0 Then
        DoEvents ' Flush events
        LockWindowUpdate 0
        UserControl.Refresh
        Screen.MousePointer = ll_Mousepointer
        lb_Locked = False
    End If
    
    Err.Number = ll_errNumber
    Err.Source = ls_ErrSrc
    Err.Description = ls_ErrDesc
    
    Exit Sub
    
errhandler:
    Call ErrorHandler("LockScreen")
End Sub

Private Function OpenSQLSafe(ByVal ao_Db As ARMSYSCOMLib.ArmDb, ByVal as_Request As String, Optional ByVal al_RowExpectedCount = -1) As Long
On Error GoTo errhandler
    Dim lc_Data As Long
    lc_Data = ao_Db.OpenSQL(as_Request)
    If lc_Data = 0 Then
        Err.Raise ArmErr.SQLFailure, "SQL : " & as_Request, Join(ao_Db.SQLErrorCodes, SEP2) & SEP1 & Join(ao_Db.SQLErrorMessages, SEP2)
    End If
    
    If al_RowExpectedCount <> -1 Then
        ' Then check the rowcount
        If ao_Db.RowCount(lc_Data) <> al_RowExpectedCount Then
            Err.Raise ArmErr.SQLBadRowExpectedCount, "SQL : " & as_Request, al_RowExpectedCount & "<>" & ao_Db.RowCount(lc_Data)
        End If
    End If
    OpenSQLSafe = lc_Data
    Exit Function
errhandler:
    Call ErrorHandler("OpenSQLSafe")
End Function

Private Sub ExecuteSQLSafe(ByVal ao_Db As ARMSYSCOMLib.ArmDb, ByVal as_Request As String, Optional ByVal al_RowAffectedCount = -1, Optional ab_DuplicityCheck As Boolean = False)
On Error GoTo errhandler

    ' First execute the request
    If Not ao_Db.ExecuteSQL(as_Request) Then
        If GetArrayValue(ao_Db.SQLErrorCodes, 0) = 547 Then
            Err.Raise ArmErr.SQLTableReferenceConstraint, "SQL : " & as_Request, Join(ao_Db.SQLErrorCodes, SEP2) & SEP1 & Join(ao_Db.SQLErrorMessages, SEP2)
        End If
        Err.Raise ArmErr.SQLFailure, "SQL : " & as_Request, Join(ao_Db.SQLErrorCodes, SEP2) & SEP1 & Join(ao_Db.SQLErrorMessages, SEP2)
    End If

    If al_RowAffectedCount <> -1 Then
        ' Then check the rowcount
        If ao_Db.SQLRowsAffected <> al_RowAffectedCount Then
            
            If ab_DuplicityCheck Then
                Err.Raise ArmErr.DuplicityDetected, "SQL : " & as_Request, al_RowAffectedCount & "<>" & ao_Db.SQLRowsAffected
            Else
                Err.Raise ArmErr.SQLBadRowAffectedCount, "SQL : " & as_Request, al_RowAffectedCount & "<>" & ao_Db.SQLRowsAffected
            End If
        End If
    End If
    
    Exit Sub

errhandler:
    Call ErrorHandler("ExecuteSQLSafe")
End Sub

Private Function GetDbError(ByVal lo_Db As ARMSYSCOMLib.ArmDb) As String
On Error GoTo errhandler
    If IsArray(lo_Db.SQLErrorMessages) Then
        Debug.Assert (IsArray(lo_Db.SQLErrorCodes))
        ' Display errors msgBox
        GetDbError = Join(lo_Db.SQLErrorCodes, ",") & vbCrLf & Join(lo_Db.SQLErrorMessages, vbCrLf)
    Else
        ' ExecuteSQL failed but no error message?
        GetDbError = "Unknown error"
    End If
    Exit Function
errhandler:
    Call ErrorHandler("GetDbError()")
End Function

Private Function GetArrayValue(ByRef ao_variantArray As Variant, ByVal al_Index As Long) As Variant
    If IsArray(ao_variantArray) Then
        If UBound(ao_variantArray) <= al_Index Then
            GetArrayValue = ao_variantArray(al_Index)
        Else
            GetArrayValue = 0
        End If
    Else
        GetArrayValue = 0
    End If
End Function

Private Sub cal_InvoiceDate_changeposition(y As Integer)
    cal_InvoiceDate.Zorder
    cal_InvoiceDate.Top = cal_InvoiceDate.Top + y
End Sub

Private Sub cbo_CARRIER_Code_ComboItemSelected()
On Error GoTo errhandler

Const C_REQ As String = "EXEC DC_Invoice_Transaction_cbo $DC_CARRIER_Code$, $TT_Code$"

    ' refresh transactions
    If GetCboKey(cbo_CARRIER_Code) = "" Then
        cbo_TRANS_Code.Request = ""
        Set cbo_TRANS_Code.SelectedItem = Nothing
    Else
        cbo_TRANS_Code.Request = Item_ReplacePlaceholders(C_REQ)
    End If
    
    Exit Sub
errhandler:
     Call ErrorMessage("cbo_CARRIER_Code_ComboItemSelected()")
End Sub


Private Sub cbo_DC_Code_ComboItemSelected()
On Error GoTo errhandler

    Dim ls_oldCarrier As String
    ls_oldCarrier = GetCboKey(cbo_CARRIER_Code)

    Call cbo_CARRIER_Code.Clear
    Set cbo_CARRIER_Code.SelectedItem = Nothing
    
    cbo_TRANS_Code.Request = ""
    Set cbo_TRANS_Code.SelectedItem = Nothing
    
    Dim ls_DC_Code As String
    ls_DC_Code = GetCboKey(cbo_DC_Code)
    
    If ls_DC_Code = "" Then
        cbo_CARRIER_Code.Request = ""
    Else
        cbo_CARRIER_Code.Request = Replace(C_REQ_CARRIER, "$DC_CODE$", SqlStr(ls_DC_Code, 4, True))
        
        If ls_oldCarrier <> "" Then
            Call SetCboKey(cbo_CARRIER_Code, ls_oldCarrier)
        End If
    End If
    
    ' secrh for currency in combobox
    Dim ls_CURR_Code As String
    ls_CURR_Code = GetCboValue(cbo_DC_Code, "CURR_Code")
    
    If ls_CURR_Code = "" Then
        cbo_CURR_Code.Clear
    Else
        Call SetCboKey(cbo_CURR_Code, ls_CURR_Code)
    End If
    
    Exit Sub
errhandler:
     Call ErrorMessage("cbo_DC_Code_ComboItemSelected()")
End Sub

Private Sub cbo_TRANS_Code_ComboItemSelected()
On Error GoTo errhandler
    If mb_eventRunning Then Exit Sub
    
    If Val(txt_DCII_Amount.Text) = 0 Then
        txt_DCII_Amount.Text = GetCboValue(cbo_TRANS_Code, "DC_Cost")
    End If
    Exit Sub
errhandler:
     Call ErrorMessage("cbo_TRANS_Code_ComboItemSelected()")
End Sub


Private Sub grd_items_SelChange()
On Error GoTo errhandler
    If grd_items.SelectedCount = 0 Then Exit Sub
    
    Call LockScreen(True)
    
    Call ItemLine_ViewInit(grd_items.SelectedKey(0))
    
    Call LockScreen(False)
    Exit Sub
errhandler:
    Call LockScreen(False)
    Call ErrorMessage("grd_items_SelChange()")
End Sub


Private Function SearchGridSafe(ByRef ao_grid As ArmGrid, ByVal av_Key As Variant)
On Error GoTo errhandler
    SearchGridSafe = False
    
    If ao_grid.SearchKey(False, av_Key) Then
        SearchGridSafe = True
        Exit Function
    End If

    SearchGridSafe = ao_grid.SearchKey(True, av_Key)
    
    Exit Function
errhandler:
    Call ErrorHandler("SearchGridSafe()")
End Function

Private Sub tlb_Item_action(ByVal as_Role As String, as_Language As String)
On Error GoTo errhandler
    Call LockScreen(True)
    mb_eventRunning = True

    Select Case as_Role
    Case "A"
        Call ItemLine_AddInit
    Case "B", "I"       ' Update, refresh detail
        If mu_Item_ActiveMode = smAdd Then
            Call ItemLine_AddInit
        ElseIf (mu_Item_ActiveMode = smView) Or (mu_Item_ActiveMode = smMain) Or (mu_Item_ActiveMode = smUpdate) Then
            If grd_items.SelectedCount > 0 Then
                Call ItemLine_UpdateInit(grd_items.SelectedKey(0))
            Else
                Call SendMessage(2404, "#Please select a row.", ms_Language_Code, vbOKOnly)
            End If
        End If
    Case "C"
        If grd_items.SelectedCount > 0 Then
            Call ItemLine_DeleteInit(grd_items.SelectedKey(0))
        Else
            Call SendMessage(2404, "#Please select a row.", ms_Language_Code, vbOKOnly)
        End If
    Case "J"
        If grd_items.PreviousLine Then
            Call grd_items_SelChange
        End If
    Case "K"
        If grd_items.NextLine Then
            Call grd_items_SelChange
        End If
    Case "F"        ' refresh grid
        Call grd_items.Refresh
        
        Call Item_UpdateUI(smMain)
    Case "H"
        If mu_Item_ActiveMode = smAdd Then
            If ItemLine_Add Then
                Call Item_UpdateUI(ArmScreenMode.smView)
            End If
        ElseIf mu_Item_ActiveMode = smUpdate Then
            If ItemLine_Update Then
                Call Item_UpdateUI(ArmScreenMode.smView)
            End If
        ElseIf mu_Item_ActiveMode = smDelete Then
            If ItemLine_Delete Then
                Call Item_UpdateUI(ArmScreenMode.smMain)
            End If
        End If
    Case "T"
        Call Item_UpdateUI(ArmScreenMode.smMain)
        
    End Select

    Call LockScreen(False)
    mb_eventRunning = False
    Exit Sub
errhandler:
    Call LockScreen(False)
    mb_eventRunning = False
    Call ErrorMessage("tlb_item_action")
End Sub

Private Function MsgText(ByVal aID As Long, ByVal aLang As String, ByVal aDefault As String, Optional ByVal aInfo As Variant) As String
On Error GoTo errhandler

Const DB_REQ As String = "SELECT message_text FROM error_message WHERE msgid = $id$ AND Language_code = '$lang$'"

    MsgText = ""
    
    Dim lRequest As String
    lRequest = Replace(DB_REQ, "$id$", aID, , , vbTextCompare)
    lRequest = Replace(lRequest, "$lang$", aLang, , , vbTextCompare)
    Dim lData As Long
    
    lData = OpenSQLSafe(mo_Db, lRequest)
    
    Dim lBuffer As String
    lBuffer = mo_Db.GetFields(lData, "message_text")
    mo_Db.Close (lData)
    If lBuffer = "" Then lBuffer = aDefault
    
    Dim li_idx As Integer
    If Not IsMissing(aInfo) Then
        For li_idx = 0 To UBound(aInfo)
            lBuffer = Replace(lBuffer, aInfo(li_idx, 0), aInfo(li_idx, 1), , , vbTextCompare)
        Next li_idx
    End If
    
    
    MsgText = lBuffer
    Exit Function
errhandler:
    mo_Db.Close (lData)
    Call MsgBox("Connection failure accessing message information.")
    MsgText = aDefault
End Function

' Load the labels of a containers
Private Sub LoadLabels(ByRef aControls As Variant, ByVal as_ScreenName As String, ByVal as_Language As String)

On Error GoTo errhandler

    Dim lIdx As Long, lCount As Long, lLabels As Long
    Dim lControl As Control

    lLabels = OpenSQLSafe(mo_Db, "exec Screen_Csts '" & as_ScreenName & "','" & as_Language & "'")
    Debug.Assert (lLabels <> 0)
    
    lCount = aControls.Count - 1
    
    For lIdx = 0 To lCount
        Set lControl = aControls.Item(lIdx)
            Select Case UCase(TypeName(lControl))
                Case "LABEL", "FRAME", "COMMANDBUTTON", "OPTIONBUTTON", "MENU", "CHECKBOX"
                    If lControl.Tag <> "" Then
                        If mo_Db.Find(lLabels, "FIELD_NAME", lControl.Tag, , 1) >= 0 Then
                            lControl.Caption = mo_Db.GetFields(lLabels, "LOCAL_TEXT")
                        End If
                        ' once translation is done and control is not in array CLEAR tag
                        If Not TypeOf lControl Is Frame And Not TypeOf lControl Is Label Then
                            lControl.Tag = ""
                        End If
                    End If
                Case "ARMGRID"
                    If mo_Db.Find(lLabels, "FIELD_NAME", lControl.Tag, , 1) >= 0 Then
                      Call lControl.LoadConstants(ptStatic, mo_Db.GetFields(lLabels, "LOCAL_TEXT"), ctColumns)
                        End If
                    If mo_Db.Find(lLabels, "FIELD_NAME", lControl.Tag & "_Title", , 1) >= 0 Then
                      lControl.Title = mo_Db.GetFields(lLabels, "LOCAL_TEXT")
                    End If
                Case "TABSTRIP"
                    If mo_Db.Find(lLabels, "FIELD_NAME", lControl.Tag, , 1) >= 0 Then
                        Dim lsa_TextArr() As String
                        Dim ll_Index As Long
                        
                        lsa_TextArr = Split(mo_Db.GetFields(lLabels, "LOCAL_TEXT"), SEP)
                        
                        For ll_Index = LBound(lsa_TextArr, 1) To UBound(lsa_TextArr, 1)
                            lControl.Tabs(ll_Index + 1).Caption = lsa_TextArr(ll_Index)
                        Next
                    End If
                    ' once translation is done and control is not in array CLEAR tag
                    lControl.Tag = ""
                Case "MSFLEXGRID", "TOOLBARCONTROL", "TEXTBOX", "ARMCHECKVIEW", "ARMCOMBOBOX", "A_CALOCX", "OPTIONBUTTON", "ARMTREEVIEW", "LISTBOX", "PICTUREBOX", "TOOLBR", "SPINBUTTON"
                    ' Do nothing !
                Case Else
                    'debug.print "LoadLabels " & UCase(TypeName(lControl))
            End Select
        Set lControl = Nothing
    Next
    
    Call mo_Db.Close(lLabels)
    lLabels = 0

    Exit Sub

errhandler:
    If lLabels > 0 Then
        Call mo_Db.Close(lLabels)
    End If
    Call ErrorHandler(Extender.Name & ".LoadLabels")
End Sub


Private Sub ChangeCharset(ByRef ao_Container As Object, Optional ByVal aCodePage As Long)
On Error GoTo errhandler
   
    Dim lc_Control As Control
    Dim ll_Charset As Long
    
    On Error Resume Next
    ll_Charset = GetCharSetFromCodePage(aCodePage)
    
    For Each lc_Control In ao_Container
        Select Case UCase(TypeName(lc_Control))
        Case "TABSTRIP", "TEXTBOX", "LABEL", "FRAME", "COMMANDBUTTON", _
              "LISTVIEW", "CHECKBOX", "OPTIONBUTTON", _
              "ARMCHECKVIEW", "ARMTREEVIEW", "ARMGRID", "ARMCOMBOBOX", "ARMCHECKVIEW0"
            lc_Control.Font.Name = "Arial"
            lc_Control.Font.Charset = ll_Charset
        Case "A_SEEK", "A_SRCHTXT"
            lc_Control.Charset = ll_Charset
        End Select
    Next
    
    Exit Sub

errhandler:
    Call ErrorHandler(Extender.Name & ".ChangeCharset")
End Sub

Private Function GetNextRecordID(ByVal as_ID As String) As Long
On Error GoTo errhandler
    
    Dim ls_retVal As String
    ls_retVal = mo_Db.SQLNextID(as_ID)
    If ls_retVal = "" Then
        Call Err.Raise(666, "SQLNextID", "Missing A_ID for '" & as_ID & "'")
    End If
    
    GetNextRecordID = ls_retVal
    Exit Function
errhandler:
    Call ErrorHandler(Extender.Name & ".GetNextRecordID")
End Function

Private Function BeginTran(as_Tran As String) As Boolean

On Error GoTo errhandler
    BeginTran = False
    
    If ms_inTranName <> "" Then
        MsgBox ("Already in transaction!!!!! " & ms_inTranName)
        Exit Function
    End If
    
    ExecuteSQLSafe mo_Db, "BEGIN TRANSACTION " & as_Tran
    
    ms_inTranName = as_Tran

    BeginTran = True
    Exit Function
    
errhandler:
    'try to log error
'    Call LogMessage("BeginTran: " & as_Tran)
    Call mo_Db.Disconnect
    Set mo_Db = Nothing
    MsgBox "A Fatal error occured in " & SCREEN_NAME & ".BeginTran, your application will be close. Please contact your IT support", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End
End Function

Private Function CommitTran(as_Tran As String) As Boolean

On Error GoTo errhandler
    CommitTran = False
    
    If ms_inTranName <> as_Tran Then
        Call MsgBox("Warning!!! Commit transaction name does not match!!! " & as_Tran & "<>" & ms_inTranName, vbCritical)
    End If
    
    ExecuteSQLSafe mo_Db, "COMMIT TRANSACTION " & as_Tran

    ms_inTranName = ""
    CommitTran = True
    Exit Function
    
errhandler:
    'try to log error
'    Call LogMessage("CommitTran: " & as_Tran)
    Call mo_Db.Disconnect
    Set mo_Db = Nothing
    MsgBox "A Fatal error occured in " & SCREEN_NAME & ".CommitTran, your application will be close. Please contact your IT support", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End

End Function

Private Function RollbackTran(as_Tran As String) As Boolean
    
    Dim ll_errNumber As Long, ls_ErrSource As String, ls_ErrDesc As String
    ll_errNumber = Err.Number
    ls_ErrSource = Err.Source
    ls_ErrDesc = Err.Description

On Error GoTo errhandler
    RollbackTran = False
    
    If ms_inTranName <> as_Tran Then
        Call MsgBox("Warning!!! Rollback transaction name does not match!!! " & as_Tran & "<>" & ms_inTranName, vbCritical)
    End If
    
    ExecuteSQLSafe mo_Db, "ROLLBACK TRANSACTION " & as_Tran
    ms_inTranName = ""


    Err.Number = ll_errNumber
    Err.Source = ls_ErrSource
    Err.Description = ls_ErrDesc

    RollbackTran = True
    Exit Function
    
errhandler:
    'try to log error
'    Call LogMessage("RollbackTran: " & as_Tran)
    Call mo_Db.Disconnect
    Set mo_Db = Nothing
    MsgBox "A Fatal error occured in " & SCREEN_NAME & ".RollbackTran, your application will be close. Please contact your IT support", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End
End Function

