Module: Models::TaxableLine
- Extended by:
- ActiveSupport::Concern
- Included in:
- LineItem
- Defined in:
- app/concerns/models/taxable_line.rb
Overview
Mixin for LineItem that holds per-line tax fields and the
create/update callbacks that re-evaluate them against the parent
TaxableResource's ResourceTaxRate. Decisions about which
rate applies live on the resource; this concern just routes the
line through get_rates_for_line and computes tax_total.
Instance Attribute Summary collapse
-
#do_not_calculate_tax ⇒ Object
Returns the value of attribute do_not_calculate_tax.
Belongs to collapse
-
#destination_state ⇒ State?
Destination (ship-to) state for the line's tax lookup.
-
#origin_state ⇒ State?
Origin (warehouse) state for the line's tax lookup.
-
#resource_tax_rate ⇒ ResourceTaxRate?
Tax-rate snapshot applied to this line.
Instance Method Summary collapse
-
#calculate_tax ⇒ void
before_update hook — recomputes
tax_totalfor the line. -
#has_tax? ⇒ Boolean
Whether the line carries a positive computed tax amount.
-
#is_international? ⇒ Boolean
Whether the line ships across a country border (origin vs. shipping address country).
-
#set_initial_tax_rate ⇒ void, Symbol
before_create hook — populates the tax rate / type / resource-rate id on the line by asking the parent resource for the right rate (zero for
RoomConfigurationlines, which never carry tax). -
#update_tax_rate(rate:, resource_tax_rate_id:, tax_type:, auto_save: true) ⇒ void
Writes a new tax rate / type / resource-rate id onto the line, rounds in a fresh
tax_total = taxable_total × rate(unlessdo_not_calculate_taxis set), and persists with deadlock retry whenauto_saveis true.
Instance Attribute Details
#do_not_calculate_tax ⇒ Object
Returns the value of attribute do_not_calculate_tax.
23 24 25 |
# File 'app/concerns/models/taxable_line.rb', line 23 def do_not_calculate_tax @do_not_calculate_tax end |
Instance Method Details
#calculate_tax ⇒ void
This method returns an undefined value.
before_update hook — recomputes tax_total for the line. If the
tax_class changed (e.g. a goods → service swap) we re-resolve
the rate via the parent resource; otherwise we just multiply
taxable_total × tax_rate. RoomConfiguration lines force a zero
rate. Skipped entirely when do_not_calculate_tax is set (used
when copying lines from a CI invoice with marketplace-set tax).
52 53 54 55 56 57 58 59 60 61 62 |
# File 'app/concerns/models/taxable_line.rb', line 52 def calculate_tax if tax_class_changed? update_tax_rate(**resource.get_rates_for_line(self), auto_save: false) elsif tax_rate self.tax_total = taxable_total.to_f * tax_rate unless do_not_calculate_tax == true elsif resource.nil? || resource.is_a?(RoomConfiguration) update_tax_rate(rate: 0, tax_type: nil, resource_tax_rate_id: nil, auto_save: false) else resource.refresh_tax_rate end end |
#destination_state ⇒ State?
Returns destination (ship-to) state for the line's tax lookup.
17 |
# File 'app/concerns/models/taxable_line.rb', line 17 belongs_to :destination_state, class_name: 'State', foreign_key: 'destination_state_code', primary_key: 'code', optional: true |
#has_tax? ⇒ Boolean
Whether the line carries a positive computed tax amount.
79 80 81 |
# File 'app/concerns/models/taxable_line.rb', line 79 def has_tax? tax_rate.present? and tax_type.present? and tax_total.present? and tax_total > 0 end |
#is_international? ⇒ Boolean
Whether the line ships across a country border (origin vs. shipping
address country). Defaults to false for legacy rows missing addresses.
68 69 70 71 72 73 74 |
# File 'app/concerns/models/taxable_line.rb', line 68 def is_international? if resource&.origin_address && resource.shipping_address resource.origin_address.country_iso3 != resource.shipping_address.country_iso3 else false # default to handle legacy end end |
#origin_state ⇒ State?
Returns origin (warehouse) state for the line's tax lookup.
15 |
# File 'app/concerns/models/taxable_line.rb', line 15 belongs_to :origin_state, class_name: 'State', foreign_key: 'origin_state_code', primary_key: 'code', optional: true |
#resource_tax_rate ⇒ ResourceTaxRate?
Returns tax-rate snapshot applied to this line.
19 |
# File 'app/concerns/models/taxable_line.rb', line 19 belongs_to :resource_tax_rate, optional: true |
#set_initial_tax_rate ⇒ void, Symbol
before_create hook — populates the tax rate / type / resource-rate
id on the line by asking the parent resource for the right rate
(zero for RoomConfiguration lines, which never carry tax).
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'app/concerns/models/taxable_line.rb', line 31 def set_initial_tax_rate # !!!! MUST use !resource.nil? here - if you call resource.present? it will # !!!! do an active record call and ignore any changes that may have been made in memory return :no_resource if resource.nil? if resource.is_a?(RoomConfiguration) update_tax_rate(rate: 0, tax_type: nil, resource_tax_rate_id: nil, auto_save: false) else tr = resource.get_rates_for_line(self) update_tax_rate(rate: tr[:rate], tax_type: tr[:tax_type], resource_tax_rate_id: tr[:resource_tax_rate_id], auto_save: false) end end |
#update_tax_rate(rate:, resource_tax_rate_id:, tax_type:, auto_save: true) ⇒ void
This method returns an undefined value.
Writes a new tax rate / type / resource-rate id onto the line,
rounds in a fresh tax_total = taxable_total × rate (unless
do_not_calculate_tax is set), and persists with deadlock retry
when auto_save is true. Deadlocks happen when parallel worker
processes (e.g. customer-merge / coupon recalc) update line_items
on the same order at once.
95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/concerns/models/taxable_line.rb', line 95 def update_tax_rate(rate:, resource_tax_rate_id:, tax_type:, auto_save: true) self.tax_rate = rate self.tax_type = tax_type self.resource_tax_rate_id = resource_tax_rate_id self.tax_total = taxable_total.to_f * rate unless do_not_calculate_tax == true return unless auto_save # Retry on deadlock - can occur when parallel processes (e.g., customer merge workers) # update line_items on the same orders simultaneously Retryable.retryable(tries: 3, sleep: ->(n) { 2**n }, on: [ActiveRecord::Deadlocked]) do save end end |