rconomic 0.2.1 → 0.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 (73) hide show
  1. data/.travis.yml +1 -0
  2. data/Gemfile +8 -1
  3. data/Gemfile.lock +8 -1
  4. data/Guardfile +6 -0
  5. data/README.md +39 -14
  6. data/lib/economic/account.rb +25 -0
  7. data/lib/economic/cash_book.rb +39 -0
  8. data/lib/economic/cash_book_entry.rb +111 -0
  9. data/lib/economic/current_invoice.rb +33 -2
  10. data/lib/economic/current_invoice_line.rb +1 -1
  11. data/lib/economic/debtor.rb +2 -1
  12. data/lib/economic/debtor_contact.rb +1 -1
  13. data/lib/economic/entity/handle.rb +66 -0
  14. data/lib/economic/entity.rb +39 -36
  15. data/lib/economic/invoice.rb +58 -0
  16. data/lib/economic/proxies/account_proxy.rb +22 -0
  17. data/lib/economic/proxies/cash_book_entry_proxy.rb +53 -0
  18. data/lib/economic/proxies/cash_book_proxy.rb +47 -0
  19. data/lib/economic/proxies/current_invoice_line_proxy.rb +7 -1
  20. data/lib/economic/proxies/current_invoice_proxy.rb +18 -1
  21. data/lib/economic/proxies/debtor_contact_proxy.rb +36 -10
  22. data/lib/economic/proxies/debtor_proxy.rb +32 -1
  23. data/lib/economic/proxies/entity_proxy.rb +30 -3
  24. data/lib/economic/proxies/invoice_proxy.rb +31 -0
  25. data/lib/economic/session.rb +18 -1
  26. data/lib/economic/support/string.rb +19 -0
  27. data/lib/rconomic/version.rb +1 -1
  28. data/lib/rconomic.rb +10 -2
  29. data/spec/economic/cash_book_entry_spec.rb +20 -0
  30. data/spec/economic/cash_book_spec.rb +34 -0
  31. data/spec/economic/current_invoice_spec.rb +44 -1
  32. data/spec/economic/debtor_contact_spec.rb +2 -2
  33. data/spec/economic/debtor_spec.rb +6 -0
  34. data/spec/economic/entity/handle_spec.rb +116 -0
  35. data/spec/economic/entity_spec.rb +26 -22
  36. data/spec/economic/invoice_spec.rb +68 -0
  37. data/spec/economic/proxies/cash_book_entry_proxy_spec.rb +62 -0
  38. data/spec/economic/proxies/cash_book_proxy_spec.rb +54 -0
  39. data/spec/economic/proxies/current_invoice_line_proxy_spec.rb +1 -1
  40. data/spec/economic/proxies/current_invoice_proxy_spec.rb +66 -2
  41. data/spec/economic/proxies/debtor_proxy_spec.rb +39 -1
  42. data/spec/economic/proxies/invoice_proxy_spec.rb +75 -0
  43. data/spec/economic/session_spec.rb +11 -1
  44. data/spec/fixtures/cash_book_book/success.xml +10 -0
  45. data/spec/fixtures/cash_book_entry_create_debtor_payment/success.xml +11 -0
  46. data/spec/fixtures/cash_book_entry_create_finance_voucher/success.xml +11 -0
  47. data/spec/fixtures/cash_book_entry_create_from_data/success.xml +11 -0
  48. data/spec/fixtures/cash_book_entry_get_data/success.xml +73 -0
  49. data/spec/fixtures/cash_book_get_all/multiple.xml +15 -0
  50. data/spec/fixtures/cash_book_get_entries/success.xml +17 -0
  51. data/spec/fixtures/cash_book_get_name/success.xml +8 -0
  52. data/spec/fixtures/current_invoice_book/success.xml +10 -0
  53. data/spec/fixtures/current_invoice_find_by_date_interval/many.xml +15 -0
  54. data/spec/fixtures/current_invoice_find_by_date_interval/none.xml +8 -0
  55. data/spec/fixtures/current_invoice_find_by_date_interval/single.xml +12 -0
  56. data/spec/fixtures/current_invoice_get_all/multiple.xml +15 -0
  57. data/spec/fixtures/current_invoice_get_all/none.xml +8 -0
  58. data/spec/fixtures/current_invoice_get_all/single.xml +12 -0
  59. data/spec/fixtures/current_invoice_get_data_array/multiple.xml +141 -0
  60. data/spec/fixtures/current_invoice_get_data_array/single.xml +75 -0
  61. data/spec/fixtures/debtor_find_by_number/found.xml +10 -0
  62. data/spec/fixtures/debtor_find_by_number/not_found.xml +7 -0
  63. data/spec/fixtures/debtor_get_all/multiple.xml +15 -0
  64. data/spec/fixtures/debtor_get_all/single.xml +12 -0
  65. data/spec/fixtures/debtor_get_data_array/multiple.xml +103 -0
  66. data/spec/fixtures/invoice_find_by_date_interval/many.xml +15 -0
  67. data/spec/fixtures/invoice_find_by_date_interval/none.xml +9 -0
  68. data/spec/fixtures/invoice_find_by_date_interval/single.xml +12 -0
  69. data/spec/fixtures/invoice_get_data/success.xml +74 -0
  70. data/spec/fixtures/invoice_get_pdf/success.xml +8 -0
  71. data/spec/fixtures/invoice_get_remainder/success.xml +8 -0
  72. data/spec/fixtures/spec_entity_delete/success.xml +6 -0
  73. metadata +54 -6
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
+ - 1.9.3
5
6
  - ree
