Invalid Use Of Null

Тема в разделе "Lotus - Программирование", создана пользователем beloff, 9 авг 2012.

  1. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    Опять завелся какой то демон. Проблема кроется в том что скрипт написан на кнопку в форме, которая вызывается диалогбоксом, т.е. посмотреть дебагером не получится (кроме предпросмотра непосредственно этой формы из дизайнера вызвать её в клиент, но это не вариант, т.к. куча данных берется непосредственно из документа). Ситуация: БД персонал, оформление отпусков, попытка оформить новый отпуск вызывает ошибку invalid use of null в строке
    ItemNumTmp = Arraygetindex(vArrCur, Cdat(vDatePeriod0)).
    Я так понял что гемор именно с этой функцией (Arraygetindex), т.к. работает она через пень-колоду (встречал в нете). Смысл функции - взять индекс
    выбранной даты в массиве, т.к. у человека который работает не первый год может быть куча отпускных периодов и нужно как-то оперировать с данными в массивах с этим индексом. Дополнительная проблема - не выявлена закономерность, т.к. на некоторых работает, на некоторых отказывается, на некоторых сначала отказывается, потом ни с того, ни с сего работает. Ломаю голову уже 3-й день. Может, переписать скрипт вставив вместо этой долбаной функции обычный цикл сравнения одного значения с каждым элементом массива. Вобщем, СОС, ай нид хэлп


    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">скрипт на кнопке</div></div><div class="sp-body"><div class="sp-content">Sub OnAcceptChanges(Byval bNew As Boolean)
    Dim StrTmp As String
    Dim vNames(0 To 10) As String
    Dim ItemNum As Long, i As Long, j As Long, k As Long
    Dim vIndex As Variant, vArrCur As Variant, vArrCurCopy As Variant
    Dim vDate0 As Variant, vDate1 As Variant
    Dim vDatePeriod0 As Variant, vDatePeriod1 As Variant
    Dim VacationLen As Long, ItemNumTmp As Long
    Dim bRedim As Boolean, bCompens As Boolean

    Dim ThisDoc As NotesDocument
    Dim Wks As New NotesUIWorkspace

    'On Error Goto errmsg

    Call Wks.CurrentDocument.Refresh
    Set ThisDoc = Wks.CurrentDocument.Document

    '// Проверка полей, обязательных для заполнения
    Dim str_listfields List As String

    StrTmp = Lcase$(Wks.CurrentDocument.FieldGetText("VacKind"))
    str_listfields("VacKind") = "Вид отпуска"

    If StrTmp Like "*компенсац*" And Wks.CurrentDocument.FieldGetText("VacType")="Трудовой" Then
    bCompens = True
    Else
    bCompens = False
    str_listfields("VacBegin") = "Дата начала отпуска"
    str_listfields("VacEnd") = "Дата окончания отпуска"
    End If

    If Lib_CheckMandatoryFields(Wks.CurrentDocument, str_listfields) = False Then Exit Sub

    If ThisDoc.HideOrder(0) = "1" Then
    vArrCur = ThisDoc.RC_VacType
    If vArrCur(0) <> "" And Wks.CurrentDocument.FieldGetText("VacType") <> vArrCur(0) Then
    Messagebox "Не допустимо предоставление и трудового и социального отпусков в одной записке.", 16, "Отпуск"
    Exit Sub
    End If
    End If

    If Not bCompens Then
    vDate0 = Cdat(ThisDoc.GetItemValue("VacBegin")(0))
    vDate1 = Cdat(ThisDoc.GetItemValue("VacEnd")(0))
    End If

    StrTmp = Wks.CurrentDocument.FieldGetText("VacLen")
    If StrTmp <> "" And Not Isnumeric(StrTmp) Then
    Messagebox "Неверно указана продолжительность отпуска.", 16, "Ошибка ввода"
    Exit Sub
    Elseif StrTmp = "" And Not bCompens Then
    If Cdat(vDate1) >= Cdat(vDate0) Then
    StrTmp = Cstr(vDate1 - vDate0)
    Call ThisDoc.ReplaceItemValue("VacLen", StrTmp)
    End If
    End If

    If Wks.CurrentDocument.FieldGetText("VacType") = "Трудовой" Then
    If StrTmp = "" Then
    Messagebox "Не задана продолжительность трудового отпуска.", 16, "Ошибка ввода"
    Exit Sub
    End If
    i = Clng(StrTmp)
    StrTmp = Wks.CurrentDocument.FieldGetText("VacPeriod")
    If StrTmp = "" Or StrTmp = "-" Then
    Messagebox "Не задан период трудового отпуска.", 16, "Ошибка ввода"
    Exit Sub
    End If
    vDatePeriod0 = Cdat(Fulltrim(Strleft(StrTmp, "-")))
    vDatePeriod1 = Cdat(Fulltrim(Strright(StrTmp, "-")))
    If Not bCompens Then
    If Cdat(vDate0)+i-1 > Cdat(vDate1) Then
    Messagebox "Даты начала и окончания отпуска не согласуются с продолжительностью.", 16, "Ошибка ввода"
    Exit Sub
    End If
    End If

    VacationLen = i
    vArrCur = ThisDoc.GetItemValue("RC_VacPeriodStart")
    ItemNumTmp = Arraygetindex(vArrCur, Cdat(vDatePeriod0))
    End If

    ' имена полей
    vNames(0) = "Indexes"
    vNames(1) = "RC_VacKind"
    vNames(2) = "RC_VacType"
    vNames(3) = "RC_VacPeriod"
    vNames(4) = "RC_VacLen"
    vNames(5) = "RC_VacBegin"
    vNames(6) = "RC_VacEnd"
    vNames(7) = "RC_VacOrder"
    vNames(8) = "RC_VacCache"
    vNames(9) = "RC_VacNotes"
    vNames(10) = "RC_VacFlags"

    ' Определение номера текущей записи (редактирование/добавление), 0 - новая запись
    StrTmp = Cstr(ThisDoc.GetItemValue("CurItem")(0))
    If Not Isnumeric(StrTmp) Then ItemNum = 0 Else ItemNum = Clng(StrTmp)
    If bNew Then ItemNum = 0

    vIndex = ThisDoc.GetItemValue("Indexes")
    If vIndex(0) <> "" And Not bCompens Then
    vDatePeriod0 = ThisDoc.GetItemValue("RC_VacBegin")
    vDatePeriod1 = ThisDoc.GetItemValue("RC_VacEnd")
    For i = 0 To Ubound(vIndex)
    If Isdate(vDatePeriod0(i)) And Isdate(vDatePeriod1(i)) Then
    If (ItemNum-1) <> i And Not (Cdat(vDate1) < Cdat(vDatePeriod0(i)) Or Cdat(vDate0) > Cdat(vDatePeriod1(i))) Then
    Messagebox "Заданный период пересекается с существующим: "+_
    Format$(vDatePeriod0(i), "dd.mm.yyyy")+" - "+Format$(vDatePeriod1(i), "dd.mm.yyyy")+Chr$(10)+_
    "( № "+Cstr(i+1)+" в списке )", 16, "Ошибка ввода"
    Exit Sub
    End If
    End If
    Next i
    End If

    If ItemNum = 0 Then
    'Добавление новой записи
    bNew = True
    If vIndex(0) <> "" Then
    bRedim = True
    ItemNum = Ubound(vIndex)+1
    Else
    bRedim = False
    End If
    Else
    bNew = False
    bRedim = False
    ItemNum = ItemNum-1
    End If

    For i = 0 To Ubound(vNames)
    vArrCur = ThisDoc.GetItemValue(vNames(i))
    If bRedim Then Redim Preserve vArrCur(0 To ItemNum)
    If vNames(i) = "Indexes" Then
    vArrCur(ItemNum) = Cstr(ItemNum+1)
    Elseif vNames(i) = "RC_VacBegin" Or vNames(i) = "RC_VacEnd" Then
    If bCompens Then
    vArrCur(ItemNum) = "-"
    Else
    vArrCur(ItemNum) = Format(ThisDoc.GetItemValue(Strright(vNames(i), "_"))(0), "dd.mm.yyyy")
    End If
    Else
    StrTmp = ThisDoc.GetItemValue(Strright(vNames(i), "_"))(0)
    If StrTmp = "" Then StrTmp = "-"
    vArrCur(ItemNum) = StrTmp
    End If
    Call ThisDoc.ReplaceItemValue(vNames(i), vArrCur)
    Next i
    vIndex = ThisDoc.GetItemValue("Indexes")
    Call ThisDoc.ReplaceItemValue("CurItem", vIndex(ItemNum))

    If VacationLen <> 0 Then
    Dim OldLen As Long

    If Not bNew And Isnumeric(ThisDoc.GetItemValue("VacLen0")(0)) Then
    OldLen = Clng(ThisDoc.GetItemValue("VacLen0")(0))
    Else
    OldLen = 0
    End If
    VacationLen = VacationLen - OldLen
    If VacationLen <> 0 Then
    vArrCur = GetFieldNumArray(ThisDoc, "RC_VacPeriodUsed")
    vArrCur(ItemNumTmp) = vArrCur(ItemNumTmp)+VacationLen
    If vArrCur(ItemNumTmp) < 0 Then ' неверные данные ?
    vArrCur(ItemNumTmp) = 0
    VacationLen = VacationLen + vArrCur(ItemNumTmp) ' correct delta
    End If
    Call ThisDoc.ReplaceItemValue("RC_VacPeriodUsed", vArrCur)
    vArrCur = GetFieldNumArray(ThisDoc, "RC_VacPeriodUnused")
    vArrCur(ItemNumTmp) = vArrCur(ItemNumTmp)-VacationLen
    If vArrCur(ItemNumTmp) < 0 Then vArrCur(ItemNumTmp) = 0
    Call ThisDoc.ReplaceItemValue("RC_VacPeriodUnused", vArrCur)
    Call ThisDoc.ReplaceItemValue("VacLen0", Clng(ThisDoc.VacLen(0)))
    End If
    End If

    ' Сортировка записей по дате
    vIndex = ThisDoc.GetItemValue("Indexes")
    If Ubound(vIndex) > 0 Then
    vArrCur = ThisDoc.GetItemValue("RC_VacBegin")
    vArrCurCopy = ThisDoc.GetItemValue("RC_VacPeriod")

    'Call DoInsertSortByDate(vArrCur, vIndex)
    Call DoInsertSortByDateAlt (vArrCur, vArrCurCopy, vIndex)

    Call ThisDoc.ReplaceItemValue("RC_VacBegin", vArrCur)
    For i = 1 To Ubound(vNames)
    If vNames(i) <> "RC_VacBegin" Then
    vArrCur = ThisDoc.GetItemValue(vNames(i))
    vArrCurCopy = vArrCur
    For k = 0 To Ubound(vIndex)
    j = Clng(vIndex(k))-1
    vArrCur(k) = vArrCurCopy(j)
    Next k
    Call ThisDoc.ReplaceItemValue(vNames(i), vArrCur)
    End If
    Next i
    For i = 0 To Ubound(vIndex)
    j = Clng(vIndex(i))-1
    If j = ItemNum Then ItemNumTmp = i
    vIndex(i) = Cstr(i+1)
    Next i
    ItemNum = ItemNumTmp
    Call ThisDoc.ReplaceItemValue("Indexes", vIndex)
    End If

    Call Wks.CurrentDocument.Refresh
    Call ThisDoc.ReplaceItemValue("RC_VacListDsp", ThisDoc.GetItemValue("RC_VacList")(ItemNum))

    'errmsg :
    ' Msgbox Erl()
    End Sub
     
  2. NickProstoNick

    NickProstoNick Статус как статус :)

    Регистрация:
    22 авг 2008
    Сообщения:
    1.766
    Симпатии:
    39
    как-то странно... у кнопки вроде нет такого события как OnAcceptChanges
    Ну это так... лирика...
    Диалог всегда можно обмануть.
    Например в форме диалога при открытии можно инициализировать документ по UNID... ну в общем варианты есть.
    Раз определил место ошибки - знач какой-то из твоих массивов пуст. Т.е. даже не инициализирован
     
  3. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Функция ArrayGetIndex работает прекрасно, надо "уметь готовить".
    Она возвращает Null, когда значения нет в массиве. Т.е. результат надо проверять на IsNull.

    Конкретно ваша ошибка в том, что переменная ItemNumTmp описана As Long, т.е. когда ArrayGetIndex возвращает Null этот самый Null загнать в Long невозможно. О чём, собственно, оно и пытается вам сказать.

    И ещё. Даты я бы не сравнивал со значениями в массиве (см. в хэлпе инфу по автоконвертации массива в стринги), а перегонял бы в строку - CStr.

    P.S. Дурной тон вываливать огромный скрипт, большая часть которого тут бесполезна; лучше порезать его, - 3-4 строчки для данного вопроса вполне достаточно.
     
  4. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    vArrCur = ThisDoc.GetItemValue("RC_VacPeriodStart")
    If Ubound(vArrCur) >0 then
    ItemNumTmp = Arraygetindex(vArrCur, Cdat(vDatePeriod0))
    Elseif ItemNumTmp = 0

    End If

    Teamstudio Analyzer
     
  5. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.051
    Симпатии:
    146
    beloff

    Сделай ItemNumTmp Variant'ом и проверяй на IsNull или:
    Код (LotusScript):
    dim k as variant
    k = Arraygetindex(vArrCur, Cdat(vDatePeriod0))
    if IsNull(k) then
    ItemNumTmp = 0
    else
    ItemNumTmp = k
    end if
     
  6. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    savl
    спасибо, мне как раз ночью это и приснилось. Чуть повыше практически то же самое и вписал. Все равно спасибо
     
  7. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    все равно что-то не то по сути. Проверка на isnull это просто попытка обойти проблему.

    Итак: массив берется и становится эквивалентным полю по размерности (vArrCur = ThisDoc.GetItemValue("RC_VacPeriodStart"))
    например в поле 6 значений (тип поля Time/Date List). В поле "RC_VacPeriodStart" следующие значения
    03.01.2008 01:00:00 ZE3
    26.01.2008 01:00:00 ZE3
    03.01.2009 01:00:00 ZE3
    03.01.2010 01:00:00 ZE3
    03.01.2011 00:00:00 ZE3
    03.01.2012 00:00:00 ZE3

    Спрашиваем msgbox'om значения каждого элемента массива и вот что он нам выдает (на каждый элемент массива перечисленный выше)
    03.01.2008
    26.01.2008
    03.01.2009
    03.01.2010
    02.01.2011 23:00:00
    02.01.2012 23:00:00

    я думаю теперь понятно почему он выдает NULL, т.к. я ищу значение 02.01.2012 в указанном массиве, а там такого естественно нету. Как я и думал тут какая-то херня с типами данных в массиве. Тут раньше был совет по поводу конвертации в String, только я ничего не понял (сорри за ламерство, у меня был большой перерыв в программинге на Лотусе, кое-что просто подзабыл)
     
  8. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    функция DateValue спасла
     
  9. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    проблема решена, всем спасибо
     
  10. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Ну и зачем? А "на подумать" что-то оставить?) Оно и так следует из моего сообщения. Тем более что приснилось) я иногда код тоже во сне пишу))

    Код (LotusScript):
    if IsNull(k) then
    ItemNumTmp = 0
    else
    ItemNumTmp = k
    end if
    ItemNumTmp = 0 логически неверно, т.к. тем самым мы говорим, что значение в массиве всё-таки есть, и находится в 0-м элементе.

    Если в массиве не будет значения, даже со всеми преобразованиями, то будет ошибка, потому в тему. Если не верите, можно оставить ItemNumTmp As Long :) Т.о. это первая часть проблемы.
    Спасибо, что отписались по 2-й, интересное наблюдение.
    DateValue делаем передаваемой строке в ArrayGetIndex или отказались от него и цикл с перебором по значениям item'а?
     
  11. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.051
    Симпатии:
    146
    VladSh
    про =0 согласен, лохонулся. Обычно пишу -1, тогда точно знаю, что элемента нет.
     
  12. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    VladSh
    перед поиском написал цикл чтобы перебором всех элементов в массиве каждый конвертировался в нормальную дату (т.е. через DateValue)

    vArrCur = ThisDoc.GetItemValue("RC_VacPeriodStart")
    For a = 0 To Ubound(vArrCur)
    'Msgbox vArrCur(a)
    vArrCur(a) = Datevalue(vArrCur(a))
    'Msgbox vArrCur(a)
    Next

    ItemNumTmp = Arraygetindex(vArrCur, Cdat(vDatePeriod0))
     
  13. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    beloff
    Я бы строку с GetItemValue и цикл заменил на
    Код (LotusScript):
    Const IN_DT = "RC_VacPeriodStart"
    arrDt = Evaluate({@Text(} + IN_DT + {; "D0T0")}, nd)
     
  14. beloff

    beloff Well-Known Member

    Регистрация:
    24 июл 2012
    Сообщения:
    103
    Симпатии:
    0
    мне еще далеко до таких глубин
     
Загрузка...

Поделиться этой страницей