pagopa-soap 0.1.0

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +137 -0
  4. data/.travis.yml +14 -0
  5. data/CODE_OF_CONDUCT.md +75 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +29 -0
  8. data/README.md +229 -0
  9. data/Rakefile +13 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/diagrams/diagrammi-psp.jpg +0 -0
  13. data/diagrams/diagrammi-revoca.jpg +0 -0
  14. data/diagrams/diagrammi-wisp.jpg +0 -0
  15. data/lib/pago_pa.rb +14 -0
  16. data/lib/pago_pa/soap.rb +17 -0
  17. data/lib/pago_pa/soap/configurable.rb +38 -0
  18. data/lib/pago_pa/soap/message/domain.rb +31 -0
  19. data/lib/pago_pa/soap/message/institution.rb +42 -0
  20. data/lib/pago_pa/soap/message/payer.rb +42 -0
  21. data/lib/pago_pa/soap/message/payment.rb +61 -0
  22. data/lib/pago_pa/soap/message/rpt.rb +86 -0
  23. data/lib/pago_pa/soap/message/rt.rb +43 -0
  24. data/lib/pago_pa/soap/message/single_payment.rb +18 -0
  25. data/lib/pago_pa/soap/version.rb +8 -0
  26. data/lib/pago_pa/soap/wsdl_loader.rb +66 -0
  27. data/lib/soap.rb +126 -0
  28. data/lib/soap/parser.rb +74 -0
  29. data/lib/soap/parser/binding.rb +53 -0
  30. data/lib/soap/parser/message.rb +27 -0
  31. data/lib/soap/parser/port_type.rb +42 -0
  32. data/lib/soap/parser/service.rb +25 -0
  33. data/lib/soap/parser/types.rb +97 -0
  34. data/lib/soap/string.rb +33 -0
  35. data/lib/soap/webservice.rb +4 -0
  36. data/lib/soap/webservice/client.rb +37 -0
  37. data/lib/soap/webservice/error.rb +17 -0
  38. data/lib/soap/webservice/fault_error.rb +12 -0
  39. data/lib/soap/webservice/request.rb +118 -0
  40. data/lib/soap/webservice/response.rb +88 -0
  41. data/pagopa-soap.gemspec +45 -0
  42. data/resources/PaPerNodo.wsdl +214 -0
  43. data/resources/PaPerNodoChiediElencoAvvisiDigitali.wsdl +93 -0
  44. data/resources/PaPerNodoPagamentoPsp.wsdl +241 -0
  45. data/resources/PaPerNodoRichiestaAvvisi.wsdl +202 -0
  46. data/resources/pagopa_avvisi.wsdl +98 -0
  47. data/resources/pagopa_base.wsdl +869 -0
  48. metadata +245 -0
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PagoPA; end
4
+ module PagoPA::SOAP; end
5
+
6
+ module PagoPA::SOAP
7
+ VERSION = "0.1.0"
8
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PagoPA; end
4
+ module PagoPA::SOAP; end
5
+
6
+ class PagoPA::SOAP::WSDLLoader
7
+ attr_reader :wsdl_base
8
+ attr_reader :wsdl_notify
9
+ attr_reader :namespace
10
+
11
+ def initialize(options = {})
12
+ @wsdl_base = options[:wsdl_base] || PagoPA::SOAP.config.wsdl_base
13
+ @wsdl_notify = options[:wsdl_notify] || PagoPA::SOAP.config.wsdl_notify
14
+ @namespace = options[:namespace] || PagoPA::SOAP.config.namespace
15
+
16
+ validate_wsdl_base!
17
+ validate_wsdl_notify!
18
+ end
19
+
20
+ def build
21
+ soap_base.build
22
+ soap_notify.build
23
+ end
24
+
25
+ def requests
26
+ soap_base.request + soap_notify.request
27
+ end
28
+
29
+ def clients
30
+ soap_base.client + soap_notify.client
31
+ end
32
+
33
+ def responses
34
+ soap_base.response + soap_notify.response
35
+ end
36
+
37
+ private
38
+
39
+ def soap_base
40
+ @soap_base ||=
41
+ Soap::Base.new(
42
+ wsdl: wsdl_base,
43
+ namespace: namespace,
44
+ endpoint: PagoPA::SOAP.config.endpoint_base
45
+ )
46
+ end
47
+
48
+ def soap_notify
49
+ @soap_notify ||=
50
+ Soap::Base.new(
51
+ wsdl: wsdl_notify,
52
+ namespace: namespace,
53
+ endpoint: PagoPA::SOAP.config.endpoint_notify
54
+ )
55
+ end
56
+
57
+ def validate_wsdl_base!
58
+ raise "Error: WSDL is empty" if !@wsdl_base.instance_of?(String)
59
+ raise "Error: File not exists" if !File.exists?(@wsdl_base)
60
+ end
61
+
62
+ def validate_wsdl_notify!
63
+ raise "Error: WSDL is empty" if !@wsdl_notify.instance_of?(String)
64
+ raise "Error: File not exists" if !File.exists?(@wsdl_notify)
65
+ end
66
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+ require "gyoku"
5
+ require "nori"
6
+ require "soap/string"
7
+
8
+ # Parser
9
+ require "soap/parser"
10
+ require "soap/parser/types"
11
+ require "soap/parser/port_type"
12
+ require "soap/parser/binding"
13
+ require "soap/parser/message"
14
+ require "soap/parser/service"
15
+
16
+ # WebService
17
+ require "soap/webservice/request"
18
+ require "soap/webservice/response"
19
+ require "soap/webservice/client"
20
+ require "soap/webservice/error"
21
+ require "soap/webservice/fault_error"
22
+
23
+ module Soap
24
+ class << self
25
+ def to_snakecase(str)
26
+ Soap::String.snakecase(str)
27
+ end
28
+
29
+ def to_camelcase(str)
30
+ Soap::String.camelcase(
31
+ Soap.to_snakecase(str)
32
+ )
33
+ end
34
+
35
+ def to_wsdl_camelcase(str)
36
+ Soap::String.wsdl_camelcase(
37
+ Soap.to_snakecase(str)
38
+ )
39
+ end
40
+ end
41
+ end
42
+
43
+ class Soap::Base
44
+ SUB_CLASSES = %i[request client response].freeze
45
+ attr_reader :wsdl
46
+ attr_reader :namespace
47
+ attr_reader :endpoint
48
+
49
+ def initialize(wsdl:, namespace:, endpoint: nil)
50
+ @wsdl = wsdl
51
+ @namespace = namespace
52
+ @endpoint = endpoint
53
+ end
54
+
55
+ def build
56
+ ns_module =
57
+ if Object.const_defined?(namespace)
58
+ Object.const_get(namespace)
59
+ else
60
+ Object.const_set(namespace, Module.new)
61
+ end
62
+ parser.soap_actions.each do |action|
63
+ build_klass(ns_module, action, parser.soap_action(action), endpoint)
64
+ end
65
+ true
66
+ end
67
+
68
+ def build_klass(mod, name, action, endpoint)
69
+ service_name = parser.service[:base_endpoint]
70
+ k_mod = mod.const_set(Soap.to_camelcase(name), Module.new)
71
+ build_custom_klass(k_mod, "Request", action[:input])
72
+ build_custom_klass(k_mod, "Response", action[:output])
73
+
74
+ klass = Class.new(Soap::Webservice::Client) do
75
+ define_singleton_method :namespace do
76
+ if !endpoint.blank?
77
+ endpoint
78
+ else
79
+ service_name
80
+ end
81
+ end
82
+
83
+ define_singleton_method :action do
84
+ action[:input][:port_type][:name]
85
+ end
86
+
87
+ define_method :response do
88
+ @response ||= k_mod.const_get("Response")
89
+ end
90
+
91
+ # rubocop:disable all
92
+ private :response
93
+ # rubocop:enable all
94
+ end
95
+ k_mod.const_set("Client", klass)
96
+ end
97
+
98
+ def build_custom_klass(mod, type_klass, action_klass)
99
+ klass = Class.new(Object.const_get("Soap::Webservice::#{type_klass}")) do
100
+ define_singleton_method :body_attributes do
101
+ action_klass[:types][:body]
102
+ end
103
+
104
+ define_singleton_method :header_attributes do
105
+ action_klass[:types][:header]
106
+ end
107
+ end
108
+
109
+ mod.const_set(type_klass.to_s, klass)
110
+ end
111
+
112
+ SUB_CLASSES.each do |sub_class|
113
+ define_method(sub_class) do
114
+ name = Soap.to_camelcase(sub_class.to_s)
115
+ parser.soap_actions.map do |action|
116
+ "#{namespace}::#{Soap.to_camelcase(action)}::#{name}"
117
+ end
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ def parser
124
+ @parser ||= Soap::Parse.new(File.read(wsdl))
125
+ end
126
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soap; end
4
+ module Soap::Parser; end
5
+
6
+ class Soap::Parse
7
+ COMMON_ATTRIBUTES = %i[input output].freeze
8
+ DEFAULT_SECTIONS = %w[types message port_type binding service].freeze
9
+ attr_reader :document
10
+
11
+ def initialize(file)
12
+ @document = Nokogiri::XML(file)
13
+ end
14
+
15
+ def namespaces
16
+ @namespaces = @document.namespaces.inject({}) do |memo, (key, value)|
17
+ memo[key.sub("xmlns:", "")] = value
18
+ memo
19
+ end
20
+ end
21
+
22
+ DEFAULT_SECTIONS.each do |sec|
23
+ define_method(sec.to_sym) do
24
+ sec_klass = Object.const_get("Soap::Parser::#{Soap.to_camelcase(sec)}")
25
+ sec_result = sec_klass.new(namespaces, section(sec))
26
+ sec_result.parse
27
+ sec_result.hash
28
+ end
29
+ end
30
+
31
+ def soap_actions
32
+ port_type.keys.map do |pt|
33
+ pt
34
+ end
35
+ end
36
+
37
+ def soap_action(name)
38
+ Soap::Parse::COMMON_ATTRIBUTES.each.with_object({}) do |common, attrs|
39
+ attrs[common] = {
40
+ port_type: port_type[name][common],
41
+ binding: binding[:operations][name][common],
42
+ message: message[port_type[name][common][:message].split(":").last],
43
+ types: extract_types_attribute(name, common)
44
+ }
45
+ end
46
+ end
47
+
48
+ def extract_types_attribute(name, io)
49
+ msg_name = port_type[name][io][:message].split(":").last
50
+ components = binding[:operations][name][io]
51
+ ext = {}
52
+ components.map do |k, v|
53
+ component = message[msg_name][:part]
54
+ if v[:part].nil? && v[:parts].nil?
55
+ namespace, params = component.values.first.split(":")
56
+ else
57
+ namespace, params = component[v[:part] || v[:parts]].split(":")
58
+ end
59
+ ext[k.to_sym] = types[namespace][params][:params]
60
+ end
61
+ ext
62
+ end
63
+
64
+ def section(section_name)
65
+ sections[section_name] || []
66
+ end
67
+
68
+ def sections
69
+ @sections ||=
70
+ @document.root.element_children.each.with_object({}) do |node, attrs|
71
+ (attrs[Soap.to_snakecase(node.name)] ||= []) << node
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soap; end
4
+ module Soap::Parser; end
5
+
6
+ class Soap::Parser::Binding
7
+ COMPONENT_ATTRIBUTES = %i[part parts message].freeze
8
+ attr_accessor :hash
9
+ attr_reader :node
10
+
11
+ def initialize(_namespaces, node)
12
+ @node = node
13
+ @hash = {}
14
+ end
15
+
16
+ def parse
17
+ parse_binding
18
+ end
19
+
20
+ def parse_binding
21
+ return if @node.empty? && @node.first.nil?
22
+ binding_node = @node.first
23
+
24
+ @hash[:name] = binding_node["name"]
25
+ @hash[:type] = binding_node["type"]
26
+ operations = Hash[binding_node.xpath("./wsdl:operation").map do |operation|
27
+ [operation["name"], {
28
+ input: parse_input_output(operation, "input"),
29
+ output: parse_input_output(operation, "output")
30
+ }]
31
+ end]
32
+ @hash[:operations] = operations
33
+ end
34
+
35
+ def parse_input_output(node, type)
36
+ type_node = node.element_children.find { |ec| ec.name == type }
37
+
38
+ Hash[type_node.element_children.map do |elem|
39
+ [elem.name, parse_attribute(elem)]
40
+ end]
41
+ end
42
+
43
+ def parse_attribute(node)
44
+ attributes =
45
+ COMPONENT_ATTRIBUTES.each.with_object({}) do |attr, attrs|
46
+ value = node.attribute(attr.to_s)
47
+ attrs[attr] = value.to_s if value
48
+ end
49
+ attributes[:name] = node.parent["name"]
50
+
51
+ attributes
52
+ end
53
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soap; end
4
+ module Soap::Parser; end
5
+
6
+ class Soap::Parser::Message
7
+ attr_accessor :hash
8
+ attr_reader :node
9
+
10
+ def initialize(_namespaces, node)
11
+ @node = node
12
+ @hash = {}
13
+ end
14
+
15
+ def parse
16
+ parse_message
17
+ end
18
+
19
+ def parse_message
20
+ @hash = Hash[@node.map do |node|
21
+ [node["name"], Hash[:part, Hash[node.element_children.map do |mec|
22
+ [mec["name"], mec.attribute("element").value]
23
+ end
24
+ ]]]
25
+ end]
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soap; end
4
+ module Soap::Parser; end
5
+
6
+ class Soap::Parser::PortType
7
+ attr_accessor :hash
8
+ attr_reader :node
9
+
10
+ def initialize(_namespaces, node)
11
+ @node = node
12
+ @hash = {}
13
+ end
14
+
15
+ def parse
16
+ parse_port_types
17
+ end
18
+
19
+ def parse_port_types
20
+ return if @node.empty? && @node.first.nil?
21
+ node_elements =
22
+ node.first.element_children.select do |op|
23
+ op.name == "operation"
24
+ end
25
+
26
+ @hash = Hash[node_elements.map do |operation|
27
+ [operation["name"], {
28
+ input: parse_input_or_output(operation, "input"),
29
+ output: parse_input_or_output(operation, "output")
30
+ }]
31
+ end]
32
+ end
33
+
34
+ def parse_input_or_output(node, type)
35
+ node_type = node.element_children.find { |n| n.name == type }
36
+ {
37
+ name: node_type.attribute("message").to_s.split(":").last,
38
+ message: node_type.attribute("message").to_s,
39
+ action: node_type.attribute("Action").to_s
40
+ }
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soap; end
4
+ module Soap::Parser; end
5
+
6
+ class Soap::Parser::Service
7
+ attr_accessor :hash
8
+ attr_reader :node
9
+
10
+ def initialize(_namespaces, node)
11
+ @node = node
12
+ @hash = {}
13
+ end
14
+
15
+ def parse
16
+ parse_service
17
+ end
18
+
19
+ def parse_service
20
+ address = node.first.at_xpath("./wsdl:port/soap:address")
21
+ @hash = {
22
+ base_endpoint: address["location"]
23
+ }
24
+ end
25
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soap; end
4
+ module Soap::Parser; end
5
+
6
+ class Soap::Parser::Types
7
+ VALIDATION_ATTRIBUTES = %i[nillable default minOccurs maxOccurs].freeze
8
+
9
+ attr_accessor :hash
10
+ attr_reader :node
11
+ attr_reader :namespaces
12
+
13
+ def initialize(namespaces, node)
14
+ @namespaces = namespaces
15
+ @node = node
16
+ @hash = {}
17
+ end
18
+
19
+ def parse
20
+ parse_types
21
+ end
22
+
23
+ def parse_types
24
+ schemas.each do |schema|
25
+ namespace = @namespaces.key(schema["targetNamespace"])
26
+ @hash[namespace] = {}
27
+ schema.element_children.each do |node|
28
+ case node.name
29
+ when "element"
30
+ if !node.children.empty?
31
+ node_type = node.at_xpath("./xsd:complexType")
32
+ else
33
+ complex_type = node.attribute("type").to_s
34
+ node_type = schema.at_xpath(
35
+ "xsd:complexType[@name='#{complex_type.split(':').last}']"
36
+ )
37
+ end
38
+ @hash[namespace].merge!(parse_type(node_type, node["name"]))
39
+ when "complexType"
40
+ @hash[namespace].merge!(parse_type(node, node["name"]))
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def simple_type
47
+ { "base" => @node.at_xpath("./xs|xsd:restriction")["base"] }
48
+ end
49
+
50
+ # rubocop:disable all
51
+ def parse_type(node, name)
52
+ element = {}
53
+ element[name] ||= { params: [] }
54
+ node.xpath("./xsd:complexContent/xsd:extension/xsd:sequence/xsd:element").each do |inner|
55
+ elem_name = inner.attribute("name").to_s
56
+ elem_type = inner.attribute("type").to_s
57
+ elem_attributes =
58
+ VALIDATION_ATTRIBUTES.each.with_object({}) do |attr, attrs|
59
+ value = inner.attribute(attr.to_s)
60
+ attrs[attr] = value.to_s if value
61
+ end
62
+
63
+ element[name][:params] << {
64
+ name: elem_name,
65
+ type: elem_type,
66
+ attributes: elem_attributes
67
+ }
68
+ end
69
+
70
+ node.xpath("./xsd:sequence/xsd:element").each do |inner|
71
+ elem_name = inner.attribute("name").value
72
+ elem_type = inner.attribute("type").value
73
+ elem_attributes =
74
+ VALIDATION_ATTRIBUTES.each.with_object({}) do |attr, attrs|
75
+ value = inner.attribute(attr.to_s)
76
+ attrs[attr] = value.to_s if value
77
+ end
78
+
79
+ element[name][:params] << {
80
+ name: elem_name,
81
+ type: elem_type,
82
+ attributes: elem_attributes
83
+ }
84
+ end
85
+
86
+ element
87
+ end
88
+ # rubocop:enable all
89
+
90
+ private
91
+
92
+ def schemas
93
+ return [] if @node.empty? && @node.first.nil?
94
+ types = @node.first
95
+ types ? types.element_children : []
96
+ end
97
+ end