Class: ToQbxml

Inherits:
Object
  • Object
show all
Defined in:
lib/to_qbxml/version.rb,
lib/to_qbxml/to_qbxml.rb

Constant Summary collapse

VERSION =
"1.0.2"
ACRONYMS =
[/Ap\z/, /Ar/, /Cogs/, /Com\z/, /Uom/, /Qbxml/, /Ui/, /Avs/, /Id\z/,
/Pin/, /Ssn/, /Clsid/, /Fob/, /Ein/, /Uom/, /Po\z/, /Pin/, /Qb/]
ATTR_ROOT =
'xml_attributes'.freeze
IGNORED_KEYS =
[ATTR_ROOT]
REPEATABLE_KEY =
'Repeat'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash, options = {}) ⇒ ToQbxml

Returns a new instance of ToQbxml.



8
9
10
11
12
13
# File 'lib/to_qbxml/to_qbxml.rb', line 8

def initialize(hash, options = {})
  @hash = hash
  @options = options
  @version = ToQbxml.version
  @on_error = ToQbxml.on_error
end

Class Method Details

.configure {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:

  • _self (ToQbxml)

    the object that the method was called on



15
16
17
# File 'lib/to_qbxml/to_qbxml.rb', line 15

def self.configure(&block)
  yield self
end

.on_errorObject



27
28
29
# File 'lib/to_qbxml/to_qbxml.rb', line 27

def self.on_error
  @on_error ||= 'stopOnError' 
end

.on_error=(err_kind) ⇒ Object



31
32
33
# File 'lib/to_qbxml/to_qbxml.rb', line 31

def self.on_error=(err_kind)
  @on_error = err_kind
end

.versionObject



19
20
21
# File 'lib/to_qbxml/to_qbxml.rb', line 19

def self.version
  @version ||= '7.0' 
end

.version=(number) ⇒ Object



23
24
25
# File 'lib/to_qbxml/to_qbxml.rb', line 23

def self.version=(number)
  @version = number
end

Instance Method Details

#boilerplate(type, opts = {}) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/to_qbxml/to_qbxml.rb', line 108

def boilerplate(type, opts = {})
  head = boilerplate_header(type, opts[:action] || 'add')
  body_hash = opts[:action] == :query ? @hash : { head => @hash }
  {  :qbxml_msgs_rq =>
     [
       {
         :xml_attributes =>  { "onError" => opts[:on_error] || @on_error},
         head + '_rq' =>
         [
           {
             :xml_attributes => { "requestID" => "#{opts[:request_id] || 1}" }.merge(opts[:attrs] || {})
           }.merge(body_hash)
         ]
       }
     ]
  }
end

#boilerplate_header(type, action) ⇒ Object



104
105
106
# File 'lib/to_qbxml/to_qbxml.rb', line 104

def boilerplate_header(type, action)
  "#{type}_#{action}"
end

#convert_to_qbxml_hashObject

Transforms to QBXML camelcase e.g. :first_name = FirstName There are also special cases handled within ACRONYMS e.g. :list_id = ListID | != ListId



54
55
56
57
# File 'lib/to_qbxml/to_qbxml.rb', line 54

def convert_to_qbxml_hash
  key_proc = lambda { |k| k.camelize.gsub(Regexp.union(ACRONYMS)) { |val| val.upcase }}
  deep_convert(@hash, &key_proc)
end

#generateObject



40
41
42
43
44
45
# File 'lib/to_qbxml/to_qbxml.rb', line 40

def generate
  @hash = convert_to_qbxml_hash
  xml = hash_to_xml(@hash, @options)
  handler = xml_handler(xml)
  @options[:doc] ? handler : handler.to_xml(encoding: 'US-ASCII')
end

#hash_to_xml(hash, opts = {}) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/to_qbxml/to_qbxml.rb', line 73

def hash_to_xml(hash, opts = {})
  opts = opts.dup
  opts[:indent]          ||= 0
  opts[:root]            ||= :QBXML
  opts[:version]         ||= @version
  opts[:attributes]      ||= (hash.delete(ATTR_ROOT) || {})
  opts[:builder]         ||= Builder::XmlMarkup.new(indent: opts[:indent])
  opts[:skip_types]      = true unless opts.key?(:skip_types) 
  opts[:skip_instruct]   = false unless opts.key?(:skip_instruct)
  builder = opts[:builder]

  unless opts.delete(:skip_instruct)
    builder.instruct!(:qbxml, version: opts[:version])
  end

  builder.tag!(opts[:root], opts.delete(:attributes)) do
    hash.each do |key, val|
      case val
      when Hash
        self.hash_to_xml(val, opts.merge({root: key, skip_instruct: true}))
      when Array
        val.map { |i| self.hash_to_xml(i, opts.merge({root: key, skip_instruct: true})) }
      else
        builder.tag!(key, val, {})
      end
    end

    yield builder if block_given?
  end
end

#make(type, boilerplate_options = {}) ⇒ Object



35
36
37
38
# File 'lib/to_qbxml/to_qbxml.rb', line 35

def make(type, boilerplate_options = {})
  @hash = boilerplate(type, boilerplate_options)
  generate
end

#remove_tags_preserve_content(doc, name) ⇒ Object

Removes the parent Repeat node intended for repeatable nodes like InvoiceLineAdd



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/to_qbxml/to_qbxml.rb', line 61

def remove_tags_preserve_content(doc, name)
  doc.xpath(".//#{name}").reverse.each do |element|
    element.children.reverse.each do |child|
      child_clone = child.clone
      element.add_next_sibling child_clone
      child.unlink
    end
    element.unlink
  end
  doc
end

#xml_handler(xml) ⇒ Object



47
48
49
50
# File 'lib/to_qbxml/to_qbxml.rb', line 47

def xml_handler(xml)
  doc = Nokogiri.XML(xml)
  remove_tags_preserve_content(doc, REPEATABLE_KEY)
end