Форма поиска банка Primer. Часть 5. Фильтрация записей

2022, Feb 21    

Это пятая статья из серии, посвященной описанию процесса разработки управляющей формы, предназначенной для отбора кандидатов на работу в демонстрационном банке кадрового агентства Primer.

Предыдущие статьи серии:

Часть 1. Готовим макет формы

Часть 2. Организуем контроль правильности ввода

Часть 3. Добавляем диалоговые окна

Часть 4. Диалоговое окно с деревом

В предыдущей части мы окончательно сформировали строчный запрос на отбор записей из базы “Лицо” с учетом ограничений на возраст, специальность по образованию, опыт работы и место проживания.

Сегодня выполним финальную работу по отбору: отфильтруем отобранный запросом набор записей с учетом ограничений по стажу работы на определенных должностях.

В общих чертах алгоритм нашей работы выглядит так:

  • перебрать полученный в результате выполнения запроса набор записей ЛЦ;
  • для каждой такой записи получить набор связанных с ней записей ТД, соответствующих критерию отбора на опыт работы, сохраненному нами в conditions.career;
  • для каждой записи из полученного набора ТД, подсчитать стаж работы как разницу между датой увольнения и датой начала работы;
  • просуммировать полученные временные интервалы и исключить из исходного набора ЛЦ записи, у которых результат ниже ограничения, указанного в поле experience таблицы conditions.

Прежде чем браться за реализацию данного алгоритма нам необходимо научиться вычислять временной интервал между датой начала работы и датой окончания для конкретной записи базы “Трудовая деятельность”.

Первая задача, которую нам необходимо при этом решить, - преобразовать значения полей типа “Дата”, которые являются строками в объекты типа DateTime, которые можно использовать в вычислениях. Вторая - научиться получать корректные значения DateTime для случаев, когда дата указана в сокращенном формате (00.00.ГГГГ) или не указана вовсе.

Будем придерживаться следующей стратегии:

  • записи, в которых не указана дата начала (явное нарушение ограничений целостности), не будем учитывать при подсчете;
  • если дата окончания не указана, ее следует принять равной текущей дате;
  • даты, превышающие текущую, также следует приравнивать к текущей;
  • дату начала работы, заданную в сокращенном формате следует принять равной дате начала соответствующего периода (месяца или года), дату окончания - равной максимальной дате в соответствующем периоде.

При таком подходе периоды работы, в которых не указана дата окончания, будут трактоваться как продолжающиеся по сей день, а периоды работы, в которых даты указаны сокращенно, будут трактоваться в пользу кандидата - как максимально возможные.

Опишем функцию makedate, которая возвращает корректное значение DateTime, принимая на вход строковое значение val, содержащее дату, и строковый параметр mode (значения min или max, по умолчанию min), указывающий требуется ли вернуть минимальную дату периода или максимальную:

function makedate(val,mode)
--	пустое значение: дата отсутствует
	if val == "" then
		return DateTime.Now
	end
	local date = DateTime(val)
	if date.IsValid and date <= DateTime.Now then
		return date
	elseif date.IsValid then	
		return DateTime.Now
	end
	
--	обработка неполных дат
	if not mode or mode == "min" then
		val = val:gsub("^00%.","01.")
		val = val:gsub("%.00%.",".01.")
		return DateTime(val)
	else
		local day, month, year = unpack(val:split(".",0,true,tonumber))
		if month == 0 then
			month = 12
		end
		if day == 0 then
			local last = {31,28,31,30,31,30,31,31,30,31,30,31}
			day = last[month]
		end		
		date = DateTime()
		date.Year, date.Month, date.Day  = year, month, day
		return date
	end	
end

А теперь используем эту функцию в реализации нашего алгоритма фильтрации записей ЛЦ.

function FilterByExperience(rs)
--	фильтрация по стажу
	for rec in rs.Records do
		local td_rs = rec:GetValue(90,"ТД")
		if conditions.career then
			td_rs:StringRequest("ОТ "..conditions.career)
		end	
		local exp = DateTimeSpan()
		for td in td_rs.Records do
			if td:GetValue(1) ~= "" then
				local start = makedate(td:GetValue(1))
				local finish = makedate(td:GetValue(2),"max")
				exp = exp + (finish - start)
			end	
		end
		if exp.Days/365 < conditions.experience then
			rs:Remove(rec.SN)
		end
	end	
	return rs
end

Осталось внести дополнения в блок отображения найденных записей функции btnFind_Click:

--	отображение найденных записей
	if conditions.experience then
		rs = FilterByExperience(rs)
	end	
	GetBank():GetBase("ЛЦ"):OpenReview(rs)
	Me.WindowState = Form.Minimized

На этом наша работа, связанная с реализацией отбора записей, завершена. В последней статье данной серии мы сделаем небольшие улучшения пользовательского интерфейса, связанные с обработкой событий от клавиатуры.

Дополнительные материалы

Текст модуля формы поиска на данный момент

Страница создана на основе шаблона flexible-jekyll