Class: CreditMemo::SubmitToTaxjar
- Inherits:
-
BaseService
- Object
- BaseService
- CreditMemo::SubmitToTaxjar
- Defined in:
- app/services/credit_memo/submit_to_taxjar.rb
Overview
Service that creates / updates / deletes the TaxJar "refund"
transaction matching a CreditMemo. Mirrors Invoicing::SubmitToTaxjar
but on the negative side. Called via the Models::TaxjarSubmittable
state machine when a memo posts or is voided.
Defined Under Namespace
Classes: Result
Constant Summary collapse
- MARKETPLACE_PROVIDERS =
Mapping from marketplace customer ids to TaxJar provider strings.
When a memo's customer matches, the transaction is tagged
provider: amazon|walmartandexemption_type: marketplaceso
TaxJar treats it as marketplace-facilitated rather than direct. { 5_322_434 => 'amazon', 23_041_827 => 'walmart' }.freeze
Instance Attribute Summary
Attributes inherited from BaseService
Instance Method Summary collapse
-
#delete ⇒ Result
DELETEs the TaxJar refund transaction for this memo (used when a memo is voided).
-
#details ⇒ Hash{Symbol => Object}
Builds the full TaxJar
create_refund/update_refundpayload — negative-quantity / negative-price line items, destination address parts, marketplace flags, and the inverted sales-tax total. -
#existing_record? ⇒ Boolean
Whether TaxJar already has a refund transaction matching this memo's id — first by listing the day's refunds, then by direct show lookup as a fallback.
-
#initialize(credit_memo, options = {}) ⇒ SubmitToTaxjar
constructor
A new instance of SubmitToTaxjar.
-
#submit ⇒ Result
POSTs a fresh refund transaction to TaxJar, returning a Result carrying the original tax amount and TaxJar's calculated tax.
-
#taxjar_id ⇒ String
The TaxJar transaction id we'll use for this credit memo — the reference number, prefixed with the Rails env outside production so staging/dev don't collide with prod transactions.
-
#update ⇒ Result
PUTs an updated refund transaction to TaxJar.
Methods inherited from BaseService
#log_debug, #log_error, #log_info, #log_warning, #logger, #process, #tagged_logger
Constructor Details
#initialize(credit_memo, options = {}) ⇒ SubmitToTaxjar
Returns a new instance of SubmitToTaxjar.
23 24 25 26 27 28 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 23 def initialize(credit_memo, = {}) @credit_memo = credit_memo @options = @logger = [:logger] || Rails.logger @client = Api::Taxjar.client end |
Instance Method Details
#delete ⇒ Result
DELETEs the TaxJar refund transaction for this memo (used when a
memo is voided). Returns a Result with success / message.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 142 def delete @client.show_refund(taxjar_id) @client.delete_refund(taxjar_id) Result.new( success: true, message: "Record on Taxjar for credit memo #{taxjar_id} successfully deleted" ) rescue Api::Taxjar::Error::NotFound @logger.info "Record not found on Taxjar for credit memo #{taxjar_id}" Result.new( success: false, message: "Record not found on Taxjar for credit memo #{taxjar_id}" ) end |
#details ⇒ Hash{Symbol => Object}
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 163 def details line_items = [] if @credit_memo.line_items.present? @credit_memo.line_items.parents_only.non_shipping.each do |li| next if li.taxable_total.zero? product_identifier = li.item.present? ? li.item.sku : li.cm_category unit_price = li.price.zero? ? ((li.taxable_total / li.quantity) * -1) : (li.price * -1) # unit_price = li.taxable_total description = if li.item.present? (li.item.sku + ' - ' + li.item.name) else li.description.presence || li.cm_category end line_items << { quantity: (li.quantity * -1), product_identifier: product_identifier, product_tax_code: li.item&.product_tax_code&.product_tax_code, description: description, unit_price: unit_price, discount: [li.line_discounts.sum(:amount), 0].max, sales_tax: (li.tax_total * -1) } end end # Map customer IDs to their marketplace providers marketplace_provider = MARKETPLACE_PROVIDERS[@credit_memo.customer_id] # Build base transaction details base_details = { customer_id: @credit_memo.taxjar_customer_id, transaction_id: taxjar_id, provider: marketplace_provider.presence || 'api', transaction_date: @credit_memo.gl_date.to_s, to_country: @credit_memo.shipping_address.country.iso, to_zip: @credit_memo.shipping_address.zip, to_state: @credit_memo.shipping_address.state_code, to_city: @credit_memo.shipping_address.city, to_street: @credit_memo.shipping_address.street1, amount: @credit_memo.line_items.to_a.sum(&:taxable_total).to_f, shipping: @credit_memo.shipping_cost.to_f == @credit_memo.line_items.shipping_only.to_a.sum(&:taxable_total).to_f ? @credit_memo.shipping_cost.to_f : @credit_memo.line_items.shipping_only.to_a.sum(&:taxable_total).to_f, sales_tax: (@credit_memo.tax_total * -1).to_f, line_items: line_items } # Add exemption_type for marketplace providers only base_details[:exemption_type] = 'marketplace' if marketplace_provider.present? base_details end |
#existing_record? ⇒ Boolean
Whether TaxJar already has a refund transaction matching this
memo's id — first by listing the day's refunds, then by direct
show lookup as a fallback.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 90 def existing_record? # check it already exists existing_records = @client.list_refunds({ from_transaction_date: @credit_memo.gl_date.to_s, to_transaction_date: @credit_memo.gl_date.to_s }) existing_records.include?(taxjar_id) rescue Api::Taxjar::Error begin existing_record = @client.show_refund(taxjar_id) existing_record.present? rescue Api::Taxjar::Error::NotFound false end end |
#submit ⇒ Result
POSTs a fresh refund transaction to TaxJar, returning a Result
carrying the original tax amount and TaxJar's calculated tax. If
a record already exists (#existing_record?) returns
success: false to avoid duplicates. TaxJar server errors are
returned in Result#message (not raised).
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 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 48 def submit if existing_record? @logger.info "Record already exists on Taxjar for credit memo #{taxjar_id}" Result.new( success: false, message: "Record already exists on Taxjar for credit memo #{taxjar_id}" ) else new_record = @client.create_refund(details) Result.new( success: true, original_tax_amount: (@credit_memo.tax_total * -1).to_f, calculated_tax: new_record.sales_tax ) end rescue Api::Taxjar::Error::UnprocessableEntity => e # Handle "Provider tranx already imported" — refund exists via marketplace integration # (mirrors Invoicing::SubmitToTaxjar#submit, since memos for marketplace # customers are tagged provider: amazon|walmart and can collide the same way). if e..include?('already imported') Result.new( success: true, message: "Record already exists on Taxjar via marketplace provider for credit memo #{taxjar_id}" ) else Result.new( success: false, message: e. ) end rescue Api::Taxjar::Error::ServerError => e Result.new( success: false, message: e. ) end |
#taxjar_id ⇒ String
The TaxJar transaction id we'll use for this credit memo —
the reference number, prefixed with the Rails env outside
production so staging/dev don't collide with prod transactions.
35 36 37 38 39 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 35 def taxjar_id str = @credit_memo.reference_number.clone str.prepend("#{Rails.env}-") if !Rails.env.production? && !str.start_with?("#{Rails.env}-") str end |
#update ⇒ Result
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'app/services/credit_memo/submit_to_taxjar.rb', line 113 def update marketplace_provider = MARKETPLACE_PROVIDERS[@credit_memo.customer_id] # Fetch existing record with provider parameter if applicable if marketplace_provider.present? @client.show_refund(taxjar_id, { provider: marketplace_provider }) else @client.show_refund(taxjar_id) end updated_record = @client.update_refund(details) Result.new( success: true, original_tax_amount: (@credit_memo.tax_total * -1).to_f, calculated_tax: updated_record.sales_tax ) rescue Api::Taxjar::Error::NotFound @logger.info "Record not found on Taxjar for credit memo #{taxjar_id}" Result.new( success: false, message: "Record not found on Taxjar for credit memo #{taxjar_id}" ) end |