mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-25 20:46:48 +00:00
There were a few changes needed: * Plugins are now specified through `plugin:` config keyword. * All plugin gems need to be specified explicitly in Gemfile since they are no longer dependencies of plugins already specified explicitly. * All plugin gems need to be updated in other to use the new APIs. * One cop was renamed. * New offenses safe to correct were corrected directly with `bundle exec rubocop -a`. * New offenses unsafe to correct were added to the TODO configuration with `bundle exec rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1400 --no-auto-gen-timestamp`.
190 lines
5.5 KiB
Ruby
190 lines
5.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Invoice
|
|
class DataPresenter
|
|
include ::ActionView::Helpers::NumberHelper
|
|
|
|
attr_reader :invoice
|
|
|
|
delegate :display_number, :data, :previous_invoice, to: :invoice
|
|
delegate :date, to: :invoice, prefix: true
|
|
|
|
FINALIZED_NON_SUCCESSFUL_STATES = %w(canceled returned).freeze
|
|
|
|
extend Invoice::DataPresenterAttributes
|
|
|
|
attributes :additional_tax_total, :currency, :included_tax_total, :payment_total,
|
|
:shipping_method_id, :state, :total, :number, :note, :special_instructions,
|
|
:completed_at
|
|
|
|
attributes_with_presenter :bill_address, :customer, :distributor, :ship_address,
|
|
:shipping_method, :order_cycle
|
|
|
|
array_attribute :sorted_line_items, class_name: 'LineItem'
|
|
array_attribute :all_eligible_adjustments, class_name: 'Adjustment'
|
|
array_attribute :payments, class_name: 'Payment'
|
|
|
|
# if any of the following attributes is updated, a new invoice should be generated
|
|
invoice_generation_attributes :additional_tax_total, :all_eligible_adjustments, :bill_address,
|
|
:included_tax_total, :payments, :payment_total, :ship_address,
|
|
:shipping_method_id, :sorted_line_items, :total
|
|
|
|
# if any of the following attributes is updated, the latest invoice should be updated
|
|
invoice_update_attributes :note, :special_instructions, :state,
|
|
:all_eligible_adjustments, :payments
|
|
|
|
def initialize(invoice)
|
|
@invoice = invoice
|
|
end
|
|
|
|
def has_taxes_included
|
|
included_tax_total > 0
|
|
end
|
|
|
|
def total_tax
|
|
additional_tax_total + included_tax_total
|
|
end
|
|
|
|
def order_completed_at
|
|
return nil if data[:completed_at].blank?
|
|
|
|
Time.zone.parse(data[:completed_at])
|
|
end
|
|
|
|
def checkout_adjustments(exclude: [])
|
|
adjustments = all_eligible_adjustments
|
|
.reject { |a| a.originator.type == 'Spree::TaxRate' }
|
|
.map(&:clone)
|
|
|
|
adjustments.reject! { |a| a.amount == 0 }
|
|
[:line_item, :shipment].each do |type|
|
|
next unless exclude.include? type
|
|
|
|
adjustments.reject! { |a|
|
|
a.adjustable_type == "Spree::#{type.to_s.classify}"
|
|
}
|
|
end
|
|
adjustments
|
|
end
|
|
|
|
def shipment_adjustment
|
|
all_eligible_adjustments.find { |a| a.originator.type == 'Spree::ShippingMethod' }
|
|
end
|
|
|
|
# contains limited information about the shipment
|
|
def shipment
|
|
shipment_adjustment&.adjustable || null_shipment
|
|
end
|
|
|
|
def null_shipment
|
|
Struct.new(
|
|
:amount,
|
|
:included_tax_total,
|
|
:additional_tax_total,
|
|
).new(0, 0, 0)
|
|
end
|
|
|
|
def display_shipment_amount_without_taxes
|
|
Spree::Money.new(shipment.amount - shipment.included_tax_total, currency:)
|
|
end
|
|
|
|
def display_shipment_amount_with_taxes
|
|
Spree::Money.new(shipment.amount + shipment.additional_tax_total, currency:)
|
|
end
|
|
|
|
def display_line_item_tax_rate(item)
|
|
all_tax_adjustments.select { |a|
|
|
a.adjustable.type == 'Spree::LineItem' && a.adjustable.id == item.id
|
|
}.map(&:originator).map { |tr|
|
|
number_to_percentage(tr.amount * 100, precision: 1)
|
|
}.join(", ")
|
|
end
|
|
|
|
def display_shipment_tax_rates
|
|
all_eligible_adjustments.select { |a|
|
|
a.originator.type == 'Spree::TaxRate' && a.adjustable_type == 'Spree::Shipment'
|
|
}.map(&:originator)
|
|
.map { |tr| number_to_percentage(tr.amount * 100, precision: 1) }.join(", ")
|
|
end
|
|
|
|
def display_checkout_taxes_hash
|
|
tax_adjustment_totals.map do |tax_rate_id, tax_amount|
|
|
tax_rate = tax_rate_by_id[tax_rate_id]
|
|
{
|
|
amount: Spree::Money.new(tax_amount, currency:),
|
|
percentage: number_to_percentage(tax_rate.amount * 100, precision: 1),
|
|
rate_amount: tax_rate.amount,
|
|
}
|
|
end.sort_by { |tax| tax[:rate_amount] }
|
|
end
|
|
|
|
def display_date
|
|
I18n.l(invoice_date.to_date, format: :long)
|
|
end
|
|
|
|
def display_tax_adjustment_total
|
|
Spree::Money.new(all_tax_adjustments.map(&:amount).sum, currency:)
|
|
end
|
|
|
|
def tax_adjustment_totals
|
|
all_tax_adjustments.each_with_object(Hash.new(0)) do |adjustment, totals|
|
|
totals[adjustment.originator.id] += adjustment.amount
|
|
end
|
|
end
|
|
|
|
def tax_rate_by_id
|
|
all_tax_adjustments.each_with_object({}) do |adjustment, tax_rates|
|
|
tax_rates[adjustment.originator.id] = adjustment.originator
|
|
end
|
|
end
|
|
|
|
def all_tax_adjustments
|
|
all_eligible_adjustments.select { |a| a.originator.type == 'Spree::TaxRate' }
|
|
end
|
|
|
|
def paid?
|
|
['paid', 'credit_owed'].include?(data[:payment_state])
|
|
end
|
|
|
|
def outstanding_balance?
|
|
!new_outstanding_balance.zero?
|
|
end
|
|
|
|
def new_outstanding_balance
|
|
if state.in?(FINALIZED_NON_SUCCESSFUL_STATES)
|
|
-payment_total
|
|
else
|
|
total - payment_total
|
|
end
|
|
end
|
|
|
|
def outstanding_balance_label
|
|
new_outstanding_balance.negative? ? I18n.t(:credit_owed) : I18n.t(:balance_due)
|
|
end
|
|
|
|
def last_payment
|
|
payments.max_by(&:created_at)
|
|
end
|
|
|
|
def last_payment_method
|
|
last_payment&.payment_method
|
|
end
|
|
|
|
def display_outstanding_balance
|
|
Spree::Money.new(new_outstanding_balance, currency:)
|
|
end
|
|
|
|
def display_checkout_tax_total
|
|
Spree::Money.new(total_tax, currency:)
|
|
end
|
|
|
|
def display_checkout_total_less_tax
|
|
Spree::Money.new(total - total_tax, currency:)
|
|
end
|
|
|
|
def display_total
|
|
Spree::Money.new(total, currency:)
|
|
end
|
|
end
|
|
end
|