clearbooks 0.16.3

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS.md +31 -0
  3. data/CHANGELOG.md +0 -0
  4. data/COPYING.md +12 -0
  5. data/FAQ.md +8 -0
  6. data/Gemfile +105 -0
  7. data/LICENSE.md +14 -0
  8. data/MAINTAINERS.md +40 -0
  9. data/README.md +549 -0
  10. data/Rakefile +94 -0
  11. data/Thorfile +80 -0
  12. data/bin/clearbooks +28 -0
  13. data/clearbooks.gemspec +119 -0
  14. data/examples/demo.rb +8 -0
  15. data/lib/clearbooks.rb +92 -0
  16. data/lib/clearbooks/core_ext.rb +8 -0
  17. data/lib/clearbooks/core_ext/array.rb +51 -0
  18. data/lib/clearbooks/core_ext/hash.rb +47 -0
  19. data/lib/clearbooks/core_ext/io_binary_read.rb +20 -0
  20. data/lib/clearbooks/core_ext/string.rb +21 -0
  21. data/lib/clearbooks/error.rb +8 -0
  22. data/lib/clearbooks/error/errors.rb +228 -0
  23. data/lib/clearbooks/interface/rake/cucumber.rb +36 -0
  24. data/lib/clearbooks/interface/rake/default.rb +28 -0
  25. data/lib/clearbooks/interface/rake/documentation.rb +45 -0
  26. data/lib/clearbooks/interface/rake/guard.rb +13 -0
  27. data/lib/clearbooks/interface/rake/helpers.rb +27 -0
  28. data/lib/clearbooks/interface/rake/library.rb +126 -0
  29. data/lib/clearbooks/interface/rake/metric.rb +15 -0
  30. data/lib/clearbooks/interface/rake/rspec.rb +31 -0
  31. data/lib/clearbooks/interface/thor/info.thor +292 -0
  32. data/lib/clearbooks/interface/thor/mixin/config_choice.rb +27 -0
  33. data/lib/clearbooks/interface/thor/mixin/configuration.rb +28 -0
  34. data/lib/clearbooks/interface/thor/mixin/default.rb +30 -0
  35. data/lib/clearbooks/interface/thor/mixin/default_config.rb +31 -0
  36. data/lib/clearbooks/interface/thor/mixin/guess.rb +57 -0
  37. data/lib/clearbooks/interface/thor/mixin/shell.rb +225 -0
  38. data/lib/clearbooks/interface/thor/version.thor +34 -0
  39. data/lib/clearbooks/library/client.rb +257 -0
  40. data/lib/clearbooks/library/configuration.rb +34 -0
  41. data/lib/clearbooks/model/account_code.rb +65 -0
  42. data/lib/clearbooks/model/base.rb +67 -0
  43. data/lib/clearbooks/model/entity.rb +225 -0
  44. data/lib/clearbooks/model/invoice.rb +163 -0
  45. data/lib/clearbooks/model/item.rb +78 -0
  46. data/lib/clearbooks/model/journal.rb +74 -0
  47. data/lib/clearbooks/model/ledger.rb +52 -0
  48. data/lib/clearbooks/model/payment.rb +113 -0
  49. data/lib/clearbooks/model/project.rb +58 -0
  50. data/lib/clearbooks/version.rb +12 -0
  51. data/spec/clearbooks/clearbooks_spec.rb +27 -0
  52. data/spec/clearbooks/model/account_code_spec.rb +52 -0
  53. data/spec/clearbooks/model/entity_spec.rb +107 -0
  54. data/spec/clearbooks/model/invoice_spec.rb +109 -0
  55. data/spec/clearbooks/model/journal_spec.rb +77 -0
  56. data/spec/clearbooks/model/payment_spec.rb +103 -0
  57. data/spec/clearbooks/model/project_spec.rb +72 -0
  58. data/spec/fixtures/response/allocate_payment.xml +12 -0
  59. data/spec/fixtures/response/create_entity.xml +12 -0
  60. data/spec/fixtures/response/create_invoice.xml +11 -0
  61. data/spec/fixtures/response/create_journal.xml +12 -0
  62. data/spec/fixtures/response/create_payment.xml +12 -0
  63. data/spec/fixtures/response/create_project.xml +12 -0
  64. data/spec/fixtures/response/delete_entity.xml +12 -0
  65. data/spec/fixtures/response/delete_journal.xml +12 -0
  66. data/spec/fixtures/response/list_account_codes.xml +168 -0
  67. data/spec/fixtures/response/list_entities.xml +45 -0
  68. data/spec/fixtures/response/list_invoices.xml +56 -0
  69. data/spec/fixtures/response/list_projects.xml +16 -0
  70. data/spec/fixtures/response/no_api_key_fault.xml +8 -0
  71. data/spec/fixtures/response/well_formed_request.xml +10 -0
  72. data/spec/fixtures/response/wrong_api_key_fault.xml +8 -0
  73. data/spec/spec_helper.rb +26 -0
  74. metadata +212 -0
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # @module module Mixin
4
+ # @brief Mixin module contains various functions to be used in other components
5
+ module Mixin
6
+
7
+ # @module ConfigChoice Module
8
+ # @brief Module wrapper around ConfigChoice tasks
9
+ module ConfigChoice
10
+
11
+ def config_choice
12
+ defaults = YAML.load_file(File.expand_path( File.dirname( __FILE__ ) + '/../../../template/default_values.yml'))
13
+ defaults['clearbooks'].each_key { |key| choice_option(defaults['clearbooks'], key) }
14
+ defaults
15
+ end
16
+
17
+ private def choice_option(defaults, option)
18
+ print ("%s (%s): " % [option, defaults[option]])
19
+ value = STDIN.gets.chomp
20
+ defaults[option] = value unless value.empty?
21
+ end
22
+ end # of module ConfigChoice
23
+
24
+ end # of module Mixin
25
+
26
+
27
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ # @module module Mixin
5
+ # @brief Mixin module contains various functions to be used in other components
6
+ module Mixin
7
+
8
+ # @module Configuration Module
9
+ # @brief Module wrapper around tasks which demands config file
10
+ module Configuration
11
+
12
+ # @fn def initialize *args {{{
13
+ # @brief Default constructor
14
+ #
15
+ # @param [Array] args Argument array
16
+ def initialize *args
17
+ super
18
+ unless File.exist?("~/.clearbooks/config.yaml")
19
+ abort("Could not find configuration file in ~/clearbooks/config.yaml. Please run 'clearbooks config:generate' to generate it.")
20
+ end
21
+ end # }}}
22
+
23
+ end # of module Configuration
24
+
25
+ end # of module Mixin
26
+
27
+
28
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ # System includes
5
+ require 'thor'
6
+ require 'andand'
7
+
8
+
9
+ # @module module Mixin
10
+ # @brief Mixin module contains various functions to be used in other components
11
+ module Mixin
12
+
13
+ # @module Default Module
14
+ # @brief Module wrapper around default tasks
15
+ module Default
16
+
17
+ # @fn def initialize *args {{{
18
+ # @brief Default constructor
19
+ #
20
+ # @param [Array] args Argument array
21
+ def initialize *args
22
+ super
23
+ end # }}}
24
+
25
+ end # of module Default
26
+
27
+ end # of module Mixin
28
+
29
+
30
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Custom includes
4
+ require File.expand_path( File.dirname( __FILE__ ) + '/config_choice' )
5
+
6
+ # @module module Mixin
7
+ # @brief Mixin module contains various functions to be used in other components
8
+ module Mixin
9
+
10
+ # @module DefaultConfig Module
11
+ # @brief Module wrapper around default tasks
12
+ module DefaultConfig
13
+
14
+ # Include various partials
15
+ include ::Mixin::ConfigChoice
16
+
17
+ def defaults
18
+ config_path = File.expand_path( '~/.clearbooks/config.yml' )
19
+ if File.exists?(config_path)
20
+ YAML.load_file(config_path)
21
+ else
22
+ FileUtils.mkdir_p( File.expand_path( '~/.clearbooks' ) )
23
+ config_choice
24
+ end
25
+ end
26
+ end # of module DefaultConfig
27
+
28
+ end # of module Mixin
29
+
30
+
31
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ # System includes
5
+ require 'andand'
6
+
7
+
8
+ # @module module Mixin
9
+ # @brief Mixin module contains various functions to be used in other components
10
+ module Mixin
11
+
12
+ # @module Guess Module
13
+ # @brief Module wrapper around guess tasks to extract version numbers etc
14
+ module Guess
15
+
16
+ # @fn def initialize *args {{{
17
+ # @brief Default constructor
18
+ #
19
+ # @param [Array] args Argument array
20
+ def initialize *args
21
+ super
22
+ end # }}}
23
+
24
+ # @fn def guess_version string {{{
25
+ # @brief Guess version from full version string
26
+ #
27
+ # @example e.g. "ruby 2.1.1p76 (2014-02-24 revision 45161) [i686-linux]"
28
+ # -> 2.1.1
29
+ #
30
+ # "rake, version 10.1.1"
31
+ # -> 10.1.1
32
+ def guess_version string
33
+
34
+ result = ""
35
+
36
+ begin
37
+
38
+ # Sanity
39
+ raise ArgumentError, "Version has to be of type string" unless( string.is_a?( String ) )
40
+ raise ArgumentError, "Version can't be empty" if( string.empty? )
41
+
42
+ result = string.match( /\d+\.\d+\.\d+/ ).to_s # matches first only
43
+
44
+ rescue Exception => e
45
+ say "(EE) " + e.message, :red
46
+ result = ""
47
+ end
48
+
49
+ return result
50
+ end # }}}
51
+
52
+ end # of Module Guess
53
+
54
+ end # of module Mixin
55
+
56
+
57
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ # System includes
5
+ require 'andand'
6
+ require 'ptools'
7
+ require 'tempfile'
8
+
9
+ # Custom includes
10
+ require File.expand_path( File.dirname( __FILE__ ) + '/guess' )
11
+
12
+
13
+ # @module module Mixin
14
+ # @brief Mixin module contains various functions to be used in other components
15
+ module Mixin
16
+
17
+ # @module Shell Module
18
+ # @brief Module wrapper around shell commands
19
+ module Shell
20
+
21
+ include ::Mixin::Guess
22
+
23
+ # @fn def initialize *args {{{
24
+ # @brief Default constructor
25
+ #
26
+ # @param [Array] args Argument array
27
+ def initialize *args
28
+ super
29
+ end # }}}
30
+
31
+ ## Actions
32
+
33
+ # @fn def run command {{{
34
+ # @brief Run the given command gracefully (without throwing exceptions)
35
+ #
36
+ # @param [String] command The command to run
37
+ # @param [RegExp] regexp Optional regular expression used for matching output
38
+ #
39
+ # @return [String] Returns empty string if command not found or other problem,
40
+ # otherwise result of command.
41
+ def run command, regexp = nil
42
+
43
+ result = ''
44
+
45
+ begin
46
+ if( regexp.nil? )
47
+ result = execute( command ).strip
48
+ else
49
+ raise ArgumentError, 'Regular Expression input needs to be of type Regexp' unless( regexp.is_a?( Regexp ) )
50
+
51
+ result = execute( command ).andand.send( :match, regexp ).andand.send( :to_s ).strip
52
+ end
53
+
54
+ rescue Exception => e
55
+ say '(EE) ' + e.message, :red
56
+ result = ''
57
+ end
58
+
59
+ return result
60
+ end # }}}
61
+
62
+ # @fn def execute command {{{
63
+ # @brief Execute single shell command
64
+ #
65
+ # @param [String] command Shell command string with arguments
66
+ #
67
+ # @return [String] Returns result of command
68
+ #
69
+ # @throws [ArgumentError] Throws exception if command not found
70
+ def execute command
71
+
72
+ exists = which( command )
73
+ raise ArgumentError, "Command not found" unless( exists )
74
+ result = `#{command}`
75
+
76
+ return result
77
+ end # }}}
78
+
79
+ # @fn def which command {{{
80
+ # @brief Checks if command is available
81
+ #
82
+ # @param [String] command Shell command string with or without arguments.
83
+ # If arguments are given, they are split on first
84
+ # whitespace and discarded
85
+ #
86
+ # @return [Boolean] Returns boolean true if command is available, false if not
87
+ #
88
+ #
89
+ # @info Crude alternative: `#{command} 2>/dev/null`.strip.empty?
90
+ def which command
91
+ result = false
92
+
93
+ begin
94
+ partial = command.to_s
95
+ partial = partial.split(' ').first.to_s if( partial =~ %r{ }i )
96
+ path = File.which( partial )
97
+
98
+ result = true unless( path.nil? )
99
+ rescue Exception => e
100
+ say "(EE) " + e.message, :red
101
+ result = false
102
+ end
103
+
104
+ return result
105
+ end # }}}
106
+
107
+ # @fn def version command {{{
108
+ # @brief Prints the version of given command, if command exists
109
+ #
110
+ # @param [String] command Command string to probe version for, e.g. ruby
111
+ #
112
+ # @return [String] Returns version string or empty if command not found / error
113
+ def version command
114
+
115
+ result = ""
116
+
117
+ begin
118
+
119
+ # Sanity
120
+ raise ArgumentError, "Command not found" unless( which( command ) )
121
+
122
+ # Get usage help screen for command
123
+ help = usage( command )
124
+
125
+ # Get version flag from help screen
126
+ flag = version_flag( help )
127
+
128
+ return result if( flag.empty? ) # some stupid commands don't follow standard rules, e.g. bundle
129
+
130
+ # Get actual version string
131
+ banner = run( command + " " + flag )
132
+
133
+ # Guess way to extract and extract semver
134
+ result = guess_version( banner.to_s )
135
+
136
+ rescue Exception => e
137
+ say "(EE) " + e.message, :red
138
+ result = ""
139
+ end
140
+
141
+ return result
142
+ end # }}}
143
+
144
+
145
+ alias_method :exists?, :which
146
+
147
+ private
148
+
149
+ # @fn def usage command {{{
150
+ # @brief Extracts help/usage screen from command
151
+ #
152
+ # @param [String] command Command string
153
+ #
154
+ # @return [String Result screen output string
155
+ def usage command
156
+
157
+ result = ""
158
+
159
+ begin
160
+
161
+ # Some commands misbehave when using wrong arguments
162
+ # e.g. java
163
+ help = []
164
+
165
+ # Collect all possible outputs
166
+ %w(--help -h -help).each do |argument|
167
+ tempfile = Tempfile.new( "clearbooks-" )
168
+ `#{command} #{argument} > #{tempfile.path.to_s} 2>&1`
169
+ help << File.read( tempfile.path )
170
+ end
171
+
172
+ # Prune to relevent one
173
+ help.each do |h|
174
+
175
+ # Sanity
176
+ next if( h.strip.empty? )
177
+ next if( h.split( "\n" ).length < 4 )
178
+ next unless( h.match( /unknown/i ).to_s.empty? ) # does it contain unknown? (argument)
179
+ next unless( h.match( /unrecognized/i ).to_s.empty? ) # does it contain unrecognized? (argument)
180
+ next unless( h.match( /error/i ).to_s.empty? ) # does it contain error
181
+ next unless( h.match( /does not exist/i ).to_s.empty? ) # does not exist error
182
+ next unless( result.empty? )
183
+
184
+ result = h
185
+
186
+ end # of help.each
187
+
188
+
189
+ rescue Exception => e
190
+ say "(EE) " + e.message, :red
191
+ result = ""
192
+ end
193
+
194
+ return result
195
+ end # }}}
196
+
197
+ # @fn def version_flag usage {{{
198
+ # @brief Extracts version flag from usage help screen of command
199
+ #
200
+ # @param [String] usage Usage help screen output (string), e.g. ruby --help
201
+ #
202
+ # @return [String] Returns the string which according to help screen will print version
203
+ # e.g. -version for java
204
+ def version_flag usage
205
+
206
+ result = ""
207
+
208
+ begin
209
+ result = usage.match( /--version/i ).to_s
210
+ result = usage.match( /-version/i ).to_s if( result.empty? )
211
+ rescue Exception => e
212
+ say "(EE) " + e.message, :red
213
+ result = ""
214
+ end
215
+
216
+ return result
217
+ end # }}}
218
+
219
+ end # of Module Shell
220
+
221
+ end # of module Mixin
222
+
223
+
224
+
225
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'clearbooks/version'
4
+
5
+ # @class Server command class
6
+ # @brief Implements the server command
7
+ class Version < Thor
8
+
9
+ default_task :show
10
+
11
+ ## API
12
+
13
+ # @fn def show {{{
14
+ # @brief Show version string of app
15
+ desc 'show', 'Show version of this app'
16
+ def show
17
+ version = Clearbooks::VERSION
18
+
19
+ puts version
20
+ end # }}}
21
+
22
+
23
+ private
24
+
25
+ no_tasks do
26
+
27
+ ## Actions
28
+
29
+ end # of no_tasks do
30
+
31
+ end # of Class Version
32
+
33
+
34
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # System include
4
+ require 'savon'
5
+
6
+
7
+ # @module Clearbooks
8
+ # @brief Handles Ruby idomatic expression of Clear Books SOAP API
9
+ module Clearbooks
10
+
11
+ # @class Clearbooks SOAP client {{{
12
+ # @brief interacts with Clearbooks API via Savon
13
+ #
14
+ # @note You should not use it directly. Use static methods in Clearbooks module instead.
15
+ # @example Clearbooks.list_invoices
16
+ # Clearbooks.create_entity(Clearbooks::Entity.new(...))
17
+ #
18
+ class Client
19
+
20
+ extend Savon::Model
21
+
22
+ client wsdl: Clearbooks.config.wsdl,
23
+ log: Clearbooks.config.log,
24
+ logger: Clearbooks.config.logger,
25
+ soap_header: { 'tns:authenticate' => '', attributes!: {'tns:authenticate' => { apiKey: Clearbooks.config.api_key } } }
26
+
27
+ operations :create_invoice, :list_invoices, :create_entity, :list_entities, :delete_entity,
28
+ :create_project, :list_projects, :list_account_codes, :create_journal,
29
+ :delete_journal, :create_payment, :allocate_payment
30
+
31
+
32
+ # @fn def list_invoices {{{
33
+ # @brief Get list of invoices from Clearbooks API
34
+ #
35
+ # @param [Hash] query Hash of options to filter invoices. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/listinvoices/
36
+ #
37
+ # @return [Array, Invoice] An array or invoices.
38
+ #
39
+ # @example Clearbooks.list_invoices
40
+ #
41
+ def list_invoices query = {}
42
+ defaults = { ledger: :sales }
43
+ query = defaults.merge(query)
44
+ response = super message: {query: '', attributes!: {query: query}}
45
+ response = response.to_hash
46
+ Invoice.build response[:list_invoices_response][:create_invoices_return][:invoice]
47
+ end # }}}
48
+
49
+ # @fn def create_invoice {{{
50
+ # @brief Creates invoice via Clearbooks API.
51
+ #
52
+ # @param [Invoice] invoice An invoice to be created. See the list of available options in official API docs: https://www.clearbooks.co.uk/support/api/docs/soap/createinvoice/
53
+ #
54
+ # @return [Hash] [:due, :invoice_id, :invoice_prefix, :invoice_number] according to official API docs.
55
+ #
56
+ # @example
57
+ # Clearbooks.create_invoice Clearbooks::Invoice.new(date_created: Date.today,
58
+ # credit_terms: 30,
59
+ # entity_id: 1,
60
+ # type: 'purchases',
61
+ # items: [
62
+ # Clearbooks::Item.new(description: 'abcd', unit_price: 10,
63
+ # quantity: 5, type: '1001001', vat: 0, vat_rate: '0.00:Out')
64
+ # ])
65
+ #
66
+ def create_invoice invoice
67
+ response = super message: invoice.to_savon
68
+ response = response.to_hash
69
+ response = response[:create_invoice_response][:create_invoice_return]
70
+ {
71
+ due: BigDecimal.new(response[:@due]),
72
+ invoice_id: response[:@invoice_id].to_i,
73
+ invoice_prefix: response[:@invoice_prefix],
74
+ invoice_number: response[:@invoice_number]
75
+ }
76
+ end # }}}
77
+
78
+ # @fn def create_entity {{{
79
+ # @brief Creates entity via Clearbooks API
80
+ #
81
+ # @param [Entity] entity An entity to be created. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/createentity/
82
+ #
83
+ # @return [Hash] [:entity_id] ID of the created entity.
84
+ #
85
+ # @example
86
+ # Clearbooks.create_entity Clearbooks::Entity.new(company_name: 'DataLogic',
87
+ # contact_name: 'Oleg Kukareka',
88
+ # address1: 'Kiev',
89
+ # country: 'UA',
90
+ # postcode: '04073',
91
+ # email: 'info@datalogic.co.uk',
92
+ # website: 'https://datalogic.co.uk',
93
+ # phone1: '01234 567890',
94
+ # supplier: {
95
+ # default_account_code: '1001001',
96
+ # default_credit_terms: 30,
97
+ # default_vat_rate: 0
98
+ # })
99
+ #
100
+ def create_entity entity
101
+ response = super message: entity.to_savon
102
+ response = response.to_hash
103
+ { entity_id: response[:create_entity_response][:create_entity_return].to_i }
104
+ end # }}}
105
+
106
+ # @fn def list_entities {{{
107
+ # @brief Get list of entities from Clearbooks API.
108
+ # @param [Hash] query Hash of options to filter entities. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/list-entities/
109
+ # @return [Array, Entity] An array or entities.
110
+ # @example
111
+ # Clearbooks.list_entities
112
+ def list_entities query = {}
113
+ attributes = {query: query.except(:id)}
114
+ response = super message: {query: {id: query[:id]}, attributes!: attributes}
115
+ response = response.to_hash
116
+ Entity.build response[:list_entities_response][:entities][:entity]
117
+ end # }}}
118
+
119
+ # @fn def delete_entity {{{
120
+ # @brief Deletes entity via Clearbooks API.
121
+ #
122
+ # @param [Fixnum] entity_id Id of the entity to be deleted. See official docs: https://www.clearbooks.co.uk/support/api/docs/soap/deleteentity/
123
+ #
124
+ # @return [Boolean] True if the request was successful, otherwise false.
125
+ #
126
+ # @example
127
+ # Clearbooks.delete_entity 10
128
+ #
129
+ def delete_entity entity_id
130
+ response = super message: {entityId: entity_id}
131
+ response = response.to_hash
132
+ response[:delete_entity_response][:delete_entity_success]
133
+ end # }}}
134
+
135
+ # @fn def create_project {{{
136
+ # @brief Creates project via Clearbooks API.
137
+ #
138
+ # @param [Project] project A project to be created. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/createproject/
139
+ #
140
+ # @return [Hash] [:project_id] ID of the created project.
141
+ #
142
+ # @example
143
+ # Clearbooks.create_project Project.new(description: 'Project 1 description',
144
+ # project_name: 'Project 1 name',
145
+ # status: 'open')
146
+ def create_project project
147
+ response = super message: project.to_savon
148
+ response = response.to_hash
149
+ { project_id: response[:create_project_response][:create_project_return][:@project_id].to_i }
150
+ end # }}}
151
+
152
+ # @fn def list_projects {{{
153
+ # @brief Get list of projects from Clearbooks API.
154
+ #
155
+ # @param [Hash] query Hash of options to filter projects. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/listprojects/
156
+ #
157
+ # @return [Array, Project] An array or projects.
158
+ #
159
+ # @example
160
+ # Clearbooks.list_projects
161
+ def list_projects query = {}
162
+ response = super message: {query: query}
163
+ response = response.to_hash
164
+ Project.build response[:list_projects_response][:projects][:project]
165
+ end # }}}
166
+
167
+ # @fn def list_account_codes {{{
168
+ # @brief Get list of account codes from Clearbooks API.
169
+ #
170
+ # @return [Array, AccountCode] An array or projects.
171
+ #
172
+ # @example
173
+ # Clearbooks.list_account_codes
174
+ def list_account_codes
175
+ response = super
176
+ response = response.to_hash
177
+ AccountCode.build response[:list_account_codes_response][:account_codes][:account_code]
178
+ end # }}}
179
+
180
+ # @fn def create_journal {{{
181
+ # @brief Creates journal via Clearbooks API.
182
+ #
183
+ # @param [Journal] journal A journal to be created. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/createjournal/
184
+ #
185
+ # @return [Hash] [:journal_id] ID of the created journal.
186
+ #
187
+ def create_journal journal
188
+ response = super message: journal.to_savon
189
+ response = response.to_hash
190
+ { journal_id: response[:create_journal_response][:create_journal_return][:@journal_id].to_i }
191
+ end # }}}
192
+
193
+ # @fn def delete_journal {{{
194
+ # @brief Deletes journal via Clearbooks API.
195
+ #
196
+ # @param [Fixnum] journal_id Id of the journal to be deleted.
197
+ #
198
+ # @return [Boolean] True if the request was successful, otherwise false.
199
+ #
200
+ # @example Clearbooks.delete_journal 10
201
+ # @see https://www.clearbooks.co.uk/support/api/docs/soap/deletejournal/
202
+ def delete_journal journal_id
203
+ response = super message: {journalId: journal_id}
204
+ response = response.to_hash
205
+ response[:delete_journal_response][:journal_success]
206
+ end # }}}
207
+
208
+ # @fn def create_payment {{{
209
+ # @brief Create payment via Clearbooks API
210
+ #
211
+ # @param [Payment] payment The payment to be created. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/createpayment/
212
+ #
213
+ # @return [Hash] [:payment_id] ID of the created payment.
214
+ # @see https://www.clearbooks.co.uk/support/api/docs/soap/createpayment/
215
+ #
216
+ def create_payment payment
217
+ response = super message: payment.to_savon
218
+ response = response.to_hash
219
+ { payment_id: response[:create_payment_response][:create_payment_return][:@payment_id].to_i }
220
+ end # }}}
221
+
222
+ # @fn def allocate_payment {{{
223
+ # @brief Allocate a payment against an invoice or set of invoices.
224
+ #
225
+ # @param [Hash] params Params of the payment. See the list of available options in official docs: https://www.clearbooks.co.uk/support/api/docs/soap/allocatepayment/
226
+ #
227
+ # @return [Hash] [:success, :msg] Operation results and brief message.
228
+ # @see https://www.clearbooks.co.uk/support/api/docs/soap/allocatepayment/
229
+ def allocate_payment params
230
+ invoices = params[:invoices].map do |i|
231
+ {
232
+ :@id => i[:id],
233
+ :@amount => i[:amount]
234
+ }
235
+ end
236
+
237
+ payment = {
238
+ :@paymentId => params[:payment_id],
239
+ :@entityId => params[:entity_id],
240
+ :@type => params[:type],
241
+ :invoices => { invoice: invoices }
242
+ }
243
+
244
+ response = super message: {payment: payment}
245
+ response = response.to_hash
246
+ response = response[:allocate_payment_response][:status]
247
+ {
248
+ success: response[:@success].to_b,
249
+ msg: response[:@msg]
250
+ }
251
+ end # }}}
252
+
253
+ end # of class Client
254
+
255
+ end # of module Clearbooks
256
+
257
+ # vim:ts=2:tw=100:wm=100:syntax=ruby