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
Instance Method Summary collapse
-
#calculate_tax ⇒ void
before_update hook — recomputes
tax_totalfor the line. - #has_tax? ⇒ Boolean
- #is_international? ⇒ Boolean
-
#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).
-
#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.
20 21 22 |
# File 'app/concerns/models/taxable_line.rb', line 20 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).
49 50 51 52 53 54 55 56 57 58 59 |
# File 'app/concerns/models/taxable_line.rb', line 49 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
15 |
# File 'app/concerns/models/taxable_line.rb', line 15 belongs_to :destination_state, class_name: 'State', foreign_key: 'destination_state_code', primary_key: 'code', optional: true |
#has_tax? ⇒ Boolean
69 70 71 |
# File 'app/concerns/models/taxable_line.rb', line 69 def has_tax? tax_rate.present? and tax_type.present? and tax_total.present? and tax_total > 0 end |
#is_international? ⇒ Boolean
61 62 63 64 65 66 67 |
# File 'app/concerns/models/taxable_line.rb', line 61 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
14 |
# File 'app/concerns/models/taxable_line.rb', line 14 belongs_to :origin_state, class_name: 'State', foreign_key: 'origin_state_code', primary_key: 'code', optional: true |
#resource_tax_rate ⇒ ResourceTaxRate
16 |
# File 'app/concerns/models/taxable_line.rb', line 16 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).
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'app/concerns/models/taxable_line.rb', line 28 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.
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'app/concerns/models/taxable_line.rb', line 85 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 |