Compare commits
4 Commits
developmen
...
feature/75
Author | SHA1 | Date |
---|---|---|
Paul van Tilburg | e21058c5d8 | |
Paul van Tilburg | cd488cbee8 | |
Paul van Tilburg | fad9076913 | |
Paul van Tilburg | f87954b73d |
|
@ -13,6 +13,9 @@
|
||||||
# The VAT rate
|
# The VAT rate
|
||||||
#vat_rate: 21.0
|
#vat_rate: 21.0
|
||||||
|
|
||||||
|
# VAT rate to Gnucash tax table name mapping
|
||||||
|
#gnucash_vat_table: {}
|
||||||
|
|
||||||
# The invoice ID format (see strftime(3) and %N for the sequence number)
|
# The invoice ID format (see strftime(3) and %N for the sequence number)
|
||||||
#invoice_id: %Y%N
|
#invoice_id: %Y%N
|
||||||
|
|
||||||
|
|
99
stoptime.rb
99
stoptime.rb
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
require "action_view"
|
require "action_view"
|
||||||
require "active_support"
|
require "active_support"
|
||||||
|
require "csv"
|
||||||
require "camping"
|
require "camping"
|
||||||
require "camping/mab"
|
require "camping/mab"
|
||||||
require "camping/ar"
|
require "camping/ar"
|
||||||
|
@ -162,12 +163,13 @@ module StopTime::Models
|
||||||
|
|
||||||
# The default configuration. Note that the configuration of the root
|
# The default configuration. Note that the configuration of the root
|
||||||
# will be merged with this configuration.
|
# will be merged with this configuration.
|
||||||
DefaultConfig = { "invoice_id" => "%Y%N",
|
DefaultConfig = { "gnucash_vat_table" => {},
|
||||||
"invoice_template" => "invoice",
|
"invoice_id" => "%Y%N",
|
||||||
"hourly_rate" => 20.0,
|
"invoice_template" => "invoice",
|
||||||
"time_resolution" => 1,
|
"hourly_rate" => 20.0,
|
||||||
"date_new_entry" => "today",
|
"time_resolution" => 1,
|
||||||
"vat_rate" => 21.0 }
|
"date_new_entry" => "today",
|
||||||
|
"vat_rate" => 21.0 }
|
||||||
|
|
||||||
# Creates a new configuration object and loads the configuation.
|
# Creates a new configuration object and loads the configuation.
|
||||||
# by reading the file +config.yaml+ on disk (see {ConfigFile}, parsing
|
# by reading the file +config.yaml+ on disk (see {ConfigFile}, parsing
|
||||||
|
@ -236,6 +238,8 @@ module StopTime::Models
|
||||||
# @!attribute time_specification
|
# @!attribute time_specification
|
||||||
# @return [Boolean] flag whether the customer requires time
|
# @return [Boolean] flag whether the customer requires time
|
||||||
# specifications
|
# specifications
|
||||||
|
# @!attribute gnucash_customer_owner_id
|
||||||
|
# @return [String] owner ID used in GnuCash for this customer
|
||||||
# @!attribute created_at
|
# @!attribute created_at
|
||||||
# @return [Time] time of creation
|
# @return [Time] time of creation
|
||||||
# @!attribute updated_at
|
# @!attribute updated_at
|
||||||
|
@ -630,6 +634,8 @@ module StopTime::Models
|
||||||
# @return [String] number of the bank account
|
# @return [String] number of the bank account
|
||||||
# @!attribute accountiban
|
# @!attribute accountiban
|
||||||
# @return [String] international bank account number
|
# @return [String] international bank account number
|
||||||
|
# @!attribute gnucash_revenues_account_name
|
||||||
|
# @return [String] account name used in GnuCash for the revenues account
|
||||||
# @!attribute created_at
|
# @!attribute created_at
|
||||||
# @return [Time] time of creation
|
# @return [Time] time of creation
|
||||||
# @!attribute updated_at
|
# @!attribute updated_at
|
||||||
|
@ -887,6 +893,19 @@ module StopTime::Models
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @private
|
||||||
|
class GnuCashInvoiceExportSupport < V 1.96
|
||||||
|
def self.up
|
||||||
|
add_column(CompanyInfo.table_name, :gnucash_revenues_account_name, :string)
|
||||||
|
add_column(Customer.table_name, :gnucash_customer_owner_id, :string)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column(CompanyInfo.table_name, :gnucash_revenues_account_name)
|
||||||
|
remove_column(Customer.table_name, :gnucash_customer_owner_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end # StopTime::Models
|
end # StopTime::Models
|
||||||
|
|
||||||
# = The Stop… Camping Time! helpers
|
# = The Stop… Camping Time! helpers
|
||||||
|
@ -1085,7 +1104,7 @@ module StopTime::Controllers
|
||||||
elsif @input.has_key? "update"
|
elsif @input.has_key? "update"
|
||||||
attrs = ["name", "short_name", "financial_contact",
|
attrs = ["name", "short_name", "financial_contact",
|
||||||
"address_street", "address_postal_code", "address_city",
|
"address_street", "address_postal_code", "address_city",
|
||||||
"email", "phone", "hourly_rate"]
|
"email", "phone", "hourly_rate", "gnucash_customer_owner_id"]
|
||||||
attrs.each do |attr|
|
attrs.each do |attr|
|
||||||
@customer[attr] = @input[attr]
|
@customer[attr] = @input[attr]
|
||||||
end
|
end
|
||||||
|
@ -1368,9 +1387,12 @@ module StopTime::Controllers
|
||||||
|
|
||||||
tex_file = PUBLIC_DIR + "invoices/#{@number}.tex"
|
tex_file = PUBLIC_DIR + "invoices/#{@number}.tex"
|
||||||
pdf_file = PUBLIC_DIR + "invoices/#{@number}.pdf"
|
pdf_file = PUBLIC_DIR + "invoices/#{@number}.pdf"
|
||||||
|
csv_file = PUBLIC_DIR + "invoices/#{@number}.csv"
|
||||||
|
@csv_enabled = @company.gnucash_revenues_account_name.present? &&
|
||||||
|
@customer.gnucash_customer_owner_id.present?
|
||||||
if @format == "html"
|
if @format == "html"
|
||||||
@input = @invoice.attributes
|
@input = @invoice.attributes
|
||||||
@invoice_file_present = tex_file.exist?
|
@invoice_file_present = tex_file.exist? || csv_file.exist?
|
||||||
render :invoice_form
|
render :invoice_form
|
||||||
elsif @format == "tex"
|
elsif @format == "tex"
|
||||||
_generate_invoice_tex(@number) unless tex_file.exist?
|
_generate_invoice_tex(@number) unless tex_file.exist?
|
||||||
|
@ -1378,6 +1400,9 @@ module StopTime::Controllers
|
||||||
elsif @format == "pdf"
|
elsif @format == "pdf"
|
||||||
_generate_invoice_pdf(@number) unless pdf_file.exist?
|
_generate_invoice_pdf(@number) unless pdf_file.exist?
|
||||||
redirect R(Static, "") + "invoices/#{pdf_file.basename}"
|
redirect R(Static, "") + "invoices/#{pdf_file.basename}"
|
||||||
|
elsif @format == "csv"
|
||||||
|
_generate_invoice_csv(@number) unless csv_file.exist?
|
||||||
|
redirect R(Static, "") + "invoices/#{csv_file.basename}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1410,6 +1435,9 @@ module StopTime::Controllers
|
||||||
pdf_file = PUBLIC_DIR + "invoices/#{invoice_number}.pdf"
|
pdf_file = PUBLIC_DIR + "invoices/#{invoice_number}.pdf"
|
||||||
File.unlink(pdf_file) if pdf_file.exist?
|
File.unlink(pdf_file) if pdf_file.exist?
|
||||||
|
|
||||||
|
csv_file = PUBLIC_DIR + "invoices/#{invoice_number}.csv"
|
||||||
|
File.unlink(csv_file) if csv_file.exist?
|
||||||
|
|
||||||
redirect R(CustomersNInvoicesX, customer_id, invoice_number)
|
redirect R(CustomersNInvoicesX, customer_id, invoice_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1467,6 +1495,44 @@ module StopTime::Controllers
|
||||||
system("rubber --pdf --inplace #{tex_file}")
|
system("rubber --pdf --inplace #{tex_file}")
|
||||||
system("rubber --clean --inplace #{tex_file}")
|
system("rubber --clean --inplace #{tex_file}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generates a CSV file for the invoice with the give number
|
||||||
|
# using {#_generate_invoice_csv}.
|
||||||
|
#
|
||||||
|
# @raise if CSV generation is not enabled due to missing
|
||||||
|
# data
|
||||||
|
def _generate_invoice_csv(number)
|
||||||
|
raise "GnuCash CSV is not enabled due to missing data" unless @csv_enabled
|
||||||
|
csv_file = PUBLIC_DIR + "invoices/#{number}.csv"
|
||||||
|
|
||||||
|
CSV.open(csv_file, "wb", col_sep: ";", headers: false) do |csv|
|
||||||
|
id = @invoice.number
|
||||||
|
date = @invoice.created_at.to_date
|
||||||
|
owner_id = @customer.gnucash_customer_owner_id
|
||||||
|
account = @company.gnucash_revenue_account_name
|
||||||
|
@tasks.each do |task, line|
|
||||||
|
desc = task.comment_or_name
|
||||||
|
tax_table = config["gnucash_vat_table"][task.vat_rate]
|
||||||
|
taxable = tax_table.present?
|
||||||
|
if line[1].blank?
|
||||||
|
# This is a fixed cost task
|
||||||
|
action = "Project"
|
||||||
|
quantity = 1
|
||||||
|
price = number_with_precision(line[2])
|
||||||
|
else
|
||||||
|
# This is a task with an hourly rate
|
||||||
|
action = "Hours"
|
||||||
|
quantity = number_with_precision(line[0])
|
||||||
|
price = number_with_precision(line[1])
|
||||||
|
end
|
||||||
|
due_date = date + 30.days # FIXME: hardcoded?!
|
||||||
|
csv_row = [id, date, owner_id, nil, nil, date, desc, action,
|
||||||
|
account, quantity, price, nil, nil, nil, taxable, nil,
|
||||||
|
tax_table, due_date, nil, nil, nil, nil]
|
||||||
|
csv << csv_row
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end # class StopTime::Controllers::CustomerNInvoicesX
|
end # class StopTime::Controllers::CustomerNInvoicesX
|
||||||
|
|
||||||
# == The invoice creating controller for a specifc customer
|
# == The invoice creating controller for a specifc customer
|
||||||
|
@ -1738,7 +1804,8 @@ module StopTime::Controllers
|
||||||
"country", "country_code",
|
"country", "country_code",
|
||||||
"phone", "cell", "email", "website",
|
"phone", "cell", "email", "website",
|
||||||
"chamber", "vatno",
|
"chamber", "vatno",
|
||||||
"bank_name", "bank_bic", "accountno", "accountiban"]
|
"bank_name", "bank_bic", "accountno", "accountiban",
|
||||||
|
"gnucash_revenues_account_name"]
|
||||||
attrs.each do |attr|
|
attrs.each do |attr|
|
||||||
@company[attr] = @input[attr]
|
@company[attr] = @input[attr]
|
||||||
end
|
end
|
||||||
|
@ -2163,6 +2230,8 @@ module StopTime::Views
|
||||||
_form_input_with_label("Default hourly rate", "hourly_rate", :text,
|
_form_input_with_label("Default hourly rate", "hourly_rate", :text,
|
||||||
control_class: "col-sm-4 col-xs-5",
|
control_class: "col-sm-4 col-xs-5",
|
||||||
input_addon: "€ / h")
|
input_addon: "€ / h")
|
||||||
|
_form_input_with_label("GnuCash owner ID",
|
||||||
|
"gnucash_customer_owner_id", :text)
|
||||||
div.form_group do
|
div.form_group do
|
||||||
label.control_label.col_sm_3.col_xs_4 "Time specifications?"
|
label.control_label.col_sm_3.col_xs_4 "Time specifications?"
|
||||||
div.col_sm_6.col_xs_8 do
|
div.col_sm_6.col_xs_8 do
|
||||||
|
@ -2585,6 +2654,14 @@ module StopTime::Views
|
||||||
_icon("download")
|
_icon("download")
|
||||||
span "Download LaTeX"
|
span "Download LaTeX"
|
||||||
end
|
end
|
||||||
|
if @csv_enabled
|
||||||
|
a.btn.btn_default role: "button",
|
||||||
|
href: R(CustomersNInvoicesX,
|
||||||
|
@customer.id, "#{@invoice.number}.csv") do
|
||||||
|
_icon("download")
|
||||||
|
span "Download GnuCash CSV"
|
||||||
|
end
|
||||||
|
end
|
||||||
a.btn.btn_default role: "button",
|
a.btn.btn_default role: "button",
|
||||||
href: R(Company, revision: @company.revision) do
|
href: R(Company, revision: @company.revision) do
|
||||||
_icon("briefcase")
|
_icon("briefcase")
|
||||||
|
@ -2853,6 +2930,10 @@ module StopTime::Views
|
||||||
_form_input_with_label("Intl. account number", "accountiban", :text,
|
_form_input_with_label("Intl. account number", "accountiban", :text,
|
||||||
control_class: "col-sm-5 col-xs-6")
|
control_class: "col-sm-5 col-xs-6")
|
||||||
|
|
||||||
|
h3 "GnuCash export information"
|
||||||
|
_form_input_with_label("Revenues account name",
|
||||||
|
"gnucash_revenues_account_name", :text)
|
||||||
|
|
||||||
div.form_group do
|
div.form_group do
|
||||||
div.col_sm_offset_3.col_sm_6.col_xs_offset_4.col_xs_8 do
|
div.col_sm_offset_3.col_sm_6.col_xs_offset_4.col_xs_8 do
|
||||||
button.btn.btn_primary "Update", type: "submit",
|
button.btn.btn_primary "Update", type: "submit",
|
||||||
|
|
Loading…
Reference in New Issue