6
7
  - rbx
7
8
 
data/Gemfile CHANGED
@@ -5,4 +5,11 @@ gemspec
5
5
  group :test do
6
6
  gem 'rake'
7
7
  gem 'savon_spec', '0.1.6'
8
- end
8
+ end
9
+
10
+ # Not required to develop rconomic, but useful. See file
11
+ # mappings in Guardfile
12
+ group :guard do
13
+ gem 'guard'
14
+ gem 'guard-rspec'
15
+ end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rconomic (0.1.0)
4
+ rconomic (0.3)
5
5
  activesupport (~> 3.0)
6
6
  savon (= 0.9.5)
7
7
 
@@ -13,6 +13,10 @@ GEM
13
13
  gyoku (>= 0.4.0)
14
14
  builder (3.0.0)
15
15
  diff-lcs (1.1.2)
16
+ guard (0.8.8)
17
+ thor (~> 0.14.6)
18
+ guard-rspec (0.5.0)
19
+ guard (>= 0.8.4)
16
20
  gyoku (0.4.4)
17
21
  builder (>= 2.1.2)
18
22
  httpi (0.9.5)
@@ -42,6 +46,7 @@ GEM
42
46
  mocha (>= 0.9.8)
43
47
  rspec (>= 2.0.0)
44
48
  savon (>= 0.8.0)
49
+ thor (0.14.6)
45
50
  wasabi (1.0.0)
46
51
  nokogiri (>= 1.4.0)
47
52
 
@@ -49,6 +54,8 @@ PLATFORMS
49
54
  ruby
50
55
 
51
56
  DEPENDENCIES
57
+ guard
58
+ guard-rspec
52
59
  rake
53
60
  rconomic!
54
61
  savon_spec (= 0.1.6)
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2, :cli => "--color", :all_after_pass => false, :all_on_start => false, :keep_failed => false do
2
+ watch('spec/spec_helper.rb') { "spec" }
3
+ watch(%r{^spec/.+_spec\.rb$})
4
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
5
+ end
6
+
data/README.md CHANGED
@@ -31,11 +31,11 @@ Usage example
31
31
  debtor.save
32
32
 
33
33
  # Create invoice for debtor:
