afd_parser 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/afd_parser.rb +257 -0
- data/lib/afd_parser/clock_in_out.rb +71 -0
- data/lib/afd_parser/header.rb +144 -0
- data/lib/afd_parser/record_parser.rb +65 -0
- data/lib/afd_parser/set_employee.rb +98 -0
- data/lib/afd_parser/set_employer.rb +109 -0
- data/lib/afd_parser/set_time.rb +77 -0
- data/lib/afd_parser/trailer.rb +83 -0
- data/lib/afd_parser/version.rb +3 -0
- data/test/afd_file +11 -0
- data/test/afd_invalid_utf-8_chars +2 -0
- data/test/afd_parser_test.rb +633 -0
- data/test/clock_in_out_test.rb +32 -0
- data/test/header_test.rb +52 -0
- data/test/set_employee_test.rb +67 -0
- data/test/set_employer_test.rb +29 -0
- data/test/set_time_test.rb +23 -0
- data/test/test_helper.rb +25 -0
- data/test/trailer_test.rb +26 -0
- metadata +85 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
class AfdParser::RecordParser
|
22
|
+
def self.size
|
23
|
+
raise "record size not defined for parser class '#{self.class.to_s}'"
|
24
|
+
end
|
25
|
+
|
26
|
+
def export
|
27
|
+
raise "record export is not defined for parser class '#{self.class.to_s}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def parse_date(date_array)
|
32
|
+
day = date_array[0..1].to_i
|
33
|
+
month = date_array[2..3].to_i
|
34
|
+
year = date_array[4..7].to_i
|
35
|
+
Date.civil(year,month,day)
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_time(date_array)
|
39
|
+
day = date_array[0..1].to_i
|
40
|
+
month = date_array[2..3].to_i
|
41
|
+
year = date_array[4..7].to_i
|
42
|
+
hour = date_array[8..9].to_i
|
43
|
+
minute = date_array[10..11].to_i
|
44
|
+
Time.local(year,month,day,hour,minute)
|
45
|
+
end
|
46
|
+
|
47
|
+
def format_date(date)
|
48
|
+
date.class == Date ? date.strftime("%d%m%Y") : date.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def format_time(time)
|
52
|
+
time.class == Time ? time.strftime("%d%m%Y%H%M") : time.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def well_formed_number_string?(string)
|
56
|
+
string.to_i.to_s.rjust(string.size, "0") == string
|
57
|
+
end
|
58
|
+
|
59
|
+
# Destructively removes invalid utf-8 chars from strings. Ignores data from
|
60
|
+
# other classes.
|
61
|
+
def _clean!(string)
|
62
|
+
return string unless string.class == String
|
63
|
+
string.force_encoding('ISO-8859-1').encode('UTF-8', {:invalid => :replace, :replace => ""})
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'afd_parser/record_parser'
|
22
|
+
|
23
|
+
class AfdParser::SetEmployee < AfdParser::RecordParser
|
24
|
+
attr_reader :line_id, :record_type_id, :creation_time, :operation_type,
|
25
|
+
:pis, :name
|
26
|
+
|
27
|
+
OPERATION_TYPE = {"I" => :add, "A" => :edit, "E" => :remove}
|
28
|
+
|
29
|
+
def initialize(line)
|
30
|
+
self.line_id, self.record_type_id, self.creation_time,
|
31
|
+
self.operation_type =
|
32
|
+
line.unpack("A9AA12A").collect{|str| _clean!(str)}
|
33
|
+
self.pis, self.name = line[23..-1].match(/\A(\d{1,12})(.{1,52})/)[1..2].collect{|str| _clean!(str)}
|
34
|
+
end
|
35
|
+
|
36
|
+
def export
|
37
|
+
line_export = ""
|
38
|
+
line_export += @line_id.to_s.rjust(9,"0")
|
39
|
+
line_export += @record_type_id.to_s
|
40
|
+
line_export += format_time(@creation_time)
|
41
|
+
line_export += get_operation_letter(@operation_type).to_s
|
42
|
+
line_export += @pis.to_s.rjust(12,"0")
|
43
|
+
line_export += @name.ljust(52, " ")
|
44
|
+
line_export
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.size
|
48
|
+
87
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
return self.class == other.class && [:line_id, :record_type_id, :creation_time, :operation_type, :pis, :name].all? do |reader|
|
53
|
+
self.send(reader) == other.send(reader)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def line_id=(data)
|
59
|
+
@line_id = well_formed_number_string?(data) ? data.to_i : data
|
60
|
+
end
|
61
|
+
|
62
|
+
def record_type_id=(data)
|
63
|
+
@record_type_id = well_formed_number_string?(data) ? data.to_i : data
|
64
|
+
end
|
65
|
+
|
66
|
+
def pis=(data)
|
67
|
+
@pis = well_formed_number_string?(data) ? data.to_i : data
|
68
|
+
end
|
69
|
+
|
70
|
+
def operation_type=(data)
|
71
|
+
@operation_type = get_operation_type(data)
|
72
|
+
end
|
73
|
+
|
74
|
+
def name=(data)
|
75
|
+
@name = data.rstrip
|
76
|
+
end
|
77
|
+
|
78
|
+
def creation_time=(raw_time)
|
79
|
+
begin
|
80
|
+
parsed_time = parse_time(raw_time)
|
81
|
+
@creation_time = parsed_time
|
82
|
+
rescue
|
83
|
+
@creation_time = ""
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_operation_type(operation_type_letter)
|
88
|
+
type = OPERATION_TYPE[operation_type_letter]
|
89
|
+
if type.nil?
|
90
|
+
raise AfdParser::AfdParserException.new("Unknown employee operation type letter '#{operation_type_letter}' found in line #{@line_id.to_s}")
|
91
|
+
end
|
92
|
+
type
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_operation_letter(operation_type)
|
96
|
+
OPERATION_TYPE.invert[operation_type]
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'afd_parser/record_parser'
|
22
|
+
|
23
|
+
class AfdParser::SetEmployer < AfdParser::RecordParser
|
24
|
+
attr_accessor :line_id, :record_type_id, :creation_time, :document_type,
|
25
|
+
:document_number, :cei, :name, :location
|
26
|
+
|
27
|
+
DOCUMENT_TYPES = {1 => :cnpj, 2 => :cpf}
|
28
|
+
|
29
|
+
def initialize(line)
|
30
|
+
self.line_id, self.record_type_id, self.creation_time,
|
31
|
+
self.document_type, self.document_number, self.cei, self.name,
|
32
|
+
self.location = line.unpack("A9AA12AA14A12A150A100").collect do |str|
|
33
|
+
_clean!(str)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def export
|
38
|
+
line_export = ""
|
39
|
+
line_export += @line_id.to_s.rjust(9,"0")
|
40
|
+
line_export += @record_type_id.to_s
|
41
|
+
line_export += format_time(@creation_time)
|
42
|
+
line_export += get_document_type_number(@document_type).to_s
|
43
|
+
line_export += @document_number.to_s.rjust(14, "0")
|
44
|
+
line_export += @cei.to_s.rjust(12, "0")
|
45
|
+
line_export += @name.ljust(150, " ")
|
46
|
+
line_export += @location.ljust(100, " ")
|
47
|
+
line_export
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.size
|
51
|
+
299
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
return self.class == other.class && [:line_id, :record_type_id, :creation_time, :document_type, :document_number, :cei, :name, :location].all? do |reader|
|
56
|
+
self.send(reader) == other.send(reader)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def line_id=(data)
|
62
|
+
@line_id = well_formed_number_string?(data) ? data.to_i : data
|
63
|
+
end
|
64
|
+
|
65
|
+
def record_type_id=(data)
|
66
|
+
@record_type_id = well_formed_number_string?(data) ? data.to_i : data
|
67
|
+
end
|
68
|
+
|
69
|
+
def document_type=(data)
|
70
|
+
@document_type = get_document_type(data.to_i)
|
71
|
+
end
|
72
|
+
|
73
|
+
def document_number=(data)
|
74
|
+
@document_number = well_formed_number_string?(data) ? data.to_i : data
|
75
|
+
end
|
76
|
+
|
77
|
+
def cei=(data)
|
78
|
+
@cei = well_formed_number_string?(data) ? data.to_i : data
|
79
|
+
end
|
80
|
+
|
81
|
+
def name=(data)
|
82
|
+
@name = data.rstrip
|
83
|
+
end
|
84
|
+
|
85
|
+
def location=(data)
|
86
|
+
@location = data.rstrip
|
87
|
+
end
|
88
|
+
|
89
|
+
def creation_time=(raw_time)
|
90
|
+
begin
|
91
|
+
parsed_time = parse_time(raw_time)
|
92
|
+
@creation_time = parsed_time
|
93
|
+
rescue
|
94
|
+
@creation_time = ""
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_document_type(document_type_id)
|
99
|
+
type = DOCUMENT_TYPES[document_type_id]
|
100
|
+
if type.nil?
|
101
|
+
raise AfdParser::AfdParserException.new("Unknown employer type id '#{document_type_id.to_s}' found in set employer record on line #{@line_id.to_s}")
|
102
|
+
end
|
103
|
+
type
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_document_type_number(document_type_id)
|
107
|
+
DOCUMENT_TYPES.invert[document_type_id]
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'afd_parser/record_parser'
|
22
|
+
|
23
|
+
class AfdParser::SetTime < AfdParser::RecordParser
|
24
|
+
attr_reader :line_id, :record_type_id, :before_time, :after_time
|
25
|
+
alias :creation_time :before_time
|
26
|
+
|
27
|
+
def initialize(line)
|
28
|
+
self.line_id, self.record_type_id, self.before_time,
|
29
|
+
self.after_time = line.unpack("A9AA12A12").collect{|str| _clean!(str)}
|
30
|
+
end
|
31
|
+
|
32
|
+
def export
|
33
|
+
line_export = ""
|
34
|
+
line_export += @line_id.to_s.rjust(9,"0")
|
35
|
+
line_export += @record_type_id.to_s
|
36
|
+
line_export += format_time(@before_time)
|
37
|
+
line_export += format_time(@after_time)
|
38
|
+
line_export
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.size
|
42
|
+
34
|
43
|
+
end
|
44
|
+
|
45
|
+
def ==(other)
|
46
|
+
return self.class == other.class && [:line_id, :record_type_id, :before_time, :after_time].all? do |reader|
|
47
|
+
self.send(reader) == other.send(reader)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def line_id=(data)
|
53
|
+
@line_id = well_formed_number_string?(data) ? data.to_i : data
|
54
|
+
end
|
55
|
+
|
56
|
+
def record_type_id=(data)
|
57
|
+
@record_type_id = well_formed_number_string?(data) ? data.to_i : data
|
58
|
+
end
|
59
|
+
|
60
|
+
def before_time=(raw_time)
|
61
|
+
begin
|
62
|
+
parsed_time = parse_time(raw_time)
|
63
|
+
@before_time = parsed_time
|
64
|
+
rescue
|
65
|
+
@before_time = ""
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def after_time=(raw_time)
|
70
|
+
begin
|
71
|
+
parsed_time = parse_time(raw_time)
|
72
|
+
@after_time = parsed_time
|
73
|
+
rescue
|
74
|
+
@after_time = ""
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'afd_parser/record_parser'
|
22
|
+
|
23
|
+
class AfdParser::Trailer < AfdParser::RecordParser
|
24
|
+
attr_reader :line_id, :set_employer, :clock_in_out, :set_time, :set_employee, :record_type_id
|
25
|
+
|
26
|
+
def initialize(*args)
|
27
|
+
if args.size == 1
|
28
|
+
counter = args[0]
|
29
|
+
@line_id = 999999999
|
30
|
+
@set_employer = counter[:set_employer]
|
31
|
+
@clock_in_out = counter[:clock_in_out]
|
32
|
+
@set_time = counter[:set_time]
|
33
|
+
@set_employee = counter[:set_employee]
|
34
|
+
@record_type_id = 9
|
35
|
+
|
36
|
+
elsif args.size == 2
|
37
|
+
line = args[0]
|
38
|
+
counter = args[1]
|
39
|
+
|
40
|
+
line_id, set_employer, clock_in_out, set_time, set_employee,
|
41
|
+
record_type_id = line.unpack("A9A9A9A9A9A").collect{|str| _clean!(str)}
|
42
|
+
|
43
|
+
@line_id = line_id.to_i
|
44
|
+
@set_employer = set_employer.to_i
|
45
|
+
@clock_in_out = clock_in_out.to_i
|
46
|
+
@set_time = set_time.to_i
|
47
|
+
@set_employee = set_employee.to_i
|
48
|
+
@record_type_id = record_type_id.to_i
|
49
|
+
|
50
|
+
["set_employer", "clock_in_out", "set_time", "set_employee"].each do |key|
|
51
|
+
value = eval("@"+key)
|
52
|
+
if value != counter[key.to_sym]
|
53
|
+
raise AfdParser::AfdParserException.new("Mismatch counting changes of #{key} in REP!\n" +
|
54
|
+
"REP: #{value.to_s} | System: #{counter[key.to_sym].to_s}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
else
|
59
|
+
raise AfdParser::AfdParserException.new("wrong number of arguments for trailer object, should be 1 or 2")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def export
|
64
|
+
line_export = ""
|
65
|
+
line_export += @line_id.to_s.rjust(9,"0")
|
66
|
+
line_export += @set_employer.to_s.rjust(9,"0")
|
67
|
+
line_export += @clock_in_out.to_s.rjust(9,"0")
|
68
|
+
line_export += @set_time.to_s.rjust(9,"0")
|
69
|
+
line_export += @set_employee.to_s.rjust(9,"0")
|
70
|
+
line_export += @record_type_id.to_s
|
71
|
+
line_export
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.time
|
75
|
+
46
|
76
|
+
end
|
77
|
+
|
78
|
+
def ==(other)
|
79
|
+
return self.class == other.class && [:line_id, :set_employer, :clock_in_out, :set_time, :set_employee, :record_type_id].all? do |reader|
|
80
|
+
self.send(reader) == other.send(reader)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/test/afd_file
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
0000000001100000000067890000000009876RAZAO_SOCIAL 000040000700044032001201122022011210220111048
|
2
|
+
0000000014280120111112280120111113
|
3
|
+
0000000022270120111756108682040000172000000000000O.S. SYSTEMS SOFTWARES LTDA. PELOTAS - RS
|
4
|
+
0000000035270120111759I111111111111TESTE 1 2 3
|
5
|
+
0000000045080220111709I222222222222TESTE 2
|
6
|
+
0000000055110220111719A222222222222TESTE 2
|
7
|
+
0000000065110220111723E222222222222TESTE 2
|
8
|
+
0000000073190220111814111111111111
|
9
|
+
0000000083210220111133111111111111
|
10
|
+
0000000093210220111134111111111111
|
11
|
+
9999999990000000010000000030000000010000000049
|