Страница 1 из 1
Импорт Табеля рабочего времени из файла
Добавлено: 07 авг 2007, 14:37
SergeyZhd
Здравствуйте!
Интересует вопрос кто нибудь заполняет табель из какого либо внешнего файла и как это делается?
в хелпе написано Стандартная форма но нигде её примеров нету
а текстовый файл не подходит, т.к заполнять будут руководители отделов и отдавать в кадры.
есть ли возможность загружать табель из какой либо наглядной формы типа таблицы?
Добавлено: 07 авг 2007, 15:13
voronov
Собственная доработка выгрузки из EXCEL, например, если наглядно надо.
Добавлено: 07 авг 2007, 16:46
edward_K
стандартная форма получается при печати Т12. Там есть еще алтернативный формат - о нем написано в доке и по F1. Наскока помню хорошо не получается(оссобенно с неявками).
Добавлено: 08 авг 2007, 17:53
SergeyZhd
пробовал выгружать форму т12 из галактики (лист 2) пишет некорректный формат
Добавлено: 14 авг 2007, 18:06
Maxx
Мы используем альтернативный формат текстового файла. Он наиболее подходящий. Есть итоговые часы. Но у нас очень много отклонений от графика и после импорта из текстового файла все равно приходится смотреть и корректировать. Насчет формата скажу, что он очень урезан. За день можно указать только часы или буквенное обозначение. Нельзя передать за день ночные и т.д.
Вопрос к voronov: можно подробнее рассказать как написали импорт в таблицы гал-ки?
Добавлено: 14 авг 2007, 22:45
voronov
Maxx писал(а):
Вопрос к voronov: можно подробнее рассказать как написали импорт в таблицы гал-ки?
В основном, проблема была именно в том, каким образом все построить в эксель файле. Различные обозначения рабочего дня (а у клиента их используется ужастно много). Число отработанных дней. Обработка отклонений.
В результате работы месяцов подходящий шаблон был найден
А дальше просто:
1. Считываем из excel обозначение рабочих дней и проставляем его в галактику
2. Считаем число рабочих дней (ежедневно и в сумме) и тоже переносим в галку
3. Считываем отклонения. Удаляем все отклоения Галки за этот месяц и заменяем своими
Добавлено: 15 авг 2007, 08:39
PViP
Maxx, о каком ипорте в таблицы галактики идеь речь? Есть стандартная реализация импорта табеля из тхт файла(пункт меню Формирование табеля). Все подходы в принципе озвучены выше. Я делал табель в таблицах MS Excel, из Excel экспортировал в текстовый файл в "алтернативном" формате и затем ипотртировал этот файл в галку.
А вот о подводных камнях импорта: при импорте обозначения "ДО", не происходит его корректная обработка, тоесть если в галке нет приказа на отпуск, а мы его импортируем, то при переформировании не происходит удаление "ДО" из табеля, а должно бы быть!
Добавлено: 16 авг 2007, 01:59
Screw
Для справки: альтернативный формат был реализован как демонстрация возможностей API импорта табелей. Не очень, надо заметить, удачная (итоги по часам надо было расположить не в конце, а в начале, до подённых данных). В своей собственной реализации импортера можно реализовать сколь угодно сложный алгоритм разбора исходных данных. Однако "превращение" отклонений в "настоящие" отпуска, больничные и командировки - это не забота табельного импортера. Его дело - передача в Галактику подённых часов (в том числе ночных, вечерних, выходных и праздничных) и табельных отклонений (не путать с системными, для которых заведены соответствующие таблицы, например, "Отпуска"). К сожалению, API для генерации пакетов отпусков и прочих системных отклонений пока не существует, поэтому могу рекомендовать только непосредственную работу с БД.
Для особо интересующихся привожу описания объектных интерфейсов API импорта табелей и код импортера из формата "данные разделены символом ';' (альтернативный)".
Содержимое WTImport.vih
Код: Выделить всё
//******************************************************************************
// (с) корпорация Галактика
// Галактика 8.1 - Заработная плата
// Объектные инт-сы для импорта табеля из текстового файла
//******************************************************************************
#ifndef _WTIMPORT_INCLUDED_
#define _WTIMPORT_INCLUDED_
#ifdef ComponentVersion
#component "Z_WT"
#end
//------------------------------------------------------------------------------
#doc
Объктный интерфейс итератора по отклонениям табеля учета рабочего времени.
#end
objinterface IWorkingTableVarianceIterator;
#doc
Устанавливает курсор на первое отклонение. Возвращает true, если
позиционирование прошло успешно, в противном случае возвращает false.
#end
function First: boolean;
#doc
Установливает курсор на следующее отклонение. Возвращает true, если
позиционирование прошло успешно, в противном случае возвращает false.
#end
function Next: boolean;
#doc
Возвращает в B содержимое буфера отклонения.
#end
procedure GetData(var B: type$VARIANCE);
end;
//------------------------------------------------------------------------------
#doc
Объектный интерфейс импортера данных табеля учета рабочего времени.
#end
objinterface IWorkingTableImporter;
#doc
Открывает файл с данными.
#end
function OpenFile(FileName: string): boolean;
#doc
Закрывает файл с данными.
#end
procedure CloseFile;
#doc
Тестирует содержимое файла на соответствие формату.
#end
function TestFile: boolean;
#doc
Переходит к данным первого импортируего табеля. Возвращает true в случае
успеха, иначе возвращает false.
#end
function First: boolean;
#doc
Переходит к данным следующего импортируемого табеля. Возвращает true в
случае успеха, иначе возвращает false.
#end
function Next: boolean;
#doc
Возвращает true, если в процессе загрузки данных очередного табеля
произошла какая-либо ошибка.
#end
function ErrorFound: boolean;
#doc
Возвращает значение числового табельного номера лицевого счета.
#end
function GetClockNumber: longint;
#doc
Возвращает месяц, к которому относятся данные импортируемого табеля.
#end
function GetMonth: byte;
#doc
Возвращает год, к которому относятся данные импортируемого табеля.
#end
function GetYear: word;
#doc
Возвращает true, если данные о количестве часов вида HourKind за день D
были представлены в файле импорта. Количество часов при этом передаётся в
Hours. Возвращает false в противном случае.
#end
function GetDailyHours(D: byte; HourKind: byte; var Hours: double): boolean;
#doc
Возвращает true, если данные о суммарном количестве часов вида HourKind
были представлены в файле импорта. Количество часов при этом передаётся в
Hours. Возвращает false в противном случае.
#end
function GetMonthlyHours(HourKind: byte; var Hours: double): boolean;
#doc
Возвращает ссылку на итератор по табельным отклонениям.
#end
function GetVarianceIterator: IWorkingTableVarianceIterator;
end;
//------------------------------------------------------------------------------
#doc
Объектный интерфейс описателя и загрузчика импортера данных табеля учета
рабочего времени.</brief>
<p>ВНИМАНИЕ: имена всех реализаций данного объектного интерфейса должны
начинаться с "VWorkingTableImporterLoader_"!</p>
<p>Интерфейс ввода параметров импорта табеля загружает список имен реализаций
объектного интерфейса IWorkingTableImporterLoader, загружает каждую
реализацию и вызывает ее метод GetFormat. Таким образом заполняется список
форматов файлов.</p>
<p>После того, как пользователь выбрал интересующий его формат и задал имя файла,
инициализируется соответствующий загрузчик и вызывается его метод GetImporter.
Далее вызываются методы импортера OpenFile и TestFile для открытия файла
импорта и проверки корректности его формата.</p>
<p>Вызов методов First и Next импортера означает подгрузку из файла и проверку
корректности данных первого/следующего табеля. Если данные загружены
корректно, посредством метода GetDailyHours выбираются часы за каждый день.
Затем, при помощи метода GetMonthlyHours, - итоговые величины за месяц.
Завершается цикл проходом по списку отклонений.</p>
#end
objinterface IWorkingTableImporterLoader;
#doc
Возвращает краткое описание поддерживаемого формата.</brief>
<p>Используется для составления списка поддерживаемых форматов в интерфейсе
настройки параметров импорта табелей учета рабочего времени.</p>
#end
function GetFormat: string;
#doc
Возвращает краткое описание синтаксиса записи импортируемых данных.
#end
function GetSyntax: string;
#doc
Возвращает ссылку на импортер, представленный данным загрузчиком.
#end
function GetImporter: IWorkingTableImporter;
end;
vipinterface VWorkingTableVarianceIterator implements IWorkingTableVarianceIterator
#ifdef ATL51
Licensed(Free)
#end
;
vipinterface VWorkingTableImporterLoader_CSV implements IWorkingTableImporterLoader
#ifdef ATL51
Licensed(Free)
#end
;
vipinterface vWorkingTableImporter_CSV implements IWorkingTableImporter
#ifdef ATL51
Licensed(Free)
#end
;
#end
Содержимое WTImport.vip
Код: Выделить всё
/*
╔═══════════════════════════════════════════════════════════════════════════╗
║ (c) 1994,97 корпорация ГАЛАКТИКА ║
║ Проект : ГАЛАКТИКА ║
║ Система : Заработная плата ║
║ Назначение : Простая реализация расширяемого импорта табеля ║
║ Ответственный : Корзюк Виталий Францевич ║
╚═══════════════════════════════════════════════════════════════════════════╝
*/
#include WTIMPORT.VIH
table struct SVARIANCE = VARIANCE;
#doc
Простая реализация итератора отклонений от табеля
#end
interface VWorkingTableVarianceIterator cacheable;
create view x;
public function First: boolean;
{
First := getfirst SVARIANCE = tsOk;
}
public function Next: boolean;
{
Next := getnext SVARIANCE = tsOk;
}
public procedure GetData(var B: type$VARIANCE);
{
B := type$VARIANCE(SVARIANCE.BUFFER);
}
end.
#doc
Простая реализация загрузчика импортера
#end
interface VWorkingTableImporterLoader_CSV cacheable;
create view x;
public function GetFormat: string;
{
GetFormat := 'Данные разделены символом ";" (альтернативный формат)' ;
}
public function GetSyntax: string;
{
GetSyntax :=
'<строка> ::= <таб.н.> ";" <месяц> ";" <год> ";" [ <часы по дням> [ <итого часов> ] ]'#13 +
'<часы по дням> ::= { [ <часы> ] ";" }'#13 +
'<итого часов> ::= [ <вечерних> ] ";" [ [ ночных> ] ";" [ [ <праздничных> ] ";" [ [ <выходных> ] ";" ] ] ]';
}
public function GetImporter: IWorkingTableImporter;
{
var I: IWorkingTableImporter;
LoadVipRef(I, 'VWorkingTableImporter_CSV');
GetImporter := I;
}
end.
#doc
Простая реализация импортера табеля из текстового файла
#end
interface VWorkingTableImporter_CSV '' EscClose;
show at (,,,);
table struct SDAILYDATA
(
DAY: byte,
ABBREVIATURE: comp,
WORKINGHOURS: double
)
with index
(
SDAILYDATA01 = DAY(unique)
);
table struct SMONTHLYHOURS
(
KIND: byte,
HOURS: double
)
with index
(
SMONTHLYHOURS01 = KIND(unique)
);
create view ImporterView
var
ClockNumber: longint;
CurMonth: byte;
CurYear: word;
DataDelimiter: char;
ParseError: boolean;
CurLine: longint;
CurPos: integer;
from
SDAILYDATA
, SMONTHLYHOURS
, SVARIANCE
, LSCHET
;
file F;
function ValidDataString(var S: string): boolean;
{
ValidDataString := false;
S := Trim(S);
if (S = '')
exit;
// комментарий
if (SubStr(S, 1, 1) = '!')
exit;
ValidDataString := true;
}
function GetData(var S: string; var Data: string): boolean;
{
GetData := false;
Data := '';
if (CurPos > Length(S))
exit;
do
{
var C: string;
C := SubStr(S, CurPos, 1);
CurPos := CurPos + 1;
if (C = DataDelimiter)
break;
else
Data := Data + C;
}
while (CurPos <= Length(S));
Data := Trim(Data);
GetData := true;
}
function Position: string;
{
Position := '(стр. ' + string(CurLine) + ', поз. ' + string(CurPos - 1) + ')';
}
function ParseString(S: string): boolean;
{
ParseString := false;
var Data: string;
CurPos := 1;
_try
{
if (GetData(S, Data))
{
CLockNumber := longint(Data);
if (getfirst LSCHET where ((ClockNumber == LSCHET.TABN)) <> tsOk)
{
Displ('[x] Лицевой счет с табельным номером ' + string(ClockNumber) + ' не найден ' + Position);
exit;
}
}
else
{
Displ('[x] Ошибка импорта табельного номера ' + Position);
exit;
}
if (GetData(S, Data))
{
CurMonth := byte(Data);
if (CurMonth > 12) or (CurMonth = 0)
{
Displ('[x] Обнаружено недопустимое значение месяца: ' + string(CurMonth) + ' ' + Position);
exit;
}
}
else
{
Displ('[x] Ошибка импорта месяца ' + Position);
exit;
}
if (GetData(S, Data))
{
CurYear := word(Data);
if (CurYear = 0)
{
Displ('[x] Обнаружено недопустимое значение года: ' + string(CurYear) + ' ' + Position);
exit;
}
}
else
{
Displ('[x] Ошибка импорта года ' + Position);
exit;
}
// импорт данных по дням месяца
// некоторые дни могут быть пропущены - это допустимо
var I: integer;
for(I := 1; I <= Last_Day(Date(1, CurMonth, CurYear)); I := I + 1)
{
if (GetData(S, Data))
{
if (Data <> '')
{
ClearBuffer(#SDAILYDATA);
SDAILYDATA.DAY := I;
if (getfirst UOWRKTABEL where ((Data == UOWRKTABEL.NUM)) = tsOk)
SDAILYDATA.ABBREVIATURE := UOWRKTABEL.NREC;
else
_try
{
SDAILYDATA.WORKINGHOURS := double(Data);
if (SDAILYDATA.WORKINGHOURS > 24)
{
Displ('[x] Обнаружено недопустимое количество отработанных часов: ' +
string(SDAILYDATA.WORKINGHOURS) + ' ' + Position);
exit;
}
}
_except
on ExNumberConvert:
{
Displ('[x] Код "' + Data + '" не найден в классификаторе условных обозначений ' + Position);
Displ(S);
exit;
}
insert current SDAILYDATA;
}
}
}
if (GetData(S, Data))
{
SMONTHLYHOURS.KIND := hkEvening;
SMONTHLYHOURS.HOURS := double(Data);
insert current SMONTHLYHOURS;
}
if (GetData(S, Data))
{
SMONTHLYHOURS.KIND := hkNight;
SMONTHLYHOURS.HOURS := double(Data);
insert current SMONTHLYHOURS;
}
if (GetData(S, Data))
{
SMONTHLYHOURS.KIND := hkHoliday;
SMONTHLYHOURS.HOURS := double(Data);
insert current SMONTHLYHOURS;
}
if (GetData(S, Data))
{
SMONTHLYHOURS.KIND := hkWeekend;
SMONTHLYHOURS.HOURS := double(Data);
insert current SMONTHLYHOURS;
}
var LastAbbr: comp;
LastAbbr := 0;
_loop SDAILYDATA novisual
{
if (SDAILYDATA.ABBREVIATURE <> LastAbbr) and (LastAbbr <> 0)
{
insert current SVARIANCE;
LastAbbr := 0;
}
if (SDAILYDATA.ABBREVIATURE <> 0)
{
if (SDAILYDATA.ABBREVIATURE <> LastAbbr)
{
ClearBuffer(#SVARIANCE);
LastAbbr := SDAILYDATA.ABBREVIATURE;
SVARIANCE.CUO := SDAILYDATA.ABBREVIATURE;
SVARIANCE.KIND := 1;
SVARIANCE.BEGINNING := SDAILYDATA.DAY;
}
SVARIANCE.ENDING := SDAILYDATA.DAY;
}
}
if (LastAbbr <> 0)
insert current SVARIANCE;
ParseString := true;
}
_except
on ExNumberConvert:
{
Displ('[x] Ошибка преобразования строки в число ' + Position);
Displ(S);
}
on ExDatabase:
Displ('[x] ' + ExploreException);
}
public function OpenFile(FileName: string): boolean;
{
OpenFile := false;
_try
OpenFile := F.OpenFile(FileName, stOpenRead);
_except
on ExFile:
Displ('[x] ' + ExploreException);
}
public procedure CloseFile;
{
F.Close;
}
public function Next: boolean;
{
Next := false;
CurMonth := 0;
CurYear := 0;
ClockNumber := 0;
delete all SDAILYDATA;
delete all SMONTHLYHOURS;
delete all SVARIANCE;
if (F.EOF)
exit;
do
{
var S: string;
F.ReadLn(S);
CurLine := CurLine + 1;
if not ValidDataString(S)
continue;
ParseError := not ParseString(S);
break;
}
while not F.EOF;
Next := true;
}
public function ErrorFound: boolean;
{
ErrorFound := ParseError;
}
public function First: boolean;
{
First := false;
F.Seek(0);
CurLine := 1;
First := Next;
}
public function TestFile: boolean;
{
TestFile := true;
}
public function GetClockNumber: longint;
{
GetClockNumber := ClockNumber;
}
public function GetMonth: byte;
{
GetMonth := CurMonth;
}
public function GetYear: word;
{
GetYear := CurYear;
}
public function GetDailyHours(D: byte; HourKind: byte; var Hours: double): boolean;
{
if (getfirst SDAILYDATA where ((D == SDAILYDATA.DAY)) = tsOk) and (HourKind = hkWorking) and (SDAILYDATA.ABBREVIATURE = 0)
{
Hours := SDAILYDATA.WORKINGHOURS;
GetDailyHours := true;
}
else
GetDailyHours := false;
}
public function GetMonthlyHours(HourKind: byte; var Hours: double): boolean;
{
if (getfirst SMONTHLYHOURS where ((HourKind == SMONTHLYHOURS.KIND)) = tsOk)
{
Hours := SMONTHLYHOURS.HOURS;
GetMonthlyHours := true;
}
else
GetMonthlyHours := false;
}
public function GetVarianceIterator: IWorkingTableVarianceIterator;
{
var WTVI: IWorkingTableVarianceIterator;
LoadVipRef(WTVI, 'VWorkingTableVarianceIterator');
GetVarianceIterator := WTVI;
}
HandleEvent
cmOnVipLoad:
{
DataDelimiter := ';';
}
cmOnVipUnLoad:
{
CloseFile;
}
end;
end.
Добавлено: 16 авг 2007, 02:01
Screw
Посмотрел пост и аж огорчился: до чего ж некрасиво я реализовал работу с отклонениями