From 38e1bd413998b7eccf2d31716f9adc9085e4053e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 1 May 2015 15:44:19 +1000 Subject: [PATCH 01/14] Fix indentation --- lib/open_food_network/order_and_distributor_report.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/open_food_network/order_and_distributor_report.rb b/lib/open_food_network/order_and_distributor_report.rb index 2662b176dd..011e8d19fe 100644 --- a/lib/open_food_network/order_and_distributor_report.rb +++ b/lib/open_food_network/order_and_distributor_report.rb @@ -1,4 +1,3 @@ - module OpenFoodNetwork class OrderAndDistributorReport @@ -8,14 +7,15 @@ module OpenFoodNetwork def header ["Order date", "Order Id", - "Customer Name","Customer Email", "Customer Phone", "Customer City", - "SKU", "Item name", "Variant", "Quantity", "Max Quantity", "Cost", "Shipping cost", - "Payment method", - "Distributor", "Distributor address", "Distributor city", "Distributor postcode", "Shipping instructions"] + "Customer Name","Customer Email", "Customer Phone", "Customer City", + "SKU", "Item name", "Variant", "Quantity", "Max Quantity", "Cost", "Shipping cost", + "Payment method", + "Distributor", "Distributor address", "Distributor city", "Distributor postcode", "Shipping instructions"] end def table order_and_distributor_details = [] + @orders.each do |order| order.line_items.each do |line_item| order_and_distributor_details << [order.created_at, order.id, @@ -25,6 +25,7 @@ module OpenFoodNetwork order.distributor.andand.name, order.distributor.address.address1, order.distributor.address.city, order.distributor.address.zipcode, order.special_instructions ] end end + order_and_distributor_details end end From 0a2f2e0fbaa5b393bc8b4ed1d15425784db7a111 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 May 2015 15:31:39 +1000 Subject: [PATCH 02/14] Output summary data without customisation Add route for xero invoices report Add require for reports controller decorator --- .../admin/reports_controller_decorator.rb | 11 +++- config/routes.rb | 1 + lib/open_food_network/xero_invoices_report.rb | 60 +++++++++++++++++++ spec/features/admin/reports_spec.rb | 60 +++++++++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 lib/open_food_network/xero_invoices_report.rb diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 3aa4f560a1..3ef32aa074 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -7,6 +7,7 @@ require 'open_food_network/customers_report' require 'open_food_network/users_and_enterprises_report' require 'open_food_network/order_cycle_management_report' require 'open_food_network/sales_tax_report' +require 'open_food_network/xero_invoices_report' Spree::Admin::ReportsController.class_eval do @@ -679,7 +680,15 @@ Spree::Admin::ReportsController.class_eval do render_report(@report.header, @report.table, params[:csv], "users_and_enterprises_#{timestamp}.csv") end - def render_report (header, table, create_csv, csv_file_name) + def xero_invoices + @search = Spree::Order.complete.managed_by(spree_current_user).search(params[:q]) + orders = @search.result + @report = OpenFoodNetwork::XeroInvoicesReport.new orders + render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv") + end + + + def render_report(header, table, create_csv, csv_file_name) unless create_csv render :html => table else diff --git a/config/routes.rb b/config/routes.rb index 4621ee4a35..66805807ce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -134,6 +134,7 @@ Spree::Core::Engine.routes.prepend do match '/admin/orders/bulk_management' => 'admin/orders#bulk_management', :as => "admin_bulk_order_management" match '/admin/reports/products_and_inventory' => 'admin/reports#products_and_inventory', :as => "products_and_inventory_admin_reports", :via => [:get, :post] match '/admin/reports/customers' => 'admin/reports#customers', :as => "customers_admin_reports", :via => [:get, :post] + match '/admin/reports/xero_invoices' => 'admin/reports#xero_invoices', :as => "xero_invoices_admin_reports", :via => [:get, :post] match '/admin', :to => 'admin/overview#index', :as => :admin match '/admin/payment_methods/show_provider_preferences' => 'admin/payment_methods#show_provider_preferences', :via => :get diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb new file mode 100644 index 0000000000..18c95073d3 --- /dev/null +++ b/lib/open_food_network/xero_invoices_report.rb @@ -0,0 +1,60 @@ +module OpenFoodNetwork + class XeroInvoicesReport + def initialize(orders) + @orders = orders + end + + def header + %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme) + end + + def table + rows = [] + + @orders.each do |order| + rows << summary_row(order, 'Total untaxable produce (no tax)', 0, 'GST Free Income') + rows << summary_row(order, 'Total taxable produce (tax inclusive)', 0, 'GST on Income') + rows << summary_row(order, 'Total untaxable fees (no tax)', 0, 'GST Free Income') + rows << summary_row(order, 'Total taxable fees (tax inclusive)', 0, 'GST on Income') + rows << summary_row(order, 'Delivery Shipping Cost (tax inclusive)', 0, 'Tax or No Tax - depending on enterprise setting') + end + + rows + end + + + private + + def summary_row(order, description, amount, tax_type) + [order.bill_address.full_name, + order.email, + order.bill_address.address1, + order.bill_address.address2, + '', + '', + order.bill_address.city, + order.bill_address.state, + order.bill_address.zipcode, + order.bill_address.country.andand.name, + order.number, # To customise + order.number, + Date.today, # To customise + 2.weeks.from_now.to_date, # To customise + '', + description, + '1', + amount, + '', + 'food sales', # To customise + tax_type, + '', + '', + '', + '', + Spree::Config.currency, + '' + ] + end + + end +end diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 309e0a3e81..70e7711759 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -298,4 +298,64 @@ feature %q{ ].sort end end + + describe "Xero invoices report" do + let(:distributor1) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } + let(:distributor2) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } + let(:user1) { create_enterprise_user enterprises: [distributor1] } + let(:user2) { create_enterprise_user enterprises: [distributor2] } + let(:shipping_method) { create(:shipping_method, name: "Shipping", description: "Expensive", calculator: Spree::Calculator::FlatRate.new(preferred_amount: 100.55)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 120.0)) } + let(:order_cycle) { create(:simple_order_cycle, coordinator: distributor1, coordinator_fees: [enterprise_fee], distributors: [distributor1], variants: [product1.master]) } + + let!(:zone) { create(:zone_with_member) } + let(:country) { Spree::Country.find Spree::Config.default_country_id } + let(:bill_address) { create(:address, firstname: 'Customer', lastname: 'Name', address1: 'customer l1', address2: '', city: 'customer city', zipcode: 1234, country: country) } + let(:order1) { create(:order, order_cycle: order_cycle, distributor: user1.enterprises.first, shipping_method: shipping_method, bill_address: bill_address) } + let(:product1) { create(:taxed_product, zone: zone, price: 12.54, tax_rate_amount: 0) } + let(:product2) { create(:taxed_product, zone: zone, price: 500.15, tax_rate_amount: 0.2) } + + let!(:line_item1) { create(:line_item, variant: product1.master, price: 12.54, quantity: 1, order: order1) } + let!(:line_item2) { create(:line_item, variant: product2.master, price: 500.15, quantity: 3, order: order1) } + + let!(:adj_shipping) { create(:adjustment, adjustable: order1, label: "Shipping", amount: 100.55) } + + before do + order1.update_attribute :email, 'customer@email.com' + Timecop.travel(Time.zone.local(2015, 4, 25, 14, 0, 0)) { order1.finalize! } + + login_to_admin_section + click_link 'Reports' + + click_link 'Xero invoices' + end + + around do |example| + Timecop.travel(Time.zone.local(2015, 4, 26, 14, 0, 0)) do + example.yield + end + end + + it "shows Xero invoices report" do + rows = find("table#listing_invoices").all("tr") + table = rows.map { |r| r.all("th,td").map { |c| c.text.strip } } + + table.should == [ + %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), + xero_invoice_row('Total untaxable produce (no tax)', 0, 'GST Free Income'), + xero_invoice_row('Total taxable produce (tax inclusive)', 0, 'GST on Income'), + xero_invoice_row('Total untaxable fees (no tax)', 0, 'GST Free Income'), + xero_invoice_row('Total taxable fees (tax inclusive)', 0, 'GST on Income'), + xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 0, 'Tax or No Tax - depending on enterprise setting') + ] + end + + + private + + def xero_invoice_row(description, amount, tax_type) + ['Customer Name', 'customer@email.com', 'customer l1', '', '', '', 'customer city', 'Victoria', '1234', country.name, order1.number, order1.number, '2015-04-26', '2015-05-10', '', description, '1', amount.to_s, '', 'food sales', tax_type, '', '', '', '', Spree::Config.currency, ''] + + end + end end From 0737ac8da02f253a1c7a5e766240d90090c9c87b Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 14 May 2015 12:11:38 +1000 Subject: [PATCH 03/14] Write an rspec table matcher that gives informative error messages --- spec/support/matchers/table_matchers.rb | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/spec/support/matchers/table_matchers.rb b/spec/support/matchers/table_matchers.rb index 053562b9e4..411b0b646f 100644 --- a/spec/support/matchers/table_matchers.rb +++ b/spec/support/matchers/table_matchers.rb @@ -26,3 +26,44 @@ RSpec::Matchers.define :have_table_row do |row| node.all('tr').map { |tr| tr.all('th, td').map(&:text) } end end + + + +# find("#my-table").should match_table [[...]] +RSpec::Matchers.define :match_table do |expected_table| + + match_for_should do |node| + rows = node. + all("tr"). + map { |r| r.all("th,td").map { |c| c.text.strip } } + + if rows.count != expected_table.count + @failure_message = "found table with #{rows.count} rows, expected #{expected_table.count}" + + else + rows.each_with_index do |row, i| + expected_row = expected_table[i] + if row.count != expected_row.count + @failure_message = "row #{i} has #{row.count} columns, expected #{expected_row.count}" + break + + elsif row != expected_row + row.each_with_index do |cell, j| + if cell != expected_row[j] + @failure_message = "cell [#{i}, #{j}] has content '#{cell}', expected '#{expected_row[j]}'" + break + end + end + break if @failure_message + end + end + end + + @failure_message.nil? + end + + failure_message_for_should do |text| + @failure_message + end + +end From c5b618b1f4589f8243da2455e509fc012c2ebc09 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 14 May 2015 12:25:48 +1000 Subject: [PATCH 04/14] Admin can customise some fields on Xero invoices report Add require for xero invoices report spec --- .../admin/reports_controller_decorator.rb | 6 ++- .../admin/reports/xero_invoices.html.haml | 33 +++++++++++++++ lib/open_food_network/xero_invoices_report.rb | 32 +++++++++------ spec/features/admin/reports_spec.rb | 40 +++++++++++++++---- .../xero_invoices_report_spec.rb | 25 ++++++++++++ 5 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 app/views/spree/admin/reports/xero_invoices.html.haml create mode 100644 spec/lib/open_food_network/xero_invoices_report_spec.rb diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 3ef32aa074..15fab60d89 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -683,7 +683,7 @@ Spree::Admin::ReportsController.class_eval do def xero_invoices @search = Spree::Order.complete.managed_by(spree_current_user).search(params[:q]) orders = @search.result - @report = OpenFoodNetwork::XeroInvoicesReport.new orders + @report = OpenFoodNetwork::XeroInvoicesReport.new orders, params render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv") end @@ -725,7 +725,9 @@ Spree::Admin::ReportsController.class_eval do :sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" }, :users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" }, :order_cycle_management => {:name => "Order Cycle Management", :description => ''}, - :sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" } + :sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" }, + :xero_invoices => { :name => "Xero Invoices", :description => 'Invoices for import into Xero' } + } # Return only reports the user is authorized to view. reports.select { |action| can? action, :report } diff --git a/app/views/spree/admin/reports/xero_invoices.html.haml b/app/views/spree/admin/reports/xero_invoices.html.haml new file mode 100644 index 0000000000..8c11e5f543 --- /dev/null +++ b/app/views/spree/admin/reports/xero_invoices.html.haml @@ -0,0 +1,33 @@ += form_tag spree.xero_invoices_admin_reports_path do + .row + .four.columns.alpha= label_tag :initial_invoice_number, "Initial invoice number:" + .twelve.columns.omega= text_field_tag :initial_invoice_number + .row + .four.columns.alpha= label_tag :invoice_date, "Invoice date:" + .twelve.columns.omega= text_field_tag :invoice_date, '', class: 'datetimepicker' + .row + .four.columns.alpha= label_tag :due_date, "Due date:" + .twelve.columns.omega= text_field_tag :due_date, '', class: 'datetimepicker' + .row + .four.columns.alpha= label_tag :account_code, "Account code:" + .twelve.columns.omega= text_field_tag :account_code + .row + .four.columns.alpha= label_tag :csv, "Download as CSV:" + .twelve.columns.omega= check_box_tag :csv + .row + .four.columns.alpha= button t(:search) + + +%table#listing_invoices.index + %thead + %tr + - @report.header.each do |header| + %th= header + %tbody + - @report.table.each do |row| + %tr + - row.each do |column| + %td= column + - if @report.table.empty? + %tr + %td{:colspan => "2"}= t(:none) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 18c95073d3..784550a4b4 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -1,7 +1,10 @@ module OpenFoodNetwork class XeroInvoicesReport - def initialize(orders) + def initialize(orders, opts={}) @orders = orders + @opts = opts.reverse_merge({invoice_date: Date.today, + due_date: 2.weeks.from_now.to_date, + account_code: 'food sales'}) end def header @@ -11,12 +14,13 @@ module OpenFoodNetwork def table rows = [] - @orders.each do |order| - rows << summary_row(order, 'Total untaxable produce (no tax)', 0, 'GST Free Income') - rows << summary_row(order, 'Total taxable produce (tax inclusive)', 0, 'GST on Income') - rows << summary_row(order, 'Total untaxable fees (no tax)', 0, 'GST Free Income') - rows << summary_row(order, 'Total taxable fees (tax inclusive)', 0, 'GST on Income') - rows << summary_row(order, 'Delivery Shipping Cost (tax inclusive)', 0, 'Tax or No Tax - depending on enterprise setting') + @orders.each_with_index do |order, i| + invoice_number = invoice_number_for(order, i) + rows << summary_row(order, 'Total untaxable produce (no tax)', 0, invoice_number, 'GST Free Income', @opts) + rows << summary_row(order, 'Total taxable produce (tax inclusive)', 0, invoice_number, 'GST on Income', @opts) + rows << summary_row(order, 'Total untaxable fees (no tax)', 0, invoice_number, 'GST Free Income', @opts) + rows << summary_row(order, 'Total taxable fees (tax inclusive)', 0, invoice_number, 'GST on Income', @opts) + rows << summary_row(order, 'Delivery Shipping Cost (tax inclusive)', 0, invoice_number, 'Tax or No Tax - depending on enterprise setting', @opts) end rows @@ -25,7 +29,11 @@ module OpenFoodNetwork private - def summary_row(order, description, amount, tax_type) + def invoice_number_for(order, i) + @opts[:initial_invoice_number] ? @opts[:initial_invoice_number].to_i+i : order.number + end + + def summary_row(order, description, amount, invoice_number, tax_type, opts={}) [order.bill_address.full_name, order.email, order.bill_address.address1, @@ -36,16 +44,16 @@ module OpenFoodNetwork order.bill_address.state, order.bill_address.zipcode, order.bill_address.country.andand.name, - order.number, # To customise + invoice_number, order.number, - Date.today, # To customise - 2.weeks.from_now.to_date, # To customise + opts[:invoice_date], + opts[:due_date], '', description, '1', amount, '', - 'food sales', # To customise + opts[:account_code], tax_type, '', '', diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 70e7711759..49a0979406 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -327,7 +327,7 @@ feature %q{ login_to_admin_section click_link 'Reports' - click_link 'Xero invoices' + click_link 'Xero Invoices' end around do |example| @@ -337,10 +337,7 @@ feature %q{ end it "shows Xero invoices report" do - rows = find("table#listing_invoices").all("tr") - table = rows.map { |r| r.all("th,td").map { |c| c.text.strip } } - - table.should == [ + xero_invoice_table.should match_table [ %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), xero_invoice_row('Total untaxable produce (no tax)', 0, 'GST Free Income'), xero_invoice_row('Total taxable produce (tax inclusive)', 0, 'GST on Income'), @@ -350,11 +347,40 @@ feature %q{ ] end + it "can customise a number of fields" do + fill_in 'initial_invoice_number', with: '5' + fill_in 'invoice_date', with: '2015-02-12' + fill_in 'due_date', with: '2015-03-12' + fill_in 'account_code', with: 'abc123' + click_button 'Search' + + opts = {invoice_number: '5', invoice_date: '2015-02-12', due_date: '2015-03-12', account_code: 'abc123'} + + xero_invoice_table.should match_table [ + %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), + xero_invoice_row('Total untaxable produce (no tax)', 0, 'GST Free Income', opts), + xero_invoice_row('Total taxable produce (tax inclusive)', 0, 'GST on Income', opts), + xero_invoice_row('Total untaxable fees (no tax)', 0, 'GST Free Income', opts), + xero_invoice_row('Total taxable fees (tax inclusive)', 0, 'GST on Income', opts), + xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 0, 'Tax or No Tax - depending on enterprise setting', opts) + ] + + # TODO: + # - Amounts + # - Tax specification for shipping + end + private - def xero_invoice_row(description, amount, tax_type) - ['Customer Name', 'customer@email.com', 'customer l1', '', '', '', 'customer city', 'Victoria', '1234', country.name, order1.number, order1.number, '2015-04-26', '2015-05-10', '', description, '1', amount.to_s, '', 'food sales', tax_type, '', '', '', '', Spree::Config.currency, ''] + def xero_invoice_table + find("table#listing_invoices") + end + + def xero_invoice_row(description, amount, tax_type, opts={}) + opts.reverse_merge!({invoice_number: order1.number, invoice_date: '2015-04-26', due_date: '2015-05-10', account_code: 'food sales'}) + + ['Customer Name', 'customer@email.com', 'customer l1', '', '', '', 'customer city', 'Victoria', '1234', country.name, opts[:invoice_number], order1.number, opts[:invoice_date], opts[:due_date], '', description, '1', amount.to_s, '', opts[:account_code], tax_type, '', '', '', '', Spree::Config.currency, ''] end end diff --git a/spec/lib/open_food_network/xero_invoices_report_spec.rb b/spec/lib/open_food_network/xero_invoices_report_spec.rb new file mode 100644 index 0000000000..9756629f0e --- /dev/null +++ b/spec/lib/open_food_network/xero_invoices_report_spec.rb @@ -0,0 +1,25 @@ +require 'open_food_network/xero_invoices_report' + +module OpenFoodNetwork + describe XeroInvoicesReport do + subject { XeroInvoicesReport.new [] } + + describe "generating invoice numbers" do + let(:order) { double(:order, number: 'R731032860') } + + describe "when no initial invoice number is given" do + it "returns the order number" do + subject.send(:invoice_number_for, order, 123).should == 'R731032860' + end + end + + describe "when an initial invoice number is given" do + subject { XeroInvoicesReport.new [], {initial_invoice_number: '123'} } + + it "increments the number by the index" do + subject.send(:invoice_number_for, order, 456).should == 579 + end + end + end + end +end From 5660e3737e2e5fd82b01fb2dcba7daf22e305704 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 14 May 2015 13:01:46 +1000 Subject: [PATCH 05/14] Extract order rows generation to method --- lib/open_food_network/xero_invoices_report.rb | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 784550a4b4..7308f7740b 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -16,11 +16,7 @@ module OpenFoodNetwork @orders.each_with_index do |order, i| invoice_number = invoice_number_for(order, i) - rows << summary_row(order, 'Total untaxable produce (no tax)', 0, invoice_number, 'GST Free Income', @opts) - rows << summary_row(order, 'Total taxable produce (tax inclusive)', 0, invoice_number, 'GST on Income', @opts) - rows << summary_row(order, 'Total untaxable fees (no tax)', 0, invoice_number, 'GST Free Income', @opts) - rows << summary_row(order, 'Total taxable fees (tax inclusive)', 0, invoice_number, 'GST on Income', @opts) - rows << summary_row(order, 'Delivery Shipping Cost (tax inclusive)', 0, invoice_number, 'Tax or No Tax - depending on enterprise setting', @opts) + rows += rows_for_order(order, invoice_number, @opts) end rows @@ -29,6 +25,17 @@ module OpenFoodNetwork private + def rows_for_order(order, invoice_number, opts) + [ + summary_row(order, 'Total untaxable produce (no tax)', 0, invoice_number, 'GST Free Income', opts), + summary_row(order, 'Total taxable produce (tax inclusive)', 0, invoice_number, 'GST on Income', opts), + summary_row(order, 'Total untaxable fees (no tax)', 0, invoice_number, 'GST Free Income', opts), + summary_row(order, 'Total taxable fees (tax inclusive)', 0, invoice_number, 'GST on Income', opts), + summary_row(order, 'Delivery Shipping Cost (tax inclusive)', 0, invoice_number, 'Tax or No Tax - depending on enterprise setting', opts) + ] + end + + def invoice_number_for(order, i) @opts[:initial_invoice_number] ? @opts[:initial_invoice_number].to_i+i : order.number end From ca1d88d8b142d015edbc71e8a9de961d3db564d8 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 11:49:24 +1000 Subject: [PATCH 06/14] Find line items with and without tax --- app/models/spree/line_item_decorator.rb | 9 +++++++++ spec/models/spree/line_item_spec.rb | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/models/spree/line_item_decorator.rb b/app/models/spree/line_item_decorator.rb index b2c0a583fc..0d6532327c 100644 --- a/app/models/spree/line_item_decorator.rb +++ b/app/models/spree/line_item_decorator.rb @@ -23,6 +23,15 @@ Spree::LineItem.class_eval do where('spree_products.supplier_id IN (?)', enterprises) } + scope :with_tax, joins(:adjustments). + where('spree_adjustments.originator_type = ?', 'Spree::TaxRate'). + select('DISTINCT spree_line_items.*') + + # Line items without a Spree::TaxRate-originated adjustment + scope :without_tax, joins("LEFT OUTER JOIN spree_adjustments ON (spree_adjustments.adjustable_id=spree_line_items.id AND spree_adjustments.adjustable_type = 'Spree::LineItem' AND spree_adjustments.originator_type='Spree::TaxRate')"). + where('spree_adjustments.id IS NULL') + + 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/spec/models/spree/line_item_spec.rb b/spec/models/spree/line_item_spec.rb index 6166732b76..b39b51e1a5 100644 --- a/spec/models/spree/line_item_spec.rb +++ b/spec/models/spree/line_item_spec.rb @@ -24,6 +24,22 @@ module Spree LineItem.supplied_by_any([s2]).should == [li2] LineItem.supplied_by_any([s1, s2]).sort.should == [li1, li2].sort end + + describe "finding line items with and without tax" do + let(:tax_rate) { create(:tax_rate, calculator: Spree::Calculator::DefaultTax.new) } + let!(:adjustment1) { create(:adjustment, adjustable: li1, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) } + let!(:adjustment2) { create(:adjustment, adjustable: li1, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) } + + before { li1; li2 } + + it "finds line items with tax" do + LineItem.with_tax.should == [li1] + end + + it "finds line items without tax" do + LineItem.without_tax.should == [li2] + end + end end describe "calculating price with adjustments" do From 0dcd8eb8cc9df25af785b09a26cb21bc5edbd2f8 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 11:57:01 +1000 Subject: [PATCH 07/14] Find adjustments with and without tax --- app/models/spree/adjustment_decorator.rb | 2 ++ spec/models/spree/adjustment_spec.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/app/models/spree/adjustment_decorator.rb b/app/models/spree/adjustment_decorator.rb index 836080183c..153cc10a82 100644 --- a/app/models/spree/adjustment_decorator.rb +++ b/app/models/spree/adjustment_decorator.rb @@ -4,6 +4,8 @@ module Spree scope :enterprise_fee, where(originator_type: 'EnterpriseFee') scope :included_tax, where(originator_type: 'Spree::TaxRate', adjustable_type: 'Spree::LineItem') + scope :with_tax, where('spree_adjustments.included_tax > 0') + scope :without_tax, where('spree_adjustments.included_tax = 0') attr_accessible :included_tax diff --git a/spec/models/spree/adjustment_spec.rb b/spec/models/spree/adjustment_spec.rb index 579965aa7a..bd952f2e9c 100644 --- a/spec/models/spree/adjustment_spec.rb +++ b/spec/models/spree/adjustment_spec.rb @@ -5,6 +5,21 @@ module Spree adjustment.metadata.should be end + describe "finding adjustments with and without tax included" do + let!(:adjustment_with_tax) { create(:adjustment, included_tax: 123) } + let!(:adjustment_without_tax) { create(:adjustment, included_tax: 0) } + + it "finds adjustments with tax" do + Adjustment.with_tax.should include adjustment_with_tax + Adjustment.with_tax.should_not include adjustment_without_tax + end + + it "finds adjustments without tax" do + Adjustment.without_tax.should include adjustment_without_tax + Adjustment.without_tax.should_not include adjustment_with_tax + end + end + describe "recording included tax" do describe "TaxRate adjustments" do let!(:zone) { create(:zone_with_member) } From dc8270ed72971a490f444fdc6d06f491d8022706 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 12:16:35 +1000 Subject: [PATCH 08/14] Display amounts on xero invoice report --- lib/open_food_network/xero_invoices_report.rb | 30 +++++++++++++++--- spec/features/admin/reports_spec.rb | 31 ++++++++++--------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 7308f7740b..5b346f9263 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -27,15 +27,35 @@ module OpenFoodNetwork def rows_for_order(order, invoice_number, opts) [ - summary_row(order, 'Total untaxable produce (no tax)', 0, invoice_number, 'GST Free Income', opts), - summary_row(order, 'Total taxable produce (tax inclusive)', 0, invoice_number, 'GST on Income', opts), - summary_row(order, 'Total untaxable fees (no tax)', 0, invoice_number, 'GST Free Income', opts), - summary_row(order, 'Total taxable fees (tax inclusive)', 0, invoice_number, 'GST on Income', opts), - summary_row(order, 'Delivery Shipping Cost (tax inclusive)', 0, invoice_number, 'Tax or No Tax - depending on enterprise setting', opts) + summary_row(order, 'Total untaxable produce (no tax)', total_untaxable_products(order), invoice_number, 'GST Free Income', opts), + summary_row(order, 'Total taxable produce (tax inclusive)', total_taxable_products(order), invoice_number, 'GST on Income', opts), + summary_row(order, 'Total untaxable fees (no tax)', total_untaxable_fees(order), invoice_number, 'GST Free Income', opts), + summary_row(order, 'Total taxable fees (tax inclusive)', total_taxable_fees(order), invoice_number, 'GST on Income', opts), + summary_row(order, 'Delivery Shipping Cost (tax inclusive)', total_shipping(order), invoice_number, 'Tax or No Tax - depending on enterprise setting', opts) ] end + def total_untaxable_products(order) + order.line_items.without_tax.sum &:amount + end + + def total_taxable_products(order) + order.line_items.with_tax.sum &:amount + end + + def total_untaxable_fees(order) + order.adjustments.enterprise_fee.without_tax.sum &:amount + end + + def total_taxable_fees(order) + order.adjustments.enterprise_fee.with_tax.sum &:amount + end + + def total_shipping(order) + order.adjustments.shipping.sum &:amount + end + def invoice_number_for(order, i) @opts[:initial_invoice_number] ? @opts[:initial_invoice_number].to_i+i : order.number end diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 49a0979406..2de44d175d 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -305,8 +305,9 @@ feature %q{ let(:user1) { create_enterprise_user enterprises: [distributor1] } let(:user2) { create_enterprise_user enterprises: [distributor2] } let(:shipping_method) { create(:shipping_method, name: "Shipping", description: "Expensive", calculator: Spree::Calculator::FlatRate.new(preferred_amount: 100.55)) } - let(:enterprise_fee) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 120.0)) } - let(:order_cycle) { create(:simple_order_cycle, coordinator: distributor1, coordinator_fees: [enterprise_fee], distributors: [distributor1], variants: [product1.master]) } + let(:enterprise_fee1) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 10)) } + let(:enterprise_fee2) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 20)) } + let(:order_cycle) { create(:simple_order_cycle, coordinator: distributor1, coordinator_fees: [enterprise_fee1, enterprise_fee2], distributors: [distributor1], variants: [product1.master]) } let!(:zone) { create(:zone_with_member) } let(:country) { Spree::Country.find Spree::Config.default_country_id } @@ -318,7 +319,10 @@ feature %q{ let!(:line_item1) { create(:line_item, variant: product1.master, price: 12.54, quantity: 1, order: order1) } let!(:line_item2) { create(:line_item, variant: product2.master, price: 500.15, quantity: 3, order: order1) } - let!(:adj_shipping) { create(:adjustment, adjustable: order1, label: "Shipping", amount: 100.55) } + let!(:adj_shipping) { create(:adjustment, adjustable: order1, label: "Shipping", originator: shipping_method, amount: 100.55) } + let!(:adj_fee1) { create(:adjustment, adjustable: order1, originator: enterprise_fee1, label: "Enterprise fee untaxed", amount: 10, included_tax: 0) } + let!(:adj_fee2) { create(:adjustment, adjustable: order1, originator: enterprise_fee2, label: "Enterprise fee taxed", amount: 20, included_tax: 2) } + before do order1.update_attribute :email, 'customer@email.com' @@ -339,11 +343,11 @@ feature %q{ it "shows Xero invoices report" do xero_invoice_table.should match_table [ %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), - xero_invoice_row('Total untaxable produce (no tax)', 0, 'GST Free Income'), - xero_invoice_row('Total taxable produce (tax inclusive)', 0, 'GST on Income'), - xero_invoice_row('Total untaxable fees (no tax)', 0, 'GST Free Income'), - xero_invoice_row('Total taxable fees (tax inclusive)', 0, 'GST on Income'), - xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 0, 'Tax or No Tax - depending on enterprise setting') + xero_invoice_row('Total untaxable produce (no tax)', 12.54, 'GST Free Income'), + xero_invoice_row('Total taxable produce (tax inclusive)', 1500.45, 'GST on Income'), + xero_invoice_row('Total untaxable fees (no tax)', 10.0, 'GST Free Income'), + xero_invoice_row('Total taxable fees (tax inclusive)', 20.0, 'GST on Income'), + xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'Tax or No Tax - depending on enterprise setting') ] end @@ -358,15 +362,14 @@ feature %q{ xero_invoice_table.should match_table [ %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), - xero_invoice_row('Total untaxable produce (no tax)', 0, 'GST Free Income', opts), - xero_invoice_row('Total taxable produce (tax inclusive)', 0, 'GST on Income', opts), - xero_invoice_row('Total untaxable fees (no tax)', 0, 'GST Free Income', opts), - xero_invoice_row('Total taxable fees (tax inclusive)', 0, 'GST on Income', opts), - xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 0, 'Tax or No Tax - depending on enterprise setting', opts) + xero_invoice_row('Total untaxable produce (no tax)', 12.54, 'GST Free Income', opts), + xero_invoice_row('Total taxable produce (tax inclusive)', 1500.45, 'GST on Income', opts), + xero_invoice_row('Total untaxable fees (no tax)', 10.0, 'GST Free Income', opts), + xero_invoice_row('Total taxable fees (tax inclusive)', 20.0, 'GST on Income', opts), + xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'Tax or No Tax - depending on enterprise setting', opts) ] # TODO: - # - Amounts # - Tax specification for shipping end From ca37efdd262277c3b7fbabe9f3f07847c06395fb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 12:44:48 +1000 Subject: [PATCH 09/14] Display whether there is tax included in shipping --- lib/open_food_network/xero_invoices_report.rb | 15 ++++++++++----- spec/features/admin/reports_spec.rb | 9 +++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 5b346f9263..504bf03349 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -27,11 +27,11 @@ module OpenFoodNetwork def rows_for_order(order, invoice_number, opts) [ - summary_row(order, 'Total untaxable produce (no tax)', total_untaxable_products(order), invoice_number, 'GST Free Income', opts), - summary_row(order, 'Total taxable produce (tax inclusive)', total_taxable_products(order), invoice_number, 'GST on Income', opts), - summary_row(order, 'Total untaxable fees (no tax)', total_untaxable_fees(order), invoice_number, 'GST Free Income', opts), - summary_row(order, 'Total taxable fees (tax inclusive)', total_taxable_fees(order), invoice_number, 'GST on Income', opts), - summary_row(order, 'Delivery Shipping Cost (tax inclusive)', total_shipping(order), invoice_number, 'Tax or No Tax - depending on enterprise setting', opts) + summary_row(order, 'Total untaxable produce (no tax)', total_untaxable_products(order), invoice_number, 'GST Free Income', opts), + summary_row(order, 'Total taxable produce (tax inclusive)', total_taxable_products(order), invoice_number, 'GST on Income', opts), + summary_row(order, 'Total untaxable fees (no tax)', total_untaxable_fees(order), invoice_number, 'GST Free Income', opts), + summary_row(order, 'Total taxable fees (tax inclusive)', total_taxable_fees(order), invoice_number, 'GST on Income', opts), + summary_row(order, 'Delivery Shipping Cost (tax inclusive)', total_shipping(order), invoice_number, tax_on_shipping_s(order), opts) ] end @@ -56,6 +56,11 @@ module OpenFoodNetwork order.adjustments.shipping.sum &:amount end + def tax_on_shipping_s(order) + tax_on_shipping = order.adjustments.shipping.sum(&:included_tax) > 0 + tax_on_shipping ? 'GST on Income' : 'GST Free Income' + end + def invoice_number_for(order, i) @opts[:initial_invoice_number] ? @opts[:initial_invoice_number].to_i+i : order.number end diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 2de44d175d..86cf803fe5 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -319,7 +319,7 @@ feature %q{ let!(:line_item1) { create(:line_item, variant: product1.master, price: 12.54, quantity: 1, order: order1) } let!(:line_item2) { create(:line_item, variant: product2.master, price: 500.15, quantity: 3, order: order1) } - let!(:adj_shipping) { create(:adjustment, adjustable: order1, label: "Shipping", originator: shipping_method, amount: 100.55) } + let!(:adj_shipping) { create(:adjustment, adjustable: order1, label: "Shipping", originator: shipping_method, amount: 100.55, included_tax: 10.06) } let!(:adj_fee1) { create(:adjustment, adjustable: order1, originator: enterprise_fee1, label: "Enterprise fee untaxed", amount: 10, included_tax: 0) } let!(:adj_fee2) { create(:adjustment, adjustable: order1, originator: enterprise_fee2, label: "Enterprise fee taxed", amount: 20, included_tax: 2) } @@ -347,7 +347,7 @@ feature %q{ xero_invoice_row('Total taxable produce (tax inclusive)', 1500.45, 'GST on Income'), xero_invoice_row('Total untaxable fees (no tax)', 10.0, 'GST Free Income'), xero_invoice_row('Total taxable fees (tax inclusive)', 20.0, 'GST on Income'), - xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'Tax or No Tax - depending on enterprise setting') + xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'GST on Income') ] end @@ -366,11 +366,8 @@ feature %q{ xero_invoice_row('Total taxable produce (tax inclusive)', 1500.45, 'GST on Income', opts), xero_invoice_row('Total untaxable fees (no tax)', 10.0, 'GST Free Income', opts), xero_invoice_row('Total taxable fees (tax inclusive)', 20.0, 'GST on Income', opts), - xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'Tax or No Tax - depending on enterprise setting', opts) + xero_invoice_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'GST on Income', opts) ] - - # TODO: - # - Tax specification for shipping end From 3640a71ab8e7b5a7c7dab1bfa8016f5faa981e7e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 15:05:18 +1000 Subject: [PATCH 10/14] Reorder methods --- lib/open_food_network/xero_invoices_report.rb | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 504bf03349..9a316e08ed 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -25,6 +25,10 @@ module OpenFoodNetwork private + def invoice_number_for(order, i) + @opts[:initial_invoice_number] ? @opts[:initial_invoice_number].to_i+i : order.number + end + def rows_for_order(order, invoice_number, opts) [ summary_row(order, 'Total untaxable produce (no tax)', total_untaxable_products(order), invoice_number, 'GST Free Income', opts), @@ -35,36 +39,6 @@ module OpenFoodNetwork ] end - - def total_untaxable_products(order) - order.line_items.without_tax.sum &:amount - end - - def total_taxable_products(order) - order.line_items.with_tax.sum &:amount - end - - def total_untaxable_fees(order) - order.adjustments.enterprise_fee.without_tax.sum &:amount - end - - def total_taxable_fees(order) - order.adjustments.enterprise_fee.with_tax.sum &:amount - end - - def total_shipping(order) - order.adjustments.shipping.sum &:amount - end - - def tax_on_shipping_s(order) - tax_on_shipping = order.adjustments.shipping.sum(&:included_tax) > 0 - tax_on_shipping ? 'GST on Income' : 'GST Free Income' - end - - def invoice_number_for(order, i) - @opts[:initial_invoice_number] ? @opts[:initial_invoice_number].to_i+i : order.number - end - def summary_row(order, description, amount, invoice_number, tax_type, opts={}) [order.bill_address.full_name, order.email, @@ -96,5 +70,29 @@ module OpenFoodNetwork ] end + def total_untaxable_products(order) + order.line_items.without_tax.sum &:amount + end + + def total_taxable_products(order) + order.line_items.with_tax.sum &:amount + end + + def total_untaxable_fees(order) + order.adjustments.enterprise_fee.without_tax.sum &:amount + end + + def total_taxable_fees(order) + order.adjustments.enterprise_fee.with_tax.sum &:amount + end + + def total_shipping(order) + order.adjustments.shipping.sum &:amount + end + + def tax_on_shipping_s(order) + tax_on_shipping = order.adjustments.shipping.sum(&:included_tax) > 0 + tax_on_shipping ? 'GST on Income' : 'GST Free Income' + end end end From 3d4a0f84077fd58afdbddfcbdea85efef267882d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 15:27:46 +1000 Subject: [PATCH 11/14] Xero invoices report: Preserve form fields on submit, do not show rows with no cost --- .../spree/admin/reports_controller_decorator.rb | 2 +- app/views/spree/admin/reports/xero_invoices.html.haml | 8 ++++---- lib/open_food_network/xero_invoices_report.rb | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 15fab60d89..df86d224fd 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -681,7 +681,7 @@ Spree::Admin::ReportsController.class_eval do end def xero_invoices - @search = Spree::Order.complete.managed_by(spree_current_user).search(params[:q]) + @search = Spree::Order.complete.managed_by(spree_current_user).order('id DESC').search(params[:q]) orders = @search.result @report = OpenFoodNetwork::XeroInvoicesReport.new orders, params render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv") diff --git a/app/views/spree/admin/reports/xero_invoices.html.haml b/app/views/spree/admin/reports/xero_invoices.html.haml index 8c11e5f543..9433ee91bb 100644 --- a/app/views/spree/admin/reports/xero_invoices.html.haml +++ b/app/views/spree/admin/reports/xero_invoices.html.haml @@ -1,16 +1,16 @@ = form_tag spree.xero_invoices_admin_reports_path do .row .four.columns.alpha= label_tag :initial_invoice_number, "Initial invoice number:" - .twelve.columns.omega= text_field_tag :initial_invoice_number + .twelve.columns.omega= text_field_tag :initial_invoice_number, params[:initial_invoice_number] .row .four.columns.alpha= label_tag :invoice_date, "Invoice date:" - .twelve.columns.omega= text_field_tag :invoice_date, '', class: 'datetimepicker' + .twelve.columns.omega= text_field_tag :invoice_date, params[:invoice_date], class: 'datetimepicker' .row .four.columns.alpha= label_tag :due_date, "Due date:" - .twelve.columns.omega= text_field_tag :due_date, '', class: 'datetimepicker' + .twelve.columns.omega= text_field_tag :due_date, params[:due_date], class: 'datetimepicker' .row .four.columns.alpha= label_tag :account_code, "Account code:" - .twelve.columns.omega= text_field_tag :account_code + .twelve.columns.omega= text_field_tag :account_code, params[:account_code] .row .four.columns.alpha= label_tag :csv, "Download as CSV:" .twelve.columns.omega= check_box_tag :csv diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 9a316e08ed..b3d2bc77f3 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -36,10 +36,12 @@ module OpenFoodNetwork summary_row(order, 'Total untaxable fees (no tax)', total_untaxable_fees(order), invoice_number, 'GST Free Income', opts), summary_row(order, 'Total taxable fees (tax inclusive)', total_taxable_fees(order), invoice_number, 'GST on Income', opts), summary_row(order, 'Delivery Shipping Cost (tax inclusive)', total_shipping(order), invoice_number, tax_on_shipping_s(order), opts) - ] + ].compact end def summary_row(order, description, amount, invoice_number, tax_type, opts={}) + return nil if amount == 0 + [order.bill_address.full_name, order.email, order.bill_address.address1, From a467d3c379f3b2f60b982fae662f05ee1df0cfcb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 16:20:56 +1000 Subject: [PATCH 12/14] Add filtering to xero invoices report - order date range, hub and order cycle --- .../spree/admin/reports_controller_decorator.rb | 7 +++++++ .../spree/admin/reports/xero_invoices.html.haml | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index df86d224fd..9633b6cd68 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -681,6 +681,13 @@ Spree::Admin::ReportsController.class_eval do end def xero_invoices + if request.get? + params[:q] ||= {} + params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month + end + @distributors = Enterprise.is_distributor.managed_by(spree_current_user) + @order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC') + @search = Spree::Order.complete.managed_by(spree_current_user).order('id DESC').search(params[:q]) orders = @search.result @report = OpenFoodNetwork::XeroInvoicesReport.new orders, params diff --git a/app/views/spree/admin/reports/xero_invoices.html.haml b/app/views/spree/admin/reports/xero_invoices.html.haml index 9433ee91bb..1ae4e3b279 100644 --- a/app/views/spree/admin/reports/xero_invoices.html.haml +++ b/app/views/spree/admin/reports/xero_invoices.html.haml @@ -1,4 +1,15 @@ -= form_tag spree.xero_invoices_admin_reports_path do += form_for @search, url: spree.xero_invoices_admin_reports_path do |f| + = render 'date_range_form', f: f + + .row + .four.columns.alpha= label_tag nil, "Hub: " + .four.columns.omega= f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => 'All'}, {:class => "select2 fullwidth"}) + .row + .four.columns.alpha= label_tag nil, "Order Cycle: " + .four.columns.omega= f.select(:order_cycle_id_eq, + options_for_select(report_order_cycle_options(@order_cycles), params[:q][:order_cycle_id_eq]), + {:include_blank => true}, {:class => "select2 fullwidth"}) + .row .four.columns.alpha= label_tag :initial_invoice_number, "Initial invoice number:" .twelve.columns.omega= text_field_tag :initial_invoice_number, params[:initial_invoice_number] From f7642b2a1b8e6fb19cff2a639f1a44c6f360cc09 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 16:51:04 +1000 Subject: [PATCH 13/14] When blank values are submitted, do not override defaults --- lib/open_food_network/xero_invoices_report.rb | 9 ++++++--- .../open_food_network/xero_invoices_report_spec.rb | 12 ++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index b3d2bc77f3..79305d655a 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -2,9 +2,12 @@ module OpenFoodNetwork class XeroInvoicesReport def initialize(orders, opts={}) @orders = orders - @opts = opts.reverse_merge({invoice_date: Date.today, - due_date: 2.weeks.from_now.to_date, - account_code: 'food sales'}) + + @opts = opts. + reject { |k, v| v.blank? }. + reverse_merge({invoice_date: Date.today, + due_date: 2.weeks.from_now.to_date, + account_code: 'food sales'}) end def header diff --git a/spec/lib/open_food_network/xero_invoices_report_spec.rb b/spec/lib/open_food_network/xero_invoices_report_spec.rb index 9756629f0e..8551d663a8 100644 --- a/spec/lib/open_food_network/xero_invoices_report_spec.rb +++ b/spec/lib/open_food_network/xero_invoices_report_spec.rb @@ -4,6 +4,18 @@ module OpenFoodNetwork describe XeroInvoicesReport do subject { XeroInvoicesReport.new [] } + describe "option defaults" do + let(:report) { XeroInvoicesReport.new [], {initial_invoice_number: '', invoice_date: '', due_date: '', account_code: ''} } + + around { |example| Timecop.travel(Time.zone.local(2015, 5, 5, 14, 0, 0)) { example.run } } + + it "uses defaults when blank params are passed" do + report.instance_variable_get(:@opts).should == {invoice_date: Date.civil(2015, 5, 5), + due_date: Date.civil(2015, 5, 19), + account_code: 'food sales'} + end + end + describe "generating invoice numbers" do let(:order) { double(:order, number: 'R731032860') } From 70b5ac4785dab82d79853ad43fc48c61dab11c40 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 15 May 2015 16:55:52 +1000 Subject: [PATCH 14/14] Add column for whether the order has been paid for --- lib/open_food_network/xero_invoices_report.rb | 5 +++-- spec/features/admin/reports_spec.rb | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb index 79305d655a..1a7f7bd636 100644 --- a/lib/open_food_network/xero_invoices_report.rb +++ b/lib/open_food_network/xero_invoices_report.rb @@ -11,7 +11,7 @@ module OpenFoodNetwork end def header - %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme) + %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme Paid?) end def table @@ -71,7 +71,8 @@ module OpenFoodNetwork '', '', Spree::Config.currency, - '' + '', + order.paid? ? 'Y' : 'N' ] end diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 86cf803fe5..d8f7e1e14d 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -342,7 +342,7 @@ feature %q{ it "shows Xero invoices report" do xero_invoice_table.should match_table [ - %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), + xero_invoice_header, xero_invoice_row('Total untaxable produce (no tax)', 12.54, 'GST Free Income'), xero_invoice_row('Total taxable produce (tax inclusive)', 1500.45, 'GST on Income'), xero_invoice_row('Total untaxable fees (no tax)', 10.0, 'GST Free Income'), @@ -361,7 +361,7 @@ feature %q{ opts = {invoice_number: '5', invoice_date: '2015-02-12', due_date: '2015-03-12', account_code: 'abc123'} xero_invoice_table.should match_table [ - %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme), + xero_invoice_header, xero_invoice_row('Total untaxable produce (no tax)', 12.54, 'GST Free Income', opts), xero_invoice_row('Total taxable produce (tax inclusive)', 1500.45, 'GST on Income', opts), xero_invoice_row('Total untaxable fees (no tax)', 10.0, 'GST Free Income', opts), @@ -377,10 +377,14 @@ feature %q{ find("table#listing_invoices") end + def xero_invoice_header + %w(*ContactName EmailAddress POAddressLine1 POAddressLine2 POAddressLine3 POAddressLine4 POCity PORegion POPostalCode POCountry *InvoiceNumber Reference *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount Discount *AccountCode *TaxType TrackingName1 TrackingOption1 TrackingName2 TrackingOption2 Currency BrandingTheme Paid?) + end + def xero_invoice_row(description, amount, tax_type, opts={}) opts.reverse_merge!({invoice_number: order1.number, invoice_date: '2015-04-26', due_date: '2015-05-10', account_code: 'food sales'}) - ['Customer Name', 'customer@email.com', 'customer l1', '', '', '', 'customer city', 'Victoria', '1234', country.name, opts[:invoice_number], order1.number, opts[:invoice_date], opts[:due_date], '', description, '1', amount.to_s, '', opts[:account_code], tax_type, '', '', '', '', Spree::Config.currency, ''] + ['Customer Name', 'customer@email.com', 'customer l1', '', '', '', 'customer city', 'Victoria', '1234', country.name, opts[:invoice_number], order1.number, opts[:invoice_date], opts[:due_date], '', description, '1', amount.to_s, '', opts[:account_code], tax_type, '', '', '', '', Spree::Config.currency, '', 'N'] end end