├── .rspec ├── .gemrelease ├── lib └── quickbooks │ ├── version.rb │ ├── model │ ├── description_line_detail.rb │ ├── entity_ref.rb │ ├── line_ex.rb │ ├── name_value.rb │ ├── item_group_detail.rb │ ├── other_contact_info.rb │ ├── item_change.rb │ ├── delivery_info.rb │ ├── vendor_change.rb │ ├── customer_change.rb │ ├── payment_change.rb │ ├── validator.rb │ ├── credit_memo_change.rb │ ├── linked_transaction.rb │ ├── refund_receipt_change.rb │ ├── invoice_change.rb │ ├── has_line_items.rb │ ├── bill_payment_credit_card.rb │ ├── telephone_number.rb │ ├── sales_tax_rate_list.rb │ ├── purchase_tax_rate_list.rb │ ├── entity.rb │ ├── web_site_address.rb │ ├── change_model.rb │ ├── check_payment.rb │ ├── base_model_json.rb │ ├── item_group_line.rb │ ├── transaction_tax_detail.rb │ ├── email_address.rb │ ├── group_line_detail.rb │ ├── fault.rb │ ├── bill_payment_check.rb │ ├── effective_tax_rate.rb │ ├── global_tax_calculation.rb │ ├── document_numbering.rb │ ├── markup_info.rb │ ├── tax_rate_detail.rb │ ├── payment_line_detail.rb │ ├── invoice_group_line_detail.rb │ ├── custom_field.rb │ ├── tax_line.rb │ ├── discount_override.rb │ ├── budget_line_item.rb │ ├── attachable_ref.rb │ ├── sub_total_line_detail.rb │ ├── base_reference.rb │ ├── company_currency.rb │ ├── tax_agency.rb │ ├── meta_data.rb │ ├── account_based_expense_line_detail.rb │ ├── deposit_line_detail.rb │ ├── bill_payment_line_item.rb │ ├── credit_card_payment.rb │ ├── tax_line_detail.rb │ ├── discount_line_detail.rb │ ├── tax_code.rb │ ├── budget.rb │ ├── sales_item_line_detail.rb │ ├── transfer.rb │ ├── payment_method.rb │ ├── exchange_rate.rb │ ├── class.rb │ ├── attachable.rb │ ├── access_token_response.rb │ ├── department.rb │ ├── definition.rb │ ├── item_based_expense_line_detail.rb │ ├── physical_address.rb │ ├── deposit_line_item.rb │ ├── tax_rate.rb │ ├── term.rb │ ├── tax_rate_detail_line.rb │ ├── upload.rb │ ├── journal_entry_line_detail.rb │ ├── change_data_capture.rb │ └── report.rb │ ├── service │ ├── budget.rb │ ├── tax_code.rb │ ├── tax_rate.rb │ ├── tax_agency.rb │ ├── attachable.rb │ ├── tax_service.rb │ ├── company_info.rb │ ├── item_change.rb │ ├── invoice_change.rb │ ├── payment_change.rb │ ├── vendor_change.rb │ ├── bill.rb │ ├── customer_change.rb │ ├── deposit.rb │ ├── transfer.rb │ ├── credit_memo_change.rb │ ├── purchase.rb │ ├── journal_entry.rb │ ├── refund_receipt_change.rb │ ├── credit_memo.rb │ ├── term.rb │ ├── bill_payment.rb │ ├── time_activity.rb │ ├── purchase_order.rb │ ├── refund_receipt.rb │ ├── vendor_credit.rb │ ├── account.rb │ ├── customer.rb │ ├── batch.rb │ ├── company_currency.rb │ ├── preferences.rb │ ├── estimate.rb │ ├── class.rb │ ├── department.rb │ ├── vendor.rb │ ├── change_service.rb │ ├── employee.rb │ ├── change_data_capture.rb │ ├── exchange_rate.rb │ ├── payment.rb │ ├── service_crud_json.rb │ ├── payment_method.rb │ ├── item.rb │ ├── upload.rb │ ├── reports.rb │ ├── base_service_json.rb │ ├── access_token.rb │ └── invoice.rb │ └── util │ ├── logging.rb │ ├── collection.rb │ └── query_builder.rb ├── Gemfile ├── spec ├── fixtures │ ├── monkey.jpg │ ├── custom_field_date.xml │ ├── custom_field_string.xml │ ├── custom_field_number.xml │ ├── item_change.xml │ ├── invoice_change.xml │ ├── vendor_change.xml │ ├── customer_change.xml │ ├── payment_change.xml │ ├── credit_memo_change.xml │ ├── refund_receipt_change.xml │ ├── item_delete_success_response.xml │ ├── invoice_delete_success_response.xml │ ├── deposit_delete_success_response.xml │ ├── payment_delete_success_response.xml │ ├── bill_payment_delete_success_response.xml │ ├── deleted_time_activity.xml │ ├── tax_rate_detail_line.xml │ ├── disconnect_200.xml │ ├── query_validation_error.xml │ ├── disconnect_270.xml │ ├── access_token_24.xml │ ├── access_token_270.xml │ ├── access_token_212.xml │ ├── tax_service.xml │ ├── throttle_exceeded_error.xml │ ├── company_currency.xml │ ├── generic_error.xml │ ├── class.xml │ ├── fault.xml │ ├── json │ │ └── tax_service_error_dup.json │ ├── tax_agency.xml │ ├── too_many_requests_error.xml │ ├── attachable_create_response.xml │ ├── item_changes.xml │ ├── vendor_changes.xml │ ├── invoice_changes.xml │ ├── customer_changes.xml │ ├── exchange_rate.xml │ ├── payment_changes.xml │ ├── department.xml │ ├── credit_memo_changes.xml │ ├── access_token_200.xml │ ├── refund_receipt_changes.xml │ ├── exchange_rate_by_currency.xml │ ├── invoice_sparse_create_request.xml │ ├── customer_duplicate_error.xml │ ├── fetch_payment_method_by_id.xml │ ├── deleted_payment_method.xml │ ├── deleted_company_currency.xml │ ├── fetch_company_currency_by_id.xml │ ├── term.xml │ ├── fetch_class_by_id.xml │ ├── tax_service_entity.xml │ ├── deleted_class.xml │ ├── transfer.xml │ ├── payment.xml │ ├── company_currency_query.xml │ ├── tax_agency_entity.xml │ ├── item.xml │ ├── fetch_payment_method_by_name.xml │ ├── fetch_department_by_id.xml │ ├── deleted_department.xml │ ├── bill_payment_check_response.xml │ ├── tax_agencies.xml │ ├── exchange_rates.xml │ ├── payment_void_response_success.xml │ ├── terms.xml │ ├── fetch_term_by_id.xml │ ├── fetch_payment_by_id.xml │ ├── term_delete_success_response.xml │ ├── fetch_item_by_id.xml │ ├── bill_payment_cc_response.xml │ ├── tax_rate.xml │ ├── time_activity.xml │ ├── tax_rates.xml │ ├── transfers.xml │ ├── fetch_bill_payment_by_id.xml │ ├── term_by_id.xml │ ├── fetch_time_activity_by_id.xml │ ├── payments.xml │ ├── payment_by_id.xml │ ├── fetch_account_by_id.xml │ ├── tax_code.xml │ ├── bill_payments.xml │ ├── bill_line_item_expense.xml │ ├── upload_create_response.xml │ ├── vendor_credit.xml │ ├── purchase_create.xml │ ├── fetch_deposit_by_id.xml │ ├── purchase_credit_card_response.xml │ ├── attachables.xml │ ├── deposit.xml │ ├── payment_with_line_extras.xml │ ├── employee.xml │ ├── bill_create_request.xml │ ├── sales_receipt.xml │ ├── fetch_employee_by_id.xml │ ├── deleted_employee.xml │ └── items.xml ├── lib │ ├── quickbooks_spec.rb │ └── quickbooks │ │ ├── model │ │ ├── telephone_number_spec.rb │ │ ├── item_change_spec.rb │ │ ├── vendor_change_spec.rb │ │ ├── invoice_change_spec.rb │ │ ├── payment_change_spec.rb │ │ ├── customer_change_spec.rb │ │ ├── credit_memo_change_spec.rb │ │ ├── sales_line_item_detail_spec.rb │ │ ├── exchange_rate_spec.rb │ │ ├── refund_receipt_change_spec.rb │ │ ├── company_currency_spec.rb │ │ ├── payment_method_spec.rb │ │ ├── access_token_response_spec.rb │ │ ├── tax_rate_spec.rb │ │ ├── tax_agency_spec.rb │ │ ├── budget_spec.rb │ │ ├── fault_spec.rb │ │ ├── preferences_spec.rb │ │ ├── class_spec.rb │ │ ├── transaction_tax_detail_spec.rb │ │ ├── custom_field_spec.rb │ │ ├── department_spec.rb │ │ ├── transfer_spec.rb │ │ ├── time_activity_spec.rb │ │ ├── tax_code_spec.rb │ │ ├── account_spec.rb │ │ └── term_spec.rb │ │ ├── service │ │ ├── tax_code_spec.rb │ │ ├── tax_rate_spec.rb │ │ ├── purchase_order_spec.rb │ │ ├── transfer_spec.rb │ │ ├── preferences_spec.rb │ │ ├── base_service_json_spec.rb │ │ ├── budget_spec.rb │ │ ├── item_change_spec.rb │ │ ├── upload_spec.rb │ │ ├── vendor_change_spec.rb │ │ ├── invoice_change_spec.rb │ │ ├── payment_change_spec.rb │ │ ├── customer_change_spec.rb │ │ ├── company_info_spec.rb │ │ ├── credit_memo_change_spec.rb │ │ ├── refund_receipt_change_spec.rb │ │ ├── account_spec.rb │ │ ├── purchase_spec.rb │ │ ├── exchange_rate_spec.rb │ │ ├── batch_spec.rb │ │ ├── attachable_spec.rb │ │ └── tax_agency_spec.rb │ │ └── util │ │ ├── collection_spec.rb │ │ └── query_builder_spec.rb ├── support │ ├── fixture_helpers.rb │ ├── net_helpers.rb │ └── oauth_helpers.rb └── spec_helper.rb ├── .gitignore ├── RELEASE.md ├── .travis.yml ├── Rakefile ├── quickbooks-ruby.gemspec ├── LICENSE.txt └── webapp └── .env /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | -------------------------------------------------------------------------------- /.gemrelease: -------------------------------------------------------------------------------- 1 | bump: 2 | tag: true 3 | -------------------------------------------------------------------------------- /lib/quickbooks/version.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | 3 | VERSION = "0.6.4" 4 | 5 | end 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | ruby RUBY_VERSION 4 | 5 | gem 'pry' 6 | 7 | gemspec 8 | -------------------------------------------------------------------------------- /spec/fixtures/monkey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DV/quickbooks-ruby/master/spec/fixtures/monkey.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | coverage/ 3 | quickbooks-ruby-*.gem 4 | 5 | Gemfile.lock 6 | 7 | .ruby-version 8 | .ruby-gemset 9 | .bundle 10 | .idea 11 | -------------------------------------------------------------------------------- /spec/fixtures/custom_field_date.xml: -------------------------------------------------------------------------------- 1 | 2 | LastUpdated 3 | DateType 4 | 2013-04-04 5 | -------------------------------------------------------------------------------- /lib/quickbooks/model/description_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class DescriptionLineDetail < BaseModel 4 | 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/fixtures/custom_field_string.xml: -------------------------------------------------------------------------------- 1 | 2 | SalesAssociate 3 | StringType 4 | Miller 5 | -------------------------------------------------------------------------------- /spec/fixtures/custom_field_number.xml: -------------------------------------------------------------------------------- 1 | 2 | NumberOfWatermelons 3 | NumberType 4 | 43 5 | -------------------------------------------------------------------------------- /spec/lib/quickbooks_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks do 2 | 3 | describe "VERSION" do 4 | subject { Quickbooks::VERSION } 5 | it { should be_a String } 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/entity_ref.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class EntityRef < BaseModel 4 | xml_accessor :type 5 | xml_accessor :value 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/fixtures/item_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 39 3 | 4 | 2014-12-08T19:36:24-08:00 5 | 6 | -------------------------------------------------------------------------------- /spec/fixtures/invoice_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 39 3 | 4 | 2014-12-08T19:36:24-08:00 5 | 6 | -------------------------------------------------------------------------------- /spec/fixtures/vendor_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 39 3 | 4 | 2014-12-08T19:36:24-08:00 5 | 6 | -------------------------------------------------------------------------------- /spec/fixtures/customer_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 39 3 | 4 | 2014-12-08T19:36:24-08:00 5 | 6 | -------------------------------------------------------------------------------- /spec/fixtures/payment_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 39 3 | 4 | 2014-12-08T19:36:24-08:00 5 | 6 | 7 | -------------------------------------------------------------------------------- /spec/fixtures/credit_memo_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 39 3 | 4 | 2014-12-08T19:36:24-08:00 5 | 6 | 7 | -------------------------------------------------------------------------------- /lib/quickbooks/model/line_ex.rb: -------------------------------------------------------------------------------- 1 | 2 | module Quickbooks 3 | module Model 4 | class LineEx < BaseModel 5 | 6 | xml_accessor :name_values, :from => "NameValue", :as => [NameValue] 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/fixtures/refund_receipt_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 40 3 | 4 | 2014-12-09T19:30:24-08:00 5 | 6 | 7 | -------------------------------------------------------------------------------- /lib/quickbooks/model/name_value.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class NameValue < BaseModel 4 | xml_accessor :name, :from => "Name" 5 | xml_accessor :value, :from => "Value" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/fixtures/item_delete_success_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 5 | -------------------------------------------------------------------------------- /spec/fixtures/invoice_delete_success_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 5 | -------------------------------------------------------------------------------- /lib/quickbooks/service/budget.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Budget < BaseService 4 | 5 | private 6 | 7 | def model 8 | Quickbooks::Model::Budget 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/fixtures/deposit_delete_success_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 148 4 | 5 | -------------------------------------------------------------------------------- /spec/fixtures/payment_delete_success_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8748 4 | 5 | -------------------------------------------------------------------------------- /lib/quickbooks/service/tax_code.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class TaxCode < BaseService 4 | 5 | private 6 | 7 | def model 8 | Quickbooks::Model::TaxCode 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/quickbooks/service/tax_rate.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class TaxRate < BaseService 4 | 5 | private 6 | 7 | def model 8 | Quickbooks::Model::TaxRate 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/quickbooks/service/tax_agency.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class TaxAgency < BaseService 4 | 5 | private 6 | 7 | def model 8 | Quickbooks::Model::TaxAgency 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/quickbooks/service/attachable.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Attachable < BaseService 4 | 5 | private 6 | 7 | def model 8 | Quickbooks::Model::Attachable 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/quickbooks/service/tax_service.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class TaxService < BaseServiceJSON 4 | private 5 | 6 | def model 7 | Quickbooks::Model::TaxService 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/quickbooks/model/item_group_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class ItemGroupDetail < BaseModel 4 | include HasLineItems 5 | 6 | xml_accessor :line_items, :from => 'ItemGroupLine', :as => [ItemGroupLine] 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /spec/fixtures/bill_payment_delete_success_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 623 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/quickbooks/service/company_info.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class CompanyInfo < BaseService 4 | 5 | private 6 | 7 | def model 8 | Quickbooks::Model::CompanyInfo 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/quickbooks/model/other_contact_info.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class OtherContactInfo < BaseModel 4 | xml_accessor :type, :from => 'Type' 5 | xml_accessor :telephone, :from => 'Telephone', :as => TelephoneNumber 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/item_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class ItemChange < ChangeModel 5 | XML_NODE = "Item" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/delivery_info.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class DeliveryInfo < BaseModel 4 | xml_accessor :delivery_type, :from => 'DeliveryType' 5 | xml_accessor :delivery_time, :from => 'DeliveryTime', :as => DateTime 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/vendor_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class VendorChange < ChangeModel 5 | XML_NODE = "Vendor" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/customer_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class CustomerChange < ChangeModel 5 | XML_NODE = "Customer" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/payment_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class PaymentChange < ChangeModel 5 | XML_NODE = "Payment" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/validator.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | module Validator 4 | 5 | def line_item_size 6 | validates_length_of :line_items, :minimum => 1, :message => 'At least 1 line item is required' 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/fixtures/deleted_time_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | Description 5 | 6 | 7 | -------------------------------------------------------------------------------- /lib/quickbooks/model/credit_memo_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class CreditMemoChange < ChangeModel 5 | XML_NODE = "CreditMemo" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/linked_transaction.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class LinkedTransaction < BaseModel 4 | xml_accessor :txn_id, :from => 'TxnId' 5 | xml_accessor :txn_type, :from => 'TxnType' 6 | xml_accessor :txn_line_id, :from => 'TxnLineId' 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /lib/quickbooks/model/refund_receipt_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class RefundReceiptChange < ChangeModel 5 | XML_NODE = "RefundReceipt" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/fixtures/tax_rate_detail_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | Rate Detail Line Spec 4 | 3.5 5 | 2 6 | Sales 7 | 8 | -------------------------------------------------------------------------------- /lib/quickbooks/model/invoice_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: 4 | # - https://developer.intuit.com/docs/0100_quickbooks_online/0200_dev_guides/accounting/change_data_capture 5 | class InvoiceChange < ChangeModel 6 | XML_NODE = "Invoice" 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/telephone_number_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::TelephoneNumber" do 2 | 3 | it "can be initialized with a number" do 4 | number = "415-555-1212" 5 | tel = Quickbooks::Model::TelephoneNumber.new(number) 6 | tel.free_form_number.should == number 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /lib/quickbooks/service/item_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class ItemChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "Item" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::ItemChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/disconnect_200.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 2011-11-23T17:15:27.21097Z 5 | 6 | -------------------------------------------------------------------------------- /lib/quickbooks/service/invoice_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class InvoiceChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "Invoice" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::InvoiceChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/payment_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class PaymentChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "Payment" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::PaymentChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/vendor_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class VendorChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "Vendor" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::VendorChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | ## How to Release 2 | 3 | * Bump version number in `lib/quickbooks/version.rb` 4 | * Document changes in `HISTORY.md` 5 | * Run `gem release quickbooks-ruby.gemspec` -- requires the `gem-release` gem 6 | 7 | * Tag the release 8 | $ git tag -a v0.5.0 -m "0.5.0" 9 | 10 | * Push with tags 11 | git push origin --tags 12 | -------------------------------------------------------------------------------- /lib/quickbooks/service/bill.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Bill < BaseService 4 | 5 | def delete(bill) 6 | delete_by_query_string(bill) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::Bill 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/customer_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class CustomerChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "Customer" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::CustomerChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | - 2.0.0 5 | - 2.1.0 6 | - 2.2.0 7 | # Bundler 1.13 added support for `ruby RUBY_VERSION` in the Gemfile 8 | before_install: gem install bundler -v '>= 1.13.0' 9 | 10 | sudo: false 11 | notifications: 12 | email: 13 | - toolbag@gmail.com 14 | - christian@minimul.com 15 | -------------------------------------------------------------------------------- /lib/quickbooks/service/deposit.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Deposit < BaseService 4 | 5 | def delete(payment) 6 | delete_by_query_string(payment) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::Deposit 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/transfer.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Transfer < BaseService 4 | 5 | def delete(transfer) 6 | delete_by_query_string(transfer) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::Transfer 13 | end 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /lib/quickbooks/service/credit_memo_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class CreditMemoChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "CreditMemo" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::CreditMemoChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/purchase.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Purchase < BaseService 4 | 5 | def delete(purchase) 6 | delete_by_query_string(purchase) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::Purchase 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/model/has_line_items.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | module HasLineItems 4 | def initialize(*args) 5 | ensure_line_items_initialization 6 | super 7 | end 8 | 9 | def ensure_line_items_initialization 10 | self.line_items ||= [] 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/quickbooks/service/journal_entry.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class JournalEntry < BaseService 4 | 5 | def delete(entry) 6 | delete_by_query_string(entry) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::JournalEntry 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/refund_receipt_change.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class RefundReceiptChange < ChangeService 4 | 5 | private 6 | 7 | def entity 8 | "RefundReceipt" 9 | end 10 | 11 | def model 12 | Quickbooks::Model::RefundReceiptChange 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/credit_memo.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class CreditMemo < BaseService 4 | 5 | def delete(credit_memo) 6 | delete_by_query_string(credit_memo) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::CreditMemo 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/term.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Term < BaseService 4 | 5 | def delete(term) 6 | term.active = false 7 | update(term, :sparse => true) 8 | end 9 | 10 | private 11 | 12 | def model 13 | Quickbooks::Model::Term 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/quickbooks/model/bill_payment_credit_card.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class BillPaymentCreditCard < BaseModel 4 | xml_accessor :cc_account_ref, :from => 'CCAccountRef', :as => BaseReference 5 | xml_accessor :cc_detail, :from => 'CCDetail', :as => CreditCardPayment 6 | 7 | reference_setters 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/quickbooks/service/bill_payment.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class BillPayment < BaseService 4 | 5 | def delete(bill_payment) 6 | delete_by_query_string(bill_payment) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::BillPayment 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/time_activity.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class TimeActivity < BaseService 4 | 5 | def delete(time_activity) 6 | delete_by_query_string(time_activity) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::TimeActivity 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/query_validation_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Invalid query 5 | QueryValidationError: value 0 is too small. Min allowed value is 1 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/quickbooks/model/telephone_number.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TelephoneNumber < BaseModel 4 | xml_accessor :free_form_number, :from => 'FreeFormNumber' 5 | 6 | def initialize(number = nil) 7 | unless number.nil? 8 | self.free_form_number = number 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/quickbooks/service/purchase_order.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class PurchaseOrder < BaseService 4 | 5 | def delete(purchase_order) 6 | delete_by_query_string(purchase_order) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::PurchaseOrder 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/refund_receipt.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class RefundReceipt < BaseService 4 | 5 | def delete(refund_receipt) 6 | delete_by_query_string(refund_receipt) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::RefundReceipt 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/vendor_credit.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class VendorCredit < BaseService 4 | 5 | def delete(vendor_credit) 6 | delete_by_query_string(vendor_credit) 7 | end 8 | 9 | private 10 | 11 | def model 12 | Quickbooks::Model::VendorCredit 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/service/account.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Account < BaseService 4 | 5 | def delete(account) 6 | account.active = false 7 | update(account, :sparse => true) 8 | end 9 | 10 | private 11 | 12 | def model 13 | Quickbooks::Model::Account 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/fixtures/disconnect_270.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | OAuth Token rejected 4 | 270 5 | 2011-11-24T17:45:27.11097Z 6 | 7 | -------------------------------------------------------------------------------- /spec/fixtures/access_token_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Invalid App Token 4 | 24 5 | 2012-01-04T19:21:21.0782072Z 6 | 7 | -------------------------------------------------------------------------------- /lib/quickbooks/model/sales_tax_rate_list.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class SalesTaxRateList < BaseModel 4 | XML_COLLECTION_NODE = "SalesTaxRateList" 5 | XML_NODE = "SalesTaxRateList" 6 | REST_RESOURCE = "salestaxratelist" 7 | 8 | xml_accessor :tax_rate_detail, :from => "TaxRateDetail", :as => [TaxRateDetail] 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/quickbooks/service/customer.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Customer < BaseService 4 | 5 | def delete(customer) 6 | customer.active = false 7 | update(customer, :sparse => true) 8 | end 9 | 10 | private 11 | 12 | def model 13 | Quickbooks::Model::Customer 14 | end 15 | 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/fixtures/access_token_270.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | OAuth Token Rejected 4 | 270 5 | 2012-01-04T19:21:21.0782072Z 6 | 7 | -------------------------------------------------------------------------------- /lib/quickbooks/service/batch.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Batch < BaseService 4 | 5 | def make_request(entity, options = {}) 6 | response = do_http_post(url_for_resource('batch'), valid_xml_document(entity.to_xml_ns), options[:query]) 7 | Quickbooks::Model::BatchResponse.from_xml(response.plain_body) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/fixtures/access_token_212.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Token Refresh Window Out of Bounds 4 | 212 5 | 2012-01-04T19:21:21.0782072Z 6 | 7 | -------------------------------------------------------------------------------- /lib/quickbooks/model/purchase_tax_rate_list.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class PurchaseTaxRateList < BaseModel 4 | XML_COLLECTION_NODE = "PurchaseTaxRateList" 5 | XML_NODE = "PurchaseTaxRateList" 6 | REST_RESOURCE = "purchasetaxratelist" 7 | 8 | xml_accessor :tax_rate_detail, :from => "TaxRateDetail", :as => [TaxRateDetail] 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/fixtures/tax_service.xml: -------------------------------------------------------------------------------- 1 | 2 | Rate Spec 3 | 1 4 | 5 | 1 6 | Rate Spec 7 | 3.5 8 | 2 9 | Sales 10 | 11 | 12 | -------------------------------------------------------------------------------- /spec/fixtures/throttle_exceeded_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | message=ThrottleExceeded; errorCode=003001; statusCode=403 5 | The request limit was reached. Try again later 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/quickbooks/model/entity.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Entity < BaseModel 4 | include NameEntity::Quality 5 | 6 | xml_accessor :type, :from => 'Type' 7 | xml_accessor :entity_ref, :as => BaseReference 8 | 9 | reference_setters :entity_ref 10 | 11 | #== Validations 12 | validate :entity_type_is_valid 13 | 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/model/web_site_address.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class WebSiteAddress < BaseModel 4 | xml_accessor :uri, :from => 'URI' 5 | 6 | def initialize(uri = nil) 7 | self.uri = uri if uri 8 | end 9 | 10 | def to_xml(options = {}) 11 | return "" if uri.to_s.empty? 12 | super(options) 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/model/change_model.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | # Refer to: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture 4 | class ChangeModel < BaseModel 5 | xml_accessor :id, :from => 'Id' 6 | xml_accessor :status, :from => '@status' 7 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/fixtures/company_currency.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 3 5 | 6 | 2013-04-20T10:32:18-07:00 7 | 2013-07-11T08:27:06-07:00 8 | 9 | Euro 10 | EUR 11 | true 12 | 13 | -------------------------------------------------------------------------------- /spec/fixtures/generic_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | An application error has occurred while processing your request 5 | System Failure Error: Could not find resource for relative : some more info here 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/quickbooks/model/check_payment.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class CheckPayment < BaseModel 4 | xml_accessor :check_number, :from => 'CheckNum' 5 | xml_accessor :status, :from => 'Status' 6 | xml_accessor :name_on_account, :from => 'NameOnAcct' 7 | xml_accessor :account_number, :from => 'AcctNum' 8 | xml_accessor :bank_name, :from => 'BankName' 9 | end 10 | end 11 | end -------------------------------------------------------------------------------- /spec/fixtures/class.xml: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | 1 4 | 5 | 2014-04-16T05:40:25-07:00 6 | 2014-04-16T05:40:25-07:00 7 | 8 | Design 9 | false 10 | Design 11 | true 12 | 13 | -------------------------------------------------------------------------------- /spec/fixtures/fault.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Length exceeds limit 4 | Length of the field exceeds 21 chars 5 | 6 | 7 | Illegal number format 8 | ZipCode should be a number with at least 5 digits 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/quickbooks/service/company_currency.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class CompanyCurrency < BaseService 4 | 5 | def delete(company_currency) 6 | company_currency.active = false 7 | update(company_currency, :sparse => true) 8 | end 9 | 10 | private 11 | 12 | def model 13 | Quickbooks::Model::CompanyCurrency 14 | end 15 | 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/fixtures/json/tax_service_error_dup.json: -------------------------------------------------------------------------------- 1 | { 2 | "Fault": { 3 | "Error": [ 4 | { 5 | "Message": "Duplicate Name Exists Error", 6 | "Detail": "The name supplied already exists. : Another tax rate is already using this \nname. Please use a different name.", 7 | "code": "6240", 8 | "element": "" 9 | } 10 | ], 11 | "type": "ValidationFault" 12 | }, 13 | "time": "2015-08-07T05:35:56.791-07:00" 14 | } 15 | -------------------------------------------------------------------------------- /spec/support/fixture_helpers.rb: -------------------------------------------------------------------------------- 1 | module FixtureHelpers 2 | def fixture_path 3 | File.expand_path("../../fixtures", __FILE__) 4 | end 5 | 6 | def fixture(file) 7 | File.new(fixture_path + '/' + file).read 8 | end 9 | 10 | def json_fixture(file) 11 | File.new("#{fixture_path}/json/#{file.to_s}.json").read 12 | end 13 | 14 | end 15 | 16 | RSpec.configure do |config| 17 | config.include(FixtureHelpers) 18 | end 19 | -------------------------------------------------------------------------------- /lib/quickbooks/model/base_model_json.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class BaseModelJSON < BaseModel 4 | 5 | def to_json 6 | params = {} 7 | attributes.each_pair do |k, v| 8 | next if v.blank? 9 | params[k.camelize] = v.is_a?(Array) ? v.inject([]){|mem, item| mem << item.to_json; mem} : v 10 | end 11 | params.to_json 12 | end 13 | 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/util/logging.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Util 3 | module Logging 4 | def log(msg) 5 | ::Quickbooks.log(msg) 6 | end 7 | 8 | def log_xml(str) 9 | if ::Quickbooks.log_xml_pretty_print? && !(str and str.empty?) 10 | Nokogiri::XML(str).to_xml 11 | else 12 | str 13 | end 14 | rescue => e 15 | e 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/fixtures/tax_agency.xml: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | 0 4 | 5 | 2013-12-11T10:59:51-08:00 6 | 2013-12-11T10:59:51-08:00 7 | 8 | First TaxAgency 9 | false 10 | true 11 | 12 | -------------------------------------------------------------------------------- /lib/quickbooks/util/collection.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | class Collection 3 | include Enumerable 4 | attr_accessor :entries 5 | 6 | attr_accessor :body 7 | 8 | # Legacy Attributes (v2) 9 | attr_accessor :count, :current_page 10 | 11 | # v3 Attributes 12 | attr_accessor :start_position, :max_results, :total_count 13 | 14 | def each(*args, &block) 15 | (entries|| []).each *args, &block 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/fixtures/too_many_requests_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | message=ThrottleExceeded; errorCode=003001; statusCode=429 6 | The request limit was reached. Try again later 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/item_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::ItemChange" do 4 | it "parse from XML" do 5 | xml = fixture("item_change.xml") 6 | item = Quickbooks::Model::ItemChange.from_xml(xml) 7 | item.status.should == 'Deleted' 8 | item.id.should == "39" 9 | 10 | item.meta_data.should_not be_nil 11 | item.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 12 | end 13 | end -------------------------------------------------------------------------------- /lib/quickbooks/model/item_group_line.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class ItemGroupLine < BaseModel 4 | xml_accessor :item_ref, :from => 'ItemRef', :as => BaseReference 5 | xml_accessor :quantity, :from => 'Qty' 6 | 7 | def id 8 | item_ref.value.to_i 9 | end 10 | 11 | def name 12 | item_ref.name 13 | end 14 | 15 | def type 16 | item_ref.type 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/fixtures/attachable_create_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2700000000002413265 4 | 0 5 | 6 | 2015-02-07T15:12:13-08:00 7 | 2015-02-07T15:12:13-08:00 8 | 9 | A note 10 | 11 | -------------------------------------------------------------------------------- /spec/fixtures/item_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 39 6 | 7 | 2014-12-08T19:36:24-08:00 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/quickbooks/model/transaction_tax_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TransactionTaxDetail < BaseModel 4 | 5 | xml_accessor :txn_tax_code_ref, :from => 'TxnTaxCodeRef', :as => BaseReference 6 | xml_accessor :total_tax, :from => 'TotalTax', :as => BigDecimal, :to_xml => to_xml_big_decimal 7 | xml_accessor :lines, :from => 'TaxLine', :as => [TaxLine] 8 | 9 | reference_setters :txn_tax_code_ref 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/fixtures/vendor_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 39 6 | 7 | 2014-12-08T19:36:24-08:00 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/quickbooks/model/email_address.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class EmailAddress < BaseModel 4 | xml_accessor :address, :from => 'Address' 5 | 6 | def to_xml(options = {}) 7 | return "" if address.to_s.empty? 8 | super 9 | end 10 | 11 | def initialize(email_address = nil) 12 | unless email_address.nil? 13 | self.address = email_address 14 | end 15 | end 16 | 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/fixtures/invoice_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 39 6 | 7 | 2014-12-08T19:36:24-08:00 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /spec/fixtures/customer_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 39 6 | 7 | 2014-12-08T19:36:24-08:00 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /spec/fixtures/exchange_rate.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 3 | 0 4 | 5 | 2013-12-11T10:59:51-08:00 6 | 2013-12-11T10:59:51-08:00 7 | 8 | EUR 9 | USD 10 | 2.5 11 | 2015-07-07 12 | 13 | -------------------------------------------------------------------------------- /spec/fixtures/payment_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 39 6 | 7 | 2014-12-08T19:36:24-08:00 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/vendor_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::VendorChange" do 4 | it "parse from XML" do 5 | xml = fixture("vendor_change.xml") 6 | vendor = Quickbooks::Model::VendorChange.from_xml(xml) 7 | vendor.status.should == 'Deleted' 8 | vendor.id.should == "39" 9 | 10 | vendor.meta_data.should_not be_nil 11 | vendor.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 12 | end 13 | end -------------------------------------------------------------------------------- /lib/quickbooks/model/group_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class GroupLineDetail < BaseModel 4 | include HasLineItems 5 | 6 | xml_accessor :group_item_ref, :from => 'CustomerRef', :as => BaseReference 7 | xml_accessor :quantity, :from => 'Quantity', :as => BigDecimal, :to_xml => to_xml_big_decimal 8 | xml_accessor :line_items, :from => 'Line', :as => [Line] 9 | 10 | reference_setters :group_item_ref 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/fixtures/department.xml: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | 0 4 | 5 | 2013-08-13T11:49:31-07:00 6 | 2013-08-13T11:49:31-07:00 7 | 8 | Sales Department 9 | false 10 | Sales Department 11 | true 12 | 13 | -------------------------------------------------------------------------------- /spec/fixtures/credit_memo_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 39 6 | 7 | 2014-12-08T19:36:24-08:00 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/invoice_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::InvoiceChange" do 4 | it "parse from XML" do 5 | xml = fixture("invoice_change.xml") 6 | invoice = Quickbooks::Model::InvoiceChange.from_xml(xml) 7 | invoice.status.should == 'Deleted' 8 | invoice.id.should == "39" 9 | 10 | invoice.meta_data.should_not be_nil 11 | invoice.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 12 | end 13 | end -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/tax_code_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::TaxCode" do 2 | before(:all) { construct_service :tax_code } 3 | 4 | it "can query tax codes" do 5 | stub_request(:get, 6 | @service.url_for_query, 7 | ["200", "OK"], 8 | fixture("tax_codes.xml")) 9 | 10 | tax_codes = @service.query 11 | 12 | tax_codes.entries.count.should eq(11) 13 | tax_codes.entries.first.name.should eq("TAX") 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/fixtures/access_token_200.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0 5 | 2012-01-04T19:21:21.0782072Z 6 | qye2eIdQ5H5yMyrlJflUWh712xfFXjyNnW1MfbC0rz04TfCP 7 | cyDeUNQTkFzoR0KkDn7viN6uLQxWTobeEUKW7I79 8 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/payment_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::PaymentChange" do 4 | it "parse from XML" do 5 | xml = fixture("payment_change.xml") 6 | payment = Quickbooks::Model::PaymentChange.from_xml(xml) 7 | payment.status.should == 'Deleted' 8 | payment.id.should == "39" 9 | 10 | payment.meta_data.should_not be_nil 11 | payment.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/quickbooks/model/fault.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Fault < BaseModel 4 | class Error 5 | include ROXML 6 | xml_name 'Error' 7 | xml_accessor :code, :from => "@code" 8 | xml_accessor :element, :from => "@element" 9 | xml_accessor :message, :from => "Message" 10 | xml_accessor :detail, :from => "Detail" 11 | end 12 | 13 | xml_accessor :errors, :as => [Quickbooks::Model::Fault::Error] 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/refund_receipt_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 40 6 | 7 | 2014-12-09T19:30:24-08:00 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/customer_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::CustomerChange" do 4 | it "parse from XML" do 5 | xml = fixture("customer_change.xml") 6 | customer = Quickbooks::Model::CustomerChange.from_xml(xml) 7 | customer.status.should == 'Deleted' 8 | customer.id.should == "39" 9 | 10 | customer.meta_data.should_not be_nil 11 | customer.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 12 | end 13 | end -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/tax_rate_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::TaxRate" do 2 | before(:all) { construct_service :tax_rate } 3 | 4 | it "can query tax rates" do 5 | stub_request(:get, 6 | @service.url_for_query, 7 | ["200", "OK"], 8 | fixture("tax_rates.xml")) 9 | 10 | tax_rates = @service.query 11 | 12 | tax_rates.entries.count.should eq(1) 13 | tax_rates.entries.first.name.should eq("Mountain View") 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/quickbooks/model/bill_payment_check.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class BillPaymentCheck < BaseModel 4 | xml_accessor :bank_account_ref, :from => 'BankAccountRef', :as => BaseReference 5 | xml_accessor :print_status, :from => 'PrintStatus' 6 | xml_accessor :check_detail, :from => 'CheckDetail', :as => CheckPayment 7 | xml_accessor :payee_address, :from => 'PayeeAddr', :as => PhysicalAddress 8 | 9 | reference_setters :bank_account_ref 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /spec/fixtures/exchange_rate_by_currency.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2013-12-11T10:59:51-08:00 5 | 6 | EUR 7 | USD 8 | 2.5 9 | 2015-07-07 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/quickbooks/model/effective_tax_rate.rb: -------------------------------------------------------------------------------- 1 | require 'time' 2 | 3 | module Quickbooks 4 | module Model 5 | class EffectiveTaxRate < BaseModel 6 | XML_COLLECTION_NODE = "EffectiveTaxRate" 7 | XML_NODE = "EffectiveTaxRate" 8 | REST_RESOURCE = "effectivetaxrate" 9 | 10 | xml_accessor :rate_value, :from => 'RateValue' 11 | xml_accessor :effective_date, :from => 'EffectiveDate', :as => Time 12 | xml_accessor :end_date, :from => 'EndDate', :as => Time 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/quickbooks/service/preferences.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Preferences < BaseService 4 | 5 | def url_for_query(query = nil, start_position = 1, max_results = 20, options = {}) 6 | url = super(query, start_position, max_results, options) 7 | "#{url}&minorversion=#{Quickbooks::Model::Preferences::MINORVERSION}" 8 | end 9 | 10 | private 11 | 12 | def model 13 | Quickbooks::Model::Preferences 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/fixtures/invoice_sparse_create_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 1001 3 | 2013-11-20 4 | 5 | Plush Baby Doll 6 | 50 7 | SalesItemLineDetail 8 | 9 | 1 10 | 50 11 | 1 12 | 13 | 14 | 1 15 | -------------------------------------------------------------------------------- /spec/fixtures/customer_duplicate_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Duplicate Name Exists Error 6 | The name supplied already exists. : Another $$customer$$ is already using this name. Please use a different name. 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | unless ENV['CI'] 3 | require 'simplecov' 4 | SimpleCov.start do 5 | add_filter 'spec' 6 | end 7 | end 8 | 9 | require 'rubygems' 10 | require 'rspec' 11 | require 'fakeweb' 12 | require 'oauth' 13 | require 'quickbooks-ruby' 14 | require 'json' 15 | require 'pry' 16 | 17 | Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f } 18 | 19 | RSpec.configure do |config| 20 | config.color = true 21 | end 22 | 23 | I18n.enforce_available_locales = false 24 | -------------------------------------------------------------------------------- /lib/quickbooks/model/global_tax_calculation.rb: -------------------------------------------------------------------------------- 1 | module GlobalTaxCalculation 2 | extend ActiveSupport::Concern 3 | 4 | TAX_INCLUSIVE = "TaxInclusive" 5 | TAX_EXCLUDED = "TaxExcluded" 6 | NOT_APPLICABLE = "NotApplicable" 7 | GLOBAL_TAX_CALCULATION = [TAX_INCLUSIVE, TAX_EXCLUDED, NOT_APPLICABLE] 8 | 9 | included do 10 | xml_accessor :global_tax_calculation, :from => 'GlobalTaxCalculation' 11 | validates_inclusion_of :global_tax_calculation, :in => GLOBAL_TAX_CALCULATION, allow_blank: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/quickbooks/model/document_numbering.rb: -------------------------------------------------------------------------------- 1 | module DocumentNumbering 2 | 3 | # Convenience method for proper AutoDocNumber tag 4 | # construction, which should be blank if auto 5 | # document numbering is desired. 6 | def auto_doc_number! 7 | self.auto_doc_number = '' 8 | end 9 | 10 | private 11 | 12 | def document_numbering 13 | if !auto_doc_number.nil? && !doc_number.nil? 14 | errors.add(:doc_number, "DocumentNumber should not be specified if AutoDocNumber is.") 15 | end 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /lib/quickbooks/model/markup_info.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class MarkupInfo < BaseModel 4 | xml_accessor :percent_based, :from => 'PercentBased' 5 | xml_accessor :value, :from => 'Value', :as => BigDecimal, :to_xml => to_xml_big_decimal 6 | xml_accessor :percent, :from => 'Percent', :as => BigDecimal, :to_xml => to_xml_big_decimal 7 | xml_accessor :price_level_ref, :from => 'PriceLevelRef', :as => BaseReference 8 | 9 | reference_setters :price_level_ref 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_rate_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxRateDetail < BaseModel 4 | XML_COLLECTION_NODE = "TaxRateDetail" 5 | XML_NODE = "TaxRateDetail" 6 | REST_RESOURCE = "taxratedetail" 7 | 8 | xml_accessor :tax_rate_ref, :from => "TaxRateRef", :as => BaseReference 9 | xml_accessor :tax_type_applicable, :from => "TaxTypeApplicable" 10 | xml_accessor :tax_order, :from => "TaxOrder" 11 | 12 | reference_setters :tax_rate_ref 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/credit_memo_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::CreditMemoChange" do 4 | it "parse from XML" do 5 | xml = fixture("credit_memo_change.xml") 6 | credit_memo = Quickbooks::Model::CreditMemoChange.from_xml(xml) 7 | credit_memo.status.should == 'Deleted' 8 | credit_memo.id.should == "39" 9 | 10 | credit_memo.meta_data.should_not be_nil 11 | credit_memo.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/sales_line_item_detail_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::SalesItemLineDetail" do 2 | 3 | it "rate percent should be a decimal/float if set" do 4 | detail = Quickbooks::Model::SalesItemLineDetail.new 5 | detail.rate_percent = 10 6 | detail.to_xml.at_css('RatePercent').content.should == '10.0' 7 | end 8 | 9 | it "rate percent should not be included if not set" do 10 | detail = Quickbooks::Model::SalesItemLineDetail.new 11 | detail.to_xml.should_not =~ /RatePercent/ 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/quickbooks/model/payment_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class PaymentLineDetail < BaseModel 4 | xml_accessor :item_ref, :from => 'ItemRef', :as => BaseReference 5 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 6 | xml_accessor :balance, :from => 'Balance', :as => BigDecimal, :to_xml => to_xml_big_decimal 7 | xml_accessor :discount, :from => 'Discount', :as => DiscountOverride 8 | 9 | reference_setters :item_ref, :class_ref 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/exchange_rate_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::ExchangeRate" do 2 | it "parse from XML" do 3 | xml = fixture("exchange_rate.xml") 4 | item = Quickbooks::Model::ExchangeRate.from_xml(xml) 5 | item.id.should == "9" 6 | item.sync_token.should == 0 7 | item.meta_data.should_not be_nil 8 | item.source_currency_code.should == "EUR" 9 | item.target_currency_code.should == "USD" 10 | item.rate.should == 2.5 11 | item.as_of_date.to_date.should == Date.civil(2015, 07, 07) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_payment_method_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 4 | 0 5 | 6 | 2013-12-09T10:44:18-08:00 7 | 2013-12-09T10:44:18-08:00 8 | 9 | Discover 10 | true 11 | CREDIT_CARD 12 | 13 | 14 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/purchase_order_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::PurchaseOrder" do 2 | 3 | before(:all) do 4 | construct_service :purchase_order 5 | end 6 | 7 | it "can delete a vendor" do 8 | model = Quickbooks::Model::PurchaseOrder 9 | purchase_order = model.new 10 | xml = fixture("deleted_purchase_order.xml") 11 | stub_request(:post, @service.url_for_resource(model::REST_RESOURCE), ["200", "OK"], xml, {}, false) 12 | expect(@service.delete(purchase_order)).to eq true 13 | 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/deleted_payment_method.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 4 | 0 5 | 6 | 2013-12-09T10:44:18-08:00 7 | 2013-12-09T10:44:18-08:00 8 | 9 | Discover (Deleted) 10 | false 11 | CREDIT_CARD 12 | 13 | 14 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/refund_receipt_change_spec.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | 3 | describe "Quickbooks::Model::RefundReceiptChange" do 4 | it "parse from XML" do 5 | xml = fixture("refund_receipt_change.xml") 6 | refund_receipt = Quickbooks::Model::RefundReceiptChange.from_xml(xml) 7 | refund_receipt.status.should == 'Deleted' 8 | refund_receipt.id.should == "40" 9 | 10 | refund_receipt.meta_data.should_not be_nil 11 | refund_receipt.meta_data.last_updated_time.should == DateTime.parse("2014-12-09T19:30:24-08:00") 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/quickbooks/model/invoice_group_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class InvoiceGroupLineDetail < InvoiceLineItem 4 | include HasLineItems 5 | 6 | xml_accessor :id, :from => 'Id' 7 | xml_accessor :group_item_ref, :from => 'GroupItemRef', :as => BaseReference 8 | xml_accessor :quantity, :from => 'Quantity', :as => BigDecimal, :to_xml => to_xml_big_decimal 9 | xml_accessor :line_items, :from => 'Line', :as => [InvoiceLineItem] 10 | 11 | reference_setters :group_item_ref 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/transfer_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::Transfer" do 2 | before(:all) do 3 | construct_service :transfer 4 | end 5 | 6 | it "can query for transfers" do 7 | xml = fixture("transfers.xml") 8 | model = Quickbooks::Model::Transfer 9 | 10 | stub_request(:get, @service.url_for_query, ["200", "OK"], xml) 11 | transfers_query = @service.query 12 | transfers_query.entries.count.should == 1 13 | 14 | transfer = transfers_query.entries.first 15 | transfer.amount.should == 250.00 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /lib/quickbooks/model/custom_field.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class CustomField < BaseModel 4 | xml_accessor :id, :from => 'DefinitionId', :as => Integer 5 | xml_accessor :name, :from => 'Name' 6 | xml_accessor :type, :from => 'Type' 7 | xml_accessor :string_value, :from => 'StringValue' 8 | xml_accessor :boolean_value, :from => 'BooleanValue' 9 | xml_accessor :date_value, :from => 'DateValue', :as => Date 10 | xml_accessor :number_value, :from => 'NumberValue', :as => Integer 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/fixtures/deleted_company_currency.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 3 6 | 7 | 2013-04-20T10:32:18-07:00 8 | 2013-07-11T08:27:06-07:00 9 | 10 | Euro 11 | EUR 12 | false 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_company_currency_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 3 6 | 7 | 2013-04-20T10:32:18-07:00 8 | 2013-07-11T08:27:06-07:00 9 | 10 | Euro 11 | EUR 12 | true 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/company_currency_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::CompanyCurrency" do 2 | it "parse from XML" do 3 | xml = fixture('company_currency.xml') 4 | company_currency = Quickbooks::Model::CompanyCurrency.from_xml(xml) 5 | 6 | company_currency.id.should == "1" 7 | company_currency.sync_token.should == 3 8 | 9 | company_currency.meta_data.should_not be_nil 10 | company_currency.name.should == "Euro" 11 | company_currency.code.should == "EUR" 12 | company_currency.active?.should == true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_line.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxLine < BaseModel 4 | 5 | xml_accessor :id, :from => 'Id' 6 | xml_accessor :line_num, :from => 'LineNum', :as => Integer 7 | xml_accessor :description, :from => 'Description' 8 | xml_accessor :amount, :from => 'Amount', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 9 | xml_accessor :detail_type, :from => 'DetailType' 10 | 11 | xml_accessor :tax_line_detail, :from => 'TaxLineDetail', :as => TaxLineDetail 12 | 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/fixtures/term.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 3 | 0 4 | 5 | 2013-07-11T17:46:39-07:00 6 | 2013-07-11T17:46:42-07:00 7 | 8 | TermForV3Testing-1373590184130 9 | true 10 | DATE_DRIVEN 11 | 4.0000000 12 | 1 13 | 2 14 | 3 15 | 16 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_class_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 2 5 | 6 | 2014-04-16T05:40:25-07:00 7 | 2014-04-16T05:40:25-07:00 8 | 9 | Design 10 | false 11 | Design 12 | true 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/quickbooks/model/discount_override.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class DiscountOverride < BaseModel 4 | xml_accessor :discount_ref, :from => 'DiscountRef', :as => BaseReference 5 | xml_accessor :percent_based?, :from => 'PercentBased' 6 | xml_accessor :discount_percent, :from => 'DiscountPercent', :as => BigDecimal, :to_xml => to_xml_big_decimal 7 | xml_accessor :discount_account_ref, :from => 'DiscountAccountRef', :as => BaseReference 8 | 9 | reference_setters :discount_ref, :discount_account_ref 10 | 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/fixtures/tax_service_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | First Tax Service 5 | 1 6 | 7 | 1 8 | Rate Spec 9 | 3.5 10 | 2 11 | Sales 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/quickbooks/service/estimate.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Estimate < BaseService 4 | 5 | def delete(estimate) 6 | delete_by_query_string(estimate) 7 | end 8 | 9 | def pdf(estimate) 10 | url = "#{url_for_resource(model::REST_RESOURCE)}/#{estimate.id}/pdf" 11 | response = do_http_raw_get(url, {}, {'Accept' => 'application/pdf'}) 12 | response.plain_body 13 | end 14 | 15 | private 16 | 17 | def model 18 | Quickbooks::Model::Estimate 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/fixtures/deleted_class.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 3000000000000299495 4 | 0 5 | 6 | 2014-04-16T05:40:25-07:00 7 | 2014-04-16T05:40:25-07:00 8 | 9 | Design (Deleted) 10 | false 11 | Design 12 | false 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/fixtures/transfer.xml: -------------------------------------------------------------------------------- 1 | 2 | 148 3 | 0 4 | 5 | 2016-02-11T06:00:44-08:00 6 | 2016-02-11T06:00:44-08:00 7 | 8 | 2016-02-11 9 | USD 10 | Important notes to explain this transaction 11 | 36 12 | 35 13 | 250.00 14 | -------------------------------------------------------------------------------- /spec/fixtures/payment.xml: -------------------------------------------------------------------------------- 1 | 2 | 8748 3 | 0 4 | 5 | 2013-07-11T17:51:41-07:00 6 | 2013-07-11T17:51:42-07:00 7 | 8 | 2013-07-11 9 | Payment smoke test 10 | 25342 11 | 4 12 | 40.00 13 | 40.00 14 | false 15 | 16 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/payment_method_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Model::PaymentMethod do 2 | it "must have a valid type if defined" do 3 | account = Quickbooks::Model::PaymentMethod.new 4 | 5 | # It should allow nil 6 | account.valid? 7 | account.errors.keys.include?(:type).should == false 8 | 9 | account.type = 'Undocummented Type' 10 | account.valid? 11 | account.errors.keys.include?(:type).should == true 12 | 13 | account.type = Quickbooks::Model::PaymentMethod::CREDIT_CARD 14 | account.valid? 15 | account.errors.keys.include?(:type).should == false 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/fixtures/company_currency_query.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1 6 | 3 7 | 8 | 2013-04-20T10:32:18-07:00 9 | 2013-07-11T08:27:06-07:00 10 | 11 | Euro 12 | EUR 13 | true 14 | 15 | 16 | -------------------------------------------------------------------------------- /spec/fixtures/tax_agency_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 0 6 | 7 | 2013-12-11T10:59:51-08:00 8 | 2013-12-11T10:59:51-08:00 9 | 10 | First TaxAgency 11 | false 12 | true 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/util/collection_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Collection do 2 | it "is has an #each" do 3 | collection = Quickbooks::Collection.new() 4 | collection.entries = [:foo] 5 | expect{ |b| collection.each &b}.to yield_with_args(:foo) 6 | end 7 | it "has a method from enumerable" do 8 | collection = Quickbooks::Collection.new() 9 | collection.entries = [:foo] 10 | expect( collection.first).to be(:foo) 11 | end 12 | it "doesn't error when no entries are set" do 13 | collection = Quickbooks::Collection.new() 14 | expect{collection.first}.to_not raise_error 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/quickbooks/model/budget_line_item.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class BudgetLineItem < BaseModel 4 | 5 | xml_accessor :date, :from => 'BudgetDate', :as => Date 6 | xml_accessor :amount, :from => 'Amount' 7 | xml_accessor :account_ref, :from => 'AccountRef', :as => BaseReference 8 | xml_accessor :customer_ref, :from => 'CustomerRef', :as => BaseReference 9 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 10 | xml_accessor :department_ref, :from => 'DepartmentRef', :as => BaseReference 11 | 12 | reference_setters 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/preferences_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::Preferences" do 2 | before(:all) do 3 | construct_service :preferences 4 | end 5 | 6 | it "can query for preferences" do 7 | xml = fixture("preferences_query.xml") 8 | model = Quickbooks::Model::Preferences 9 | 10 | stub_request(:get, @service.url_for_query, ["200", "OK"], xml) 11 | preferences_query = @service.query 12 | preferences_query.entries.count.should == 1 13 | 14 | preferences = preferences_query.entries.first 15 | preferences.accounting_info.customer_terminology.should == "Customers" 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /lib/quickbooks/service/class.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Class < BaseService 4 | 5 | def update(entity, options = {}) 6 | raise Quickbooks::InvalidModelException.new('Class sparse update is not supported by Intuit at this time') if options[:sparse] && options[:sparse] == true 7 | super(entity, options) 8 | end 9 | 10 | def delete(classs) 11 | classs.active = false 12 | update(classs, :sparse => false) 13 | end 14 | 15 | private 16 | 17 | def model 18 | Quickbooks::Model::Class 19 | end 20 | 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/fixtures/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 2 3 | 0 4 | 5 | 2013-11-16T17:42:03-08:00 6 | 2013-11-16T17:42:03-08:00 7 | 8 | Plush Baby Doll 9 | PBD01 10 | A fine baby doll - in many colors 11 | true 12 | false 13 | 50 14 | Service 15 | 1 16 | 0 17 | false 18 | 19 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_payment_method_by_name.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 5 | 0 6 | 7 | 2013-12-09T10:44:18-08:00 8 | 2013-12-09T10:44:18-08:00 9 | 10 | Discover 11 | true 12 | CREDIT_CARD 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/quickbooks/model/attachable_ref.rb: -------------------------------------------------------------------------------- 1 | require 'quickbooks/model/entity_ref' 2 | require 'quickbooks/model/custom_field' 3 | 4 | module Quickbooks 5 | module Model 6 | class AttachableRef < BaseModel 7 | xml_accessor :entity_ref, :as => BaseReference 8 | xml_accessor :line_info 9 | xml_accessor :include_on_send? 10 | xml_accessor :inactive? 11 | xml_accessor :no_ref_only? 12 | xml_accessor :custom_fields, :as => [CustomField] 13 | 14 | def initialize(an_entity_ref = nil) 15 | if an_entity_ref 16 | self.entity_ref = an_entity_ref 17 | end 18 | end 19 | 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/quickbooks/service/department.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Department < BaseService 4 | 5 | def update(entity, options = {}) 6 | raise Quickbooks::InvalidModelException.new('Department sparse update is not supported by Intuit at this time') if options[:sparse] && options[:sparse] == true 7 | super(entity, options) 8 | end 9 | 10 | def delete(department) 11 | department.active = false 12 | update(department, :sparse => false) 13 | end 14 | 15 | private 16 | 17 | def model 18 | Quickbooks::Model::Department 19 | end 20 | 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/access_token_response_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Model::AccessTokenResponse do 2 | it "can parse a successful response" do 3 | xml = fixture("access_token_200.xml") 4 | response = Quickbooks::Model::AccessTokenResponse.from_xml(xml) 5 | response.error?.should == false 6 | response.error_message.should == "" 7 | response.token.length.should > 0 8 | response.secret.length.should > 0 9 | end 10 | 11 | it "can parse a unsuccessful response" do 12 | xml = fixture("access_token_270.xml") 13 | response = Quickbooks::Model::AccessTokenResponse.from_xml(xml) 14 | response.error?.should == true 15 | end 16 | end -------------------------------------------------------------------------------- /lib/quickbooks/model/sub_total_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class SubTotalLineDetail < BaseModel 4 | xml_accessor :item_ref, :from => 'ItemRef', :as => BaseReference 5 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 6 | xml_accessor :unit_price, :from => 'UnitPrice', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 7 | xml_accessor :quantity, :from => 'Qty', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 8 | xml_accessor :tax_code_ref, :from => 'TaxCodeRef', :as => BaseReference 9 | 10 | reference_setters :item_ref, :class_ref, :tax_code_ref 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /lib/quickbooks/service/vendor.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Vendor < BaseService 4 | 5 | # override update as sparse is not supported 6 | def update(entity, options = {}) 7 | raise InvalidModelException.new('Vendor sparse update is not supported by Intuit at this time') if options[:sparse] && options[:sparse] == true 8 | super(entity, options) 9 | end 10 | 11 | def delete(vendor) 12 | vendor.active = false 13 | update(vendor, :sparse => false) 14 | end 15 | 16 | private 17 | 18 | def model 19 | Quickbooks::Model::Vendor 20 | end 21 | 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_department_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 0 5 | 6 | 2013-08-13T11:52:48-07:00 7 | 2013-08-13T11:52:48-07:00 8 | 9 | Marketing Department 10 | false 11 | Marketing Department 12 | true 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/tax_rate_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::TaxRate" do 2 | it "parse from XML" do 3 | xml = fixture("tax_rate.xml") 4 | item = Quickbooks::Model::TaxRate.from_xml(xml) 5 | item.id.should == "9" 6 | item.sync_token.should == 0 7 | item.meta_data.should_not be_nil 8 | item.name.should == "Santa Clara County" 9 | item.description.should == "Sales Tax" 10 | item.should be_active 11 | item.rate_value.should == 0.5 12 | item.agency_ref.value.should == "3" 13 | item.effective_tax_rate.should_not be_nil 14 | item.special_tax_type.should == "NONE" 15 | item.display_type.should == "ReadOnly" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/fixtures/deleted_department.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 0 5 | 6 | 2013-08-13T11:52:48-07:00 7 | 2013-08-13T11:52:48-07:00 8 | 9 | Marketing Department (Deleted) 10 | false 11 | Marketing Department 12 | false 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/base_service_json_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module Quickbooks 4 | module Service 5 | describe ServiceCrudJSON do 6 | 7 | it "has the correct content-type" do 8 | json_service = construct_service :tax_service 9 | expect(json_service.class::HTTP_CONTENT_TYPE).to eq 'application/json' 10 | end 11 | 12 | it "has the correct content-type" do 13 | json_service = construct_service :tax_service 14 | json_service.send(:parse_json, json_fixture(:tax_service_error_dup)) 15 | expect { json_service.send(:parse_intuit_error) }.to_not raise_exception 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/quickbooks/model/base_reference.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class BaseReference < BaseModel 4 | xml_convention :camelcase 5 | xml_accessor :name, :from => '@name' # Attribute with name 'name' 6 | xml_accessor :value, :from => :content 7 | xml_accessor :type, :from => '@type' # Attribute with name 'type' 8 | 9 | def initialize(value=nil, attributes={}) 10 | self.value = value 11 | attributes.each {|key, value| public_send("#{key}=", value) } 12 | end 13 | 14 | def to_i 15 | self.value.to_i 16 | end 17 | 18 | def to_s 19 | self.value.to_s 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/quickbooks/model/company_currency.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class CompanyCurrency < BaseModel 4 | include NameEntity::PermitAlterations 5 | 6 | XML_COLLECTION_NODE = 'CompanyCurrency' 7 | XML_NODE = 'CompanyCurrency' 8 | REST_RESOURCE = 'companycurrency' 9 | 10 | xml_name XML_NODE 11 | xml_accessor :id, :from => 'Id' 12 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 13 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 14 | xml_accessor :name, :from => 'Name' 15 | xml_accessor :code, :from => 'Code' 16 | xml_accessor :active?, :from => 'Active' 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/quickbooks/service/change_service.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class ChangeService < BaseService 4 | 5 | def url_for_query(query = nil, start_position = 1, max_results = 20) 6 | q = entity 7 | q = "#{q}&#{query}" if query.present? 8 | 9 | "#{url_for_base}/cdc?entities=#{q}" 10 | end 11 | 12 | def since(timestamp) 13 | query("changedSince=#{URI.encode_www_form_component(timestamp.iso8601)}") 14 | end 15 | 16 | private 17 | 18 | def entity 19 | raise NotImplementedError 20 | end 21 | 22 | def model 23 | raise NotImplementedError 24 | end 25 | 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/fixtures/bill_payment_check_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 623 3 | 1 4 | 5 | 2015-12-15T00:00:00-08:00 6 | 2015-12-15T00:00:00-08:00 7 | 8 | 1 9 | 2015-12-15 10 | Acct. 1JK90 11 | 32 12 | Check 13 | 14 | 133 15 | NotSet 16 | 17 | 110.00 18 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | require "bundler" 3 | require "bundler/gem_tasks" 4 | 5 | Bundler.setup 6 | 7 | require "rake" 8 | require "rspec" 9 | require "rspec/core/rake_task" 10 | 11 | $:.unshift File.expand_path("../lib", __FILE__) 12 | require "quickbooks-ruby" 13 | 14 | task :default => :spec 15 | 16 | desc "Run all specs" 17 | RSpec::Core::RakeTask.new(:spec) do |t| 18 | t.pattern = 'spec/**/*_spec.rb' 19 | end 20 | 21 | 22 | desc "Open an irb (or pry) session preloaded with Quickbooks" 23 | task :console do 24 | begin 25 | require 'pry' 26 | sh %{pry -I lib -r quickbooks-ruby.rb} 27 | rescue LoadError => _ 28 | sh 'irb -rubygems -I lib -r quickbooks.rb' 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/quickbooks/service/employee.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Employee < BaseService 4 | 5 | # override update as sparse is not supported 6 | def update(entity, options = {}) 7 | raise Quickbooks::InvalidModelException.new('Employee sparse update is not supported by Intuit at this time') if options[:sparse] && options[:sparse] == true 8 | super(entity, options) 9 | end 10 | 11 | def delete(employee) 12 | employee.active = false 13 | update(employee, :sparse => false) 14 | end 15 | 16 | private 17 | 18 | def model 19 | Quickbooks::Model::Employee 20 | end 21 | 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/tax_agencies.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 0 6 | 7 | 2013-12-11T10:59:51-08:00 8 | 2013-12-11T10:59:51-08:00 9 | 10 | First TaxAgency 11 | false 12 | true 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_agency.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxAgency < BaseModel 4 | XML_COLLECTION_NODE = "TaxAgency" 5 | XML_NODE = "TaxAgency" 6 | REST_RESOURCE = "taxagency" 7 | 8 | xml_accessor :id, :from => "Id" 9 | xml_accessor :sync_token, :from => "SyncToken", :as => Integer 10 | xml_accessor :meta_data, :from => "MetaData", :as => MetaData 11 | xml_accessor :tax_tracked_on_purchases?, :from => "TaxTrackedOnPurchases" 12 | xml_accessor :tax_tracked_on_sales?, :from => "TaxTrackedOnSales" 13 | xml_accessor :display_name, :from => "DisplayName" 14 | 15 | validates_presence_of :display_name 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/quickbooks/service/change_data_capture.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class ChangeDataCapture < BaseService 4 | 5 | def url_for_query(entity_list, query=nil) 6 | q = entity_list.join(",") 7 | q = "#{q}&#{query}" if query.present? 8 | return "#{url_for_base}/cdc?entities=#{q}" 9 | end 10 | 11 | def since(entity_list, timestamp) 12 | do_http_get(url_for_query(entity_list, "changedSince=#{URI.encode_www_form_component(timestamp.iso8601)}")) 13 | model.new(:xml => @last_response_xml) 14 | end 15 | 16 | private 17 | 18 | def model 19 | Quickbooks::Model::ChangeDataCapture 20 | end 21 | 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/exchange_rates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 5 | 0 6 | 7 | 2013-12-11T10:59:51-08:00 8 | 2013-12-11T10:59:51-08:00 9 | 10 | EUR 11 | USD 12 | 2.5 13 | 2015-07-07 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /spec/fixtures/payment_void_response_success.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8748 4 | 0 5 | 6 | 2013-07-11T17:51:41-07:00 7 | 2013-07-11T17:51:42-07:00 8 | 9 | 2013-07-11 10 | Voided 11 | 25342 12 | 4 13 | 0 14 | 0 15 | false 16 | 17 | -------------------------------------------------------------------------------- /spec/support/net_helpers.rb: -------------------------------------------------------------------------------- 1 | module NetHelpers 2 | 3 | # +strict+ indicates whether we want to use a regex for a matching URL, which is needed 4 | # for URLs that use query params. If you don't need use query params 5 | # than its suggested to use strict = true 6 | def stub_request(method, url, status = ["200", "OK"], body = nil, headers = {}, strict = true) 7 | if !strict 8 | if url.is_a?(String) 9 | url = url.gsub('?', '\?') 10 | end 11 | uri = %r|#{url}| 12 | else 13 | uri = url 14 | end 15 | FakeWeb.register_uri(method, uri, { :status => status, :body => body }.merge(headers)) 16 | end 17 | end 18 | 19 | RSpec.configure do |config| 20 | config.include(NetHelpers) 21 | end 22 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/tax_agency_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::TaxAgency" do 2 | it "parse from XML" do 3 | xml = fixture("tax_agency.xml") 4 | item = Quickbooks::Model::TaxAgency.from_xml(xml) 5 | 6 | item.id.should == "1" 7 | item.sync_token.should == 0 8 | item.meta_data.should_not be_nil 9 | item.display_name.should == "First TaxAgency" 10 | item.tax_tracked_on_purchases?.should be_false 11 | item.tax_tracked_on_sales?.should be_true 12 | end 13 | 14 | it "should require display_name for create / update" do 15 | invoice = Quickbooks::Model::TaxAgency.new 16 | invoice.should_not be_valid 17 | invoice.errors.keys.include?(:display_name).should be_true 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /lib/quickbooks/model/meta_data.rb: -------------------------------------------------------------------------------- 1 | require 'time' 2 | 3 | module Quickbooks 4 | module Model 5 | class MetaData < BaseModel 6 | xml_accessor :create_time, :from => 'CreateTime', :as => Time 7 | xml_accessor :last_updated_time, :from => 'LastUpdatedTime', :as => Time 8 | 9 | def to_xml(options = {}) 10 | xml = %Q{} 11 | xml = "#{xml}#{formatted_date(create_time)}" 12 | xml = "#{xml}#{formatted_date(last_updated_time)}" 13 | xml 14 | end 15 | 16 | private 17 | 18 | def formatted_date(datetime) 19 | datetime.strftime('%Y-%m-%dT%H:%M:%S%z') 20 | end 21 | 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/terms.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 4 | 0 5 | 6 | 2013-07-11T17:46:39-07:00 7 | 2013-07-11T17:46:39-07:00 8 | 9 | TermForV3Testing-1373590184130 10 | true 11 | DATE_DRIVEN 12 | 4.0000000 13 | 1 14 | 2 15 | 3 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/quickbooks/model/account_based_expense_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class AccountBasedExpenseLineDetail < BaseModel 4 | xml_accessor :customer_ref, :from => 'CustomerRef', :as => BaseReference 5 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 6 | xml_accessor :account_ref, :from => 'AccountRef', :as => BaseReference 7 | xml_accessor :billable_status, :from => 'BillableStatus' 8 | xml_accessor :tax_amount, :from => 'UnitPrice', :as => BigDecimal, :to_xml => to_xml_big_decimal 9 | xml_accessor :tax_code_ref, :from => 'TaxCodeRef', :as => BaseReference 10 | 11 | reference_setters :customer_ref, :class_ref, :account_ref, :tax_code_ref 12 | 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_term_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 4 | 0 5 | 6 | 2013-07-11T17:46:39-07:00 7 | 2013-07-11T17:46:39-07:00 8 | 9 | TermForV3Testing-1373590184130 10 | true 11 | DATE_DRIVEN 12 | 4.0000000 13 | 1 14 | 2 15 | 3 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/quickbooks/model/deposit_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class DepositLineDetail < BaseModel 4 | 5 | xml_accessor :entity_ref, :from => 'Entity', :as => BaseReference 6 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 7 | xml_accessor :account_ref, :from => 'AccountRef', :as => BaseReference 8 | xml_accessor :payment_method_ref, :from => 'PaymentMethodRef', :as => BaseReference 9 | xml_accessor :check_num, :from => 'CheckNum' 10 | xml_accessor :txn_type, :from => 'TxnType' 11 | xml_accessor :custom_fields, :from => 'CustomField', :as => [CustomField] 12 | 13 | reference_setters :class_ref, :account_ref, :payment_method_ref, :entity_ref 14 | 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/quickbooks/model/bill_payment_line_item.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class BillPaymentLineItem < BaseModel 4 | 5 | #== Constants 6 | PAYMENT_LINE_DETAIL = 'PaymentLineDetail' 7 | DISCOUNT_LINE_DETAIL = 'DiscountLineDetail' 8 | 9 | xml_accessor :id, :from => 'Id' 10 | xml_accessor :line_num, :from => 'LineNum', :as => Integer 11 | xml_accessor :description, :from => 'Description' 12 | xml_accessor :amount, :from => 'Amount', :as => BigDecimal, :to_xml => to_xml_big_decimal 13 | xml_accessor :detail_type, :from => 'DetailType' 14 | 15 | xml_accessor :linked_transactions, :from => 'LinkedTxn', :as => [LinkedTransaction] 16 | 17 | #== Various detail types 18 | 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/quickbooks/service/exchange_rate.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class ExchangeRate < BaseService 4 | 5 | def fetch_by_currency(source_currency_code, as_of_date = nil) 6 | url = url_for_resource(model::REST_RESOURCE) 7 | params = { sourcecurrencycode: source_currency_code } 8 | params[:asofdate] = as_of_date unless as_of_date.nil? 9 | 10 | response = do_http_get(url, params) 11 | if response.code.to_i == 200 12 | model.from_xml(parse_singular_entity_response(model, response.plain_body)) 13 | else 14 | nil 15 | end 16 | end 17 | 18 | private 19 | 20 | def model 21 | Quickbooks::Model::ExchangeRate 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_payment_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8748 4 | 0 5 | 6 | 2013-07-11T17:51:41-07:00 7 | 2013-07-11T17:51:41-07:00 8 | 9 | 2013-07-11 10 | Payment smoke test 11 | 25342 12 | 4 13 | 40.00 14 | 40.00 15 | false 16 | 17 | 18 | -------------------------------------------------------------------------------- /spec/fixtures/term_delete_success_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 4 | 1 5 | 6 | 2013-07-11T17:46:39-07:00 7 | 2013-07-11T17:46:40-07:00 8 | 9 | TermForV3Testing-1373590184515 10 | false 11 | DATE_DRIVEN 12 | 10.0000000 13 | 1 14 | 2 15 | 3 16 | 17 | 18 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_item_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 0 5 | 6 | 2013-11-16T17:42:03-08:00 7 | 2013-11-16T17:42:03-08:00 8 | 9 | Plush Baby Doll 10 | A fine baby doll - in many colors 11 | true 12 | false 13 | 50 14 | Service 15 | 1 16 | 0 17 | false 18 | 19 | -------------------------------------------------------------------------------- /spec/fixtures/bill_payment_cc_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 812 3 | 0 4 | 5 | 2013-10-18T10:19:48-07:00 6 | 2013-10-18T10:19:48-07:00 7 | 8 | 2013-10-18 9 | 5-487-00 10 | 11 | 336.00 12 | 13 | 134 14 | Bill 15 | 16 | 17 | 38 18 | CreditCard 19 | 20 | 135 21 | 22 | 336.00 23 | -------------------------------------------------------------------------------- /spec/fixtures/tax_rate.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 3 | 0 4 | 5 | 2013-12-11T10:59:51-08:00 6 | 2013-12-11T10:59:51-08:00 7 | 8 | Santa Clara County 9 | Sales Tax 10 | true 11 | 0.5 12 | 3 13 | 14 | 17.5 15 | 1970-01-01T00:00:00-08:00 16 | 2014-06-30T00:00:00-07:00 17 | 18 | NONE 19 | ReadOnly 20 | 21 | -------------------------------------------------------------------------------- /spec/fixtures/time_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 1255 3 | 0 4 | 5 | 2014-02-05T07:17:08-08:00 6 | 2014-02-05T07:17:08-08:00 7 | 8 | 2014-02-05 9 | Employee 10 | 66 11 | 123 12 | 49 13 | 100100000000000321233 14 | Billable 15 | false 16 | 115 17 | 1 18 | 0 19 | Description 1 20 | 21 | -------------------------------------------------------------------------------- /spec/fixtures/tax_rates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 0 6 | 7 | 2013-03-15T17:05:13-07:00 8 | 2013-03-15T17:05:13-07:00 9 | 10 | Mountain View 11 | Sales Tax 12 | true 13 | 10 14 | 1 15 | NONE 16 | ReadOnly 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lib/quickbooks/model/credit_card_payment.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class CreditCardPayment < BaseModel 4 | xml_accessor :number, :from => 'Number' 5 | xml_accessor :type, :from => 'Type' 6 | xml_accessor :name_on_account, :from => 'NameOnAcct' 7 | xml_accessor :expiry_month, :from => 'CcExpiryMonth', :as => Integer 8 | xml_accessor :expiry_year, :from => 'CcExpiryYear', :as => Integer 9 | xml_accessor :bill_address, :from => 'BillAddrStreet' 10 | xml_accessor :postal_code, :from => 'PostalCode' 11 | xml_accessor :commercial_card_code, :from => 'CommercialCardCode' 12 | xml_accessor :txn_mode, :from => 'CCTxnMode' 13 | xml_accessor :txn_type, :from => 'CCTxnType' 14 | xml_accessor :previous_txn_id, :from => 'PrevCCTransId' 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/fixtures/transfers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 148 5 | 0 6 | 7 | 2016-02-11T06:00:44-08:00 8 | 2016-02-11T06:00:44-08:00 9 | 10 | 2016-02-11 11 | USD 12 | BABABABAB 13 | 36 14 | 35 15 | 250.00 16 | 17 | 18 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/budget_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::Budget" do 2 | 3 | it "parse from XML" do 4 | xml = fixture("budget.xml") 5 | budget = Quickbooks::Model::Budget.from_xml(xml) 6 | 7 | budget.sync_token.should == 1 8 | budget.active?.should == true 9 | budget.line_items.count.should == 192 10 | 11 | line1 = budget.line_items[0] 12 | line1.date.should == Date.parse("2015-01-01") 13 | line1.amount.should == '0' 14 | line1.account_ref.value.should == '14' 15 | line1.account_ref.name.should == 'Miscellaneous' 16 | 17 | line2 = budget.line_items[23] 18 | line2.date.should == Date.parse("2015-12-01") 19 | line2.amount.should == '475.00' 20 | line2.account_ref.value.should == '45' 21 | line2.account_ref.name.should == 'Landscaping Services' 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/fault_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Quickbooks::Model::Fault do 4 | it "should parse from xml" do 5 | fault_xml = fixture("fault.xml") 6 | fault = Quickbooks::Model::Fault.from_xml(fault_xml) 7 | fault.errors.size.should == 2 8 | first_error = fault.errors.first 9 | first_error.code.should == "2050" 10 | first_error.element.should == "firstname" 11 | first_error.message.should == "Length exceeds limit" 12 | first_error.detail.should == "Length of the field exceeds 21 chars" 13 | last_error = fault.errors.last 14 | last_error.code.should == "2080" 15 | last_error.element.should == "postalcode" 16 | last_error.message.should == "Illegal number format" 17 | last_error.detail.should == "ZipCode should be a number with at least 5 digits" 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/budget_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::Budget" do 2 | before(:all) do 3 | construct_service :budget 4 | end 5 | 6 | it "can query for budgets" do 7 | xml = fixture("budgets.xml") 8 | model = Quickbooks::Model::Invoice 9 | 10 | stub_request(:get, @service.url_for_query, ["200", "OK"], xml) 11 | budgets = @service.query 12 | budgets.entries.count.should == 2 13 | first_budget = budgets.entries[0] 14 | first_budget.id.should == "1" 15 | end 16 | 17 | it "can fetch a Budget by ID" do 18 | xml = fixture("fetch_budget_by_id.xml") 19 | model = Quickbooks::Model::Budget 20 | stub_request(:get, "#{@service.url_for_resource(model::REST_RESOURCE)}/1", ["200", "OK"], xml) 21 | budget = @service.fetch_by_id(1) 22 | budget.name.should == "TestBudgie" 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_bill_payment_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 623 4 | 1 5 | 6 | 2015-12-15T00:00:00-08:00 7 | 2015-12-15T00:00:00-08:00 8 | 9 | 1 10 | 2015-12-15 11 | Acct. 1JK90 12 | 32 13 | Check 14 | 15 | 133 16 | NotSet 17 | 18 | 110.00 19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxLineDetail < BaseModel 4 | 5 | xml_accessor :percent_based?, :from => 'PercentBased' 6 | xml_accessor :net_amount_taxable, :from => 'NetAmountTaxable', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 7 | xml_accessor :tax_inclusive_amount, :from => 'TaxInclusiveAmount', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 8 | xml_accessor :override_delta_amount, :from => 'OverrideDeltaAmount', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 9 | xml_accessor :tax_percent, :from => 'TaxPercent', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 10 | xml_accessor :tax_rate_ref, :from => 'TaxRateRef', :as => BaseReference 11 | 12 | reference_setters :tax_rate_ref 13 | 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/term_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 5 | 2 6 | 7 | 2013-07-11T17:46:39-07:00 8 | 2013-07-11T17:46:40-07:00 9 | 10 | null-1373590184786 11 | true 12 | DATE_DRIVEN 13 | 20.0000000 14 | 1 15 | 2 16 | 3 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/preferences_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::Preferences" do 2 | it "should parse from XML" do 3 | xml = fixture("preferences.xml") 4 | preferences = Quickbooks::Model::Preferences.from_xml(xml) 5 | 6 | preferences.accounting_info.customer_terminology.should == "Customers" 7 | preferences.currency.home_currency.should == "USD" 8 | 9 | preferences.tax.using_sales_tax?.should be_false 10 | preferences.tax.partner_tax_enabled?.should be_false 11 | preferences.time_tracking.bill_customers?.should be_true 12 | 13 | preferences.email_messages.invoice_message.subject.should == "Invoice from Demo Company" 14 | preferences.email_messages.estimate_message.message.should include("We look forward to working with you.") 15 | 16 | preferences.other_prefs["SalesFormsPrefs.DefaultItem"].should == "1" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/item_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::ItemChange" do 2 | let(:service) { construct_service :item_change } 3 | 4 | it "can query for items" do 5 | xml = fixture("item_changes.xml") 6 | model = Quickbooks::Model::ItemChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | items = service.query 10 | items.entries.count.should == 1 11 | 12 | first_item = items.entries.first 13 | first_item.status.should == 'Deleted' 14 | first_item.id.should == "39" 15 | 16 | first_item.meta_data.should_not be_nil 17 | first_item.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=Item" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /lib/quickbooks/service/payment.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Payment < BaseService 4 | 5 | def delete(payment) 6 | delete_by_query_string(payment) 7 | end 8 | 9 | def void(entity, options = {}) 10 | raise Quickbooks::InvalidModelException.new(entity.errors.full_messages.join(',')) unless entity.valid? 11 | xml = entity.to_xml_ns(options) 12 | url = "#{url_for_resource(model::REST_RESOURCE)}?include=void" 13 | 14 | response = do_http_post(url, valid_xml_document(xml), {}) 15 | if response.code.to_i == 200 16 | model.from_xml(parse_singular_entity_response(model, response.plain_body)) 17 | else 18 | false 19 | end 20 | end 21 | 22 | private 23 | 24 | def model 25 | Quickbooks::Model::Payment 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/quickbooks/service/service_crud_json.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | module ServiceCrudJSON 4 | 5 | def fetch_by_id(id, params = {}) 6 | raise NotImplementedError 7 | end 8 | 9 | def create(entity, options = {}) 10 | raise Quickbooks::InvalidModelException.new(entity.errors.full_messages.join(',')) unless entity.valid? 11 | response = do_http(:post, url_for_resource(model.resource_for_singular), entity.to_json, options) 12 | if response.code.to_i == 200 13 | JSON.parse(response.plain_body) 14 | else 15 | nil 16 | end 17 | end 18 | alias :update :create 19 | 20 | def delete 21 | raise NotImplementedError 22 | end 23 | 24 | def delete_by_query_string 25 | raise NotImplementedError 26 | end 27 | 28 | end 29 | end 30 | end 31 | 32 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/upload_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Service::Upload do 2 | before(:all) do 3 | construct_service :upload 4 | end 5 | 6 | it "can create an upload" do 7 | xml = fixture("upload_create_response.xml") 8 | stub_request(:post, @service.url_for_resource('upload'), ["200", "OK"], xml, {}, true) 9 | 10 | attachable = Quickbooks::Model::Attachable.new 11 | attachable.file_name = "monkey.jpg" 12 | attachable.note = "A note" 13 | entity = Quickbooks::Model::EntityRef.new 14 | entity.type = 'Customer' 15 | entity.value = 3 16 | attachable.attachable_ref = Quickbooks::Model::AttachableRef.new(entity) 17 | 18 | path = File.join(fixture_path, "monkey.jpg") 19 | mime = "image/jpeg" 20 | 21 | response = @service.upload(path, mime, attachable) 22 | 23 | response.note.should == attachable.note 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /lib/quickbooks/model/discount_line_detail.rb: -------------------------------------------------------------------------------- 1 | # https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/030_entity_services_reference/invoice#DiscountLineDetail 2 | module Quickbooks 3 | module Model 4 | class DiscountLineDetail < BaseModel 5 | xml_accessor :discount_ref, :from => 'DiscountRef', :as => BaseReference 6 | xml_accessor :percent_based?, :from => 'PercentBased' 7 | xml_accessor :discount_percent, :from => 'DiscountPercent', :as => BigDecimal, :to_xml => to_xml_big_decimal 8 | xml_accessor :discount_account_ref, :from => 'DiscountAccountRef', :as => BaseReference 9 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 10 | xml_accessor :tax_code_ref, :from => 'TaxCodeRef', :as => BaseReference 11 | 12 | reference_setters :tax_code_ref, :class_ref, :discount_ref, :discount_account_ref 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/class_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::Class" do 2 | 3 | it "parse from XML" do 4 | xml = fixture("class.xml") 5 | classs = Quickbooks::Model::Class.from_xml(xml) 6 | classs.sync_token.should == 1 7 | classs.name.should == 'Design' 8 | classs.sub_class?.should == false 9 | classs.fully_qualified_name.should == 'Design' 10 | classs.active?.should == true 11 | end 12 | 13 | it "can't assign a bad name" do 14 | classs = Quickbooks::Model::Class.new 15 | classs.name = "My:Class" 16 | classs.valid? 17 | classs.errors.keys.should include(:name) 18 | end 19 | 20 | it "cannot update an invalid model" do 21 | classs = Quickbooks::Model::Class.new 22 | classs.valid_for_update?.should == false 23 | classs.to_xml_ns.should match('Class') 24 | classs.errors.keys.should include(:sync_token) 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_code.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxCode < BaseModel 4 | XML_COLLECTION_NODE = "TaxCode" 5 | XML_NODE = "TaxCode" 6 | REST_RESOURCE = "taxcode" 7 | 8 | xml_accessor :id, :from => "Id" 9 | xml_accessor :sync_token, :from => "SyncToken", :as => Integer 10 | xml_accessor :meta_data, :from => "MetaData", :as => MetaData 11 | xml_accessor :name, :from => "Name" 12 | xml_accessor :description, :from => "Description" 13 | xml_accessor :active?, :from => "Active" 14 | xml_accessor :taxable?, :from => "Taxable" 15 | xml_accessor :tax_group?, :from => "TaxGroup" 16 | xml_accessor :sales_tax_rate_list, :from => "SalesTaxRateList", :as => SalesTaxRateList 17 | xml_accessor :purchase_tax_rate_list, :from => "PurchaseTaxRateList", :as => PurchaseTaxRateList 18 | 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/quickbooks/service/payment_method.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class PaymentMethod < BaseService 4 | 5 | def fetch_by_name(name) 6 | self.query(search_name_query(name)).entries.first 7 | end 8 | 9 | def search_name_query(name) 10 | "SELECT * FROM PaymentMethod WHERE Name = '#{name}'" 11 | end 12 | 13 | def update(entity, options = {}) 14 | raise Quickbooks::InvalidModelException.new('Payment Method sparse update is not supported by Intuit at this time') if options[:sparse] && options[:sparse] == true 15 | super(entity, options) 16 | end 17 | 18 | def delete(department) 19 | department.active = false 20 | update(department, :sparse => false) 21 | end 22 | 23 | private 24 | 25 | def model 26 | Quickbooks::Model::PaymentMethod 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/vendor_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::VendorChange" do 2 | let(:service) { construct_service :vendor_change } 3 | 4 | it "can query for vendors" do 5 | xml = fixture("vendor_changes.xml") 6 | model = Quickbooks::Model::VendorChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | vendors = service.query 10 | vendors.entries.count.should == 1 11 | 12 | first_vendor = vendors.entries.first 13 | first_vendor.status.should == 'Deleted' 14 | first_vendor.id.should == "39" 15 | 16 | first_vendor.meta_data.should_not be_nil 17 | first_vendor.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=Vendor" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_time_activity_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 0 5 | 6 | 2014-02-05T07:17:08-08:00 7 | 2014-02-05T07:17:08-08:00 8 | 9 | 2014-02-05 10 | Employee 11 | 66 12 | 123 13 | 49 14 | Billable 15 | false 16 | 115 17 | 1 18 | 30 19 | Description 1 20 | 21 | 22 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/transaction_tax_detail_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::TransactionTaxDetail" do 2 | it "allows setting of the TxnTaxCodeRef via #txn_tax_code_ref_id=" do 3 | transaction_tax_detail = Quickbooks::Model::TransactionTaxDetail.new 4 | transaction_tax_detail.total_tax = 42 5 | transaction_tax_detail.txn_tax_code_id = 42 6 | transaction_tax_detail.txn_tax_code_ref.value.should == 42 7 | end 8 | 9 | it "total tax should be a decimal/float" do 10 | transaction_tax_detail = Quickbooks::Model::TransactionTaxDetail.new 11 | transaction_tax_detail.total_tax = 42 12 | transaction_tax_detail.to_xml.at_css('TotalTax').content.should == '42.0' 13 | end 14 | 15 | it "total tax should not be included if not set" do 16 | transaction_tax_detail = Quickbooks::Model::TransactionTaxDetail.new 17 | transaction_tax_detail.to_xml.should_not =~ /TotalTax/ 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/invoice_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::InvoiceChange" do 2 | let(:service) { construct_service :invoice_change } 3 | 4 | it "can query for invoices" do 5 | xml = fixture("invoice_changes.xml") 6 | model = Quickbooks::Model::InvoiceChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | invoices = service.query 10 | invoices.entries.count.should == 1 11 | 12 | first_invoice = invoices.entries.first 13 | first_invoice.status.should == 'Deleted' 14 | first_invoice.id.should == "39" 15 | 16 | first_invoice.meta_data.should_not be_nil 17 | first_invoice.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=Invoice" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/payment_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::PaymentChange" do 2 | let(:service) { construct_service :payment_change } 3 | 4 | it "can query for payments" do 5 | xml = fixture("payment_changes.xml") 6 | model = Quickbooks::Model::PaymentChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | payments = service.query 10 | payments.entries.count.should == 1 11 | 12 | first_payment = payments.entries.first 13 | first_payment.status.should == 'Deleted' 14 | first_payment.id.should == "39" 15 | 16 | first_payment.meta_data.should_not be_nil 17 | first_payment.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=Payment" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /spec/fixtures/payments.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8748 5 | 1 6 | 7 | 2013-07-11T17:51:41-07:00 8 | 2013-07-11T17:51:43-07:00 9 | 10 | 2013-07-11 11 | H60jzmw0Uq 12 | 25342 13 | 4 14 | 40.00 15 | 40.00 16 | false 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /spec/fixtures/payment_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8748 5 | 1 6 | 7 | 2013-07-11T17:51:41-07:00 8 | 2013-07-11T17:51:43-07:00 9 | 10 | 2013-07-11 11 | H60jzmw0Uq 12 | 25342 13 | 4 14 | 40.00 15 | 40.00 16 | false 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lib/quickbooks/model/budget.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Budget < BaseModel 4 | include HasLineItems 5 | 6 | XML_COLLECTION_NODE = "Budget" 7 | XML_NODE = "Budget" 8 | REST_RESOURCE = 'budget' 9 | 10 | xml_name XML_NODE 11 | 12 | xml_accessor :id, :from => 'Id' 13 | xml_accessor :name, :from => 'Name' 14 | xml_accessor :type, :from => 'BudgetType' 15 | xml_accessor :entry_type, :from => 'BudgetEntryType' 16 | xml_accessor :start_date, :from => 'StartDate' 17 | xml_accessor :end_date, :from => 'EndDate' 18 | xml_accessor :active?, :from => 'Active' 19 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 20 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 21 | 22 | xml_accessor :line_items, :from => 'BudgetDetail', :as => [BudgetLineItem] 23 | 24 | reference_setters 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/customer_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::CustomerChange" do 2 | let(:service) { construct_service :customer_change } 3 | 4 | it "can query for customers" do 5 | xml = fixture("customer_changes.xml") 6 | model = Quickbooks::Model::CustomerChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | customers = service.query 10 | customers.entries.count.should == 1 11 | 12 | first_customer = customers.entries.first 13 | first_customer.status.should == 'Deleted' 14 | first_customer.id.should == "39" 15 | 16 | first_customer.meta_data.should_not be_nil 17 | first_customer.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=Customer" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_account_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 0 5 | 6 | 2013-11-15T12:43:10-08:00 7 | 2013-11-15T12:43:10-08:00 8 | 9 | Sales of Product Income 10 | false 11 | Sales of Product Income 12 | true 13 | Revenue 14 | Income 15 | SalesOfProductIncome 16 | 0 17 | 0 18 | USD 19 | 20 | 21 | -------------------------------------------------------------------------------- /spec/fixtures/tax_code.xml: -------------------------------------------------------------------------------- 1 | 2 | 2 3 | 0 4 | 5 | 2014-02-19T12:08:08-08:00 6 | 2014-02-19T12:08:08-08:00 7 | 8 | Stupid tax 9 | Stupid tax 10 | true 11 | true 12 | true 13 | 14 | 15 | 1 16 | TaxOnAmount 17 | 0 18 | 19 | 20 | 21 | 22 | 2 23 | TaxOnAmount 24 | 0 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /spec/fixtures/bill_payments.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 623 5 | 1 6 | 7 | 2015-12-15T00:00:00-08:00 8 | 2015-12-15T00:00:00-08:00 9 | 10 | 1 11 | 2015-12-15 12 | Acct. 1JK90 13 | 32 14 | Check 15 | 16 | 133 17 | NotSet 18 | 19 | 110.00 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /lib/quickbooks/model/sales_item_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class SalesItemLineDetail < BaseModel 4 | xml_accessor :item_ref, :from => 'ItemRef', :as => BaseReference 5 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 6 | xml_accessor :unit_price, :from => 'UnitPrice', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 7 | xml_accessor :rate_percent, :from => 'RatePercent', :as => BigDecimal, :to_xml => to_xml_big_decimal 8 | xml_accessor :price_level_ref, :from => 'PriceLevelRef', :as => BaseReference 9 | xml_accessor :quantity, :from => 'Qty', :as => BigDecimal, :to_xml => Proc.new { |val| val.to_f } 10 | xml_accessor :tax_code_ref, :from => 'TaxCodeRef', :as => BaseReference 11 | xml_accessor :service_date, :from => 'ServiceDate', :as => Date 12 | 13 | reference_setters :item_ref, :class_ref, :price_level_ref, :tax_code_ref 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/bill_line_item_expense.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 3 | 2017-12-16 4 | 5 | 1 6 | 700.00 7 | ItemBasedExpenseLineDetail 8 | 9 | 1001 10 | 100000000000128320 11 | 9.79 12 | NON 13 | 14 | true 15 | 10 16 | 17 | 18 | 19 | 4 20 | 38 21 | 755.12 22 | 2018-12-26 23 | 24 | -------------------------------------------------------------------------------- /spec/fixtures/upload_create_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2700000000002443649 5 | 0 6 | 7 | 2015-02-12T08:56:11-08:00 8 | 2015-02-12T08:56:11-08:00 9 | 10 | monkey.jpg 11 | /v3/company/12345/download/2700000000002443649 12 | https://intuit-qbo-prod-15.s3.amazonaws.com/1002341430%2Fattachments%2Fmonkey-1423760170483.jpgD 13 | 105840 14 | image/jpeg 15 | A note 16 | /v3/company/12345/attachable-thumbnail/2700000000002443649 17 | 18 | 19 | -------------------------------------------------------------------------------- /spec/fixtures/vendor_credit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 3 | 0 4 | 5 | 2013-10-10T11:16:32-07:00 6 | 2013-10-10T11:16:32-07:00 7 | 8 | 2013-09-20 9 | 10 | 1 11 | 90.00 12 | AccountBasedExpenseLineDetail 13 | 14 | 2 15 | 8 16 | Billable 17 | TAX 18 | 19 | 20 | 5 21 | 38 22 | 90.00 23 | 24 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/company_info_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::CompanyInfo" do 2 | before(:all) do 3 | construct_service :company_info 4 | end 5 | 6 | it "can query for company info" do 7 | xml = fixture("company_info_query.xml") 8 | model = Quickbooks::Model::CompanyInfo 9 | 10 | stub_request(:get, @service.url_for_query, ["200", "OK"], xml) 11 | company_info_query = @service.query 12 | company_info_query.entries.count.should == 1 13 | 14 | company_info = company_info_query.entries.first 15 | company_info.company_name.should == 'Acme Corp.' 16 | end 17 | 18 | it "can fetch company info by ID" do 19 | xml = fixture("fetch_company_info_by_id.xml") 20 | model = Quickbooks::Model::CompanyInfo 21 | stub_request(:get, "#{@service.url_for_resource(model::REST_RESOURCE)}/1", ["200", "OK"], xml) 22 | company_info = @service.fetch_by_id(1) 23 | company_info.company_name.should == "Acme Corp." 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/credit_memo_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::CreditMemoChange" do 2 | let(:service) { construct_service :credit_memo_change } 3 | 4 | it "can query for credit memos" do 5 | xml = fixture("credit_memo_changes.xml") 6 | model = Quickbooks::Model::CreditMemoChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | credit_memos = service.query 10 | credit_memos.entries.count.should == 1 11 | 12 | first_credit_memo = credit_memos.entries.first 13 | first_credit_memo.status.should == 'Deleted' 14 | first_credit_memo.id.should == "39" 15 | 16 | first_credit_memo.meta_data.should_not be_nil 17 | first_credit_memo.meta_data.last_updated_time.should == DateTime.parse("2014-12-08T19:36:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=CreditMemo" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /lib/quickbooks/service/item.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Item < BaseService 4 | 5 | def delete(item) 6 | item.active = false 7 | update(item, :sparse => true) 8 | end 9 | 10 | def url_for_resource(resource) 11 | url = super(resource) 12 | "#{url}?minorversion=#{Quickbooks::Model::Item::MINORVERSION}" 13 | end 14 | 15 | def fetch_by_id(id, params = {}) 16 | url = "#{url_for_base}/item/#{id}?minorversion=#{Quickbooks::Model::Item::MINORVERSION}" 17 | fetch_object(model, url, params) 18 | end 19 | 20 | def url_for_query(query = nil, start_position = 1, max_results = 20, options = {}) 21 | url = super(query, start_position, max_results, options) 22 | "#{url}&minorversion=#{Quickbooks::Model::Item::MINORVERSION}" 23 | end 24 | 25 | private 26 | 27 | def model 28 | Quickbooks::Model::Item 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/quickbooks/model/transfer.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Transfer < BaseModel 4 | XML_COLLECTION_NODE = "Transfer" 5 | XML_NODE = "Transfer" 6 | REST_RESOURCE = 'transfer' 7 | 8 | xml_accessor :id, :from => 'Id' 9 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 10 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 11 | xml_accessor :txn_date, :from => 'TxnDate', :as => Date 12 | xml_accessor :currency_ref, :from => 'CurrencyRef', :as => BaseReference 13 | xml_accessor :private_note, :from => 'PrivateNote' 14 | xml_accessor :from_account_ref, :from => 'FromAccountRef', :as => BaseReference 15 | xml_accessor :to_account_ref, :from => 'ToAccountRef', :as => BaseReference 16 | xml_accessor :amount, :from => 'Amount', :as => BigDecimal, :to_xml => to_xml_big_decimal 17 | 18 | reference_setters :currency_ref, :to_account_ref, :from_account_ref 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/custom_field_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::CustomField" do 2 | 3 | it "parse from XML as String" do 4 | xml = fixture("custom_field_string.xml") 5 | field = Quickbooks::Model::CustomField.from_xml(xml) 6 | field.name.should == "SalesAssociate" 7 | field.type.should == "StringType" 8 | field.string_value.should == "Miller" 9 | end 10 | 11 | it "parse from XML as Date" do 12 | xml = fixture("custom_field_date.xml") 13 | field = Quickbooks::Model::CustomField.from_xml(xml) 14 | field.name.should == "LastUpdated" 15 | field.type.should == "DateType" 16 | field.date_value.should == Date.civil(2013, 4, 4) 17 | end 18 | 19 | it "parse from XML as Number" do 20 | xml = fixture("custom_field_number.xml") 21 | field = Quickbooks::Model::CustomField.from_xml(xml) 22 | field.name.should == "NumberOfWatermelons" 23 | field.type.should == "NumberType" 24 | field.number_value.should == 43 25 | end 26 | 27 | end -------------------------------------------------------------------------------- /lib/quickbooks/model/payment_method.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class PaymentMethod < BaseModel 4 | REST_RESOURCE = 'paymentmethod' 5 | XML_COLLECTION_NODE = "PaymentMethod" 6 | XML_NODE = "PaymentMethod" 7 | include NameEntity::PermitAlterations 8 | 9 | CREDIT_CARD = "CREDIT_CARD" 10 | NON_CREDIT_CARD = "NON_CREDIT_CARD" 11 | 12 | PAYMENT_METHOD_TYPES = [CREDIT_CARD, NON_CREDIT_CARD] 13 | 14 | xml_accessor :id, :from => 'Id' 15 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 16 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 17 | xml_accessor :name, :from => 'Name' 18 | xml_accessor :type, :from => 'Type' 19 | xml_accessor :active?, :from => 'Active' 20 | xml_accessor :amount, :from => 'Amount', :as => BigDecimal, :to_xml => to_xml_big_decimal 21 | 22 | validates_inclusion_of :type, :in => PAYMENT_METHOD_TYPES, :allow_nil => true 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/fixtures/purchase_create.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 160 4 | 0 5 | 6 | 2015-03-31T08:27:00-0400 7 | 2015-03-31T08:27:00-0400 8 | 9 | 2015-03-31 10 | 11 | 1 12 | Rink Liner 13 | 419.99 14 | AccountBasedExpenseLineDetail 15 | 16 | 1 17 | 28 18 | NotBillable 19 | NON 20 | 21 | 22 | 36 23 | Cash 24 | 419.99 25 | 26 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/department_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::Department" do 2 | 3 | it "parse from XML" do 4 | xml = fixture("department.xml") 5 | department = Quickbooks::Model::Department.from_xml(xml) 6 | department.sync_token.should == 0 7 | department.name.should == 'Sales Department' 8 | department.sub_department?.should == false 9 | department.fully_qualified_name.should == 'Sales Department' 10 | department.active?.should == true 11 | end 12 | 13 | it "can't assign a bad name" do 14 | department = Quickbooks::Model::Department.new 15 | department.name = "This:Department" 16 | department.valid? 17 | department.errors.keys.should include(:name) 18 | end 19 | 20 | it "cannot update an invalid model" do 21 | department = Quickbooks::Model::Department.new 22 | department.valid_for_update?.should == false 23 | department.to_xml_ns.should match('Department') 24 | department.errors.keys.should include(:sync_token) 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/refund_receipt_change_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::RefundReceiptChange" do 2 | let(:service) { construct_service :refund_receipt_change } 3 | 4 | it "can query for refund_receipts" do 5 | xml = fixture("refund_receipt_changes.xml") 6 | model = Quickbooks::Model::RefundReceiptChange 7 | 8 | stub_request(:get, service.url_for_query, ["200", "OK"], xml) 9 | refund_receipts = service.query 10 | refund_receipts.entries.count.should == 1 11 | 12 | first_refund_receipt = refund_receipts.entries.first 13 | first_refund_receipt.status.should == 'Deleted' 14 | first_refund_receipt.id.should == "40" 15 | 16 | first_refund_receipt.meta_data.should_not be_nil 17 | first_refund_receipt.meta_data.last_updated_time.should == DateTime.parse("2014-12-09T19:30:24-08:00") 18 | end 19 | 20 | describe "#url_for_query" do 21 | subject { service.url_for_query } 22 | it { should eq "#{service.url_for_base}/cdc?entities=RefundReceipt" } 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /lib/quickbooks/model/exchange_rate.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class ExchangeRate < BaseModel 4 | XML_COLLECTION_NODE = "ExchangeRate" 5 | XML_NODE = "ExchangeRate" 6 | REST_RESOURCE = "exchangerate" 7 | 8 | xml_accessor :id, :from => "Id" 9 | xml_accessor :sync_token, :from => "SyncToken", :as => Integer 10 | xml_accessor :meta_data, :from => "MetaData", :as => MetaData 11 | 12 | xml_accessor :custom_fields, :from => 'CustomField', :as => [CustomField] 13 | xml_accessor :source_currency_code, :from => 'SourceCurrencyCode' 14 | xml_accessor :target_currency_code, :from => 'TargetCurrencyCode' 15 | xml_accessor :rate, :from => 'Rate', :as => BigDecimal, :to_xml => to_xml_big_decimal 16 | xml_accessor :as_of_date, :from => 'AsOfDate', :as => Date 17 | 18 | validates_presence_of :source_currency_code, :rate, :as_of_date 19 | validates_length_of :source_currency_code, :is => 3 20 | validates_length_of :target_currency_code, :is => 3 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/fixtures/fetch_deposit_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 4 | 0 5 | 6 | 2014-11-11T15:22:31-08:00 7 | 2014-11-11T15:22:31-08:00 8 | 9 | Deposit Note 10 | 2014-11-11 11 | 12 | 78 13 | 14 | 38 15 | SalesReceipt 16 | 0 17 | 18 | 19 | 20 | 140 21 | 22 | 47 23 | SalesReceipt 24 | 0 25 | 26 | 27 | 35 28 | 218.75 29 | 30 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/transfer_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::Transfer" do 2 | it "parse from XML" do 3 | xml = fixture("transfer.xml") 4 | transfer = Quickbooks::Model::Transfer.from_xml(xml) 5 | transfer.id.should == "148" 6 | transfer.sync_token.should == 0 7 | 8 | transfer.meta_data.should_not be_nil 9 | transfer.meta_data.create_time.should == DateTime.parse("2016-02-11T06:00:44-08:00") 10 | transfer.meta_data.last_updated_time.should == DateTime.parse("2016-02-11T06:00:44-08:00") 11 | transfer.txn_date.should == Date.civil(2016, 2, 11) 12 | transfer.currency_ref.name.should == "United States Dollar" 13 | transfer.currency_ref.value.should == "USD" 14 | transfer.private_note.should == "Important notes to explain this transaction" 15 | transfer.from_account_ref.name.should == "Savings" 16 | transfer.from_account_ref.value.should == "36" 17 | transfer.to_account_ref.name.should == "Checking" 18 | transfer.to_account_ref.value.should == "35" 19 | transfer.amount.should == 250.00 20 | end 21 | end -------------------------------------------------------------------------------- /lib/quickbooks/util/query_builder.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | 3 | module Quickbooks 4 | module Util 5 | class QueryBuilder 6 | 7 | VALUE_QUOTE = "'" 8 | 9 | def initialize 10 | end 11 | 12 | def clause(field, operator, value) 13 | value = case value 14 | when DateTime, Time 15 | value.iso8601 16 | when Date 17 | value.strftime('%Y-%m-%d') 18 | when Array 19 | value = value.map{|v| v.to_s.gsub("'", "\\\\'") } 20 | else 21 | # escape single quotes with an escaped backslash 22 | value = value.gsub("'", "\\\\'") 23 | end 24 | 25 | if operator.downcase == 'in' && value.is_a?(Array) 26 | value = value.map{|v| "#{VALUE_QUOTE}#{v}#{VALUE_QUOTE}"} 27 | "#{field} #{operator} (#{value.join(', ')})" 28 | else 29 | "#{field} #{operator} #{VALUE_QUOTE}#{value}#{VALUE_QUOTE}" 30 | end 31 | end 32 | 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/quickbooks/model/class.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Class < BaseModel 4 | XML_COLLECTION_NODE = "Class" 5 | XML_NODE = "Class" 6 | REST_RESOURCE = 'class' 7 | include NameEntity::Quality 8 | include NameEntity::PermitAlterations 9 | 10 | xml_name XML_NODE 11 | xml_accessor :id, :from => 'Id' 12 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 13 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 14 | xml_accessor :name, :from => 'Name' 15 | xml_accessor :sub_class, :from => 'SubClass' 16 | xml_accessor :parent_ref, :from => 'ParentRef', :as => BaseReference 17 | xml_accessor :fully_qualified_name, :from => 'FullyQualifiedName' # ReadOnly 18 | xml_accessor :active?, :from => 'Active' 19 | 20 | reference_setters :parent_ref 21 | 22 | #== Validations 23 | validate :names_cannot_contain_invalid_characters 24 | 25 | def sub_class? 26 | sub_class.to_s == 'true' 27 | end 28 | 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/quickbooks/model/attachable.rb: -------------------------------------------------------------------------------- 1 | require 'quickbooks/model/attachable_ref' 2 | 3 | module Quickbooks 4 | module Model 5 | class Attachable < BaseModel 6 | 7 | XML_COLLECTION_NODE = "Attachable" 8 | XML_NODE = "Attachable" 9 | REST_RESOURCE = 'attachable' 10 | 11 | xml_accessor :id, :from => 'Id' 12 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 13 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 14 | xml_accessor :attachable_ref, :as => AttachableRef 15 | xml_accessor :file_name 16 | xml_accessor :file_access_uri 17 | xml_accessor :temp_download_uri 18 | xml_accessor :size 19 | xml_accessor :content_type 20 | xml_accessor :category 21 | xml_accessor :lat 22 | xml_accessor :long 23 | xml_accessor :place_name 24 | xml_accessor :note 25 | xml_accessor :tag 26 | xml_accessor :thumbnail_file_access_uri 27 | xml_accessor :thumbnail_temp_download_uri 28 | 29 | reference_setters :attachable_ref 30 | 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/quickbooks/model/access_token_response.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class AccessTokenResponse < BaseModel 4 | xml_convention :camelcase 5 | xml_accessor :error_code, :from => 'ErrorCode' 6 | xml_accessor :error_message, :from => 'ErrorMessage' 7 | xml_accessor :token, :from => 'OAuthToken' 8 | xml_accessor :secret, :from => 'OAuthTokenSecret' 9 | xml_accessor :server_time, :from => 'ServerTime', :as => Time 10 | 11 | def error? 12 | error_code.to_i != 0 13 | end 14 | 15 | end 16 | end 17 | end 18 | 19 | =begin 20 | 21 | 22 | 23 | 0 24 | 2012-01-04T19:21:21.0782072Z 25 | qye2eIdQ5H5yMyrlJflUWh712xfFXjyNnW1MfbC0rz04TfCP 26 | cyDeUNQTkFzoR0KkDn7viN6uLQxWTobeEUKW7I79 27 | 28 | 29 | =end -------------------------------------------------------------------------------- /spec/fixtures/purchase_credit_card_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 6834 3 | 0 4 | 5 | 2013-04-23T18:44:42-07:00 6 | 2013-04-23T18:44:42-07:00 7 | 8 | 2013-01-04 9 | 10 | 1 11 | this is description only. 12 | 0 13 | AccountBasedExpenseLineDetail 14 | 15 | 60 16 | NotBillable 17 | NON 18 | 19 | 20 | 64 21 | CreditCard 22 | 1 23 | false 24 | 0 25 | TaxExcluded 26 | 27 | -------------------------------------------------------------------------------- /spec/fixtures/attachables.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2700000000001439108 5 | 0 6 | 7 | 2014-08-18T09:58:06-07:00 8 | 2014-08-18T09:58:06-07:00 9 | 10 | monkey.jpg 11 | /v3/company/1002341430/download/2700000000001439108 12 | https://intuit-qbo-prod-30.s3.amazonaws.com/1002341430%2Fattachments%2Fmonkey.jpg 13 | 105840 14 | image/jpeg 15 | /v3/company/1002341430/attachable-thumbnail/2700000000001439108 16 | https://intuit-qbo-prod-30.s3.amazonaws.com/1002341430%2Fattachmentthumbnails%2Ftn_monkey.jpg 17 | 18 | 19 | -------------------------------------------------------------------------------- /spec/support/oauth_helpers.rb: -------------------------------------------------------------------------------- 1 | module OauthHelpers 2 | def construct_oauth 3 | FakeWeb.allow_net_connect = false 4 | 5 | oauth_consumer = OAuth::Consumer.new("app_key", "app_secret", { 6 | :site => "https://oauth.intuit.com", 7 | :request_token_path => "/oauth/v1/get_request_token", 8 | :authorize_url => "https://appcenter.intuit.com/Connect/Begin", 9 | :access_token_path => "/oauth/v1/get_access_token" 10 | }) 11 | 12 | OAuth::AccessToken.new(oauth_consumer, "token", "secret") 13 | end 14 | 15 | def construct_service(model, access_token=construct_oauth) 16 | @service = "Quickbooks::Service::#{model.to_s.camelcase}".constantize.new 17 | @service.access_token = access_token 18 | @service.company_id = "9991111222" 19 | @service 20 | end 21 | 22 | def construct_compact_service(model) 23 | @service = "Quickbooks::Service::#{model.to_s.camelcase}".constantize.new(access_token: construct_oauth, company_id:"9991111222") 24 | end 25 | end 26 | 27 | RSpec.configure do |config| 28 | config.include(OauthHelpers) 29 | end 30 | -------------------------------------------------------------------------------- /lib/quickbooks/model/department.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Department < BaseModel 4 | XML_COLLECTION_NODE = "Department" 5 | XML_NODE = "Department" 6 | REST_RESOURCE = 'department' 7 | include NameEntity::Quality 8 | include NameEntity::PermitAlterations 9 | 10 | xml_name XML_NODE 11 | xml_accessor :id, :from => 'Id' 12 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 13 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 14 | xml_accessor :name, :from => 'Name' 15 | xml_accessor :sub_department, :from => 'SubDepartment' 16 | xml_accessor :parent_ref, :from => 'ParentRef', :as => BaseReference 17 | xml_accessor :fully_qualified_name, :from => 'FullyQualifiedName' # ReadOnly 18 | xml_accessor :active?, :from => 'Active' 19 | 20 | reference_setters :parent_ref 21 | 22 | #== Validations 23 | validate :names_cannot_contain_invalid_characters 24 | 25 | def sub_department? 26 | sub_department.to_s == 'true' 27 | end 28 | 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /quickbooks-ruby.gemspec: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path("../lib", __FILE__) 2 | require "quickbooks/version" 3 | 4 | Gem::Specification.new do |gem| 5 | gem.name = "quickbooks-ruby" 6 | gem.version = Quickbooks::VERSION 7 | 8 | gem.author = "Cody Caughlan" 9 | gem.email = "toolbag@gmail.com" 10 | gem.homepage = "http://github.com/ruckus/quickbooks-ruby" 11 | gem.summary = "REST API to Quickbooks Online" 12 | gem.license = 'MIT' 13 | gem.description = "QBO V3 REST API to Quickbooks Online" 14 | 15 | gem.files = Dir['lib/**/*'] 16 | 17 | gem.add_dependency 'oauth', '0.4.7' 18 | gem.add_dependency 'roxml', '>= 3.3.1', '< 4.1' 19 | gem.add_dependency 'nokogiri' # promiscuous mode 20 | gem.add_dependency 'activemodel' # promiscuous mode 21 | gem.add_dependency 'multipart-post' # promiscuous mode 22 | 23 | gem.add_development_dependency 'rake', '10.1.0' 24 | gem.add_development_dependency 'simplecov', '0.7.1' 25 | gem.add_development_dependency 'rr', '~> 1.0.2' 26 | gem.add_development_dependency 'rspec', '2.14.1' 27 | gem.add_development_dependency 'fakeweb', '1.3.0' 28 | end 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Cody Caughlan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/account_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Service::Account do 2 | before(:all) do 3 | construct_service :account 4 | end 5 | 6 | it "can query for accounts" do 7 | xml = fixture("accounts.xml") 8 | stub_request(:get, @service.url_for_query, ["200", "OK"], xml, {}, true) 9 | 10 | accounts = @service.query 11 | accounts.entries.count.should == 10 12 | 13 | sales = accounts.entries.first 14 | sales.name.should == 'Cost of Goods Sold' 15 | end 16 | 17 | it "can fetch an account by ID" do 18 | xml = fixture("fetch_account_by_id.xml") 19 | model = Quickbooks::Model::Account 20 | stub_request(:get, "#{@service.url_for_resource(model::REST_RESOURCE)}/1", ["200", "OK"], xml) 21 | account = @service.fetch_by_id(1) 22 | 23 | account.name.should == "Sales of Product Income" 24 | account.classification.should == Quickbooks::Model::Account::REVENUE 25 | account.tax_account?.should == nil 26 | account.currency_ref.to_s.should == 'USD' 27 | account.current_balance.should == 0 28 | account.current_balance_with_sub_accounts.should == 0 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /webapp/.env: -------------------------------------------------------------------------------- 1 | OAUTH_CLIENT_ID=Q0gp5eNzm0eBqpIwabAhqjCGwk70UTBBZF993r4xMMnXHLl7x5 2 | OAUTH_CLIENT_SECRET=i5AgJfMgyNvXhjuK0XVXp92fucieuSsBRtCdstOU 3 | OAUTH_REDIRECT_URI=https://vinoqbwc.ngrok.io/oauth2callback 4 | #OAUTH_REDIRECT_URI=http://localhost:4567/oauth2callback 5 | 6 | REALM_ID=1313827825 7 | 8 | TOKEN=eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..2x43y21fTn_VuZeGfk58IA.fVyiBbWoMbs1k-HNGHQgJy02egHln1I-vspJ5LiK1pAngbEof8Kyx9ZcXpziGZGY-1vYrdy-vAUSx9IlfDkeJUD5-9keMtGcpTtpjk3dE4pKGVixpUisN9WZwV4fBRouLofV6M1nW6FA3PQZAFYmlBIvvF8wVkIDxsDe1VV6zBbh9ueqF4Wp8bLT718e46DUXf4aLNFh_j24XSZpRwPKS88fUIbQ9FurpB70y44JO2OKl4xq5dfn5XuGCFqbDffsafi8ugSD0LLJHtAJiDTEzmYA7JQNfUmjIEQlXf2b5LMSK_L0OBvBp9a-Om2UwDzfJWEl0l48d82eb_kLXIPdgsTecJqXacpH86OTAZTCTzXm19FJ_CMpIPJ4SI7j5muLixWUWjOKKZwFxAXay6PyOremx6IJu5kseg3oEtvEk_XWfD3HSc8EvVxdChE-rlCqSH59fm0OoLffSlzrnqHaxXMZG5P1Ow-mCGTvmnPcipxQHEQvOuQ-ldXsOONTMl48rQwow4SMoC2lXyTzwT1oOxMqur3Xjw8o6WWhnaLt3mDsTS3WfjcQHIgvV5Jb09x81W1hGhs3VOv4ge01wv1sDKqGn1x1sMMt1HopVpagRB4fM3QO0Lvh7-4F5dtd9fCrydFPsw4YNCY9ajUnvP7pqdoT4QnOSvuAgWUIBzC5ccc._aM7ScFbAgqq8J-j-NGuWQ 9 | REFRESH_TOKEN=Q011524972938ScjZuzP7MgOkzY1esCekaph7cpTBwSogmdO5k 10 | -------------------------------------------------------------------------------- /spec/fixtures/deposit.xml: -------------------------------------------------------------------------------- 1 | 2 | 155 3 | 0 4 | 5 | 2015-03-07T11:30:04-07:00 6 | 2015-03-07T11:30:04-07:00 7 | 8 | Deposit smoke test 9 | 2015-03-07 10 | USD 11 | 12 | 262 13 | 14 | 154 15 | Payment 16 | 0 17 | 18 | 19 | 20 | 1 21 | 1 22 | -62.50 23 | DepositLineDetail 24 | 25 | 58 26 | 31 27 | 1 28 | 29 | 30 | 4 31 | 200.00 32 | 33 | -------------------------------------------------------------------------------- /lib/quickbooks/service/upload.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Upload < BaseService 4 | 5 | XML_NODE = "AttachableResponse" 6 | 7 | # path_to_file: String - path to file 8 | # mime_type: String - the MIME type of the file, e.g. image/jpeg 9 | # attachable: Quickbooks::Model::Attachable meta-data details, can be null 10 | def upload(path_to_file, mime_type, attachable = nil) 11 | url = url_for_resource("upload") 12 | uploadIO = UploadIO.new(path_to_file, mime_type) 13 | response = do_http_file_upload(uploadIO, url, attachable) 14 | prefix = "AttachableResponse/xmlns:Attachable" 15 | if response.code.to_i == 200 16 | model.from_xml(parse_singular_entity_response(model, response.plain_body, prefix)) 17 | else 18 | nil 19 | end 20 | end 21 | 22 | def download(uploadId) 23 | url = url_for_resource("download/#{uploadId}") 24 | do_http_get(url, {}, headers) 25 | end 26 | 27 | private 28 | 29 | def model 30 | Quickbooks::Model::Attachable 31 | end 32 | 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/quickbooks/model/definition.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | module Definition 4 | 5 | def self.included(base) 6 | base.extend(ClassMethods) 7 | end 8 | 9 | module ClassMethods 10 | # https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services 11 | TRANSACTION_ENTITIES = %w{ 12 | Bill 13 | BillPayment 14 | CreditMemo 15 | Estimate 16 | Invoice 17 | JournalEntry 18 | Payment 19 | Purchase 20 | PurchaseOrder 21 | RefundReceipt 22 | SalesReceipt 23 | TimeActivity 24 | VendorCredit 25 | } 26 | 27 | def is_transaction_entity? 28 | TRANSACTION_ENTITIES.include?(self.name.demodulize) 29 | end 30 | 31 | def is_name_list_entity? 32 | !self.is_transaction_entity? 33 | end 34 | end 35 | 36 | def is_transaction_entity? 37 | self.class.is_transaction_entity? 38 | end 39 | 40 | def is_name_list_entity? 41 | self.class.is_name_list_entity? 42 | end 43 | 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/quickbooks/model/item_based_expense_line_detail.rb: -------------------------------------------------------------------------------- 1 | require 'quickbooks/model/markup_info' 2 | 3 | module Quickbooks 4 | module Model 5 | class ItemBasedExpenseLineDetail < BaseModel 6 | xml_accessor :item_ref, :from => 'ItemRef', :as => BaseReference 7 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 8 | xml_accessor :unit_price, :from => 'UnitPrice', :as => BigDecimal, :to_xml => to_xml_big_decimal 9 | xml_accessor :rate_percent, :from => 'RatePercent', :as => BigDecimal, :to_xml => to_xml_big_decimal 10 | xml_accessor :price_level_ref, :from => 'PriceLevelRef', :as => BaseReference 11 | xml_accessor :markup_info, :from => 'MarkupInfo', :as => MarkupInfo 12 | xml_accessor :quantity, :from => 'Qty', :as => BigDecimal, :to_xml => to_xml_big_decimal 13 | xml_accessor :tax_code_ref, :from => 'TaxCodeRef', :as => BaseReference 14 | xml_accessor :customer_ref, :from => 'CustomerRef', :as => BaseReference 15 | xml_accessor :billable_status, :from => 'BillableStatus' 16 | 17 | reference_setters :item_ref, :class_ref, :price_level_ref, :customer_ref, :tax_code_ref 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/quickbooks/model/physical_address.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class PhysicalAddress < BaseModel 4 | xml_accessor :id, :from => 'Id' 5 | xml_accessor :line1, :from => 'Line1' 6 | xml_accessor :line2, :from => 'Line2' 7 | xml_accessor :line3, :from => 'Line3' 8 | xml_accessor :line4, :from => 'Line4' 9 | xml_accessor :line5, :from => 'Line5' 10 | xml_accessor :city, :from => 'City' 11 | xml_accessor :country, :from => 'Country' 12 | xml_accessor :country_sub_division_code, :from => 'CountrySubDivisionCode' 13 | xml_accessor :postal_code, :from => 'PostalCode' 14 | xml_accessor :note, :from => 'Note' 15 | xml_accessor :lat, :from => 'Lat' 16 | xml_accessor :lon, :from => 'Long' 17 | 18 | def zip 19 | postal_code 20 | end 21 | 22 | def lat_to_f 23 | BigDecimal.new(lat) 24 | end 25 | 26 | def lon_to_f 27 | BigDecimal.new(lon) 28 | end 29 | 30 | def have_lat? 31 | lat.to_s != "INVALID" 32 | end 33 | 34 | def have_lon? 35 | lon.to_s != "INVALID" 36 | end 37 | 38 | end 39 | end 40 | end -------------------------------------------------------------------------------- /spec/fixtures/payment_with_line_extras.xml: -------------------------------------------------------------------------------- 1 | 2 | 83 3 | 0 4 | 5 | 2017-07-17T14:26:54-07:00 6 | 2017-07-17T14:26:54-07:00 7 | 8 | 2016-09-16 9 | USD 10 | 11 | 2400.00 12 | 13 | 68 14 | Invoice 15 | 16 | 17 | 18 | txnId 19 | 68 20 | 21 | 22 | txnOpenBalance 23 | 2400.00 24 | 25 | 26 | txnReferenceNumber 27 | 1246 28 | 29 | 30 | 31 | 3 32 | 4 33 | 2400.00 34 | 0 35 | false 36 | 37 | 38 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/time_activity_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::TimeActivity" do 2 | 3 | it "parse from XML" do 4 | xml = fixture("time_activity.xml") 5 | time_activity = Quickbooks::Model::TimeActivity.from_xml(xml) 6 | time_activity.sync_token.should == 0 7 | time_activity.txn_date.should == "2014-02-05" 8 | time_activity.name_of.should == "Employee" 9 | time_activity.employee_ref.value.should == "66" 10 | time_activity.employee_ref.name.should == "John Smith" 11 | time_activity.customer_ref.value.should == "123" 12 | time_activity.customer_ref.name.should == "Test Customer" 13 | time_activity.item_ref.value.should == "49" 14 | time_activity.item_ref.name.should == "General Consulting" 15 | time_activity.class_ref.value.should == "100100000000000321233" 16 | time_activity.class_ref.name.should == "Training" 17 | time_activity.billable_status.should == "Billable" 18 | time_activity.taxable.should == "false" 19 | time_activity.hourly_rate.should == "115" 20 | time_activity.hours.should == 1 21 | time_activity.minutes.should == 0 22 | time_activity.description.should == "Description 1" 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/util/query_builder_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Util::QueryBuilder do 2 | it "can escape a single-quoted query" do 3 | expected = "DisplayName LIKE '%O\\'Halloran'" 4 | generated = subject.clause("DisplayName", "LIKE", "%O'Halloran") 5 | expected.should == generated 6 | end 7 | 8 | it "parses a Time value to the required format" do 9 | time = Time.new(2014, 10, 31, 2, 2, 2, "+00:00") 10 | expected = "Metadata.LastUpdatedTime > '#{time.iso8601}'" 11 | generated = subject.clause("Metadata.LastUpdatedTime", ">", time) 12 | expected.should == generated 13 | end 14 | 15 | it "parses a Date value the required format" do 16 | date = Date.new(2014) 17 | expected = "DueDate > '#{date.strftime('%Y-%m-%d')}'" 18 | generated = subject.clause("DueDate", ">", date) 19 | expected.should == generated 20 | end 21 | 22 | it "parses an IN query with an array of values" do 23 | values = [10, 20, "something", "40", "it's a quote!"] 24 | expected = "DocNumber IN ('10', '20', 'something', '40', 'it\\'s a quote!')" 25 | generated = subject.clause("DocNumber", "IN", values) 26 | expected.should == generated 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/purchase_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::Purchase" do 2 | before(:all) do 3 | construct_service :purchase 4 | @resource_url = @service.url_for_resource(Quickbooks::Model::Purchase::REST_RESOURCE) 5 | end 6 | 7 | it "cannot create a Purchase without any line items" do 8 | purchase = Quickbooks::Model::Purchase.new 9 | expect(purchase.valid?).to be_false 10 | expect(purchase.errors.keys.include?(:line_items)).to be_true 11 | end 12 | 13 | it "created for account based expense" do 14 | xml = fixture("purchase_create.xml") 15 | stub_request(:post, @resource_url, ["200", "OK"], xml) 16 | 17 | purchase = Quickbooks::Model::Purchase.new 18 | purchase.payment_type = 'Cash' 19 | purchase.account_id = 36 20 | line_item = Quickbooks::Model::PurchaseLineItem.new 21 | line_item.amount = 419.99 22 | line_item.description = "Rink Liner" 23 | line_item.account_based_expense! do |detail| 24 | detail.account_id = 28 25 | detail.customer_id = 1 26 | end 27 | purchase.line_items << line_item 28 | result = @service.create(purchase) 29 | expect(result.id).to eq '160' 30 | end 31 | end 32 | 33 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/tax_code_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::TaxCode" do 2 | it "parse from XML" do 3 | xml = fixture("tax_code.xml") 4 | item = Quickbooks::Model::TaxCode.from_xml(xml) 5 | item.id.should == "2" 6 | item.sync_token.should == 0 7 | item.meta_data.should_not be_nil 8 | item.name.should == "Stupid tax" 9 | item.description.should == "Stupid tax" 10 | item.should be_active 11 | item.should be_taxable 12 | item.should be_tax_group 13 | 14 | sales_tax_rate_detail = item.sales_tax_rate_list.tax_rate_detail.first 15 | sales_tax_rate_detail.tax_rate_ref.value.should == "1" 16 | sales_tax_rate_detail.tax_rate_ref.name.should == "Stupid tax" 17 | sales_tax_rate_detail.tax_type_applicable.should == "TaxOnAmount" 18 | sales_tax_rate_detail.tax_order.should == "0" 19 | 20 | purchase_tax_rate_detail = item.purchase_tax_rate_list.tax_rate_detail.first 21 | purchase_tax_rate_detail.tax_rate_ref.value.should == "2" 22 | purchase_tax_rate_detail.tax_rate_ref.name.should == "Banana tax" 23 | purchase_tax_rate_detail.tax_type_applicable.should == "TaxOnAmount" 24 | purchase_tax_rate_detail.tax_order.should == "0" 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/quickbooks/service/reports.rb: -------------------------------------------------------------------------------- 1 | # Docs: https://developer.intuit.com/docs/0100_accounting/0400_references/reports 2 | module Quickbooks 3 | module Service 4 | class Reports < BaseService 5 | 6 | def url_for_query(which_report = 'BalanceSheet', date_macro = 'This Fiscal Year-to-date', options = {}) 7 | if(options == {}) 8 | return "#{url_for_base}/reports/#{which_report}?date_macro=#{URI.encode_www_form_component(date_macro)}" 9 | else 10 | options_string = "" 11 | options.each do |key, value| 12 | options_string += "#{key}=#{value}&" 13 | end 14 | options_string = options_string[0..-2] 15 | options_string.gsub!(/\s/,"%20") 16 | return "#{url_for_base}/reports/#{which_report}?#{options_string}" 17 | end 18 | end 19 | 20 | def query(object_query = 'BalanceSheet', date_macro = 'This Fiscal Year-to-date', options = {}) 21 | do_http_get(url_for_query(object_query, date_macro, options)) 22 | model.new(:xml => @last_response_xml) 23 | end 24 | 25 | private 26 | 27 | def model 28 | Quickbooks::Model::Report 29 | end 30 | 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/quickbooks/model/deposit_line_item.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class DepositLineItem < BaseModel 4 | 5 | #== Constants 6 | DEPOSIT_LINE_DETAIL = 'DepositLineDetail' 7 | 8 | xml_accessor :id, :from => 'Id' 9 | xml_accessor :line_num, :from => 'LineNum', :as => Integer 10 | xml_accessor :description, :from => 'Description' 11 | xml_accessor :amount, :from => 'Amount', :as => BigDecimal, :to_xml => to_xml_big_decimal 12 | xml_accessor :linked_transactions, :from => 'LinkedTxn', :as => [LinkedTransaction] 13 | 14 | xml_accessor :detail_type, :from => 'DetailType' 15 | 16 | #== Various detail types 17 | xml_accessor :deposit_line_detail, :from => 'DepositLineDetail', :as => DepositLineDetail 18 | 19 | xml_accessor :custom_fields, :from => 'CustomField', :as => [CustomField] 20 | 21 | 22 | def deposit_line_detail? 23 | detail_type.to_s == DEPOSIT_LINE_DETAIL 24 | end 25 | 26 | def deposit_line_detail! 27 | self.detail_type = DEPOSIT_LINE_DETAIL 28 | self.deposit_line_detail = DepositLineDetail.new 29 | 30 | yield self.deposit_line_detail if block_given? 31 | end 32 | 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_rate.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxRate < BaseModel 4 | XML_COLLECTION_NODE = "TaxRate" 5 | XML_NODE = "TaxRate" 6 | REST_RESOURCE = "taxrate" 7 | 8 | xml_accessor :id, :from => "Id" 9 | xml_accessor :sync_token, :from => "SyncToken", :as => Integer 10 | xml_accessor :meta_data, :from => "MetaData", :as => MetaData 11 | xml_accessor :name, :from => "Name" 12 | xml_accessor :description, :from => "Description" 13 | xml_accessor :active?, :from => "Active" 14 | xml_accessor :rate_value, :from => "RateValue", :as => BigDecimal, :to_xml => :to_f.to_proc 15 | xml_accessor :agency_ref, :from => "AgencyRef", :as => BaseReference 16 | xml_accessor :tax_return_line_ref, :from => "TaxReturnLineRef", :as => BaseReference 17 | xml_accessor :special_tax_type, :from => "SpecialTaxType" 18 | xml_accessor :display_type, :from => "DisplayType" 19 | xml_accessor :effective_tax_rate, :from => "EffectiveTaxRate", :as => [EffectiveTaxRate] 20 | 21 | validates_presence_of :name, :rate_value 22 | 23 | reference_setters :agency_ref 24 | reference_setters :tax_return_line_ref 25 | 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/quickbooks/model/term.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Term < BaseModel 4 | XML_COLLECTION_NODE = "Term" 5 | XML_NODE = "Term" 6 | REST_RESOURCE = 'term' 7 | 8 | xml_accessor :id, :from => 'Id' 9 | xml_accessor :sync_token, :from => 'SyncToken', :as => Integer 10 | xml_accessor :meta_data, :from => 'MetaData', :as => MetaData 11 | xml_accessor :name, :from => 'Name' 12 | xml_accessor :active?, :from => 'Active' 13 | xml_accessor :type, :from => 'Type' 14 | xml_accessor :discount_percent, :from => 'DiscountPercent', :as => BigDecimal 15 | xml_accessor :due_days, :from => 'DueDays', :as => Integer 16 | xml_accessor :discount_days, :from => 'DiscountDays', :as => Integer 17 | xml_accessor :day_of_month_due, :from => 'DayOfMonthDue', :as => Integer 18 | xml_accessor :due_next_month_days, :from => 'DueNextMonthDays', :as => Integer 19 | xml_accessor :discount_day_of_month, :from => 'DiscountDayOfMonth', :as => Integer 20 | xml_accessor :attachable_ref, :from => 'AttachableRef', :as => BaseReference 21 | 22 | validates_presence_of :name 23 | 24 | reference_setters :attachable_ref 25 | 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/quickbooks/service/base_service_json.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class BaseServiceJSON < BaseService 4 | include ServiceCrudJSON 5 | HTTP_CONTENT_TYPE = 'application/json' 6 | HTTP_ACCEPT = 'application/json' 7 | attr_reader :last_response_json 8 | 9 | private 10 | 11 | def parse_json(json) 12 | @last_response_json = json 13 | end 14 | 15 | def response_is_error? 16 | @last_response_json['Fault'].present? 17 | end 18 | 19 | def parse_intuit_error 20 | error = {:message => "", :detail => "", :type => nil, :code => 0} 21 | resp = JSON.parse(@last_response_json) 22 | fault = resp['Fault'] 23 | if fault.present? 24 | error[:type] = fault['type'] if fault.has_key?('type') 25 | if fault_error = fault['Error'].first 26 | error[:message] = fault_error['Message'] 27 | error[:detail] = fault_error['Detail'] 28 | error[:code] = fault_error['code'] 29 | end 30 | end 31 | error 32 | rescue Exception => exception 33 | error[:detail] = @last_response_json.to_s 34 | error 35 | end 36 | 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/exchange_rate_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::ExchangeRate" do 2 | before(:all) { construct_service :exchange_rate } 3 | 4 | it "can query exchange rates" do 5 | stub_request(:get, 6 | @service.url_for_query, 7 | ["200", "OK"], 8 | fixture("exchange_rates.xml")) 9 | 10 | exchange_rates = @service.query 11 | 12 | exchange_rates.entries.count.should eq(1) 13 | exchange_rates.entries.first.source_currency_code.should eq("EUR") 14 | exchange_rates.entries.first.target_currency_code.should eq("USD") 15 | exchange_rates.entries.first.rate.should eq(2.5) 16 | end 17 | 18 | it "can query exchange rates by currency" do 19 | model = Quickbooks::Model::ExchangeRate 20 | stub_request(:get, 21 | "#{@service.url_for_resource(model::REST_RESOURCE)}?sourcecurrencycode=EUR", 22 | ["200", "OK"], 23 | fixture("exchange_rate_by_currency.xml")) 24 | 25 | exchange_rate = @service.fetch_by_currency('EUR') 26 | 27 | exchange_rate.source_currency_code.should eq("EUR") 28 | exchange_rate.target_currency_code.should eq("USD") 29 | exchange_rate.rate.should eq(2.5) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/quickbooks/model/tax_rate_detail_line.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class TaxRateDetailLine < BaseModel 4 | 5 | xml_accessor :tax_rate_id, :from => "TaxRateId" 6 | xml_accessor :tax_rate_name, :from => "TaxRateName" 7 | xml_accessor :rate_value, :from => "RateValue" 8 | xml_accessor :tax_agency_id, :from => "TaxAgencyId" 9 | xml_accessor :tax_applicable_on, :from => 'TaxApplicableOn', :as => :text 10 | 11 | validates :tax_rate_name, presence: true, length: { maximum: 100 }, if: Proc.new {|line| line.tax_rate_id.blank?} 12 | validates :tax_agency_id, presence: true, numericality: {greater_than: 0}, if: Proc.new {|line| line.tax_rate_id.blank?} 13 | validates :rate_value, presence: true, numericality: {less_than_or_equal_to: 100}, if: Proc.new {|line| line.tax_rate_id.blank?} 14 | validates :tax_rate_id, numericality: true, if: Proc.new {|line| line.tax_rate_name.blank? && tax_agency_id.blank? && rate_value.blank? } 15 | 16 | validates :tax_applicable_on, inclusion: {in: %w(Sales Purchase)} 17 | 18 | def to_json 19 | attributes.inject({}){|mem, item| mem[item.first.camelize] = item.last if item.last.present?; mem} 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/fixtures/employee.xml: -------------------------------------------------------------------------------- 1 | 2 | 48 3 | 0 4 | 5 | 2013-10-11T08:28:30-07:00 6 | 2013-10-11T08:28:30-07:00 7 | 8 | false 9 | Jenny 10 | Miller 11 | Jenny Miller 12 | Jenny Miller 13 | true 14 | 15 | 525-7891 16 | 17 | 18 |
jenny.employee@intuit.com
19 |
20 | XXX-XX-XXXX 21 | 22 | 50 23 | 45 N. Elm Street 24 | Middlefield 25 | CA 26 | 93242 27 | 28 | true 29 | 115.00 30 | 1995-06-01 31 | female 32 | 2013-11-01 33 |
34 | -------------------------------------------------------------------------------- /lib/quickbooks/service/access_token.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class AccessToken < BaseService 4 | 5 | RENEW_URL = "https://appcenter.intuit.com/api/v1/connection/reconnect" 6 | DISCONNECT_URL = "https://appcenter.intuit.com/api/v1/connection/disconnect" 7 | 8 | # https://developer.intuit.com/docs/0025_quickbooksapi/0053_auth_auth/oauth_management_api#Reconnect 9 | def renew 10 | result = nil 11 | response = do_http_get(RENEW_URL) 12 | if response 13 | code = response.code.to_i 14 | if code == 200 15 | result = Quickbooks::Model::AccessTokenResponse.from_xml(response.plain_body) 16 | end 17 | end 18 | 19 | result 20 | end 21 | 22 | # https://developer.intuit.com/docs/0025_quickbooksapi/0053_auth_auth/oauth_management_api#Disconnect 23 | def disconnect 24 | result = nil 25 | response = do_http_get(DISCONNECT_URL) 26 | if response 27 | code = response.code.to_i 28 | if code == 200 29 | result = Quickbooks::Model::AccessTokenResponse.from_xml(response.plain_body) 30 | end 31 | end 32 | 33 | result 34 | end 35 | 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/batch_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Service::Batch" do 2 | before(:all) do 3 | construct_service :batch 4 | end 5 | 6 | it "make batch request with success" do 7 | xml = fixture("batch_response.xml") 8 | stub_request(:post, @service.url_for_resource('batch'), ["200", "OK"], xml) 9 | batch_resp = @service.make_request(Quickbooks::Model::BatchRequest.new) 10 | batch_resp.class.should == Quickbooks::Model::BatchResponse 11 | end 12 | 13 | it "make batch request with error" do 14 | xml = fixture("batch_response.xml") 15 | stub_request(:post, @service.url_for_resource('batch'), ["400", ""], xml) 16 | Proc.new{ 17 | @service.make_request(Quickbooks::Model::BatchRequest.new) 18 | }.should raise_error(Quickbooks::IntuitRequestException) 19 | end 20 | 21 | it "allows user to specify a RequestId in a create call" do 22 | requestid = "foobar123" 23 | xml = fixture("batch_response.xml") 24 | stub_request(:post, "#{@service.url_for_resource('batch')}?requestid=#{requestid}", ["200", "OK"], xml) 25 | batch_resp = @service.make_request(Quickbooks::Model::BatchRequest.new, :query => {:requestid => requestid}) 26 | batch_resp.class.should == Quickbooks::Model::BatchResponse 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/quickbooks/model/upload.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Upload < BaseModel 4 | xml_convention :camelcase 5 | 6 | #xml_accessor :attache, :as => Attachable 7 | 8 | end 9 | end 10 | end 11 | 12 | =begin 13 | 14 | Response XML: 15 | 16 | 17 | 18 | 19 | 2700000000001439108 20 | 0 21 | 22 | 2014-08-18T09:58:06-07:00 23 | 2014-08-18T09:58:06-07:00 24 | 25 | monkey.jpg 26 | /v3/company/1002341430/download/2700000000001439108 27 | https://intuit-qbo-prod-30.s3.amazonaws.com/1002341430%2Fattachments%2Fmonkey.jpg?Expires=1408381986&AWSAccessKeyId=AKIAJEXDXKNYCBUNCCCQ&Signature=WOVACYm6zi1rM5EGZRq3d3AMSM0%3D 28 | 105840 29 | image/jpeg 30 | /v3/company/1002341430/attachable-thumbnail/2700000000001439108 31 | 32 | 33 | 34 | 35 | =end 36 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/attachable_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Service::Account do 2 | before(:all) do 3 | construct_service :attachable 4 | end 5 | 6 | it "can query for attachables" do 7 | xml = fixture("attachables.xml") 8 | stub_request(:get, @service.url_for_query, ["200", "OK"], xml, {}, true) 9 | 10 | attachables = @service.query 11 | attachables.entries.count.should == 1 12 | 13 | monkey = attachables.entries.first 14 | monkey.file_name.should == 'monkey.jpg' 15 | end 16 | 17 | it "can create an attachble" do 18 | xml = fixture("attachable_create_response.xml") 19 | stub_request(:post, @service.url_for_resource('attachable'), ["200", "OK"], xml, {}, true) 20 | 21 | attachable = Quickbooks::Model::Attachable.new 22 | attachable.file_name = "monkey.jpg" 23 | attachable.note = "A note" 24 | entity = Quickbooks::Model::BaseReference.new(3, type: 'Customer') 25 | attachable.attachable_ref = Quickbooks::Model::AttachableRef.new(entity) 26 | n = Nokogiri::XML(attachable.to_xml.to_s) 27 | n.at('AttachableRef > EntityRef').content.should == '3' 28 | n.at('AttachableRef > EntityRef')[:type].should == 'Customer' 29 | response = @service.create(attachable) 30 | response.note.should == attachable.note 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /lib/quickbooks/model/journal_entry_line_detail.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class JournalEntryLineDetail < BaseModel 4 | include NameEntity::Quality 5 | 6 | xml_accessor :posting_type, :from => 'PostingType' 7 | xml_accessor :entity, :from => 'Entity', :as => Entity 8 | xml_accessor :account_ref, :from => 'AccountRef', :as => BaseReference 9 | xml_accessor :class_ref, :from => 'ClassRef', :as => BaseReference 10 | xml_accessor :department_ref, :from => 'DepartmentRef', :as => BaseReference 11 | 12 | xml_accessor :tax_code_ref, :from => 'TaxCodeRef', :as => BaseReference 13 | xml_accessor :tax_applicable_on, :from => 'TaxApplicableOn', :as => :text 14 | xml_accessor :tax_amount, :from => 'TaxAmount', :as => BigDecimal, :to_xml => to_xml_big_decimal 15 | 16 | xml_accessor :billable_status, :from => 'BillableStatus' 17 | 18 | reference_setters :account_ref, :class_ref, :department_ref, :tax_code_ref 19 | 20 | validates_length_of :description, :maximum => 4000 21 | validates_numericality_of :tax_amount, allow_nil: true, greater_than_or_equal_to:0.0, less_than_or_equal_to:999999999.0 22 | validate :posting_type_is_valid 23 | validate :billable_status_is_valid 24 | validate :journal_line_entry_tax 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/fixtures/bill_create_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 3 | 2017-12-16 4 | 5 | 1 6 | 700.00 7 | AccountBasedExpenseLineDetail 8 | 9 | 100000000000128320 10 | 42 11 | NotBillable 12 | NON 13 | 14 | 15 | 16 | 2 17 | 55.12 18 | AccountBasedExpenseLineDetail 19 | 20 | 100000000000128320 21 | 77 22 | NotBillable 23 | NON 24 | 25 | 26 | 4 27 | 38 28 | 755.12 29 | 2018-12-26 30 | -------------------------------------------------------------------------------- /spec/fixtures/sales_receipt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 0 5 | 6 | 2013-12-10T05:35:42-08:00 7 | 2013-12-10T05:35:42-08:00 8 | 9 | 1002 10 | 2013-12-10 11 | private 12 | BRL 13 | 14 | 1 15 | 1 16 | 10.00 17 | SalesItemLineDetail 18 | 19 | 1 20 | 10 21 | 1 22 | 23 | 24 | 25 | 10.00 26 | SubTotalLineDetail 27 | 28 | 29 | 1 30 | memo! 31 | NotApplicable 32 | 10.00 33 | NotSet 34 | NotSet 35 | 0 36 | 28 37 | 38 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/account_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Model::Account do 2 | it "must have a name for create / update" do 3 | account = Quickbooks::Model::Account.new 4 | account.valid? 5 | account.errors.keys.include?(:name).should == true 6 | 7 | account.name = Array.new(102).join("a") # 101 character, too long 8 | account.valid? 9 | account.errors.keys.include?(:name).should == true 10 | 11 | account.name = "Invalid name with :" 12 | account.valid? 13 | account.errors.keys.include?(:name).should == true 14 | 15 | account.name = "Invalid name with \"" 16 | account.valid? 17 | account.errors.keys.include?(:name).should == true 18 | 19 | account.name = "Regular" 20 | account.valid? 21 | account.errors.keys.include?(:name).should == false 22 | end 23 | 24 | it "must have a classifiction" do 25 | account = Quickbooks::Model::Account.new 26 | account.valid? 27 | account.errors.keys.include?(:classification).should == true 28 | 29 | account.classification = 'Undocummented Classification' 30 | account.valid? 31 | account.errors.keys.include?(:classification).should == true 32 | 33 | account.classification = Quickbooks::Model::Account::LIABILITY 34 | account.valid? 35 | account.errors.keys.include?(:classification).should == false 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/quickbooks/model/change_data_capture.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class ChangeDataCapture < BaseModel 4 | 5 | attr_accessor :xml 6 | 7 | TYPES = ["Bill", "BillPayment", "CreditMemo", "Deposit", "Invoice", "JournalEntry", "Payment", 8 | "Purchase", "RefundReceipt", "SalesReceipt", "PurchaseOrder", "VendorCredit", "Transfer", 9 | "Estimate", "Account", "Budget", "Class", "Customer", "Department", "Employee", "Item", 10 | "PaymentMethod", "Term", "Vendor"] 11 | 12 | def all_types 13 | data = {} 14 | TYPES.each do |entity| 15 | if xml.css(entity).first != nil 16 | data[entity] = all_of_type(entity) 17 | end 18 | end 19 | data 20 | end 21 | 22 | private 23 | 24 | def all_of_type(entity) 25 | parse_block(xml.css(entity).first.parent, entity) 26 | end 27 | 28 | def parse_block(node, entity) 29 | model = "Quickbooks::Model::#{entity}".constantize 30 | models = [] 31 | all_items = node.css(entity).map do |item| 32 | if item.attribute("status").try(:value) == "Deleted" 33 | Quickbooks::Model::ChangeModel.from_xml(item) 34 | else 35 | model.from_xml(item) 36 | end 37 | end 38 | end 39 | 40 | end 41 | end 42 | end -------------------------------------------------------------------------------- /spec/fixtures/fetch_employee_by_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 0 5 | 6 | 2013-10-11T08:28:30-07:00 7 | 2013-10-11T08:28:30-07:00 8 | 9 | false 10 | Lindy 11 | Miller 12 | Lindy Miller 13 | Lindy Miller 14 | true 15 | 16 | 525-7892 17 | 18 | 19 |
lindy.employee@intuit.com
20 |
21 | XXX-XX-XXXX 22 | 23 | 50 24 | 99 N. Elm Street 25 | Middlesburg 26 | VA 27 | 93242 28 | 29 | true 30 | 215.00 31 | 1991-03-28 32 | female 33 | 2013-09-01 34 |
35 | -------------------------------------------------------------------------------- /spec/fixtures/deleted_employee.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 1 5 | 6 | 2013-10-11T08:28:30-07:00 7 | 2013-10-11T08:28:30-07:00 8 | 9 | false 10 | Lindy 11 | Miller 12 | Lindy Miller (Deleted) 13 | Lindy Miller 14 | false 15 | 16 | 525-7892 17 | 18 | 19 |
lindy.employee@intuit.com
20 |
21 | XXX-XX-XXXX 22 | 23 | 50 24 | 99 N. Elm Street 25 | Middlesburg 26 | VA 27 | 93242 28 | 29 | true 30 | 215.00 31 | 1991-03-28 32 | female 33 | 2013-09-01 34 |
35 | -------------------------------------------------------------------------------- /lib/quickbooks/model/report.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Model 3 | class Report < BaseModel 4 | 5 | attr_accessor :xml 6 | 7 | def all_rows 8 | @all_rows ||= xml.css("ColData:first-child").map {|node| parse_row(node.parent) } 9 | end 10 | 11 | def columns 12 | @columns ||= begin 13 | nodes = xml.css('Column') 14 | nodes.map do |node| 15 | # There is also a ColType field, but it does not seem valuable to capture 16 | node.at('ColTitle').content 17 | end 18 | end 19 | end 20 | 21 | def find_row(label) 22 | all_rows.find {|r| r[0] == label } 23 | end 24 | 25 | private 26 | 27 | # Parses the given row: 28 | # 29 | # 30 | # 31 | # 32 | # 33 | # 34 | # To: 35 | # ['Checking', BigDecimal(1201.00), BigDecimal(200.50)] 36 | def parse_row(row_node) 37 | row_node.elements.map.with_index do |el, i| 38 | value = el.attr('value') 39 | 40 | next nil if value.blank? 41 | next value if value.to_s.match(/^\d+$|^\d+.\d+$|^-\d+|^-\d+.\d+$|^.\d+$/).nil? 42 | BigDecimal(value) 43 | end 44 | end 45 | 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/service/tax_agency_spec.rb: -------------------------------------------------------------------------------- 1 | describe Quickbooks::Service::TaxAgency do 2 | before(:all) { construct_service :tax_agency } 3 | 4 | before do 5 | subject.company_id = "9991111222" 6 | subject.access_token = construct_oauth 7 | end 8 | 9 | let(:model) { Quickbooks::Model::TaxAgency } 10 | let(:tax_agency) { model.new(display_name: 'First TaxAgency')} 11 | let(:resource) { model::REST_RESOURCE } 12 | 13 | it "can query tax agency" do 14 | stub_request(:get, 15 | @service.url_for_query, 16 | ["200", "OK"], 17 | fixture("tax_agencies.xml")) 18 | tax_agencies = @service.query 19 | tax_agencies.entries.count.should eq(1) 20 | tax_agencies.entries.first.display_name.should eq("First TaxAgency") 21 | end 22 | 23 | it "can create tax agency" do 24 | xml = fixture("tax_agency_entity.xml") 25 | stub_request(:post, subject.url_for_resource(resource), ["200", "OK"], xml) 26 | 27 | entity = subject.create(tax_agency) 28 | expect(entity.display_name).to eq tax_agency.display_name 29 | end 30 | 31 | it "can not create tax agency without display_name" do 32 | agency = model.new 33 | 34 | expect { 35 | subject.create(agency) 36 | }.to raise_error(Quickbooks::InvalidModelException) 37 | 38 | expect(agency.errors.messages).to have_key(:display_name) 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /spec/fixtures/items.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2 5 | 0 6 | 7 | 2013-11-16T17:42:03-08:00 8 | 2013-11-16T17:42:03-08:00 9 | 10 | Plush Baby Doll 11 | A fine baby doll - in many colors 12 | true 13 | false 14 | 50 15 | Service 16 | 1 17 | 0 18 | false 19 | 20 | 21 | 1 22 | 0 23 | 24 | 2013-11-15T11:28:31-08:00 25 | 2013-11-15T11:28:31-08:00 26 | 27 | Sales 28 | true 29 | false 30 | 0 31 | Service 32 | 1 33 | 0 34 | false 35 | 36 | 37 | -------------------------------------------------------------------------------- /lib/quickbooks/service/invoice.rb: -------------------------------------------------------------------------------- 1 | module Quickbooks 2 | module Service 3 | class Invoice < BaseService 4 | 5 | def delete(invoice) 6 | delete_by_query_string(invoice) 7 | end 8 | 9 | def send(invoice, email_address=nil) 10 | query = email_address.present? ? "?sendTo=#{email_address}" : "" 11 | url = "#{url_for_resource(model::REST_RESOURCE)}/#{invoice.id}/send#{query}" 12 | response = do_http_post(url,{}) 13 | if response.code.to_i == 200 14 | model.from_xml(parse_singular_entity_response(model, response.plain_body)) 15 | else 16 | nil 17 | end 18 | end 19 | 20 | def pdf(invoice) 21 | url = "#{url_for_resource(model::REST_RESOURCE)}/#{invoice.id}/pdf" 22 | response = do_http_raw_get(url, {}, {'Accept' => 'application/pdf'}) 23 | response.plain_body 24 | end 25 | 26 | def void(invoice, options = {}) 27 | url = "#{url_for_resource(model::REST_RESOURCE)}?operation=void" 28 | 29 | xml = invoice.to_xml_ns(options) 30 | response = do_http_post(url, valid_xml_document(xml)) 31 | if response.code.to_i == 200 32 | model.from_xml(parse_singular_entity_response(model, response.plain_body)) 33 | else 34 | false 35 | end 36 | end 37 | 38 | private 39 | 40 | def model 41 | Quickbooks::Model::Invoice 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/lib/quickbooks/model/term_spec.rb: -------------------------------------------------------------------------------- 1 | describe "Quickbooks::Model::Term" do 2 | it "parses from XML" do 3 | xml = fixture("term.xml") 4 | term = Quickbooks::Model::Term.from_xml(xml) 5 | 6 | term.id.should == "11" 7 | term.sync_token.should == 0 8 | term.meta_data.create_time.should == Time.new(2013, 7, 11, 17, 46, 39, "-07:00") 9 | term.meta_data.last_updated_time.should == Time.new(2013, 7, 11, 17, 46, 42, "-07:00") 10 | term.name.should == "TermForV3Testing-1373590184130" 11 | term.active?.should be_true 12 | term.type.should == "DATE_DRIVEN" 13 | term.discount_percent.should == 4.0 14 | term.due_days.should be_nil 15 | term.discount_days.should be_nil 16 | term.day_of_month_due.should == 1 17 | term.due_next_month_days.should == 2 18 | term.discount_day_of_month.should == 3 19 | end 20 | 21 | it "is invalid without a name" do 22 | term = Quickbooks::Model::Term.new 23 | term.should_not be_valid 24 | end 25 | 26 | it "is valid with a name" do 27 | term = Quickbooks::Model::Term.new 28 | term.name = "Cool Term, Yo" 29 | term.should be_valid 30 | end 31 | 32 | describe "#active?" do 33 | it "returns true when active == 'true'" do 34 | term = Quickbooks::Model::Term.new 35 | term.active = "true" 36 | term.should be_true 37 | end 38 | 39 | it "returns false when active == 'false'" do 40 | term = Quickbooks::Model::Term.new 41 | term.active = "false" 42 | term.should_not be_false 43 | end 44 | end 45 | end 46 | --------------------------------------------------------------------------------