34
- invoice = economic.current_invoices.build
35
- invoice.date = Time.now
36
- invoice.due_date = Time.now + 15
37
- invoice.exchange_rate = 100
38
- invoice.is_vat_included = false
34
+ current_invoice = economic.current_invoices.build
35
+ current_invoice.date = Time.now
36
+ current_invoice.due_date = Time.now + 15
37
+ current_invoice.exchange_rate = 100
38
+ current_invoice.is_vat_included = false
39
39
 
40
40
  invoice_line = Economic::CurrentInvoiceLine.new
41
41
  invoice_line.description = 'Line on invoice'
@@ -43,9 +43,31 @@ Usage example
43
43
  invoice_line.product_handle = { :number => 101 }
44
44
  invoice_line.quantity = 12
45
45
  invoice_line.unit_net_price = 19.95
46
- invoice.lines << invoice_line
47
-
48
- invoice.save
46
+ current_invoice.lines << invoice_line
47
+
48
+ current_invoice.save
49
+
50
+ # You can delete it by doing:
51
+ # current_invoice.destroy
52
+
53
+ invoice = current_invoice.book
54
+
55
+ # Create a debtor payment
56
+
57
+ cash_book = economic.cash_books.all.last # Or find it by its number
58
+
59
+ # The reason debtor payments are done this way is because we don't want to specify the voucher number. If we build the cash book entry ourselves,
60
+ # without specifying the voucher number, the API will complain. This way, E-Conomics will assign a voucher number for us.
61
+
62
+ cash_book_entry = cash_book.entries.create_debtor_payment(:debtor_handle => debtor.handle, :contra_account_handle => { :number => '1920' })
63
+ cash_book_entry.cash_book_entry_type = "DebtorPayment" # For some reason, we need to specify this.
64
+ cash_book_entry.amount = -123.45
65
+ cash_book_entry.currency_handle = { "Code" => "DKK" }
66
+ cash_book_entry.debtor_invoice_number = invoice.number
67
+ cash_book_entry.text = "Payment, invoice #{ invoice.number }"
68
+ cash_book_entry.save
69
+
70
+ cash_book.book
49
71
 
50
72
 
51
73
  How to enable e-conomic API access
@@ -61,12 +83,15 @@ It doesn't do everything
61
83
 
