clearbooks 0.16.3

Sign up to get free protection for your applications and to get access to all the features.
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