fiscalizer 0.0.12 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rspec +2 -0
  4. data/Gemfile +0 -4
  5. data/LICENSE.txt +1 -1
  6. data/README.md +187 -171
  7. data/bin/console +14 -0
  8. data/bin/setup +7 -0
  9. data/doc/Tehnicka specifikacija za korisnike 1.4.pdf +0 -0
  10. data/fiscalizer.gemspec +14 -13
  11. data/lib/fiscalizer.rb +33 -4
  12. data/lib/fiscalizer/constants.rb +11 -0
  13. data/lib/fiscalizer/data_objects/echo.rb +10 -0
  14. data/lib/fiscalizer/data_objects/fee.rb +18 -0
  15. data/lib/fiscalizer/data_objects/invoice.rb +79 -0
  16. data/lib/fiscalizer/data_objects/office.rb +41 -0
  17. data/lib/fiscalizer/{tax.rb → data_objects/tax.rb} +3 -5
  18. data/lib/fiscalizer/deserializers/base.rb +58 -0
  19. data/lib/fiscalizer/deserializers/echo.rb +13 -0
  20. data/lib/fiscalizer/deserializers/invoice.rb +9 -0
  21. data/lib/fiscalizer/deserializers/office.rb +6 -0
  22. data/lib/fiscalizer/fiscalizer.rb +36 -152
  23. data/lib/fiscalizer/fiscalizers/base.rb +54 -0
  24. data/lib/fiscalizer/fiscalizers/echo.rb +13 -0
  25. data/lib/fiscalizer/fiscalizers/invoice.rb +24 -0
  26. data/lib/fiscalizer/fiscalizers/office.rb +15 -0
  27. data/lib/fiscalizer/serializers/base.rb +58 -0
  28. data/lib/fiscalizer/serializers/echo.rb +21 -0
  29. data/lib/fiscalizer/serializers/invoice.rb +92 -0
  30. data/lib/fiscalizer/serializers/office.rb +85 -0
  31. data/lib/fiscalizer/serializers/signature.rb +62 -0
  32. data/lib/fiscalizer/serializers/tax.rb +81 -0
  33. data/lib/fiscalizer/services/request_sender.rb +68 -0
  34. data/lib/fiscalizer/services/security_code_generator.rb +29 -0
  35. data/lib/fiscalizer/version.rb +1 -1
  36. data/spec/fiscalizer_spec.rb +119 -0
  37. data/spec/spec_helper.rb +9 -0
  38. metadata +67 -39
  39. data/doc/README.md +0 -3
  40. data/doc/Tehnicka_specifikacija_za_korisnike_1.2.pdf +0 -0
  41. data/example/README.md +0 -25
  42. data/example/echo_P12.rb +0 -13
  43. data/example/echo_public_and_private_keys.rb +0 -16
  44. data/example/invoice_fiscalization_passing_arguments.rb +0 -44
  45. data/example/invoice_fiscalization_passing_object.rb +0 -48
  46. data/example/office_fiscalization_passing_arguments.rb +0 -22
  47. data/example/office_fiscalization_passing_object.rb +0 -26
  48. data/lib/README.md +0 -0
  49. data/lib/fiscalizer/README.md +0 -9
  50. data/lib/fiscalizer/communication.rb +0 -305
  51. data/lib/fiscalizer/echo.rb +0 -11
  52. data/lib/fiscalizer/fee.rb +0 -20
  53. data/lib/fiscalizer/invoice.rb +0 -190
  54. data/lib/fiscalizer/office.rb +0 -66
  55. data/lib/fiscalizer/response.rb +0 -124
  56. data/test/README.md +0 -13
  57. data/test/test_echo.rb +0 -20
  58. data/test/test_fee +0 -64
  59. data/test/test_fiscalizer.rb +0 -222
  60. data/test/test_fiscalizer_communication.rb +0 -28
  61. data/test/test_invoice.rb +0 -11
  62. data/test/test_office.rb +0 -11
  63. data/test/test_tax.rb +0 -89
