fortnox-api 0.9.2 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +78 -100
- data/{LICENSE.txt → LICENSE.md} +0 -0
- data/README.md +234 -248
- data/bin/fortnox-setup +195 -0
- data/bin/fortnox-update-env +38 -0
- data/fortnox.gemspec +29 -0
- data/lib/fortnox/auth/thread_local.rb +28 -0
- data/lib/fortnox/collection.rb +23 -0
- data/lib/fortnox/mappers/country_code.rb +34 -0
- data/lib/fortnox/mappers/date.rb +21 -0
- data/lib/fortnox/mappers/document_row.rb +12 -0
- data/lib/fortnox/mappers/edi_information.rb +15 -0
- data/lib/fortnox/mappers/email_information.rb +11 -0
- data/lib/fortnox/mappers/invoice_row.rb +14 -0
- data/lib/fortnox/mappers/label_references.rb +24 -0
- data/lib/fortnox/mappers/order_row.rb +9 -0
- data/lib/fortnox/mappers/struct.rb +71 -0
- data/lib/fortnox/mappers/struct_array.rb +31 -0
- data/lib/fortnox/resource.rb +121 -0
- data/lib/fortnox/resources/article.rb +159 -0
- data/lib/fortnox/resources/customer.rb +208 -0
- data/lib/fortnox/resources/document.rb +202 -0
- data/lib/fortnox/resources/invoice.rb +91 -0
- data/lib/fortnox/resources/label.rb +14 -0
- data/lib/fortnox/resources/order.rb +37 -0
- data/lib/fortnox/resources/project.rb +40 -0
- data/lib/fortnox/resources/terms_of_payment.rb +22 -0
- data/lib/fortnox/resources/unit.rb +25 -0
- data/lib/fortnox/struct.rb +24 -0
- data/lib/fortnox/structs/default_delivery_types.rb +16 -0
- data/lib/fortnox/structs/default_templates.rb +19 -0
- data/lib/fortnox/structs/document_row.rb +62 -0
- data/lib/fortnox/structs/edi_information.rb +25 -0
- data/lib/fortnox/structs/email_information.rb +22 -0
- data/lib/fortnox/structs/invoice_row.rb +13 -0
- data/lib/fortnox/structs/order_row.rb +10 -0
- data/lib/fortnox/types.rb +129 -0
- data/lib/fortnox/{api/version.rb → version.rb} +1 -3
- data/lib/fortnox.rb +102 -0
- metadata +55 -580
- data/.codeclimate.yml +0 -20
- data/.env.template +0 -7
- data/.env.test +0 -11
- data/.gitignore +0 -20
- data/.rspec +0 -2
- data/.rubocop.yml +0 -41
- data/.tool-versions +0 -1
- data/.travis.yml +0 -32
- data/CLAUDE.md +0 -79
- data/CONTRIBUTE.md +0 -38
- data/DEVELOPER_README.md +0 -69
- data/Gemfile +0 -6
- data/Guardfile +0 -16
- data/Rakefile +0 -140
- data/bin/console +0 -22
- data/bin/fortnox +0 -285
- data/bin/get_tokens +0 -79
- data/bin/renew_tokens +0 -28
- data/docs/gotchas.md +0 -146
- data/fortnox-api.gemspec +0 -50
- data/lib/fortnox/api/mappers/article.rb +0 -23
- data/lib/fortnox/api/mappers/base/canonical_name_sym.rb +0 -21
- data/lib/fortnox/api/mappers/base/from_json.rb +0 -91
- data/lib/fortnox/api/mappers/base/to_json.rb +0 -66
- data/lib/fortnox/api/mappers/base.rb +0 -30
- data/lib/fortnox/api/mappers/customer.rb +0 -27
- data/lib/fortnox/api/mappers/default_delivery_types.rb +0 -15
- data/lib/fortnox/api/mappers/default_templates.rb +0 -16
- data/lib/fortnox/api/mappers/edi_information.rb +0 -23
- data/lib/fortnox/api/mappers/email_information.rb +0 -19
- data/lib/fortnox/api/mappers/invoice.rb +0 -29
- data/lib/fortnox/api/mappers/invoice_row.rb +0 -25
- data/lib/fortnox/api/mappers/order.rb +0 -26
- data/lib/fortnox/api/mappers/order_row.rb +0 -23
- data/lib/fortnox/api/mappers/project.rb +0 -17
- data/lib/fortnox/api/mappers/terms_of_payment.rb +0 -17
- data/lib/fortnox/api/mappers/unit.rb +0 -17
- data/lib/fortnox/api/mappers/value/array.rb +0 -18
- data/lib/fortnox/api/mappers/value/country_string.rb +0 -24
- data/lib/fortnox/api/mappers/value/date.rb +0 -11
- data/lib/fortnox/api/mappers/value/hash.rb +0 -16
- data/lib/fortnox/api/mappers/value/identity.rb +0 -18
- data/lib/fortnox/api/mappers.rb +0 -21
- data/lib/fortnox/api/models/article.rb +0 -134
- data/lib/fortnox/api/models/base.rb +0 -128
- data/lib/fortnox/api/models/customer.rb +0 -210
- data/lib/fortnox/api/models/document.rb +0 -189
- data/lib/fortnox/api/models/invoice.rb +0 -87
- data/lib/fortnox/api/models/label.rb +0 -19
- data/lib/fortnox/api/models/order.rb +0 -27
- data/lib/fortnox/api/models/project.rb +0 -42
- data/lib/fortnox/api/models/terms_of_payment.rb +0 -28
- data/lib/fortnox/api/models/unit.rb +0 -24
- data/lib/fortnox/api/models.rb +0 -9
- data/lib/fortnox/api/repositories/article.rb +0 -17
- data/lib/fortnox/api/repositories/authentication.rb +0 -61
- data/lib/fortnox/api/repositories/base/loaders.rb +0 -64
- data/lib/fortnox/api/repositories/base/savers.rb +0 -57
- data/lib/fortnox/api/repositories/base.rb +0 -93
- data/lib/fortnox/api/repositories/customer.rb +0 -17
- data/lib/fortnox/api/repositories/invoice.rb +0 -17
- data/lib/fortnox/api/repositories/order.rb +0 -17
- data/lib/fortnox/api/repositories/project.rb +0 -17
- data/lib/fortnox/api/repositories/terms_of_payment.rb +0 -17
- data/lib/fortnox/api/repositories/unit.rb +0 -17
- data/lib/fortnox/api/repositories.rb +0 -10
- data/lib/fortnox/api/request_handling.rb +0 -46
- data/lib/fortnox/api/types/default_delivery_types.rb +0 -20
- data/lib/fortnox/api/types/default_templates.rb +0 -23
- data/lib/fortnox/api/types/defaulted.rb +0 -11
- data/lib/fortnox/api/types/document_row.rb +0 -64
- data/lib/fortnox/api/types/edi_information.rb +0 -29
- data/lib/fortnox/api/types/email_information.rb +0 -26
- data/lib/fortnox/api/types/enums.rb +0 -116
- data/lib/fortnox/api/types/invoice_row.rb +0 -19
- data/lib/fortnox/api/types/model.rb +0 -37
- data/lib/fortnox/api/types/nullable.rb +0 -25
- data/lib/fortnox/api/types/order_row.rb +0 -16
- data/lib/fortnox/api/types/required.rb +0 -13
- data/lib/fortnox/api/types/shim/country_string.rb +0 -10
- data/lib/fortnox/api/types/sized.rb +0 -33
- data/lib/fortnox/api/types.rb +0 -144
- data/lib/fortnox/api.rb +0 -62
- data/spec/fortnox/api/mappers/article_spec.rb +0 -17
- data/spec/fortnox/api/mappers/base/canonical_name_sym_spec.rb +0 -36
- data/spec/fortnox/api/mappers/base/from_json_spec.rb +0 -70
- data/spec/fortnox/api/mappers/base/to_json_spec.rb +0 -68
- data/spec/fortnox/api/mappers/base_spec.rb +0 -154
- data/spec/fortnox/api/mappers/contexts/json_conversion.rb +0 -62
- data/spec/fortnox/api/mappers/customer_spec.rb +0 -27
- data/spec/fortnox/api/mappers/default_delivery_types_spec.rb +0 -14
- data/spec/fortnox/api/mappers/edi_information_spec.rb +0 -23
- data/spec/fortnox/api/mappers/email_information_spec.rb +0 -19
- data/spec/fortnox/api/mappers/examples/mapper.rb +0 -34
- data/spec/fortnox/api/mappers/invoice_row_spec.rb +0 -24
- data/spec/fortnox/api/mappers/invoice_spec.rb +0 -27
- data/spec/fortnox/api/mappers/order_row_spec.rb +0 -21
- data/spec/fortnox/api/mappers/order_spec.rb +0 -23
- data/spec/fortnox/api/mappers/project_spec.rb +0 -12
- data/spec/fortnox/api/mappers/terms_of_payment_spec.rb +0 -16
- data/spec/fortnox/api/mappers/unit_spec.rb +0 -56
- data/spec/fortnox/api/models/article_spec.rb +0 -9
- data/spec/fortnox/api/models/base_spec.rb +0 -117
- data/spec/fortnox/api/models/customer_spec.rb +0 -9
- data/spec/fortnox/api/models/examples/document_base.rb +0 -15
- data/spec/fortnox/api/models/examples/model.rb +0 -22
- data/spec/fortnox/api/models/invoice_spec.rb +0 -11
- data/spec/fortnox/api/models/order_spec.rb +0 -12
- data/spec/fortnox/api/models/project_spec.rb +0 -9
- data/spec/fortnox/api/models/terms_of_payment_spec.rb +0 -9
- data/spec/fortnox/api/models/unit_spec.rb +0 -33
- data/spec/fortnox/api/repositories/article_spec.rb +0 -80
- data/spec/fortnox/api/repositories/authentication_spec.rb +0 -103
- data/spec/fortnox/api/repositories/base_spec.rb +0 -168
- data/spec/fortnox/api/repositories/customer_spec.rb +0 -119
- data/spec/fortnox/api/repositories/examples/all.rb +0 -17
- data/spec/fortnox/api/repositories/examples/find.rb +0 -84
- data/spec/fortnox/api/repositories/examples/only.rb +0 -34
- data/spec/fortnox/api/repositories/examples/save.rb +0 -76
- data/spec/fortnox/api/repositories/examples/save_with_nested_model.rb +0 -28
- data/spec/fortnox/api/repositories/examples/save_with_specially_named_attribute.rb +0 -26
- data/spec/fortnox/api/repositories/examples/search.rb +0 -39
- data/spec/fortnox/api/repositories/invoice_spec.rb +0 -297
- data/spec/fortnox/api/repositories/order_spec.rb +0 -53
- data/spec/fortnox/api/repositories/project_spec.rb +0 -36
- data/spec/fortnox/api/repositories/terms_of_payment_spec.rb +0 -34
- data/spec/fortnox/api/repositories/unit_spec.rb +0 -39
- data/spec/fortnox/api/types/account_number_spec.rb +0 -35
- data/spec/fortnox/api/types/country_code_spec.rb +0 -42
- data/spec/fortnox/api/types/country_spec.rb +0 -67
- data/spec/fortnox/api/types/default_delivery_types_spec.rb +0 -12
- data/spec/fortnox/api/types/edi_information_spec.rb +0 -15
- data/spec/fortnox/api/types/email_information_spec.rb +0 -15
- data/spec/fortnox/api/types/email_spec.rb +0 -56
- data/spec/fortnox/api/types/enums_spec.rb +0 -17
- data/spec/fortnox/api/types/examples/document_row.rb +0 -25
- data/spec/fortnox/api/types/examples/enum.rb +0 -55
- data/spec/fortnox/api/types/examples/types.rb +0 -11
- data/spec/fortnox/api/types/housework_types_spec.rb +0 -149
- data/spec/fortnox/api/types/invoice_row_spec.rb +0 -11
- data/spec/fortnox/api/types/model_spec.rb +0 -69
- data/spec/fortnox/api/types/nullable_spec.rb +0 -79
- data/spec/fortnox/api/types/order_row_spec.rb +0 -15
- data/spec/fortnox/api/types/required_spec.rb +0 -36
- data/spec/fortnox/api/types/sales_account_spec.rb +0 -57
- data/spec/fortnox/api/types/sized_spec.rb +0 -76
- data/spec/fortnox/api_spec.rb +0 -66
- data/spec/spec_helper.rb +0 -35
- data/spec/support/helpers/configuration_helper.rb +0 -39
- data/spec/support/helpers/repository_helper.rb +0 -10
- data/spec/support/helpers.rb +0 -3
- data/spec/support/matchers/type/attribute_matcher.rb +0 -40
- data/spec/support/matchers/type/enum_matcher.rb +0 -23
- data/spec/support/matchers/type/have_account_number_matcher.rb +0 -23
- data/spec/support/matchers/type/have_currency_matcher.rb +0 -9
- data/spec/support/matchers/type/have_customer_type_matcher.rb +0 -15
- data/spec/support/matchers/type/have_default_delivery_type_matcher.rb +0 -9
- data/spec/support/matchers/type/have_discount_type_matcher.rb +0 -9
- data/spec/support/matchers/type/have_email_matcher.rb +0 -24
- data/spec/support/matchers/type/have_housework_type_matcher.rb +0 -9
- data/spec/support/matchers/type/have_nullable_date_matcher.rb +0 -60
- data/spec/support/matchers/type/have_nullable_matcher.rb +0 -54
- data/spec/support/matchers/type/have_nullable_string_matcher.rb +0 -47
- data/spec/support/matchers/type/have_sized_float_matcher.rb +0 -10
- data/spec/support/matchers/type/have_sized_integer_matcher.rb +0 -10
- data/spec/support/matchers/type/have_sized_string_matcher.rb +0 -36
- data/spec/support/matchers/type/have_vat_type_matcher.rb +0 -9
- data/spec/support/matchers/type/numeric_matcher.rb +0 -52
- data/spec/support/matchers/type/require_attribute_matcher.rb +0 -68
- data/spec/support/matchers/type/type_matcher.rb +0 -40
- data/spec/support/matchers/type.rb +0 -19
- data/spec/support/matchers.rb +0 -3
- data/spec/support/vcr_setup.rb +0 -25
- data/spec/vcr_cassettes/articles/all.yml +0 -67
- data/spec/vcr_cassettes/articles/find_by_hash_failure.yml +0 -62
- data/spec/vcr_cassettes/articles/find_failure.yml +0 -62
- data/spec/vcr_cassettes/articles/find_id_1.yml +0 -63
- data/spec/vcr_cassettes/articles/find_new.yml +0 -63
- data/spec/vcr_cassettes/articles/limits/quantity_in_stock_min_value.yml +0 -63
- data/spec/vcr_cassettes/articles/limits/quantity_in_stock_rounding_positive_value.yml +0 -63
- data/spec/vcr_cassettes/articles/multi_param_find_by_hash.yml +0 -62
- data/spec/vcr_cassettes/articles/save_new.yml +0 -63
- data/spec/vcr_cassettes/articles/save_old.yml +0 -63
- data/spec/vcr_cassettes/articles/save_with_specially_named_attribute.yml +0 -63
- data/spec/vcr_cassettes/articles/search_by_name.yml +0 -65
- data/spec/vcr_cassettes/articles/search_miss.yml +0 -62
- data/spec/vcr_cassettes/articles/search_with_special_char.yml +0 -62
- data/spec/vcr_cassettes/articles/single_param_find_by_hash.yml +0 -62
- data/spec/vcr_cassettes/authentication/expired_token.yml +0 -54
- data/spec/vcr_cassettes/authentication/invalid_authorization.yml +0 -57
- data/spec/vcr_cassettes/authentication/invalid_refresh_token.yml +0 -58
- data/spec/vcr_cassettes/authentication/valid_request.yml +0 -63
- data/spec/vcr_cassettes/customers/all.yml +0 -69
- data/spec/vcr_cassettes/customers/find_by_hash_failure.yml +0 -62
- data/spec/vcr_cassettes/customers/find_failure.yml +0 -62
- data/spec/vcr_cassettes/customers/find_id_1.yml +0 -64
- data/spec/vcr_cassettes/customers/find_new.yml +0 -63
- data/spec/vcr_cassettes/customers/find_with_sales_account.yml +0 -63
- data/spec/vcr_cassettes/customers/multi_param_find_by_hash.yml +0 -63
- data/spec/vcr_cassettes/customers/save_new.yml +0 -63
- data/spec/vcr_cassettes/customers/save_new_with_country_code_SE.yml +0 -64
- data/spec/vcr_cassettes/customers/save_new_with_idn_email.yml +0 -67
- data/spec/vcr_cassettes/customers/save_new_with_sales_account.yml +0 -63
- data/spec/vcr_cassettes/customers/save_old.yml +0 -63
- data/spec/vcr_cassettes/customers/save_with_specially_named_attribute.yml +0 -63
- data/spec/vcr_cassettes/customers/search_by_name.yml +0 -64
- data/spec/vcr_cassettes/customers/search_miss.yml +0 -62
- data/spec/vcr_cassettes/customers/search_with_special_char.yml +0 -62
- data/spec/vcr_cassettes/customers/single_param_find_by_hash.yml +0 -64
- data/spec/vcr_cassettes/invoices/all.yml +0 -96
- data/spec/vcr_cassettes/invoices/filter_hit.yml +0 -64
- data/spec/vcr_cassettes/invoices/filter_invalid.yml +0 -60
- data/spec/vcr_cassettes/invoices/find_by_hash_failure.yml +0 -62
- data/spec/vcr_cassettes/invoices/find_failure.yml +0 -62
- data/spec/vcr_cassettes/invoices/find_id_1.yml +0 -65
- data/spec/vcr_cassettes/invoices/find_new.yml +0 -65
- data/spec/vcr_cassettes/invoices/multi_param_find_by_hash.yml +0 -63
- data/spec/vcr_cassettes/invoices/row_delivered_quantity_decimals.yml +0 -65
- data/spec/vcr_cassettes/invoices/row_delivered_quantity_decimals_round_up.yml +0 -65
- data/spec/vcr_cassettes/invoices/row_description_limit.yml +0 -65
- data/spec/vcr_cassettes/invoices/row_price_limit.yml +0 -65
- data/spec/vcr_cassettes/invoices/row_price_limit_round_up.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_comments.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_country.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_country_GB.yml +0 -66
- data/spec/vcr_cassettes/invoices/save_new_with_country_Norge.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_country_Norway.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_country_Sverige.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_country_VA.yml +0 -66
- data/spec/vcr_cassettes/invoices/save_new_with_country_VI.yml +0 -66
- data/spec/vcr_cassettes/invoices/save_new_with_country_empty_string.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_country_nil.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_new_with_unsaved_parent.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_old.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_old_with_empty_comments.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_old_with_empty_country.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_old_with_nil_comments.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_old_with_nil_country.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_with_nested_model.yml +0 -65
- data/spec/vcr_cassettes/invoices/save_with_specially_named_attribute.yml +0 -65
- data/spec/vcr_cassettes/invoices/search_by_name.yml +0 -63
- data/spec/vcr_cassettes/invoices/search_miss.yml +0 -62
- data/spec/vcr_cassettes/invoices/search_with_special_char.yml +0 -62
- data/spec/vcr_cassettes/invoices/single_param_find_by_hash.yml +0 -64
- data/spec/vcr_cassettes/orders/all.yml +0 -69
- data/spec/vcr_cassettes/orders/filter_hit.yml +0 -64
- data/spec/vcr_cassettes/orders/filter_invalid.yml +0 -60
- data/spec/vcr_cassettes/orders/find_by_hash_failure.yml +0 -62
- data/spec/vcr_cassettes/orders/find_failure.yml +0 -62
- data/spec/vcr_cassettes/orders/find_id_1.yml +0 -67
- data/spec/vcr_cassettes/orders/find_new.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_invalid_tax_reduction_type.yml +0 -61
- data/spec/vcr_cassettes/orders/housework_othercoses_invalid.yml +0 -61
- data/spec/vcr_cassettes/orders/housework_type_babysitting.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_cleaning.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_construction.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_cooking.yml +0 -61
- data/spec/vcr_cassettes/orders/housework_type_electricity.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_gardening.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_glassmetalwork.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_grounddrainagework.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_hvac.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_itservices.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_majorappliancerepair.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_masonry.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_movingservices.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_othercare.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_othercosts.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_paintingwallpapering.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_snowplowing.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_textileclothing.yml +0 -65
- data/spec/vcr_cassettes/orders/housework_type_tutoring.yml +0 -61
- data/spec/vcr_cassettes/orders/multi_param_find_by_hash.yml +0 -63
- data/spec/vcr_cassettes/orders/save_new.yml +0 -65
- data/spec/vcr_cassettes/orders/save_old.yml +0 -65
- data/spec/vcr_cassettes/orders/save_with_nested_model.yml +0 -65
- data/spec/vcr_cassettes/orders/search_by_name.yml +0 -63
- data/spec/vcr_cassettes/orders/search_miss.yml +0 -62
- data/spec/vcr_cassettes/orders/search_with_special_char.yml +0 -62
- data/spec/vcr_cassettes/orders/single_param_find_by_hash.yml +0 -64
- data/spec/vcr_cassettes/projects/all.yml +0 -64
- data/spec/vcr_cassettes/projects/find_by_hash_failure.yml +0 -62
- data/spec/vcr_cassettes/projects/find_failure.yml +0 -62
- data/spec/vcr_cassettes/projects/find_id_1.yml +0 -63
- data/spec/vcr_cassettes/projects/find_new.yml +0 -63
- data/spec/vcr_cassettes/projects/multi_param_find_by_hash.yml +0 -64
- data/spec/vcr_cassettes/projects/save_new.yml +0 -63
- data/spec/vcr_cassettes/projects/save_old.yml +0 -63
- data/spec/vcr_cassettes/projects/single_param_find_by_hash.yml +0 -63
- data/spec/vcr_cassettes/termsofpayments/all.yml +0 -68
- data/spec/vcr_cassettes/termsofpayments/find_failure.yml +0 -62
- data/spec/vcr_cassettes/termsofpayments/find_id_1.yml +0 -62
- data/spec/vcr_cassettes/termsofpayments/find_new.yml +0 -63
- data/spec/vcr_cassettes/termsofpayments/save_new.yml +0 -63
- data/spec/vcr_cassettes/termsofpayments/save_old.yml +0 -63
- data/spec/vcr_cassettes/units/all.yml +0 -64
- data/spec/vcr_cassettes/units/find_failure.yml +0 -62
- data/spec/vcr_cassettes/units/find_id_1.yml +0 -63
- data/spec/vcr_cassettes/units/find_new.yml +0 -63
- data/spec/vcr_cassettes/units/save_new.yml +0 -63
- data/spec/vcr_cassettes/units/save_old.yml +0 -63
- data/spec/vcr_cassettes/units/save_with_specially_named_attribute.yml +0 -63
data/README.md
CHANGED
|
@@ -1,355 +1,341 @@
|
|
|
1
|
-
#
|
|
1
|
+
# fortnox-api
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
PRs of your own 😃
|
|
3
|
+
Ruby gem for Fortnox's version 3 REST API, built on
|
|
4
|
+
[rest-easy](https://github.com/accodeing/rest-easy). If you need to integrate an existing or new Ruby
|
|
5
|
+
or Rails app against Fortnox this gem will save you a lot of time.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
Feel free to repay the community with some nice PRs of your own.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
[](https://app.travis-ci.com/github/accodeing/fortnox-api)
|
|
9
|
+
## Supported resources
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
Article, Customer, Invoice, Label, Order, Project, TermsOfPayment, Unit
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
[
|
|
17
|
-
[](https://codeclimate.com/github/accodeing/fortnox-api/test_coverage)
|
|
13
|
+
Adding more resources is quick and easy, see the
|
|
14
|
+
[Contributing](#contributing) section.
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
## Status
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- We have ideas for more advanced features, like sorting entities, pagination of
|
|
27
|
-
results but it's not implemented...
|
|
28
|
-
- A few models implemented. Right now we pretty good support for `Customer`,
|
|
29
|
-
`Invoice`, `Order`, `Article`, `Label` and `Project`. Adding more models in
|
|
30
|
-
general is quick and easy (that's the whole point with this gem), see the
|
|
31
|
-
developer guide further down.
|
|
18
|
+
Version 1.0 is a complete rewrite, currently in release candidate
|
|
19
|
+
(`1.0.0.rc1`). It is built on
|
|
20
|
+
[rest-easy](https://github.com/accodeing/rest-easy), replacing the old
|
|
21
|
+
HTTParty + Data Mapper architecture with a single resource class per entity.
|
|
22
|
+
Authorization uses the Fortnox client credentials flow.
|
|
32
23
|
|
|
33
|
-
|
|
24
|
+
## Migrating from 0.x
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
and saving state. These are called: model, type, mapper and repository.
|
|
26
|
+
See the [Migration guide](MIGRATING_TO_1.0.md).
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
structuring the solution to the CRUD problem this might seem strange to you
|
|
40
|
-
since ActiveRecord merges these roles into the `ActiveRecord::Base` class.
|
|
28
|
+
## Architecture overview
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
into active record like classes than to separate active records parts to get a
|
|
48
|
-
data mapper style structure.
|
|
30
|
+
The gem uses the [rest-easy](https://github.com/accodeing/rest-easy) framework to map between Ruby
|
|
31
|
+
objects and the Fortnox JSON API. Each resource is a class that declares its
|
|
32
|
+
attributes with types and constraints. rest-easy handles the HTTP requests,
|
|
33
|
+
JSON serialisation, and attribute convention mapping (PascalCase in the API,
|
|
34
|
+
snake_case in Ruby).
|
|
49
35
|
|
|
50
|
-
|
|
51
|
-
the two architectures you can read this post that explains it well using simple
|
|
52
|
-
examples:
|
|
53
|
-
[What’s the difference between Active Record and Data Mapper?](http://culttt.com/2014/06/18/whats-difference-active-record-data-mapper/)
|
|
36
|
+
### Immutability
|
|
54
37
|
|
|
55
|
-
|
|
38
|
+
The model instances are immutable. That means:
|
|
56
39
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
40
|
+
```ruby
|
|
41
|
+
customer.model.name # => "Old Name"
|
|
42
|
+
customer.model.name = 'New Name' # => NoMethodError
|
|
43
|
+
```
|
|
60
44
|
|
|
61
|
-
|
|
45
|
+
Any operation that updates state returns a new instance with the updated
|
|
46
|
+
attributes while leaving the old instance alone:
|
|
62
47
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
```ruby
|
|
49
|
+
customer.model.name # => "Old Name"
|
|
50
|
+
updated_customer = customer.update(name: 'New Name')
|
|
51
|
+
updated_customer.model.name # => "New Name"
|
|
52
|
+
customer.model.name # => "Old Name"
|
|
53
|
+
```
|
|
67
54
|
|
|
68
|
-
|
|
55
|
+
This is how all resources work, they are all immutable.
|
|
69
56
|
|
|
70
|
-
|
|
57
|
+
### Types
|
|
71
58
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
59
|
+
Types automatically enforce constraints on values, lengths and, in some cases,
|
|
60
|
+
content of the resource attributes. Types force your data to be correct before
|
|
61
|
+
sending it to the API, which saves you API calls and time debugging. You can
|
|
62
|
+
still get errors from the server; our implementation is not perfect. Also,
|
|
63
|
+
Fortnox sometimes requires a specific combination of attributes.
|
|
75
64
|
|
|
76
|
-
|
|
77
|
-
```
|
|
65
|
+
#### Exceptions
|
|
78
66
|
|
|
79
|
-
|
|
80
|
-
`name` field. Immutability explicitly means that you can't mutate state this
|
|
81
|
-
way, any operation that attempts to update state needs to return a new instance
|
|
82
|
-
with the updated state while leaving the old instance alone.
|
|
67
|
+
The gem raises the following exceptions:
|
|
83
68
|
|
|
84
|
-
|
|
69
|
+
- `Fortnox::Error` — base class for everything below. Rescue this to catch
|
|
70
|
+
any error raised by the gem.
|
|
71
|
+
- `Fortnox::RequestError` — 4xx/5xx responses from the Fortnox API. Carries
|
|
72
|
+
the response object as `.response`.
|
|
73
|
+
- `Fortnox::AttributeError` — base for attribute validation failures.
|
|
74
|
+
- `Fortnox::ConstraintError` — an attribute value violates a type
|
|
75
|
+
constraint (max size, format, etc.). Carries `.attribute_name` and
|
|
76
|
+
`.value`.
|
|
77
|
+
- `Fortnox::MissingAttributeError` — a required attribute is missing
|
|
78
|
+
from an API response. Carries `.attribute_name`.
|
|
79
|
+
- `Fortnox::MissingAccessToken` — `Fortnox.access_token=` was not called
|
|
80
|
+
on the current thread before an API call.
|
|
85
81
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
## Requirements
|
|
83
|
+
|
|
84
|
+
Ruby 3.1 or higher.
|
|
85
|
+
|
|
86
|
+
### Installation
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
does not work. The result of any assignment, `LHS = RHS`, operation in Ruby is
|
|
92
|
-
`RHS`. Even if you implement your own `=` method and explicitly return something
|
|
93
|
-
else. This is a feature of the language and not something we can get around. So
|
|
94
|
-
instead you have to do:
|
|
88
|
+
Add this line to your application's Gemfile:
|
|
95
89
|
|
|
96
90
|
```ruby
|
|
97
|
-
|
|
98
|
-
updated_customer = customer.update( name: 'New Name' ) # => <Fortnox::API::Model::Customer:0x007fdf22949298 ... >
|
|
99
|
-
updated_customer.name == "New Name" # => true
|
|
91
|
+
gem 'fortnox-api'
|
|
100
92
|
```
|
|
101
93
|
|
|
102
|
-
And
|
|
94
|
+
And then execute:
|
|
103
95
|
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
customer.update( name: 'New Name' ) # => <Fortnox::API::Model::Customer:0x007fdf21100b00 ... >
|
|
107
|
-
customer.name == "New Name" # => false
|
|
96
|
+
```shell
|
|
97
|
+
bundle install
|
|
108
98
|
```
|
|
109
99
|
|
|
110
|
-
|
|
100
|
+
## Authorization
|
|
111
101
|
|
|
112
|
-
|
|
102
|
+
Fortnox uses OAuth2 for authorization. This gem supports the **client
|
|
103
|
+
credentials** flow, which is the recommended way to authenticate server-to-server
|
|
104
|
+
integrations. The older refresh token flow is no longer supported. Read more
|
|
105
|
+
about this change in the
|
|
106
|
+
[Fortnox blog post](https://www.fortnox.se/developer/blog/say-goodbye-to-refresh-tokens-).
|
|
113
107
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
attribute is missing.
|
|
108
|
+
With client credentials you can request a new access token at any time using
|
|
109
|
+
three pieces of information: your **client ID**, **client secret**, and the
|
|
110
|
+
**tenant ID** of the Fortnox account you are integrating with.
|
|
118
111
|
|
|
119
|
-
|
|
112
|
+
### Prerequisites
|
|
120
113
|
|
|
121
|
-
|
|
122
|
-
cases, content of the model attributes. Types forces your models to be correct
|
|
123
|
-
before sending data to the API, which saves you a lot of API calls and rescuing
|
|
124
|
-
the exception we throw when we get a 4xx/5xx response from the server (you can
|
|
125
|
-
still get errors from the server; our implementation is not perfect. Also,
|
|
126
|
-
Fortnox sometimes requires a specific combination of attributes).
|
|
114
|
+
You need:
|
|
127
115
|
|
|
128
|
-
|
|
116
|
+
- A Fortnox developer account
|
|
117
|
+
([register here](https://developer.fortnox.se/getting-started/))
|
|
118
|
+
- A Fortnox app in the developer portal with:
|
|
119
|
+
- Service account setting enabled
|
|
120
|
+
- Correct scopes configured
|
|
121
|
+
- A redirect URL
|
|
122
|
+
- A Fortnox test environment for testing your integration
|
|
129
123
|
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
Read the
|
|
125
|
+
[Fortnox getting started guide](https://developer.fortnox.se/getting-started/)
|
|
126
|
+
and
|
|
127
|
+
[authorization documentation](https://www.fortnox.se/developer/authorization/get-access-token-using-client-credentials)
|
|
128
|
+
for more details.
|
|
132
129
|
|
|
133
|
-
###
|
|
130
|
+
### Initial setup
|
|
134
131
|
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
Before you can use client credentials you need to perform a one-time
|
|
133
|
+
authorization code exchange. This grants your app access to a specific Fortnox
|
|
134
|
+
account and gives you the **tenant ID** you need for all future token requests.
|
|
137
135
|
|
|
138
|
-
|
|
136
|
+
This gem includes an executable to help with this:
|
|
139
137
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
will not need to use them directly.
|
|
138
|
+
```shell
|
|
139
|
+
fortnox-setup
|
|
140
|
+
```
|
|
144
141
|
|
|
145
|
-
|
|
142
|
+
The script will:
|
|
146
143
|
|
|
147
|
-
|
|
148
|
-
|
|
144
|
+
1. Ask for your client ID, client secret, and scopes
|
|
145
|
+
2. Offer to use a local server on `http://localhost:4242` to catch the
|
|
146
|
+
authorization response automatically. If you choose this, set your Fortnox
|
|
147
|
+
app's redirect URL to `http://localhost:4242`. Otherwise, enter your existing
|
|
148
|
+
redirect URL and paste the authorization code manually.
|
|
149
|
+
3. Open your browser to the Fortnox authorization page
|
|
150
|
+
4. You log in to Fortnox and grant your app access
|
|
151
|
+
5. The script exchanges the authorization code for an access token and extracts
|
|
152
|
+
the tenant ID from the JWT
|
|
153
|
+
6. The tenant ID is printed for you to store in your application's configuration
|
|
149
154
|
|
|
150
|
-
|
|
155
|
+
After this you have a tenant ID and never need to run this script again (unless
|
|
156
|
+
you need to authorize against a different Fortnox account).
|
|
151
157
|
|
|
152
|
-
|
|
158
|
+
### Requesting access tokens
|
|
159
|
+
|
|
160
|
+
Once you have a tenant ID, you can request access tokens programmatically.
|
|
161
|
+
Access tokens expire after 1 hour, but you can request a new one at any time:
|
|
153
162
|
|
|
154
163
|
```ruby
|
|
155
|
-
|
|
156
|
-
```
|
|
164
|
+
require 'fortnox'
|
|
157
165
|
|
|
158
|
-
|
|
166
|
+
token = Fortnox.request_access_token(
|
|
167
|
+
client_id: 'your-client-id',
|
|
168
|
+
client_secret: 'your-client-secret',
|
|
169
|
+
tenant_id: 'your-tenant-id'
|
|
170
|
+
)
|
|
159
171
|
|
|
160
|
-
|
|
161
|
-
$ bundle
|
|
172
|
+
Fortnox.access_token = token
|
|
162
173
|
```
|
|
163
174
|
|
|
164
|
-
|
|
175
|
+
It is up to you to manage the token lifecycle in your application. A common
|
|
176
|
+
approach is to request a new token before each batch of API calls, or to cache
|
|
177
|
+
the token and refresh it when it expires.
|
|
178
|
+
|
|
179
|
+
### Updating access tokens in env files
|
|
180
|
+
|
|
181
|
+
For development and testing, the gem includes an executable that reads your
|
|
182
|
+
credentials from an env file, requests a new access token, and writes it back:
|
|
165
183
|
|
|
166
184
|
```shell
|
|
167
|
-
|
|
185
|
+
fortnox-update-env # reads/writes .env
|
|
186
|
+
fortnox-update-env .env.local # reads/writes a specific file
|
|
168
187
|
```
|
|
169
188
|
|
|
170
|
-
|
|
189
|
+
See [.env.test.local.template](.env.test.local.template) for the required
|
|
190
|
+
variables.
|
|
171
191
|
|
|
172
|
-
|
|
192
|
+
### Multiple Fortnox accounts
|
|
173
193
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
> the old way of authorization from v0.9.0.
|
|
194
|
+
The access token is stored per thread, so concurrent threads — Sidekiq
|
|
195
|
+
workers, Puma threads, etc. — can use different tokens without leaking to
|
|
196
|
+
each other. Each thread must set its own token before making API calls.
|
|
178
197
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
integration to Fortnox, not build a public app to in the marketplace". Yeah, we
|
|
182
|
-
agree... You don't need to release the app on the Fortnox Marketplace, but you
|
|
183
|
-
need that Fortnox app. Also, see further Fortnox app requirements down below.
|
|
198
|
+
Within a single thread you can switch tokens between calls. Each call uses
|
|
199
|
+
the token currently set on the calling thread:
|
|
184
200
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
bundled with this gem to help you getting started, see
|
|
189
|
-
[Initialization](#initialization). Also read
|
|
190
|
-
[Authorizing your integration](https://developer.fortnox.se/general/authentication/).
|
|
201
|
+
```ruby
|
|
202
|
+
Fortnox.access_token = 'account1_token'
|
|
203
|
+
Fortnox::Customer.all
|
|
191
204
|
|
|
192
|
-
|
|
205
|
+
Fortnox.access_token = 'account2_token'
|
|
206
|
+
Fortnox::Customer.all
|
|
207
|
+
```
|
|
193
208
|
|
|
194
|
-
|
|
195
|
-
- A Fortnox app with:
|
|
196
|
-
- Service account setting enabled (it's used in server to server integrations,
|
|
197
|
-
which this is)
|
|
198
|
-
- Correct scopes set
|
|
199
|
-
- A redirect URL (just use a dummy URL if you want to, you just need the
|
|
200
|
-
parameters send to that URL)
|
|
201
|
-
- A Fortnox test environment so that you can test your integration.
|
|
202
|
-
|
|
203
|
-
When you have authorized your integration you get an access token from Fortnox.
|
|
204
|
-
It's a JWT with a expiration time (currently **1 hour**). You also get a long
|
|
205
|
-
lived refresh token (currently lasts for **45 days** ). When you need a new
|
|
206
|
-
access token you send a renewal request to Fortnox. That request contains the
|
|
207
|
-
new access token as well as a new refresh token and some other data. Note that
|
|
208
|
-
**the old refresh token is invalidated when new tokens are requested**. As long
|
|
209
|
-
as you have a valid refresh token you will be available to request new tokens.
|
|
210
|
-
|
|
211
|
-
The gem exposes a specific repository for renewing tokens. You use it like this:
|
|
209
|
+
## Usage
|
|
212
210
|
|
|
213
|
-
|
|
214
|
-
require 'fortnox/api'
|
|
211
|
+
Set the access token before making any API calls:
|
|
215
212
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
client_id: "the integration's client id",
|
|
219
|
-
client_secret: "the integration's client secret"
|
|
220
|
-
)
|
|
213
|
+
```ruby
|
|
214
|
+
require 'fortnox'
|
|
221
215
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
store_access_token(tokens[:access_token])
|
|
216
|
+
Fortnox.access_token = 'your-access-token'
|
|
217
|
+
```
|
|
225
218
|
|
|
226
|
-
|
|
227
|
-
Fortnox::API.access_token = tokens[:access_token]
|
|
219
|
+
### Listing all records
|
|
228
220
|
|
|
229
|
-
|
|
230
|
-
Fortnox::
|
|
221
|
+
```ruby
|
|
222
|
+
Fortnox::Customer.all
|
|
231
223
|
```
|
|
232
224
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
## Get tokens
|
|
225
|
+
`.all`, `.search`, `.only`, and `.find(hash)` return a `Fortnox::Collection`
|
|
226
|
+
— an iterable wrapper that also exposes the pagination metadata Fortnox
|
|
227
|
+
returns alongside collection responses:
|
|
238
228
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
229
|
+
```ruby
|
|
230
|
+
customers = Fortnox::Customer.all
|
|
231
|
+
customers.first.model.name # => "Acme Corp"
|
|
232
|
+
customers.size # => 50
|
|
233
|
+
customers.total # => 327
|
|
234
|
+
customers.pages # => 7
|
|
235
|
+
customers.current_page # => 1
|
|
236
|
+
```
|
|
242
237
|
|
|
243
|
-
|
|
238
|
+
`Collection` is `Enumerable`, so `.each`, `.map`, `.select`, `.first`, etc.
|
|
239
|
+
all work as expected.
|
|
244
240
|
|
|
245
|
-
|
|
246
|
-
|
|
241
|
+
Fortnox's collection endpoints return fewer attributes per record than
|
|
242
|
+
single-resource endpoints, so instances from a `Collection` are flagged as
|
|
243
|
+
partial. Check `instance.meta.partial?` and re-fetch via `find(id)` if you
|
|
244
|
+
need the full record:
|
|
247
245
|
|
|
248
246
|
```ruby
|
|
249
|
-
Fortnox::
|
|
250
|
-
|
|
251
|
-
|
|
247
|
+
customers = Fortnox::Customer.all
|
|
248
|
+
customers.first.meta.partial? # => true
|
|
249
|
+
Fortnox::Customer.find(1).meta.partial? # => false
|
|
252
250
|
```
|
|
253
251
|
|
|
254
|
-
|
|
255
|
-
| ----------- | --------------------------------- | -------- | --------------------------------------------------------------- |
|
|
256
|
-
| `base_url` | The base url to Fortnox API | No | `'https://api.fortnox.se/3/'` |
|
|
257
|
-
| `token_url` | The url to Fortnox token endpoint | No | `'https://apps.fortnox.se/oauth-v1/token'` |
|
|
258
|
-
| `debugging` | For debugging | No | `false` |
|
|
259
|
-
| `logger` | The logger to use | No | A simple logger that writes to `$stdout` with log level `WARN`. |
|
|
252
|
+
### Finding a record
|
|
260
253
|
|
|
261
|
-
|
|
254
|
+
```ruby
|
|
255
|
+
# By ID
|
|
256
|
+
customer = Fortnox::Customer.find(1)
|
|
262
257
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
258
|
+
# By query parameters (pagination, limits, etc.)
|
|
259
|
+
customers = Fortnox::Customer.find(limit: 10, offset: 0)
|
|
260
|
+
```
|
|
266
261
|
|
|
267
|
-
|
|
268
|
-
|
|
262
|
+
Note that `find` supports a hash as an argument, which adds the given keys as
|
|
263
|
+
HTTP parameters to the call. This lets you use limits, offsets, and pagination.
|
|
264
|
+
See the
|
|
265
|
+
[Fortnox documentation](https://developer.fortnox.se/general/parameters/)
|
|
266
|
+
for available parameters.
|
|
269
267
|
|
|
270
|
-
|
|
271
|
-
repository.all # Calls account1
|
|
268
|
+
The returned object wraps the model. Access attributes through `.model`:
|
|
272
269
|
|
|
273
|
-
|
|
274
|
-
|
|
270
|
+
```ruby
|
|
271
|
+
customer = Fortnox::Customer.find(1)
|
|
272
|
+
customer.model.name # => "Acme Corp"
|
|
273
|
+
customer.model.city # => "Stockholm"
|
|
274
|
+
customer.unique_id # => "1"
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
###
|
|
277
|
+
### Creating a record
|
|
278
278
|
|
|
279
|
-
|
|
280
|
-
[adjustments to the rate limit](https://developer.fortnox.se/blog/adjustments-to-the-rate-limit/)
|
|
281
|
-
and it is no longer calculated per access token (if you are not using the old
|
|
282
|
-
auth flow, but that flow is deprecated in this gem since v0.9.0).
|
|
279
|
+
Use `.stub` to build a new instance and `.save` to persist it:
|
|
283
280
|
|
|
284
|
-
|
|
281
|
+
```ruby
|
|
282
|
+
customer = Fortnox::Customer.stub(name: 'Acme Corp', city: 'Stockholm')
|
|
283
|
+
result = Fortnox::Customer.save(customer)
|
|
284
|
+
result.model.customer_number # => "1"
|
|
285
|
+
```
|
|
285
286
|
|
|
286
|
-
|
|
287
|
+
### Updating a record
|
|
287
288
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
rescue appropriate network errors in your code.
|
|
289
|
+
Fetch, update, and save. Models are immutable, so `.update` returns a new
|
|
290
|
+
instance:
|
|
291
291
|
|
|
292
292
|
```ruby
|
|
293
|
-
|
|
293
|
+
customer = Fortnox::Customer.find(1)
|
|
294
|
+
updated = customer.update(name: 'Acme Inc')
|
|
295
|
+
Fortnox::Customer.save(updated)
|
|
296
|
+
```
|
|
294
297
|
|
|
295
|
-
|
|
298
|
+
### Searching
|
|
296
299
|
|
|
297
|
-
|
|
298
|
-
|
|
300
|
+
```ruby
|
|
301
|
+
Fortnox::Customer.search(name: 'Acme')
|
|
302
|
+
```
|
|
299
303
|
|
|
300
|
-
|
|
301
|
-
repo.all #=> <Fortnox::API::Collection:0x007fdf2104575638 @entities: [<Fortnox::API::Customer::Simple:0x007fdf21033ee8>, <Fortnox::API::Customer::Simple:0x007fdf22994310>, ... ]
|
|
304
|
+
### Filtering
|
|
302
305
|
|
|
303
|
-
|
|
304
|
-
repo.find( 5 ) #=> <Fortnox::API::Model::Customer:0x007fdf21100b00>
|
|
306
|
+
Some resources support server-side filters:
|
|
305
307
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
+
```ruby
|
|
309
|
+
Fortnox::Invoice.only('unpaid')
|
|
308
310
|
```
|
|
309
311
|
|
|
310
|
-
|
|
311
|
-
entities returned in a collection vs the one we get from find. The simple
|
|
312
|
-
version of a class is used in thouse cases where the API-server doesn't return a
|
|
313
|
-
full set of attributes for an entity. For customers the simple version has 10
|
|
314
|
-
attributes while the full have over 40.
|
|
312
|
+
### Gotchas
|
|
315
313
|
|
|
316
|
-
|
|
314
|
+
See [docs/gotchas.md](docs/gotchas.md) for known quirks and edge cases in the
|
|
315
|
+
Fortnox API.
|
|
317
316
|
|
|
318
|
-
|
|
319
|
-
hash keys as HTTP parameters to the call. This will let you search, sort, use
|
|
320
|
-
limits and offsets as well as do pagination. See
|
|
321
|
-
[Fortnox documentation](https://developer.fortnox.se/general/parameters/) for
|
|
322
|
-
more information about available parameters.
|
|
317
|
+
### Resources
|
|
323
318
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
```
|
|
319
|
+
Each resource maps to a Fortnox API endpoint. Attributes are typed and
|
|
320
|
+
validated before sending data to the API. Read-only attributes (like `url`)
|
|
321
|
+
cannot be set when creating or updating records.
|
|
328
322
|
|
|
329
|
-
|
|
323
|
+
Resources that share structure inherit from a common base. For example,
|
|
324
|
+
`Invoice` and `Order` both extend `Document`, which defines shared attributes
|
|
325
|
+
like administration fee, delivery address, and row items.
|
|
330
326
|
|
|
331
|
-
|
|
332
|
-
resource class such as customer, invoice, item, voucher and so on.
|
|
327
|
+
## Changelog
|
|
333
328
|
|
|
334
|
-
|
|
335
|
-
appropriate attributes changed (see the Immutable section under Architecture
|
|
336
|
-
above for more details). To change the properties of a model works like this:
|
|
329
|
+
See the [Changelog](CHANGELOG.md).
|
|
337
330
|
|
|
338
|
-
|
|
339
|
-
require 'fortnox/api'
|
|
331
|
+
## Development
|
|
340
332
|
|
|
341
|
-
|
|
342
|
-
customer.name #=> "Nelly Bloom"
|
|
343
|
-
customer.update( name: "Ned Stark" ) #=> <Fortnox::API::Model::Customer:0x0193a456ff0307>
|
|
344
|
-
customer.name #=> "Nelly Bloom"
|
|
333
|
+
See the [Developer readme](DEVELOPER_README.md).
|
|
345
334
|
|
|
346
|
-
|
|
347
|
-
updated_customer.name #=> "Ned Stark"
|
|
348
|
-
```
|
|
335
|
+
## Contributing
|
|
349
336
|
|
|
350
|
-
|
|
351
|
-
update as many as you like in one go.
|
|
337
|
+
See the [Contribute readme](CONTRIBUTE.md).
|
|
352
338
|
|
|
353
|
-
|
|
339
|
+
## License
|
|
354
340
|
|
|
355
|
-
|
|
341
|
+
[LGPL-3.0](LICENSE.md). Copyright (c) 2015-2026 Accodeing to you KB.
|