fiscalizer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ require 'fiscalizer/communication'
2
+ require 'fiscalizer/echo'
3
+ require 'fiscalizer/office'
4
+ require 'fiscalizer/invoice'
5
+ require 'fiscalizer/response'
6
+
7
+ class Fiscalizer
8
+
9
+ # Accessible attributes
10
+ attr_accessor :url, :key_public_path, :key_private_path, :certificate_path,
11
+ :key_private, :key_public, :certificate,
12
+ :tns, :schemaLocation, :certificate_issued_by
13
+
14
+ # Public methods
15
+ def initialize( url: "https://cis.porezna-uprava.hr:8449/FiskalizacijaService",
16
+ key_public_path: nil, key_private_path: nil, certificate_path: nil,
17
+ tns: "http://www.apis-it.hr/fin/2012/types/f73",
18
+ schemaLocation: "http://www.apis-it.hr/fin/2012/types/f73 FiskalizacijaSchema.xsd",
19
+ certificate_issued_by: "OU=RDC,O=FINA,C=HR", certificate_p12_path: nil, password: nil)
20
+ @url = url
21
+ @key_public_path = key_public_path
22
+ @key_private_path = key_private_path
23
+ @certificate_path = certificate_path
24
+ @certificate_p12_path = certificate_p12_path
25
+ @tns = tns
26
+ @schemaLocation = schemaLocation
27
+
28
+ # Import certificates
29
+ export_keys password
30
+
31
+ if @key_public_path != nil && File.exists?(@key_public_path)
32
+ @key_public = OpenSSL::X509::Certificate.new(File.read(@key_public_path))
33
+ end
34
+
35
+ if @key_private_path != nil && File.exists?(@key_private_path)
36
+ @key_private = OpenSSL::PKey::RSA.new(File.read(@key_private_path))
37
+ end
38
+
39
+ if @certificate_path != nil && File.exists?(@certificate_path)
40
+ @certificate = OpenSSL::X509::Certificate.new(File.read(@certificate_path))
41
+ end
42
+ end # new
43
+
44
+ def echo echo=nil, text: "Hello World!"
45
+ # Build echo request
46
+ echo = Fiscalizer::Echo.new text: text if echo == nil
47
+ # Send it
48
+ comm = Fiscalizer::Communication.new url: @url, tns: @tns, schemaLocation: @schemaLocation,
49
+ key_public: @key_public, key_private: @key_private,
50
+ certificate: @certificate, certificate_issued_by: @certificate_issued_by
51
+ raw_response = comm.send echo
52
+ response = Fiscalizer::Response.new object: echo, html_response: raw_response, tns: @tns
53
+ return response
54
+ end # echo
55
+
56
+ def fiscalize_office( office=nil, uuid: nil, time_sent: nil, pin: nil,
57
+ office_label: nil, adress_street_name: nil, adress_house_num: nil,
58
+ adress_house_num_addendum: nil, adress_post_num: nil, adress_settlement: nil,
59
+ adress_township: nil, adress_other: nil, office_time: nil, take_effect_date: nil,
60
+ closure_mark: nil, specific_purpose: nil, reconnect_attempts: 3 )
61
+ # Test connection
62
+ response_alive = echo text: "Is the server alive?"
63
+ recconect_attempted = 1
64
+ reconnect_attempts = 0 if reconnect_attempts < 0
65
+ while recconect_attempted < reconnect_attempts && !response_alive.echo?
66
+ response_alive = echo text: "Is the server alive?"
67
+ recconect_attempted += 1
68
+ end
69
+ if !response_alive.echo?
70
+ response_alive.type = 0
71
+ response_alive.errors['f100'] = "Failed to connect to server"
72
+ return response_alive
73
+ end
74
+ # Build office
75
+ office = Fiscalizer::Office.new( uuid: uuid, time_sent: time_sent, pin: pin,
76
+ office_label: office_label, adress_street_name: adress_street_name, adress_house_num: adress_house_num,
77
+ adress_house_num_addendum: adress_house_num_addendum, adress_post_num: adress_post_num, adress_settlement: adress_settlement,
78
+ adress_township: adress_township, adress_other: adress_other, office_time: office_time, take_effect_date: take_effect_date,
79
+ closure_mark: closure_mark, specific_purpose: specific_purpose) if office == nil
80
+ # Send it
81
+ comm = Fiscalizer::Communication.new url: @url, tns: @tns, schemaLocation: @schemaLocation,
82
+ key_public: @key_public, key_private: @key_private,
83
+ certificate: @certificate, certificate_issued_by: @certificate_issued_by
84
+ raw_response = comm.send office
85
+ response = Fiscalizer::Response.new object: office, html_response: raw_response, tns: @tns
86
+ return response
87
+ end # fiscalize_office
88
+ alias_method :office, :fiscalize_office
89
+ alias_method :fiscalize_office_space, :fiscalize_office
90
+
91
+ def fiscalize_invoice( invoice=nil, uuid: nil, time_sent: nil, pin: nil,
92
+ in_vat_system: nil, time_issued: nil, consistance_mark: nil,
93
+ issued_number: nil, issued_office: nil, issued_machine: nil,
94
+ tax_vat: [], tax_spending: [], tax_other: [],
95
+ value_tax_liberation: nil, value_tax_margin: nil, value_non_taxable: nil,
96
+ fees: [], summed_total: nil, payment_method: nil,
97
+ operator_pin: nil, security_code: nil, subsequent_delivery: nil,
98
+ paragon_label: nil, specific_purpose: nil, unique_identifier: nil,
99
+ automatic: true, reconnect_attempts: 3)
100
+ # Test connection
101
+ response_alive = echo text: "Is the server alive"
102
+ recconect_attempted = 1
103
+ reconnect_attempts = 0 if reconnect_attempts < 0
104
+ while recconect_attempted < reconnect_attempts && !response_alive.echo?
105
+ response_alive = echo text: "Is the server alive"
106
+ recconect_attempted += 1
107
+ end
108
+ if !response_alive.echo?
109
+ response_alive.type = 0
110
+ response_alive.errors['f100'] = "Failed to connect to server"
111
+ return response_alive
112
+ end
113
+ # Build invoice
114
+ invoice = Fiscalizer::Invoice.new( uuid: uuid, time_sent: time_sent, pin: pin,
115
+ in_vat_system: in_vat_system, time_issued: time_issued, consistance_mark: consistance_mark,
116
+ issued_number: issued_number, issued_office: issued_office, issued_machine: issued_machine,
117
+ tax_vat: tax_vat, tax_spending: tax_spending, tax_other: tax_other,
118
+ value_tax_liberation: value_tax_liberation, value_tax_margin: value_tax_margin, value_non_taxable: value_non_taxable,
119
+ fees: fees, summed_total: summed_total, payment_method: payment_method,
120
+ operator_pin: operator_pin, security_code: security_code, subsequent_delivery: subsequent_delivery,
121
+ paragon_label: paragon_label, specific_purpose: specific_purpose, unique_identifier: unique_identifier,
122
+ automatic: automatic) if invoice == nil
123
+ # Send it
124
+ comm = Fiscalizer::Communication.new url: @url, tns: @tns, schemaLocation: @schemaLocation,
125
+ key_public: @key_public, key_private: @key_private,
126
+ certificate: @certificate, certificate_issued_by: @certificate_issued_by
127
+ raw_response = comm.send invoice
128
+ response = Fiscalizer::Response.new object: invoice, html_response: raw_response, tns: @tns
129
+ return response
130
+ end # fiscalize_invoice
131
+ alias_method :invoice, :fiscalize_invoice
132
+
133
+ def certificate_p12_path= path
134
+ @certificate_p12_path = path
135
+ export_keys
136
+ end # certificate_p12_path
137
+
138
+ private
139
+ def export_keys password
140
+ if @certificate_p12_path != nil && File.exists?(@certificate_p12_path) && password != nil
141
+ extracted = OpenSSL::PKCS12.new(File.read(@certificate_p12_path), password)
142
+ @key_public = OpenSSL::X509::Certificate.new(extracted.certificate)
143
+ @key_private = OpenSSL::PKey::RSA.new(extracted.key)
144
+ @certificate = OpenSSL::X509::Certificate.new(extracted.ca_certs.first.to_s) if extracted.ca_certs != nil && extracted.ca_certs.size != 0
145
+ end
146
+ end # export_keys
147
+
148
+ end # FiscalizerRuby
@@ -0,0 +1,190 @@
1
+ require 'fiscalizer/tax'
2
+ require 'fiscalizer/fee'
3
+
4
+ class Fiscalizer
5
+ class Invoice
6
+
7
+ attr_accessor :uuid, :time_sent, :pin,
8
+ :in_vat_system, :time_issued, :consistance_mark,
9
+ :issued_number, :issued_office, :issued_machine,
10
+ :tax_vat, :tax_spending, :tax_other,
11
+ :value_tax_liberation, :value_tax_margin, :value_non_taxable,
12
+ :fees, :summed_total, :payment_method,
13
+ :operator_pin, :security_code, :subsequent_delivery,
14
+ :paragon_label, :specific_purpose, :unique_identifier,
15
+ :automatic, :generated_xml
16
+
17
+ def initialize( uuid: nil, time_sent: nil, pin: nil,
18
+ in_vat_system: nil, time_issued: nil, consistance_mark: nil,
19
+ issued_number: nil, issued_office: nil, issued_machine: nil,
20
+ tax_vat: [], tax_spending: [], tax_other: [],
21
+ value_tax_liberation: nil, value_tax_margin: nil, value_non_taxable: nil,
22
+ fees: [], summed_total: nil, payment_method: nil,
23
+ operator_pin: nil, security_code: nil, subsequent_delivery: nil,
24
+ paragon_label: nil, specific_purpose: nil, unique_identifier: nil,
25
+ automatic: true)
26
+ @uuid = uuid
27
+ @time_sent = time_sent
28
+ @pin = pin
29
+ @in_vat_system = in_vat_system
30
+ @time_issued = time_issued
31
+ @consistance_mark = consistance_mark
32
+ @issued_number = issued_number
33
+ @issued_office = issued_office
34
+ @issued_machine = issued_machine
35
+ @tax_vat = tax_vat
36
+ @tax_spending = tax_spending
37
+ @tax_other = tax_other
38
+ @value_tax_liberation = value_tax_liberation
39
+ @value_tax_margin = value_tax_margin
40
+ @value_non_taxable = value_non_taxable
41
+ @fees = fees
42
+ @summed_total = summed_total
43
+ @payment_method = payment_method
44
+ @operator_pin = operator_pin
45
+ @security_code = security_code
46
+ @subsequent_delivery = subsequent_delivery
47
+ @paragon_label = paragon_label
48
+ @specific_purpose = specific_purpose
49
+ @unique_identifier = unique_identifier
50
+ @automatic = automatic
51
+
52
+ autocomplete_data_set if @automatic
53
+ end # initialize
54
+
55
+ # Add taxes
56
+ def add_tax_vat base: 0.0, rate: 0.0, name: "", tax: nil
57
+ tax = Fiscalizer::Tax.new base: base, rate: rate, name: name if tax == nil
58
+ @tax_vat = Array.new if @tax_vat.class != Array
59
+ @tax_vat << tax
60
+ end # add_tax_vat
61
+
62
+ def add_tax_spending base: 0.0, rate: 0.0, name: "", tax: nil
63
+ tax = Fiscalizer::Tax.new base: base, rate: rate, name: name if tax == nil
64
+ @tax_spending = Array.new if @tax_spending.class != Array
65
+ @tax_spending << tax
66
+ end # add_tax_spending
67
+
68
+ def add_tax_other base: 0.0, rate: 0.0, name: "", tax: nil
69
+ tax = Fiscalizer::Tax.new base: base, rate: rate, name: name if tax == nil
70
+ @tax_other = Array.new if @tax_other.class != Array
71
+ @tax_other << tax
72
+ end # add_tax_spending
73
+
74
+ # Add fees
75
+ def add_fee name: "", value: 0.0, fee: nil
76
+ fee = Fiscalizer::Fee.new name: base, value: rate if fee == nil
77
+ @fee << fee
78
+ end # add_fee
79
+
80
+ # Check if all necessary values are present
81
+ def is_valid
82
+ # Check values
83
+ return false if @uuid == nil
84
+ return false if @time_sent == nil
85
+ return false if @pin == nil
86
+ return false if @in_vat_system == nil
87
+ return false if @time_issued == nil
88
+ return false if @consistance_mark == nil
89
+ return false if @issued_number == nil
90
+ return false if @issued_office == nil
91
+ return false if @issued_machine == nil
92
+ return false if summed_total == nil
93
+ return false if @payment_method == nil
94
+ return false if @operator_pin == nil
95
+ return false if @security_code == nil
96
+ return false if @subsequent_delivery == nil
97
+
98
+ # Check taxes
99
+ tax_vat.each do |tax|
100
+ return false if tax.name == nil || tax.name.class != String
101
+ return false if tax.base == nil || tax.base.class != Float
102
+ return false if tax.rate == nil || tax.rate.class != Float
103
+ end # tax_vat.each
104
+
105
+ tax_spending.each do |tax|
106
+ return false if tax.name == nil || tax.name.class != String
107
+ return false if tax.base == nil || tax.base.class != Float
108
+ return false if tax.rate == nil || tax.rate.class != Float
109
+ end # tax_spending.each
110
+
111
+ tax_other.each do |tax|
112
+ return false if tax.name == nil || tax.name.class != String
113
+ return false if tax.base == nil || tax.base.class != Float
114
+ return false if tax.rate == nil || tax.rate.class != Float
115
+ end # tax_other.each
116
+
117
+ # Check fees
118
+ fees.each do |fee|
119
+ return false if fee.name == nil || fee.name.class != String
120
+ return false if fee.value == nil || fee.value.class != Float
121
+ end # fees.each
122
+
123
+ return true
124
+ end # is_valid
125
+ alias_method :valid?, :is_valid
126
+ alias_method :valdate, :is_valid
127
+
128
+ # Getters
129
+ def time_issued_str separator="T"
130
+ return @time_issued.strftime('%d.%m.%Y') + separator + @time_issued.strftime('%H:%M:%S')
131
+ end # time_issued_str
132
+
133
+ def time_sent_str separator="T"
134
+ return @time_sent.strftime('%d.%m.%Y') + separator + @time_sent.strftime('%H:%M:%S')
135
+ end # time_sent_str
136
+
137
+ def summed_total
138
+ return @summed_total if @summed_total != nil
139
+ total = 0.0
140
+ tax_vat.each do |tax|
141
+ total += tax.summed
142
+ end
143
+ tax_spending.each do |tax|
144
+ total += tax.summed
145
+ end
146
+ tax_other.each do |tax|
147
+ total += tax.summed
148
+ end
149
+ return total.round(2)
150
+ end # summed_total
151
+
152
+ def summed_total_str
153
+ return ("%15.2f" % summed_total).strip
154
+ end # summed_total_str
155
+
156
+ def payment_method
157
+ return "G" if @payment_method[0].downcase == "g"
158
+ return "K" if @payment_method[0].downcase == "k"
159
+ return "C" if @payment_method[0].downcase == "c"
160
+ return "T" if @payment_method[0].downcase == "t"
161
+ return "O" if @payment_method[0].downcase == "o"
162
+ raise "Invalid payment method type!"
163
+ end # payment_method
164
+
165
+ def consistance_mark
166
+ return @consistance_mark.upcase
167
+ end # consistance_mark
168
+
169
+ def value_tax_liberation_str
170
+ return nil if @value_tax_liberation == nil
171
+ return ("%15.2f" % @value_tax_liberation.round(2)).strip
172
+ end # value_tax_liberation_str
173
+
174
+ def value_tax_margin_str
175
+ return nil if @value_tax_margin == nil
176
+ return ("%15.2f" % @value_tax_margin.round(2)).strip
177
+ end # value_tax_margin_str
178
+
179
+ def value_non_taxable_str
180
+ return nil if @value_non_taxable == nil
181
+ return ("%15.2f" % @value_non_taxable.round(2)).strip
182
+ end # value_non_taxable_str
183
+
184
+
185
+ # Helpers
186
+ def autocomplete_data_set
187
+ end # autocomplete_data_set
188
+
189
+ end # Invoice
190
+ end # Fiscalizer
@@ -0,0 +1,66 @@
1
+ class Fiscalizer
2
+ class Office
3
+
4
+ attr_accessor :uuid, :time_sent, :pin,
5
+ :office_label, :adress_street_name, :adress_house_num,
6
+ :adress_house_num_addendum, :adress_post_num, :adress_settlement,
7
+ :adress_township, :adress_other, :office_time,
8
+ :take_effect_date, :closure_mark, :specific_purpose,
9
+ :generated_xml
10
+
11
+ def initialize( uuid: nil, time_sent: nil, pin: nil,
12
+ office_label: nil, adress_street_name: nil, adress_house_num: nil,
13
+ adress_house_num_addendum: nil, adress_post_num: nil, adress_settlement: nil,
14
+ adress_township: nil, adress_other: nil, office_time: nil, take_effect_date: nil,
15
+ closure_mark: nil, specific_purpose: nil)
16
+ @uuid = uuid
17
+ @time_sent = time_sent
18
+ @pin = pin
19
+ @office_label = office_label
20
+ @adress_street_name = adress_street_name
21
+ @adress_house_num = adress_house_num
22
+ @adress_house_num_addendum = adress_house_num_addendum
23
+ @adress_post_num = adress_post_num
24
+ @adress_settlement = adress_settlement
25
+ @adress_township = adress_township
26
+ @adress_other = adress_other
27
+ @office_time = office_time
28
+ @take_effect_date = take_effect_date
29
+ @closure_mark = closure_mark
30
+ @specific_purpose = specific_purpose
31
+
32
+ end # initialize
33
+
34
+ # Getters
35
+ def time_sent_str separator="T"
36
+ return @time_sent.strftime('%d.%m.%Y') + separator + @time_sent.strftime('%H:%M:%S')
37
+ end # time_issued_str
38
+
39
+ def take_effect_date_str
40
+ return @take_effect_date.strftime('%d.%m.%Y')
41
+ end # time_sent_str
42
+
43
+ def is_valid
44
+ # Check values
45
+ return false if @uuid == nil
46
+ return false if @time_sent == nil
47
+ return false if @pin == nil
48
+ return false if @office_label == nil
49
+ return false if @office_time == nil
50
+ return false if @take_effect_date == nil
51
+ # Check adress
52
+ if @adress_other == nil
53
+ return false if @adress_street_name == nil
54
+ return false if @adress_house_num == nil
55
+ return false if @adress_house_num_addendum == nil
56
+ return false if @adress_post_num == nil
57
+ return false if @adress_settlement == nil
58
+ return false if @adress_township == nil
59
+ end
60
+ return true
61
+ end # is_valid
62
+ alias_method :valid?, :is_valid
63
+ alias_method :valdate, :is_valid
64
+
65
+ end # Office
66
+ end # Fiscalizer
@@ -0,0 +1,124 @@
1
+ require 'fiscalizer/echo'
2
+ require 'fiscalizer/office'
3
+ require 'fiscalizer/invoice'
4
+
5
+ class Fiscalizer
6
+ class Response
7
+
8
+ attr_accessor :type, :errors, :object,
9
+ :uuid, :processed_at, :response,
10
+ :unique_identifier, :tns, :html_response
11
+
12
+ def initialize( type: 0, errors: {}, object: nil, html_response: nil,
13
+ tns: "http://www.apis-it.hr/fin/2012/types/f73", automatic: true)
14
+ # Save
15
+ @type = type
16
+ @errors = errors
17
+ @object = object
18
+ @uuid = uuid
19
+ @processed_at = processed_at
20
+ @response = response
21
+ @unique_identifier = unique_identifier
22
+ @tns = tns
23
+ @html_response = html_response
24
+
25
+ if automatic && @object != nil
26
+ @type = 0
27
+ @type = 1 if @object.class == Echo
28
+ @type = 2 if @object.class == Office
29
+ @type = 3 if @object.class == Invoice
30
+ end
31
+
32
+ # Automatically fill
33
+ parse_response @html_response.body if @html_response != nil && automatic
34
+ end # initialize
35
+
36
+ def generated_xml
37
+ return @object.generated_xml if @object != nil && @object.respond_to?(:generated_xml)
38
+ return nil
39
+ end # generated_xml
40
+
41
+ def has_error
42
+ return true if @errors.count > 0
43
+ return false
44
+ end # has_error
45
+ alias_method :errors?, :has_error
46
+
47
+ def error_codes
48
+ return errors.keys
49
+ end # error_keys
50
+
51
+ def error_messages
52
+ return errors.values
53
+ end # error_messages
54
+
55
+ def type_str
56
+ if @type == 0
57
+ return "Error"
58
+ elsif @type == 1
59
+ return "Echo"
60
+ elsif @type == 2
61
+ return "Office"
62
+ elsif @type == 3
63
+ return "Invoice"
64
+ end
65
+ return "Unknown"
66
+ end # type_str
67
+
68
+ def echo_succeeded
69
+ return false if @object == nil
70
+ parse_response_echo @html_response.body if @response == nil && @html_response != nil
71
+ return false if @response == nil
72
+ return true if @object.text == @response
73
+ return false
74
+ end
75
+ alias_method :echo?, :echo_succeeded
76
+
77
+
78
+ private
79
+ def parse_response object
80
+ return nil if object == nil || object.class != String
81
+ if @type == 1
82
+ parse_response_echo object
83
+ elsif @type == 2
84
+ parse_response_office object
85
+ elsif @type == 3
86
+ parse_response_invoice object
87
+ end
88
+ parse_response_errors object
89
+ end # parse_response
90
+
91
+ def parse_response_echo object
92
+ @response = Nokogiri::XML(object).root.xpath('//tns:EchoResponse', 'tns' => @tns).first
93
+ @response = @response.text if @response != nil
94
+ end # parse_response_echo
95
+
96
+ def parse_response_office object
97
+ @uuid = Nokogiri::XML(object).root.xpath('//tns:IdPoruke', 'tns' => @tns).first
98
+ @processed_at = Nokogiri::XML(object).root.xpath('//tns:DatumVrijeme', 'tns' => @tns).first
99
+ @uuid = @uuid.text if @uuid != nil
100
+ @processed_at = @processed_at.text if @processed_at != nil
101
+ end # parse_response_office
102
+
103
+ def parse_response_invoice object
104
+ @uuid = Nokogiri::XML(object).root.xpath('//tns:IdPoruke', 'tns' => @tns).first
105
+ @processed_at = Nokogiri::XML(object).root.xpath('//tns:DatumVrijeme', 'tns' => @tns).first
106
+ @unique_identifier = Nokogiri::XML(object).root.xpath('//tns:Jir', 'tns' => @tns).first
107
+ @uuid = @uuid.text if @uuid != nil
108
+ @processed_at = @processed_at.text if @processed_at != nil
109
+ @unique_identifier = @unique_identifier.text if @unique_identifier != nil
110
+ end # parse_response_office
111
+
112
+ def parse_response_errors object
113
+ raw_errors = Nokogiri::XML(object).root.xpath('//tns:Greske', 'tns' => @tns)
114
+ raw_errors.each do |raw_error|
115
+ error_code = raw_error.xpath('//tns:SifraGreske', 'tns' => @tns).first
116
+ error_message = raw_error.xpath('//tns:PorukaGreske', 'tns' => @tns).first
117
+ error_code = error_code.text.strip if error_code != nil
118
+ error_message = error_message.text.strip if error_message != nil
119
+ @errors[error_code] = error_message if error_code != nil
120
+ end
121
+ end
122
+
123
+ end # Response
124
+ end # Fiscalizer