62
84
  Not even remotely... For now, limited to a small subset of all the [available operations](https://www.e-conomic.com/secure/api1/EconomicWebService.asmx):
63
85
 
64
- | Create | Read | Update
65
- -------------------+--------+------+-------
66
- CurrentInvoice | X | X | X
67
- CurrentInvoiceLine | X | X | X
68
- Debtor | X | X | X
69
- DebtorContact | X | X | X
86
+ | Create | Read | Update | Delete
87
+ -------------------+--------+------+--------+-------
88
+ CashBook | X | X | X | X
89
+ CashBookEntry | X | X | X | X
90
+ CurrentInvoice | X | X | X | X
91
+ CurrentInvoiceLine | X | X | X | X
92
+ Debtor | X | X | X | X
93
+ DebtorContact | X | X | X | X
94
+ Invoice | X | X | |
70
95
 
71
96
 
72
97
  Credits
@@ -0,0 +1,25 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+ class Account < Entity
5
+ has_properties :name, :number, :balance, :block_direct_entries, :contra_account, :debit_credit, :department, :distribution_key, :is_accessible, :opening_account, :total_from, :type, :vat_account
6
+
7
+
8
+ def handle
9
+ Handle.new({:name => @name})
10
+ end
11
+
12
+
13
+ protected
14
+
15
+ def build_soap_data
16
+ data = ActiveSupport::OrderedHash.new
17
+
18
+ data['Handle'] = handle.to_hash
19
+ data['Name'] = handle.number
20
+ data['Number'] = number
21
+
22
+ return data
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+
5
+ # Represents a cash book in E-conomic.
6
+ #
7
+ # API documentation: http://www.e-conomic.com/apidocs/Documentation/T_Economic_Api_ICashBook.html
8
+ class CashBook < Entity
9
+ has_properties :name, :number
10
+
11
+ def handle
12
+ Handle.new({:number => @number})
13
+ end
14
+
15
+ def entries
16
+ CashBookEntryProxy.new(self)
17
+ end
18
+
19
+ # Books all entries in the cashbook. Returns book result.
20
+ def book
21
+ response = session.request(soap_action(:book)) do
22
+ soap.body = { "cashBookHandle" => handle.to_hash }
23
+ end
24
+ response[:number].to_i
25
+ end
26
+
27
+ protected
28
+
29
+ def build_soap_data
30
+ data = ActiveSupport::OrderedHash.new
31
+
32
+ data['Handle'] = handle.to_hash
33
+ data['Name'] = name
34
+ data['Number'] = number
35
+
36
+ return data
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,111 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+
5
+ # Represents a cash book in E-conomic.
6
+ #
7
+ # API documentation: http://www.e-conomic.com/apidocs/Documentation/T_Economic_Api_ICashBook.html
8
+ class CashBookEntry < Entity
9
+ has_properties :id1,
10
+ :id2,
11
+ :account_handle,
12
+ :amount,
13
+ :amount_default_currency,
14
+ :bank_payment_creditor_id,
15
+ :bank_payment_creditor_invoice_id,
16
+ :bank_payment_type_handle,
17
+ :capitalise_handle,
18
+ :cash_book_handle,
19
+ :contra_account_handle,
20
+ :contra_vat_account_handle,
21
+ :cost_type_handle,
22
+ :creditor_handle,
23
+ :creditor_invoice_number,
24
+ :currency_handle,
25
+ :date,
26
+ :debtor_handle,
27
+ :debtor_invoice_number,
28
+ :department_handle,
29
+ :distribution_key_handle,
30
+ :due_date,
31
+ :employee_handle,
32
+ :end_date,
33
+ :project_handle,
34
+ :start_date,
35
+ :text,
36
+ :cash_book_entry_type,
37
+ :vat_account_handle,
38
+ :voucher_number
39
+
40
+ def initialize_defaults
41
+ self.account_handle = nil
42
+ self.amount = 0
43
+ self.amount_default_currency = 0
44
+ self.bank_payment_creditor_id = 0
45
+ self.bank_payment_creditor_invoice_id = 0
46
+ self.bank_payment_type_handle = nil
47
+ self.capitalise_handle = nil
48
+ self.cash_book_handle = nil
49
+ self.contra_account_handle = nil
50
+ self.contra_vat_account_handle = nil
51
+ self.cost_type_handle = nil
52
+ self.creditor_handle = nil
53
+ self.creditor_invoice_number = nil
54
+ self.currency_handle = nil
55
+ self.date = Time.now
56
+ self.debtor_handle = nil
57
+ self.debtor_invoice_number = nil
58
+ self.department_handle = nil
59
+ self.distribution_key_handle = nil
60
+ self.due_date = nil
61
+ self.employee_handle = nil
62
+ self.end_date = nil
63
+ self.project_handle = nil
64
+ self.start_date = Time.now
65
+ self.text = ""
66
+ self.cash_book_entry_type = ""
67
+ self.vat_account_handle = nil
68
+ self.voucher_number = 0
69
+ end
70
+
71
+ def handle
72
+ Handle.new(:id1 => @id1, :id2 => @id2)
73
+ end
74
+
75
+ def build_soap_data
76
+ data = ActiveSupport::OrderedHash.new
77
+
78
+ data['Handle'] = handle.to_hash
79
+ data['Type'] = cash_book_entry_type unless cash_book_entry_type.blank?
80
+ data['CashBookHandle'] = { 'Number' => cash_book_handle[:number] } unless cash_book_handle.blank?
81
+ data['DebtorHandle'] = { 'Number' => debtor_handle[:number] } unless debtor_handle.blank?
82
+ data['CreditorHandle'] = { 'Number' => creditor_handle[:number] } unless creditor_handle.blank?
83
+ data['AccountHandle'] = { 'Number' => account_handle[:number] } unless account_handle.blank?
84
+ data['ContraAccountHandle'] = { 'Number' => contra_account_handle[:number] } unless contra_account_handle.blank?
85
+ data['Date'] = date
86
+ data['VoucherNumber'] = voucher_number
87
+ data['Text'] = text
88
+ data['AmountDefaultCurrency'] = amount_default_currency
89
+ data['CurrencyHandle'] = { 'Code' => currency_handle[:code] } unless currency_handle.blank?
90
+ data['Amount'] = amount
91
+ data['VatAccountHandle'] = { 'Number' => vat_account_handle[:number] } unless vat_account_handle.blank?
92
+ data['ContraVatAccountHandle'] = { 'Number' => contra_vat_account_handle[:number] } unless contra_vat_account_handle.blank?
93
+ data['DebtorInvoiceNumber'] = debtor_invoice_number unless debtor_invoice_number.blank?
94
+ data['CreditorInvoiceNumber'] = creditor_invoice_number unless creditor_invoice_number.blank?
95
+ data['DueDate'] = due_date
96
+ data['DepartmentHandle'] = { 'Number' => department_handle[:number] } unless department_handle.blank?
97
+ data['DistributionKeyHandle'] = { 'Number' => distribution_key_handle[:number] } unless distribution_key_handle.blank?
98
+ data['ProjectHandle'] = { 'Number' => project_handle[:number] } unless project_handle.blank?
99
+ data['CostTypeHandle'] = { 'Number' => cost_type_handle[:number] } unless cost_type_handle.blank?
100
+ data['BankPaymentTypeHandle'] = { 'Number' => bank_payment_type_handle[:number] } unless bank_payment_type_handle.blank?
101
+ data['BankPaymentCreditorId'] = bank_payment_creditor_id
102
+ data['BankPaymentCreditorInvoiceId'] = bank_payment_creditor_invoice_id
103
+ data['CapitaliseHandle'] = { 'Number' => capitalise_handle[:number] } unless capitalise_handle.blank?
104
+ data['StartDate'] = start_date
105
+ data['EndDate'] = end_date
106
+ data['EmployeeHandle'] = { 'Number' => employee_handle[:number] } unless employee_handle.blank?
107
+
108
+ return data
109
+ end
110
+ end
111
+ end
@@ -26,12 +26,40 @@ module Economic
26
26
  #
27
27
  # invoice.save
28
28
  class CurrentInvoice < Entity
29
- has_properties :id, :debtor_handle, :debtor_name, :debtor_address, :debtor_postal_code, :debtor_city, :debtor_country, :date, :term_of_payment_handle, :due_date, :currency_handle, :exchange_rate, :is_vat_included, :layout_handle, :delivery_date, :net_amount, :vat_amount, :gross_amount, :margin, :margin_as_percent
29
+ has_properties :id, :debtor_handle, :debtor_name, :debtor_address, :debtor_postal_code, :debtor_city, :debtor_country, :attention_handle, :date, :term_of_payment_handle, :due_date, :currency_handle, :exchange_rate, :is_vat_included, :layout_handle, :delivery_date, :net_amount, :vat_amount, :gross_amount, :margin, :margin_as_percent, :heading
30
30
 
31
31
  def initialize(properties = {})
32
32
  super
33
33
  end
34
34
 
35
+ def attention
36
+ return nil if attention_handle.blank?
37
+ @attention ||= session.contacts.find(attention_handle)
38
+ end
39
+
40
+ def attention=(contact)
41
+ self.attention_handle = contact.handle
42
+ @attention = contact
43
+ end
44
+
45
+ def attention_handle=(handle)
46
+ @attention = nil unless handle == @attention_handle
47
+ @attention_handle = handle
48
+ end
49
+
50
+ # Books a current invoice. An invoice number greater than all other invoice numbers will be
51
+ # assigned to the resulting Economic::Invoice.
52
+ #
53
+ # Returns the resulting Economic::Invoice object
54
+ def book
55
+ response = session.request soap_action(:book) do
56
+ soap.body = { "currentInvoiceHandle" => handle.to_hash }
57
+ end
58
+
59
+ # Find the created Invoice
60
+ session.invoices.find(response[:number])
61
+ end
62
+
35
63
  def debtor
36
64
  return nil if debtor_handle.blank?
37
65
  @debtor ||= session.debtors.find(debtor_handle)
@@ -66,6 +94,7 @@ module Economic
66
94
  self.is_vat_included = nil
67
95
  self.layout_handle = nil
68
96
  self.delivery_date = nil
97
+ self.heading = nil
69
98
  self.net_amount = 0
70
99
  self.vat_amount = 0
71
100
  self.gross_amount = 0
@@ -85,6 +114,7 @@ module Economic
85
114
  data['DebtorPostalCode'] = debtor_postal_code unless debtor_postal_code.blank?
86
115
  data['DebtorCity'] = debtor_city unless debtor_city.blank?
87
116
  data['DebtorCountry'] = debtor_country unless debtor_country.blank?
117
+ data['AttentionHandle'] = { 'Id' => attention_handle[:id] } unless attention_handle.blank?
88
118
  data['Date'] = date.iso8601 unless date.blank?
89
119
  data['TermOfPaymentHandle'] = { 'Id' => term_of_payment_handle[:id] } unless term_of_payment_handle.blank?
90
120
  data['DueDate'] = (due_date.blank? ? nil : due_date.iso8601)
@@ -93,6 +123,7 @@ module Economic
93
123
  data['IsVatIncluded'] = is_vat_included
94
124
  data['LayoutHandle'] = { 'Id' => layout_handle[:id] } unless layout_handle.blank?
95
125
  data['DeliveryDate'] = delivery_date ? delivery_date.iso8601 : nil
126
+ data['Heading'] = heading unless heading.blank?
96
127
  data['NetAmount'] = net_amount
97
128
  data['VatAmount'] = vat_amount
98
129
  data['GrossAmount'] = gross_amount
@@ -114,4 +145,4 @@ module Economic
114
145
  end
115
146
  end
116
147
 
117
- end
148
+ end
@@ -68,4 +68,4 @@ module Economic
68
68
  end
69
69
  end
70
70
 
71
- end
71
+ end
@@ -31,11 +31,12 @@ module Economic
31
31
  Handle.new({:number => @number})
32
32
  end
33
33
 
34
+ # Returns the Debtors contacts
34
35
  def contacts
35
36
  @contacts ||= DebtorContactProxy.new(self)
36
37
  end
37
38
 
38
- # Provides access to the current invoices - ie invoices that haven't yet been booked
39
+ # Provides access to the current invoices for Debtor - ie invoices that haven't yet been booked
39
40
  def current_invoices
40
41
  @current_invoices ||= CurrentInvoiceProxy.new(self)
41
42
  end
@@ -22,7 +22,7 @@ module Economic
22
22
 
23
23
  def debtor
24
24
  return nil if debtor_handle.blank?
25
- @debtor ||= session.debtors.find(debtor_handle)
25
+ @debtor ||= session.debtors.find(debtor_handle[:number])
26
26
  end
27
27
 
28
28
  def debtor=(debtor)
@@ -0,0 +1,66 @@
1
+ class Economic::Entity
2
+ class Handle
3
+ attr_accessor :id, :id1, :id2, :number
4
+
5
+ def initialize(hash)
6
+ verify_sanity_of_arguments!(hash)
7
+ hash = prepare_hash_argument(hash) unless hash.is_a?(self.class)
8
+
9
+ @id = hash[:id].to_i if hash[:id]
10
+ @id1 = hash[:id1].to_i if hash[:id1]
11
+ @id2 = hash[:id2].to_i if hash[:id2]
12
+ @number = hash[:number].to_i if hash[:number]
13
+ end
14
+
15
+ def to_hash
16
+ hash = {}
17
+ hash['Id'] = id unless id.blank?
18
+ hash['Id1'] = id1 unless id1.blank?
19
+ hash['Id2'] = id2 unless id2.blank?
20
+ hash['Number'] = number unless number.blank?
21
+ hash
22
+ end
23
+
24
+ def [](key)
25
+ {:id => @id, :id1 => @id1, :id2 => @id2, :number => @number}[key]
26
+ end
27
+
28
+ def ==(other)
29
+ return false if other.nil?
30
+ return false unless other.respond_to?(:id) && other.respond_to?(:number)
31
+ self.id == other.id && self.number == other.number
32
+ end
33
+
34
+ private
35
+
36
+ # Raises exceptions if hash doesn't contain values we can use to construct a new handle
37
+ def verify_sanity_of_arguments!(hash)
38
+ return if hash.is_a?(self.class)
39
+
40
+ if hash.nil? || (!hash.respond_to?(:to_i) && (!hash.respond_to?(:keys) && !hash.respond_to?(:values)))
41
+ raise ArgumentError.new("Expected Number, Hash or Economic::Entity::Handle - got #{hash.inspect}")
42
+ end
43
+
44
+ if hash.respond_to?(:keys)
45
+ unknown_keys = hash.keys - [:id, :id1, :id2, :number, "Number", "Id", "Id1", "Id2"]
46
+ raise ArgumentError.new("Unknown keys in handle: #{unknown_keys.inspect}") unless unknown_keys.empty?
47
+
48
+ not_to_iable = hash.select { |k, v| !v.respond_to?(:to_i) }
49
+ raise ArgumentError.new("All values must respond to to_i. #{not_to_iable.inspect} didn't") unless not_to_iable.empty?
50
+ end
51
+ end
52
+
53
+ # Examples
54
+ #
55
+ # prepare_hash_argument(12) #=> {:id => 12}
56
+ # prepare_hash_argument(:id => 12) #=> {:id => 12}
57
+ # prepare_hash_argument('Id' => 12) #=> {:id => 12}
58
+ # prepare_hash_argument('Id' => 12, 'Number' => 13) #=> {:id => 12, :number => 13}
59
+ def prepare_hash_argument(hash)
60
+ hash = {:id => hash.to_i} if hash.respond_to?(:to_i) unless hash.blank?
61
+ hash[:id] ||= hash['Id']
62
+ hash[:number] ||= hash['Number']
63
+ hash
64
+ end
65
+ end
66
+ end
@@ -1,31 +1,7 @@
1
+ require 'economic/entity/handle'
2
+
1
3
  module Economic
2
4
  class Entity
3
- class Handle
4
- attr_accessor :id, :number
5
-
6
- def initialize(hash)
7
- @id = hash[:id]
8
- @number = hash[:number]
9
- end
10
-
11
- def to_hash
12
- hash = {}
13
- hash['Id'] = id unless id.blank?
14
- hash['Number'] = number unless number.blank?
15
- hash
16
- end
17
-
18
- def [](key)
19
- {:id => @id, :number => @number}[key]
20
- end
21
-
22
- def ==(other)
23
- return false if other.nil?
24
- return false unless other.respond_to?(:id) && other.respond_to?(:number)
25
- self.id == other.id && self.number == other.number
26
- end
27
- end
28
-
29
5
  # Internal accessors
30
6
  attr_accessor :persisted, :session, :partial
31
7
 
@@ -71,6 +47,17 @@ module Economic
71
47
  class_name_without_modules = class_name.split('::').last
72
48
  "#{class_name_without_modules.snakecase}_#{action.to_s.snakecase}".intern
73
49
  end
50
+
51
+ # Returns a symbol based on the name of the entity. Used to request and read data responses.
52
+ #
53
+ # Entity.key #=> :entity
54
+ # CurrentInvoice.key #=> :current_invoice
55
+ def key
56
+ key = self.name
57
+ key = Economic::Support::String.demodulize(key)
58
+ key = Economic::Support::String.underscore(key)
59
+ key.intern
60
+ end
74
61
  end
75
62
 
76
63
  def handle
@@ -90,12 +77,12 @@ module Economic
90
77
 
91
78
  # Updates Entity with its data from the API
92
79
  def get_data
93
- response = proxy.get_data(number)
80
+ response = proxy.get_data(handle)
94
81
  self.update_properties(response)
95
82
  self.partial = false
96
83
  self.persisted = true
97
84
  end
98
-
85
+
99
86
  # Returns the number of Entity. This does not trigger a load from the API even if Entity is partial
100
87
  def number
101
88
  @number
@@ -106,13 +93,6 @@ module Economic
106
93
  @id
107
94
  end
108
95
 
109
- def handle
110
- handle = {}
111
- handle[:id] = id unless id.blank?
112
- handle[:number] = number unless number.blank?
113
- handle
114
- end
115
-
116
96
  # Returns true if CurrentInvoiceLine has been persisted in e-conomic
117
97
  def persisted?
118
98
  !!@persisted
@@ -141,6 +121,19 @@ module Economic
141
121
  create_or_update
142
122
  end
143
123
 
124
+ # Deletes entity permanently from E-conomic.
125
+ def destroy
126
+ handleKey = "#{camel_back(class_name)}Handle"
127
+ response = session.request soap_action(:delete) do
128
+ soap.body = { handleKey => handle.to_hash }
129
+ end
130
+
131
+ @persisted = false
132
+ @partial = true
133
+
134
+ response
135
+ end
136
+
144
137
  # Updates properties of Entity with the values from hash
145
138
  def update_properties(hash)
146
139
  hash.each do |key, value|
@@ -169,6 +162,8 @@ module Economic
169
162
  if response
170
163
  @number = response[:number]
171
164
  @id = response[:id]
165
+ @id1 = response[:id1]
166
+ @id2 = response[:id2]
172
167
  end
173
168
 
174
169
  @persisted = true
@@ -196,6 +191,14 @@ module Economic
196
191
  self.class.soap_action(action)
197
192
  end
198
193
 
194
+ def class_name
195
+ self.class.to_s.split("::").last
196
+ end
197
+
198
+ def camel_back(name)
199
+ name[0,1].downcase + name[1..-1]
200
+ end
201
+
199
202
  end
200
203
 
201
- end
204
+ end
@@ -0,0 +1,58 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+ class Invoice < Entity
5
+ has_properties :number, :net_amount, :vat_amount, :due_date, :debtor_handle, :debtor_name, :debtor_name, :debtor_address, :debtor_postal_code, :debtor_city, :debtor_country, :debtor_ean, :attention_handle, :heading
6
+
7
+ def attention
8
+ return nil if attention_handle.blank?
9
+ @attention ||= session.contacts.find(attention_handle)
10
+ end
11
+
12
+ def attention=(contact)
13
+ self.attention_handle = contact.handle
14
+ @attention = contact
15
+ end
16
+
17
+ def attention_handle=(handle)
18
+ @attention = nil unless handle == @attention_handle
19
+ @attention_handle = handle
20
+ end
21
+
22
+ def debtor
23
+ return nil if debtor_handle.blank?
24
+ @debtor ||= session.debtors.find(debtor_handle)
25
+ end
26
+
27
+ def debtor=(debtor)
28
+ self.debtor_handle = debtor.handle
29
+ @debtor = debtor
30
+ end
31
+
32
+ def debtor_handle=(handle)
33
+ @debtor = nil unless handle == @debtor_handle
34
+ @debtor_handle = handle
35
+ end
36
+
37
+ def remainder
38
+ session.request(soap_action(:get_remainder)) do
39
+ soap.body = { "invoiceHandle" => handle.to_hash }
40
+ end
41
+ end
42
+
43
+ # Returns the PDF version of Invoice as a String.
44
+ #
45
+ # To get it as a file you can do:
46
+ #
47
+ # File.open("invoice.pdf", 'wb') do |file|
48
+ # file << invoice.pdf
49
+ # end
50
+ def pdf
51
+ response = session.request soap_action(:get_pdf) do
52
+ soap.body = { "invoiceHandle" => handle.to_hash }
53
+ end
54
+
55
+ Base64.decode64(response)
56
+ end
57
+ end
58
+ end