My Shiny Weblog!

programming, photography and lifestyle

Печатница за фактури

Като един млад фирмаджия, нямаше начин да не реша проблема с фактурите. На всяка фирма и се налага да произвежда фактури. По прични, за които съм писал и преди, не ми се занимаваше с никакъв готов счетоводен софтуер. Отделих един ден и една нощ и започнах. В началото мислех да е някаква простра Ruby програмка, която да пише в SQLite и да произвежда LaTeX файл за печат. Надявах се да намеря някакъв читав LaTeX binding за Ruby, но за съжаление не успях. Пробвах да генерирам PDF с pdf-writer, но се сблъсках с неприятен проблем с кодировките – по някакви причини в PDF формата нямалко поддръжка за UTF-8. Остана единствено варианта да произвеждам HTML+CSS, колкото и да го мразя, като формат за печатане. Казах си че, щом така или иначе ще ползвам HTML, по-добре цялото нещо “да е на релси”, сложих последния Ruby on Rails и започнах. След кратък размисъл реших, че ще е добре да имам три основни обекта – клиент, услуга и фактура. Смятайки на пръсти се вижда, че една фактура може да има един клиент и много услуги. Ето ми ги и моделите:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Client < ActiveRecord::Base
   has_many :invoices
   validates_presence_of :name, :address, :bulstat, :mol, :bic, :iban
end

class Service < ActiveRecord::Base
        has_and_belongs_to_many :invoices
        validates_presence_of :name
        validates_presence_of :price
end

class Invoice < ActiveRecord::Base
        has_and_belongs_to_many :services
        belongs_to :client
end

След като написах полетата, които ми трябва във валидиращите функции, вече мога да си направя и базата данни. Все пак е хубаво да се сложат още няколко полета, който мисля да произвеждам автоматично:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ActiveRecord::Schema.define(:version => 4) do

  create_table "clients", :force => true do |t|
    t.datetime "created_at"
    t.string   "name"
    t.string   "address"
    t.string   "bulstat"
    t.string   "mol"
    t.string   "bic"
    t.string   "iban"
  end

  create_table "invoices", :force => true do |t|
    t.datetime "created_at"
    t.string   "signature"
    t.integer  "client_id"
    t.float    "price"
  end

  create_table "invoices_services", :force => true do |t|
    t.integer  "invoice_id"
    t.integer  "service_id"
    t.datetime "created_at"
  end

  create_table "services", :force => true do |t|
    t.datetime "created_at"
    t.string   "name"
    t.float    "price"
  end

end

Ясно е, че за тази проста/просташка програмка, няма никакъв смисъл да мисля някакъв изгъзен интерфейс, реших да ползвеам ActiveScaffold. Освен това е добре поне част от имената да са на български:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class InvoiceController < ApplicationController
   active_scaffold :invoice do |config|
      # Тема
      config.theme = :blue

      # Превод на заглавията на колоните
      config.label = 'Фактури'
      config.columns[:created_at].label = 'Създадена на'
      config.columns[:services].label = 'Услуги'
      config.list.columns.add :id
      config.columns[:id].label = 'Номер'
      config.create.columns.exclude :signature
      config.columns[:client].label = 'Клиент'
      config.columns[:price].label = 'Стойност'
      config.create.columns.exclude :price

      # Превод на имената на връзките
      config.actions.exclude :update
      config.actions.exclude :delete
      config.action_links.add 'print', :label => 'Принтиране', :page => true, :type => :record
      config.show.link.label = 'Показване'
   end
   def print
      @print = Invoice.find(params[:id])
      render :partial => 'print'
   end
end

Мда, до тук добре, остана досадната част от работата. Да се измисли някакъв HTML+CSS template за принтиране. За HTML частта използвах Malline от чист мързел. CSS нещата ги нагодих някакси на око, след принтиране на няколко неуспешни дизайнерски решения. Тези неща няма да си ги давам, щото са уникални за фирмата, който иска да ги види да дойде да му напиша фактура (и да си я плати после). Друго хубаво нещо, което се сетих да сложа е “цифров подпис”. Това е една хеш стойност, която генерирам по мой си начин от някои полета на фактурата. Не е кой знае каква сигурност, но за тези фактури ще свърши добра работа (всъшност хич не е лесно човек да я фалшифицира). Стойността на цялата фактура смятам автоматично, като сумирам цените на отделните услуги. Данните на мойта си фирма съм ги сложил статично в генерирания от Malline HTML файл. Това ще ми върши работа засега, но подозирам, че през годините тази програма ще се превърне в една огромна система за документооборот, която ще се чопли непрекъснато и ще се добавят нови неща в нея. Както и да е, дано да съм лош пророк.