@@ -0,0 +1,54 @@
1
+ class Fiscalizer
2
+ module Fiscalizers
3
+ class Base
4
+ # rubocop:disable Metrics/ParameterLists
5
+ def initialize(app_cert_path, password, timeout, demo, ca_cert_path, object)
6
+ @app_cert_path = app_cert_path
7
+ @password = password
8
+ @timeout = timeout
9
+ @demo = demo
10
+ @ca_cert_path = ca_cert_path
11
+ @object = object
12
+ end
13
+
14
+ attr_reader :app_cert_path, :password, :timeout, :demo, :ca_cert_path, :object
15
+
16
+ def call
17
+ # check_echo
18
+ send_request
19
+ end
20
+
21
+ private
22
+
23
+ def send_request
24
+ response = request_sender.send(request_message)
25
+ deserialize(response)
26
+ end
27
+
28
+ def request_message
29
+ serializer.new(object, app_private_key, app_public_key, demo).call
30
+ end
31
+
32
+ def deserialize(response)
33
+ deserializer.new(response.body, object)
34
+ end
35
+
36
+ def request_sender
37
+ @request_sender ||=
38
+ Fiscalizer::RequestSender.new(extracted_app_cert, password, timeout, demo, ca_cert_path)
39
+ end
40
+
41
+ def app_public_key
42
+ @app_public_key ||= OpenSSL::X509::Certificate.new(extracted_app_cert.certificate)
43
+ end
44
+
45
+ def app_private_key
46
+ @app_private_key ||= OpenSSL::PKey::RSA.new(extracted_app_cert.key)
47
+ end
48
+
49
+ def extracted_app_cert
50
+ @extracted_app_cert ||= OpenSSL::PKCS12.new(File.read(app_cert_path), password)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,13 @@
1
+ class Fiscalizer
2
+ module Fiscalizers
3
+ class Echo < Base
4
+ def serializer
5
+ Serializers::Echo
6
+ end
7
+
8
+ def deserializer
9
+ Deserializers::Echo
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ class Fiscalizer
2
+ module Fiscalizers
3
+ class Invoice < Base
4
+ def call
5
+ generate_security_code
6
+ send_request
7
+ end
8
+
9
+ private
10
+
11
+ def generate_security_code
12
+ SecurityCodeGenerator.new(object, app_private_key).call
13
+ end
14
+
15
+ def serializer
16
+ Serializers::Invoice
17
+ end
18
+
19
+ def deserializer
20
+ Deserializers::Invoice
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ class Fiscalizer
2
+ module Fiscalizers
3
+ class Office < Base
4
+ private
5
+
6
+ def serializer
7
+ Serializers::Office
8
+ end
9
+
10
+ def deserializer
11
+ Deserializers::Office
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ class Fiscalizer
2
+ module Serializers
3
+ class Base
4
+ include Constants
5
+
6
+ def initialize(object, private_key, public_key, demo)
7
+ @object = object
8
+ @private_key = private_key
9
+ @public_key = public_key
10
+ @demo = demo
11
+ end
12
+
13
+ attr_reader :object, :private_key, :public_key, :demo
14
+
15
+ def call
16
+ sign_xml
17
+ end
18
+
19
+ private
20
+
21
+ def sign_xml
22
+ document = Xmldsig_fiscalizer::SignedDocument.new(xml_with_soap_envelope.doc.root.to_xml)
23
+ signed_xml = document.sign(private_key)
24
+ signed_xml.sub!('<?xml version="1.0"?>', '')
25
+ signed_xml = signed_xml.gsub(/^$\n/, '')
26
+ object.generated_xml = signed_xml
27
+ signed_xml
28
+ end
29
+
30
+ def xml_with_soap_envelope
31
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
32
+ xml['soapenv'].Envelope('xmlns:soapenv' => 'http://schemas.xmlsoap.org/soap/envelope/') do
33
+ xml['soapenv'].Body do
34
+ xml << raw_xml.doc.root.to_xml
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def root_hash
41
+ {
42
+ 'xmlns:tns' => TNS,
43
+ 'xmlns:xsi' => XSI,
44
+ 'xsi:schemaLocation' => SCHEMA_LOCATION,
45
+ 'Id' => message_id
46
+ }
47
+ end
48
+
49
+ def add_signature(xml)
50
+ Serializers::Signature.new(xml, "##{message_id}", public_key, cert_issuer).call
51
+ end
52
+
53
+ def cert_issuer
54
+ demo ? DEMO_CERT_ISSUER : PROD_CERT_ISSUER
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ class Fiscalizer
2
+ module Serializers
3
+ class Echo < Base
4
+ private
5
+
6
+ def message_id
7
+ 'EchoRequest'
8
+ end
9
+
10
+ def raw_xml
11
+ @raw_xml ||= begin
12
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
13
+ xml['tns'].EchoRequest(root_hash) do
14
+ xml.text object.message
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,92 @@
1
+ class Fiscalizer
2
+ module Serializers
3
+ class Invoice < Base
4
+ private
5
+
6
+ def message_id
7
+ 'RacunZahtjev'
8
+ end
9
+
10
+ def raw_xml
11
+ @raw_xml ||= begin
12
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
13
+ xml['tns'].RacunZahtjev(root_hash) do
14
+ add_header(xml)
15
+ add_body(xml)
16
+ add_signature(xml)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def add_header(xml)
23
+ xml['tns'].Zaglavlje do
24
+ xml['tns'].IdPoruke object.uuid
25
+ xml['tns'].DatumVrijeme object.time_sent_str
26
+ end
27
+ end
28
+
29
+ def add_body(xml)
30
+ xml['tns'].Racun do
31
+ add_general_invoice_info(xml)
32
+ add_invoice_number_info(xml)
33
+ add_invoice_tax_info(xml)
34
+ add_invoice_fee_info(xml)
35
+ add_invoice_summary(xml)
36
+ add_paragon_label(xml)
37
+ add_specific_purpose(xml)
38
+ end
39
+ end
40
+
41
+ def add_general_invoice_info(xml)
42
+ xml['tns'].Oib object.pin
43
+ xml['tns'].USustPdv object.in_vat_system
44
+ xml['tns'].DatVrijeme object.time_issued_str
45
+ xml['tns'].OznSlijed object.consistance_mark
46
+ end
47
+
48
+ def add_invoice_number_info(xml)
49
+ xml['tns'].BrRac do
50
+ xml['tns'].BrOznRac object.issued_number.to_s
51
+ xml['tns'].OznPosPr object.issued_office.to_s
52
+ xml['tns'].OznNapUr object.issued_machine.to_s
53
+ end
54
+ end
55
+
56
+ def add_invoice_tax_info(xml)
57
+ Serializers::Tax.new(xml, object).call
58
+ end
59
+
60
+ def add_invoice_fee_info(xml)
61
+ return if object.fees.empty?
62
+
63
+ xml['tns'].Naknade do
64
+ object.fees.each do |fee|
65
+ xml['tns'].Naknada do
66
+ xml['tns'].NazivN fee.name
67
+ xml['tns'].IznosN fee.value
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def add_invoice_summary(xml)
74
+ xml['tns'].IznosUkupno object.summed_total_str
75
+ xml['tns'].NacinPlac object.payment_method
76
+ xml['tns'].OibOper object.operator_pin
77
+ xml['tns'].ZastKod object.security_code
78
+ xml['tns'].NakDost object.subsequent_delivery
79
+ end
80
+
81
+ def add_paragon_label(xml)
82
+ return if object.paragon_label.nil?
83
+ xml['tns'].ParagonBrRac object.paragon_label
84
+ end
85
+
86
+ def add_specific_purpose(xml)
87
+ return if object.specific_purpose.nil?
88
+ xml['tns'].SpecNamj object.specific_purpose
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,85 @@
1
+ class Fiscalizer
2
+ module Serializers
3
+ class Office < Base
4
+ private
5
+
6
+ def message_id
7
+ 'PoslovniProstorZahtjev'
8
+ end
9
+
10
+ def raw_xml
11
+ @raw_xml ||= begin
12
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
13
+ xml['tns'].PoslovniProstorZahtjev(root_hash) do
14
+ add_header(xml)
15
+ add_body(xml)
16
+ add_signature(xml)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def add_header(xml)
23
+ xml['tns'].Zaglavlje do
24
+ xml['tns'].IdPoruke object.uuid
25
+ xml['tns'].DatumVrijeme object.time_sent_str
26
+ end
27
+ end
28
+
29
+ def add_body(xml)
30
+ xml['tns'].PoslovniProstor do
31
+ add_general_info(xml)
32
+ add_address_info(xml)
33
+ add_time_info(xml)
34
+ add_closure_mark(xml)
35
+ add_specific_purpose(xml)
36
+ end
37
+ end
38
+
39
+ def add_general_info(xml)
40
+ xml['tns'].Oib object.pin
41
+ xml['tns'].OznPoslProstora object.office_label
42
+ end
43
+
44
+ def add_address_info(xml)
45
+ xml['tns'].AdresniPodatak do
46
+ add_address(xml)
47
+ add_other_address(xml)
48
+ end
49
+ end
50
+
51
+ def add_address(xml)
52
+ return if object.adress_other
53
+
54
+ xml['tns'].Adresa do
55
+ xml['tns'].Ulica object.adress_street_name
56
+ xml['tns'].KucniBroj object.adress_house_num
57
+ xml['tns'].KucniBrojDodatak object.adress_house_num_addendum
58
+ xml['tns'].BrojPoste object.adress_post_num
59
+ xml['tns'].Naselje object.adress_settlement
60
+ xml['tns'].Opcina object.adress_township
61
+ end
62
+ end
63
+
64
+ def add_other_address(xml)
65
+ return if object.adress_other.nil?
66
+ xml['tns'].OstaliTipoviP object.adress_other
67
+ end
68
+
69
+ def add_time_info(xml)
70
+ xml['tns'].RadnoVrijeme object.office_time
71
+ xml['tns'].DatumPocetkaPrimjene object.take_effect_date_str
72
+ end
73
+
74
+ def add_closure_mark(xml)
75
+ return if object.closure_mark.nil?
76
+ xml['tns'].OznakaZatvaranja object.closure_mark
77
+ end
78
+
79
+ def add_specific_purpose(xml)
80
+ return if object.specific_purpose.nil?
81
+ xml['tns'].SpecNamj object.specific_purpose
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,62 @@
1
+ class Fiscalizer
2
+ module Serializers
3
+ class Signature
4
+ def initialize(xml, reference, public_key, cert_issuer)
5
+ @xml = xml
6
+ @reference = reference
7
+ @public_key = public_key
8
+ @cert_issuer = cert_issuer
9
+ end
10
+
11
+ attr_reader :xml, :reference, :public_key, :cert_issuer
12
+
13
+ def call
14
+ xml.Signature('xmlns' => 'http://www.w3.org/2000/09/xmldsig#') do
15
+ add_signed_info
16
+ add_signature_value
17
+ add_key_info
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def add_signed_info
24
+ xml.SignedInfo do
25
+ xml.CanonicalizationMethod('Algorithm' => 'http://www.w3.org/2001/10/xml-exc-c14n#')
26
+ xml.SignatureMethod('Algorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1')
27
+ xml.Reference('URI' => reference) do
28
+ xml.Transforms do
29
+ xml.Transform('Algorithm' => 'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
30
+ xml.Transform('Algorithm' => 'http://www.w3.org/2001/10/xml-exc-c14n#')
31
+ end
32
+ xml.DigestMethod('Algorithm' => 'http://www.w3.org/2000/09/xmldsig#sha1')
33
+ xml.DigestValue
34
+ end
35
+ end
36
+ end
37
+
38
+ def add_signature_value
39
+ xml.SignatureValue
40
+ end
41
+
42
+ def add_key_info
43
+ xml.KeyInfo do
44
+ xml.X509Data do
45
+ xml.X509Certificate public_key_string
46
+ xml.X509IssuerSerial do
47
+ xml.X509IssuerName cert_issuer
48
+ xml.X509SerialNumber '1053520622'
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def public_key_string
55
+ public_key.to_s
56
+ .gsub('-----BEGIN CERTIFICATE-----', '')
57
+ .gsub('-----END CERTIFICATE-----', '')
58
+ .gsub("\n", '')
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,81 @@
1
+ class Fiscalizer
2
+ module Serializers
3
+ class Tax
4
+ def initialize(xml, object)
5
+ @xml = xml
6
+ @object = object
7
+ end
8
+
9
+ attr_reader :xml, :object
10
+
11
+ def call
12
+ add_vat_tax
13
+ add_spending_tax
14
+ add_other_taxes
15
+ add_general_tax_info
16
+ end
17
+
18
+ private
19
+
20
+ def add_vat_tax
21
+ return if object.tax_vat.empty?
22
+
23
+ xml['tns'].Pdv do
24
+ object.tax_vat.each do |tax|
25
+ add_tax(tax)
26
+ end
27
+ end
28
+ end
29
+
30
+ def add_spending_tax
31
+ return if object.tax_spending.empty?
32
+
33
+ xml['tns'].Pnp do
34
+ object.tax_spending.each do |tax|
35
+ add_tax(tax)
36
+ end
37
+ end
38
+ end
39
+
40
+ def add_other_taxes
41
+ return if object.tax_other.empty?
42
+
43
+ xml['tns'].OstaliPor do
44
+ object.tax_other.each do |tax|
45
+ add_tax(tax, true)
46
+ end
47
+ end
48
+ end
49
+
50
+ def add_tax(tax, include_name = false)
51
+ xml['tns'].Porez do
52
+ xml['tns'].Naziv tax.name if include_name
53
+ xml['tns'].Stopa tax.rate_str
54
+ xml['tns'].Osnovica tax.base_str
55
+ xml['tns'].Iznos tax.total_str
56
+ end
57
+ end
58
+
59
+ def add_general_tax_info
60
+ add_tax_liberation
61
+ add_tax_margin
62
+ add_non_taxable
63
+ end
64
+
65
+ def add_tax_liberation
66
+ return if object.value_tax_liberation_str.nil?
67
+ xml['tns'].IznosOslobPdv object.value_tax_liberation_str
68
+ end
69
+
70
+ def add_tax_margin
71
+ return if object.value_tax_margin_str.nil?
72
+ xml['tns'].IznosMarza object.value_tax_margin_str
73
+ end
74
+
75
+ def add_non_taxable
76
+ return if object.value_non_taxable_str.nil?
77
+ xml['tns'].IznosNePodlOpor object.value_non_taxable_str
78
+ end
79
+ end
80
+ end
81
+ end