From 2d2792225a607a06dbd06aab694030a5cfa04d95 Mon Sep 17 00:00:00 2001 From: Pierre de Lacroix Date: Thu, 15 Dec 2016 23:26:09 +0100 Subject: [PATCH] change invoice layout to include amount for each relevant tax rate --- app/helpers/checkout_helper.rb | 10 ++++ app/models/spree/address_decorator.rb | 12 +++++ app/models/spree/adjustment_decorator.rb | 1 + app/models/spree/line_item_decorator.rb | 5 ++ app/models/spree/order_decorator.rb | 16 ++++++ .../admin/orders/_invoice_table.html.haml | 37 +++++++------ .../spree/admin/orders/invoice.html.haml | 52 +++++++++++-------- config/locales/en.yml | 16 +++++- config/locales/fr.yml | 23 ++++++-- 9 files changed, 129 insertions(+), 43 deletions(-) diff --git a/app/helpers/checkout_helper.rb b/app/helpers/checkout_helper.rb index 57cbfd7b73..b8e4adc964 100644 --- a/app/helpers/checkout_helper.rb +++ b/app/helpers/checkout_helper.rb @@ -43,6 +43,16 @@ module CheckoutHelper Spree::Money.new order.total_tax, currency: order.currency end + def display_checkout_taxes_hash(order) + order.tax_adjustment_totals.each_with_object(Hash.new) do |(tax_rate, tax_value), acc| + acc[number_to_percentage(tax_rate.amount * 100, :precision => 1)] = Spree::Money.new tax_value, currency: order.currency + end + end + + def display_line_item_tax_rates(line_item) + line_item.tax_rates.map { |tr| number_to_percentage(tr.amount * 100, :precision => 1) }.join(", ") + end + def display_checkout_total_less_tax(order) Spree::Money.new order.total - order.total_tax, currency: order.currency end diff --git a/app/models/spree/address_decorator.rb b/app/models/spree/address_decorator.rb index 03fa4da0cd..db092f5eb2 100644 --- a/app/models/spree/address_decorator.rb +++ b/app/models/spree/address_decorator.rb @@ -20,6 +20,18 @@ Spree::Address.class_eval do filtered_address.compact.join(', ') end + def address_part1 + address_part1 = [address1, address2] + filtered_address = address_part1.select{ |field| !field.nil? && field != '' } + filtered_address.compact.join(', ') + end + + def address_part2 + address_part2= [city, zipcode, state.andand.name] + filtered_address = address_part2.select{ |field| !field.nil? && field != '' } + filtered_address.compact.join(', ') + end + private def touch_enterprise diff --git a/app/models/spree/adjustment_decorator.rb b/app/models/spree/adjustment_decorator.rb index c8529fc577..093f1c86fd 100644 --- a/app/models/spree/adjustment_decorator.rb +++ b/app/models/spree/adjustment_decorator.rb @@ -4,6 +4,7 @@ module Spree # So we don't need the option `dependent: :destroy` as long as # AdjustmentMetadata has no destroy logic itself. has_one :metadata, class_name: 'AdjustmentMetadata' + belongs_to :tax_rate, foreign_key: 'originator_id', conditions: "spree_adjustments.originator_type = 'Spree::TaxRate'" scope :enterprise_fee, where(originator_type: 'EnterpriseFee') scope :billable_period, where(source_type: 'BillablePeriod') diff --git a/app/models/spree/line_item_decorator.rb b/app/models/spree/line_item_decorator.rb index 8a89d8fdef..120624949c 100644 --- a/app/models/spree/line_item_decorator.rb +++ b/app/models/spree/line_item_decorator.rb @@ -3,6 +3,7 @@ require 'open_food_network/variant_and_line_item_naming' Spree::LineItem.class_eval do include OpenFoodNetwork::VariantAndLineItemNaming has_and_belongs_to_many :option_values, join_table: 'spree_option_values_line_items', class_name: 'Spree::OptionValue' + has_many :tax_adjustments, class_name: "Adjustment", conditions: "spree_adjustments.originator_type = 'Spree::TaxRate'", as: :adjustable attr_accessible :max_quantity, :final_weight_volume, :price attr_accessible :final_weight_volume, :price, :as => :api @@ -56,6 +57,10 @@ Spree::LineItem.class_eval do adjustments.included_tax.sum(&:included_tax) end + def tax_rates + product.tax_category.tax_rates + end + def price_with_adjustments # EnterpriseFee#create_locked_adjustment applies adjustments on line items to their parent order, # so line_item.adjustments returns an empty array diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index c62f114177..1751431055 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -227,6 +227,22 @@ Spree::Order.class_eval do (adjustments + price_adjustments).sum &:included_tax end + def tax_adjustments + adjustments.with_tax + + line_items.includes(:tax_adjustments).map {|li| li.tax_adjustments}.flatten + end + + def tax_adjustment_totals + Hash[tax_adjustments.group_by(&:label).map do |label, adjustments| + [adjustments.first.originator, adjustments.sum(&:amount)] + end] + end + + # Uses the first associated tax to determine if taxes are included in price + def has_taxes_included + not line_items.with_tax.empty? + end + def account_invoice? distributor_id == Spree::Config.accounts_distributor_id end diff --git a/app/views/spree/admin/orders/_invoice_table.html.haml b/app/views/spree/admin/orders/_invoice_table.html.haml index 4bd9917eb0..2591a8ad7d 100644 --- a/app/views/spree/admin/orders/_invoice_table.html.haml +++ b/app/views/spree/admin/orders/_invoice_table.html.haml @@ -2,13 +2,15 @@ %thead %tr %th{:align => "left"} - %h4= t(:invoice_column_item) + %h5= t(:invoice_column_item) %th{:align => "right", :width => "15%"} - %h4= t(:invoice_column_qty) + %h5= t(:invoice_column_qty) %th{:align => "right", :width => "15%"} - %h4= @order.total_tax > 0 ? t(:invoice_column_tax) : "" + %h5= @order.has_taxes_included ? t(:invoice_column_unit_price_with_taxes) : t(:invoice_column_unit_price_without_taxes) %th{:align => "right", :width => "15%"} - %h4= t(:invoice_column_price) + %h5= @order.has_taxes_included ? t(:invoice_column_price_with_taxes) : t(:invoice_column_price_without_taxes) + %th{:align => "right", :width => "15%"} + %h5= @order.total_tax > 0 ? t(:invoice_column_tax_rate) : "" %tbody - @order.line_items.sort_by{ |li| li.product.name }.each do |item| %tr @@ -17,9 +19,11 @@ %td{:align => "right"} = item.quantity %td{:align => "right"} - = item.included_tax > 0 ? item.display_included_tax : "" + = item.single_display_amount_with_adjustments %td{:align => "right"} = item.display_amount_with_adjustments + %td{:align => "right"} + = display_line_item_tax_rates(item) - checkout_adjustments_for(@order, exclude: [:line_item]).reject{ |a| a.amount == 0 }.reverse_each do |adjustment| %tr %td @@ -32,19 +36,20 @@ = adjustment.display_amount %tfoot %tr + %td{:align => "right", :colspan => "3"} + %strong= @order.has_taxes_included ? t(:total_incl_tax) : t(:total_excl_tax) %td{:align => "right", :colspan => "2"} - %strong GST Total: - %td{:align => "right", :colspan => "2"} - %strong= display_checkout_tax_total(@order) + %strong= @order.has_taxes_included ? @order.display_total : display_checkout_total_less_tax(@order) + - display_checkout_taxes_hash(@order).each do |tax_rate, tax_value| + %tr + %td{:align => "right", :colspan => "3"} + = t(:tax_total, rate: tax_rate) + %td{:align => "right", :colspan => "2"} + = tax_value %tr + %td{:align => "right", :colspan => "3"} + = @order.has_taxes_included ? t(:total_excl_tax) : t(:total_incl_tax) %td{:align => "right", :colspan => "2"} - %strong Total (Excl. GST): - %td{:align => "right", :colspan => "2"} - %strong= display_checkout_total_less_tax(@order) - %tr - %td{:align => "right", :colspan => "2"} - %strong Total (Incl. GST): - %td{:align => "right", :colspan => "2"} - %strong= @order.display_total + = @order.has_taxes_included ? display_checkout_total_less_tax(@order) : @order.display_total %p   diff --git a/app/views/spree/admin/orders/invoice.html.haml b/app/views/spree/admin/orders/invoice.html.haml index 37969b96b1..a15a1a1bb9 100644 --- a/app/views/spree/admin/orders/invoice.html.haml +++ b/app/views/spree/admin/orders/invoice.html.haml @@ -4,38 +4,46 @@ %tbody %tr{ valign: "top" } %td{ :align => "left", colspan: 3 } - %h6= "Issued on: #{Time.zone.now.strftime("%F")}" - %tr{ valign: "top" } - %td{ :align => "left" } %h4 - = t('.tax_invoice') - = "#{@order.number}" - %td{width: "10%" } -   - %td{ :align => "right" } - %h4= @order.order_cycle.andand.name + = t(:tax_invoice) %tr{ valign: "top" } - %td{ :align => "left" } - %strong= "From: #{@order.distributor.name}" - - if @order.distributor.abn.present? - %br - = "ABN: #{@order.distributor.abn}" + %td{ :align => "left", colspan: 3 } + %strong= @order.distributor.name %br - = @order.distributor.address.full_address + = @order.distributor.address.address_part1 + %br + = @order.distributor.address.address_part2 %br = @order.distributor.email - %td{width: "10%" } -   - %td{ :align => "right" } - %strong= "To: #{@order.ship_address.full_name}" + - if @order.distributor.phone.present? + %br + = @order.distributor.phone + - if @order.distributor.abn.present? + %br + = "#{t :abn} #{@order.distributor.abn}" + - if @order.distributor.acn.present? + %br + = "#{t :acn} #{@order.distributor.acn}" + %tr{ valign: "top" } + %td{ :align => "right", colspan: 3 } + %strong= @order.ship_address.full_name - if @order.customer.code.present? %br = "Code: #{@order.customer.code}" %br - = @order.ship_address.full_address + = @order.ship_address.address_part1 %br - = "#{@order.customer.email}," - = "#{@order.bill_address.phone}" + = @order.ship_address.address_part2 + %tr{ valign: "top" } + %td{ :align => "left", colspan: 3 } + = t :invoice_issued_on + = l Time.zone.now.to_date + %br + = t :date_of_transaction + = l @order.completed_at.to_date + %br + = t :order_number + = @order.number = render 'spree/admin/orders/invoice_table' diff --git a/config/locales/en.yml b/config/locales/en.yml index a737b1ce8b..9cfbc6691e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -531,8 +531,20 @@ en: # Printable Invoice Columns invoice_column_item: "Item" invoice_column_qty: "Qty" - invoice_column_tax: "GST" - invoice_column_price: "Price" + invoice_column_unit_price_with_taxes: "Unit price (Incl. GST)" + invoice_column_unit_price_without_taxes: "Unit price (Excl. GST)" + invoice_column_price_with_taxes: "Total price (Incl. GST)" + invoice_column_price_without_taxes: "Total price (Excl. GST)" + invoice_column_tax_rate: "Tax rate" + tax_invoice: "TAX INVOICE" + tax_total: "GST Total (%{rate}):" + total_excl_tax: "Total (Excl. GST):" + total_incl_tax: "Total (Incl. GST):" + abn: "ABN:" + acn: "ACN:" + invoice_issued_on: "Invoice issued on:" + order_number: "Invoice number:" + date_of_transaction: "Date of transaction:" logo: "Logo (640x130)" #FIXME logo_mobile: "Mobile logo (75x26)" #FIXME diff --git a/config/locales/fr.yml b/config/locales/fr.yml index b107857913..b2bb1aa4a8 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -484,8 +484,25 @@ fr: require_customer_html: "Veuillez %{contact} %{enterprise} pour devenir membre." invoice_column_item: "Produit" invoice_column_qty: "Qté" - invoice_column_tax: "TVA" - invoice_column_price: "Prix" + invoice_column_unit_price_with_taxes: "Prix unitaire (TTC)" + invoice_column_unit_price_without_taxes: "Prix unitaire (HT)" + invoice_column_price_with_taxes: "Prix total (TTC)" + invoice_column_price_without_taxes: "Prix total (HT)" + invoice_column_tax_rate: "Taux TVA" + tax_invoice: "FACTURE" + tax_total: "Total TVA (%{rate}) :" + total_excl_tax: "Total HT :" + total_incl_tax: "Total TTC :" + abn: "SIRET :" + acn: "n° TVA :" + invoice_issued_on: "Facture éditée le :" + order_number: "Numéro de facture :" + date_of_transaction: "Date de la transaction :" + number: + percentage: + format: + format: "%n %" + logo: "Logo (640x130)" logo_mobile: "Logo smartphone (75x26)" logo_mobile_svg: "Logo smartphone (SVG)" @@ -689,7 +706,7 @@ fr: email_payment_paid: RÉGLÉ email_payment_not_paid: NON RÉGLÉ email_payment_summary: Résumé du paiement - email_payment_method: "Payer via :" + email_payment_method: "Moyen de paiement :" email_shipping_delivery_details: Détails de livraison email_shipping_delivery_time: "Livré le:" email_shipping_delivery_address: "Adresse de livraison:"