Class: Taxes::GetTaxRate
- Inherits:
-
BaseService
- Object
- BaseService
- Taxes::GetTaxRate
- Defined in:
- app/services/taxes/get_tax_rate.rb
Defined Under Namespace
Classes: Result
Constant Summary collapse
- TAXABLE_STATES_SOURCE_TAXJAR =
TAXABLE_STATES.select{|k,v| v[:source] == :taxjar}.keys.map(&:to_s).freeze
- TAXABLE_STATES_SOURCE_INTERNAL =
TAXABLE_STATES.select{|k,v| v[:source] == :internal}.keys.map(&:to_s).freeze
Instance Method Summary collapse
-
#process(effective_date: Date.current, to_street: nil, to_city: nil, to_state: nil, to_zip: nil, to_country:, from_street: nil, from_city: nil, from_state: nil, from_zip: nil, from_country: nil, line_items: nil, freight_charged: nil) ⇒ Object
You can call this method without line items for just a rate dip or with line items and freight charged for a detail breakdown Line items is optional but needs this info line_items: {:line_items => [ { :id => '1', :quantity => 1, :product_tax_code => '20010', :unit_price => 15, :discount => 0 } ]} # See https://developers.taxjar.com/api/reference/#post-calculate-sales-tax-for-an-order.
Instance Method Details
#process(effective_date: Date.current, to_street: nil, to_city: nil, to_state: nil, to_zip: nil, to_country:, from_street: nil, from_city: nil, from_state: nil, from_zip: nil, from_country: nil, line_items: nil, freight_charged: nil) ⇒ Object
You can call this method without line items for just a rate dip or with line items and freight charged
for a detail breakdown
Line items is optional but needs this info
line_items: {:line_items => [
{
:id => '1',
:quantity => 1,
:product_tax_code => '20010',
:unit_price => 15,
:discount => 0
}
]}
See https://developers.taxjar.com/api/reference/#post-calculate-sales-tax-for-an-order
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'app/services/taxes/get_tax_rate.rb', line 25 def process(effective_date: Date.current, to_street: nil, to_city: nil, to_state: nil, to_zip: nil, to_country:, from_street: nil, from_city: nil, from_state: nil, from_zip: nil, from_country: nil, line_items: nil, freight_charged: nil) if from_country.in?(%w(US CA)) # Try a rate pull from our table if from_country == to_country if TAXABLE_STATES_SOURCE_INTERNAL.include?(to_state) && (tax_rate = TaxRate.effective_on(effective_date).find_by(country_iso: to_country, state_code: to_state)) # pull the rate from internal tax_rates table Result.new( rate_goods: tax_rate.goods, rate_services: tax_rate.services, rate_shipping: tax_rate.shipping, source: 'internal', tax_rate_id: tax_rate.id, retrieved_on: Date.current, tax_type: tax_rate.tax_type, country_iso: tax_rate.country_iso ) elsif TAXABLE_STATES_SOURCE_TAXJAR.include?(to_state.to_s.upcase) require 'taxjar' # get tax rate from Tax Jar api_params = { from_street: from_street, from_city: from_city, from_state: from_state, from_zip: from_zip, from_country: from_country, to_street: to_street, to_city: to_city, to_state: to_state, to_country: to_country, to_zip: to_zip } sample_line_item_goods = { :id => 1, :quantity => 1, :product_tax_code => nil, :tax_class => 'g', :unit_price => 100, :discount => 0 } sample_line_item_services = { :id => 2, :quantity => 1, :product_tax_code => '19000', :tax_class => 'svc', :unit_price => 100, :discount => 0 } if line_items.present? && freight_charged if line_items.detect{|li| li[:tax_class] == 'g'}.nil? line_items << sample_line_item_goods elsif line_items.detect{|li| li[:tax_class] == 'svc'}.nil? line_items << sample_line_item_services end api_params[:line_items] = line_items api_params[:shipping] = freight_charged || 0 else # Just a rate dip with dummy values # api_params[:amount] = 100 # just passing any amount here, as we just want the rate line_items = [sample_line_item_goods, sample_line_item_services] #passing line_items to get rates for goods and services api_params[:line_items] = line_items api_params[:shipping] = freight_charged || 10 # same here end client = Api::Taxjar.client begin result = client.tax_for_order(api_params) logger.debug("Api::Taxjar results:") logger.debug(result.to_hash.inspect) result_shipping_rate = result.freight_taxable ? result.rate : 0.0 if result.freight_taxable && freight_charged result_freight_tax_collectable = (result_shipping_rate * freight_charged).round(2) else result_freight_tax_collectable = 0.0 end result_line_items = result.breakdown&.line_items&.map do |lir| OpenStruct.new( id: lir.id.to_i, taxable_amount: lir.taxable_amount, tax_collectable: lir.tax_collectable, combined_tax_rate: lir.combined_tax_rate ) end # Establish default rate as the combined rate result_rate_goods = result.rate result_rate_services = result.rate # Here's where we're going to determine the rate of services vs goods, if we have line items specified if result_line_items.present? # What line item id can use use to sample for service rate? if any if service_line_item_id = line_items.detect{|li| li[:tax_class] == 'svc'}&.dig(:id) # in our result line items, what rate was assigned? result_rate_services = result_line_items.detect{|rli| rli.id == service_line_item_id}&.combined_tax_rate end # Take the rate of a goods line, in a similar fashion if goods_line_item_id = line_items.detect{|li| li[:tax_class] == 'g'}&.dig(:id) result_rate_goods = result_line_items.detect{|rli| rli.id == goods_line_item_id}&.combined_tax_rate end end rescue Taxjar::Error => e # <Taxjar::Error::NotAcceptable: transaction_id is missing> logger.debug(e) # We try to retrieve from a recent pull in case of taxjar failure rtr = ResourceTaxRate.order(retrieved_on: :desc).find_by(tax_type: to_state.downcase) result_rate_goods = rtr.rate_goods result_rate_services = rtr.rate_services result_shipping_rate = rtr.rate_shipping result_freight_tax_collectable = 0.0 result_line_items = nil end Result.new( rate_goods: result_rate_goods, rate_services: result_rate_services, rate_shipping: result_shipping_rate, source: 'taxjar', retrieved_on: Date.current, tax_type: to_state.downcase, freight_tax_collectable: result_freight_tax_collectable, line_items: result_line_items, country_iso: to_country ) else Result.new(taxable: false, message: "State #{to_state} not taxable when shipping from #{from_country}") end else Result.new(taxable: false, message: "Not taxable when shipping from #{from_country} to #{to_country}") end elsif (tax_rate = TaxRate.effective_on(effective_date).find_by(country_iso: to_country)) Result.new( rate_goods: tax_rate.goods, rate_services: tax_rate.services, rate_shipping: tax_rate.shipping, source: 'internal', tax_rate_id: tax_rate.id, retrieved_on: Date.current, tax_type: tax_rate.tax_type, country_iso: tax_rate.country_iso ) else Result.new(taxable: false, message: "Not taxable") end end |